summaryrefslogtreecommitdiff
path: root/chromium/content/browser
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@theqtcompany.com>2014-12-05 15:04:29 +0100
committerAndras Becsi <andras.becsi@theqtcompany.com>2014-12-09 10:49:28 +0100
commitaf6588f8d723931a298c995fa97259bb7f7deb55 (patch)
tree060ca707847ba1735f01af2372e0d5e494dc0366 /chromium/content/browser
parent2fff84d821cc7b1c785f6404e0f8091333283e74 (diff)
downloadqtwebengine-chromium-af6588f8d723931a298c995fa97259bb7f7deb55.tar.gz
BASELINE: Update chromium to 40.0.2214.28 and ninja to 1.5.3.
Change-Id: I759465284fd64d59ad120219cbe257f7402c4181 Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'chromium/content/browser')
-rw-r--r--chromium/content/browser/BUILD.gn171
-rw-r--r--chromium/content/browser/DEPS20
-rw-r--r--chromium/content/browser/OWNERS4
-rw-r--r--chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc191
-rw-r--r--chromium/content/browser/accessibility/accessibility_mode_browsertest.cc87
-rw-r--r--chromium/content/browser/accessibility/accessibility_mode_helper.cc25
-rw-r--r--chromium/content/browser/accessibility/accessibility_mode_helper.h5
-rw-r--r--chromium/content/browser/accessibility/accessibility_mode_helper_unittest.cc32
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter.cc12
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter.h4
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm39
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc1
-rw-r--r--chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc5
-rw-r--r--chromium/content/browser/accessibility/accessibility_ui.cc54
-rw-r--r--chromium/content/browser/accessibility/accessibility_ui.h2
-rw-r--r--chromium/content/browser/accessibility/accessibility_win_browsertest.cc7
-rw-r--r--chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc209
-rw-r--r--chromium/content/browser/accessibility/android_hit_testing_browsertest.cc12
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.cc26
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility.h17
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_android.cc273
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_android.h34
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_cocoa.h2
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_cocoa.mm312
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_mac.h6
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.cc71
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager.h104
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_android.cc289
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_android.h64
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_mac.h10
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm17
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc61
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.cc79
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_manager_win.h32
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl.cc71
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_state_impl.h22
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win.cc150
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win.h645
-rw-r--r--chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc77
-rw-r--r--chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc4
-rw-r--r--chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc655
-rw-r--r--chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc146
-rw-r--r--chromium/content/browser/android/DEPS3
-rw-r--r--chromium/content/browser/android/OWNERS2
-rw-r--r--chromium/content/browser/android/browser_startup_controller.cc4
-rw-r--r--chromium/content/browser/android/browser_surface_texture_manager.cc136
-rw-r--r--chromium/content/browser/android/browser_surface_texture_manager.h43
-rw-r--r--chromium/content/browser/android/child_process_launcher_android.cc52
-rw-r--r--chromium/content/browser/android/child_process_launcher_android.h22
-rw-r--r--chromium/content/browser/android/composited_touch_handle_drawable.cc165
-rw-r--r--chromium/content/browser/android/composited_touch_handle_drawable.h48
-rw-r--r--chromium/content/browser/android/content_readback_handler.cc9
-rw-r--r--chromium/content/browser/android/content_settings.cc4
-rw-r--r--chromium/content/browser/android/content_settings.h2
-rw-r--r--chromium/content/browser/android/content_startup_flags.cc24
-rw-r--r--chromium/content/browser/android/content_startup_flags.h2
-rw-r--r--chromium/content/browser/android/content_video_view.cc80
-rw-r--r--chromium/content/browser/android/content_video_view.h23
-rw-r--r--chromium/content/browser/android/content_view_core_impl.cc784
-rw-r--r--chromium/content/browser/android/content_view_core_impl.h179
-rw-r--r--chromium/content/browser/android/content_view_render_view.cc17
-rw-r--r--chromium/content/browser/android/content_view_render_view.h10
-rw-r--r--chromium/content/browser/android/content_view_statics.cc9
-rw-r--r--chromium/content/browser/android/date_time_chooser_android.cc8
-rw-r--r--chromium/content/browser/android/date_time_chooser_android.h3
-rw-r--r--chromium/content/browser/android/devtools_auth.cc21
-rw-r--r--chromium/content/browser/android/download_controller_android_impl.cc12
-rw-r--r--chromium/content/browser/android/download_controller_android_impl.h11
-rw-r--r--chromium/content/browser/android/edge_effect.cc261
-rw-r--r--chromium/content/browser/android/edge_effect.h90
-rw-r--r--chromium/content/browser/android/edge_effect_base.h49
-rw-r--r--chromium/content/browser/android/edge_effect_l.cc286
-rw-r--r--chromium/content/browser/android/edge_effect_l.h81
-rw-r--r--chromium/content/browser/android/gesture_event_type.h27
-rw-r--r--chromium/content/browser/android/gesture_event_type_list.h33
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.cc189
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_factory_impl.h36
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_impl.cc64
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_impl.h49
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_output_surface.cc92
-rw-r--r--chromium/content/browser/android/in_process/synchronous_compositor_output_surface.h43
-rw-r--r--chromium/content/browser/android/in_process/synchronous_input_event_filter.h10
-rw-r--r--chromium/content/browser/android/interstitial_page_delegate_android.h8
-rw-r--r--chromium/content/browser/android/java/DEPS3
-rw-r--r--chromium/content/browser/android/java/OWNERS (renamed from chromium/content/browser/renderer_host/java/OWNERS)0
-rw-r--r--chromium/content/browser/android/java/gin_java_bound_object.cc (renamed from chromium/content/browser/renderer_host/java/gin_java_bound_object.cc)6
-rw-r--r--chromium/content/browser/android/java/gin_java_bound_object.h (renamed from chromium/content/browser/renderer_host/java/gin_java_bound_object.h)8
-rw-r--r--chromium/content/browser/android/java/gin_java_bound_object_delegate.cc (renamed from chromium/content/browser/renderer_host/java/gin_java_bound_object_delegate.cc)2
-rw-r--r--chromium/content/browser/android/java/gin_java_bound_object_delegate.h (renamed from chromium/content/browser/renderer_host/java/gin_java_bound_object_delegate.h)20
-rw-r--r--chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.cc564
-rw-r--r--chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h126
-rw-r--r--chromium/content/browser/android/java/gin_java_method_invocation_helper.cc (renamed from chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper.cc)64
-rw-r--r--chromium/content/browser/android/java/gin_java_method_invocation_helper.h (renamed from chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper.h)17
-rw-r--r--chromium/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc (renamed from chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper_unittest.cc)94
-rw-r--r--chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.cc (renamed from chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc)96
-rw-r--r--chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.h (renamed from chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.h)14
-rw-r--r--chromium/content/browser/android/java/java_method.cc (renamed from chromium/content/browser/renderer_host/java/java_method.cc)51
-rw-r--r--chromium/content/browser/android/java/java_method.h (renamed from chromium/content/browser/renderer_host/java/java_method.h)13
-rw-r--r--chromium/content/browser/android/java/java_type.cc165
-rw-r--r--chromium/content/browser/android/java/java_type.h (renamed from chromium/content/browser/renderer_host/java/java_type.h)17
-rw-r--r--chromium/content/browser/android/java/java_type_unittest.cc86
-rw-r--r--chromium/content/browser/android/overscroll_glow.cc236
-rw-r--r--chromium/content/browser/android/overscroll_glow.h41
-rw-r--r--chromium/content/browser/android/popup_item_type_list.h23
-rw-r--r--chromium/content/browser/android/popup_touch_handle_drawable.cc87
-rw-r--r--chromium/content/browser/android/popup_touch_handle_drawable.h40
-rw-r--r--chromium/content/browser/android/surface_texture_peer_browser_impl.cc91
-rw-r--r--chromium/content/browser/android/surface_texture_peer_browser_impl.h37
-rw-r--r--chromium/content/browser/android/system_ui_resource_manager_impl.cc178
-rw-r--r--chromium/content/browser/android/system_ui_resource_manager_impl.h54
-rw-r--r--chromium/content/browser/android/system_ui_resource_manager_impl_unittest.cc169
-rw-r--r--chromium/content/browser/android/tracing_controller_android.cc22
-rw-r--r--chromium/content/browser/android/tracing_controller_android.h4
-rw-r--r--chromium/content/browser/android/ui_resource_provider_impl.cc14
-rw-r--r--chromium/content/browser/android/ui_resource_provider_impl.h15
-rw-r--r--chromium/content/browser/android/web_contents_observer_android.cc133
-rw-r--r--chromium/content/browser/android/web_contents_observer_android.h62
-rw-r--r--chromium/content/browser/appcache/DEPS3
-rw-r--r--chromium/content/browser/appcache/appcache.cc327
-rw-r--r--chromium/content/browser/appcache/appcache.h210
-rw-r--r--chromium/content/browser/appcache/appcache_backend_impl.cc182
-rw-r--r--chromium/content/browser/appcache/appcache_backend_impl.h75
-rw-r--r--chromium/content/browser/appcache/appcache_database.cc1228
-rw-r--r--chromium/content/browser/appcache/appcache_database.h251
-rw-r--r--chromium/content/browser/appcache/appcache_database_unittest.cc20
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache.cc372
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache.h115
-rw-r--r--chromium/content/browser/appcache/appcache_disk_cache_unittest.cc28
-rw-r--r--chromium/content/browser/appcache/appcache_dispatcher_host.cc12
-rw-r--r--chromium/content/browser/appcache/appcache_dispatcher_host.h22
-rw-r--r--chromium/content/browser/appcache/appcache_entry.h67
-rw-r--r--chromium/content/browser/appcache/appcache_executable_handler.h54
-rw-r--r--chromium/content/browser/appcache/appcache_frontend_proxy.cc12
-rw-r--r--chromium/content/browser/appcache/appcache_frontend_proxy.h35
-rw-r--r--chromium/content/browser/appcache/appcache_group.cc264
-rw-r--r--chromium/content/browser/appcache/appcache_group.h173
-rw-r--r--chromium/content/browser/appcache/appcache_group_unittest.cc95
-rw-r--r--chromium/content/browser/appcache/appcache_histograms.cc154
-rw-r--r--chromium/content/browser/appcache/appcache_histograms.h63
-rw-r--r--chromium/content/browser/appcache/appcache_host.cc552
-rw-r--r--chromium/content/browser/appcache/appcache_host.h341
-rw-r--r--chromium/content/browser/appcache/appcache_host_unittest.cc127
-rw-r--r--chromium/content/browser/appcache/appcache_interceptor.cc64
-rw-r--r--chromium/content/browser/appcache/appcache_interceptor.h39
-rw-r--r--chromium/content/browser/appcache/appcache_manifest_parser.cc382
-rw-r--r--chromium/content/browser/appcache/appcache_manifest_parser.h72
-rw-r--r--chromium/content/browser/appcache/appcache_manifest_parser_unittest.cc (renamed from chromium/content/browser/appcache/manifest_parser_unittest.cc)52
-rw-r--r--chromium/content/browser/appcache/appcache_policy.h32
-rw-r--r--chromium/content/browser/appcache/appcache_quota_client.cc251
-rw-r--r--chromium/content/browser/appcache/appcache_quota_client.h94
-rw-r--r--chromium/content/browser/appcache/appcache_quota_client_unittest.cc93
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler.cc417
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler.h151
-rw-r--r--chromium/content/browser/appcache/appcache_request_handler_unittest.cc216
-rw-r--r--chromium/content/browser/appcache/appcache_response.cc423
-rw-r--r--chromium/content/browser/appcache/appcache_response.h262
-rw-r--r--chromium/content/browser/appcache/appcache_response_unittest.cc17
-rw-r--r--chromium/content/browser/appcache/appcache_service_impl.cc580
-rw-r--r--chromium/content/browser/appcache/appcache_service_impl.h222
-rw-r--r--chromium/content/browser/appcache/appcache_service_unittest.cc25
-rw-r--r--chromium/content/browser/appcache/appcache_storage.cc139
-rw-r--r--chromium/content/browser/appcache/appcache_storage.h327
-rw-r--r--chromium/content/browser/appcache/appcache_storage_impl.cc1866
-rw-r--r--chromium/content/browser/appcache/appcache_storage_impl.h183
-rw-r--r--chromium/content/browser/appcache/appcache_storage_impl_unittest.cc255
-rw-r--r--chromium/content/browser/appcache/appcache_storage_unittest.cc16
-rw-r--r--chromium/content/browser/appcache/appcache_unittest.cc126
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.cc1636
-rw-r--r--chromium/content/browser/appcache/appcache_update_job.h346
-rw-r--r--chromium/content/browser/appcache/appcache_update_job_unittest.cc117
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job.cc449
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job.h175
-rw-r--r--chromium/content/browser/appcache/appcache_url_request_job_unittest.cc74
-rw-r--r--chromium/content/browser/appcache/appcache_working_set.cc80
-rw-r--r--chromium/content/browser/appcache/appcache_working_set.h76
-rw-r--r--chromium/content/browser/appcache/chrome_appcache_service.cc11
-rw-r--r--chromium/content/browser/appcache/chrome_appcache_service.h24
-rw-r--r--chromium/content/browser/appcache/chrome_appcache_service_unittest.cc20
-rw-r--r--chromium/content/browser/appcache/mock_appcache_policy.h12
-rw-r--r--chromium/content/browser/appcache/mock_appcache_service.h12
-rw-r--r--chromium/content/browser/appcache/mock_appcache_storage.cc17
-rw-r--r--chromium/content/browser/appcache/mock_appcache_storage.h81
-rw-r--r--chromium/content/browser/appcache/mock_appcache_storage_unittest.cc69
-rw-r--r--chromium/content/browser/appcache/view_appcache_internals_job.cc111
-rw-r--r--chromium/content/browser/appcache/view_appcache_internals_job.h9
-rw-r--r--chromium/content/browser/battery_status/OWNERS1
-rw-r--r--chromium/content/browser/battery_status/battery_status_browsertest.cc76
-rw-r--r--chromium/content/browser/battery_status/battery_status_manager.h57
-rw-r--r--chromium/content/browser/battery_status/battery_status_manager_android.cc56
-rw-r--r--chromium/content/browser/battery_status/battery_status_manager_default.cc31
-rw-r--r--chromium/content/browser/battery_status/battery_status_message_filter.cc56
-rw-r--r--chromium/content/browser/battery_status/battery_status_message_filter.h4
-rw-r--r--chromium/content/browser/battery_status/battery_status_service.cc106
-rw-r--r--chromium/content/browser/battery_status/battery_status_service.h66
-rw-r--r--chromium/content/browser/battery_status/battery_status_service_unittest.cc193
-rw-r--r--chromium/content/browser/bootstrap_sandbox_mac.cc78
-rw-r--r--chromium/content/browser/browser_child_process_host_impl.cc59
-rw-r--r--chromium/content/browser/browser_child_process_host_impl.h52
-rw-r--r--chromium/content/browser/browser_context.cc55
-rw-r--r--chromium/content/browser/browser_main_loop.cc195
-rw-r--r--chromium/content/browser/browser_main_loop.h29
-rw-r--r--chromium/content/browser/browser_main_runner.cc156
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_embedder.cc114
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_embedder.h37
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_guest.cc599
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_guest.h178
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_message_filter.cc57
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_message_filter.h13
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h11
-rw-r--r--chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.mm5
-rw-r--r--chromium/content/browser/browser_process_sub_thread.h6
-rw-r--r--chromium/content/browser/browser_shutdown_profile_dumper.cc30
-rw-r--r--chromium/content/browser/browser_shutdown_profile_dumper.h14
-rw-r--r--chromium/content/browser/browser_thread_impl.cc21
-rw-r--r--chromium/content/browser/browser_thread_impl.h10
-rw-r--r--chromium/content/browser/browser_thread_unittest.cc4
-rw-r--r--chromium/content/browser/browser_url_handler_impl.cc21
-rw-r--r--chromium/content/browser/browser_url_handler_impl.h12
-rw-r--r--chromium/content/browser/browser_url_handler_impl_unittest.cc15
-rw-r--r--chromium/content/browser/byte_stream.cc22
-rw-r--r--chromium/content/browser/cert_store_impl.h10
-rw-r--r--chromium/content/browser/child_process_launcher.cc177
-rw-r--r--chromium/content/browser/child_process_launcher.h5
-rw-r--r--chromium/content/browser/child_process_launcher_browsertest.cc25
-rw-r--r--chromium/content/browser/child_process_security_policy_browsertest.cc4
-rw-r--r--chromium/content/browser/child_process_security_policy_impl.cc57
-rw-r--r--chromium/content/browser/child_process_security_policy_impl.h110
-rw-r--r--chromium/content/browser/child_process_security_policy_unittest.cc66
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_helper_mac.h56
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_helper_mac.mm77
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_map.h66
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_map.mm165
-rw-r--r--chromium/content/browser/cocoa/system_hotkey_map_unittest.mm196
-rw-r--r--chromium/content/browser/compositor/OWNERS3
-rw-r--r--chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h136
-rw-r--r--chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm406
-rw-r--r--chromium/content/browser/compositor/browser_compositor_output_surface.cc22
-rw-r--r--chromium/content/browser/compositor/browser_compositor_output_surface.h11
-rw-r--r--chromium/content/browser/compositor/browser_compositor_view_mac.h121
-rw-r--r--chromium/content/browser/compositor/browser_compositor_view_mac.mm296
-rw-r--r--chromium/content/browser/compositor/buffer_queue.cc176
-rw-r--r--chromium/content/browser/compositor/buffer_queue.h90
-rw-r--r--chromium/content/browser/compositor/buffer_queue_unittest.cc288
-rw-r--r--chromium/content/browser/compositor/delegated_frame_host.cc331
-rw-r--r--chromium/content/browser/compositor/delegated_frame_host.h80
-rw-r--r--chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc73
-rw-r--r--chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h19
-rw-r--r--chromium/content/browser/compositor/gpu_process_transport_factory.cc194
-rw-r--r--chromium/content/browser/compositor/gpu_process_transport_factory.h53
-rw-r--r--chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc100
-rw-r--r--chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h44
-rw-r--r--chromium/content/browser/compositor/image_transport_factory.cc8
-rw-r--r--chromium/content/browser/compositor/image_transport_factory.h9
-rw-r--r--chromium/content/browser/compositor/image_transport_factory_browsertest.cc10
-rw-r--r--chromium/content/browser/compositor/io_surface_context_mac.h72
-rw-r--r--chromium/content/browser/compositor/io_surface_context_mac.mm121
-rw-r--r--chromium/content/browser/compositor/io_surface_layer_mac.h161
-rw-r--r--chromium/content/browser/compositor/io_surface_layer_mac.mm302
-rw-r--r--chromium/content/browser/compositor/io_surface_texture_mac.h121
-rw-r--r--chromium/content/browser/compositor/io_surface_texture_mac.mm297
-rw-r--r--chromium/content/browser/compositor/no_transport_image_transport_factory.cc53
-rw-r--r--chromium/content/browser/compositor/no_transport_image_transport_factory.h46
-rw-r--r--chromium/content/browser/compositor/onscreen_display_client.cc87
-rw-r--r--chromium/content/browser/compositor/onscreen_display_client.h42
-rw-r--r--chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc1
-rw-r--r--chromium/content/browser/compositor/overlay_candidate_validator_ozone.h2
-rw-r--r--chromium/content/browser/compositor/owned_mailbox.h4
-rw-r--r--chromium/content/browser/compositor/reflector_impl.cc6
-rw-r--r--chromium/content/browser/compositor/reflector_impl.h4
-rw-r--r--chromium/content/browser/compositor/software_browser_compositor_output_surface.cc10
-rw-r--r--chromium/content/browser/compositor/software_browser_compositor_output_surface.h8
-rw-r--r--chromium/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc25
-rw-r--r--chromium/content/browser/compositor/software_layer_mac.h (renamed from chromium/content/browser/renderer_host/software_layer_mac.h)0
-rw-r--r--chromium/content/browser/compositor/software_layer_mac.mm (renamed from chromium/content/browser/renderer_host/software_layer_mac.mm)4
-rw-r--r--chromium/content/browser/compositor/software_output_device_mac.h4
-rw-r--r--chromium/content/browser/compositor/software_output_device_mac.mm9
-rw-r--r--chromium/content/browser/compositor/software_output_device_ozone.cc3
-rw-r--r--chromium/content/browser/compositor/software_output_device_ozone.h6
-rw-r--r--chromium/content/browser/compositor/software_output_device_ozone_unittest.cc33
-rw-r--r--chromium/content/browser/compositor/software_output_device_win.h8
-rw-r--r--chromium/content/browser/compositor/software_output_device_x11.h4
-rw-r--r--chromium/content/browser/compositor/surface_display_output_surface.cc65
-rw-r--r--chromium/content/browser/compositor/surface_display_output_surface.h32
-rw-r--r--chromium/content/browser/cross_site_request_manager.cc42
-rw-r--r--chromium/content/browser/cross_site_request_manager.h64
-rw-r--r--chromium/content/browser/cross_site_transfer_browsertest.cc30
-rw-r--r--chromium/content/browser/database_browsertest.cc1
-rw-r--r--chromium/content/browser/database_quota_client_unittest.cc75
-rw-r--r--chromium/content/browser/database_tracker_unittest.cc106
-rw-r--r--chromium/content/browser/database_util_unittest.cc10
-rw-r--r--chromium/content/browser/databases_table_unittest.cc6
-rw-r--r--chromium/content/browser/device_monitor_mac.mm224
-rw-r--r--chromium/content/browser/device_monitor_udev.h4
-rw-r--r--chromium/content/browser/device_sensors/OWNERS1
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory.h14
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_android.cc7
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc17
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.h4
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc142
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_default.cc18
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_win.cc18
-rw-r--r--chromium/content/browser/device_sensors/device_inertial_sensor_browsertest.cc109
-rw-r--r--chromium/content/browser/device_sensors/device_inertial_sensor_service.cc16
-rw-r--r--chromium/content/browser/device_sensors/device_inertial_sensor_service.h1
-rw-r--r--chromium/content/browser/device_sensors/device_light_message_filter.cc60
-rw-r--r--chromium/content/browser/device_sensors/device_light_message_filter.h33
-rw-r--r--chromium/content/browser/device_sensors/device_motion_message_filter.h4
-rw-r--r--chromium/content/browser/device_sensors/device_orientation_message_filter.h4
-rw-r--r--chromium/content/browser/device_sensors/inertial_sensor_consts.h19
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_android.cc95
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_android.h28
-rw-r--r--chromium/content/browser/device_sensors/sensor_manager_android_unittest.cc30
-rw-r--r--chromium/content/browser/devtools/BUILD.gn74
-rw-r--r--chromium/content/browser/devtools/OWNERS2
-rw-r--r--chromium/content/browser/devtools/browser_protocol.json34
-rw-r--r--chromium/content/browser/devtools/devtools.gyp44
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.cc138
-rw-r--r--chromium/content/browser/devtools/devtools_agent_host_impl.h51
-rw-r--r--chromium/content/browser/devtools/devtools_browser_target.cc180
-rw-r--r--chromium/content/browser/devtools/devtools_browser_target.h75
-rw-r--r--chromium/content/browser/devtools/devtools_frontend_host.cc96
-rw-r--r--chromium/content/browser/devtools/devtools_frontend_host.h51
-rw-r--r--chromium/content/browser/devtools/devtools_frontend_host_impl.cc56
-rw-r--r--chromium/content/browser/devtools/devtools_frontend_host_impl.h33
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler_impl.cc396
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler_impl.h53
-rw-r--r--chromium/content/browser/devtools/devtools_http_handler_unittest.cc125
-rw-r--r--chromium/content/browser/devtools/devtools_manager.cc130
-rw-r--r--chromium/content/browser/devtools/devtools_manager.h80
-rw-r--r--chromium/content/browser/devtools/devtools_manager_impl.cc202
-rw-r--r--chromium/content/browser/devtools/devtools_manager_impl.h113
-rw-r--r--chromium/content/browser/devtools/devtools_manager_unittest.cc338
-rw-r--r--chromium/content/browser/devtools/devtools_netlog_observer.h4
-rw-r--r--chromium/content/browser/devtools/devtools_power_handler.cc83
-rw-r--r--chromium/content/browser/devtools/devtools_power_handler.h38
-rw-r--r--chromium/content/browser/devtools/devtools_protocol.cc7
-rw-r--r--chromium/content/browser/devtools/devtools_protocol.h10
-rw-r--r--chromium/content/browser/devtools/devtools_system_info_handler.cc30
-rw-r--r--chromium/content/browser/devtools/devtools_system_info_handler.h2
-rw-r--r--chromium/content/browser/devtools/devtools_tracing_handler.cc248
-rw-r--r--chromium/content/browser/devtools/devtools_tracing_handler.h63
-rw-r--r--chromium/content/browser/devtools/embedded_worker_devtools_agent_host.cc232
-rw-r--r--chromium/content/browser/devtools/embedded_worker_devtools_agent_host.h84
-rw-r--r--chromium/content/browser/devtools/embedded_worker_devtools_manager.cc348
-rw-r--r--chromium/content/browser/devtools/embedded_worker_devtools_manager.h81
-rw-r--r--chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc178
-rw-r--r--chromium/content/browser/devtools/forwarding_agent_host.cc29
-rw-r--r--chromium/content/browser/devtools/forwarding_agent_host.h19
-rw-r--r--chromium/content/browser/devtools/ipc_devtools_agent_host.cc31
-rw-r--r--chromium/content/browser/devtools/ipc_devtools_agent_host.h17
-rw-r--r--chromium/content/browser/devtools/protocol/color_picker.cc265
-rw-r--r--chromium/content/browser/devtools/protocol/color_picker.h57
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_client.cc97
-rw-r--r--chromium/content/browser/devtools/protocol/devtools_protocol_client.h75
-rwxr-xr-xchromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py776
-rw-r--r--chromium/content/browser/devtools/protocol/dom_handler.cc47
-rw-r--r--chromium/content/browser/devtools/protocol/dom_handler.h38
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.cc111
-rw-r--r--chromium/content/browser/devtools/protocol/input_handler.h46
-rw-r--r--chromium/content/browser/devtools/protocol/inspector_handler.cc23
-rw-r--r--chromium/content/browser/devtools/protocol/inspector_handler.h31
-rw-r--r--chromium/content/browser/devtools/protocol/network_handler.cc52
-rw-r--r--chromium/content/browser/devtools/protocol/network_handler.h45
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.cc615
-rw-r--r--chromium/content/browser/devtools/protocol/page_handler.h135
-rw-r--r--chromium/content/browser/devtools/protocol/power_handler.cc86
-rw-r--r--chromium/content/browser/devtools/protocol/power_handler.h45
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.cc215
-rw-r--r--chromium/content/browser/devtools/protocol/tracing_handler.h77
-rw-r--r--chromium/content/browser/devtools/protocol/usage_and_quota_query.cc136
-rw-r--r--chromium/content/browser/devtools/protocol/usage_and_quota_query.h55
-rw-r--r--chromium/content/browser/devtools/protocol/worker_handler.cc30
-rw-r--r--chromium/content/browser/devtools/protocol/worker_handler.h35
-rw-r--r--chromium/content/browser/devtools/render_view_devtools_agent_host.cc275
-rw-r--r--chromium/content/browser/devtools/render_view_devtools_agent_host.h89
-rw-r--r--chromium/content/browser/devtools/renderer_overrides_handler.cc1007
-rw-r--r--chromium/content/browser/devtools/renderer_overrides_handler.h119
-rw-r--r--chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc102
-rw-r--r--chromium/content/browser/devtools/tethering_handler.cc263
-rw-r--r--chromium/content/browser/devtools/tethering_handler.h26
-rw-r--r--chromium/content/browser/devtools/worker_devtools_manager.cc453
-rw-r--r--chromium/content/browser/devtools/worker_devtools_manager.h110
-rw-r--r--chromium/content/browser/devtools/worker_devtools_message_filter.cc49
-rw-r--r--chromium/content/browser/devtools/worker_devtools_message_filter.h34
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_area.cc12
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_area_unittest.cc6
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_browsertest.cc1
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_impl.cc12
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_impl.h13
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_impl_unittest.cc8
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc2
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_context_wrapper.h30
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_database.cc2
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_database_unittest.cc11
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_message_filter.h39
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_namespace.cc24
-rw-r--r--chromium/content/browser/dom_storage/dom_storage_task_runner.h40
-rw-r--r--chromium/content/browser/dom_storage/local_storage_database_adapter.cc2
-rw-r--r--chromium/content/browser/dom_storage/local_storage_database_adapter.h12
-rw-r--r--chromium/content/browser/dom_storage/session_storage_database.cc2
-rw-r--r--chromium/content/browser/dom_storage/session_storage_database_adapter.h9
-rw-r--r--chromium/content/browser/dom_storage/session_storage_database_unittest.cc6
-rw-r--r--chromium/content/browser/dom_storage/session_storage_namespace_impl.cc5
-rw-r--r--chromium/content/browser/dom_storage/session_storage_namespace_impl.h26
-rw-r--r--chromium/content/browser/download/base_file.cc22
-rw-r--r--chromium/content/browser/download/base_file.h14
-rw-r--r--chromium/content/browser/download/base_file_posix.cc4
-rw-r--r--chromium/content/browser/download/base_file_unittest.cc72
-rw-r--r--chromium/content/browser/download/base_file_win.cc43
-rw-r--r--chromium/content/browser/download/download_browsertest.cc131
-rw-r--r--chromium/content/browser/download/download_create_info.cc4
-rw-r--r--chromium/content/browser/download/download_create_info.h6
-rw-r--r--chromium/content/browser/download/download_file_impl.cc131
-rw-r--r--chromium/content/browser/download/download_file_impl.h59
-rw-r--r--chromium/content/browser/download/download_file_unittest.cc344
-rw-r--r--chromium/content/browser/download/download_interrupt_reasons_impl.cc29
-rw-r--r--chromium/content/browser/download/download_interrupt_reasons_impl.h5
-rw-r--r--chromium/content/browser/download/download_item_impl.cc15
-rw-r--r--chromium/content/browser/download/download_item_impl.h150
-rw-r--r--chromium/content/browser/download/download_item_impl_unittest.cc28
-rw-r--r--chromium/content/browser/download/download_manager_impl.cc23
-rw-r--r--chromium/content/browser/download/download_manager_impl.h70
-rw-r--r--chromium/content/browser/download/download_manager_impl_unittest.cc31
-rw-r--r--chromium/content/browser/download/download_net_log_parameters.cc5
-rw-r--r--chromium/content/browser/download/download_request_handle.h14
-rw-r--r--chromium/content/browser/download/download_resource_handler.cc14
-rw-r--r--chromium/content/browser/download/download_resource_handler.h34
-rw-r--r--chromium/content/browser/download/download_stats.cc12
-rw-r--r--chromium/content/browser/download/download_stats.h5
-rw-r--r--chromium/content/browser/download/drag_download_file.cc6
-rw-r--r--chromium/content/browser/download/drag_download_file.h8
-rw-r--r--chromium/content/browser/download/drag_download_file_browsertest.cc23
-rw-r--r--chromium/content/browser/download/drag_download_util.h6
-rw-r--r--chromium/content/browser/download/file_metadata_linux.cc2
-rw-r--r--chromium/content/browser/download/file_metadata_unittest_linux.cc4
-rw-r--r--chromium/content/browser/download/mhtml_generation_browsertest.cc4
-rw-r--r--chromium/content/browser/download/mhtml_generation_manager.cc13
-rw-r--r--chromium/content/browser/download/save_file_manager.cc2
-rw-r--r--chromium/content/browser/download/save_file_resource_handler.cc5
-rw-r--r--chromium/content/browser/download/save_file_resource_handler.h33
-rw-r--r--chromium/content/browser/download/save_package.cc30
-rw-r--r--chromium/content/browser/download/save_package.h7
-rw-r--r--chromium/content/browser/download/save_package_browsertest.cc2
-rw-r--r--chromium/content/browser/download/save_package_unittest.cc36
-rw-r--r--chromium/content/browser/file_descriptor_info_impl.cc69
-rw-r--r--chromium/content/browser/file_descriptor_info_impl.h39
-rw-r--r--chromium/content/browser/file_descriptor_info_impl_unittest.cc86
-rw-r--r--chromium/content/browser/fileapi/OWNERS3
-rw-r--r--chromium/content/browser/fileapi/blob_storage_context_unittest.cc6
-rw-r--r--chromium/content/browser/fileapi/blob_storage_host.cc8
-rw-r--r--chromium/content/browser/fileapi/blob_storage_host.h8
-rw-r--r--chromium/content/browser/fileapi/blob_url_request_job_unittest.cc52
-rw-r--r--chromium/content/browser/fileapi/browser_file_system_helper.cc46
-rw-r--r--chromium/content/browser/fileapi/browser_file_system_helper.h21
-rw-r--r--chromium/content/browser/fileapi/chrome_blob_storage_context.cc25
-rw-r--r--chromium/content/browser/fileapi/chrome_blob_storage_context.h8
-rw-r--r--chromium/content/browser/fileapi/copy_or_move_file_validator_unittest.cc64
-rw-r--r--chromium/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc134
-rw-r--r--chromium/content/browser/fileapi/dragged_file_util_unittest.cc54
-rw-r--r--chromium/content/browser/fileapi/external_mount_points_unittest.cc284
-rw-r--r--chromium/content/browser/fileapi/file_system_browsertest.cc8
-rw-r--r--chromium/content/browser/fileapi/file_system_context_unittest.cc171
-rw-r--r--chromium/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc80
-rw-r--r--chromium/content/browser/fileapi/file_system_file_stream_reader_unittest.cc37
-rw-r--r--chromium/content/browser/fileapi/file_system_operation_impl_unittest.cc800
-rw-r--r--chromium/content/browser/fileapi/file_system_operation_impl_write_unittest.cc48
-rw-r--r--chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc21
-rw-r--r--chromium/content/browser/fileapi/file_system_quota_client_unittest.cc152
-rw-r--r--chromium/content/browser/fileapi/file_system_url_request_job_unittest.cc83
-rw-r--r--chromium/content/browser/fileapi/file_system_url_unittest.cc18
-rw-r--r--chromium/content/browser/fileapi/file_system_usage_cache_unittest.cc10
-rw-r--r--chromium/content/browser/fileapi/file_writer_delegate_unittest.cc76
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter.cc112
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter.h82
-rw-r--r--chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc24
-rw-r--r--chromium/content/browser/fileapi/isolated_context_unittest.cc53
-rw-r--r--chromium/content/browser/fileapi/local_file_stream_reader_unittest.cc10
-rw-r--r--chromium/content/browser/fileapi/local_file_stream_writer_unittest.cc12
-rw-r--r--chromium/content/browser/fileapi/local_file_util_unittest.cc32
-rw-r--r--chromium/content/browser/fileapi/mock_file_change_observer.cc4
-rw-r--r--chromium/content/browser/fileapi/mock_file_change_observer.h26
-rw-r--r--chromium/content/browser/fileapi/mock_file_update_observer.cc42
-rw-r--r--chromium/content/browser/fileapi/mock_file_update_observer.h50
-rw-r--r--chromium/content/browser/fileapi/mock_url_request_delegate.h7
-rw-r--r--chromium/content/browser/fileapi/native_file_util_unittest.cc14
-rw-r--r--chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc257
-rw-r--r--chromium/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc203
-rw-r--r--chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc53
-rw-r--r--chromium/content/browser/fileapi/sandbox_database_test_helper.cc6
-rw-r--r--chromium/content/browser/fileapi/sandbox_directory_database_unittest.cc10
-rw-r--r--chromium/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc25
-rw-r--r--chromium/content/browser/fileapi/sandbox_file_system_backend_unittest.cc136
-rw-r--r--chromium/content/browser/fileapi/sandbox_isolated_origin_database_unittest.cc8
-rw-r--r--chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc8
-rw-r--r--chromium/content/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc12
-rw-r--r--chromium/content/browser/fileapi/timed_task_helper_unittest.cc4
-rw-r--r--chromium/content/browser/fileapi/transient_file_util_unittest.cc50
-rw-r--r--chromium/content/browser/fileapi/upload_file_system_file_element_reader.cc22
-rw-r--r--chromium/content/browser/fileapi/upload_file_system_file_element_reader.h24
-rw-r--r--chromium/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc30
-rw-r--r--chromium/content/browser/frame_host/OWNERS1
-rw-r--r--chromium/content/browser/frame_host/cross_process_frame_connector.cc27
-rw-r--r--chromium/content/browser/frame_host/cross_process_frame_connector.h11
-rw-r--r--chromium/content/browser/frame_host/cross_site_transferring_request.h2
-rw-r--r--chromium/content/browser/frame_host/debug_urls.cc38
-rw-r--r--chromium/content/browser/frame_host/debug_urls.h9
-rw-r--r--chromium/content/browser/frame_host/frame_accessibility.cc179
-rw-r--r--chromium/content/browser/frame_host/frame_accessibility.h79
-rw-r--r--chromium/content/browser/frame_host/frame_tree.cc173
-rw-r--r--chromium/content/browser/frame_host/frame_tree.h44
-rw-r--r--chromium/content/browser/frame_host/frame_tree_browsertest.cc122
-rw-r--r--chromium/content/browser/frame_host/frame_tree_node.cc13
-rw-r--r--chromium/content/browser/frame_host/frame_tree_node.h4
-rw-r--r--chromium/content/browser/frame_host/frame_tree_unittest.cc68
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl.cc116
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_impl.h156
-rw-r--r--chromium/content/browser/frame_host/interstitial_page_navigator_impl.h11
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_android.cc252
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_android.h39
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_delegate.h3
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl.cc152
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl.h117
-rw-r--r--chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc460
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl.cc8
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl.h112
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc15
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc33
-rw-r--r--chromium/content/browser/frame_host/navigation_entry_screenshot_manager.h6
-rw-r--r--chromium/content/browser/frame_host/navigation_request.cc67
-rw-r--r--chromium/content/browser/frame_host/navigation_request.h74
-rw-r--r--chromium/content/browser/frame_host/navigation_request_info.cc18
-rw-r--r--chromium/content/browser/frame_host/navigation_request_info.h40
-rw-r--r--chromium/content/browser/frame_host/navigator.cc6
-rw-r--r--chromium/content/browser/frame_host/navigator.h58
-rw-r--r--chromium/content/browser/frame_host/navigator_delegate.h19
-rw-r--r--chromium/content/browser/frame_host/navigator_impl.cc542
-rw-r--r--chromium/content/browser/frame_host/navigator_impl.h124
-rw-r--r--chromium/content/browser/frame_host/navigator_impl_unittest.cc480
-rw-r--r--chromium/content/browser/frame_host/popup_menu_helper_mac.h (renamed from chromium/content/browser/renderer_host/popup_menu_helper_mac.h)28
-rw-r--r--chromium/content/browser/frame_host/popup_menu_helper_mac.mm (renamed from chromium/content/browser/renderer_host/popup_menu_helper_mac.mm)25
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_delegate.cc45
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_delegate.h52
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.cc1126
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_impl.h405
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager.cc1124
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager.h304
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager_browsertest.cc79
-rw-r--r--chromium/content/browser/frame_host/render_frame_host_manager_unittest.cc1232
-rw-r--r--chromium/content/browser/frame_host/render_frame_message_filter.h4
-rw-r--r--chromium/content/browser/frame_host/render_frame_proxy_host.cc101
-rw-r--r--chromium/content/browser/frame_host/render_frame_proxy_host.h25
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_child_frame.cc71
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_child_frame.h173
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_child_frame_unittest.cc6
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest.cc223
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest.h168
-rw-r--r--chromium/content/browser/frame_host/render_widget_host_view_guest_unittest.cc9
-rw-r--r--chromium/content/browser/gamepad/canonical_axis_index_list.h16
-rw-r--r--chromium/content/browser/gamepad/canonical_button_index_list.h28
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h2
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.h4
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc46
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h6
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h16
-rw-r--r--chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h4
-rw-r--r--chromium/content/browser/gamepad/gamepad_provider.cc17
-rw-r--r--chromium/content/browser/gamepad/gamepad_provider.h4
-rw-r--r--chromium/content/browser/gamepad/gamepad_provider_unittest.cc14
-rw-r--r--chromium/content/browser/gamepad/gamepad_service.cc21
-rw-r--r--chromium/content/browser/gamepad/gamepad_service.h3
-rw-r--r--chromium/content/browser/gamepad/gamepad_service_unittest.cc130
-rw-r--r--chromium/content/browser/gamepad/gamepad_standard_mappings.cc20
-rw-r--r--chromium/content/browser/gamepad/gamepad_standard_mappings.h53
-rw-r--r--chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc322
-rw-r--r--chromium/content/browser/gamepad/gamepad_standard_mappings_mac.mm381
-rw-r--r--chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc168
-rw-r--r--chromium/content/browser/gamepad/gamepad_test_helpers.cc9
-rw-r--r--chromium/content/browser/gamepad/gamepad_test_helpers.h13
-rw-r--r--chromium/content/browser/gamepad/raw_input_data_fetcher_win.h2
-rw-r--r--chromium/content/browser/gamepad/xbox_data_fetcher_mac.h6
-rw-r--r--chromium/content/browser/geofencing/OWNERS1
-rw-r--r--chromium/content/browser/geofencing/geofencing_dispatcher_host.cc111
-rw-r--r--chromium/content/browser/geofencing/geofencing_dispatcher_host.h58
-rw-r--r--chromium/content/browser/geofencing/geofencing_manager.cc371
-rw-r--r--chromium/content/browser/geofencing/geofencing_manager.h179
-rw-r--r--chromium/content/browser/geofencing/geofencing_manager_unittest.cc414
-rw-r--r--chromium/content/browser/geofencing/geofencing_provider.h44
-rw-r--r--chromium/content/browser/geofencing/geofencing_registration_delegate.h31
-rw-r--r--chromium/content/browser/geofencing/geofencing_service.cc199
-rw-r--r--chromium/content/browser/geofencing/geofencing_service.h105
-rw-r--r--chromium/content/browser/geofencing/geofencing_service_unittest.cc193
-rw-r--r--chromium/content/browser/geolocation/OWNERS1
-rw-r--r--chromium/content/browser/geolocation/empty_wifi_data_provider.cc4
-rw-r--r--chromium/content/browser/geolocation/empty_wifi_data_provider.h12
-rw-r--r--chromium/content/browser/geolocation/geolocation_dispatcher_host.cc193
-rw-r--r--chromium/content/browser/geolocation/geolocation_dispatcher_host.h59
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_impl.h18
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc (renamed from chromium/content/browser/geolocation/geolocation_provider_unittest.cc)16
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_context.cc63
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_context.h58
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_impl.cc155
-rw-r--r--chromium/content/browser/geolocation/geolocation_service_impl.h64
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator_impl.cc15
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator_impl.h20
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc17
-rw-r--r--chromium/content/browser/geolocation/location_provider_android.h10
-rw-r--r--chromium/content/browser/geolocation/location_provider_base.h8
-rw-r--r--chromium/content/browser/geolocation/mock_location_arbitrator.h9
-rw-r--r--chromium/content/browser/geolocation/mock_location_provider.cc4
-rw-r--r--chromium/content/browser/geolocation/mock_location_provider.h10
-rw-r--r--chromium/content/browser/geolocation/network_location_provider.cc35
-rw-r--r--chromium/content/browser/geolocation/network_location_provider.h32
-rw-r--r--chromium/content/browser/geolocation/network_location_provider_unittest.cc62
-rw-r--r--chromium/content/browser/geolocation/network_location_request.cc19
-rw-r--r--chromium/content/browser/geolocation/network_location_request.h10
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider.cc124
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider.h98
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc3
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos.h11
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc6
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_common.h12
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_common_unittest.cc42
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm4
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_linux.cc7
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_linux.h6
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_linux_unittest.cc2
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_mac.cc21
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_mac.h12
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_manager.cc98
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_manager.h98
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_win.cc19
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_win.h8
-rw-r--r--chromium/content/browser/geolocation/wifi_data_provider_win_unittest.cc (renamed from chromium/content/browser/geolocation/wifi_data_provider_unittest_win.cc)8
-rw-r--r--chromium/content/browser/gpu/OWNERS1
-rw-r--r--chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc224
-rw-r--r--chromium/content/browser/gpu/browser_gpu_channel_host_factory.h71
-rw-r--r--chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc250
-rw-r--r--chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h77
-rw-r--r--chromium/content/browser/gpu/compositor_util.cc145
-rw-r--r--chromium/content/browser/gpu/compositor_util.h13
-rw-r--r--chromium/content/browser/gpu/compositor_util_browsertest.cc32
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl.cc10
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl.h55
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private.cc207
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private.h13
-rw-r--r--chromium/content/browser/gpu/gpu_data_manager_impl_private_unittest.cc52
-rw-r--r--chromium/content/browser/gpu/gpu_internals_ui.cc67
-rw-r--r--chromium/content/browser/gpu/gpu_ipc_browsertests.cc10
-rw-r--r--chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.cc94
-rw-r--r--chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.h55
-rw-r--r--chromium/content/browser/gpu/gpu_process_host.cc414
-rw-r--r--chromium/content/browser/gpu/gpu_process_host.h67
-rw-r--r--chromium/content/browser/gpu/gpu_process_host_ui_shim.cc145
-rw-r--r--chromium/content/browser/gpu/gpu_process_host_ui_shim.h17
-rw-r--r--chromium/content/browser/gpu/gpu_surface_tracker.h4
-rw-r--r--chromium/content/browser/gpu/shader_disk_cache.cc34
-rw-r--r--chromium/content/browser/gpu/shader_disk_cache_unittest.cc4
-rw-r--r--chromium/content/browser/gpu/test_support_gpu.gypi2
-rw-r--r--chromium/content/browser/histogram_internals_request_job.cc10
-rw-r--r--chromium/content/browser/histogram_internals_request_job.h10
-rw-r--r--chromium/content/browser/histogram_message_filter.cc2
-rw-r--r--chromium/content/browser/histogram_message_filter.h4
-rw-r--r--chromium/content/browser/histogram_synchronizer.h12
-rw-r--r--chromium/content/browser/host_zoom_map_impl.cc52
-rw-r--r--chromium/content/browser/host_zoom_map_impl.h58
-rw-r--r--chromium/content/browser/indexed_db/OWNERS1
-rw-r--r--chromium/content/browser/indexed_db/indexed_db.h13
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_active_blob_registry.cc2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_active_blob_registry.h21
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_active_blob_registry_unittest.cc55
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store.cc607
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store.h535
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_backing_store_unittest.cc196
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_blob_info.cc4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_blob_info.h8
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_browsertest.cc87
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_callbacks.cc135
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_callbacks.h7
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_class_factory.cc6
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_class_factory.h8
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc156
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_connection.cc10
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_connection.h6
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_context_impl.cc118
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_context_impl.h59
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_cursor.cc4
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_cursor.h5
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database.cc182
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database.h48
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_database_unittest.cc62
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc92
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h98
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory.h119
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_impl.cc (renamed from chromium/content/browser/indexed_db/indexed_db_factory.cc)194
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_impl.h136
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc59
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_fake_backing_store.cc14
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_fake_backing_store.h203
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_index_writer.cc9
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_internals_ui.cc43
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_internals_ui.h2
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc14
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h50
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc13
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_metadata.h11
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_quota_client.cc48
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_quota_client.h45
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_quota_client_unittest.cc55
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction.cc52
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction.h35
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc34
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.h3
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_transaction_unittest.cc58
-rw-r--r--chromium/content/browser/indexed_db/indexed_db_unittest.cc62
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_database.cc131
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_database.h15
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_factory.h33
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_iterator.h3
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc72
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_iterator_impl.h42
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_transaction.cc27
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_transaction.h41
-rw-r--r--chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc10
-rw-r--r--chromium/content/browser/indexed_db/leveldb/mock_leveldb_factory.cc14
-rw-r--r--chromium/content/browser/indexed_db/leveldb/mock_leveldb_factory.h29
-rw-r--r--chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc124
-rw-r--r--chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h9
-rw-r--r--chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h14
-rw-r--r--chromium/content/browser/indexed_db/mock_indexed_db_database_callbacks.h12
-rw-r--r--chromium/content/browser/indexed_db/mock_indexed_db_factory.cc20
-rw-r--r--chromium/content/browser/indexed_db/mock_indexed_db_factory.h85
-rw-r--r--chromium/content/browser/loader/OWNERS1
-rw-r--r--chromium/content/browser/loader/async_resource_handler.cc29
-rw-r--r--chromium/content/browser/loader/async_resource_handler.h38
-rw-r--r--chromium/content/browser/loader/buffered_resource_handler.cc9
-rw-r--r--chromium/content/browser/loader/buffered_resource_handler.h29
-rw-r--r--chromium/content/browser/loader/certificate_resource_handler.cc9
-rw-r--r--chromium/content/browser/loader/certificate_resource_handler.h35
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler.cc203
-rw-r--r--chromium/content/browser/loader/cross_site_resource_handler.h55
-rw-r--r--chromium/content/browser/loader/detachable_resource_handler.cc19
-rw-r--r--chromium/content/browser/loader/detachable_resource_handler.h43
-rw-r--r--chromium/content/browser/loader/layered_resource_handler.cc9
-rw-r--r--chromium/content/browser/loader/layered_resource_handler.h36
-rw-r--r--chromium/content/browser/loader/navigation_resource_handler.cc149
-rw-r--r--chromium/content/browser/loader/navigation_resource_handler.h60
-rw-r--r--chromium/content/browser/loader/navigation_url_loader.cc37
-rw-r--r--chromium/content/browser/loader/navigation_url_loader.h62
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_delegate.h52
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_factory.h36
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl.cc76
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl.h66
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl_core.cc104
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_impl_core.h75
-rw-r--r--chromium/content/browser/loader/navigation_url_loader_unittest.cc389
-rw-r--r--chromium/content/browser/loader/power_save_block_resource_throttle.h8
-rw-r--r--chromium/content/browser/loader/redirect_to_file_resource_handler.cc15
-rw-r--r--chromium/content/browser/loader/redirect_to_file_resource_handler.h32
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc39
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.cc616
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_impl.h105
-rw-r--r--chromium/content/browser/loader/resource_dispatcher_host_unittest.cc367
-rw-r--r--chromium/content/browser/loader/resource_handler.h3
-rw-r--r--chromium/content/browser/loader/resource_loader.cc79
-rw-r--r--chromium/content/browser/loader/resource_loader.h52
-rw-r--r--chromium/content/browser/loader/resource_loader_unittest.cc101
-rw-r--r--chromium/content/browser/loader/resource_message_filter.cc4
-rw-r--r--chromium/content/browser/loader/resource_message_filter.h34
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.cc49
-rw-r--r--chromium/content/browser/loader/resource_request_info_impl.h72
-rw-r--r--chromium/content/browser/loader/resource_scheduler.cc607
-rw-r--r--chromium/content/browser/loader/resource_scheduler.h113
-rw-r--r--chromium/content/browser/loader/resource_scheduler_filter.cc14
-rw-r--r--chromium/content/browser/loader/resource_scheduler_filter.h4
-rw-r--r--chromium/content/browser/loader/resource_scheduler_unittest.cc1781
-rw-r--r--chromium/content/browser/loader/stream_resource_handler.cc64
-rw-r--r--chromium/content/browser/loader/stream_resource_handler.h48
-rw-r--r--chromium/content/browser/loader/stream_writer.cc82
-rw-r--r--chromium/content/browser/loader/stream_writer.h83
-rw-r--r--chromium/content/browser/loader/sync_resource_handler.cc10
-rw-r--r--chromium/content/browser/loader/sync_resource_handler.h33
-rw-r--r--chromium/content/browser/loader/temporary_file_stream.cc6
-rw-r--r--chromium/content/browser/loader/temporary_file_stream.h12
-rw-r--r--chromium/content/browser/loader/temporary_file_stream_unittest.cc6
-rw-r--r--chromium/content/browser/loader/throttling_resource_handler.cc21
-rw-r--r--chromium/content/browser/loader/throttling_resource_handler.h25
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder.cc36
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder.h16
-rw-r--r--chromium/content/browser/loader/upload_data_stream_builder_unittest.cc91
-rw-r--r--chromium/content/browser/mach_broker_mac.h25
-rw-r--r--chromium/content/browser/mach_broker_mac.mm25
-rw-r--r--chromium/content/browser/manifest/OWNERS1
-rw-r--r--chromium/content/browser/manifest/manifest_browsertest.cc202
-rw-r--r--chromium/content/browser/manifest/manifest_manager_host.cc138
-rw-r--r--chromium/content/browser/manifest/manifest_manager_host.h54
-rw-r--r--chromium/content/browser/media/OWNERS8
-rw-r--r--chromium/content/browser/media/android/browser_demuxer_android.cc6
-rw-r--r--chromium/content/browser/media/android/browser_demuxer_android.h4
-rw-r--r--chromium/content/browser/media/android/browser_media_player_manager.cc101
-rw-r--r--chromium/content/browser/media/android/browser_media_player_manager.h48
-rw-r--r--chromium/content/browser/media/android/media_resource_getter_impl.cc184
-rw-r--r--chromium/content/browser/media/android/media_resource_getter_impl.h38
-rw-r--r--chromium/content/browser/media/audio_stream_monitor.cc162
-rw-r--r--chromium/content/browser/media/audio_stream_monitor.h153
-rw-r--r--chromium/content/browser/media/audio_stream_monitor_unittest.cc297
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager.cc290
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager.h144
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc525
-rw-r--r--chromium/content/browser/media/capture/content_video_capture_device_core.cc41
-rw-r--r--chromium/content/browser/media/capture/content_video_capture_device_core.h21
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device.cc220
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device.h19
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura.cc100
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura.h8
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_aura_unittest.cc8
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_uma_types.h2
-rw-r--r--chromium/content/browser/media/capture/desktop_capture_device_unittest.cc61
-rw-r--r--chromium/content/browser/media/capture/video_capture_oracle.cc376
-rw-r--r--chromium/content/browser/media/capture/video_capture_oracle.h193
-rw-r--r--chromium/content/browser/media/capture/video_capture_oracle_unittest.cc872
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream.cc154
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream.h36
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc101
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_muter.cc152
-rw-r--r--chromium/content/browser/media/capture/web_contents_audio_muter.h43
-rw-r--r--chromium/content/browser/media/capture/web_contents_capture_util.cc30
-rw-r--r--chromium/content/browser/media/capture/web_contents_capture_util.h11
-rw-r--r--chromium/content/browser/media/capture/web_contents_tracker.cc130
-rw-r--r--chromium/content/browser/media/capture/web_contents_tracker.h105
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device.cc341
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device.h36
-rw-r--r--chromium/content/browser/media/capture/web_contents_video_capture_device_unittest.cc151
-rw-r--r--chromium/content/browser/media/cdm/browser_cdm_manager.cc305
-rw-r--r--chromium/content/browser/media/cdm/browser_cdm_manager.h114
-rw-r--r--chromium/content/browser/media/encrypted_media_browsertest.cc77
-rw-r--r--chromium/content/browser/media/media_browsertest.cc122
-rw-r--r--chromium/content/browser/media/media_browsertest.h19
-rw-r--r--chromium/content/browser/media/media_canplaytype_browsertest.cc1141
-rw-r--r--chromium/content/browser/media/media_internals.cc103
-rw-r--r--chromium/content/browser/media/media_internals.h48
-rw-r--r--chromium/content/browser/media/media_internals_handler.h4
-rw-r--r--chromium/content/browser/media/media_internals_proxy.cc3
-rw-r--r--chromium/content/browser/media/media_internals_proxy.h10
-rw-r--r--chromium/content/browser/media/media_internals_ui.cc2
-rw-r--r--chromium/content/browser/media/media_internals_unittest.cc223
-rw-r--r--chromium/content/browser/media/media_source_browsertest.cc20
-rw-r--r--chromium/content/browser/media/media_web_contents_observer.cc83
-rw-r--r--chromium/content/browser/media/media_web_contents_observer.h29
-rw-r--r--chromium/content/browser/media/midi_dispatcher_host.cc43
-rw-r--r--chromium/content/browser/media/midi_dispatcher_host.h12
-rw-r--r--chromium/content/browser/media/midi_host.cc46
-rw-r--r--chromium/content/browser/media/midi_host.h32
-rw-r--r--chromium/content/browser/media/webrtc_aecdump_browsertest.cc233
-rw-r--r--chromium/content/browser/media/webrtc_browsertest.cc318
-rw-r--r--chromium/content/browser/media/webrtc_getusermedia_browsertest.cc125
-rw-r--r--chromium/content/browser/media/webrtc_identity_store.cc2
-rw-r--r--chromium/content/browser/media/webrtc_identity_store.h6
-rw-r--r--chromium/content/browser/media/webrtc_identity_store_backend.cc15
-rw-r--r--chromium/content/browser/media/webrtc_identity_store_backend.h6
-rw-r--r--chromium/content/browser/media/webrtc_identity_store_unittest.cc14
-rw-r--r--chromium/content/browser/media/webrtc_internals.cc41
-rw-r--r--chromium/content/browser/media/webrtc_internals.h50
-rw-r--r--chromium/content/browser/media/webrtc_internals_browsertest.cc33
-rw-r--r--chromium/content/browser/media/webrtc_internals_message_handler.h7
-rw-r--r--chromium/content/browser/media/webrtc_internals_ui.cc2
-rw-r--r--chromium/content/browser/media/webrtc_internals_unittest.cc28
-rw-r--r--chromium/content/browser/media/webrtc_webcam_browsertest.cc102
-rw-r--r--chromium/content/browser/message_port_message_filter.h8
-rw-r--r--chromium/content/browser/mime_registry_message_filter.h9
-rw-r--r--chromium/content/browser/mojo/mojo_application_host.cc22
-rw-r--r--chromium/content/browser/mojo/mojo_application_host.h49
-rw-r--r--chromium/content/browser/mojo/service_registry_android.cc97
-rw-r--r--chromium/content/browser/mojo/service_registry_android.h53
-rw-r--r--chromium/content/browser/net/browser_online_state_observer.h6
-rw-r--r--chromium/content/browser/net/sqlite_persistent_cookie_store.cc45
-rw-r--r--chromium/content/browser/net/sqlite_persistent_cookie_store.h22
-rw-r--r--chromium/content/browser/net/sqlite_persistent_cookie_store_perftest.cc4
-rw-r--r--chromium/content/browser/net/sqlite_persistent_cookie_store_unittest.cc16
-rw-r--r--chromium/content/browser/net/view_blob_internals_job_factory.cc6
-rw-r--r--chromium/content/browser/net/view_blob_internals_job_factory.h9
-rw-r--r--chromium/content/browser/net/view_http_cache_job_factory.cc20
-rw-r--r--chromium/content/browser/net_info_browsertest.cc80
-rw-r--r--chromium/content/browser/notification_service_impl.h8
-rw-r--r--chromium/content/browser/notification_service_impl_unittest.cc6
-rw-r--r--chromium/content/browser/notifications/OWNERS1
-rw-r--r--chromium/content/browser/notifications/notification_message_filter.cc89
-rw-r--r--chromium/content/browser/notifications/notification_message_filter.h58
-rw-r--r--chromium/content/browser/notifications/page_notification_delegate.cc48
-rw-r--r--chromium/content/browser/notifications/page_notification_delegate.h32
-rw-r--r--chromium/content/browser/pepper_flash_settings_helper_impl.h19
-rw-r--r--chromium/content/browser/plugin_browsertest.cc63
-rw-r--r--chromium/content/browser/plugin_content_origin_whitelist.cc61
-rw-r--r--chromium/content/browser/plugin_content_origin_whitelist.h51
-rw-r--r--chromium/content/browser/plugin_data_remover_impl.cc37
-rw-r--r--chromium/content/browser/plugin_data_remover_impl.h4
-rw-r--r--chromium/content/browser/plugin_data_remover_impl_browsertest.cc2
-rw-r--r--chromium/content/browser/plugin_loader_posix.cc12
-rw-r--r--chromium/content/browser/plugin_loader_posix.h8
-rw-r--r--chromium/content/browser/plugin_loader_posix_unittest.cc4
-rw-r--r--chromium/content/browser/plugin_process_host.cc74
-rw-r--r--chromium/content/browser/plugin_process_host.h28
-rw-r--r--chromium/content/browser/plugin_process_host_mac.cc8
-rw-r--r--chromium/content/browser/plugin_service_impl.cc66
-rw-r--r--chromium/content/browser/plugin_service_impl.h100
-rw-r--r--chromium/content/browser/plugin_service_impl_browsertest.cc82
-rw-r--r--chromium/content/browser/power_monitor_message_broadcaster.cc7
-rw-r--r--chromium/content/browser/power_monitor_message_broadcaster.h10
-rw-r--r--chromium/content/browser/power_monitor_message_broadcaster_unittest.cc18
-rw-r--r--chromium/content/browser/power_profiler/power_data_provider.h9
-rw-r--r--chromium/content/browser/power_profiler/power_data_provider_ia_win.h5
-rw-r--r--chromium/content/browser/power_profiler/power_profiler_service.cc15
-rw-r--r--chromium/content/browser/power_profiler/power_profiler_service.h3
-rw-r--r--chromium/content/browser/power_profiler/power_profiler_service_unittest.cc14
-rw-r--r--chromium/content/browser/power_save_blocker_android.cc2
-rw-r--r--chromium/content/browser/power_save_blocker_impl.h2
-rw-r--r--chromium/content/browser/power_save_blocker_win.cc4
-rw-r--r--chromium/content/browser/power_save_blocker_x11.cc4
-rw-r--r--chromium/content/browser/ppapi_plugin_process_host.cc32
-rw-r--r--chromium/content/browser/ppapi_plugin_process_host.h18
-rw-r--r--chromium/content/browser/profiler_controller_impl.h8
-rw-r--r--chromium/content/browser/profiler_message_filter.h6
-rw-r--r--chromium/content/browser/push_messaging/OWNERS2
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_message_filter.cc183
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_message_filter.h76
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_router.cc104
-rw-r--r--chromium/content/browser/push_messaging/push_messaging_router.h68
-rw-r--r--chromium/content/browser/push_messaging_message_filter.cc97
-rw-r--r--chromium/content/browser/push_messaging_message_filter.h54
-rw-r--r--chromium/content/browser/quota/mock_quota_manager.cc19
-rw-r--r--chromium/content/browser/quota/mock_quota_manager.h59
-rw-r--r--chromium/content/browser/quota/mock_quota_manager_proxy.cc2
-rw-r--r--chromium/content/browser/quota/mock_quota_manager_proxy.h42
-rw-r--r--chromium/content/browser/quota/mock_quota_manager_unittest.cc14
-rw-r--r--chromium/content/browser/quota/quota_backend_impl_unittest.cc74
-rw-r--r--chromium/content/browser/quota/quota_database_unittest.cc24
-rw-r--r--chromium/content/browser/quota/quota_manager_unittest.cc158
-rw-r--r--chromium/content/browser/quota/quota_reservation_manager_unittest.cc60
-rw-r--r--chromium/content/browser/quota/quota_temporary_storage_evictor_unittest.cc40
-rw-r--r--chromium/content/browser/quota/storage_monitor_unittest.cc56
-rw-r--r--chromium/content/browser/quota/usage_tracker_unittest.cc52
-rw-r--r--chromium/content/browser/quota_dispatcher_host.cc40
-rw-r--r--chromium/content/browser/quota_dispatcher_host.h19
-rw-r--r--chromium/content/browser/renderer_host/DEPS2
-rw-r--r--chromium/content/browser/renderer_host/OWNERS7
-rw-r--r--chromium/content/browser/renderer_host/clipboard_message_filter.h10
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_context_mac.h88
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_context_mac.mm170
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_layer_mac.h71
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_layer_mac.mm234
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_mac.h331
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_mac.mm970
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_shader_programs_mac.cc448
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h81
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac.cc300
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac.h123
-rw-r--r--chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac_unittest.cc533
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android.cc251
-rw-r--r--chromium/content/browser/renderer_host/compositor_impl_android.h86
-rw-r--r--chromium/content/browser/renderer_host/compositor_resize_lock_aura.cc4
-rw-r--r--chromium/content/browser/renderer_host/compositor_resize_lock_aura.h11
-rw-r--r--chromium/content/browser/renderer_host/database_message_filter.cc34
-rw-r--r--chromium/content/browser/renderer_host/database_message_filter.h42
-rw-r--r--chromium/content/browser/renderer_host/delegated_frame_evictor.h4
-rw-r--r--chromium/content/browser/renderer_host/file_utilities_message_filter.cc2
-rw-r--r--chromium/content/browser/renderer_host/file_utilities_message_filter.h10
-rw-r--r--chromium/content/browser/renderer_host/font_utils_linux.cc260
-rw-r--r--chromium/content/browser/renderer_host/font_utils_linux.h20
-rw-r--r--chromium/content/browser/renderer_host/gamepad_browser_message_filter.h14
-rw-r--r--chromium/content/browser/renderer_host/gpu_message_filter.cc1
-rw-r--r--chromium/content/browser/renderer_host/gpu_message_filter.h8
-rw-r--r--chromium/content/browser/renderer_host/image_transport_factory_android.cc24
-rw-r--r--chromium/content/browser/renderer_host/image_transport_factory_android.h9
-rw-r--r--chromium/content/browser/renderer_host/ime_adapter_android.cc46
-rw-r--r--chromium/content/browser/renderer_host/ime_adapter_android.h5
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_event_queue_unittest.cc26
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_text_selector.cc115
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_text_selector.h72
-rw-r--r--chromium/content/browser/renderer_host/input/gesture_text_selector_unittest.cc223
-rw-r--r--chromium/content/browser/renderer_host/input/input_router.h2
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_config_helper.cc31
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl.cc61
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl.h72
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl_perftest.cc48
-rw-r--r--chromium/content/browser/renderer_host/input/input_router_impl_unittest.cc261
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_ack_handler.h20
-rw-r--r--chromium/content/browser/renderer_host/input/mock_input_router_client.h18
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_android.cc304
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_android.h132
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_android_unittest.cc174
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_web.cc73
-rw-r--r--chromium/content/browser/renderer_host/input/motion_event_web.h45
-rw-r--r--chromium/content/browser/renderer_host/input/selection_event_type.h29
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_controller.cc3
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_controller_unittest.cc143
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_target_android.h12
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc9
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.h20
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.h17
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_pinch_gesture.h6
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc9
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h6
-rw-r--r--chromium/content/browser/renderer_host/input/synthetic_tap_gesture.h6
-rw-r--r--chromium/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc27
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_browsertest.cc20
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator.cc98
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator.h29
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator_client.h3
-rw-r--r--chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc199
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue.cc332
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue.h58
-rw-r--r--chromium/content/browser/renderer_host/input/touch_event_queue_unittest.cc515
-rw-r--r--chromium/content/browser/renderer_host/input/touch_handle.cc267
-rw-r--r--chromium/content/browser/renderer_host/input/touch_handle.h135
-rw-r--r--chromium/content/browser/renderer_host/input/touch_handle_unittest.cc491
-rw-r--r--chromium/content/browser/renderer_host/input/touch_input_browsertest.cc30
-rw-r--r--chromium/content/browser/renderer_host/input/touch_selection_controller.cc423
-rw-r--r--chromium/content/browser/renderer_host/input/touch_selection_controller.h150
-rw-r--r--chromium/content/browser/renderer_host/input/touch_selection_controller_unittest.cc810
-rw-r--r--chromium/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h6
-rw-r--r--chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h6
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_builders_win.cc4
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util.cc105
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util.h4
-rw-r--r--chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc61
-rw-r--r--chromium/content/browser/renderer_host/java/DEPS4
-rw-r--r--chromium/content/browser/renderer_host/java/java_bound_object.cc1040
-rw-r--r--chromium/content/browser/renderer_host/java/java_bound_object.h96
-rw-r--r--chromium/content/browser/renderer_host/java/java_bridge_channel_host.cc95
-rw-r--r--chromium/content/browser/renderer_host/java/java_bridge_channel_host.h52
-rw-r--r--chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc167
-rw-r--r--chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host.h71
-rw-r--r--chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.cc162
-rw-r--r--chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h76
-rw-r--r--chromium/content/browser/renderer_host/java/java_type.cc114
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win.cc152
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win.h38
-rw-r--r--chromium/content/browser/renderer_host/legacy_render_widget_host_win_delegate.h26
-rw-r--r--chromium/content/browser/renderer_host/media/DEPS8
-rw-r--r--chromium/content/browser/renderer_host/media/OWNERS2
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager.cc55
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager.h37
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc4
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_renderer_host.cc184
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_renderer_host.h39
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_sync_writer.cc34
-rw-r--r--chromium/content/browser/renderer_host/media/audio_input_sync_writer.h20
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host.cc145
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host.h16
-rw-r--r--chromium/content/browser/renderer_host/media/audio_renderer_host_unittest.cc36
-rw-r--r--chromium/content/browser/renderer_host/media/audio_sync_reader.cc57
-rw-r--r--chromium/content/browser/renderer_host/media/audio_sync_reader.h16
-rw-r--r--chromium/content/browser/renderer_host/media/device_request_message_filter.cc150
-rw-r--r--chromium/content/browser/renderer_host/media/device_request_message_filter.h81
-rw-r--r--chromium/content/browser/renderer_host/media/device_request_message_filter_unittest.cc213
-rw-r--r--chromium/content/browser/renderer_host/media/media_capture_devices_impl.h6
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.cc84
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.h74
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc151
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.cc261
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager.h81
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_manager_unittest.cc16
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_requester.h14
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.cc7
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.h4
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy.cc155
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy.h48
-rw-r--r--chromium/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc44
-rw-r--r--chromium/content/browser/renderer_host/media/mock_media_observer.h4
-rw-r--r--chromium/content/browser/renderer_host/media/peer_connection_tracker_host.cc41
-rw-r--r--chromium/content/browser/renderer_host/media/peer_connection_tracker_host.h23
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_buffer_pool.cc2
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller.cc174
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller.h24
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_event_handler.h5
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_controller_unittest.cc114
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host.cc49
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host.h52
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_host_unittest.cc95
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.cc185
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager.h78
-rw-r--r--chromium/content/browser/renderer_host/media/video_capture_manager_unittest.cc17
-rw-r--r--chromium/content/browser/renderer_host/media/webrtc_identity_service_host.h4
-rw-r--r--chromium/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc17
-rw-r--r--chromium/content/browser/renderer_host/memory_benchmark_message_filter.h5
-rw-r--r--chromium/content/browser/renderer_host/native_web_keyboard_event.cc2
-rw-r--r--chromium/content/browser/renderer_host/overscroll_controller.cc27
-rw-r--r--chromium/content/browser/renderer_host/overscroll_controller.h5
-rw-r--r--chromium/content/browser/renderer_host/overscroll_controller_delegate.h5
-rw-r--r--chromium/content/browser/renderer_host/p2p/OWNERS2
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc2
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h14
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host.cc341
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host.h52
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc71
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp.h47
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.cc9
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h22
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc12
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc22
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_test_utils.h44
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc12
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_throttler.h8
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp.cc88
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp.h33
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc85
-rw-r--r--chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc102
-rw-r--r--chromium/content/browser/renderer_host/pepper/OWNERS1
-rw-r--r--chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h37
-rw-r--r--chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc18
-rw-r--r--chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.cc10
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.h2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h39
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_io_host.cc27
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_io_host.h15
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.cc6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.h14
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc59
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h34
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host_unittest.cc6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h10
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h16
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc16
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h10
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.cc40
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h55
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_message_filter.h4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.h4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc3
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_network_proxy_host.h6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc17
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.h6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_printing_host.h6
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_printing_host_unittest.cc8
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.h4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_security_helper.cc2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_security_helper.h4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h10
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h10
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font.h55
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_android.cc16
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc159
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.h69
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_linux.cc156
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.cc10
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.h2
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_win.cc4
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_mac.mm412
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_truetype_font_win.cc237
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc126
-rw-r--r--chromium/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h30
-rw-r--r--chromium/content/browser/renderer_host/pepper/quota_reservation.cc36
-rw-r--r--chromium/content/browser/renderer_host/pepper/quota_reservation.h24
-rw-r--r--chromium/content/browser/renderer_host/pepper/quota_reservation_unittest.cc60
-rw-r--r--chromium/content/browser/renderer_host/render_message_filter.cc245
-rw-r--r--chromium/content/browser/renderer_host/render_message_filter.h72
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_browsertest.cc70
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_impl.cc613
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_impl.h204
-rw-r--r--chromium/content/browser/renderer_host/render_process_host_unittest.cc61
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_browsertest.cc7
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_delegate.cc4
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_delegate.h28
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_delegate_view.h53
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_factory.cc10
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_impl.cc632
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_impl.h450
-rw-r--r--chromium/content/browser/renderer_host/render_view_host_unittest.cc120
-rw-r--r--chromium/content/browser/renderer_host/render_widget_helper.cc156
-rw-r--r--chromium/content/browser/renderer_host/render_widget_helper.h82
-rw-r--r--chromium/content/browser/renderer_host/render_widget_helper_mac.mm64
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_browsertest.cc2
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_delegate.cc13
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_delegate.h15
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.cc699
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_impl.h291
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_unittest.cc271
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_android.cc805
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_android.h267
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura.cc566
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura.h407
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc515
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base.cc127
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base.h172
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_base_unittest.cc124
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_browsertest.cc259
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac.h427
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac.mm1189
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm20
-rw-r--r--chromium/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm103
-rw-r--r--chromium/content/browser/renderer_host/render_widget_resize_helper.cc356
-rw-r--r--chromium/content/browser/renderer_host/render_widget_resize_helper.h92
-rw-r--r--chromium/content/browser/renderer_host/sandbox_ipc_linux.cc320
-rw-r--r--chromium/content/browser/renderer_host/sandbox_ipc_linux.h6
-rw-r--r--chromium/content/browser/renderer_host/socket_stream_dispatcher_host.cc307
-rw-r--r--chromium/content/browser/renderer_host/socket_stream_dispatcher_host.h99
-rw-r--r--chromium/content/browser/renderer_host/socket_stream_host.cc107
-rw-r--r--chromium/content/browser/renderer_host/socket_stream_host.h81
-rw-r--r--chromium/content/browser/renderer_host/software_frame_manager.h4
-rw-r--r--chromium/content/browser/renderer_host/software_frame_manager_unittest.cc8
-rw-r--r--chromium/content/browser/renderer_host/text_input_client_mac_unittest.mm2
-rw-r--r--chromium/content/browser/renderer_host/text_input_client_message_filter.h4
-rw-r--r--chromium/content/browser/renderer_host/ui_events_helper.cc31
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aura.cc109
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aura.h4
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aura_unittest.cc75
-rw-r--r--chromium/content/browser/renderer_host/web_input_event_aurax11.cc140
-rw-r--r--chromium/content/browser/renderer_host/websocket_dispatcher_host.cc16
-rw-r--r--chromium/content/browser/renderer_host/websocket_dispatcher_host.h4
-rw-r--r--chromium/content/browser/renderer_host/websocket_dispatcher_host_unittest.cc75
-rw-r--r--chromium/content/browser/renderer_host/websocket_host.cc61
-rw-r--r--chromium/content/browser/renderer_host/websocket_host.h6
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper.cc5
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper.h4
-rw-r--r--chromium/content/browser/resolve_proxy_msg_helper_unittest.cc13
-rw-r--r--chromium/content/browser/resource_context_impl.cc9
-rw-r--r--chromium/content/browser/resources/gpu/gpu_internals.html4
-rw-r--r--chromium/content/browser/resources/gpu/info_view.css6
-rw-r--r--chromium/content/browser/resources/gpu/info_view.js19
-rw-r--r--chromium/content/browser/resources/gpu/timeline_test.html2
-rw-r--r--chromium/content/browser/resources/indexed_db/OWNERS1
-rw-r--r--chromium/content/browser/resources/indexed_db/indexeddb_internals.html10
-rw-r--r--chromium/content/browser/resources/media/OWNERS2
-rw-r--r--chromium/content/browser/resources/media/client_renderer.js61
-rw-r--r--chromium/content/browser/resources/media/disjoint_range_set_test.html2
-rw-r--r--chromium/content/browser/resources/media/dump_creator.js14
-rw-r--r--chromium/content/browser/resources/media/main.js10
-rw-r--r--chromium/content/browser/resources/media/manager.js43
-rw-r--r--chromium/content/browser/resources/media/media_internals.css44
-rw-r--r--chromium/content/browser/resources/media/media_internals.html20
-rw-r--r--chromium/content/browser/resources/media/peer_connection_update_table.js3
-rw-r--r--chromium/content/browser/resources/media/stats_table.js2
-rw-r--r--chromium/content/browser/resources/media/tab_view.js4
-rw-r--r--chromium/content/browser/resources/media/webrtc_internals.css12
-rw-r--r--chromium/content/browser/resources/media/webrtc_internals.js83
-rw-r--r--chromium/content/browser/resources/service_worker/OWNERS2
-rw-r--r--chromium/content/browser/resources/service_worker/serviceworker_internals.css3
-rw-r--r--chromium/content/browser/resources/service_worker/serviceworker_internals.html35
-rw-r--r--chromium/content/browser/resources/service_worker/serviceworker_internals.js55
-rw-r--r--chromium/content/browser/safe_util_win.cc1
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc239
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_delegate_android.cc60
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_delegate_android.h50
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host.cc85
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host.h50
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.cc146
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h72
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.cc49
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.h32
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_provider.h28
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_provider_android.cc51
-rw-r--r--chromium/content/browser/screen_orientation/screen_orientation_provider_android.h34
-rw-r--r--chromium/content/browser/security_exploit_browsertest.cc8
-rw-r--r--chromium/content/browser/service_worker/BUILD.gn3
-rw-r--r--chromium/content/browser/service_worker/OWNERS9
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance.cc151
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance.h46
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc71
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_registry.cc159
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_registry.h36
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_test_helper.cc115
-rw-r--r--chromium/content/browser/service_worker/embedded_worker_test_helper.h27
-rw-r--r--chromium/content/browser/service_worker/service_worker_browsertest.cc448
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache.cc1259
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache.h195
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache.proto48
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_listener.cc459
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_listener.h150
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_quota_client.cc97
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_quota_client.h54
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_storage.cc683
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_storage.h165
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_storage_manager.cc325
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_storage_manager.h144
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_storage_manager_unittest.cc631
-rw-r--r--chromium/content/browser/service_worker/service_worker_cache_unittest.cc796
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_core.cc225
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_core.h106
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler.cc63
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler.h20
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc140
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_unittest.cc261
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_wrapper.cc215
-rw-r--r--chromium/content/browser/service_worker/service_worker_context_wrapper.h74
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc199
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler.h47
-rw-r--r--chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc244
-rw-r--r--chromium/content/browser/service_worker/service_worker_database.cc146
-rw-r--r--chromium/content/browser/service_worker/service_worker_database.h54
-rw-r--r--chromium/content/browser/service_worker/service_worker_database.proto3
-rw-r--r--chromium/content/browser/service_worker/service_worker_database_task_manager.cc71
-rw-r--r--chromium/content/browser/service_worker/service_worker_database_task_manager.h75
-rw-r--r--chromium/content/browser/service_worker/service_worker_database_unittest.cc355
-rw-r--r--chromium/content/browser/service_worker/service_worker_disk_cache.cc7
-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.cc547
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host.h73
-rw-r--r--chromium/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc449
-rw-r--r--chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc44
-rw-r--r--chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h18
-rw-r--r--chromium/content/browser/service_worker/service_worker_handle.cc26
-rw-r--r--chromium/content/browser/service_worker/service_worker_handle.h39
-rw-r--r--chromium/content/browser/service_worker/service_worker_handle_unittest.cc25
-rw-r--r--chromium/content/browser/service_worker/service_worker_histograms.cc30
-rw-r--r--chromium/content/browser/service_worker/service_worker_histograms.h38
-rw-r--r--chromium/content/browser/service_worker/service_worker_info.cc25
-rw-r--r--chromium/content/browser/service_worker/service_worker_info.h13
-rw-r--r--chromium/content/browser/service_worker/service_worker_internals_ui.cc88
-rw-r--r--chromium/content/browser/service_worker/service_worker_internals_ui.h2
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_coordinator.cc13
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_coordinator.h5
-rw-r--r--chromium/content/browser/service_worker/service_worker_job_unittest.cc633
-rw-r--r--chromium/content/browser/service_worker/service_worker_metrics.cc58
-rw-r--r--chromium/content/browser/service_worker/service_worker_metrics.h48
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager.cc113
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager.h42
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc54
-rw-r--r--chromium/content/browser/service_worker/service_worker_proto.gyp5
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host.cc187
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host.h102
-rw-r--r--chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc237
-rw-r--r--chromium/content/browser/service_worker/service_worker_quota_client.cc111
-rw-r--r--chromium/content/browser/service_worker/service_worker_quota_client.h50
-rw-r--r--chromium/content/browser/service_worker/service_worker_read_from_cache_job.cc42
-rw-r--r--chromium/content/browser/service_worker/service_worker_read_from_cache_job.h25
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job.cc533
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job.h123
-rw-r--r--chromium/content/browser/service_worker/service_worker_register_job_base.h8
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration.cc310
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration.h145
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_handle.cc147
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_handle.h84
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_status.cc8
-rw-r--r--chromium/content/browser/service_worker/service_worker_registration_unittest.cc161
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler.cc83
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler.h53
-rw-r--r--chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc158
-rw-r--r--chromium/content/browser/service_worker/service_worker_script_cache_map.cc60
-rw-r--r--chromium/content/browser/service_worker/service_worker_script_cache_map.h28
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage.cc859
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage.h172
-rw-r--r--chromium/content/browser/service_worker/service_worker_storage_unittest.cc739
-rw-r--r--chromium/content/browser/service_worker/service_worker_unregister_job.cc48
-rw-r--r--chromium/content/browser/service_worker/service_worker_unregister_job.h15
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.cc217
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job.h111
-rw-r--r--chromium/content/browser/service_worker/service_worker_url_request_job_unittest.cc116
-rw-r--r--chromium/content/browser/service_worker/service_worker_utils.cc40
-rw-r--r--chromium/content/browser/service_worker/service_worker_utils.h19
-rw-r--r--chromium/content/browser/service_worker/service_worker_utils_unittest.cc85
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.cc239
-rw-r--r--chromium/content/browser/service_worker/service_worker_version.h154
-rw-r--r--chromium/content/browser/service_worker/service_worker_version_unittest.cc220
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job.cc131
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job.h69
-rw-r--r--chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc300
-rw-r--r--chromium/content/browser/session_history_browsertest.cc4
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_host.cc45
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_host.h12
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_instance.h2
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_instance_unittest.cc4
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_message_filter.cc24
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_message_filter.h16
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl.cc40
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl.h14
-rw-r--r--chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc26
-rw-r--r--chromium/content/browser/shared_worker/worker_browsertest.cc145
-rw-r--r--chromium/content/browser/shared_worker/worker_document_set.cc (renamed from chromium/content/browser/worker_host/worker_document_set.cc)4
-rw-r--r--chromium/content/browser/shared_worker/worker_document_set.h (renamed from chromium/content/browser/worker_host/worker_document_set.h)8
-rw-r--r--chromium/content/browser/shared_worker/worker_storage_partition.cc (renamed from chromium/content/browser/worker_host/worker_storage_partition.cc)16
-rw-r--r--chromium/content/browser/shared_worker/worker_storage_partition.h (renamed from chromium/content/browser/worker_host/worker_storage_partition.h)44
-rw-r--r--chromium/content/browser/signed_certificate_timestamp_store_impl.h11
-rw-r--r--chromium/content/browser/site_instance_impl.cc35
-rw-r--r--chromium/content/browser/site_instance_impl.h49
-rw-r--r--chromium/content/browser/site_instance_impl_unittest.cc77
-rw-r--r--chromium/content/browser/site_per_process_browsertest.cc356
-rw-r--r--chromium/content/browser/site_per_process_browsertest.h30
-rw-r--r--chromium/content/browser/speech/audio_encoder.cc12
-rw-r--r--chromium/content/browser/speech/endpointer/endpointer_unittest.cc8
-rw-r--r--chromium/content/browser/speech/google_one_shot_remote_engine.h18
-rw-r--r--chromium/content/browser/speech/google_one_shot_remote_engine_unittest.cc8
-rw-r--r--chromium/content/browser/speech/google_streaming_remote_engine.cc2
-rw-r--r--chromium/content/browser/speech/google_streaming_remote_engine.h23
-rw-r--r--chromium/content/browser/speech/google_streaming_remote_engine_unittest.cc12
-rw-r--r--chromium/content/browser/speech/speech_recognition_browsertest.cc34
-rw-r--r--chromium/content/browser/speech/speech_recognition_dispatcher_host.cc19
-rw-r--r--chromium/content/browser/speech/speech_recognition_dispatcher_host.h46
-rw-r--r--chromium/content/browser/speech/speech_recognition_manager_impl.cc2
-rw-r--r--chromium/content/browser/speech/speech_recognition_manager_impl.h64
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl.cc14
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl.h38
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl_android.h10
-rw-r--r--chromium/content/browser/speech/speech_recognizer_impl_unittest.cc31
-rw-r--r--chromium/content/browser/ssl/ssl_cert_error_handler.cc8
-rw-r--r--chromium/content/browser/ssl/ssl_cert_error_handler.h11
-rw-r--r--chromium/content/browser/ssl/ssl_client_auth_handler.cc111
-rw-r--r--chromium/content/browser/ssl/ssl_client_auth_handler.h58
-rw-r--r--chromium/content/browser/ssl/ssl_error_handler.cc8
-rw-r--r--chromium/content/browser/ssl/ssl_error_handler.h25
-rw-r--r--chromium/content/browser/ssl/ssl_host_state.cc71
-rw-r--r--chromium/content/browser/ssl/ssl_host_state.h84
-rw-r--r--chromium/content/browser/ssl/ssl_host_state_unittest.cc203
-rw-r--r--chromium/content/browser/ssl/ssl_manager.cc15
-rw-r--r--chromium/content/browser/ssl/ssl_manager.h5
-rw-r--r--chromium/content/browser/ssl/ssl_policy.cc59
-rw-r--r--chromium/content/browser/ssl/ssl_policy.h23
-rw-r--r--chromium/content/browser/ssl/ssl_policy_backend.cc34
-rw-r--r--chromium/content/browser/ssl/ssl_policy_backend.h26
-rw-r--r--chromium/content/browser/ssl/ssl_request_info.cc2
-rw-r--r--chromium/content/browser/ssl/ssl_request_info.h8
-rw-r--r--chromium/content/browser/startup_task_runner.cc2
-rw-r--r--chromium/content/browser/startup_task_runner_unittest.cc20
-rw-r--r--chromium/content/browser/storage_partition_impl.cc253
-rw-r--r--chromium/content/browser/storage_partition_impl.h73
-rw-r--r--chromium/content/browser/storage_partition_impl_map.cc60
-rw-r--r--chromium/content/browser/storage_partition_impl_map.h2
-rw-r--r--chromium/content/browser/storage_partition_impl_map_unittest.cc2
-rw-r--r--chromium/content/browser/storage_partition_impl_unittest.cc75
-rw-r--r--chromium/content/browser/streams/stream.cc10
-rw-r--r--chromium/content/browser/streams/stream.h6
-rw-r--r--chromium/content/browser/streams/stream_handle_impl.cc22
-rw-r--r--chromium/content/browser/streams/stream_handle_impl.h18
-rw-r--r--chromium/content/browser/streams/stream_unittest.cc18
-rw-r--r--chromium/content/browser/streams/stream_url_request_job.h21
-rw-r--r--chromium/content/browser/streams/stream_url_request_job_unittest.cc9
-rw-r--r--chromium/content/browser/system_message_window_win_unittest.cc2
-rw-r--r--chromium/content/browser/tcmalloc_internals_request_job.cc6
-rw-r--r--chromium/content/browser/tcmalloc_internals_request_job.h10
-rw-r--r--chromium/content/browser/theme_helper_mac.h8
-rw-r--r--chromium/content/browser/time_zone_monitor_chromeos.cc2
-rw-r--r--chromium/content/browser/time_zone_monitor_linux.cc4
-rw-r--r--chromium/content/browser/time_zone_monitor_mac.mm2
-rw-r--r--chromium/content/browser/time_zone_monitor_win.cc2
-rw-r--r--chromium/content/browser/tracing/BUILD.gn43
-rw-r--r--chromium/content/browser/tracing/DEPS1
-rw-r--r--chromium/content/browser/tracing/etw_system_event_consumer_win.cc2
-rw-r--r--chromium/content/browser/tracing/trace_message_filter.cc16
-rw-r--r--chromium/content/browser/tracing/trace_message_filter.h14
-rw-r--r--chromium/content/browser/tracing/trace_uploader.cc210
-rw-r--r--chromium/content/browser/tracing/trace_uploader.h92
-rw-r--r--chromium/content/browser/tracing/tracing_controller_browsertest.cc172
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.cc400
-rw-r--r--chromium/content/browser/tracing/tracing_controller_impl.h90
-rw-r--r--chromium/content/browser/tracing/tracing_resources.gyp2
-rw-r--r--chromium/content/browser/tracing/tracing_ui.cc243
-rw-r--r--chromium/content/browser/tracing/tracing_ui.h13
-rw-r--r--chromium/content/browser/transition_browsertest.cc191
-rw-r--r--chromium/content/browser/transition_request_manager.cc215
-rw-r--r--chromium/content/browser/transition_request_manager.h139
-rw-r--r--chromium/content/browser/transition_request_manager_unittest.cc106
-rw-r--r--chromium/content/browser/udev_linux.cc20
-rw-r--r--chromium/content/browser/udev_linux.h12
-rw-r--r--chromium/content/browser/utility_process_host_impl.cc46
-rw-r--r--chromium/content/browser/utility_process_host_impl.h31
-rw-r--r--chromium/content/browser/vibration/vibration_message_filter.h4
-rw-r--r--chromium/content/browser/vibration/vibration_provider_android.h4
-rw-r--r--chromium/content/browser/web_contents/OWNERS3
-rw-r--r--chromium/content/browser/web_contents/aura/OWNERS2
-rw-r--r--chromium/content/browser/web_contents/aura/gesture_nav_simple.cc23
-rw-r--r--chromium/content/browser/web_contents/aura/gesture_nav_simple.h15
-rw-r--r--chromium/content/browser/web_contents/aura/image_window_delegate.cc2
-rw-r--r--chromium/content/browser/web_contents/aura/image_window_delegate.h36
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.cc74
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.h22
-rw-r--r--chromium/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc33
-rw-r--r--chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc4
-rw-r--r--chromium/content/browser/web_contents/aura/shadow_layer_delegate.h9
-rw-r--r--chromium/content/browser/web_contents/aura/window_slider.cc8
-rw-r--r--chromium/content/browser/web_contents/aura/window_slider.h18
-rw-r--r--chromium/content/browser/web_contents/aura/window_slider_unittest.cc58
-rw-r--r--chromium/content/browser/web_contents/opened_by_dom_browsertest.cc7
-rw-r--r--chromium/content/browser/web_contents/touch_editable_impl_aura.cc99
-rw-r--r--chromium/content/browser/web_contents/touch_editable_impl_aura.h62
-rw-r--r--chromium/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc166
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.cc330
-rw-r--r--chromium/content/browser/web_contents/web_contents_android.h59
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.cc948
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl.h875
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_browsertest.cc112
-rw-r--r--chromium/content/browser/web_contents/web_contents_impl_unittest.cc951
-rw-r--r--chromium/content/browser/web_contents/web_contents_user_data_unittest.cc6
-rw-r--r--chromium/content/browser/web_contents/web_contents_view.h30
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_android.cc10
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_android.h53
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura.cc363
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura.h170
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_aura_browsertest.cc476
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_guest.cc63
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_guest.h80
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_mac.h114
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_mac.mm153
-rw-r--r--chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm2
-rw-r--r--chromium/content/browser/web_contents/web_drag_dest_mac.mm2
-rw-r--r--chromium/content/browser/web_contents/web_drag_source_mac.mm2
-rw-r--r--chromium/content/browser/webui/content_web_ui_controller_factory.h19
-rw-r--r--chromium/content/browser/webui/generic_handler.cc7
-rw-r--r--chromium/content/browser/webui/generic_handler.h4
-rw-r--r--chromium/content/browser/webui/shared_resources_data_source.cc16
-rw-r--r--chromium/content/browser/webui/shared_resources_data_source.h12
-rw-r--r--chromium/content/browser/webui/url_data_manager.h2
-rw-r--r--chromium/content/browser/webui/url_data_manager_backend.cc70
-rw-r--r--chromium/content/browser/webui/url_data_manager_backend.h10
-rw-r--r--chromium/content/browser/webui/web_ui_controller_factory_registry.h18
-rw-r--r--chromium/content/browser/webui/web_ui_data_source_impl.cc44
-rw-r--r--chromium/content/browser/webui/web_ui_data_source_impl.h41
-rw-r--r--chromium/content/browser/webui/web_ui_data_source_unittest.cc16
-rw-r--r--chromium/content/browser/webui/web_ui_impl.cc6
-rw-r--r--chromium/content/browser/webui/web_ui_impl.h76
-rw-r--r--chromium/content/browser/webui/web_ui_mojo_browsertest.cc99
-rw-r--r--chromium/content/browser/worker.sb12
-rw-r--r--chromium/content/browser/worker_host/OWNERS3
-rw-r--r--chromium/content/browser/worker_host/worker_message_filter.cc75
-rw-r--r--chromium/content/browser/worker_host/worker_message_filter.h56
-rw-r--r--chromium/content/browser/worker_host/worker_process_host.cc830
-rw-r--r--chromium/content/browser/worker_host/worker_process_host.h288
-rw-r--r--chromium/content/browser/worker_host/worker_service_impl.cc600
-rw-r--r--chromium/content/browser/worker_host/worker_service_impl.h121
-rw-r--r--chromium/content/browser/zygote_host/OWNERS3
-rw-r--r--chromium/content/browser/zygote_host/zygote_host_impl_linux.cc48
-rw-r--r--chromium/content/browser/zygote_host/zygote_host_impl_linux.h12
1524 files changed, 97371 insertions, 48014 deletions
diff --git a/chromium/content/browser/BUILD.gn b/chromium/content/browser/BUILD.gn
index d76f458c7c6..a420b9e9826 100644
--- a/chromium/content/browser/BUILD.gn
+++ b/chromium/content/browser/BUILD.gn
@@ -5,10 +5,12 @@
import("//build/config/features.gni")
import("//build/config/ui.gni")
import("//content/browser/browser.gni")
+import("//media/media_options.gni")
source_set("browser") {
- # Only targets in the content tree can depend directly on this target.
- visibility = [ "//content/*" ]
+ # 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" ]
defines = []
libs = []
@@ -17,14 +19,18 @@ source_set("browser") {
# Shared deps. See also non-iOS deps below.
deps = [
"//base",
+ "//base:base_static",
"//content:resources",
- "//content/browser/service_worker:database_proto",
+ "//content/browser/service_worker:proto",
"//content/browser/speech/proto",
+ "//content/public/common:common_sources",
"//crypto",
+ "//device/battery",
"//google_apis",
"//net",
"//skia",
"//sql",
+ "//third_party/npapi",
"//third_party/re2",
"//third_party/WebKit/public:blink_headers",
"//third_party/zlib",
@@ -36,6 +42,8 @@ source_set("browser") {
"//ui/events:gesture_detection",
"//ui/gfx",
"//ui/gfx/geometry",
+ "//ui/gl",
+ "//ui/native_theme",
"//ui/resources",
"//ui/snapshot",
]
@@ -74,41 +82,40 @@ source_set("browser") {
"$root_gen_dir/webkit/grit/devtools_resources_map.cc",
"$root_gen_dir/webkit/grit/devtools_resources_map.h",
"$root_gen_dir/content/browser/tracing/grit/tracing_resources.h",
- "$root_gen_dir/ui/ui_resources/grit/webui_resources_map.cc",
+ "$root_gen_dir/ui/resources/grit/webui_resources_map.cc",
"$root_gen_dir/content/browser/devtools/devtools_protocol_constants.cc",
"$root_gen_dir/content/browser/devtools/devtools_protocol_constants.h",
+ "$root_gen_dir/content/browser/devtools/protocol/devtools_protocol_handler_impl.cc",
+ "$root_gen_dir/content/browser/devtools/protocol/devtools_protocol_handler_impl.h",
], ".")
# Non-iOS deps.
deps += [
+ "//cc",
+ "//cc/surfaces",
+ "//content/app/resources",
+ "//content/app/strings",
"//content/browser/devtools:resources",
"//content/common:mojo_bindings",
- "//cc",
- "//cc:cc_surfaces",
+ "//content/public/common:mojo_bindings",
"//mojo/public/cpp/bindings",
- "//mojo/public/interfaces/service_provider:service_provider",
- "//mojo/public/js/bindings",
+ "//mojo/public/interfaces/application",
+ "//mojo/public/js",
"//net:http_server",
+ "//storage/browser",
+ "//storage/common",
+ "//third_party/WebKit/public:resources",
+ "//third_party/angle:commit_id",
"//third_party/icu",
"//third_party/leveldatabase",
"//third_party/libyuv",
"//ui/resources",
"//ui/surface",
- "//ui/webui/resources",
- "//webkit:resources",
- "//webkit:strings",
- "//webkit/browser:storage",
- "//webkit/common",
- "//webkit/common:storage",
- # TODO(GYP)
- #"//third_party/angle:commit_id",
]
}
configs += [
"//content:content_implementation",
- "//content:libjingle_stub_config", # TODO(GYP) remove when libjingle is ready.
- "//content:webrtc_stub_config", # TODO(GYP) remove when webrtc is ready.
]
if (toolkit_views) {
@@ -122,15 +129,19 @@ source_set("browser") {
]
deps += [ "//third_party/power_gadget" ]
} else {
- sources += [ "power_profiler/power_data_provider_dummy.cc" ]
+ sources += [
+ "power_profiler/power_data_provider_dummy.cc",
+ "file_descriptor_info_impl.cc",
+ "file_descriptor_info_impl.h",
+ ]
sources -= [ "renderer_host/web_input_event_aurawin.cc" ]
}
- if (!is_win && !is_mac && (!is_linux || !use_udev)) {
+ if (!is_win && !is_mac && !is_android && (!is_linux || !use_udev)) {
sources += [ "gamepad/gamepad_platform_data_fetcher.cc" ]
}
- if (enable_printing != 0) {
+ if (enable_basic_printing || enable_print_preview) {
deps += [ "//printing" ]
}
@@ -150,24 +161,25 @@ source_set("browser") {
if (enable_webrtc) {
sources += rebase_path(content_browser_gypi_values.webrtc_browser_sources,
".", "//content")
- # TODO(GYP)
- #deps += [ "//jingle:glue" ]
+ deps += [ "//jingle:jingle_glue" ]
if (is_linux) {
- # TODO(GYP)
- #deps += [ "//third_party/libjingle:libjingle_webrtc" ]
+ deps += [ "//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_aura.cc",
- "media/capture/desktop_capture_device_aura.h",
"media/capture/desktop_capture_device_uma_types.cc",
"media/capture/desktop_capture_device_uma_types.h",
]
+ if (use_aura) {
+ sources += [
+ "media/capture/desktop_capture_device_aura.cc",
+ "media/capture/desktop_capture_device_aura.h",
+ ]
+ }
defines += [ "ENABLE_SCREEN_CAPTURE=1" ]
- # TODO(GYP)
- #deps += [ "//third_party/webrtc/modules:desktop_capture" ]
+ deps += [ "//third_party/webrtc/modules/desktop_capture" ]
}
}
@@ -235,6 +247,9 @@ source_set("browser") {
if (!use_ozone || use_pango) {
sources -= [ "renderer_host/pepper/pepper_truetype_font_list_ozone.cc" ]
}
+ if (!use_pango) {
+ sources -= [ "renderer_host/pepper/pepper_truetype_font_list_pango.cc" ]
+ }
}
if (is_linux && use_aura) {
@@ -243,11 +258,28 @@ source_set("browser") {
if (use_x11) {
configs += [ "//build/config/linux:x11" ]
- } else {
- sources -= [
- "power_save_blocker_x11.cc",
- "renderer_host/web_input_event_aurax11.cc",
- ]
+ }
+
+ # Dealing with power_save_blocker_{x11,ozone}.cc is a little complicated
+ # given the interaction between os_chromeos and the feature flags for X11 and
+ # ozone, so do it all in one spot.
+ if (is_chromeos || !use_ozone) {
+ sources -= [ "power_save_blocker_ozone.cc", ]
+ }
+ if (is_chromeos || !use_x11) {
+ sources -= [ "power_save_blocker_x11.cc", ]
+ }
+
+ # Dealing with *wifi_data_provider_*.cc is also a bit complicated given
+ # android, chromeos, linux and use_dbus.
+ if (is_android) {
+ sources -= [ "geolocation/wifi_data_provider_common.cc" ]
+ }
+ if (is_chromeos || (is_linux && !use_dbus)) {
+ sources -= [ "geolocation/wifi_data_provider_linux.cc" ]
+ }
+ if (is_linux && use_dbus) {
+ sources -= [ "geolocation/empty_wifi_data_provider.cc" ]
}
if (use_pango) {
@@ -258,17 +290,13 @@ source_set("browser") {
sources += rebase_path(content_browser_gypi_values.android_browser_sources,
".", "//content")
sources -= [
- "battery_status/battery_status_manager_default.cc",
"browser_ipc_logging.cc",
"device_sensors/data_fetcher_shared_memory_default.cc",
"font_list_async.cc",
- "geolocation/device_data_provider.cc",
- "geolocation/empty_device_data_provider.cc",
"geolocation/network_location_provider.cc",
"geolocation/network_location_provider.h",
"geolocation/network_location_request.cc",
"geolocation/network_location_request.h",
- "geolocation/wifi_data_provider_common.cc",
"renderer_host/native_web_keyboard_event.cc",
"tracing/tracing_ui.cc",
"tracing/tracing_ui.h",
@@ -296,8 +324,9 @@ source_set("browser") {
"speech/speech_recognizer_impl.h",
]
deps += [
- #"//content:jni_headers", TODO(GYP)
- #"//media", TODO(GYP)
+ "//content/public/android:jni",
+ "//media",
+ "//mojo/android:libsystem_java",
]
libs += [ "jnigraphics" ]
}
@@ -312,27 +341,43 @@ source_set("browser") {
}
if (is_chromeos) {
- sources -= [
- "geolocation/wifi_data_provider_linux.cc",
- "power_save_blocker_ozone.cc",
- "power_save_blocker_x11.cc",
+ deps += [
+ "//chromeos",
+ "//chromeos:power_manager_proto",
]
- deps += [ "//chromeos:power_manager_proto" ]
}
if (use_aura) {
deps += [
"//ui/aura",
"//ui/strings",
+ "//ui/wm",
]
} else { # Not aura.
sources -= [
+ "renderer_host/input/synthetic_gesture_target_aura.cc",
+ "renderer_host/input/synthetic_gesture_target_aura.h",
+ "renderer_host/native_web_keyboard_event_aura.cc",
"renderer_host/render_widget_host_view_aura.cc",
"renderer_host/render_widget_host_view_aura.h",
- "web_contents/touch_editable_impl_aura.cc",
- "web_contents/touch_editable_impl_aura.h",
"renderer_host/ui_events_helper.cc",
"renderer_host/ui_events_helper.h",
+ "renderer_host/web_input_event_aura.cc",
+ "renderer_host/web_input_event_aura.h",
+ "web_contents/aura/gesture_nav_simple.cc",
+ "web_contents/aura/gesture_nav_simple.h",
+ "web_contents/aura/image_window_delegate.cc",
+ "web_contents/aura/image_window_delegate.h",
+ "web_contents/aura/overscroll_navigation_overlay.cc",
+ "web_contents/aura/overscroll_navigation_overlay.h",
+ "web_contents/aura/shadow_layer_delegate.cc",
+ "web_contents/aura/shadow_layer_delegate.h",
+ "web_contents/aura/window_slider.cc",
+ "web_contents/aura/window_slider.h",
+ "web_contents/touch_editable_impl_aura.cc",
+ "web_contents/touch_editable_impl_aura.h",
+ "web_contents/web_contents_view_aura.cc",
+ "web_contents/web_contents_view_aura.h",
]
}
@@ -346,25 +391,35 @@ source_set("browser") {
"compositor/software_output_device_x11.h",
]
}
+
+ if (!use_ozone) {
+ sources -= [
+ "compositor/overlay_candidate_validator_ozone.cc",
+ "compositor/overlay_candidate_validator_ozone.h",
+ "compositor/software_output_device_ozone.cc",
+ "compositor/software_output_device_ozone.h",
+ ]
+ }
deps += [ "//ui/compositor" ]
}
- if (enable_speech_input) {
+ if (enable_web_speech) {
deps += [
"//third_party/flac",
"//third_party/speex",
]
}
- if (is_linux) {
- if (use_dbus) {
- sources -= [
- "geolocation/empty_wifi_data_provider.cc",
- ]
- deps += [ "//dbus" ]
- } else {
- # This will already have gotten removed for all non-Linux cases.
- sources -= [ "geolocation/wifi_data_provider_linux.cc" ]
- }
+ if (is_linux && use_dbus) {
+ deps += [ "//dbus" ]
+ }
+
+ if (enable_browser_cdms) {
+ sources += [
+ "media/cdm/browser_cdm_manager.cc",
+ "media/cdm/browser_cdm_manager.h",
+ "media/media_web_contents_observer.cc",
+ "media/media_web_contents_observer.h",
+ ]
}
}
diff --git a/chromium/content/browser/DEPS b/chromium/content/browser/DEPS
index 1af4237d1f0..c99434f0d7d 100644
--- a/chromium/content/browser/DEPS
+++ b/chromium/content/browser/DEPS
@@ -1,9 +1,12 @@
include_rules = [
+ "+content/app/strings/grit", # For generated headers
"+content/public/browser",
+ "+device/battery", # For battery status service.
"+media/audio", # For audio input for speech input feature.
"+media/base", # For Android JNI registration.
"+media/midi", # For Web MIDI API
"+media/video", # For Video Device monitoring in Mac.
+ "+mojo",
"+sql",
"+ui/webui",
"+win8/util",
@@ -13,6 +16,10 @@ include_rules = [
# above.
"+components/tracing",
+ # In general, //content shouldn't depend on //device.
+ # This is the an exception.
+ "+device/udev_linux", # For udev utility and wrapper library.
+
# Other libraries.
"+third_party/iaccessible2",
"+third_party/isimpledom",
@@ -25,25 +32,30 @@ include_rules = [
"+chromeos",
"+third_party/cros_system_api",
- "-webkit/child",
"-webkit/renderer",
# 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/WebBatteryStatus.h",
+ "+third_party/WebKit/public/platform/WebCircularGeofencingRegion.h",
"+third_party/WebKit/public/platform/WebCursorInfo.h",
"+third_party/WebKit/public/platform/WebGamepad.h",
"+third_party/WebKit/public/platform/WebGamepads.h",
+ "+third_party/WebKit/public/platform/WebGeofencingEventType.h",
"+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
"+third_party/WebKit/public/platform/WebIDBDatabaseException.h",
"+third_party/WebKit/public/platform/WebIDBTypes.h",
"+third_party/WebKit/public/platform/WebReferrerPolicy.h",
+ "+third_party/WebKit/public/platform/WebLockOrientationError.h",
+ "+third_party/WebKit/public/platform/WebNotificationPermission.h",
+ "+third_party/WebKit/public/platform/WebPushPermissionStatus.h",
"+third_party/WebKit/public/platform/WebScreenOrientationLockType.h",
"+third_party/WebKit/public/platform/WebScreenOrientationType.h",
"+third_party/WebKit/public/platform/WebScreenInfo.h",
+ "+third_party/WebKit/public/platform/WebServiceWorkerCacheError.h",
"+third_party/WebKit/public/platform/WebServiceWorkerError.h",
"+third_party/WebKit/public/platform/WebServiceWorkerEventResult.h",
+ "+third_party/WebKit/public/platform/WebServiceWorkerResponseType.h",
"+third_party/WebKit/public/platform/WebServiceWorkerState.h",
"+third_party/WebKit/public/platform/WebString.h",
"+third_party/WebKit/public/platform/WebVibration.h",
@@ -63,13 +75,11 @@ include_rules = [
"+third_party/WebKit/public/web/WebPopupType.h",
"+third_party/WebKit/public/web/WebSerializedScriptValueVersion.h",
"+third_party/WebKit/public/web/WebTextDirection.h",
+ "+third_party/WebKit/public/web/WebTextInputType.h",
# These should be burned down. http://crbug.com/237267
"!third_party/WebKit/public/web/mac/WebInputEventFactory.h",
- "+ui/ozone/ozone_platform.h",
- "+ui/ozone/ozone_switches.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/OWNERS b/chromium/content/browser/OWNERS
index 37b5294c54f..51f5662fd5a 100644
--- a/chromium/content/browser/OWNERS
+++ b/chromium/content/browser/OWNERS
@@ -1,11 +1,7 @@
-sky@chromium.org
-
per-file child_process_security_policy_impl.*=tsepez@chromium.org
per-file child_process_security_policy_impl.*=creis@chromium.org
-per-file child_process_security_policy_impl.*=cevans@chromium.org
per-file child_process_security_unittest.cc=tsepez@chromium.org
per-file child_process_security_unittest.cc=creis@chromium.org
-per-file child_process_security_unittest.cc=cevans@chromium.org
per-file power_save_blocker_chromeos.cc=derat@chromium.org
# Mac Sandbox profiles.
diff --git a/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
new file mode 100644
index 00000000000..5702a33ded3
--- /dev/null
+++ b/chromium/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
@@ -0,0 +1,191 @@
+// 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/frame_host/render_frame_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/accessibility_messages.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/test/accessibility_browser_test_utils.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_tree.h"
+
+namespace content {
+
+class AccessibilityIpcErrorBrowserTest : public ContentBrowserTest {
+ public:
+ AccessibilityIpcErrorBrowserTest() {}
+
+ protected:
+ // Convenience method to get the value of a particular AXNode
+ // attribute as a UTF-8 string.
+ std::string GetAttr(const ui::AXNode* node,
+ const ui::AXStringAttribute attr) {
+ const ui::AXNodeData& data = node->data();
+ for (size_t i = 0; i < data.string_attributes.size(); ++i) {
+ if (data.string_attributes[i].first == attr)
+ return data.string_attributes[i].second;
+ }
+ return std::string();
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityIpcErrorBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(AccessibilityIpcErrorBrowserTest,
+ ResetBrowserAccessibilityManager) {
+ // Create a data url and load it.
+ const char url_str[] =
+ "data:text/html,"
+ "<div aria-live='polite'>"
+ " <p id='p1'>Paragraph One</p>"
+ " <p id='p2'>Paragraph Two</p>"
+ "</div>"
+ "<button id='button'>Button</button>";
+ GURL url(url_str);
+ NavigateToURL(shell(), url);
+
+ // Simulate a condition where the RFH can't create a
+ // BrowserAccessibilityManager - like if there's no view.
+ RenderFrameHostImpl* frame = static_cast<RenderFrameHostImpl*>(
+ shell()->web_contents()->GetMainFrame());
+ frame->set_no_create_browser_accessibility_manager_for_testing(true);
+ ASSERT_EQ(nullptr, frame->GetOrCreateBrowserAccessibilityManager());
+
+ {
+ // Enable accessibility (passing AccessibilityModeComplete to
+ // AccessibilityNotificationWaiter does this automatically) and wait for
+ // the first event.
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_LAYOUT_COMPLETE);
+ waiter.WaitForNotification();
+ }
+
+ // Make sure we still didn't create a BrowserAccessibilityManager.
+ // This means that at least one accessibility IPC was lost.
+ ASSERT_EQ(nullptr, frame->GetOrCreateBrowserAccessibilityManager());
+
+ // Now create a BrowserAccessibilityManager, simulating what would happen
+ // if the RFH's view is created now - but then disallow recreating the
+ // BrowserAccessibilityManager so that we can test that this one gets
+ // destroyed.
+ frame->set_no_create_browser_accessibility_manager_for_testing(false);
+ ASSERT_TRUE(frame->GetOrCreateBrowserAccessibilityManager() != nullptr);
+ frame->set_no_create_browser_accessibility_manager_for_testing(true);
+
+ {
+ // Hide one of the elements on the page, and wait for an accessibility
+ // notification triggered by the hide.
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_LIVE_REGION_CHANGED);
+ ASSERT_TRUE(ExecuteScript(
+ shell()->web_contents(),
+ "document.getElementById('p1').style.display = 'none';"));
+ waiter.WaitForNotification();
+ }
+
+ // Show that accessibility was reset because the frame doesn't have a
+ // BrowserAccessibilityManager anymore.
+ ASSERT_EQ(nullptr, frame->browser_accessibility_manager());
+
+ // Finally, allow creating a new accessibility manager and
+ // ensure that we didn't kill the renderer; we can still send it messages.
+ frame->set_no_create_browser_accessibility_manager_for_testing(false);
+ const ui::AXTree* tree = nullptr;
+ {
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_FOCUS);
+ ASSERT_TRUE(ExecuteScript(
+ shell()->web_contents(),
+ "document.getElementById('button').focus();"));
+ waiter.WaitForNotification();
+ tree = &waiter.GetAXTree();
+ }
+
+ // Get the accessibility tree, ensure it reflects the final state of the
+ // document.
+ const ui::AXNode* root = tree->GetRoot();
+
+ // Use this for debugging if the test fails.
+ VLOG(1) << tree->ToString();
+
+ EXPECT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, root->data().role);
+ ASSERT_EQ(2, root->child_count());
+
+ const ui::AXNode* live_region = root->ChildAtIndex(0);
+ ASSERT_EQ(1, live_region->child_count());
+ EXPECT_EQ(ui::AX_ROLE_DIV, live_region->data().role);
+
+ const ui::AXNode* para = live_region->ChildAtIndex(0);
+ EXPECT_EQ(ui::AX_ROLE_PARAGRAPH, para->data().role);
+
+ const ui::AXNode* button_container = root->ChildAtIndex(1);
+ EXPECT_EQ(ui::AX_ROLE_GROUP, button_container->data().role);
+ ASSERT_EQ(1, button_container->child_count());
+
+ 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);
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityIpcErrorBrowserTest,
+ MultipleBadAccessibilityIPCsKillsRenderer) {
+ // Create a data url and load it.
+ const char url_str[] =
+ "data:text/html,"
+ "<button id='button'>Button</button>";
+ GURL url(url_str);
+ NavigateToURL(shell(), url);
+ RenderFrameHostImpl* frame = static_cast<RenderFrameHostImpl*>(
+ shell()->web_contents()->GetMainFrame());
+
+ {
+ // Enable accessibility (passing AccessibilityModeComplete to
+ // AccessibilityNotificationWaiter does this automatically) and wait for
+ // the first event.
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_LAYOUT_COMPLETE);
+ waiter.WaitForNotification();
+ }
+
+ // Construct a bad accessibility message that BrowserAccessibilityManager
+ // will reject.
+ std::vector<AccessibilityHostMsg_EventParams> bad_accessibility_event_list;
+ bad_accessibility_event_list.push_back(AccessibilityHostMsg_EventParams());
+ bad_accessibility_event_list[0].update.node_id_to_clear = -2;
+
+ // We should be able to reset accessibility |max_iterations-1| times
+ // (see render_frame_host_impl.cc - kMaxAccessibilityResets),
+ // but the subsequent time the renderer should be killed.
+ int max_iterations = RenderFrameHostImpl::kMaxAccessibilityResets;
+
+ for (int iteration = 0; iteration < max_iterations; iteration++) {
+ // Send the browser accessibility the bad message.
+ BrowserAccessibilityManager* manager =
+ frame->GetOrCreateBrowserAccessibilityManager();
+ manager->OnAccessibilityEvents(bad_accessibility_event_list);
+
+ // Now the frame should have deleted the BrowserAccessibilityManager.
+ ASSERT_EQ(nullptr, frame->browser_accessibility_manager());
+
+ if (iteration == max_iterations - 1)
+ break;
+
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete, ui::AX_EVENT_LAYOUT_COMPLETE);
+ waiter.WaitForNotification();
+ }
+
+ // Wait for the renderer to be killed.
+ if (frame->IsRenderFrameLive()) {
+ RenderProcessHostWatcher render_process_watcher(
+ frame->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+ render_process_watcher.Wait();
+ }
+ ASSERT_FALSE(frame->IsRenderFrameLive());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/accessibility_mode_browsertest.cc b/chromium/content/browser/accessibility/accessibility_mode_browsertest.cc
index 5e191bd0b0e..aa54862fa3d 100644
--- a/chromium/content/browser/accessibility/accessibility_mode_browsertest.cc
+++ b/chromium/content/browser/accessibility/accessibility_mode_browsertest.cc
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/accessibility/accessibility_mode_helper.h"
#include "content/browser/renderer_host/render_view_host_impl.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/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
@@ -23,79 +25,98 @@ const char kMinimalPageDataURL[] =
class AccessibilityModeTest : public ContentBrowserTest {
protected:
- WebContents* web_contents() {
- return shell()->web_contents();
- }
-
- RenderWidgetHostImpl* rwhi() {
- RenderWidgetHost* rwh =
- web_contents()->GetRenderWidgetHostView()->GetRenderWidgetHost();
- return RenderWidgetHostImpl::From(rwh);
- }
-
- RenderWidgetHostViewBase* host_view() {
- return static_cast<RenderWidgetHostViewBase*>(
- shell()->web_contents()->GetRenderWidgetHostView());
+ WebContentsImpl* web_contents() {
+ return static_cast<WebContentsImpl*>(shell()->web_contents());
}
void ExpectBrowserAccessibilityManager(bool expect_bam,
std::string message = "") {
if (expect_bam) {
- EXPECT_NE((BrowserAccessibilityManager*)NULL,
- host_view()->GetBrowserAccessibilityManager()) << message;
+ EXPECT_NE(
+ (BrowserAccessibilityManager*)NULL,
+ web_contents()->GetRootBrowserAccessibilityManager()) << message;
} else {
- EXPECT_EQ((BrowserAccessibilityManager*)NULL,
- host_view()->GetBrowserAccessibilityManager()) << message;
+ EXPECT_EQ(
+ (BrowserAccessibilityManager*)NULL,
+ web_contents()->GetRootBrowserAccessibilityManager()) << message;
+ }
+ }
+
+ AccessibilityMode CorrectedAccessibility(AccessibilityMode mode) {
+ return AddAccessibilityModeTo(GetBaseAccessibilityMode(), mode);
+ }
+
+ bool ShouldBeBrowserAccessibilityManager(AccessibilityMode mode) {
+ mode = CorrectedAccessibility(mode);
+ switch (mode) {
+ case AccessibilityModeOff:
+ case AccessibilityModeTreeOnly:
+ return false;
+ case AccessibilityModeComplete:
+ return true;
+ default:
+ NOTREACHED();
}
+ return false;
}
};
IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, AccessibilityModeOff) {
NavigateToURL(shell(), GURL(kMinimalPageDataURL));
- EXPECT_EQ(AccessibilityModeOff, rwhi()->accessibility_mode());
- ExpectBrowserAccessibilityManager(false);
+ EXPECT_EQ(CorrectedAccessibility(AccessibilityModeOff),
+ web_contents()->GetAccessibilityMode());
+ ExpectBrowserAccessibilityManager(
+ ShouldBeBrowserAccessibilityManager(AccessibilityModeOff));
}
IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, AccessibilityModeComplete) {
NavigateToURL(shell(), GURL(kMinimalPageDataURL));
- ASSERT_EQ(AccessibilityModeOff, rwhi()->accessibility_mode());
+ ASSERT_EQ(CorrectedAccessibility(AccessibilityModeOff),
+ web_contents()->GetAccessibilityMode());
AccessibilityNotificationWaiter waiter(shell());
- rwhi()->AddAccessibilityMode(AccessibilityModeComplete);
- EXPECT_EQ(AccessibilityModeComplete, rwhi()->accessibility_mode());
+ web_contents()->AddAccessibilityMode(AccessibilityModeComplete);
+ EXPECT_EQ(AccessibilityModeComplete, web_contents()->GetAccessibilityMode());
waiter.WaitForNotification();
- ExpectBrowserAccessibilityManager(true);
+ ExpectBrowserAccessibilityManager(
+ ShouldBeBrowserAccessibilityManager(AccessibilityModeComplete));
}
IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, AccessibilityModeTreeOnly) {
NavigateToURL(shell(), GURL(kMinimalPageDataURL));
- ASSERT_EQ(AccessibilityModeOff, rwhi()->accessibility_mode());
+ ASSERT_EQ(CorrectedAccessibility(AccessibilityModeOff),
+ web_contents()->GetAccessibilityMode());
AccessibilityNotificationWaiter waiter(shell());
- rwhi()->AddAccessibilityMode(AccessibilityModeTreeOnly);
- EXPECT_EQ(AccessibilityModeTreeOnly, rwhi()->accessibility_mode());
+ web_contents()->AddAccessibilityMode(AccessibilityModeTreeOnly);
+ EXPECT_EQ(CorrectedAccessibility(AccessibilityModeTreeOnly),
+ web_contents()->GetAccessibilityMode());
waiter.WaitForNotification();
// No BrowserAccessibilityManager expected for AccessibilityModeTreeOnly
- ExpectBrowserAccessibilityManager(false);
+ ExpectBrowserAccessibilityManager(
+ ShouldBeBrowserAccessibilityManager(AccessibilityModeTreeOnly));
}
IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, AddingModes) {
NavigateToURL(shell(), GURL(kMinimalPageDataURL));
AccessibilityNotificationWaiter waiter(shell());
- rwhi()->AddAccessibilityMode(AccessibilityModeTreeOnly);
- EXPECT_EQ(AccessibilityModeTreeOnly, rwhi()->accessibility_mode());
+ web_contents()->AddAccessibilityMode(AccessibilityModeTreeOnly);
+ EXPECT_EQ(CorrectedAccessibility(AccessibilityModeTreeOnly),
+ web_contents()->GetAccessibilityMode());
waiter.WaitForNotification();
- ExpectBrowserAccessibilityManager(false,
+ ExpectBrowserAccessibilityManager(ShouldBeBrowserAccessibilityManager(
+ AccessibilityModeTreeOnly),
"Should be no BrowserAccessibilityManager "
"for AccessibilityModeTreeOnly");
AccessibilityNotificationWaiter waiter2(shell());
- rwhi()->AddAccessibilityMode(AccessibilityModeComplete);
- EXPECT_EQ(AccessibilityModeComplete, rwhi()->accessibility_mode());
+ web_contents()->AddAccessibilityMode(AccessibilityModeComplete);
+ EXPECT_EQ(AccessibilityModeComplete, web_contents()->GetAccessibilityMode());
waiter2.WaitForNotification();
- ExpectBrowserAccessibilityManager(true,
+ ExpectBrowserAccessibilityManager(ShouldBeBrowserAccessibilityManager(
+ AccessibilityModeComplete),
"Should be a BrowserAccessibilityManager "
"for AccessibilityModeComplete");
}
diff --git a/chromium/content/browser/accessibility/accessibility_mode_helper.cc b/chromium/content/browser/accessibility/accessibility_mode_helper.cc
index 7988595aa21..9745e63e453 100644
--- a/chromium/content/browser/accessibility/accessibility_mode_helper.cc
+++ b/chromium/content/browser/accessibility/accessibility_mode_helper.cc
@@ -2,14 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/logging.h"
#include "content/browser/accessibility/accessibility_mode_helper.h"
-#if defined(OS_WIN)
-#include "base/command_line.h"
-#include "base/win/windows_version.h"
-#include "content/public/common/content_switches.h"
-#endif
-
namespace content {
namespace {
@@ -19,7 +14,6 @@ AccessibilityMode CastToAccessibilityMode(unsigned int int_mode) {
switch (mode) {
case AccessibilityModeOff:
case AccessibilityModeComplete:
- case AccessibilityModeEditableTextOnly:
case AccessibilityModeTreeOnly:
return mode;
}
@@ -29,6 +23,11 @@ AccessibilityMode CastToAccessibilityMode(unsigned int int_mode) {
} // namespace
+AccessibilityMode GetBaseAccessibilityMode() {
+ AccessibilityMode accessibility_mode = AccessibilityModeOff;
+ return accessibility_mode;
+}
+
AccessibilityMode AddAccessibilityModeTo(AccessibilityMode to,
AccessibilityMode mode_to_add) {
return CastToAccessibilityMode(to | mode_to_add);
@@ -38,18 +37,6 @@ AccessibilityMode RemoveAccessibilityModeFrom(
AccessibilityMode from,
AccessibilityMode mode_to_remove) {
unsigned int new_mode = from ^ (mode_to_remove & from);
-#if defined(OS_WIN)
- // On Windows 8, always enable accessibility for editable text controls
- // so we can show the virtual keyboard when one is enabled.
- if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableRendererAccessibility)) {
- if ((from & AccessibilityModeEditableTextOnly) ==
- AccessibilityModeEditableTextOnly)
- new_mode |= AccessibilityModeEditableTextOnly;
- }
-#endif // defined(OS_WIN)
-
return CastToAccessibilityMode(new_mode);
}
diff --git a/chromium/content/browser/accessibility/accessibility_mode_helper.h b/chromium/content/browser/accessibility/accessibility_mode_helper.h
index c12c2069d19..c741173ee7b 100644
--- a/chromium/content/browser/accessibility/accessibility_mode_helper.h
+++ b/chromium/content/browser/accessibility/accessibility_mode_helper.h
@@ -5,11 +5,14 @@
#ifndef CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_MODE_HELPER_H_
#define CONTENT_BROWSER_ACCESSIBILITY_ACCESSIBILITY_MODE_HELPER_H_
+#include "content/common/accessibility_mode_enums.h"
#include "content/common/content_export.h"
-#include "content/common/view_message_enums.h"
namespace content {
+// Returns base accessibility mode constant, depends on OS version.
+CONTENT_EXPORT AccessibilityMode GetBaseAccessibilityMode();
+
// Adds the given accessibility mode constant to the given accessibility mode
// bitmap.
CONTENT_EXPORT AccessibilityMode
diff --git a/chromium/content/browser/accessibility/accessibility_mode_helper_unittest.cc b/chromium/content/browser/accessibility/accessibility_mode_helper_unittest.cc
index 73388a19e9f..6bef704a363 100644
--- a/chromium/content/browser/accessibility/accessibility_mode_helper_unittest.cc
+++ b/chromium/content/browser/accessibility/accessibility_mode_helper_unittest.cc
@@ -6,10 +6,6 @@
#include "content/common/view_message_enums.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
namespace content {
TEST(AccessibilityModeHelperTest, TestNoOpRemove) {
@@ -19,35 +15,17 @@ TEST(AccessibilityModeHelperTest, TestNoOpRemove) {
}
TEST(AccessibilityModeHelperTest, TestRemoveSelf) {
- AccessibilityMode kOffMode = AccessibilityModeOff;
-#if defined(OS_WIN)
- // Always preserve AccessibilityModeEditableTextOnly on Windows 8,
- // see RemoveAccessibilityModeFrom() implementation.
- // Test won't pass if switches::kDisableRendererAccessibility is set.
- if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
- kOffMode = AccessibilityModeEditableTextOnly;
- }
-#endif // defined(OS_WIN)
+ AccessibilityMode kBaseMode = GetBaseAccessibilityMode();
- EXPECT_EQ(kOffMode,
+ EXPECT_EQ(kBaseMode,
RemoveAccessibilityModeFrom(AccessibilityModeComplete,
AccessibilityModeComplete));
-
- EXPECT_EQ(
- kOffMode,
- RemoveAccessibilityModeFrom(AccessibilityModeEditableTextOnly,
- AccessibilityModeEditableTextOnly));
}
TEST(AccessibilityModeHelperTest, TestAddMode) {
- EXPECT_EQ(
- AccessibilityModeComplete,
- AddAccessibilityModeTo(AccessibilityModeEditableTextOnly,
- AccessibilityModeComplete));
- EXPECT_EQ(
- AccessibilityModeComplete,
- AddAccessibilityModeTo(AccessibilityModeEditableTextOnly,
- AccessibilityModeTreeOnly));
+ EXPECT_EQ(AccessibilityModeComplete,
+ AddAccessibilityModeTo(AccessibilityModeTreeOnly,
+ AccessibilityModeComplete));
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
index cca61a5b5c6..d4c189fb6f1 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter.cc
@@ -12,7 +12,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
-#include "content/public/browser/render_view_host.h"
+#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/web_contents.h"
namespace content {
@@ -30,12 +30,10 @@ AccessibilityTreeFormatter::AccessibilityTreeFormatter(
// static
AccessibilityTreeFormatter* AccessibilityTreeFormatter::Create(
- RenderViewHost* rvh) {
- RenderWidgetHostViewBase* host_view = static_cast<RenderWidgetHostViewBase*>(
- WebContents::FromRenderViewHost(rvh)->GetRenderWidgetHostView());
-
+ WebContents* web_contents) {
BrowserAccessibilityManager* manager =
- host_view->GetBrowserAccessibilityManager();
+ static_cast<WebContentsImpl*>(web_contents)->
+ GetRootBrowserAccessibilityManager();
if (!manager)
return NULL;
@@ -68,7 +66,7 @@ void AccessibilityTreeFormatter::RecursiveBuildAccessibilityTree(
dict->Set(kChildrenDictAttr, children);
for (size_t i = 0; i < node.PlatformChildCount(); ++i) {
- BrowserAccessibility* child_node = node.InternalGetChild(i);
+ BrowserAccessibility* child_node = node.PlatformGetChild(i);
base::DictionaryValue* child_dict = new base::DictionaryValue;
children->Append(child_dict);
RecursiveBuildAccessibilityTree(*child_node, child_dict);
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter.h b/chromium/content/browser/accessibility/accessibility_tree_formatter.h
index a290886aad9..39c6a4aa283 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter.h
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter.h
@@ -16,7 +16,7 @@
namespace content {
-class RenderViewHost;
+class WebContents;
// A utility class for formatting platform-specific accessibility information,
// for use in testing, debugging, and developer tools.
@@ -27,7 +27,7 @@ class CONTENT_EXPORT AccessibilityTreeFormatter {
explicit AccessibilityTreeFormatter(BrowserAccessibility* root);
virtual ~AccessibilityTreeFormatter();
- static AccessibilityTreeFormatter* Create(RenderViewHost* rvh);
+ static AccessibilityTreeFormatter* Create(WebContents* wc);
// Populates the given DictionaryValue with the accessibility tree.
// The dictionary contains a key/value pair for each attribute of the node,
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
index e037d4d01bf..7d5c1bf1ee1 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -94,19 +94,35 @@ scoped_ptr<base::ListValue> PopulateArray(NSArray* array) {
scoped_ptr<base::StringValue> StringForBrowserAccessibility(
BrowserAccessibilityCocoa* obj) {
- NSString* description = [obj role];
- id value = [obj value];
+ NSMutableArray* tokens = [[NSMutableArray alloc] init];
+
+ // Always include the role
+ id role = [obj role];
+ [tokens addObject:role];
+
+ // If the role is "group", include the role description as well.
id roleDescription = [obj roleDescription];
- if (value && ![value isEqual:@""]) {
- description = [NSString stringWithFormat:@"%@ %@", description, value];
- } else if ([description isEqualToString:NSAccessibilityGroupRole] &&
- roleDescription != nil &&
- ![roleDescription isEqualToString:@""]) {
- description = [NSString stringWithFormat:@"%@ %@",
- description, roleDescription];
+ if ([role isEqualToString:NSAccessibilityGroupRole] &&
+ roleDescription != nil &&
+ ![roleDescription isEqualToString:@""]) {
+ [tokens addObject:roleDescription];
}
+
+ // Include the description, title, or value - the first one not empty.
+ id title = [obj title];
+ id description = [obj description];
+ id value = [obj value];
+ if (description && ![description isEqual:@""]) {
+ [tokens addObject:description];
+ } else if (title && ![title isEqual:@""]) {
+ [tokens addObject:title];
+ } else if (value && ![value isEqual:@""]) {
+ [tokens addObject:value];
+ }
+
+ NSString* result = [tokens componentsJoinedByString:@" "];
return scoped_ptr<base::StringValue>(
- new base::StringValue(SysNSStringToUTF16(description))).Pass();
+ new base::StringValue(SysNSStringToUTF16(result))).Pass();
}
scoped_ptr<base::Value> PopulateObject(id value) {
@@ -154,11 +170,14 @@ NSArray* BuildAllAttributesArray() {
NSAccessibilityOrientationAttribute,
@"AXRequired",
NSAccessibilityRowIndexRangeAttribute,
+ NSAccessibilitySelectedChildrenAttribute,
NSAccessibilityTitleUIElementAttribute,
NSAccessibilityURLAttribute,
NSAccessibilityVisibleCharacterRangeAttribute,
+ NSAccessibilityVisibleChildrenAttribute,
@"AXVisited",
@"AXLinkedUIElements",
+ NSAccessibilityExpandedAttribute,
nil];
return [array retain];
}
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
index 5e1d97351e1..02159bca1ad 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
@@ -197,6 +197,7 @@ AccessibilityRoleStateMap::AccessibilityRoleStateMap() {
// IAccessible2 states.
IA2_STATE_MAP(IA2_STATE_ACTIVE)
IA2_STATE_MAP(IA2_STATE_ARMED)
+ IA2_STATE_MAP(IA2_STATE_CHECKABLE)
IA2_STATE_MAP(IA2_STATE_DEFUNCT)
IA2_STATE_MAP(IA2_STATE_EDITABLE)
IA2_STATE_MAP(IA2_STATE_ICONIFIED)
diff --git a/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc b/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
index 76db849ab55..31367b40344 100644
--- a/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/chromium/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -207,11 +207,6 @@ base::string16 AccessibilityTreeFormatter::ToString(
dict.GetString("role", &role_value);
WriteAttribute(true, base::UTF16ToUTF8(role_value), &line);
- base::string16 name_value;
- dict.GetString("name", &name_value);
- WriteAttribute(true, base::StringPrintf(L"name='%ls'", name_value.c_str()),
- &line);
-
for (int i = 0; i < arraysize(ALL_ATTRIBUTES); i++) {
const char* attribute_name = ALL_ATTRIBUTES[i];
const base::Value* value;
diff --git a/chromium/content/browser/accessibility/accessibility_ui.cc b/chromium/content/browser/accessibility/accessibility_ui.cc
index 1f4df798f46..a8a5d97ad3e 100644
--- a/chromium/content/browser/accessibility/accessibility_ui.cc
+++ b/chromium/content/browser/accessibility/accessibility_ui.cc
@@ -15,7 +15,9 @@
#include "content/browser/accessibility/browser_accessibility_state_impl.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/view_message_enums.h"
+#include "content/grit/content_resources.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_process_host.h"
@@ -25,7 +27,6 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/common/url_constants.h"
-#include "grit/content_resources.h"
#include "net/base/escape.h"
static const char kDataFile[] = "targets-data.json";
@@ -63,11 +64,11 @@ base::DictionaryValue* BuildTargetDescriptor(
}
base::DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh) {
- WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
- std::string title;
- RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rvh);
- AccessibilityMode accessibility_mode = rwhi->accessibility_mode();
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderViewHost(rvh));
+ AccessibilityMode accessibility_mode = web_contents->GetAccessibilityMode();
+ std::string title;
GURL url;
GURL favicon_url;
if (web_contents) {
@@ -116,9 +117,9 @@ bool HandleRequestCallback(BrowserContext* current_context,
scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
data->Set("list", rvh_list.release());
- scoped_ptr<base::FundamentalValue> a11y_mode(base::Value::CreateIntegerValue(
- BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()));
- data->Set("global_a11y_mode", a11y_mode.release());
+ data->SetInteger(
+ "global_a11y_mode",
+ BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode());
std::string json_string;
base::JSONWriter::Write(data.get(), &json_string);
@@ -133,7 +134,6 @@ AccessibilityUI::AccessibilityUI(WebUI* web_ui) : WebUIController(web_ui) {
// Set up the chrome://accessibility source.
WebUIDataSource* html_source =
WebUIDataSource::Create(kChromeUIAccessibilityHost);
- html_source->SetUseJsonJSFormatV2();
web_ui->RegisterMessageCallback(
"toggleAccessibility",
@@ -178,14 +178,15 @@ void AccessibilityUI::ToggleAccessibility(const base::ListValue* args) {
RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
if (!rvh)
return;
- RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rvh);
- if (!rwhi)
- return;
- AccessibilityMode mode = rwhi->accessibility_mode();
- if ((mode & AccessibilityModeComplete) != AccessibilityModeComplete)
- rwhi->AddAccessibilityMode(AccessibilityModeComplete);
- else
- rwhi->ResetAccessibilityMode();
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderViewHost(rvh));
+ AccessibilityMode mode = web_contents->GetAccessibilityMode();
+ if ((mode & AccessibilityModeComplete) != AccessibilityModeComplete) {
+ web_contents->AddAccessibilityMode(AccessibilityModeComplete);
+ } else {
+ web_contents->SetAccessibilityMode(
+ BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode());
+ }
}
void AccessibilityUI::ToggleGlobalAccessibility(const base::ListValue* args) {
@@ -220,25 +221,10 @@ void AccessibilityUI::RequestAccessibilityTree(const base::ListValue* args) {
}
scoped_ptr<base::DictionaryValue> result(BuildTargetDescriptor(rvh));
- RenderWidgetHostViewBase* host_view = static_cast<RenderWidgetHostViewBase*>(
- WebContents::FromRenderViewHost(rvh)->GetRenderWidgetHostView());
- if (!host_view) {
- result->Set("error",
- new base::StringValue("Could not get accessibility tree."));
- web_ui()->CallJavascriptFunction("accessibility.showTree", *(result.get()));
- return;
- }
+ WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
scoped_ptr<AccessibilityTreeFormatter> formatter(
- AccessibilityTreeFormatter::Create(rvh));
+ AccessibilityTreeFormatter::Create(web_contents));
base::string16 accessibility_contents_utf16;
- BrowserAccessibilityManager* manager =
- host_view->GetBrowserAccessibilityManager();
- if (!manager) {
- result->Set("error",
- new base::StringValue("Could not get accessibility tree."));
- web_ui()->CallJavascriptFunction("accessibility.showTree", *(result.get()));
- return;
- }
std::vector<AccessibilityTreeFormatter::Filter> filters;
filters.push_back(AccessibilityTreeFormatter::Filter(
base::ASCIIToUTF16("*"),
diff --git a/chromium/content/browser/accessibility/accessibility_ui.h b/chromium/content/browser/accessibility/accessibility_ui.h
index 49227283038..014514a1363 100644
--- a/chromium/content/browser/accessibility/accessibility_ui.h
+++ b/chromium/content/browser/accessibility/accessibility_ui.h
@@ -17,7 +17,7 @@ namespace content {
class AccessibilityUI : public WebUIController {
public:
explicit AccessibilityUI(WebUI* web_ui);
- virtual ~AccessibilityUI();
+ ~AccessibilityUI() override;
private:
void ToggleAccessibility(const base::ListValue* args);
diff --git a/chromium/content/browser/accessibility/accessibility_win_browsertest.cc b/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
index a11c026f8ad..058e033ae4e 100644
--- a/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/chromium/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -9,6 +9,7 @@
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_variant.h"
+#include "content/browser/accessibility/accessibility_mode_helper.h"
#include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/public/browser/notification_service.h"
@@ -399,6 +400,9 @@ base::string16 AccessibleChecker::RoleVariantToString(
IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
TestBusyAccessibilityTree) {
+ if (GetBaseAccessibilityMode() != AccessibilityModeOff)
+ return;
+
NavigateToURL(shell(), GURL(url::kAboutBlankURL));
// The initial accessible returned should have state STATE_SYSTEM_BUSY while
@@ -640,8 +644,9 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
// If you made a change and this test now fails, check that the NativeViewHost
// that wraps the tab contents returns the IAccessible implementation
// provided by RenderWidgetHostViewWin in GetNativeViewAccessible().
+// flaky: http://crbug.com/402190
IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
- ContainsRendererAccessibilityTree) {
+ DISABLED_ContainsRendererAccessibilityTree) {
LoadInitialAccessibilityTreeFromHtml(
"<html><head><title>MyDocument</title></head>"
"<body>Content</body></html>");
diff --git a/chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc b/chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc
new file mode 100644
index 00000000000..975da4ceeb8
--- /dev/null
+++ b/chromium/content/browser/accessibility/android_granularity_movement_browsertest.cc
@@ -0,0 +1,209 @@
+// 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/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/accessibility/browser_accessibility_android.h"
+#include "content/browser/accessibility/browser_accessibility_manager_android.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/web_contents.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 {
+
+const int GRANULARITY_CHARACTER =
+ ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_CHARACTER;
+const int GRANULARITY_WORD =
+ ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD;
+const int GRANULARITY_LINE =
+ ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE;
+
+class AndroidGranularityMovementBrowserTest : public ContentBrowserTest {
+ public:
+ AndroidGranularityMovementBrowserTest() {}
+ virtual ~AndroidGranularityMovementBrowserTest() {}
+
+ BrowserAccessibility* LoadUrlAndGetAccessibilityRoot(const GURL& url) {
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+ // Load the page.
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_LOAD_COMPLETE);
+ NavigateToURL(shell(), url);
+ waiter.WaitForNotification();
+
+ // Get the BrowserAccessibilityManager.
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ return web_contents->GetRootBrowserAccessibilityManager()->GetRoot();
+ }
+
+ // First, set accessibility focus to a node and wait for the update that
+ // loads inline text boxes for that node. (We load inline text boxes
+ // asynchronously on Android since we only ever need them for the node
+ // with accessibility focus.)
+ //
+ // Then call NextAtGranularity repeatedly and return a string that
+ // concatenates all of the text of the returned text ranges.
+ //
+ // As an example, if the node's text is "cat dog" and you traverse by
+ // word, this returns "'cat', 'dog'".
+ //
+ // Also calls PreviousAtGranularity from the end back to the beginning
+ // and fails (by logging an error and returning the empty string) if
+ // the result when traversing backwards is not the same
+ // (but in reverse order).
+ base::string16 TraverseNodeAtGranularity(
+ BrowserAccessibility* node,
+ int granularity) {
+ AccessibilityNotificationWaiter waiter(
+ shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_TREE_CHANGED);
+ node->manager()->delegate()->AccessibilitySetAccessibilityFocus(
+ node->GetId());
+ waiter.WaitForNotification();
+
+ int start_index = -1;
+ int end_index = -1;
+ BrowserAccessibilityAndroid* android_node =
+ static_cast<BrowserAccessibilityAndroid*>(node);
+ BrowserAccessibilityManagerAndroid* manager =
+ static_cast<BrowserAccessibilityManagerAndroid*>(node->manager());
+ base::string16 text = android_node->GetText();
+ base::string16 concatenated;
+ int previous_end_index = -1;
+ while (manager->NextAtGranularity(
+ granularity, end_index, android_node,
+ &start_index, &end_index)) {
+ int len = (granularity == GRANULARITY_CHARACTER) ?
+ 1 : end_index - start_index;
+ base::string16 selection = text.substr(start_index, len);
+ if (EndsWith(selection, base::ASCIIToUTF16("\n"), false))
+ selection.erase(selection.size() - 1);
+ if (!selection.empty()) {
+ if (!concatenated.empty())
+ concatenated += base::ASCIIToUTF16(", ");
+ concatenated += base::ASCIIToUTF16("'") + selection +
+ base::ASCIIToUTF16("'");
+ }
+
+ // Prevent an endless loop.
+ if (end_index == previous_end_index) {
+ LOG(ERROR) << "Bailing from loop, NextAtGranularity didn't advance";
+ break;
+ }
+ previous_end_index = end_index;
+ }
+
+ base::string16 reverse;
+ previous_end_index = -1;
+ start_index = end_index;
+ while (manager->PreviousAtGranularity(
+ granularity, start_index, android_node, &start_index, &end_index)) {
+ int len = (granularity == GRANULARITY_CHARACTER) ?
+ 1 : end_index - start_index;
+ base::string16 selection = text.substr(start_index, len);
+ if (EndsWith(selection, base::ASCIIToUTF16("\n"), false))
+ selection = selection.substr(0, selection.size() - 1);
+ if (!reverse.empty())
+ reverse = base::ASCIIToUTF16(", ") + reverse;
+ reverse = base::ASCIIToUTF16("'") + selection +
+ base::ASCIIToUTF16("'") + reverse;
+
+ // Prevent an endless loop.
+ if (end_index == previous_end_index) {
+ LOG(ERROR) << "Bailing from loop, PreviousAtGranularity didn't advance";
+ break;
+ }
+ previous_end_index = end_index;
+ }
+
+ if (concatenated != reverse) {
+ LOG(ERROR) << "Did not get the same sequence in the forwards and "
+ << "reverse directions!";
+ LOG(ERROR) << "Forwards: " << concatenated;
+ LOG(ERROR) << "Backwards " << reverse;
+ return base::string16();
+ }
+
+ return concatenated;
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AndroidGranularityMovementBrowserTest,
+ NavigateByCharacters) {
+ GURL url("data:text/html,"
+ "<body>"
+ "<p>One, two, three!</p>"
+ "<button aria-label='Seven, eight, nine!'>Four, five, six!</button>"
+ "</body></html>");
+ BrowserAccessibility* root = LoadUrlAndGetAccessibilityRoot(url);
+ ASSERT_EQ(2U, root->PlatformChildCount());
+ BrowserAccessibility* para = root->PlatformGetChild(0);
+ ASSERT_EQ(0U, para->PlatformChildCount());
+ BrowserAccessibility* button_container = root->PlatformGetChild(1);
+ ASSERT_EQ(1U, button_container->PlatformChildCount());
+ BrowserAccessibility* button = button_container->PlatformGetChild(0);
+ ASSERT_EQ(0U, button->PlatformChildCount());
+
+ ASSERT_EQ(
+ base::ASCIIToUTF16("'O', 'n', 'e', ',', ' ', 't', 'w', 'o', "
+ "',', ' ', 't', 'h', 'r', 'e', 'e', '!'"),
+ TraverseNodeAtGranularity(para, GRANULARITY_CHARACTER));
+ ASSERT_EQ(
+ base::ASCIIToUTF16("'S', 'e', 'v', 'e', 'n', ',', ' ', 'e', 'i', 'g', "
+ "'h', 't', ',', ' ', 'n', 'i', 'n', 'e', '!'"),
+ TraverseNodeAtGranularity(button, GRANULARITY_CHARACTER));
+}
+
+IN_PROC_BROWSER_TEST_F(AndroidGranularityMovementBrowserTest,
+ NavigateByWords) {
+ GURL url("data:text/html,"
+ "<body>"
+ "<p>One, two, three!</p>"
+ "<button aria-label='Seven, eight, nine!'>Four, five, six!</button>"
+ "</body></html>");
+ BrowserAccessibility* root = LoadUrlAndGetAccessibilityRoot(url);
+ ASSERT_EQ(2U, root->PlatformChildCount());
+ BrowserAccessibility* para = root->PlatformGetChild(0);
+ ASSERT_EQ(0U, para->PlatformChildCount());
+ BrowserAccessibility* button_container = root->PlatformGetChild(1);
+ ASSERT_EQ(1U, button_container->PlatformChildCount());
+ BrowserAccessibility* button = button_container->PlatformGetChild(0);
+ ASSERT_EQ(0U, button->PlatformChildCount());
+
+ ASSERT_EQ(base::ASCIIToUTF16("'One', 'two', 'three'"),
+ TraverseNodeAtGranularity(para, GRANULARITY_WORD));
+ ASSERT_EQ(base::ASCIIToUTF16("'Seven', 'eight', 'nine'"),
+ TraverseNodeAtGranularity(button, GRANULARITY_WORD));
+}
+
+IN_PROC_BROWSER_TEST_F(AndroidGranularityMovementBrowserTest,
+ NavigateByLine) {
+ GURL url("data:text/html,"
+ "<body>"
+ "<pre>One,%0dtwo,%0dthree!</pre>"
+ "</body>");
+ BrowserAccessibility* root = LoadUrlAndGetAccessibilityRoot(url);
+ ASSERT_EQ(1U, root->PlatformChildCount());
+ BrowserAccessibility* pre = root->PlatformGetChild(0);
+ ASSERT_EQ(0U, pre->PlatformChildCount());
+
+ ASSERT_EQ(base::ASCIIToUTF16("'One,', 'two,', 'three!'"),
+ TraverseNodeAtGranularity(pre, GRANULARITY_LINE));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc b/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc
index 1070f6e63f2..f483286f7ca 100644
--- a/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc
+++ b/chromium/content/browser/accessibility/android_hit_testing_browsertest.cc
@@ -7,9 +7,8 @@
#include <vector>
#include "base/command_line.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
-#include "base/path_service.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -17,8 +16,7 @@
#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/renderer_host/render_view_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/public/browser/web_contents.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
@@ -59,10 +57,10 @@ IN_PROC_BROWSER_TEST_F(AndroidHitTestingBrowserTest,
waiter.WaitForNotification();
// Get the BrowserAccessibilityManager.
- RenderWidgetHostViewBase* host_view = static_cast<RenderWidgetHostViewBase*>(
- shell()->web_contents()->GetRenderWidgetHostView());
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
BrowserAccessibilityManager* manager =
- host_view->GetBrowserAccessibilityManager();
+ web_contents->GetRootBrowserAccessibilityManager();
// Send a hit test request, and wait for the hover event in response.
AccessibilityNotificationWaiter hover_waiter(
diff --git a/chromium/content/browser/accessibility/browser_accessibility.cc b/chromium/content/browser/accessibility/browser_accessibility.cc
index fe71fef965a..a700e9a9fd3 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility.cc
@@ -84,7 +84,16 @@ bool BrowserAccessibility::IsDescendantOf(
BrowserAccessibility* BrowserAccessibility::PlatformGetChild(
uint32 child_index) const {
DCHECK(child_index < InternalChildCount());
- return InternalGetChild(child_index);
+ BrowserAccessibility* result = InternalGetChild(child_index);
+
+ if (result->HasBoolAttribute(ui::AX_ATTR_IS_AX_TREE_HOST)) {
+ BrowserAccessibilityManager* child_manager =
+ manager_->delegate()->AccessibilityGetChildFrame(result->GetId());
+ if (child_manager)
+ result = child_manager->GetRoot();
+ }
+
+ return result;
}
BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
@@ -122,7 +131,18 @@ BrowserAccessibility* BrowserAccessibility::GetParent() const {
if (!node_ || !manager_)
return NULL;
ui::AXNode* parent = node_->parent();
- return parent ? manager_->GetFromAXNode(parent) : NULL;
+ if (parent)
+ return manager_->GetFromAXNode(parent);
+
+ if (!manager_->delegate())
+ return NULL;
+
+ BrowserAccessibility* host_node =
+ manager_->delegate()->AccessibilityGetParentFrame();
+ if (!host_node)
+ return NULL;
+
+ return host_node->GetParent();
}
int32 BrowserAccessibility::GetIndexInParent() const {
@@ -153,7 +173,7 @@ int32 BrowserAccessibility::GetState() const {
return GetData().state;
}
-const std::vector<std::pair<std::string, std::string> >&
+const BrowserAccessibility::HtmlAttributes&
BrowserAccessibility::GetHtmlAttributes() const {
return GetData().html_attributes;
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility.h b/chromium/content/browser/accessibility/browser_accessibility.h
index 17f70caf675..6318e64b53d 100644
--- a/chromium/content/browser/accessibility/browser_accessibility.h
+++ b/chromium/content/browser/accessibility/browser_accessibility.h
@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
+#include "base/strings/string_split.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "third_party/WebKit/public/web/WebAXEnums.h"
@@ -31,12 +32,13 @@ class BrowserAccessibilityWin;
//
// BrowserAccessibility
//
-// Class implementing the cross platform interface for the Browser-Renderer
-// communication of accessibility information, providing accessibility
-// to be used by screen readers and other assistive technology (AT).
+// A BrowserAccessibility object represents one node in the accessibility
+// tree on the browser side. It exactly corresponds to one WebAXObject from
+// Blink. It's owned by a BrowserAccessibilityManager.
//
-// An implementation for each platform handles platform specific accessibility
-// APIs.
+// There are subclasses of BrowserAccessibility for each platform where
+// we implement native accessibility APIs. This base class is used occasionally
+// for tests.
//
////////////////////////////////////////////////////////////////////////////////
class CONTENT_EXPORT BrowserAccessibility {
@@ -65,7 +67,7 @@ class CONTENT_EXPORT BrowserAccessibility {
virtual bool IsNative() const;
// Called when the location changed.
- virtual void OnLocationChanged() const {}
+ virtual void OnLocationChanged() {}
// Return true if this object is equal to or a descendant of |ancestor|.
bool IsDescendantOf(BrowserAccessibility* ancestor);
@@ -159,7 +161,7 @@ class CONTENT_EXPORT BrowserAccessibility {
int32 GetRole() const;
int32 GetState() const;
- typedef std::vector<std::pair<std::string, std::string> > HtmlAttributes;
+ typedef base::StringPairs HtmlAttributes;
const HtmlAttributes& GetHtmlAttributes() const;
#if defined(OS_MACOSX) && __OBJC__
@@ -262,7 +264,6 @@ class CONTENT_EXPORT BrowserAccessibility {
std::string name_;
std::string value_;
- private:
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibility);
};
diff --git a/chromium/content/browser/accessibility/browser_accessibility_android.cc b/chromium/content/browser/accessibility/browser_accessibility_android.cc
index 8a8514a0d80..53189cbf1d1 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_android.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_android.cc
@@ -4,6 +4,9 @@
#include "content/browser/accessibility/browser_accessibility_android.h"
+#include "base/i18n/break_iterator.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/accessibility/browser_accessibility_manager_android.h"
#include "content/common/accessibility_messages.h"
@@ -55,6 +58,10 @@ bool BrowserAccessibilityAndroid::IsNative() const {
return true;
}
+void BrowserAccessibilityAndroid::OnLocationChanged() {
+ manager()->NotifyAccessibilityEvent(ui::AX_EVENT_LOCATION_CHANGED, this);
+}
+
bool BrowserAccessibilityAndroid::PlatformIsLeaf() const {
if (InternalChildCount() == 0)
return true;
@@ -70,6 +77,10 @@ bool BrowserAccessibilityAndroid::PlatformIsLeaf() const {
if (HasFocusableChild())
return false;
+ // Date and time controls should drop their children.
+ if (GetRole() == ui::AX_ROLE_DATE || GetRole() == ui::AX_ROLE_TIME)
+ return true;
+
// Headings with text can drop their children.
base::string16 name = GetText();
if (GetRole() == ui::AX_ROLE_HEADING && !name.empty())
@@ -86,6 +97,24 @@ bool BrowserAccessibilityAndroid::PlatformIsLeaf() const {
return BrowserAccessibility::PlatformIsLeaf();
}
+bool BrowserAccessibilityAndroid::CanScrollForward() const {
+ if (!IsSlider())
+ return false;
+
+ float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE);
+ float max = GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE);
+ return value < max;
+}
+
+bool BrowserAccessibilityAndroid::CanScrollBackward() const {
+ if (!IsSlider())
+ return false;
+
+ float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE);
+ float min = GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE);
+ return value > min;
+}
+
bool BrowserAccessibilityAndroid::IsCheckable() const {
bool checkable = false;
bool is_aria_pressed_defined;
@@ -93,6 +122,8 @@ bool BrowserAccessibilityAndroid::IsCheckable() const {
GetAriaTristate("aria-pressed", &is_aria_pressed_defined, &is_mixed);
if (GetRole() == ui::AX_ROLE_CHECK_BOX ||
GetRole() == ui::AX_ROLE_RADIO_BUTTON ||
+ GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX ||
+ GetRole() == ui::AX_ROLE_MENU_ITEM_RADIO ||
is_aria_pressed_defined) {
checkable = true;
}
@@ -113,6 +144,7 @@ bool BrowserAccessibilityAndroid::IsCollection() const {
return (GetRole() == ui::AX_ROLE_GRID ||
GetRole() == ui::AX_ROLE_LIST ||
GetRole() == ui::AX_ROLE_LIST_BOX ||
+ GetRole() == ui::AX_ROLE_DESCRIPTION_LIST ||
GetRole() == ui::AX_ROLE_TABLE ||
GetRole() == ui::AX_ROLE_TREE);
}
@@ -136,6 +168,12 @@ bool BrowserAccessibilityAndroid::IsDismissable() const {
return false; // No concept of "dismissable" on the web currently.
}
+bool BrowserAccessibilityAndroid::IsEditableText() const {
+ return (GetRole() == ui::AX_ROLE_EDITABLE_TEXT ||
+ GetRole() == ui::AX_ROLE_TEXT_AREA ||
+ GetRole() == ui::AX_ROLE_TEXT_FIELD);
+}
+
bool BrowserAccessibilityAndroid::IsEnabled() const {
return HasState(ui::AX_STATE_ENABLED);
}
@@ -161,6 +199,7 @@ bool BrowserAccessibilityAndroid::IsHeading() const {
bool BrowserAccessibilityAndroid::IsHierarchical() const {
return (GetRole() == ui::AX_ROLE_LIST ||
+ GetRole() == ui::AX_ROLE_DESCRIPTION_LIST ||
GetRole() == ui::AX_ROLE_TREE);
}
@@ -192,6 +231,10 @@ bool BrowserAccessibilityAndroid::IsSelected() const {
return HasState(ui::AX_STATE_SELECTED);
}
+bool BrowserAccessibilityAndroid::IsSlider() const {
+ return GetRole() == ui::AX_ROLE_SLIDER;
+}
+
bool BrowserAccessibilityAndroid::IsVisibleToUser() const {
return !HasState(ui::AX_STATE_INVISIBLE);
}
@@ -213,12 +256,15 @@ const char* BrowserAccessibilityAndroid::GetClassName() const {
case ui::AX_ROLE_SLIDER:
class_name = "android.widget.SeekBar";
break;
+ case ui::AX_ROLE_COLOR_WELL:
case ui::AX_ROLE_COMBO_BOX:
+ case ui::AX_ROLE_DATE:
+ case ui::AX_ROLE_POP_UP_BUTTON:
+ case ui::AX_ROLE_TIME:
class_name = "android.widget.Spinner";
break;
case ui::AX_ROLE_BUTTON:
case ui::AX_ROLE_MENU_BUTTON:
- case ui::AX_ROLE_POP_UP_BUTTON:
class_name = "android.widget.Button";
break;
case ui::AX_ROLE_CHECK_BOX:
@@ -232,8 +278,10 @@ const char* BrowserAccessibilityAndroid::GetClassName() const {
break;
case ui::AX_ROLE_CANVAS:
case ui::AX_ROLE_IMAGE:
+ case ui::AX_ROLE_SVG_ROOT:
class_name = "android.widget.Image";
break;
+ case ui::AX_ROLE_METER:
case ui::AX_ROLE_PROGRESS_INDICATOR:
class_name = "android.widget.ProgressBar";
break;
@@ -246,6 +294,7 @@ const char* BrowserAccessibilityAndroid::GetClassName() const {
break;
case ui::AX_ROLE_LIST:
case ui::AX_ROLE_LIST_BOX:
+ case ui::AX_ROLE_DESCRIPTION_LIST:
class_name = "android.widget.ListView";
break;
case ui::AX_ROLE_DIALOG:
@@ -254,6 +303,11 @@ const char* BrowserAccessibilityAndroid::GetClassName() const {
case ui::AX_ROLE_ROOT_WEB_AREA:
class_name = "android.webkit.WebView";
break;
+ case ui::AX_ROLE_MENU_ITEM:
+ case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+ case ui::AX_ROLE_MENU_ITEM_RADIO:
+ class_name = "android.view.MenuItem";
+ break;
default:
class_name = "android.view.View";
break;
@@ -271,15 +325,59 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
// See comment in browser_accessibility_win.cc for details.
// The difference here is that we can only expose one accessible
// name on Android, not 2 or 3 like on Windows or Mac.
- //
- // The basic rule is: prefer description (aria-labelledby or aria-label),
- // then help (title), then name (inner text), then value (control value).
- // However, if title_elem_id is set, that means there's a label element
+
+ // First, always return the |value| attribute if this is an
+ // input field.
+ if (!value().empty()) {
+ if (HasState(ui::AX_STATE_EDITABLE))
+ return base::UTF8ToUTF16(value());
+
+ switch (GetRole()) {
+ case ui::AX_ROLE_COMBO_BOX:
+ case ui::AX_ROLE_EDITABLE_TEXT:
+ case ui::AX_ROLE_POP_UP_BUTTON:
+ case ui::AX_ROLE_TEXT_AREA:
+ case ui::AX_ROLE_TEXT_FIELD:
+ return base::UTF8ToUTF16(value());
+ }
+ }
+
+ // 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 red = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_RED);
+ int green = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_GREEN);
+ int blue = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE_BLUE);
+ return base::UTF8ToUTF16(
+ base::StringPrintf("#%02X%02X%02X", red, green, blue));
+ }
+
+ // Always prefer visible text if this is a link. Sites sometimes add
+ // a "title" attribute to a link with more information, but we can't
+ // lose the link text.
+ if (!name().empty() && GetRole() == ui::AX_ROLE_LINK)
+ return base::UTF8ToUTF16(name());
+
+ // If there's no text value, the basic rule is: prefer description
+ // (aria-labelledby or aria-label), then help (title), then name
+ // (inner text), then value (control value). However, if
+ // title_elem_id is set, that means there's a label element
// supplying the name and then name takes precedence over help.
// TODO(dmazzoni): clean this up by providing more granular labels in
// Blink, making the platform-specific mapping to accessible text simpler.
base::string16 description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION);
base::string16 help = GetString16Attribute(ui::AX_ATTR_HELP);
+
+ base::string16 placeholder;
+ switch (GetRole()) {
+ case ui::AX_ROLE_DATE:
+ case ui::AX_ROLE_EDITABLE_TEXT:
+ case ui::AX_ROLE_TEXT_AREA:
+ case ui::AX_ROLE_TEXT_FIELD:
+ case ui::AX_ROLE_TIME:
+ GetHtmlAttribute("placeholder", &placeholder);
+ }
+
int title_elem_id = GetIntAttribute(
ui::AX_ATTR_TITLE_UI_ELEMENT);
base::string16 text;
@@ -291,27 +389,23 @@ base::string16 BrowserAccessibilityAndroid::GetText() const {
text = help;
else if (!name().empty())
text = base::UTF8ToUTF16(name());
+ else if (!placeholder.empty())
+ text = placeholder;
else if (!value().empty())
text = base::UTF8ToUTF16(value());
// This is called from PlatformIsLeaf, so don't call PlatformChildCount
// from within this!
- if (text.empty() && HasOnlyStaticTextChildren()) {
+ if (text.empty() &&
+ (HasOnlyStaticTextChildren() ||
+ (IsFocusable() && HasOnlyTextAndImageChildren()))) {
for (uint32 i = 0; i < InternalChildCount(); i++) {
BrowserAccessibility* child = InternalGetChild(i);
text += static_cast<BrowserAccessibilityAndroid*>(child)->GetText();
}
}
- switch(GetRole()) {
- case ui::AX_ROLE_HEADING:
- // Only append "heading" if this node already has text.
- if (!text.empty())
- text += base::ASCIIToUTF16(" Heading");
- break;
- }
-
- if (text.empty() && IsLink()) {
+ if (text.empty() && (IsLink() || GetRole() == ui::AX_ROLE_IMAGE)) {
base::string16 url = GetString16Attribute(ui::AX_ATTR_URL);
// Given a url like http://foo.com/bar/baz.png, just return the
// base name, e.g., "baz".
@@ -344,11 +438,13 @@ int BrowserAccessibilityAndroid::GetItemIndex() const {
break;
case ui::AX_ROLE_SLIDER:
case ui::AX_ROLE_PROGRESS_INDICATOR: {
- float value_for_range;
- if (GetFloatAttribute(
- ui::AX_ATTR_VALUE_FOR_RANGE, &value_for_range)) {
- index = static_cast<int>(value_for_range);
- }
+ // Return a percentage here for live feedback in an AccessibilityEvent.
+ // The exact value is returned in RangeCurrentValue.
+ float min = GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE);
+ float max = GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE);
+ float value = GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE);
+ if (max > min && value >= min && value <= max)
+ index = static_cast<int>(((value - min)) * 100 / (max - min));
break;
}
}
@@ -360,17 +456,16 @@ int BrowserAccessibilityAndroid::GetItemCount() const {
switch(GetRole()) {
case ui::AX_ROLE_LIST:
case ui::AX_ROLE_LIST_BOX:
+ case ui::AX_ROLE_DESCRIPTION_LIST:
count = PlatformChildCount();
break;
case ui::AX_ROLE_SLIDER:
- case ui::AX_ROLE_PROGRESS_INDICATOR: {
- float max_value_for_range;
- if (GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE,
- &max_value_for_range)) {
- count = static_cast<int>(max_value_for_range);
- }
+ case ui::AX_ROLE_PROGRESS_INDICATOR:
+ // An AccessibilityEvent can only return integer information about a
+ // seek control, so we return a percentage. The real range is returned
+ // in RangeMin and RangeMax.
+ count = 100;
break;
- }
}
return count;
}
@@ -523,6 +618,7 @@ int BrowserAccessibilityAndroid::RowCount() const {
if (GetRole() == ui::AX_ROLE_LIST ||
GetRole() == ui::AX_ROLE_LIST_BOX ||
+ GetRole() == ui::AX_ROLE_DESCRIPTION_LIST ||
GetRole() == ui::AX_ROLE_TREE) {
return PlatformChildCount();
}
@@ -572,6 +668,116 @@ float BrowserAccessibilityAndroid::RangeCurrentValue() const {
return GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE);
}
+void BrowserAccessibilityAndroid::GetGranularityBoundaries(
+ int granularity,
+ std::vector<int32>* starts,
+ std::vector<int32>* ends,
+ int offset) {
+ switch (granularity) {
+ case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE:
+ GetLineBoundaries(starts, ends, offset);
+ break;
+ case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD:
+ GetWordBoundaries(starts, ends, offset);
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void BrowserAccessibilityAndroid::GetLineBoundaries(
+ std::vector<int32>* line_starts,
+ std::vector<int32>* line_ends,
+ int offset) {
+ // If this node has no children, treat it as all one line.
+ if (GetText().size() > 0 && !InternalChildCount()) {
+ line_starts->push_back(offset);
+ line_ends->push_back(offset + GetText().size());
+ }
+
+ // If this is a static text node, get the line boundaries from the
+ // inline text boxes if possible.
+ if (GetRole() == ui::AX_ROLE_STATIC_TEXT) {
+ int last_y = 0;
+ for (uint32 i = 0; i < InternalChildCount(); i++) {
+ BrowserAccessibilityAndroid* child =
+ static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i));
+ CHECK_EQ(ui::AX_ROLE_INLINE_TEXT_BOX, child->GetRole());
+ // TODO(dmazzoni): replace this with a proper API to determine
+ // if two inline text boxes are on the same line. http://crbug.com/421771
+ int y = child->GetLocation().y();
+ if (i == 0) {
+ line_starts->push_back(offset);
+ } else if (y != last_y) {
+ line_ends->push_back(offset);
+ line_starts->push_back(offset);
+ }
+ offset += child->GetText().size();
+ last_y = y;
+ }
+ line_ends->push_back(offset);
+ return;
+ }
+
+ // Otherwise, call GetLineBoundaries recursively on the children.
+ for (uint32 i = 0; i < InternalChildCount(); i++) {
+ BrowserAccessibilityAndroid* child =
+ static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i));
+ child->GetLineBoundaries(line_starts, line_ends, offset);
+ offset += child->GetText().size();
+ }
+}
+
+void BrowserAccessibilityAndroid::GetWordBoundaries(
+ std::vector<int32>* word_starts,
+ std::vector<int32>* word_ends,
+ int offset) {
+ if (GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) {
+ const std::vector<int32>& starts = GetIntListAttribute(
+ ui::AX_ATTR_WORD_STARTS);
+ const std::vector<int32>& ends = GetIntListAttribute(
+ ui::AX_ATTR_WORD_ENDS);
+ for (size_t i = 0; i < starts.size(); ++i) {
+ word_starts->push_back(offset + starts[i]);
+ word_ends->push_back(offset + ends[i]);
+ }
+ return;
+ }
+
+ base::string16 concatenated_text;
+ for (uint32 i = 0; i < InternalChildCount(); i++) {
+ BrowserAccessibilityAndroid* child =
+ static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i));
+ base::string16 child_text = child->GetText();
+ concatenated_text += child->GetText();
+ }
+
+ base::string16 text = GetText();
+ if (text.empty() || concatenated_text == text) {
+ // Great - this node is just the concatenation of its children, so
+ // we can get the word boundaries recursively.
+ for (uint32 i = 0; i < InternalChildCount(); i++) {
+ BrowserAccessibilityAndroid* child =
+ static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i));
+ child->GetWordBoundaries(word_starts, word_ends, offset);
+ offset += child->GetText().size();
+ }
+ } else {
+ // This node has its own accessible text that doesn't match its
+ // visible text - like alt text for an image or something with an
+ // aria-label, so split the text into words locally.
+ base::i18n::BreakIterator iter(text, base::i18n::BreakIterator::BREAK_WORD);
+ if (!iter.Init())
+ return;
+ while (iter.Advance()) {
+ if (iter.IsWord()) {
+ word_starts->push_back(iter.prev());
+ word_ends->push_back(iter.pos());
+ }
+ }
+ }
+}
+
bool BrowserAccessibilityAndroid::HasFocusableChild() const {
// This is called from PlatformIsLeaf, so don't call PlatformChildCount
// from within this!
@@ -596,6 +802,19 @@ bool BrowserAccessibilityAndroid::HasOnlyStaticTextChildren() const {
return true;
}
+bool BrowserAccessibilityAndroid::HasOnlyTextAndImageChildren() const {
+ // This is called from PlatformIsLeaf, so don't call PlatformChildCount
+ // from within this!
+ for (uint32 i = 0; i < InternalChildCount(); i++) {
+ BrowserAccessibility* child = InternalGetChild(i);
+ if (child->GetRole() != ui::AX_ROLE_STATIC_TEXT &&
+ child->GetRole() != ui::AX_ROLE_IMAGE) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool BrowserAccessibilityAndroid::IsIframe() const {
base::string16 html_tag = GetString16Attribute(
ui::AX_ATTR_HTML_TAG);
diff --git a/chromium/content/browser/accessibility/browser_accessibility_android.h b/chromium/content/browser/accessibility/browser_accessibility_android.h
index f78a96dd54d..70579ab9b85 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_android.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_android.h
@@ -10,14 +10,17 @@
namespace content {
-class BrowserAccessibilityAndroid : public BrowserAccessibility {
+class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
public:
// Overrides from BrowserAccessibility.
- virtual void OnDataChanged() OVERRIDE;
- virtual bool IsNative() const OVERRIDE;
+ virtual void OnDataChanged() override;
+ virtual bool IsNative() const override;
+ virtual void OnLocationChanged() override;
- virtual bool PlatformIsLeaf() const OVERRIDE;
+ virtual bool PlatformIsLeaf() const override;
+ bool CanScrollForward() const;
+ bool CanScrollBackward() const;
bool IsCheckable() const;
bool IsChecked() const;
bool IsClickable() const;
@@ -25,6 +28,7 @@ class BrowserAccessibilityAndroid : public BrowserAccessibility {
bool IsCollectionItem() const;
bool IsContentInvalid() const;
bool IsDismissable() const;
+ bool IsEditableText() const;
bool IsEnabled() const;
bool IsFocusable() const;
bool IsFocused() const;
@@ -36,6 +40,7 @@ class BrowserAccessibilityAndroid : public BrowserAccessibility {
bool IsRangeType() const;
bool IsScrollable() const;
bool IsSelected() const;
+ bool IsSlider() const;
bool IsVisibleToUser() const;
bool CanOpenPopup() const;
@@ -78,6 +83,26 @@ class BrowserAccessibilityAndroid : public BrowserAccessibility {
float RangeMax() const;
float RangeCurrentValue() const;
+ // Calls GetLineBoundaries or GetWordBoundaries depending on the value
+ // of |granularity|, or fails if anything else is passed in |granularity|.
+ void GetGranularityBoundaries(int granularity,
+ std::vector<int32>* starts,
+ std::vector<int32>* ends,
+ int offset);
+
+ // Append line start and end indices for the text of this node
+ // (as returned by GetText()), adding |offset| to each one.
+ void GetLineBoundaries(std::vector<int32>* line_starts,
+ std::vector<int32>* line_ends,
+ int offset);
+
+ // Append word start and end indices for the text of this node
+ // (as returned by GetText()) to |word_starts| and |word_ends|,
+ // adding |offset| to each one.
+ void GetWordBoundaries(std::vector<int32>* word_starts,
+ std::vector<int32>* word_ends,
+ int offset);
+
private:
// This gives BrowserAccessibility::Create access to the class constructor.
friend class BrowserAccessibility;
@@ -85,6 +110,7 @@ class BrowserAccessibilityAndroid : public BrowserAccessibility {
BrowserAccessibilityAndroid();
bool HasOnlyStaticTextChildren() const;
+ bool HasOnlyTextAndImageChildren() const;
bool IsIframe() const;
void NotifyLiveRegionUpdate(base::string16& aria_live);
diff --git a/chromium/content/browser/accessibility/browser_accessibility_cocoa.h b/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
index 5fc708f867b..0f01a7a8777 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_cocoa.h
@@ -95,6 +95,7 @@
@property(nonatomic, readonly) NSArray* rowHeaders;
@property(nonatomic, readonly) NSValue* rowIndexRange;
@property(nonatomic, readonly) NSArray* rows;
+@property(nonatomic, readonly) NSArray* selectedChildren;
// The size of this object.
@property(nonatomic, readonly) NSValue* size;
// A string indicating the subrole of this object as far as accessibility
@@ -109,6 +110,7 @@
@property(nonatomic, readonly) NSString* valueDescription;
@property(nonatomic, readonly) NSValue* visibleCharacterRange;
@property(nonatomic, readonly) NSArray* visibleCells;
+@property(nonatomic, readonly) NSArray* visibleChildren;
@property(nonatomic, readonly) NSArray* visibleColumns;
@property(nonatomic, readonly) NSArray* visibleRows;
@property(nonatomic, readonly) NSNumber* visited;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
index 232e4827750..ac81de7ab39 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -12,10 +12,11 @@
#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_manager.h"
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
#include "content/public/common/content_client.h"
-#include "grit/webkit_strings.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
@@ -39,197 +40,12 @@ NSString* NSStringForStringAttribute(
browserAccessibility->GetStringAttribute(attribute));
}
-struct MapEntry {
- ui::AXRole webKitValue;
- NSString* nativeValue;
-};
-
-typedef std::map<ui::AXRole, NSString*> RoleMap;
-
// GetState checks the bitmask used in AXNodeData to check
// if the given state was set on the accessibility object.
bool GetState(BrowserAccessibility* accessibility, ui::AXState state) {
return ((accessibility->GetState() >> state) & 1);
}
-RoleMap BuildRoleMap() {
- const MapEntry roles[] = {
- { ui::AX_ROLE_ALERT, NSAccessibilityGroupRole },
- { ui::AX_ROLE_ALERT_DIALOG, NSAccessibilityGroupRole },
- { ui::AX_ROLE_ANNOTATION, NSAccessibilityUnknownRole },
- { ui::AX_ROLE_APPLICATION, NSAccessibilityGroupRole },
- { ui::AX_ROLE_ARTICLE, NSAccessibilityGroupRole },
- { ui::AX_ROLE_BANNER, NSAccessibilityGroupRole },
- { ui::AX_ROLE_BROWSER, NSAccessibilityBrowserRole },
- { ui::AX_ROLE_BUSY_INDICATOR, NSAccessibilityBusyIndicatorRole },
- { ui::AX_ROLE_BUTTON, NSAccessibilityButtonRole },
- { ui::AX_ROLE_CANVAS, NSAccessibilityImageRole },
- { ui::AX_ROLE_CELL, @"AXCell" },
- { ui::AX_ROLE_CHECK_BOX, NSAccessibilityCheckBoxRole },
- { ui::AX_ROLE_COLOR_WELL, NSAccessibilityColorWellRole },
- { ui::AX_ROLE_COLUMN, NSAccessibilityColumnRole },
- { ui::AX_ROLE_COLUMN_HEADER, @"AXCell" },
- { ui::AX_ROLE_COMBO_BOX, NSAccessibilityComboBoxRole },
- { ui::AX_ROLE_COMPLEMENTARY, NSAccessibilityGroupRole },
- { ui::AX_ROLE_CONTENT_INFO, NSAccessibilityGroupRole },
- { ui::AX_ROLE_DEFINITION, NSAccessibilityGroupRole },
- { ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, NSAccessibilityGroupRole },
- { ui::AX_ROLE_DESCRIPTION_LIST_TERM, NSAccessibilityGroupRole },
- { ui::AX_ROLE_DIALOG, NSAccessibilityGroupRole },
- { ui::AX_ROLE_DIRECTORY, NSAccessibilityListRole },
- { ui::AX_ROLE_DISCLOSURE_TRIANGLE, NSAccessibilityDisclosureTriangleRole },
- { ui::AX_ROLE_DIV, NSAccessibilityGroupRole },
- { ui::AX_ROLE_DOCUMENT, NSAccessibilityGroupRole },
- { ui::AX_ROLE_DRAWER, NSAccessibilityDrawerRole },
- { ui::AX_ROLE_EDITABLE_TEXT, NSAccessibilityTextFieldRole },
- { ui::AX_ROLE_FOOTER, NSAccessibilityGroupRole },
- { ui::AX_ROLE_FORM, NSAccessibilityGroupRole },
- { ui::AX_ROLE_GRID, NSAccessibilityGridRole },
- { ui::AX_ROLE_GROUP, NSAccessibilityGroupRole },
- { ui::AX_ROLE_GROW_AREA, NSAccessibilityGrowAreaRole },
- { ui::AX_ROLE_HEADING, @"AXHeading" },
- { ui::AX_ROLE_HELP_TAG, NSAccessibilityHelpTagRole },
- { ui::AX_ROLE_HORIZONTAL_RULE, NSAccessibilityGroupRole },
- { ui::AX_ROLE_IFRAME, NSAccessibilityGroupRole },
- { ui::AX_ROLE_IGNORED, NSAccessibilityUnknownRole },
- { ui::AX_ROLE_IMAGE, NSAccessibilityImageRole },
- { ui::AX_ROLE_IMAGE_MAP, NSAccessibilityGroupRole },
- { ui::AX_ROLE_IMAGE_MAP_LINK, NSAccessibilityLinkRole },
- { ui::AX_ROLE_INCREMENTOR, NSAccessibilityIncrementorRole },
- { ui::AX_ROLE_LABEL_TEXT, NSAccessibilityGroupRole },
- { ui::AX_ROLE_LINK, NSAccessibilityLinkRole },
- { ui::AX_ROLE_LIST, NSAccessibilityListRole },
- { ui::AX_ROLE_LIST_BOX, NSAccessibilityListRole },
- { ui::AX_ROLE_LIST_BOX_OPTION, NSAccessibilityStaticTextRole },
- { ui::AX_ROLE_LIST_ITEM, NSAccessibilityGroupRole },
- { ui::AX_ROLE_LIST_MARKER, @"AXListMarker" },
- { ui::AX_ROLE_LOG, NSAccessibilityGroupRole },
- { ui::AX_ROLE_MAIN, NSAccessibilityGroupRole },
- { ui::AX_ROLE_MARQUEE, NSAccessibilityGroupRole },
- { ui::AX_ROLE_MATH, NSAccessibilityGroupRole },
- { ui::AX_ROLE_MATTE, NSAccessibilityMatteRole },
- { ui::AX_ROLE_MENU, NSAccessibilityMenuRole },
- { ui::AX_ROLE_MENU_BAR, NSAccessibilityMenuBarRole },
- { ui::AX_ROLE_MENU_BUTTON, NSAccessibilityButtonRole },
- { ui::AX_ROLE_MENU_ITEM, NSAccessibilityMenuItemRole },
- { ui::AX_ROLE_MENU_LIST_OPTION, NSAccessibilityMenuItemRole },
- { ui::AX_ROLE_MENU_LIST_POPUP, NSAccessibilityUnknownRole },
- { ui::AX_ROLE_NAVIGATION, NSAccessibilityGroupRole },
- { ui::AX_ROLE_NOTE, NSAccessibilityGroupRole },
- { ui::AX_ROLE_OUTLINE, NSAccessibilityOutlineRole },
- { ui::AX_ROLE_PARAGRAPH, NSAccessibilityGroupRole },
- { ui::AX_ROLE_POP_UP_BUTTON, NSAccessibilityPopUpButtonRole },
- { ui::AX_ROLE_PRESENTATIONAL, NSAccessibilityGroupRole },
- { ui::AX_ROLE_PROGRESS_INDICATOR, NSAccessibilityProgressIndicatorRole },
- { ui::AX_ROLE_RADIO_BUTTON, NSAccessibilityRadioButtonRole },
- { ui::AX_ROLE_RADIO_GROUP, NSAccessibilityRadioGroupRole },
- { ui::AX_ROLE_REGION, NSAccessibilityGroupRole },
- { ui::AX_ROLE_ROOT_WEB_AREA, @"AXWebArea" },
- { ui::AX_ROLE_ROW, NSAccessibilityRowRole },
- { ui::AX_ROLE_ROW_HEADER, @"AXCell" },
- { ui::AX_ROLE_RULER, NSAccessibilityRulerRole },
- { ui::AX_ROLE_RULER_MARKER, NSAccessibilityRulerMarkerRole },
- { ui::AX_ROLE_SCROLL_BAR, NSAccessibilityScrollBarRole },
- { ui::AX_ROLE_SEARCH, NSAccessibilityGroupRole },
- { ui::AX_ROLE_SHEET, NSAccessibilitySheetRole },
- { ui::AX_ROLE_SLIDER, NSAccessibilitySliderRole },
- { ui::AX_ROLE_SLIDER_THUMB, NSAccessibilityValueIndicatorRole },
- { ui::AX_ROLE_SPIN_BUTTON, NSAccessibilitySliderRole },
- { ui::AX_ROLE_SPLITTER, NSAccessibilitySplitterRole },
- { ui::AX_ROLE_SPLIT_GROUP, NSAccessibilitySplitGroupRole },
- { ui::AX_ROLE_STATIC_TEXT, NSAccessibilityStaticTextRole },
- { ui::AX_ROLE_STATUS, NSAccessibilityGroupRole },
- { ui::AX_ROLE_SVG_ROOT, NSAccessibilityGroupRole },
- { ui::AX_ROLE_SYSTEM_WIDE, NSAccessibilityUnknownRole },
- { ui::AX_ROLE_TAB, NSAccessibilityRadioButtonRole },
- { ui::AX_ROLE_TABLE, NSAccessibilityTableRole },
- { ui::AX_ROLE_TABLE_HEADER_CONTAINER, NSAccessibilityGroupRole },
- { ui::AX_ROLE_TAB_LIST, NSAccessibilityTabGroupRole },
- { ui::AX_ROLE_TAB_PANEL, NSAccessibilityGroupRole },
- { ui::AX_ROLE_TEXT_AREA, NSAccessibilityTextAreaRole },
- { ui::AX_ROLE_TEXT_FIELD, NSAccessibilityTextFieldRole },
- { ui::AX_ROLE_TIMER, NSAccessibilityGroupRole },
- { ui::AX_ROLE_TOGGLE_BUTTON, NSAccessibilityCheckBoxRole },
- { ui::AX_ROLE_TOOLBAR, NSAccessibilityToolbarRole },
- { ui::AX_ROLE_TOOLTIP, NSAccessibilityGroupRole },
- { ui::AX_ROLE_TREE, NSAccessibilityOutlineRole },
- { ui::AX_ROLE_TREE_GRID, NSAccessibilityTableRole },
- { ui::AX_ROLE_TREE_ITEM, NSAccessibilityRowRole },
- { ui::AX_ROLE_VALUE_INDICATOR, NSAccessibilityValueIndicatorRole },
- { ui::AX_ROLE_WEB_AREA, @"AXWebArea" },
- { ui::AX_ROLE_WINDOW, NSAccessibilityWindowRole },
-
- // TODO(dtseng): we don't correctly support the attributes for these roles.
- // { ui::AX_ROLE_SCROLL_AREA, NSAccessibilityScrollAreaRole },
- };
-
- RoleMap role_map;
- for (size_t i = 0; i < arraysize(roles); ++i)
- role_map[roles[i].webKitValue] = roles[i].nativeValue;
- return role_map;
-}
-
-// A mapping of webkit roles to native roles.
-NSString* NativeRoleFromAXRole(
- const ui::AXRole& role) {
- CR_DEFINE_STATIC_LOCAL(RoleMap, web_accessibility_to_native_role,
- (BuildRoleMap()));
- RoleMap::iterator it = web_accessibility_to_native_role.find(role);
- if (it != web_accessibility_to_native_role.end())
- return it->second;
- else
- return NSAccessibilityUnknownRole;
-}
-
-RoleMap BuildSubroleMap() {
- const MapEntry subroles[] = {
- { ui::AX_ROLE_ALERT, @"AXApplicationAlert" },
- { ui::AX_ROLE_ALERT_DIALOG, @"AXApplicationAlertDialog" },
- { ui::AX_ROLE_ARTICLE, @"AXDocumentArticle" },
- { ui::AX_ROLE_DEFINITION, @"AXDefinition" },
- { ui::AX_ROLE_DESCRIPTION_LIST_DETAIL, @"AXDescription" },
- { ui::AX_ROLE_DESCRIPTION_LIST_TERM, @"AXTerm" },
- { ui::AX_ROLE_DIALOG, @"AXApplicationDialog" },
- { ui::AX_ROLE_DOCUMENT, @"AXDocument" },
- { ui::AX_ROLE_FOOTER, @"AXLandmarkContentInfo" },
- { ui::AX_ROLE_APPLICATION, @"AXLandmarkApplication" },
- { ui::AX_ROLE_BANNER, @"AXLandmarkBanner" },
- { ui::AX_ROLE_COMPLEMENTARY, @"AXLandmarkComplementary" },
- { ui::AX_ROLE_CONTENT_INFO, @"AXLandmarkContentInfo" },
- { ui::AX_ROLE_MAIN, @"AXLandmarkMain" },
- { ui::AX_ROLE_NAVIGATION, @"AXLandmarkNavigation" },
- { ui::AX_ROLE_SEARCH, @"AXLandmarkSearch" },
- { ui::AX_ROLE_LOG, @"AXApplicationLog" },
- { ui::AX_ROLE_MARQUEE, @"AXApplicationMarquee" },
- { ui::AX_ROLE_MATH, @"AXDocumentMath" },
- { ui::AX_ROLE_NOTE, @"AXDocumentNote" },
- { ui::AX_ROLE_REGION, @"AXDocumentRegion" },
- { ui::AX_ROLE_STATUS, @"AXApplicationStatus" },
- { ui::AX_ROLE_TAB_PANEL, @"AXTabPanel" },
- { ui::AX_ROLE_TIMER, @"AXApplicationTimer" },
- { ui::AX_ROLE_TOGGLE_BUTTON, @"AXToggleButton" },
- { ui::AX_ROLE_TOOLTIP, @"AXUserInterfaceTooltip" },
- { ui::AX_ROLE_TREE_ITEM, NSAccessibilityOutlineRowSubrole },
- };
-
- RoleMap subrole_map;
- for (size_t i = 0; i < arraysize(subroles); ++i)
- subrole_map[subroles[i].webKitValue] = subroles[i].nativeValue;
- return subrole_map;
-}
-
-// A mapping of webkit roles to native subroles.
-NSString* NativeSubroleFromAXRole(
- const ui::AXRole& role) {
- CR_DEFINE_STATIC_LOCAL(RoleMap, web_accessibility_to_native_subrole,
- (BuildSubroleMap()));
- RoleMap::iterator it = web_accessibility_to_native_subrole.find(role);
- if (it != web_accessibility_to_native_subrole.end())
- return it->second;
- else
- return nil;
-}
-
// A mapping from an accessibility attribute to its method name.
NSDictionary* attributeToMethodNameMap = nil;
@@ -253,6 +69,7 @@ NSDictionary* attributeToMethodNameMap = nil;
{ NSAccessibilityDisclosureLevelAttribute, @"disclosureLevel" },
{ NSAccessibilityDisclosedRowsAttribute, @"disclosedRows" },
{ NSAccessibilityEnabledAttribute, @"enabled" },
+ { NSAccessibilityExpandedAttribute, @"expanded" },
{ NSAccessibilityFocusedAttribute, @"focused" },
{ NSAccessibilityHeaderAttribute, @"header" },
{ NSAccessibilityHelpAttribute, @"help" },
@@ -270,6 +87,7 @@ NSDictionary* attributeToMethodNameMap = nil;
{ NSAccessibilityRowIndexRangeAttribute, @"rowIndexRange" },
{ NSAccessibilityRowsAttribute, @"rows" },
// TODO(aboxhall): expose NSAccessibilityServesAsTitleForUIElementsAttribute
+ { NSAccessibilitySelectedChildrenAttribute, @"selectedChildren" },
{ NSAccessibilitySizeAttribute, @"size" },
{ NSAccessibilitySubroleAttribute, @"subrole" },
{ NSAccessibilityTabsAttribute, @"tabs" },
@@ -281,6 +99,7 @@ NSDictionary* attributeToMethodNameMap = nil;
{ NSAccessibilityValueDescriptionAttribute, @"valueDescription" },
{ NSAccessibilityVisibleCharacterRangeAttribute, @"visibleCharacterRange" },
{ NSAccessibilityVisibleCellsAttribute, @"visibleCells" },
+ { NSAccessibilityVisibleChildrenAttribute, @"visibleChildren" },
{ NSAccessibilityVisibleColumnsAttribute, @"visibleColumns" },
{ NSAccessibilityVisibleRowsAttribute, @"visibleRows" },
{ NSAccessibilityWindowAttribute, @"window" },
@@ -511,6 +330,11 @@ NSDictionary* attributeToMethodNameMap = nil;
GetState(browserAccessibility_, ui::AX_STATE_ENABLED)];
}
+- (NSNumber*)expanded {
+ return [NSNumber numberWithBool:
+ GetState(browserAccessibility_, ui::AX_STATE_EXPANDED)];
+}
+
- (NSNumber*)focused {
BrowserAccessibilityManager* manager = browserAccessibility_->manager();
NSNumber* ret = [NSNumber numberWithBool:
@@ -628,6 +452,11 @@ NSDictionary* attributeToMethodNameMap = nil;
if ([self internalRole] == ui::AX_ROLE_SPIN_BUTTON)
return NSAccessibilityVerticalOrientationValue;
+ if ([self internalRole] == ui::AX_ROLE_LIST ||
+ [self internalRole] == ui::AX_ROLE_LIST_BOX) {
+ return NSAccessibilityVerticalOrientationValue;
+ }
+
if (GetState(browserAccessibility_, ui::AX_STATE_VERTICAL))
return NSAccessibilityVerticalOrientationValue;
else
@@ -712,7 +541,7 @@ NSDictionary* attributeToMethodNameMap = nil;
else
return NSAccessibilityButtonRole;
}
- return NativeRoleFromAXRole(role);
+ return [AXPlatformNodeCocoa nativeRoleFromAXRole:role];
}
// Returns a string indicating the role description of this object.
@@ -752,9 +581,30 @@ NSDictionary* attributeToMethodNameMap = nil;
}
switch([self internalRole]) {
+ case ui::AX_ROLE_ARTICLE:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_ARTICLE));
+ case ui::AX_ROLE_BANNER:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_BANNER));
+ case ui::AX_ROLE_COMPLEMENTARY:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_COMPLEMENTARY));
+ case ui::AX_ROLE_CONTENT_INFO:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_ADDRESS));
case ui::AX_ROLE_FOOTER:
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
IDS_AX_ROLE_FOOTER));
+ case ui::AX_ROLE_MAIN:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_MAIN_CONTENT));
+ case ui::AX_ROLE_NAVIGATION:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_NAVIGATIONAL_LINK));
+ case ui::AX_ROLE_REGION:
+ return base::SysUTF16ToNSString(content_client->GetLocalizedString(
+ IDS_AX_ROLE_REGION));
case ui::AX_ROLE_SPIN_BUTTON:
// This control is similar to what VoiceOver calls a "stepper".
return base::SysUTF16ToNSString(content_client->GetLocalizedString(
@@ -829,6 +679,40 @@ NSDictionary* attributeToMethodNameMap = nil;
return ret;
}
+- (NSArray*)selectedChildren {
+ NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
+
+ BrowserAccessibilityManager* manager = browserAccessibility_->manager();
+ BrowserAccessibility* focusedChild =
+ manager->GetFocus(browserAccessibility_);
+ if (focusedChild && focusedChild != browserAccessibility_) {
+ // First try the focused child.
+ [ret addObject:focusedChild->ToBrowserAccessibilityCocoa()];
+ } else {
+ // Next try the active descendant.
+ int activeDescendantId;
+ if (browserAccessibility_->GetIntAttribute(
+ ui::AX_ATTR_ACTIVEDESCENDANT_ID, &activeDescendantId)) {
+ BrowserAccessibility* activeDescendant =
+ manager->GetFromID(activeDescendantId);
+ if (activeDescendant)
+ [ret addObject:activeDescendant->ToBrowserAccessibilityCocoa()];
+ } else {
+ // Otherwise return any children with the "selected" state, which
+ // may come from aria-selected.
+ uint32 childCount = browserAccessibility_->PlatformChildCount();
+ for (uint32 index = 0; index < childCount; ++index) {
+ BrowserAccessibility* child =
+ browserAccessibility_->PlatformGetChild(index);
+ if (child->HasState(ui::AX_STATE_SELECTED))
+ [ret addObject:child->ToBrowserAccessibilityCocoa()];
+ }
+ }
+ }
+
+ return ret;
+}
+
// Returns the size of this object.
- (NSValue*)size {
gfx::Rect bounds = browserAccessibility_->GetLocalBoundsRect();
@@ -843,18 +727,13 @@ NSDictionary* attributeToMethodNameMap = nil;
return @"AXSecureTextField";
}
- NSString* htmlTag = NSStringForStringAttribute(
- browserAccessibility_, ui::AX_ATTR_HTML_TAG);
+ if (browserAccessibilityRole == ui::AX_ROLE_DESCRIPTION_LIST)
+ return @"AXDescriptionList";
- if (browserAccessibilityRole == ui::AX_ROLE_LIST) {
- if ([htmlTag isEqualToString:@"dl"]) {
- return @"AXDescriptionList";
- } else {
- return @"AXContentList";
- }
- }
+ if (browserAccessibilityRole == ui::AX_ROLE_LIST)
+ return @"AXContentList";
- return NativeSubroleFromAXRole(browserAccessibilityRole);
+ return [AXPlatformNodeCocoa nativeSubroleFromAXRole:browserAccessibilityRole];
}
// Returns all tabs in this subtree.
@@ -1002,6 +881,18 @@ NSDictionary* attributeToMethodNameMap = nil;
return ret;
}
+- (NSArray*)visibleChildren {
+ NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
+ uint32 childCount = browserAccessibility_->PlatformChildCount();
+ for (uint32 index = 0; index < childCount; ++index) {
+ BrowserAccessibilityCocoa* child =
+ browserAccessibility_->PlatformGetChild(index)->
+ ToBrowserAccessibilityCocoa();
+ [ret addObject:child];
+ }
+ return ret;
+}
+
- (NSArray*)visibleColumns {
return [self columns];
}
@@ -1283,7 +1174,7 @@ NSDictionary* attributeToMethodNameMap = nil;
// Returns the count of the specified accessibility array attribute.
- (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute {
if (!browserAccessibility_)
- return nil;
+ return 0;
NSArray* fullArray = [self accessibilityAttributeValue:attribute];
return [fullArray count];
@@ -1299,6 +1190,7 @@ NSDictionary* attributeToMethodNameMap = nil;
NSAccessibilityChildrenAttribute,
NSAccessibilityDescriptionAttribute,
NSAccessibilityEnabledAttribute,
+ NSAccessibilityExpandedAttribute,
NSAccessibilityFocusedAttribute,
NSAccessibilityHelpAttribute,
NSAccessibilityLinkedUIElementsAttribute,
@@ -1396,6 +1288,12 @@ NSDictionary* attributeToMethodNameMap = nil;
nil]];
}
}
+ } else if ([role isEqualToString:NSAccessibilityListRole]) {
+ [ret addObjectsFromArray:[NSArray arrayWithObjects:
+ NSAccessibilityOrientationAttribute,
+ NSAccessibilitySelectedChildrenAttribute,
+ NSAccessibilityVisibleChildrenAttribute,
+ nil]];
}
// Add the url attribute only if it has a valid url.
@@ -1439,7 +1337,7 @@ NSDictionary* attributeToMethodNameMap = nil;
// Returns the index of the child in this objects array of children.
- (NSUInteger)accessibilityGetIndexOf:(id)child {
if (!browserAccessibility_)
- return nil;
+ return 0;
NSUInteger index = 0;
for (BrowserAccessibilityCocoa* childToCheck in [self children]) {
@@ -1454,7 +1352,7 @@ NSDictionary* attributeToMethodNameMap = nil;
// accessibility API via |accessibilitySetValue:forAttribute:|.
- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute {
if (!browserAccessibility_)
- return nil;
+ return NO;
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute])
return GetState(browserAccessibility_,
@@ -1471,7 +1369,7 @@ NSDictionary* attributeToMethodNameMap = nil;
return NO;
}
-// Returns whether or not this object should be ignored in the accessibilty
+// Returns whether or not this object should be ignored in the accessibility
// tree.
- (BOOL)accessibilityIsIgnored {
if (!browserAccessibility_)
@@ -1480,7 +1378,7 @@ NSDictionary* attributeToMethodNameMap = nil;
return [self isIgnored];
}
-// Performs the given accessibilty action on the webkit accessibility object
+// Performs the given accessibility action on the webkit accessibility object
// that backs this object.
- (void)accessibilityPerformAction:(NSString*)action {
if (!browserAccessibility_)
@@ -1491,7 +1389,12 @@ NSDictionary* attributeToMethodNameMap = nil;
[self delegate]->AccessibilityDoDefaultAction(
browserAccessibility_->GetId());
} else if ([action isEqualToString:NSAccessibilityShowMenuAction]) {
- [self delegate]->AccessibilityShowMenu(browserAccessibility_->GetId());
+ NSPoint objOrigin = [self origin];
+ NSSize size = [[self size] sizeValue];
+ gfx::Point origin = [self delegate]->AccessibilityOriginInScreen(
+ gfx::Rect(objOrigin.x, objOrigin.y, size.width, size.height));
+ origin.Offset(size.width / 2, size.height / 2);
+ [self delegate]->AccessibilityShowMenu(origin);
}
}
@@ -1516,10 +1419,11 @@ NSDictionary* attributeToMethodNameMap = nil;
return;
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
+ BrowserAccessibilityManager* manager = browserAccessibility_->manager();
NSNumber* focusedNumber = value;
BOOL focused = [focusedNumber intValue];
if (focused)
- [self delegate]->AccessibilitySetFocus(browserAccessibility_->GetId());
+ manager->SetFocus(browserAccessibility_, true);
}
if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
NSRange range = [(NSValue*)value rangeValue];
diff --git a/chromium/content/browser/accessibility/browser_accessibility_mac.h b/chromium/content/browser/accessibility/browser_accessibility_mac.h
index e1b5e384dc1..9802c60734f 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_mac.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_mac.h
@@ -18,9 +18,9 @@ namespace content {
class BrowserAccessibilityMac : public BrowserAccessibility {
public:
// BrowserAccessibility overrides.
- virtual void NativeReleaseReference() OVERRIDE;
- virtual bool IsNative() const OVERRIDE;
- virtual void OnDataChanged() OVERRIDE;
+ void NativeReleaseReference() override;
+ bool IsNative() const override;
+ void OnDataChanged() override;
// The BrowserAccessibilityCocoa associated with us.
BrowserAccessibilityCocoa* native_view() const {
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.cc b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
index 6bdce2d907a..1e368c6f8d8 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "content/browser/accessibility/browser_accessibility.h"
#include "content/common/accessibility_messages.h"
+#include "ui/accessibility/ax_tree_serializer.h"
namespace content {
@@ -48,6 +49,15 @@ BrowserAccessibility* BrowserAccessibilityFactory::Create() {
return BrowserAccessibility::Create();
}
+BrowserAccessibilityFindInPageInfo::BrowserAccessibilityFindInPageInfo()
+ : request_id(-1),
+ match_index(-1),
+ start_id(-1),
+ start_offset(0),
+ end_id(-1),
+ end_offset(-1),
+ active_request_id(-1) {}
+
#if !defined(OS_MACOSX) && \
!defined(OS_WIN) && \
!defined(OS_ANDROID) \
@@ -67,7 +77,7 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
BrowserAccessibilityFactory* factory)
: delegate_(delegate),
factory_(factory),
- tree_(new ui::AXTree()),
+ tree_(new ui::AXSerializableTree()),
focus_(NULL),
osk_state_(OSK_ALLOWED) {
tree_->SetDelegate(this);
@@ -79,7 +89,7 @@ BrowserAccessibilityManager::BrowserAccessibilityManager(
BrowserAccessibilityFactory* factory)
: delegate_(delegate),
factory_(factory),
- tree_(new ui::AXTree()),
+ tree_(new ui::AXSerializableTree()),
focus_(NULL),
osk_state_(OSK_ALLOWED) {
tree_->SetDelegate(this);
@@ -224,6 +234,43 @@ void BrowserAccessibilityManager::OnLocationChanges(
}
}
+void BrowserAccessibilityManager::OnFindInPageResult(
+ int request_id, int match_index, int start_id, int start_offset,
+ int end_id, int end_offset) {
+ find_in_page_info_.request_id = request_id;
+ find_in_page_info_.match_index = match_index;
+ find_in_page_info_.start_id = start_id;
+ find_in_page_info_.start_offset = start_offset;
+ find_in_page_info_.end_id = end_id;
+ find_in_page_info_.end_offset = end_offset;
+
+ if (find_in_page_info_.active_request_id == request_id)
+ ActivateFindInPageResult(request_id);
+}
+
+void BrowserAccessibilityManager::ActivateFindInPageResult(
+ int request_id) {
+ find_in_page_info_.active_request_id = request_id;
+ if (find_in_page_info_.request_id != request_id)
+ return;
+
+ BrowserAccessibility* node = GetFromID(find_in_page_info_.start_id);
+ if (!node)
+ return;
+
+ // If an ancestor of this node is a leaf node, fire the notification on that.
+ BrowserAccessibility* ancestor = node->GetParent();
+ while (ancestor && ancestor != GetRoot()) {
+ if (ancestor->PlatformIsLeaf())
+ node = ancestor;
+ ancestor = ancestor->GetParent();
+ }
+
+ // The "scrolled to anchor" notification is a great way to get a
+ // screen reader to jump directly to a specific location in a document.
+ NotifyAccessibilityEvent(ui::AX_EVENT_SCROLLED_TO_ANCHOR, node);
+}
+
BrowserAccessibility* BrowserAccessibilityManager::GetActiveDescendantFocus(
BrowserAccessibility* root) {
BrowserAccessibility* node = BrowserAccessibilityManager::GetFocus(root);
@@ -283,8 +330,17 @@ void BrowserAccessibilityManager::ScrollToPoint(
}
}
+void BrowserAccessibilityManager::SetValue(
+ const BrowserAccessibility& node,
+ const base::string16& value) {
+ if (delegate_)
+ delegate_->AccessibilitySetValue(node.GetId(), value);
+}
+
void BrowserAccessibilityManager::SetTextSelection(
- const BrowserAccessibility& node, int start_offset, int end_offset) {
+ const BrowserAccessibility& node,
+ int start_offset,
+ int end_offset) {
if (delegate_) {
delegate_->AccessibilitySetTextSelection(
node.GetId(), start_offset, end_offset);
@@ -363,4 +419,13 @@ void BrowserAccessibilityManager::OnNodeChangeFinished(ui::AXNode* node) {
GetFromAXNode(node)->OnUpdateFinished();
}
+ui::AXTreeUpdate BrowserAccessibilityManager::SnapshotAXTreeForTesting() {
+ scoped_ptr<ui::AXTreeSource<const ui::AXNode*> > tree_source(
+ tree_->CreateTreeSource());
+ ui::AXTreeSerializer<const ui::AXNode*> serializer(tree_source.get());
+ ui::AXTreeUpdate update;
+ serializer.SerializeChanges(tree_->GetRoot(), &update);
+ return update;
+}
+
} // namespace content
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager.h b/chromium/content/browser/accessibility/browser_accessibility_manager.h
index ae0bc30b31f..c0e59fa1d68 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager.h
@@ -13,7 +13,7 @@
#include "content/common/content_export.h"
#include "third_party/WebKit/public/web/WebAXEnums.h"
#include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree.h"
+#include "ui/accessibility/ax_serializable_tree.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/gfx/native_widget_types.h"
@@ -22,6 +22,7 @@ struct AccessibilityHostMsg_LocationChangeParams;
namespace content {
class BrowserAccessibility;
+class BrowserAccessibilityManager;
#if defined(OS_ANDROID)
class BrowserAccessibilityManagerAndroid;
#endif
@@ -42,25 +43,39 @@ CONTENT_EXPORT ui::AXTreeUpdate MakeAXTreeUpdate(
const ui::AXNodeData& node9 = ui::AXNodeData());
// Class that can perform actions on behalf of the BrowserAccessibilityManager.
+// Note: BrowserAccessibilityManager should never cache any of the return
+// values from any of these interfaces, especially those that return pointers.
+// They may only be valid within this call stack. That policy eliminates any
+// concerns about ownership and lifecycle issues; none of these interfaces
+// transfer ownership and no return values are guaranteed to be valid outside
+// of the current call stack.
class CONTENT_EXPORT BrowserAccessibilityDelegate {
public:
virtual ~BrowserAccessibilityDelegate() {}
virtual void AccessibilitySetFocus(int acc_obj_id) = 0;
virtual void AccessibilityDoDefaultAction(int acc_obj_id) = 0;
- virtual void AccessibilityShowMenu(int acc_obj_id) = 0;
+ virtual void AccessibilityShowMenu(const gfx::Point& global_point) = 0;
virtual void AccessibilityScrollToMakeVisible(
- int acc_obj_id, gfx::Rect subfocus) = 0;
+ int acc_obj_id, const gfx::Rect& subfocus) = 0;
virtual void AccessibilityScrollToPoint(
- int acc_obj_id, gfx::Point point) = 0;
+ int acc_obj_id, const gfx::Point& point) = 0;
virtual void AccessibilitySetTextSelection(
int acc_obj_id, int start_offset, int end_offset) = 0;
+ virtual void AccessibilitySetValue(
+ int acc_obj_id, const base::string16& value) = 0;
virtual bool AccessibilityViewHasFocus() const = 0;
virtual gfx::Rect AccessibilityGetViewBounds() const = 0;
virtual gfx::Point AccessibilityOriginInScreen(
const gfx::Rect& bounds) const = 0;
virtual void AccessibilityHitTest(
const gfx::Point& point) = 0;
+ virtual void AccessibilitySetAccessibilityFocus(int acc_obj_id) = 0;
virtual void AccessibilityFatalError() = 0;
+ virtual gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() = 0;
+ virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() = 0;
+ virtual BrowserAccessibilityManager* AccessibilityGetChildFrame(
+ int accessibility_node_id) = 0;
+ virtual BrowserAccessibility* AccessibilityGetParentFrame() = 0;
};
class CONTENT_EXPORT BrowserAccessibilityFactory {
@@ -72,6 +87,26 @@ class CONTENT_EXPORT BrowserAccessibilityFactory {
virtual BrowserAccessibility* Create();
};
+// This is all of the information about the current find in page result,
+// so we can activate it if requested.
+struct BrowserAccessibilityFindInPageInfo {
+ BrowserAccessibilityFindInPageInfo();
+
+ // This data about find in text results is updated as the user types.
+ int request_id;
+ int match_index;
+ int start_id;
+ int start_offset;
+ int end_id;
+ int end_offset;
+
+ // The active request id indicates that the user committed to a find query,
+ // e.g. by pressing enter or pressing the next or previous buttons. If
+ // |active_request_id| == |request_id|, we fire an accessibility event
+ // to move screen reader focus to that event.
+ int active_request_id;
+};
+
// Manages a tree of BrowserAccessibility objects.
class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
public:
@@ -82,7 +117,7 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
- virtual ~BrowserAccessibilityManager();
+ ~BrowserAccessibilityManager() override;
void Initialize(const ui::AXTreeUpdate& initial_tree);
@@ -134,6 +169,10 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
void ScrollToPoint(
const BrowserAccessibility& node, gfx::Point point);
+ // Tell the renderer to set the value of an editable text node.
+ void SetValue(
+ const BrowserAccessibility& node, const base::string16& value);
+
// Tell the renderer to set the text selection on a node.
void SetTextSelection(
const BrowserAccessibility& node, int start_offset, int end_offset);
@@ -141,6 +180,10 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
// Retrieve the bounds of the parent View in screen coordinates.
gfx::Rect GetViewBounds();
+ // Fire an event telling native assistive technology to move focus to the
+ // given find in page result.
+ void ActivateFindInPageResult(int request_id, int match_index);
+
// Called when the renderer process has notified us of about tree changes.
void OnAccessibilityEvents(
const std::vector<AccessibilityHostMsg_EventParams>& params);
@@ -150,6 +193,20 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
void OnLocationChanges(
const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
+ // Called when a new find in page result is received. We hold on to this
+ // information and don't activate it until the user requests it.
+ void OnFindInPageResult(
+ int request_id, int match_index, int start_id, int start_offset,
+ int end_id, int end_offset);
+
+ // 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,
+ // activate the result now by firing an accessibility event. If a match
+ // has not been received, we hold onto this request id and update it
+ // when OnFindInPageResult is called.
+ void ActivateFindInPageResult(int request_id);
+
#if defined(OS_WIN)
BrowserAccessibilityManagerWin* ToBrowserAccessibilityManagerWin();
#endif
@@ -175,14 +232,20 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
BrowserAccessibility* PreviousInTreeOrder(BrowserAccessibility* node);
// AXTreeDelegate implementation.
- virtual void OnNodeWillBeDeleted(ui::AXNode* node) OVERRIDE;
- virtual void OnNodeCreated(ui::AXNode* node) OVERRIDE;
- virtual void OnNodeChanged(ui::AXNode* node) OVERRIDE;
- virtual void OnNodeCreationFinished(ui::AXNode* node) OVERRIDE;
- virtual void OnNodeChangeFinished(ui::AXNode* node) OVERRIDE;
- virtual void OnRootChanged(ui::AXNode* new_root) OVERRIDE {}
+ void OnNodeWillBeDeleted(ui::AXNode* node) override;
+ void OnNodeCreated(ui::AXNode* node) override;
+ void OnNodeChanged(ui::AXNode* node) override;
+ void OnNodeCreationFinished(ui::AXNode* node) override;
+ void OnNodeChangeFinished(ui::AXNode* node) override;
+ void OnRootChanged(ui::AXNode* new_root) override {}
BrowserAccessibilityDelegate* delegate() const { return delegate_; }
+ void set_delegate(BrowserAccessibilityDelegate* delegate) {
+ delegate_ = delegate;
+ }
+
+ // Get a snapshot of the current tree as an AXTreeUpdate.
+ ui::AXTreeUpdate SnapshotAXTreeForTesting();
protected:
BrowserAccessibilityManager(
@@ -220,21 +283,6 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
OSK_ALLOWED
};
- // Update a set of nodes using data received from the renderer
- // process.
- bool UpdateNodes(const std::vector<ui::AXNodeData>& nodes);
-
- // Update one node from the tree using data received from the renderer
- // process. Returns true on success, false on fatal error.
- bool UpdateNode(const ui::AXNodeData& src);
-
- void SetRoot(BrowserAccessibility* root);
-
- BrowserAccessibility* CreateNode(
- BrowserAccessibility* parent,
- int32 id,
- int32 index_in_parent);
-
protected:
// The object that can perform actions on our behalf.
BrowserAccessibilityDelegate* delegate_;
@@ -243,7 +291,7 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
scoped_ptr<BrowserAccessibilityFactory> factory_;
// The underlying tree of accessibility objects.
- scoped_ptr<ui::AXTree> tree_;
+ scoped_ptr<ui::AXSerializableTree> tree_;
// The node that currently has focus.
ui::AXNode* focus_;
@@ -254,6 +302,8 @@ class CONTENT_EXPORT BrowserAccessibilityManager : public ui::AXTreeDelegate {
// The on-screen keyboard state.
OnScreenKeyboardState osk_state_;
+ BrowserAccessibilityFindInPageInfo find_in_page_info_;
+
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManager);
};
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
index 07f04e71b45..fd4e0ff9fae 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -8,24 +8,20 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
+#include "base/i18n/char_iterator.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/browser/accessibility/browser_accessibility_android.h"
#include "content/common/accessibility_messages.h"
#include "jni/BrowserAccessibilityManager_jni.h"
+#include "ui/accessibility/ax_text_utils.h"
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
namespace {
-// These are enums from android.view.accessibility.AccessibilityEvent in Java:
-enum {
- ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_CHANGED = 16,
- ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192
-};
-
enum AndroidHtmlElementType {
HTML_ELEMENT_TYPE_SECTION,
HTML_ELEMENT_TYPE_LIST,
@@ -74,8 +70,9 @@ BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid(
const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory)
- : BrowserAccessibilityManager(initial_tree, delegate, factory) {
+ : BrowserAccessibilityManager(delegate, factory) {
SetContentViewCore(content_view_core);
+ Initialize(initial_tree);
}
BrowserAccessibilityManagerAndroid::~BrowserAccessibilityManagerAndroid() {
@@ -119,9 +116,15 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
if (obj.is_null())
return;
+ BrowserAccessibilityAndroid* android_node =
+ static_cast<BrowserAccessibilityAndroid*>(node);
+
if (event_type == ui::AX_EVENT_HIDE)
return;
+ if (event_type == ui::AX_EVENT_TREE_CHANGED)
+ return;
+
if (event_type == ui::AX_EVENT_HOVER) {
HandleHoverEvent(node);
return;
@@ -160,15 +163,13 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
case ui::AX_EVENT_SHOW: {
// This event is fired when an object appears in a live region.
// Speak its text.
- BrowserAccessibilityAndroid* android_node =
- static_cast<BrowserAccessibilityAndroid*>(node);
Java_BrowserAccessibilityManager_announceLiveRegionText(
env, obj.obj(),
base::android::ConvertUTF16ToJavaString(
env, android_node->GetText()).obj());
break;
}
- case ui::AX_EVENT_SELECTED_TEXT_CHANGED:
+ case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
Java_BrowserAccessibilityManager_handleTextSelectionChanged(
env, obj.obj(), node->GetId());
break;
@@ -178,6 +179,9 @@ void BrowserAccessibilityManagerAndroid::NotifyAccessibilityEvent(
if (node->IsEditableText()) {
Java_BrowserAccessibilityManager_handleEditableTextChanged(
env, obj.obj(), node->GetId());
+ } else if (android_node->IsSlider()) {
+ Java_BrowserAccessibilityManager_handleSliderChanged(
+ env, obj.obj(), node->GetId());
}
break;
default:
@@ -202,6 +206,36 @@ void BrowserAccessibilityManagerAndroid::HitTest(
delegate()->AccessibilityHitTest(gfx::Point(x, y));
}
+jboolean BrowserAccessibilityManagerAndroid::IsEditableText(
+ JNIEnv* env, jobject obj, jint id) {
+ BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
+ GetFromID(id));
+ if (!node)
+ return false;
+
+ return node->IsEditableText();
+}
+
+jint BrowserAccessibilityManagerAndroid::GetEditableTextSelectionStart(
+ JNIEnv* env, jobject obj, jint id) {
+ BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
+ GetFromID(id));
+ if (!node)
+ return false;
+
+ return node->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_START);
+}
+
+jint BrowserAccessibilityManagerAndroid::GetEditableTextSelectionEnd(
+ JNIEnv* env, jobject obj, jint id) {
+ BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
+ GetFromID(id));
+ if (!node)
+ return false;
+
+ return node->GetIntAttribute(ui::AX_ATTR_TEXT_SEL_END);
+}
+
jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
JNIEnv* env, jobject obj, jobject info, jint id) {
BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
@@ -220,9 +254,12 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoBooleanAttributes(
env, obj, info,
id,
+ node->CanScrollForward(),
+ node->CanScrollBackward(),
node->IsCheckable(),
node->IsChecked(),
node->IsClickable(),
+ node->IsEditableText(),
node->IsEnabled(),
node->IsFocusable(),
node->IsFocused(),
@@ -233,10 +270,13 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoClassName(
env, obj, info,
base::android::ConvertUTF8ToJavaString(env, node->GetClassName()).obj());
- Java_BrowserAccessibilityManager_setAccessibilityNodeInfoContentDescription(
- env, obj, info,
- base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj(),
- node->IsLink());
+ if (!node->IsPassword() ||
+ Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) {
+ Java_BrowserAccessibilityManager_setAccessibilityNodeInfoContentDescription(
+ env, obj, info,
+ base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj(),
+ node->IsLink());
+ }
gfx::Rect absolute_rect = node->GetLocalBoundsRect();
gfx::Rect parent_relative_rect = absolute_rect;
@@ -247,6 +287,7 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityNodeInfo(
bool is_root = node->GetParent() == NULL;
Java_BrowserAccessibilityManager_setAccessibilityNodeInfoLocation(
env, obj, info,
+ id,
absolute_rect.x(), absolute_rect.y(),
parent_relative_rect.x(), parent_relative_rect.y(),
absolute_rect.width(), absolute_rect.height(),
@@ -317,24 +358,37 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent(
node->GetMaxScrollY());
switch (event_type) {
- case ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_CHANGED:
+ case ANDROID_ACCESSIBILITY_EVENT_TEXT_CHANGED: {
+ base::string16 before_text, text;
+ if (!node->IsPassword() ||
+ Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) {
+ before_text = node->GetTextChangeBeforeText();
+ text = node->GetText();
+ }
Java_BrowserAccessibilityManager_setAccessibilityEventTextChangedAttrs(
env, obj, event,
node->GetTextChangeFromIndex(),
node->GetTextChangeAddedCount(),
node->GetTextChangeRemovedCount(),
base::android::ConvertUTF16ToJavaString(
- env, node->GetTextChangeBeforeText()).obj(),
- base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj());
+ env, before_text).obj(),
+ base::android::ConvertUTF16ToJavaString(env, text).obj());
break;
- case ANDROID_ACCESSIBILITY_EVENT_TYPE_VIEW_TEXT_SELECTION_CHANGED:
+ }
+ case ANDROID_ACCESSIBILITY_EVENT_TEXT_SELECTION_CHANGED: {
+ base::string16 text;
+ if (!node->IsPassword() ||
+ Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) {
+ text = node->GetText();
+ }
Java_BrowserAccessibilityManager_setAccessibilityEventSelectionAttrs(
env, obj, event,
node->GetSelectionStart(),
node->GetSelectionEnd(),
node->GetEditableTextLength(),
- base::android::ConvertUTF16ToJavaString(env, node->GetText()).obj());
+ base::android::ConvertUTF16ToJavaString(env, text).obj());
break;
+ }
default:
break;
}
@@ -355,14 +409,17 @@ jboolean BrowserAccessibilityManagerAndroid::PopulateAccessibilityEvent(
node->ColumnCount(),
node->IsHierarchical());
}
- if (node->IsCollectionItem() || node->IsHeading()) {
+ if (node->IsHeading()) {
+ Java_BrowserAccessibilityManager_setAccessibilityEventHeadingFlag(
+ env, obj, event, true);
+ }
+ if (node->IsCollectionItem()) {
Java_BrowserAccessibilityManager_setAccessibilityEventCollectionItemInfo(
env, obj, event,
node->RowIndex(),
node->RowSpan(),
node->ColumnIndex(),
- node->ColumnSpan(),
- node->IsHeading());
+ node->ColumnSpan());
}
if (node->IsRangeType()) {
Java_BrowserAccessibilityManager_setAccessibilityEventRangeInfo(
@@ -401,6 +458,54 @@ void BrowserAccessibilityManagerAndroid::ScrollToMakeNodeVisible(
ScrollToMakeVisible(*node, gfx::Rect(node->GetLocation().size()));
}
+void BrowserAccessibilityManagerAndroid::SetTextFieldValue(
+ JNIEnv* env, jobject obj, jint id, jstring value) {
+ BrowserAccessibility* node = GetFromID(id);
+ if (node) {
+ BrowserAccessibilityManager::SetValue(
+ *node, base::android::ConvertJavaStringToUTF16(env, value));
+ }
+}
+
+void BrowserAccessibilityManagerAndroid::SetSelection(
+ JNIEnv* env, jobject obj, jint id, jint start, jint end) {
+ BrowserAccessibility* node = GetFromID(id);
+ if (node)
+ SetTextSelection(*node, start, end);
+}
+
+jboolean BrowserAccessibilityManagerAndroid::AdjustSlider(
+ JNIEnv* env, jobject obj, jint id, jboolean increment) {
+ BrowserAccessibility* node = GetFromID(id);
+ if (!node)
+ return false;
+
+ BrowserAccessibilityAndroid* android_node =
+ static_cast<BrowserAccessibilityAndroid*>(node);
+
+ if (!android_node->IsSlider() || !android_node->IsEnabled())
+ return false;
+
+ float value = node->GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE);
+ float min = node->GetFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE);
+ float max = node->GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE);
+ if (max <= min)
+ return false;
+
+ // To behave similarly to an Android SeekBar, move by an increment of
+ // approximately 20%.
+ float original_value = value;
+ float delta = (max - min) / 5.0f;
+ value += (increment ? delta : -delta);
+ value = std::max(std::min(value, max), min);
+ if (value != original_value) {
+ BrowserAccessibilityManager::SetValue(
+ *node, base::UTF8ToUTF16(base::DoubleToString(value)));
+ return true;
+ }
+ return false;
+}
+
void BrowserAccessibilityManagerAndroid::HandleHoverEvent(
BrowserAccessibility* node) {
JNIEnv* env = AttachCurrentThread();
@@ -410,7 +515,7 @@ void BrowserAccessibilityManagerAndroid::HandleHoverEvent(
BrowserAccessibilityAndroid* ancestor =
static_cast<BrowserAccessibilityAndroid*>(node->GetParent());
- while (ancestor) {
+ while (ancestor && ancestor != GetRoot()) {
if (ancestor->PlatformIsLeaf() ||
(ancestor->IsFocusable() && !ancestor->HasFocusableChild())) {
node = ancestor;
@@ -481,6 +586,144 @@ jint BrowserAccessibilityManagerAndroid::FindElementType(
return 0;
}
+jboolean BrowserAccessibilityManagerAndroid::NextAtGranularity(
+ JNIEnv* env, jobject obj, jint granularity, jboolean extend_selection,
+ jint id, jint cursor_index) {
+ BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
+ GetFromID(id));
+ if (!node)
+ return false;
+
+ jint start_index = -1;
+ int end_index = -1;
+ if (NextAtGranularity(granularity, cursor_index, node,
+ &start_index, &end_index)) {
+ base::string16 text;
+ if (!node->IsPassword() ||
+ Java_BrowserAccessibilityManager_shouldExposePasswordText(env, obj)) {
+ text = node->GetText();
+ }
+ Java_BrowserAccessibilityManager_finishGranularityMove(
+ env, obj, base::android::ConvertUTF16ToJavaString(
+ env, text).obj(),
+ extend_selection, start_index, end_index, true);
+ return true;
+ }
+ return false;
+}
+
+jboolean BrowserAccessibilityManagerAndroid::PreviousAtGranularity(
+ JNIEnv* env, jobject obj, jint granularity, jboolean extend_selection,
+ jint id, jint cursor_index) {
+ BrowserAccessibilityAndroid* node = static_cast<BrowserAccessibilityAndroid*>(
+ GetFromID(id));
+ if (!node)
+ return false;
+
+ jint start_index = -1;
+ int end_index = -1;
+ if (PreviousAtGranularity(granularity, cursor_index, node,
+ &start_index, &end_index)) {
+ Java_BrowserAccessibilityManager_finishGranularityMove(
+ env, obj, base::android::ConvertUTF16ToJavaString(
+ env, node->GetText()).obj(),
+ extend_selection, start_index, end_index, false);
+ return true;
+ }
+ return false;
+}
+
+bool BrowserAccessibilityManagerAndroid::NextAtGranularity(
+ int32 granularity, int32 cursor_index,
+ BrowserAccessibilityAndroid* node, int32* start_index, int32* end_index) {
+ switch (granularity) {
+ case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_CHARACTER: {
+ base::string16 text = node->GetText();
+ if (cursor_index >= static_cast<int32>(text.length()))
+ return false;
+ base::i18n::UTF16CharIterator iter(text.data(), text.size());
+ while (!iter.end() && iter.array_pos() <= cursor_index)
+ iter.Advance();
+ *start_index = iter.array_pos();
+ *end_index = iter.array_pos();
+ break;
+ }
+ case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD:
+ case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE: {
+ std::vector<int32> starts;
+ std::vector<int32> ends;
+ node->GetGranularityBoundaries(granularity, &starts, &ends, 0);
+ if (starts.size() == 0)
+ return false;
+
+ size_t index = 0;
+ while (index < starts.size() - 1 && starts[index] < cursor_index)
+ index++;
+
+ if (starts[index] < cursor_index)
+ return false;
+
+ *start_index = starts[index];
+ *end_index = ends[index];
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+
+ return true;
+}
+
+bool BrowserAccessibilityManagerAndroid::PreviousAtGranularity(
+ int32 granularity, int32 cursor_index,
+ BrowserAccessibilityAndroid* node, int32* start_index, int32* end_index) {
+ switch (granularity) {
+ case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_CHARACTER: {
+ if (cursor_index <= 0)
+ return false;
+ base::string16 text = node->GetText();
+ base::i18n::UTF16CharIterator iter(text.data(), text.size());
+ int previous_index = 0;
+ while (!iter.end() && iter.array_pos() < cursor_index) {
+ previous_index = iter.array_pos();
+ iter.Advance();
+ }
+ *start_index = previous_index;
+ *end_index = previous_index;
+ break;
+ }
+ case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD:
+ case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE: {
+ std::vector<int32> starts;
+ std::vector<int32> ends;
+ node->GetGranularityBoundaries(granularity, &starts, &ends, 0);
+ if (starts.size() == 0)
+ return false;
+
+ size_t index = starts.size() - 1;
+ while (index > 0 && starts[index] >= cursor_index)
+ index--;
+
+ if (starts[index] >= cursor_index)
+ return false;
+
+ *start_index = starts[index];
+ *end_index = ends[index];
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+
+ return true;
+}
+
+void BrowserAccessibilityManagerAndroid::SetAccessibilityFocus(
+ JNIEnv* env, jobject obj, jint id) {
+ if (delegate_)
+ delegate_->AccessibilitySetAccessibilityFocus(id);
+}
+
void BrowserAccessibilityManagerAndroid::OnRootChanged(ui::AXNode* new_root) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_android.h b/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
index a40f7e7cf88..f0e2d344ac1 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_android.h
@@ -16,6 +16,22 @@ namespace aria_strings {
extern const char kAriaLiveAssertive[];
}
+// From android.view.accessibility.AccessibilityNodeInfo in Java:
+enum AndroidMovementGranularity {
+ ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_CHARACTER = 1,
+ ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD = 2,
+ ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE = 4
+};
+
+// From android.view.accessibility.AccessibilityEvent in Java:
+enum {
+ ANDROID_ACCESSIBILITY_EVENT_TEXT_CHANGED = 16,
+ ANDROID_ACCESSIBILITY_EVENT_TEXT_SELECTION_CHANGED = 8192,
+ ANDROID_ACCESSIBILITY_EVENT_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072
+};
+
+class BrowserAccessibilityAndroid;
+
class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
: public BrowserAccessibilityManager {
public:
@@ -34,7 +50,7 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
// Implementation of BrowserAccessibilityManager.
virtual void NotifyAccessibilityEvent(
- ui::AXEvent event_type, BrowserAccessibility* node) OVERRIDE;
+ ui::AXEvent event_type, BrowserAccessibility* node) override;
// --------------------------------------------------------------------------
// Methods called from Java via JNI
@@ -45,6 +61,11 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
jboolean IsNodeValid(JNIEnv* env, jobject obj, jint id);
void HitTest(JNIEnv* env, jobject obj, jint x, jint y);
+ // Methods to get information about a specific node.
+ jboolean IsEditableText(JNIEnv* env, jobject obj, jint id);
+ jint GetEditableTextSelectionStart(JNIEnv* env, jobject obj, jint id);
+ jint GetEditableTextSelectionEnd(JNIEnv* env, jobject obj, jint id);
+
// Populate Java accessibility data structures with info about a node.
jboolean PopulateAccessibilityNodeInfo(
JNIEnv* env, jobject obj, jobject info, jint id);
@@ -55,7 +76,10 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
void Click(JNIEnv* env, jobject obj, jint id);
void Focus(JNIEnv* env, jobject obj, jint id);
void Blur(JNIEnv* env, jobject obj);
- void ScrollToMakeNodeVisible(JNIEnv* env, jobject obj, int id);
+ void ScrollToMakeNodeVisible(JNIEnv* env, jobject obj, jint id);
+ void SetTextFieldValue(JNIEnv* env, jobject obj, jint id, jstring value);
+ void SetSelection(JNIEnv* env, jobject obj, jint id, jint start, jint end);
+ jboolean AdjustSlider(JNIEnv* env, jobject obj, jint id, jboolean increment);
// Return the id of the next node in tree order in the direction given by
// |forwards|, starting with |start_id|, that matches |element_type|,
@@ -65,11 +89,43 @@ class CONTENT_EXPORT BrowserAccessibilityManagerAndroid
jint FindElementType(JNIEnv* env, jobject obj, jint start_id,
jstring element_type, jboolean forwards);
+ // Respond to a ACTION_[NEXT/PREVIOUS]_AT_MOVEMENT_GRANULARITY action
+ // and move the cursor/selection within the given node id. We keep track
+ // of our own selection in BrowserAccessibilityManager.java for static
+ // text, but if this is an editable text node, updates the selected text
+ // in Blink, too, and either way calls
+ // Java_BrowserAccessibilityManager_finishGranularityMove with the
+ // result.
+ jboolean NextAtGranularity(JNIEnv* env, jobject obj,
+ jint granularity, jboolean extend_selection,
+ jint id, jint cursor_index);
+ jboolean PreviousAtGranularity(JNIEnv* env, jobject obj,
+ jint granularity, jboolean extend_selection,
+ jint id, jint cursor_index);
+
+ // Helper functions to compute the next start and end index when moving
+ // forwards or backwards by character, word, or line. This part is
+ // unit-tested; the Java interfaces above are just wrappers. Both of these
+ // take a single cursor index as input and return the boundaries surrounding
+ // the next word or line. If moving by character, the output start and
+ // end index will be the same.
+ bool NextAtGranularity(
+ int32 granularity, int cursor_index,
+ BrowserAccessibilityAndroid* node, int32* start_index, int32* end_index);
+ bool PreviousAtGranularity(
+ int32 granularity, int cursor_index,
+ BrowserAccessibilityAndroid* node, int32* start_index, int32* end_index);
+
+ // Set accessibility focus. This sends a message to the renderer to
+ // asynchronously load inline text boxes for this node only, enabling more
+ // accurate movement by granularities on this node.
+ void SetAccessibilityFocus(JNIEnv* env, jobject obj, jint id);
+
protected:
// AXTreeDelegate overrides.
- virtual void OnRootChanged(ui::AXNode* new_root) OVERRIDE;
+ virtual void OnRootChanged(ui::AXNode* new_root) override;
- virtual bool UseRootScrollOffsetsWhenComputingBounds() OVERRIDE;
+ virtual bool UseRootScrollOffsetsWhenComputingBounds() override;
private:
// This gives BrowserAccessibilityManager::Create access to the class
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h
index fb2a0eb47b0..b754a4b4468 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -22,17 +22,17 @@ class CONTENT_EXPORT BrowserAccessibilityManagerMac
static ui::AXTreeUpdate GetEmptyDocument();
- virtual BrowserAccessibility* GetFocus(BrowserAccessibility* root) OVERRIDE;
+ BrowserAccessibility* GetFocus(BrowserAccessibility* root) override;
// Implementation of BrowserAccessibilityManager.
- virtual void NotifyAccessibilityEvent(
- ui::AXEvent event_type, BrowserAccessibility* node) OVERRIDE;
+ void NotifyAccessibilityEvent(ui::AXEvent event_type,
+ BrowserAccessibility* node) override;
NSView* parent_view() { return parent_view_; }
private:
- virtual void OnNodeCreationFinished(ui::AXNode* node) OVERRIDE;
- virtual void OnTreeUpdateFinished() OVERRIDE;
+ void OnNodeCreationFinished(ui::AXNode* node) override;
+ void OnTreeUpdateFinished() override;
// This gives BrowserAccessibilityManager::Create access to the class
// constructor.
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 53d776bc287..2000d025acc 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -25,9 +25,10 @@ BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory)
- : BrowserAccessibilityManager(initial_tree, delegate, factory),
+ : BrowserAccessibilityManager(delegate, factory),
parent_view_(parent_view),
created_live_region_(false) {
+ Initialize(initial_tree);
}
// static
@@ -96,12 +97,6 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
case ui::AX_EVENT_MENU_LIST_VALUE_CHANGED:
// Not used on Mac.
return;
- case ui::AX_EVENT_SHOW:
- // Not used on Mac.
- return;
- case ui::AX_EVENT_HIDE:
- // Not used on Mac.
- return;
case ui::AX_EVENT_ROW_COUNT_CHANGED:
event_id = NSAccessibilityRowCountChangedNotification;
break;
@@ -117,15 +112,9 @@ void BrowserAccessibilityManagerMac::NotifyAccessibilityEvent(
case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED:
event_id = NSAccessibilitySelectedChildrenChangedNotification;
break;
- case ui::AX_EVENT_SELECTED_TEXT_CHANGED:
+ case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
event_id = NSAccessibilitySelectedTextChangedNotification;
break;
- case ui::AX_EVENT_TEXT_INSERTED:
- // Not used on Mac.
- return;
- case ui::AX_EVENT_TEXT_REMOVED:
- // Not used on Mac.
- return;
case ui::AX_EVENT_VALUE_CHANGED:
event_id = NSAccessibilityValueChangedNotification;
break;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index ddff85fd804..8e2e3d033b9 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -22,15 +22,11 @@ class CountedBrowserAccessibility : public BrowserAccessibility {
global_obj_count_++;
native_ref_count_ = 1;
}
- virtual ~CountedBrowserAccessibility() {
- global_obj_count_--;
- }
+ ~CountedBrowserAccessibility() override { global_obj_count_--; }
- virtual void NativeAddReference() OVERRIDE {
- native_ref_count_++;
- }
+ void NativeAddReference() override { native_ref_count_++; }
- virtual void NativeReleaseReference() OVERRIDE {
+ void NativeReleaseReference() override {
native_ref_count_--;
if (native_ref_count_ == 0)
delete this;
@@ -55,8 +51,8 @@ int CountedBrowserAccessibility::global_obj_count_ = 0;
class CountedBrowserAccessibilityFactory
: public BrowserAccessibilityFactory {
public:
- virtual ~CountedBrowserAccessibilityFactory() {}
- virtual BrowserAccessibility* Create() OVERRIDE {
+ ~CountedBrowserAccessibilityFactory() override {}
+ BrowserAccessibility* Create() override {
return new CountedBrowserAccessibility();
}
};
@@ -67,29 +63,38 @@ class TestBrowserAccessibilityDelegate
TestBrowserAccessibilityDelegate()
: got_fatal_error_(false) {}
- virtual void AccessibilitySetFocus(int acc_obj_id) OVERRIDE {}
- virtual void AccessibilityDoDefaultAction(int acc_obj_id) OVERRIDE {}
- virtual void AccessibilityShowMenu(int acc_obj_id) OVERRIDE {}
- virtual void AccessibilityScrollToMakeVisible(
- int acc_obj_id, gfx::Rect subfocus) OVERRIDE {}
- virtual void AccessibilityScrollToPoint(
- int acc_obj_id, gfx::Point point) OVERRIDE {}
- virtual void AccessibilitySetTextSelection(
- int acc_obj_id, int start_offset, int end_offset) OVERRIDE {}
- virtual bool AccessibilityViewHasFocus() const OVERRIDE {
- return false;
+ void AccessibilitySetFocus(int acc_obj_id) override {}
+ void AccessibilityDoDefaultAction(int acc_obj_id) override {}
+ void AccessibilityShowMenu(const gfx::Point& point) override {}
+ void AccessibilityScrollToMakeVisible(int acc_obj_id,
+ const gfx::Rect& subfocus) override {}
+ void AccessibilityScrollToPoint(int acc_obj_id,
+ const gfx::Point& point) override {}
+ void AccessibilitySetTextSelection(int acc_obj_id,
+ int start_offset,
+ int end_offset) override {}
+ void AccessibilitySetValue(int acc_obj_id, const base::string16& value)
+ override {}
+ bool AccessibilityViewHasFocus() const override { return false; }
+ gfx::Rect AccessibilityGetViewBounds() const override { return gfx::Rect(); }
+ gfx::Point AccessibilityOriginInScreen(
+ const gfx::Rect& bounds) const override {
+ return gfx::Point();
}
- virtual gfx::Rect AccessibilityGetViewBounds() const OVERRIDE {
- return gfx::Rect();
+ void AccessibilityHitTest(const gfx::Point& point) override {}
+ void AccessibilitySetAccessibilityFocus(int acc_obj_id) override {}
+ void AccessibilityFatalError() override { got_fatal_error_ = true; }
+ gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override {
+ return gfx::kNullAcceleratedWidget;
}
- virtual gfx::Point AccessibilityOriginInScreen(
- const gfx::Rect& bounds) const OVERRIDE {
- return gfx::Point();
+ gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override {
+ return NULL;
}
- virtual void AccessibilityHitTest(const gfx::Point& point) OVERRIDE {}
- virtual void AccessibilityFatalError() OVERRIDE {
- got_fatal_error_ = true;
+ BrowserAccessibilityManager* AccessibilityGetChildFrame(
+ int accessibility_node_id) override {
+ return NULL;
}
+ BrowserAccessibility* AccessibilityGetParentFrame() override { return NULL; }
bool got_fatal_error() const { return got_fatal_error_; }
void reset_got_fatal_error() { got_fatal_error_ = false; }
diff --git a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
index 4e7153ab75a..b7424870cea 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -20,9 +20,7 @@ BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory) {
- return new BrowserAccessibilityManagerWin(
- content::LegacyRenderWidgetHostHWND::Create(GetDesktopWindow()).get(),
- NULL, initial_tree, delegate, factory);
+ return new BrowserAccessibilityManagerWin(initial_tree, delegate, factory);
}
BrowserAccessibilityManagerWin*
@@ -31,22 +29,14 @@ BrowserAccessibilityManager::ToBrowserAccessibilityManagerWin() {
}
BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin(
- LegacyRenderWidgetHostHWND* accessible_hwnd,
- IAccessible* parent_iaccessible,
const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory)
- : BrowserAccessibilityManager(initial_tree, delegate, factory),
- parent_hwnd_(NULL),
- parent_iaccessible_(parent_iaccessible),
+ : BrowserAccessibilityManager(delegate, factory),
tracked_scroll_object_(NULL),
- accessible_hwnd_(accessible_hwnd),
focus_event_on_root_needed_(false) {
ui::win::CreateATLModuleIfNeeded();
- if (accessible_hwnd_) {
- accessible_hwnd_->set_browser_accessibility_manager(this);
- parent_hwnd_ = accessible_hwnd_->GetParent();
- }
+ Initialize(initial_tree);
}
BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
@@ -54,8 +44,6 @@ BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
tracked_scroll_object_->Release();
tracked_scroll_object_ = NULL;
}
- if (accessible_hwnd_)
- accessible_hwnd_->OnManagerDeleted();
}
// static
@@ -73,29 +61,28 @@ ui::AXTreeUpdate BrowserAccessibilityManagerWin::GetEmptyDocument() {
return update;
}
-void BrowserAccessibilityManagerWin::SetAccessibleHWND(
- LegacyRenderWidgetHostHWND* accessible_hwnd) {
- accessible_hwnd_ = accessible_hwnd;
- if (accessible_hwnd_) {
- accessible_hwnd_->set_browser_accessibility_manager(this);
- parent_hwnd_ = accessible_hwnd_->GetParent();
- }
+HWND BrowserAccessibilityManagerWin::GetParentHWND() {
+ if (!delegate_)
+ return NULL;
+ return delegate_->AccessibilityGetAcceleratedWidget();
+}
+
+IAccessible* BrowserAccessibilityManagerWin::GetParentIAccessible() {
+ if (!delegate_)
+ return NULL;
+ return delegate_->AccessibilityGetNativeViewAccessible();
}
void BrowserAccessibilityManagerWin::MaybeCallNotifyWinEvent(DWORD event,
LONG child_id) {
- // If on Win 7 and complete accessibility is enabled, use the fake child HWND
- // to use as the root of the accessibility tree. See comments above
- // LegacyRenderWidgetHostHWND for details.
- if (accessible_hwnd_ &&
- BrowserAccessibilityStateImpl::GetInstance()->IsAccessibleBrowser()) {
- parent_hwnd_ = accessible_hwnd_->hwnd();
- parent_iaccessible_ = accessible_hwnd_->window_accessible();
- }
+ if (!delegate_)
+ return;
+
+ HWND hwnd = delegate_->AccessibilityGetAcceleratedWidget();
+ if (!hwnd)
+ return;
- // Only fire events if this view is hooked up to its parent.
- if (parent_iaccessible() && parent_hwnd())
- ::NotifyWinEvent(event, parent_hwnd(), OBJID_CLIENT, child_id);
+ ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id);
}
@@ -142,6 +129,11 @@ void BrowserAccessibilityManagerWin::OnWindowFocused() {
void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
ui::AXEvent event_type,
BrowserAccessibility* node) {
+ if (!delegate_ || !delegate_->AccessibilityGetAcceleratedWidget())
+ return;
+
+ // Inline text boxes are an internal implementation detail, we don't
+ // expose them to Windows.
if (node->GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX)
return;
@@ -232,17 +224,11 @@ void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent(
case ui::AX_EVENT_SELECTED_CHILDREN_CHANGED:
event_id = EVENT_OBJECT_SELECTIONWITHIN;
break;
- case ui::AX_EVENT_SELECTED_TEXT_CHANGED:
- event_id = IA2_EVENT_TEXT_CARET_MOVED;
- break;
case ui::AX_EVENT_TEXT_CHANGED:
event_id = EVENT_OBJECT_NAMECHANGE;
break;
- case ui::AX_EVENT_TEXT_INSERTED:
- event_id = IA2_EVENT_TEXT_INSERTED;
- break;
- case ui::AX_EVENT_TEXT_REMOVED:
- event_id = IA2_EVENT_TEXT_REMOVED;
+ case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
+ event_id = IA2_EVENT_TEXT_CARET_MOVED;
break;
case ui::AX_EVENT_VALUE_CHANGED:
event_id = EVENT_OBJECT_VALUECHANGE;
@@ -302,15 +288,4 @@ BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromUniqueIdWin(
return NULL;
}
-void BrowserAccessibilityManagerWin::OnAccessibleHwndDeleted() {
- // If the AccessibleHWND is deleted, |parent_hwnd_| and
- // |parent_iaccessible_| are no longer valid either, since they were
- // derived from AccessibleHWND. We don't have to restore them to
- // previous values, though, because this should only happen
- // during the destruct sequence for this window.
- accessible_hwnd_ = NULL;
- parent_hwnd_ = NULL;
- parent_iaccessible_ = NULL;
-}
-
} // 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 26c82b793c0..8eaa9490c85 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -14,15 +14,11 @@
namespace content {
class BrowserAccessibilityWin;
-class LegacyRenderWidgetHostHWND;
-
// Manages a tree of BrowserAccessibilityWin objects.
class CONTENT_EXPORT BrowserAccessibilityManagerWin
: public BrowserAccessibilityManager {
public:
BrowserAccessibilityManagerWin(
- content::LegacyRenderWidgetHostHWND* accessible_hwnd,
- IAccessible* parent_iaccessible,
const ui::AXTreeUpdate& initial_tree,
BrowserAccessibilityDelegate* delegate,
BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
@@ -32,27 +28,22 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
static ui::AXTreeUpdate GetEmptyDocument();
// Get the closest containing HWND.
- HWND parent_hwnd() { return parent_hwnd_; }
+ HWND GetParentHWND();
// The IAccessible for the parent window.
- IAccessible* parent_iaccessible() { return parent_iaccessible_; }
- void set_parent_iaccessible(IAccessible* parent_iaccessible) {
- parent_iaccessible_ = parent_iaccessible;
- }
-
- void SetAccessibleHWND(LegacyRenderWidgetHostHWND* accessible_hwnd);
+ IAccessible* GetParentIAccessible();
// Calls NotifyWinEvent if the parent window's IAccessible pointer is known.
void MaybeCallNotifyWinEvent(DWORD event, LONG child_id);
// AXTree methods
- virtual void OnNodeWillBeDeleted(ui::AXNode* node) OVERRIDE;
- virtual void OnNodeCreated(ui::AXNode* node) OVERRIDE;
+ virtual void OnNodeWillBeDeleted(ui::AXNode* node) override;
+ virtual void OnNodeCreated(ui::AXNode* node) override;
// BrowserAccessibilityManager methods
- virtual void OnWindowFocused() OVERRIDE;
+ virtual void OnWindowFocused() override;
virtual void NotifyAccessibilityEvent(
- ui::AXEvent event_type, BrowserAccessibility* node) OVERRIDE;
+ ui::AXEvent event_type, BrowserAccessibility* node) override;
// Track this object and post a VISIBLE_DATA_CHANGED notification when
// its container scrolls.
@@ -68,15 +59,9 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
protected:
// BrowserAccessibilityManager methods
- virtual void OnRootChanged(ui::AXNode* new_root) OVERRIDE;
+ virtual void OnRootChanged(ui::AXNode* new_root) override;
private:
- // The closest ancestor HWND.
- HWND parent_hwnd_;
-
- // The accessibility instance for the parent window.
- IAccessible* parent_iaccessible_;
-
// Give BrowserAccessibilityManager::Create access to our constructor.
friend class BrowserAccessibilityManager;
@@ -89,9 +74,6 @@ class CONTENT_EXPORT BrowserAccessibilityManagerWin
// browser process) to accessibility ids within this page.
base::hash_map<long, int32> unique_id_to_ax_id_map_;
- // Owned by its parent; OnAccessibleHwndDeleted gets called upon deletion.
- LegacyRenderWidgetHostHWND* accessible_hwnd_;
-
// Set to true if we need to fire a focus event on the root as soon as
// possible.
bool focus_event_on_root_needed_;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc b/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
index f45c31d2776..597b13ac0c1 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -6,19 +6,13 @@
#include "base/command_line.h"
#include "base/metrics/histogram.h"
-#include "base/timer/timer.h"
#include "content/browser/accessibility/accessibility_mode_helper.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/common/content_switches.h"
#include "ui/gfx/sys_color_change_listener.h"
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
namespace content {
// Update the accessibility histogram 45 seconds after initialization.
@@ -63,7 +57,7 @@ BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() {
}
void BrowserAccessibilityStateImpl::OnScreenReaderDetected() {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableRendererAccessibility)) {
return;
}
@@ -80,17 +74,7 @@ void BrowserAccessibilityStateImpl::DisableAccessibility() {
void BrowserAccessibilityStateImpl::ResetAccessibilityModeValue() {
accessibility_mode_ = AccessibilityModeOff;
-#if defined(OS_WIN)
- // On Windows 8, always enable accessibility for editable text controls
- // so we can show the virtual keyboard when one is enabled.
- if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableRendererAccessibility)) {
- accessibility_mode_ = AccessibilityModeEditableTextOnly;
- }
-#endif // defined(OS_WIN)
-
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceRendererAccessibility)) {
accessibility_mode_ = AccessibilityModeComplete;
}
@@ -99,20 +83,10 @@ void BrowserAccessibilityStateImpl::ResetAccessibilityModeValue() {
void BrowserAccessibilityStateImpl::ResetAccessibilityMode() {
ResetAccessibilityModeValue();
- // Iterate over all RenderWidgetHosts, even swapped out ones in case
- // they become active again.
- scoped_ptr<RenderWidgetHostIterator> widgets(
- RenderWidgetHostImpl::GetAllRenderWidgetHosts());
- while (RenderWidgetHost* widget = widgets->GetNextHost()) {
- // Ignore processes that don't have a connection, such as crashed tabs.
- if (!widget->GetProcess()->HasConnection())
- continue;
- if (!widget->IsRenderView())
- continue;
-
- RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
- rwhi->ResetAccessibilityMode();
- }
+ std::vector<WebContentsImpl*> web_contents_vector =
+ WebContentsImpl::GetAllWebContents();
+ for (size_t i = 0; i < web_contents_vector.size(); ++i)
+ web_contents_vector[i]->SetAccessibilityMode(accessibility_mode());
}
bool BrowserAccessibilityStateImpl::IsAccessibleBrowser() {
@@ -139,7 +113,7 @@ void BrowserAccessibilityStateImpl::UpdateHistograms() {
UMA_HISTOGRAM_BOOLEAN("Accessibility.InvertedColors",
gfx::IsInvertedColorScheme());
UMA_HISTOGRAM_BOOLEAN("Accessibility.ManuallyEnabled",
- CommandLine::ForCurrentProcess()->HasSwitch(
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceRendererAccessibility));
}
@@ -150,7 +124,7 @@ void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
void BrowserAccessibilityStateImpl::AddAccessibilityMode(
AccessibilityMode mode) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableRendererAccessibility)) {
return;
}
@@ -158,12 +132,12 @@ void BrowserAccessibilityStateImpl::AddAccessibilityMode(
accessibility_mode_ =
content::AddAccessibilityModeTo(accessibility_mode_, mode);
- AddOrRemoveFromRenderWidgets(mode, true);
+ AddOrRemoveFromAllWebContents(mode, true);
}
void BrowserAccessibilityStateImpl::RemoveAccessibilityMode(
AccessibilityMode mode) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceRendererAccessibility) &&
mode == AccessibilityModeComplete) {
return;
@@ -172,28 +146,19 @@ void BrowserAccessibilityStateImpl::RemoveAccessibilityMode(
accessibility_mode_ =
content::RemoveAccessibilityModeFrom(accessibility_mode_, mode);
- AddOrRemoveFromRenderWidgets(mode, false);
+ AddOrRemoveFromAllWebContents(mode, false);
}
-void BrowserAccessibilityStateImpl::AddOrRemoveFromRenderWidgets(
+void BrowserAccessibilityStateImpl::AddOrRemoveFromAllWebContents(
AccessibilityMode mode,
bool add) {
- // Iterate over all RenderWidgetHosts, even swapped out ones in case
- // they become active again.
- scoped_ptr<RenderWidgetHostIterator> widgets(
- RenderWidgetHostImpl::GetAllRenderWidgetHosts());
- while (RenderWidgetHost* widget = widgets->GetNextHost()) {
- // Ignore processes that don't have a connection, such as crashed tabs.
- if (!widget->GetProcess()->HasConnection())
- continue;
- if (!widget->IsRenderView())
- continue;
-
- RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
+ std::vector<WebContentsImpl*> web_contents_vector =
+ WebContentsImpl::GetAllWebContents();
+ for (size_t i = 0; i < web_contents_vector.size(); ++i) {
if (add)
- rwhi->AddAccessibilityMode(mode);
+ web_contents_vector[i]->AddAccessibilityMode(mode);
else
- rwhi->RemoveAccessibilityMode(mode);
+ web_contents_vector[i]->RemoveAccessibilityMode(mode);
}
}
diff --git a/chromium/content/browser/accessibility/browser_accessibility_state_impl.h b/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
index 2a1b1c6bb4b..4c8884373d6 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_state_impl.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/singleton.h"
-#include "content/common/view_message_enums.h"
+#include "content/common/accessibility_mode_enums.h"
#include "content/public/browser/browser_accessibility_state.h"
namespace content {
@@ -40,14 +40,14 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
static BrowserAccessibilityStateImpl* GetInstance();
- virtual void EnableAccessibility() OVERRIDE;
- virtual void DisableAccessibility() OVERRIDE;
- virtual void ResetAccessibilityMode() OVERRIDE;
- virtual void OnScreenReaderDetected() OVERRIDE;
- virtual bool IsAccessibleBrowser() OVERRIDE;
- virtual void AddHistogramCallback(base::Closure callback) OVERRIDE;
+ void EnableAccessibility() override;
+ void DisableAccessibility() override;
+ void ResetAccessibilityMode() override;
+ void OnScreenReaderDetected() override;
+ bool IsAccessibleBrowser() override;
+ void AddHistogramCallback(base::Closure callback) override;
- virtual void UpdateHistogramsForTesting() OVERRIDE;
+ void UpdateHistogramsForTesting() override;
AccessibilityMode accessibility_mode() const { return accessibility_mode_; };
@@ -72,13 +72,13 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
void UpdateHistograms();
// Leaky singleton, destructor generally won't be called.
- virtual ~BrowserAccessibilityStateImpl();
+ ~BrowserAccessibilityStateImpl() override;
void UpdatePlatformSpecificHistograms();
- // Updates the accessibility mode of all render widgets, including swapped out
+ // Updates the accessibility mode of all web contents, including swapped out
// ones. |add| specifies whether the mode should be added or removed.
- void AddOrRemoveFromRenderWidgets(AccessibilityMode mode, bool add);
+ void AddOrRemoveFromAllWebContents(AccessibilityMode mode, bool add);
AccessibilityMode accessibility_mode_;
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win.cc b/chromium/content/browser/accessibility/browser_accessibility_win.cc
index c5fa35898ff..924ad75105b 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_win.cc
@@ -21,6 +21,7 @@
#include "ui/accessibility/ax_text_utils.h"
#include "ui/base/win/accessibility_ids_win.h"
#include "ui/base/win/accessibility_misc_utils.h"
+#include "ui/base/win/atl_module.h"
namespace content {
@@ -179,6 +180,7 @@ STDMETHODIMP BrowserAccessibilityRelation::get_targets(long max_targets,
// static
BrowserAccessibility* BrowserAccessibility::Create() {
+ ui::win::CreateATLModuleIfNeeded();
CComObject<BrowserAccessibilityWin>* instance;
HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance);
DCHECK(SUCCEEDED(hr));
@@ -498,7 +500,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accParent(IDispatch** disp_parent) {
// This happens if we're the root of the tree;
// return the IAccessible for the window.
parent_obj =
- manager()->ToBrowserAccessibilityManagerWin()->parent_iaccessible();
+ manager()->ToBrowserAccessibilityManagerWin()->GetParentIAccessible();
// |parent| can only be NULL if the manager was created before the parent
// IAccessible was known and it wasn't subsequently set before a client
// requested it. This has been fixed. |parent| may also be NULL during
@@ -738,7 +740,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_windowHandle(HWND* window_handle) {
if (!window_handle)
return E_INVALIDARG;
- *window_handle = manager()->ToBrowserAccessibilityManagerWin()->parent_hwnd();
+ *window_handle =
+ manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
if (!*window_handle)
return E_FAIL;
@@ -994,7 +997,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_imagePosition(
if (coordinate_type == IA2_COORDTYPE_SCREEN_RELATIVE) {
HWND parent_hwnd =
- manager()->ToBrowserAccessibilityManagerWin()->parent_hwnd();
+ manager()->ToBrowserAccessibilityManagerWin()->GetParentHWND();
if (!parent_hwnd)
return E_FAIL;
POINT top_left = {0, 0};
@@ -2561,7 +2564,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_computedStyleForProperties(
for (unsigned short i = 0; i < num_style_properties; ++i) {
base::string16 name = (LPCWSTR)style_properties[i];
- StringToLowerASCII(&name);
+ base::StringToLowerASCII(&name);
if (name == L"display") {
base::string16 display = GetString16Attribute(
ui::AX_ATTR_DISPLAY);
@@ -2856,35 +2859,38 @@ STDMETHODIMP BrowserAccessibilityWin::GetPropertyValue(PROPERTYID id,
// CComObjectRootEx methods.
//
+// static
HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
void* this_ptr,
const _ATL_INTMAP_ENTRY* entries,
REFIID iid,
void** object) {
+ int32 ia_role =
+ reinterpret_cast<BrowserAccessibilityWin*>(this_ptr)->ia_role_;
if (iid == IID_IAccessibleImage) {
- if (ia_role_ != ROLE_SYSTEM_GRAPHIC) {
+ if (ia_role != ROLE_SYSTEM_GRAPHIC) {
*object = NULL;
return E_NOINTERFACE;
}
} else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) {
- if (ia_role_ != ROLE_SYSTEM_TABLE) {
+ if (ia_role != ROLE_SYSTEM_TABLE) {
*object = NULL;
return E_NOINTERFACE;
}
} else if (iid == IID_IAccessibleTableCell) {
- if (ia_role_ != ROLE_SYSTEM_CELL) {
+ if (ia_role != ROLE_SYSTEM_CELL) {
*object = NULL;
return E_NOINTERFACE;
}
} else if (iid == IID_IAccessibleValue) {
- if (ia_role_ != ROLE_SYSTEM_PROGRESSBAR &&
- ia_role_ != ROLE_SYSTEM_SCROLLBAR &&
- ia_role_ != ROLE_SYSTEM_SLIDER) {
+ if (ia_role != ROLE_SYSTEM_PROGRESSBAR &&
+ ia_role != ROLE_SYSTEM_SCROLLBAR &&
+ ia_role != ROLE_SYSTEM_SLIDER) {
*object = NULL;
return E_NOINTERFACE;
}
} else if (iid == IID_ISimpleDOMDocument) {
- if (ia_role_ != ROLE_SYSTEM_DOCUMENT) {
+ if (ia_role != ROLE_SYSTEM_DOCUMENT) {
*object = NULL;
return E_NOINTERFACE;
}
@@ -2906,6 +2912,7 @@ void BrowserAccessibilityWin::OnDataChanged() {
// Expose the "display" and "tag" attributes.
StringAttributeToIA2(ui::AX_ATTR_DISPLAY, "display");
+ StringAttributeToIA2(ui::AX_ATTR_TEXT_INPUT_TYPE, "text-input-type");
StringAttributeToIA2(ui::AX_ATTR_HTML_TAG, "tag");
StringAttributeToIA2(ui::AX_ATTR_ROLE, "xml-roles");
@@ -2924,6 +2931,8 @@ void BrowserAccessibilityWin::OnDataChanged() {
if (ia_role_ == ROLE_SYSTEM_CHECKBUTTON ||
ia_role_ == ROLE_SYSTEM_RADIOBUTTON ||
+ ia2_role_ == IA2_ROLE_CHECK_MENU_ITEM ||
+ ia2_role_ == IA2_ROLE_RADIO_MENU_ITEM ||
ia2_role_ == IA2_ROLE_TOGGLE_BUTTON) {
ia2_attributes_.push_back(L"checkable:true");
}
@@ -3173,7 +3182,7 @@ bool BrowserAccessibilityWin::IsNative() const {
return true;
}
-void BrowserAccessibilityWin::OnLocationChanged() const {
+void BrowserAccessibilityWin::OnLocationChanged() {
manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent(
EVENT_OBJECT_LOCATIONCHANGE, unique_id_win());
}
@@ -3388,9 +3397,16 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_role_ = ROLE_SYSTEM_APPLICATION;
break;
case ui::AX_ROLE_ARTICLE:
+ ia_role_ = ROLE_SYSTEM_DOCUMENT;
+ ia_state_ |= STATE_SYSTEM_READONLY;
+ break;
+ case ui::AX_ROLE_BANNER:
ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_HEADER;
+ break;
+ case ui::AX_ROLE_BLOCKQUOTE:
+ role_name_ = html_tag;
ia2_role_ = IA2_ROLE_SECTION;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_BUSY_INDICATOR:
ia_role_ = ROLE_SYSTEM_ANIMATION;
@@ -3420,6 +3436,7 @@ void BrowserAccessibilityWin::InitRoleAndState() {
break;
case ui::AX_ROLE_CHECK_BOX:
ia_role_ = ROLE_SYSTEM_CHECKBUTTON;
+ ia2_state_ |= IA2_STATE_CHECKABLE;
break;
case ui::AX_ROLE_COLOR_WELL:
ia_role_ = ROLE_SYSTEM_CLIENT;
@@ -3427,17 +3444,32 @@ void BrowserAccessibilityWin::InitRoleAndState() {
break;
case ui::AX_ROLE_COLUMN:
ia_role_ = ROLE_SYSTEM_COLUMN;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_COLUMN_HEADER:
ia_role_ = ROLE_SYSTEM_COLUMNHEADER;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_COMBO_BOX:
ia_role_ = ROLE_SYSTEM_COMBOBOX;
break;
+ case ui::AX_ROLE_COMPLEMENTARY:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_NOTE;
+ break;
+ case ui::AX_ROLE_CONTENT_INFO:
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ ia2_role_ = IA2_ROLE_PARAGRAPH;
+ break;
+ case ui::AX_ROLE_DATE:
+ ia_role_ = ROLE_SYSTEM_DROPLIST;
+ ia2_role_ = IA2_ROLE_DATE_EDITOR;
+ break;
+ case ui::AX_ROLE_DATE_TIME:
+ ia_role_ = ROLE_SYSTEM_DROPLIST;
+ ia2_role_ = IA2_ROLE_DATE_EDITOR;
+ break;
case ui::AX_ROLE_DIV:
role_name_ = L"div";
+ ia_role_ = ROLE_SYSTEM_GROUPING;
ia2_role_ = IA2_ROLE_SECTION;
break;
case ui::AX_ROLE_DEFINITION:
@@ -3450,17 +3482,24 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia2_role_ = IA2_ROLE_PARAGRAPH;
ia_state_ |= STATE_SYSTEM_READONLY;
break;
+ case ui::AX_ROLE_DESCRIPTION_LIST:
+ role_name_ = html_tag;
+ ia_role_ = ROLE_SYSTEM_LIST;
+ ia_state_ |= STATE_SYSTEM_READONLY;
+ break;
case ui::AX_ROLE_DESCRIPTION_LIST_TERM:
ia_role_ = ROLE_SYSTEM_LISTITEM;
ia_state_ |= STATE_SYSTEM_READONLY;
break;
+ case ui::AX_ROLE_DETAILS:
+ role_name_ = html_tag;
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ break;
case ui::AX_ROLE_DIALOG:
ia_role_ = ROLE_SYSTEM_DIALOG;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_DISCLOSURE_TRIANGLE:
- ia_role_ = ROLE_SYSTEM_OUTLINEBUTTON;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ ia_role_ = ROLE_SYSTEM_PUSHBUTTON;
break;
case ui::AX_ROLE_DOCUMENT:
case ui::AX_ROLE_ROOT_WEB_AREA:
@@ -3474,6 +3513,15 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia2_state_ |= IA2_STATE_SINGLE_LINE;
ia2_state_ |= IA2_STATE_EDITABLE;
break;
+ case ui::AX_ROLE_FIGCAPTION:
+ role_name_ = html_tag;
+ ia2_role_ = IA2_ROLE_CAPTION;
+ break;
+ case ui::AX_ROLE_FIGURE:
+ role_name_ = html_tag;
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
case ui::AX_ROLE_FORM:
role_name_ = L"form";
ia2_role_ = IA2_ROLE_FORM;
@@ -3493,6 +3541,7 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_role_ = ROLE_SYSTEM_GROUPING;
} else if (html_tag == L"li") {
ia_role_ = ROLE_SYSTEM_LISTITEM;
+ ia_state_ |= STATE_SYSTEM_READONLY;
} else {
if (html_tag.empty())
role_name_ = L"div";
@@ -3500,7 +3549,6 @@ void BrowserAccessibilityWin::InitRoleAndState() {
role_name_ = html_tag;
ia2_role_ = IA2_ROLE_SECTION;
}
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
}
case ui::AX_ROLE_GROW_AREA:
@@ -3510,14 +3558,14 @@ void BrowserAccessibilityWin::InitRoleAndState() {
case ui::AX_ROLE_HEADING:
role_name_ = html_tag;
ia2_role_ = IA2_ROLE_HEADING;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_HORIZONTAL_RULE:
ia_role_ = ROLE_SYSTEM_SEPARATOR;
break;
case ui::AX_ROLE_IFRAME:
- ia_role_ = ROLE_SYSTEM_CLIENT;
+ ia_role_ = ROLE_SYSTEM_DOCUMENT;
ia2_role_ = IA2_ROLE_INTERNAL_FRAME;
+ ia_state_ = STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_IMAGE:
ia_role_ = ROLE_SYSTEM_GRAPHIC;
@@ -3537,15 +3585,9 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_role_ = ROLE_SYSTEM_TEXT;
ia2_role_ = IA2_ROLE_LABEL;
break;
- 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:
ia_role_ = ROLE_SYSTEM_GROUPING;
ia2_role_ = IA2_ROLE_SECTION;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_LINK:
ia_role_ = ROLE_SYSTEM_LINK;
@@ -3570,9 +3612,15 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_role_ = ROLE_SYSTEM_LISTITEM;
ia_state_ |= STATE_SYSTEM_READONLY;
break;
- case ui::AX_ROLE_MATH_ELEMENT:
+ case ui::AX_ROLE_MAIN:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_PARAGRAPH;
+ break;
+ case ui::AX_ROLE_MARQUEE:
+ ia_role_ = ROLE_SYSTEM_ANIMATION;
+ break;
+ case ui::AX_ROLE_MATH:
ia_role_ = ROLE_SYSTEM_EQUATION;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_MENU:
case ui::AX_ROLE_MENU_BUTTON:
@@ -3584,6 +3632,15 @@ void BrowserAccessibilityWin::InitRoleAndState() {
case ui::AX_ROLE_MENU_ITEM:
ia_role_ = ROLE_SYSTEM_MENUITEM;
break;
+ case ui::AX_ROLE_MENU_ITEM_CHECK_BOX:
+ ia_role_ = ROLE_SYSTEM_MENUITEM;
+ ia2_role_ = IA2_ROLE_CHECK_MENU_ITEM;
+ ia2_state_ |= IA2_STATE_CHECKABLE;
+ break;
+ case ui::AX_ROLE_MENU_ITEM_RADIO:
+ ia_role_ = ROLE_SYSTEM_MENUITEM;
+ ia2_role_ = IA2_ROLE_RADIO_MENU_ITEM;
+ break;
case ui::AX_ROLE_MENU_LIST_POPUP:
ia_role_ = ROLE_SYSTEM_CLIENT;
break;
@@ -3595,6 +3652,14 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_state_ |= STATE_SYSTEM_FOCUSED;
}
break;
+ case ui::AX_ROLE_METER:
+ role_name_ = html_tag;
+ ia_role_ = ROLE_SYSTEM_PROGRESSBAR;
+ break;
+ case ui::AX_ROLE_NAVIGATION:
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ break;
case ui::AX_ROLE_NOTE:
ia_role_ = ROLE_SYSTEM_GROUPING;
ia2_role_ = IA2_ROLE_NOTE;
@@ -3602,7 +3667,6 @@ void BrowserAccessibilityWin::InitRoleAndState() {
break;
case ui::AX_ROLE_OUTLINE:
ia_role_ = ROLE_SYSTEM_OUTLINE;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_PARAGRAPH:
role_name_ = L"P";
@@ -3615,6 +3679,11 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_role_ = ROLE_SYSTEM_BUTTONMENU;
}
break;
+ case ui::AX_ROLE_PRE:
+ role_name_ = html_tag;
+ ia_role_ = ROLE_SYSTEM_TEXT;
+ ia2_role_ = IA2_ROLE_PARAGRAPH;
+ break;
case ui::AX_ROLE_PROGRESS_INDICATOR:
ia_role_ = ROLE_SYSTEM_PROGRESSBAR;
ia_state_ |= STATE_SYSTEM_READONLY;
@@ -3624,20 +3693,20 @@ void BrowserAccessibilityWin::InitRoleAndState() {
break;
case ui::AX_ROLE_RADIO_GROUP:
ia_role_ = ROLE_SYSTEM_GROUPING;
- ia2_role_ = IA2_ROLE_SECTION;
break;
case ui::AX_ROLE_REGION:
- ia_role_ = ROLE_SYSTEM_GROUPING;
- ia2_role_ = IA2_ROLE_SECTION;
- ia_state_ |= STATE_SYSTEM_READONLY;
+ if (html_tag == L"section") {
+ ia_role_ = ROLE_SYSTEM_GROUPING;
+ ia2_role_ = IA2_ROLE_SECTION;
+ } else {
+ ia_role_ = ROLE_SYSTEM_PANE;
+ }
break;
case ui::AX_ROLE_ROW:
ia_role_ = ROLE_SYSTEM_ROW;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_ROW_HEADER:
ia_role_ = ROLE_SYSTEM_ROWHEADER;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_RULER:
ia_role_ = ROLE_SYSTEM_CLIENT;
@@ -3692,7 +3761,6 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia_role_ = ROLE_SYSTEM_OUTLINE;
} else {
ia_role_ = ROLE_SYSTEM_TABLE;
- ia_state_ |= STATE_SYSTEM_READONLY;
}
break;
}
@@ -3723,6 +3791,9 @@ void BrowserAccessibilityWin::InitRoleAndState() {
ia2_state_ |= IA2_STATE_EDITABLE;
ia2_state_ |= IA2_STATE_SELECTABLE_TEXT;
break;
+ case ui::AX_ROLE_TIME:
+ ia_role_ = ROLE_SYSTEM_SPINBUTTON;
+ break;
case ui::AX_ROLE_TIMER:
ia_role_ = ROLE_SYSTEM_CLOCK;
ia_state_ |= STATE_SYSTEM_READONLY;
@@ -3737,15 +3808,12 @@ void BrowserAccessibilityWin::InitRoleAndState() {
break;
case ui::AX_ROLE_TREE:
ia_role_ = ROLE_SYSTEM_OUTLINE;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_TREE_GRID:
ia_role_ = ROLE_SYSTEM_OUTLINE;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_TREE_ITEM:
ia_role_ = ROLE_SYSTEM_OUTLINEITEM;
- ia_state_ |= STATE_SYSTEM_READONLY;
break;
case ui::AX_ROLE_WINDOW:
ia_role_ = ROLE_SYSTEM_WINDOW;
@@ -3759,8 +3827,8 @@ void BrowserAccessibilityWin::InitRoleAndState() {
case ui::AX_ROLE_IGNORED:
case ui::AX_ROLE_INCREMENTOR:
case ui::AX_ROLE_LOG:
- case ui::AX_ROLE_MARQUEE:
case ui::AX_ROLE_MATTE:
+ case ui::AX_ROLE_NONE:
case ui::AX_ROLE_PRESENTATIONAL:
case ui::AX_ROLE_RULER_MARKER:
case ui::AX_ROLE_SHEET:
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win.h b/chromium/content/browser/accessibility/browser_accessibility_win.h
index 8dca2a8a9c8..cd339d53c91 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win.h
+++ b/chromium/content/browser/accessibility/browser_accessibility_win.h
@@ -100,88 +100,94 @@ BrowserAccessibilityWin
//
// BrowserAccessibility methods.
//
- CONTENT_EXPORT virtual void OnDataChanged() OVERRIDE;
- CONTENT_EXPORT virtual void OnUpdateFinished() OVERRIDE;
- CONTENT_EXPORT virtual void NativeAddReference() OVERRIDE;
- CONTENT_EXPORT virtual void NativeReleaseReference() OVERRIDE;
- CONTENT_EXPORT virtual bool IsNative() const OVERRIDE;
- CONTENT_EXPORT virtual void OnLocationChanged() const OVERRIDE;
+ CONTENT_EXPORT virtual void OnDataChanged() override;
+ CONTENT_EXPORT virtual void OnUpdateFinished() override;
+ CONTENT_EXPORT virtual void NativeAddReference() override;
+ CONTENT_EXPORT virtual void NativeReleaseReference() override;
+ CONTENT_EXPORT virtual bool IsNative() const override;
+ CONTENT_EXPORT virtual void OnLocationChanged() override;
//
// IAccessible methods.
//
// Performs the default action on a given object.
- CONTENT_EXPORT STDMETHODIMP accDoDefaultAction(VARIANT var_id);
+ CONTENT_EXPORT STDMETHODIMP accDoDefaultAction(VARIANT var_id) override;
// Retrieves the child element or child object at a given point on the screen.
- CONTENT_EXPORT STDMETHODIMP accHitTest(LONG x_left, LONG y_top,
- VARIANT* child);
+ CONTENT_EXPORT STDMETHODIMP
+ accHitTest(LONG x_left, LONG y_top, VARIANT* child) override;
// Retrieves the specified object's current screen location.
CONTENT_EXPORT STDMETHODIMP accLocation(LONG* x_left,
LONG* y_top,
LONG* width,
LONG* height,
- VARIANT var_id);
+ VARIANT var_id) override;
// Traverses to another UI element and retrieves the object.
- CONTENT_EXPORT STDMETHODIMP accNavigate(LONG nav_dir, VARIANT start,
- VARIANT* end);
+ CONTENT_EXPORT STDMETHODIMP
+ accNavigate(LONG nav_dir, VARIANT start, VARIANT* end) override;
// Retrieves an IDispatch interface pointer for the specified child.
- CONTENT_EXPORT STDMETHODIMP get_accChild(VARIANT var_child,
- IDispatch** disp_child);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accChild(VARIANT var_child, IDispatch** disp_child) override;
// Retrieves the number of accessible children.
- CONTENT_EXPORT STDMETHODIMP get_accChildCount(LONG* child_count);
+ CONTENT_EXPORT STDMETHODIMP get_accChildCount(LONG* child_count) override;
// Retrieves a string that describes the object's default action.
- CONTENT_EXPORT STDMETHODIMP get_accDefaultAction(VARIANT var_id,
- BSTR* default_action);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accDefaultAction(VARIANT var_id, BSTR* default_action) override;
// Retrieves the object's description.
- CONTENT_EXPORT STDMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accDescription(VARIANT var_id, BSTR* desc) override;
// Retrieves the object that has the keyboard focus.
- CONTENT_EXPORT STDMETHODIMP get_accFocus(VARIANT* focus_child);
+ CONTENT_EXPORT STDMETHODIMP get_accFocus(VARIANT* focus_child) override;
// Retrieves the help information associated with the object.
- CONTENT_EXPORT STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* heflp);
+ CONTENT_EXPORT STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* heflp) override;
// Retrieves the specified object's shortcut.
- CONTENT_EXPORT STDMETHODIMP get_accKeyboardShortcut(VARIANT var_id,
- BSTR* access_key);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accKeyboardShortcut(VARIANT var_id, BSTR* access_key) override;
// Retrieves the name of the specified object.
- CONTENT_EXPORT STDMETHODIMP get_accName(VARIANT var_id, BSTR* name);
+ CONTENT_EXPORT STDMETHODIMP get_accName(VARIANT var_id, BSTR* name) override;
// Retrieves the IDispatch interface of the object's parent.
- CONTENT_EXPORT STDMETHODIMP get_accParent(IDispatch** disp_parent);
+ CONTENT_EXPORT STDMETHODIMP get_accParent(IDispatch** disp_parent) override;
// Retrieves information describing the role of the specified object.
- CONTENT_EXPORT STDMETHODIMP get_accRole(VARIANT var_id, VARIANT* role);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accRole(VARIANT var_id, VARIANT* role) override;
// Retrieves the current state of the specified object.
- CONTENT_EXPORT STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accState(VARIANT var_id, VARIANT* state) override;
// Returns the value associated with the object.
- CONTENT_EXPORT STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accValue(VARIANT var_id, BSTR* value) override;
// Make an object take focus or extend the selection.
- CONTENT_EXPORT STDMETHODIMP accSelect(LONG flags_sel, VARIANT var_id);
+ CONTENT_EXPORT STDMETHODIMP
+ accSelect(LONG flags_sel, VARIANT var_id) override;
- CONTENT_EXPORT STDMETHODIMP get_accHelpTopic(BSTR* help_file,
- VARIANT var_id,
- LONG* topic_id);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accHelpTopic(BSTR* help_file, VARIANT var_id, LONG* topic_id) override;
- CONTENT_EXPORT STDMETHODIMP get_accSelection(VARIANT* selected);
+ CONTENT_EXPORT STDMETHODIMP get_accSelection(VARIANT* selected) override;
// Deprecated methods, not implemented.
- CONTENT_EXPORT STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name) {
+ CONTENT_EXPORT STDMETHODIMP
+ put_accName(VARIANT var_id, BSTR put_name) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP put_accValue(VARIANT var_id, BSTR put_val) {
+ CONTENT_EXPORT STDMETHODIMP
+ put_accValue(VARIANT var_id, BSTR put_val) override {
return E_NOTIMPL;
}
@@ -190,95 +196,99 @@ BrowserAccessibilityWin
//
// Returns role from a longer list of possible roles.
- CONTENT_EXPORT STDMETHODIMP role(LONG* role);
+ CONTENT_EXPORT STDMETHODIMP role(LONG* role) override;
// Returns the state bitmask from a larger set of possible states.
- CONTENT_EXPORT STDMETHODIMP get_states(AccessibleStates* states);
+ CONTENT_EXPORT STDMETHODIMP get_states(AccessibleStates* states) override;
// Returns the attributes specific to this IAccessible2 object,
// such as a cell's formula.
- CONTENT_EXPORT STDMETHODIMP get_attributes(BSTR* attributes);
+ CONTENT_EXPORT STDMETHODIMP get_attributes(BSTR* attributes) override;
// Get the unique ID of this object so that the client knows if it's
// been encountered previously.
- CONTENT_EXPORT STDMETHODIMP get_uniqueID(LONG* unique_id);
+ CONTENT_EXPORT STDMETHODIMP get_uniqueID(LONG* unique_id) override;
// Get the window handle of the enclosing window.
- CONTENT_EXPORT STDMETHODIMP get_windowHandle(HWND* window_handle);
+ CONTENT_EXPORT STDMETHODIMP get_windowHandle(HWND* window_handle) override;
// Get this object's index in its parent object.
- CONTENT_EXPORT STDMETHODIMP get_indexInParent(LONG* index_in_parent);
+ CONTENT_EXPORT STDMETHODIMP get_indexInParent(LONG* index_in_parent) override;
- CONTENT_EXPORT STDMETHODIMP get_nRelations(LONG* n_relations);
+ CONTENT_EXPORT STDMETHODIMP get_nRelations(LONG* n_relations) override;
- CONTENT_EXPORT STDMETHODIMP get_relation(LONG relation_index,
- IAccessibleRelation** relation);
+ CONTENT_EXPORT STDMETHODIMP
+ get_relation(LONG relation_index, IAccessibleRelation** relation) override;
CONTENT_EXPORT STDMETHODIMP get_relations(LONG max_relations,
IAccessibleRelation** relations,
- LONG* n_relations);
+ LONG* n_relations) override;
- CONTENT_EXPORT STDMETHODIMP scrollTo(enum IA2ScrollType scroll_type);
+ CONTENT_EXPORT STDMETHODIMP scrollTo(enum IA2ScrollType scroll_type) override;
- CONTENT_EXPORT STDMETHODIMP scrollToPoint(
- enum IA2CoordinateType coordinate_type,
- LONG x,
- LONG y);
+ CONTENT_EXPORT STDMETHODIMP
+ scrollToPoint(enum IA2CoordinateType coordinate_type,
+ LONG x,
+ LONG y) override;
- CONTENT_EXPORT STDMETHODIMP get_groupPosition(LONG* group_level,
- LONG* similar_items_in_group,
- LONG* position_in_group);
+ CONTENT_EXPORT STDMETHODIMP
+ get_groupPosition(LONG* group_level,
+ LONG* similar_items_in_group,
+ LONG* position_in_group) override;
//
// IAccessibleEx methods not implemented.
//
- CONTENT_EXPORT STDMETHODIMP get_extendedRole(BSTR* extended_role) {
+ CONTENT_EXPORT STDMETHODIMP get_extendedRole(BSTR* extended_role) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_localizedExtendedRole(
- BSTR* localized_extended_role) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_localizedExtendedRole(BSTR* localized_extended_role) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_nExtendedStates(LONG* n_extended_states) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_nExtendedStates(LONG* n_extended_states) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_extendedStates(LONG max_extended_states,
- BSTR** extended_states,
- LONG* n_extended_states) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_extendedStates(LONG max_extended_states,
+ BSTR** extended_states,
+ LONG* n_extended_states) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_localizedExtendedStates(
- LONG max_localized_extended_states,
- BSTR** localized_extended_states,
- LONG* n_localized_extended_states) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_localizedExtendedStates(LONG max_localized_extended_states,
+ BSTR** localized_extended_states,
+ LONG* n_localized_extended_states) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_locale(IA2Locale* locale) {
+ CONTENT_EXPORT STDMETHODIMP get_locale(IA2Locale* locale) override {
return E_NOTIMPL;
}
//
// IAccessibleApplication methods.
//
- CONTENT_EXPORT STDMETHODIMP get_appName(BSTR* app_name);
+ CONTENT_EXPORT STDMETHODIMP get_appName(BSTR* app_name) override;
- CONTENT_EXPORT STDMETHODIMP get_appVersion(BSTR* app_version);
+ CONTENT_EXPORT STDMETHODIMP get_appVersion(BSTR* app_version) override;
- CONTENT_EXPORT STDMETHODIMP get_toolkitName(BSTR* toolkit_name);
+ CONTENT_EXPORT STDMETHODIMP get_toolkitName(BSTR* toolkit_name) override;
- CONTENT_EXPORT STDMETHODIMP get_toolkitVersion(BSTR* toolkit_version);
+ CONTENT_EXPORT STDMETHODIMP
+ get_toolkitVersion(BSTR* toolkit_version) override;
//
// IAccessibleImage methods.
//
- CONTENT_EXPORT STDMETHODIMP get_description(BSTR* description);
+ CONTENT_EXPORT STDMETHODIMP get_description(BSTR* description) override;
- CONTENT_EXPORT STDMETHODIMP get_imagePosition(
- enum IA2CoordinateType coordinate_type,
- LONG* x,
- LONG* y);
+ CONTENT_EXPORT STDMETHODIMP
+ get_imagePosition(enum IA2CoordinateType coordinate_type,
+ LONG* x,
+ LONG* y) override;
- CONTENT_EXPORT STDMETHODIMP get_imageSize(LONG* height, LONG* width);
+ CONTENT_EXPORT STDMETHODIMP get_imageSize(LONG* height, LONG* width) override;
//
// IAccessibleTable methods.
@@ -286,102 +296,96 @@ BrowserAccessibilityWin
// get_description - also used by IAccessibleImage
- CONTENT_EXPORT STDMETHODIMP get_accessibleAt(long row,
- long column,
- IUnknown** accessible);
+ CONTENT_EXPORT STDMETHODIMP
+ get_accessibleAt(long row, long column, IUnknown** accessible) override;
- CONTENT_EXPORT STDMETHODIMP get_caption(IUnknown** accessible);
+ CONTENT_EXPORT STDMETHODIMP get_caption(IUnknown** accessible) override;
- CONTENT_EXPORT STDMETHODIMP get_childIndex(long row_index,
- long column_index,
- long* cell_index);
+ CONTENT_EXPORT STDMETHODIMP
+ get_childIndex(long row_index, long column_index, long* cell_index) override;
- CONTENT_EXPORT STDMETHODIMP get_columnDescription(long column,
- BSTR* description);
+ CONTENT_EXPORT STDMETHODIMP
+ get_columnDescription(long column, BSTR* description) override;
- CONTENT_EXPORT STDMETHODIMP get_columnExtentAt(long row,
- long column,
- long* n_columns_spanned);
+ CONTENT_EXPORT STDMETHODIMP
+ get_columnExtentAt(long row, long column, long* n_columns_spanned) override;
- CONTENT_EXPORT STDMETHODIMP get_columnHeader(
- IAccessibleTable** accessible_table,
- long* starting_row_index);
+ CONTENT_EXPORT STDMETHODIMP
+ get_columnHeader(IAccessibleTable** accessible_table,
+ long* starting_row_index) override;
- CONTENT_EXPORT STDMETHODIMP get_columnIndex(long cell_index,
- long* column_index);
+ CONTENT_EXPORT STDMETHODIMP
+ get_columnIndex(long cell_index, long* column_index) override;
- CONTENT_EXPORT STDMETHODIMP get_nColumns(long* column_count);
+ CONTENT_EXPORT STDMETHODIMP get_nColumns(long* column_count) override;
- CONTENT_EXPORT STDMETHODIMP get_nRows(long* row_count);
+ CONTENT_EXPORT STDMETHODIMP get_nRows(long* row_count) override;
- CONTENT_EXPORT STDMETHODIMP get_nSelectedChildren(long* cell_count);
+ CONTENT_EXPORT STDMETHODIMP get_nSelectedChildren(long* cell_count) override;
- CONTENT_EXPORT STDMETHODIMP get_nSelectedColumns(long* column_count);
+ CONTENT_EXPORT STDMETHODIMP get_nSelectedColumns(long* column_count) override;
- CONTENT_EXPORT STDMETHODIMP get_nSelectedRows(long *row_count);
+ CONTENT_EXPORT STDMETHODIMP get_nSelectedRows(long* row_count) override;
- CONTENT_EXPORT STDMETHODIMP get_rowDescription(long row,
- BSTR* description);
+ CONTENT_EXPORT STDMETHODIMP
+ get_rowDescription(long row, BSTR* description) override;
- CONTENT_EXPORT STDMETHODIMP get_rowExtentAt(long row,
- long column,
- long* n_rows_spanned);
+ CONTENT_EXPORT STDMETHODIMP
+ get_rowExtentAt(long row, long column, long* n_rows_spanned) override;
- CONTENT_EXPORT STDMETHODIMP get_rowHeader(IAccessibleTable** accessible_table,
- long* starting_column_index);
+ CONTENT_EXPORT STDMETHODIMP
+ get_rowHeader(IAccessibleTable** accessible_table,
+ long* starting_column_index) override;
- CONTENT_EXPORT STDMETHODIMP get_rowIndex(long cell_index,
- long* row_index);
+ CONTENT_EXPORT STDMETHODIMP
+ get_rowIndex(long cell_index, long* row_index) override;
CONTENT_EXPORT STDMETHODIMP get_selectedChildren(long max_children,
long** children,
- long* n_children);
+ long* n_children) override;
CONTENT_EXPORT STDMETHODIMP get_selectedColumns(long max_columns,
long** columns,
- long* n_columns);
+ long* n_columns) override;
- CONTENT_EXPORT STDMETHODIMP get_selectedRows(long max_rows,
- long** rows,
- long* n_rows);
+ CONTENT_EXPORT STDMETHODIMP
+ get_selectedRows(long max_rows, long** rows, long* n_rows) override;
- CONTENT_EXPORT STDMETHODIMP get_summary(IUnknown** accessible);
+ CONTENT_EXPORT STDMETHODIMP get_summary(IUnknown** accessible) override;
- CONTENT_EXPORT STDMETHODIMP get_isColumnSelected(long column,
- boolean* is_selected);
+ CONTENT_EXPORT STDMETHODIMP
+ get_isColumnSelected(long column, boolean* is_selected) override;
- CONTENT_EXPORT STDMETHODIMP get_isRowSelected(long row,
- boolean* is_selected);
+ CONTENT_EXPORT STDMETHODIMP
+ get_isRowSelected(long row, boolean* is_selected) override;
- CONTENT_EXPORT STDMETHODIMP get_isSelected(long row,
- long column,
- boolean* is_selected);
+ CONTENT_EXPORT STDMETHODIMP
+ get_isSelected(long row, long column, boolean* is_selected) override;
- CONTENT_EXPORT STDMETHODIMP get_rowColumnExtentsAtIndex(long index,
- long* row,
- long* column,
- long* row_extents,
- long* column_extents,
- boolean* is_selected);
+ CONTENT_EXPORT STDMETHODIMP
+ get_rowColumnExtentsAtIndex(long index,
+ long* row,
+ long* column,
+ long* row_extents,
+ long* column_extents,
+ boolean* is_selected) override;
- CONTENT_EXPORT STDMETHODIMP selectRow(long row) {
- return E_NOTIMPL;
- }
+ CONTENT_EXPORT STDMETHODIMP selectRow(long row) override { return E_NOTIMPL; }
- CONTENT_EXPORT STDMETHODIMP selectColumn(long column) {
+ CONTENT_EXPORT STDMETHODIMP selectColumn(long column) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP unselectRow(long row) {
+ CONTENT_EXPORT STDMETHODIMP unselectRow(long row) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP unselectColumn(long column) {
+ CONTENT_EXPORT STDMETHODIMP unselectColumn(long column) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_modelChange(
- IA2TableModelChange* model_change) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_modelChange(IA2TableModelChange* model_change) override {
return E_NOTIMPL;
}
@@ -392,132 +396,136 @@ BrowserAccessibilityWin
// unique ones are included here.)
//
- CONTENT_EXPORT STDMETHODIMP get_cellAt(long row,
- long column,
- IUnknown** cell);
+ CONTENT_EXPORT STDMETHODIMP
+ get_cellAt(long row, long column, IUnknown** cell) override;
- CONTENT_EXPORT STDMETHODIMP get_nSelectedCells(long* cell_count);
+ CONTENT_EXPORT STDMETHODIMP get_nSelectedCells(long* cell_count) override;
- CONTENT_EXPORT STDMETHODIMP get_selectedCells(IUnknown*** cells,
- long* n_selected_cells);
+ CONTENT_EXPORT STDMETHODIMP
+ get_selectedCells(IUnknown*** cells, long* n_selected_cells) override;
- CONTENT_EXPORT STDMETHODIMP get_selectedColumns(long** columns,
- long* n_columns);
+ CONTENT_EXPORT STDMETHODIMP
+ get_selectedColumns(long** columns, long* n_columns) override;
- CONTENT_EXPORT STDMETHODIMP get_selectedRows(long** rows,
- long* n_rows);
+ CONTENT_EXPORT STDMETHODIMP
+ get_selectedRows(long** rows, long* n_rows) override;
//
// IAccessibleTableCell methods.
//
- CONTENT_EXPORT STDMETHODIMP get_columnExtent(long* n_columns_spanned);
+ CONTENT_EXPORT STDMETHODIMP
+ get_columnExtent(long* n_columns_spanned) override;
- CONTENT_EXPORT STDMETHODIMP get_columnHeaderCells(
- IUnknown*** cell_accessibles,
- long* n_column_header_cells);
+ CONTENT_EXPORT STDMETHODIMP
+ get_columnHeaderCells(IUnknown*** cell_accessibles,
+ long* n_column_header_cells) override;
- CONTENT_EXPORT STDMETHODIMP get_columnIndex(long* column_index);
+ CONTENT_EXPORT STDMETHODIMP get_columnIndex(long* column_index) override;
- CONTENT_EXPORT STDMETHODIMP get_rowExtent(long* n_rows_spanned);
+ CONTENT_EXPORT STDMETHODIMP get_rowExtent(long* n_rows_spanned) override;
- CONTENT_EXPORT STDMETHODIMP get_rowHeaderCells(IUnknown*** cell_accessibles,
- long* n_row_header_cells);
+ CONTENT_EXPORT STDMETHODIMP
+ get_rowHeaderCells(IUnknown*** cell_accessibles,
+ long* n_row_header_cells) override;
- CONTENT_EXPORT STDMETHODIMP get_rowIndex(long* row_index);
+ CONTENT_EXPORT STDMETHODIMP get_rowIndex(long* row_index) override;
- CONTENT_EXPORT STDMETHODIMP get_isSelected(boolean* is_selected);
+ CONTENT_EXPORT STDMETHODIMP get_isSelected(boolean* is_selected) override;
- CONTENT_EXPORT STDMETHODIMP get_rowColumnExtents(long* row,
- long* column,
- long* row_extents,
- long* column_extents,
- boolean* is_selected);
+ CONTENT_EXPORT STDMETHODIMP
+ get_rowColumnExtents(long* row,
+ long* column,
+ long* row_extents,
+ long* column_extents,
+ boolean* is_selected) override;
- CONTENT_EXPORT STDMETHODIMP get_table(IUnknown** table);
+ CONTENT_EXPORT STDMETHODIMP get_table(IUnknown** table) override;
//
// IAccessibleText methods.
//
- CONTENT_EXPORT STDMETHODIMP get_nCharacters(LONG* n_characters);
+ CONTENT_EXPORT STDMETHODIMP get_nCharacters(LONG* n_characters) override;
- CONTENT_EXPORT STDMETHODIMP get_caretOffset(LONG* offset);
+ CONTENT_EXPORT STDMETHODIMP get_caretOffset(LONG* offset) override;
- CONTENT_EXPORT STDMETHODIMP get_characterExtents(
- LONG offset,
- enum IA2CoordinateType coord_type,
- LONG* out_x,
- LONG* out_y,
- LONG* out_width,
- LONG* out_height);
+ CONTENT_EXPORT STDMETHODIMP
+ get_characterExtents(LONG offset,
+ enum IA2CoordinateType coord_type,
+ LONG* out_x,
+ LONG* out_y,
+ LONG* out_width,
+ LONG* out_height) override;
- CONTENT_EXPORT STDMETHODIMP get_nSelections(LONG* n_selections);
+ CONTENT_EXPORT STDMETHODIMP get_nSelections(LONG* n_selections) override;
CONTENT_EXPORT STDMETHODIMP get_selection(LONG selection_index,
LONG* start_offset,
- LONG* end_offset);
+ LONG* end_offset) override;
- CONTENT_EXPORT STDMETHODIMP get_text(LONG start_offset,
- LONG end_offset,
- BSTR* text);
+ CONTENT_EXPORT STDMETHODIMP
+ get_text(LONG start_offset, LONG end_offset, BSTR* text) override;
- CONTENT_EXPORT STDMETHODIMP get_textAtOffset(
- LONG offset,
- enum IA2TextBoundaryType boundary_type,
- LONG* start_offset,
- LONG* end_offset,
- BSTR* text);
+ CONTENT_EXPORT STDMETHODIMP
+ get_textAtOffset(LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset,
+ LONG* end_offset,
+ BSTR* text) override;
- CONTENT_EXPORT STDMETHODIMP get_textBeforeOffset(
- LONG offset,
- enum IA2TextBoundaryType boundary_type,
- LONG* start_offset,
- LONG* end_offset,
- BSTR* text);
+ CONTENT_EXPORT STDMETHODIMP
+ get_textBeforeOffset(LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset,
+ LONG* end_offset,
+ BSTR* text) override;
- CONTENT_EXPORT STDMETHODIMP get_textAfterOffset(
- LONG offset,
- enum IA2TextBoundaryType boundary_type,
- LONG* start_offset,
- LONG* end_offset,
- BSTR* text);
+ CONTENT_EXPORT STDMETHODIMP
+ get_textAfterOffset(LONG offset,
+ enum IA2TextBoundaryType boundary_type,
+ LONG* start_offset,
+ LONG* end_offset,
+ BSTR* text) override;
- CONTENT_EXPORT STDMETHODIMP get_newText(IA2TextSegment* new_text);
+ CONTENT_EXPORT STDMETHODIMP get_newText(IA2TextSegment* new_text) override;
- CONTENT_EXPORT STDMETHODIMP get_oldText(IA2TextSegment* old_text);
+ CONTENT_EXPORT STDMETHODIMP get_oldText(IA2TextSegment* old_text) override;
- CONTENT_EXPORT STDMETHODIMP get_offsetAtPoint(
- LONG x,
- LONG y,
- enum IA2CoordinateType coord_type,
- LONG* offset);
+ CONTENT_EXPORT STDMETHODIMP
+ get_offsetAtPoint(LONG x,
+ LONG y,
+ enum IA2CoordinateType coord_type,
+ LONG* offset) override;
- CONTENT_EXPORT STDMETHODIMP scrollSubstringTo(
- LONG start_index,
- LONG end_index,
- enum IA2ScrollType scroll_type);
+ CONTENT_EXPORT STDMETHODIMP
+ scrollSubstringTo(LONG start_index,
+ LONG end_index,
+ enum IA2ScrollType scroll_type) override;
- CONTENT_EXPORT STDMETHODIMP scrollSubstringToPoint(
- LONG start_index,
- LONG end_index,
- enum IA2CoordinateType coordinate_type,
- LONG x, LONG y);
+ CONTENT_EXPORT STDMETHODIMP
+ scrollSubstringToPoint(LONG start_index,
+ LONG end_index,
+ enum IA2CoordinateType coordinate_type,
+ LONG x,
+ LONG y) override;
- CONTENT_EXPORT STDMETHODIMP addSelection(LONG start_offset, LONG end_offset);
+ CONTENT_EXPORT STDMETHODIMP
+ addSelection(LONG start_offset, LONG end_offset) override;
- CONTENT_EXPORT STDMETHODIMP removeSelection(LONG selection_index);
+ CONTENT_EXPORT STDMETHODIMP removeSelection(LONG selection_index) override;
- CONTENT_EXPORT STDMETHODIMP setCaretOffset(LONG offset);
+ CONTENT_EXPORT STDMETHODIMP setCaretOffset(LONG offset) override;
CONTENT_EXPORT STDMETHODIMP setSelection(LONG selection_index,
LONG start_offset,
- LONG end_offset);
+ LONG end_offset) override;
// IAccessibleText methods not implemented.
- CONTENT_EXPORT STDMETHODIMP get_attributes(LONG offset, LONG* start_offset,
+ CONTENT_EXPORT STDMETHODIMP get_attributes(LONG offset,
+ LONG* start_offset,
LONG* end_offset,
- BSTR* text_attributes) {
+ BSTR* text_attributes) override {
return E_NOTIMPL;
}
@@ -525,54 +533,54 @@ BrowserAccessibilityWin
// IAccessibleHypertext methods.
//
- CONTENT_EXPORT STDMETHODIMP get_nHyperlinks(long* hyperlink_count);
+ CONTENT_EXPORT STDMETHODIMP get_nHyperlinks(long* hyperlink_count) override;
- CONTENT_EXPORT STDMETHODIMP get_hyperlink(long index,
- IAccessibleHyperlink** hyperlink);
+ CONTENT_EXPORT STDMETHODIMP
+ get_hyperlink(long index, IAccessibleHyperlink** hyperlink) override;
- CONTENT_EXPORT STDMETHODIMP get_hyperlinkIndex(long char_index,
- long* hyperlink_index);
+ CONTENT_EXPORT STDMETHODIMP
+ get_hyperlinkIndex(long char_index, long* hyperlink_index) override;
// IAccessibleHyperlink not implemented.
- CONTENT_EXPORT STDMETHODIMP get_anchor(long index, VARIANT* anchor) {
+ CONTENT_EXPORT STDMETHODIMP get_anchor(long index, VARIANT* anchor) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_anchorTarget(long index,
- VARIANT* anchor_target) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_anchorTarget(long index, VARIANT* anchor_target) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_startIndex( long* index) {
+ CONTENT_EXPORT STDMETHODIMP get_startIndex(long* index) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_endIndex( long* index) {
+ CONTENT_EXPORT STDMETHODIMP get_endIndex(long* index) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_valid(boolean* valid) {
+ CONTENT_EXPORT STDMETHODIMP get_valid(boolean* valid) override {
return E_NOTIMPL;
}
// IAccessibleAction not implemented.
- CONTENT_EXPORT STDMETHODIMP nActions(long* n_actions) {
+ CONTENT_EXPORT STDMETHODIMP nActions(long* n_actions) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP doAction(long action_index) {
+ CONTENT_EXPORT STDMETHODIMP doAction(long action_index) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_description(long action_index,
- BSTR* description) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_description(long action_index, BSTR* description) override {
return E_NOTIMPL;
}
CONTENT_EXPORT STDMETHODIMP get_keyBinding(long action_index,
long n_max_bindings,
BSTR** key_bindings,
- long* n_bindings) {
+ long* n_bindings) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_name(long action_index, BSTR* name) {
+ CONTENT_EXPORT STDMETHODIMP get_name(long action_index, BSTR* name) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_localizedName(long action_index,
- BSTR* localized_name) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_localizedName(long action_index, BSTR* localized_name) override {
return E_NOTIMPL;
}
@@ -580,32 +588,32 @@ BrowserAccessibilityWin
// IAccessibleValue methods.
//
- CONTENT_EXPORT STDMETHODIMP get_currentValue(VARIANT* value);
+ CONTENT_EXPORT STDMETHODIMP get_currentValue(VARIANT* value) override;
- CONTENT_EXPORT STDMETHODIMP get_minimumValue(VARIANT* value);
+ CONTENT_EXPORT STDMETHODIMP get_minimumValue(VARIANT* value) override;
- CONTENT_EXPORT STDMETHODIMP get_maximumValue(VARIANT* value);
+ CONTENT_EXPORT STDMETHODIMP get_maximumValue(VARIANT* value) override;
- CONTENT_EXPORT STDMETHODIMP setCurrentValue(VARIANT new_value);
+ CONTENT_EXPORT STDMETHODIMP setCurrentValue(VARIANT new_value) override;
//
// ISimpleDOMDocument methods.
//
- CONTENT_EXPORT STDMETHODIMP get_URL(BSTR* url);
+ CONTENT_EXPORT STDMETHODIMP get_URL(BSTR* url) override;
- CONTENT_EXPORT STDMETHODIMP get_title(BSTR* title);
+ CONTENT_EXPORT STDMETHODIMP get_title(BSTR* title) override;
- CONTENT_EXPORT STDMETHODIMP get_mimeType(BSTR* mime_type);
+ CONTENT_EXPORT STDMETHODIMP get_mimeType(BSTR* mime_type) override;
- CONTENT_EXPORT STDMETHODIMP get_docType(BSTR* doc_type);
+ CONTENT_EXPORT STDMETHODIMP get_docType(BSTR* doc_type) override;
- CONTENT_EXPORT STDMETHODIMP get_nameSpaceURIForID(short name_space_id,
- BSTR* name_space_uri) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_nameSpaceURIForID(short name_space_id, BSTR* name_space_uri) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP put_alternateViewMediaTypes(
- BSTR* comma_separated_media_types) {
+ CONTENT_EXPORT STDMETHODIMP
+ put_alternateViewMediaTypes(BSTR* comma_separated_media_types) override {
return E_NOTIMPL;
}
@@ -618,57 +626,60 @@ BrowserAccessibilityWin
BSTR* node_value,
unsigned int* num_children,
unsigned int* unique_id,
- unsigned short* node_type);
+ unsigned short* node_type) override;
- CONTENT_EXPORT STDMETHODIMP get_attributes(unsigned short max_attribs,
- BSTR* attrib_names,
- short* name_space_id,
- BSTR* attrib_values,
- unsigned short* num_attribs);
+ CONTENT_EXPORT STDMETHODIMP
+ get_attributes(unsigned short max_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values,
+ unsigned short* num_attribs) override;
- CONTENT_EXPORT STDMETHODIMP get_attributesForNames(
- unsigned short num_attribs,
- BSTR* attrib_names,
- short* name_space_id,
- BSTR* attrib_values);
+ CONTENT_EXPORT STDMETHODIMP
+ get_attributesForNames(unsigned short num_attribs,
+ BSTR* attrib_names,
+ short* name_space_id,
+ BSTR* attrib_values) override;
- CONTENT_EXPORT STDMETHODIMP get_computedStyle(
- unsigned short max_style_properties,
- boolean use_alternate_view,
- BSTR *style_properties,
- BSTR *style_values,
- unsigned short *num_style_properties);
+ CONTENT_EXPORT STDMETHODIMP
+ get_computedStyle(unsigned short max_style_properties,
+ boolean use_alternate_view,
+ BSTR* style_properties,
+ BSTR* style_values,
+ unsigned short* num_style_properties) override;
- CONTENT_EXPORT STDMETHODIMP get_computedStyleForProperties(
- unsigned short num_style_properties,
- boolean use_alternate_view,
- BSTR* style_properties,
- BSTR* style_values);
+ CONTENT_EXPORT STDMETHODIMP
+ get_computedStyleForProperties(unsigned short num_style_properties,
+ boolean use_alternate_view,
+ BSTR* style_properties,
+ BSTR* style_values) override;
- CONTENT_EXPORT STDMETHODIMP scrollTo(boolean placeTopLeft);
+ CONTENT_EXPORT STDMETHODIMP scrollTo(boolean placeTopLeft) override;
- CONTENT_EXPORT STDMETHODIMP get_parentNode(ISimpleDOMNode** node);
+ CONTENT_EXPORT STDMETHODIMP get_parentNode(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_firstChild(ISimpleDOMNode** node);
+ CONTENT_EXPORT STDMETHODIMP get_firstChild(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_lastChild(ISimpleDOMNode** node);
+ CONTENT_EXPORT STDMETHODIMP get_lastChild(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_previousSibling(ISimpleDOMNode** node);
+ CONTENT_EXPORT STDMETHODIMP
+ get_previousSibling(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_nextSibling(ISimpleDOMNode** node);
+ CONTENT_EXPORT STDMETHODIMP get_nextSibling(ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_childAt(unsigned int child_index,
- ISimpleDOMNode** node);
+ CONTENT_EXPORT STDMETHODIMP
+ get_childAt(unsigned int child_index, ISimpleDOMNode** node) override;
- CONTENT_EXPORT STDMETHODIMP get_innerHTML(BSTR* innerHTML) {
+ CONTENT_EXPORT STDMETHODIMP get_innerHTML(BSTR* innerHTML) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_localInterface(void** local_interface) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_localInterface(void** local_interface) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_language(BSTR* language) {
+ CONTENT_EXPORT STDMETHODIMP get_language(BSTR* language) override {
return E_NOTIMPL;
}
@@ -676,28 +687,28 @@ BrowserAccessibilityWin
// ISimpleDOMText methods.
//
- CONTENT_EXPORT STDMETHODIMP get_domText(BSTR* dom_text);
+ CONTENT_EXPORT STDMETHODIMP get_domText(BSTR* dom_text) override;
- CONTENT_EXPORT STDMETHODIMP get_clippedSubstringBounds(
- unsigned int start_index,
- unsigned int end_index,
- int* out_x,
- int* out_y,
- int* out_width,
- int* out_height);
+ CONTENT_EXPORT STDMETHODIMP
+ get_clippedSubstringBounds(unsigned int start_index,
+ unsigned int end_index,
+ int* out_x,
+ int* out_y,
+ int* out_width,
+ int* out_height) override;
- CONTENT_EXPORT STDMETHODIMP get_unclippedSubstringBounds(
- unsigned int start_index,
- unsigned int end_index,
- int* out_x,
- int* out_y,
- int* out_width,
- int* out_height);
+ CONTENT_EXPORT STDMETHODIMP
+ get_unclippedSubstringBounds(unsigned int start_index,
+ unsigned int end_index,
+ int* out_x,
+ int* out_y,
+ int* out_width,
+ int* out_height) override;
- CONTENT_EXPORT STDMETHODIMP scrollToSubstring(unsigned int start_index,
- unsigned int end_index);
+ CONTENT_EXPORT STDMETHODIMP
+ scrollToSubstring(unsigned int start_index, unsigned int end_index) override;
- CONTENT_EXPORT STDMETHODIMP get_fontFamily(BSTR *font_family) {
+ CONTENT_EXPORT STDMETHODIMP get_fontFamily(BSTR* font_family) override {
return E_NOTIMPL;
}
@@ -705,28 +716,27 @@ BrowserAccessibilityWin
// IServiceProvider methods.
//
- CONTENT_EXPORT STDMETHODIMP QueryService(REFGUID guidService,
- REFIID riid,
- void** object);
+ CONTENT_EXPORT STDMETHODIMP
+ QueryService(REFGUID guidService, REFIID riid, void** object) override;
// IAccessibleEx methods not implemented.
- CONTENT_EXPORT STDMETHODIMP GetObjectForChild(long child_id,
- IAccessibleEx** ret) {
+ CONTENT_EXPORT STDMETHODIMP
+ GetObjectForChild(long child_id, IAccessibleEx** ret) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP GetIAccessiblePair(IAccessible** acc,
- long* child_id) {
+ CONTENT_EXPORT STDMETHODIMP
+ GetIAccessiblePair(IAccessible** acc, long* child_id) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP GetRuntimeId(SAFEARRAY** runtime_id) {
+ CONTENT_EXPORT STDMETHODIMP GetRuntimeId(SAFEARRAY** runtime_id) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP ConvertReturnedElement(
- IRawElementProviderSimple* element,
- IAccessibleEx** acc) {
+ CONTENT_EXPORT STDMETHODIMP
+ ConvertReturnedElement(IRawElementProviderSimple* element,
+ IAccessibleEx** acc) override {
return E_NOTIMPL;
}
@@ -735,19 +745,21 @@ BrowserAccessibilityWin
//
// The GetPatternProvider/GetPropertyValue methods need to be implemented for
// the on-screen keyboard to show up in Windows 8 metro.
- CONTENT_EXPORT STDMETHODIMP GetPatternProvider(PATTERNID id,
- IUnknown** provider);
- CONTENT_EXPORT STDMETHODIMP GetPropertyValue(PROPERTYID id, VARIANT* ret);
+ CONTENT_EXPORT STDMETHODIMP
+ GetPatternProvider(PATTERNID id, IUnknown** provider) override;
+ CONTENT_EXPORT STDMETHODIMP
+ GetPropertyValue(PROPERTYID id, VARIANT* ret) override;
//
// IRawElementProviderSimple methods not implemented
//
- CONTENT_EXPORT STDMETHODIMP get_ProviderOptions(enum ProviderOptions* ret) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_ProviderOptions(enum ProviderOptions* ret) override {
return E_NOTIMPL;
}
- CONTENT_EXPORT STDMETHODIMP get_HostRawElementProvider(
- IRawElementProviderSimple** provider) {
+ CONTENT_EXPORT STDMETHODIMP
+ get_HostRawElementProvider(IRawElementProviderSimple** provider) override {
return E_NOTIMPL;
}
@@ -755,11 +767,12 @@ BrowserAccessibilityWin
// CComObjectRootEx methods.
//
- CONTENT_EXPORT HRESULT WINAPI InternalQueryInterface(
- void* this_ptr,
- const _ATL_INTMAP_ENTRY* entries,
- REFIID iid,
- void** object);
+ // Called by BEGIN_COM_MAP() / END_COM_MAP().
+ static CONTENT_EXPORT HRESULT WINAPI
+ InternalQueryInterface(void* this_ptr,
+ const _ATL_INTMAP_ENTRY* entries,
+ REFIID iid,
+ void** object);
// Accessors.
int32 ia_role() const { return ia_role_; }
diff --git a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
index eca0d911711..ccda97873d7 100644
--- a/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/chromium/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -11,7 +11,6 @@
#include "content/browser/accessibility/browser_accessibility_manager_win.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
-#include "content/browser/renderer_host/legacy_render_widget_host_win.h"
#include "content/common/accessibility_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/win/atl_module.h"
@@ -59,7 +58,7 @@ class CountedBrowserAccessibilityFactory : public BrowserAccessibilityFactory {
private:
virtual ~CountedBrowserAccessibilityFactory();
- virtual BrowserAccessibility* Create() OVERRIDE;
+ virtual BrowserAccessibility* Create() override;
DISALLOW_COPY_AND_ASSIGN(CountedBrowserAccessibilityFactory);
};
@@ -90,7 +89,7 @@ class BrowserAccessibilityTest : public testing::Test {
virtual ~BrowserAccessibilityTest();
private:
- virtual void SetUp() OVERRIDE;
+ virtual void SetUp() override;
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityTest);
};
@@ -605,12 +604,8 @@ TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) {
const int32 busy_state = 1 << ui::AX_STATE_BUSY;
const int32 readonly_state = 1 << ui::AX_STATE_READ_ONLY;
const int32 enabled_state = 1 << ui::AX_STATE_ENABLED;
- scoped_ptr<content::LegacyRenderWidgetHostHWND> accessible_hwnd(
- content::LegacyRenderWidgetHostHWND::Create(GetDesktopWindow()));
scoped_ptr<BrowserAccessibilityManager> manager(
new BrowserAccessibilityManagerWin(
- accessible_hwnd.get(),
- NULL,
BrowserAccessibilityManagerWin::GetEmptyDocument(),
NULL,
new CountedBrowserAccessibilityFactory()));
@@ -683,57 +678,29 @@ TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) {
ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
}
-TEST(BrowserAccessibilityManagerWinTest, TestAccessibleHWND) {
- HWND desktop_hwnd = GetDesktopWindow();
- base::win::ScopedComPtr<IAccessible> desktop_hwnd_iaccessible;
- ASSERT_EQ(S_OK, AccessibleObjectFromWindow(
- desktop_hwnd, OBJID_CLIENT,
- IID_IAccessible,
- reinterpret_cast<void**>(desktop_hwnd_iaccessible.Receive())));
-
- scoped_ptr<content::LegacyRenderWidgetHostHWND> accessible_hwnd(
- content::LegacyRenderWidgetHostHWND::Create(GetDesktopWindow()));
-
+// This is a regression test for a bug where the initial empty document
+// loaded by a BrowserAccessibilityManagerWin couldn't be looked up by
+// its UniqueIDWin, because the AX Tree was loaded in
+// BrowserAccessibilityManager code before BrowserAccessibilityManagerWin
+// was initialized.
+TEST_F(BrowserAccessibilityTest, EmptyDocHasUniqueIdWin) {
scoped_ptr<BrowserAccessibilityManagerWin> manager(
new BrowserAccessibilityManagerWin(
- accessible_hwnd.get(),
- desktop_hwnd_iaccessible,
BrowserAccessibilityManagerWin::GetEmptyDocument(),
- NULL));
- ASSERT_EQ(desktop_hwnd, manager->parent_hwnd());
-
- // Enabling screen reader support and calling MaybeCallNotifyWinEvent
- // should trigger creating the AccessibleHWND, and we should now get a
- // new parent_hwnd with the right window class to fool older screen
- // readers.
- BrowserAccessibilityStateImpl::GetInstance()->OnScreenReaderDetected();
- manager->MaybeCallNotifyWinEvent(0, 0);
- HWND new_parent_hwnd = manager->parent_hwnd();
- ASSERT_NE(desktop_hwnd, new_parent_hwnd);
- WCHAR hwnd_class_name[256];
- ASSERT_NE(0, GetClassName(new_parent_hwnd, hwnd_class_name, 256));
- ASSERT_STREQ(L"Chrome_RenderWidgetHostHWND", hwnd_class_name);
-
- // Destroy the hwnd explicitly; that should trigger clearing parent_hwnd().
- DestroyWindow(new_parent_hwnd);
- ASSERT_EQ(NULL, manager->parent_hwnd());
-
- // Now create it again.
- accessible_hwnd = content::LegacyRenderWidgetHostHWND::Create(
- GetDesktopWindow());
- manager.reset(
- new BrowserAccessibilityManagerWin(
- accessible_hwnd.get(),
- desktop_hwnd_iaccessible,
- BrowserAccessibilityManagerWin::GetEmptyDocument(),
- NULL));
- manager->MaybeCallNotifyWinEvent(0, 0);
- new_parent_hwnd = manager->parent_hwnd();
- ASSERT_FALSE(NULL == new_parent_hwnd);
-
- // This time, destroy the manager first, make sure the AccessibleHWND doesn't
- // crash on destruction (to be caught by SyzyASAN or other tools).
- manager.reset(NULL);
+ NULL,
+ new CountedBrowserAccessibilityFactory()));
+
+ // Verify the root is as we expect by default.
+ BrowserAccessibility* root = manager->GetRoot();
+ EXPECT_EQ(0, root->GetId());
+ EXPECT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, root->GetRole());
+ EXPECT_EQ(1 << ui::AX_STATE_BUSY |
+ 1 << ui::AX_STATE_READ_ONLY |
+ 1 << ui::AX_STATE_ENABLED,
+ root->GetState());
+
+ LONG unique_id_win = root->ToBrowserAccessibilityWin()->unique_id_win();
+ ASSERT_EQ(root, manager->GetFromUniqueIdWin(unique_id_win));
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index 06b72962fd2..8f83ed97b10 100644
--- a/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/chromium/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -57,8 +57,8 @@ class CrossPlatformAccessibilityBrowserTest : public ContentBrowserTest {
}
// ContentBrowserTest
- virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
- virtual void TearDownInProcessBrowserTestFixture() OVERRIDE;
+ void SetUpInProcessBrowserTestFixture() override;
+ void TearDownInProcessBrowserTestFixture() override;
protected:
std::string GetAttr(const ui::AXNode* node,
diff --git a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index d373f7b8757..fbe8f475b32 100644
--- a/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/chromium/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -7,7 +7,7 @@
#include <vector>
#include "base/command_line.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string16.h"
@@ -19,6 +19,7 @@
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/renderer_host/render_view_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/public/browser/web_contents.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
@@ -29,6 +30,10 @@
#include "content/test/accessibility_browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
+#endif
+
// TODO(aboxhall): Create expectations on Android for these
#if defined(OS_ANDROID)
#define MAYBE(x) DISABLED_##x
@@ -90,11 +95,31 @@ class DumpAccessibilityTreeTest : public ContentBrowserTest {
void AddDefaultFilters(std::vector<Filter>* filters) {
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("*=''"), Filter::DENY));
}
- void ParseFilters(const std::string& test_html,
- std::vector<Filter>* filters) {
+ // Parse the test html file and parse special directives, usually
+ // beginning with an '@' and inside an HTML comment, that control how the
+ // test is run and how the results are interpreted.
+ //
+ // When the accessibility tree is dumped as text, each attribute is
+ // run through filters before being appended to the string. An "allow"
+ // filter specifies attribute strings that should be dumped, and a "deny"
+ // filter specifies strings that should be suppressed. As an example,
+ // @MAC-ALLOW:AXSubrole=* means that the AXSubrole attribute should be
+ // printed, while @MAC-ALLOW:AXSubrole=AXList* means that any subrole
+ // beginning with the text "AXList" should be printed.
+ //
+ // The @WAIT-FOR:text directive allows the test to specify that the document
+ // may dynamically change after initial load, and the test is to wait
+ // 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.
+ void ParseHtmlForExtraDirectives(const std::string& test_html,
+ std::vector<Filter>* filters,
+ std::string* wait_for) {
std::vector<std::string> lines;
base::SplitString(test_html, '\n', &lines);
for (std::vector<std::string>::const_iterator iter = lines.begin();
@@ -107,6 +132,7 @@ class DumpAccessibilityTreeTest : public ContentBrowserTest {
AccessibilityTreeFormatter::GetAllowString();
const std::string& deny_str =
AccessibilityTreeFormatter::GetDenyString();
+ const std::string& wait_str = "@WAIT-FOR:";
if (StartsWithASCII(line, allow_empty_str, true)) {
filters->push_back(
Filter(base::UTF8ToUTF16(line.substr(allow_empty_str.size())),
@@ -119,14 +145,16 @@ class DumpAccessibilityTreeTest : public ContentBrowserTest {
filters->push_back(Filter(base::UTF8ToUTF16(
line.substr(deny_str.size())),
Filter::DENY));
+ } else if (StartsWithASCII(line, wait_str, true)) {
+ *wait_for = line.substr(wait_str.size());
}
}
}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(base::CommandLine* command_line) override {
ContentBrowserTest::SetUpCommandLine(command_line);
// Enable <dialog>, which is used in some tests.
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
}
@@ -170,32 +198,52 @@ void DumpAccessibilityTreeTest::RunTest(
return;
}
+ // Parse filters and other directives in the test file.
+ std::vector<Filter> filters;
+ 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("accessibility",
html_file.BaseName().MaybeAsASCII().c_str());
- AccessibilityNotificationWaiter waiter(
- shell(), AccessibilityModeComplete,
- ui::AX_EVENT_LOAD_COMPLETE);
- NavigateToURL(shell(), url);
- waiter.WaitForNotification();
- RenderWidgetHostViewBase* host_view = static_cast<RenderWidgetHostViewBase*>(
- shell()->web_contents()->GetRenderWidgetHostView());
- AccessibilityTreeFormatter formatter(
- host_view->GetBrowserAccessibilityManager()->GetRoot());
+ // 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));
+ }
- // Parse filters in the test file.
- std::vector<Filter> filters;
- AddDefaultFilters(&filters);
- ParseFilters(html_contents, &filters);
- formatter.SetFilters(filters);
+ // Load the test html.
+ NavigateToURL(shell(), url);
+
+ // 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.
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ shell()->web_contents());
+ std::string actual_contents;
+ do {
+ waiter->WaitForNotification();
+ base::string16 actual_contents_utf16;
+ AccessibilityTreeFormatter formatter(
+ web_contents->GetRootBrowserAccessibilityManager()->GetRoot());
+ formatter.SetFilters(filters);
+ formatter.FormatAccessibilityTree(&actual_contents_utf16);
+ actual_contents = base::UTF16ToUTF8(actual_contents_utf16);
+ } while (!wait_for.empty() &&
+ actual_contents.find(wait_for) == std::string::npos);
// Perform a diff (or write the initial baseline).
- base::string16 actual_contents_utf16;
- formatter.FormatAccessibilityTree(&actual_contents_utf16);
- std::string actual_contents = base::UTF16ToUTF8(actual_contents_utf16);
std::vector<std::string> actual_lines, expected_lines;
Tokenize(actual_contents, "\n", &actual_lines);
Tokenize(expected_contents, "\n", &expected_lines);
@@ -246,14 +294,26 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityA) {
RunTest(FILE_PATH_LITERAL("a.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAbbr) {
+ RunTest(FILE_PATH_LITERAL("abbr.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAddress) {
RunTest(FILE_PATH_LITERAL("address.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityArea) {
+ RunTest(FILE_PATH_LITERAL("area.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAName) {
RunTest(FILE_PATH_LITERAL("a-name.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityANameCalc) {
+ RunTest(FILE_PATH_LITERAL("a-name-calc.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityANoText) {
RunTest(FILE_PATH_LITERAL("a-no-text.html"));
}
@@ -263,15 +323,57 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAOnclick) {
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaActivedescendant) {
+ RunTest(FILE_PATH_LITERAL("aria-activedescendant.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaAlert) {
+ RunTest(FILE_PATH_LITERAL("aria-alert.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaApplication) {
RunTest(FILE_PATH_LITERAL("aria-application.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaArticle) {
+ RunTest(FILE_PATH_LITERAL("aria-article.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaAtomic) {
+ RunTest(FILE_PATH_LITERAL("aria-atomic.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityAriaAutocomplete) {
RunTest(FILE_PATH_LITERAL("aria-autocomplete.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaBanner) {
+ RunTest(FILE_PATH_LITERAL("aria-banner.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaBusy) {
+ RunTest(FILE_PATH_LITERAL("aria-busy.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaButton) {
+ RunTest(FILE_PATH_LITERAL("aria-button.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaCheckBox) {
+ RunTest(FILE_PATH_LITERAL("aria-checkbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaChecked) {
+ RunTest(FILE_PATH_LITERAL("aria-checked.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaColumnHeader) {
+ RunTest(FILE_PATH_LITERAL("aria-columnheader.html"));
+}
+
// crbug.com/98976 will cause new elements to be added to the Blink a11y tree
// Re-baseline after the Blink change goes in
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
@@ -280,10 +382,48 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaComplementary) {
+ RunTest(FILE_PATH_LITERAL("aria-complementary.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaContentInfo) {
+ RunTest(FILE_PATH_LITERAL("aria-contentinfo.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDefinition) {
+ RunTest(FILE_PATH_LITERAL("aria-definition.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDialog) {
+ RunTest(FILE_PATH_LITERAL("aria-dialog.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaExpanded) {
+ RunTest(FILE_PATH_LITERAL("aria-expanded.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaHasPopup) {
+ RunTest(FILE_PATH_LITERAL("aria-haspopup.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaHeading) {
+ RunTest(FILE_PATH_LITERAL("aria-heading.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaHidden) {
+ RunTest(FILE_PATH_LITERAL("aria-hidden.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
MAYBE(AccessibilityAriaFlowto)) {
RunTest(FILE_PATH_LITERAL("aria-flowto.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaImg) {
+ RunTest(FILE_PATH_LITERAL("aria-img.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaInvalid) {
RunTest(FILE_PATH_LITERAL("aria-invalid.html"));
}
@@ -301,17 +441,78 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaList) {
RunTest(FILE_PATH_LITERAL("aria-list.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaListBox) {
+ RunTest(FILE_PATH_LITERAL("aria-listbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaListBoxActiveDescendant) {
+ RunTest(FILE_PATH_LITERAL("aria-listbox-activedescendant.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaListBoxAriaSelected) {
+ RunTest(FILE_PATH_LITERAL("aria-listbox-aria-selected.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaListBoxChildFocus) {
+ RunTest(FILE_PATH_LITERAL("aria-listbox-childfocus.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaLive) {
+ RunTest(FILE_PATH_LITERAL("aria-live.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaLog) {
+ RunTest(FILE_PATH_LITERAL("aria-log.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMarquee) {
+ RunTest(FILE_PATH_LITERAL("aria-marquee.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMenu) {
RunTest(FILE_PATH_LITERAL("aria-menu.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMenuBar) {
+ RunTest(FILE_PATH_LITERAL("aria-menubar.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaMenuitemradio) {
+ AccessibilityAriaMenuItemCheckBox) {
+ RunTest(FILE_PATH_LITERAL("aria-menuitemcheckbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaMenuItemRadio) {
RunTest(FILE_PATH_LITERAL("aria-menuitemradio.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaNavigation) {
+ RunTest(FILE_PATH_LITERAL("aria-navigation.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityAriaOrientation) {
+ RunTest(FILE_PATH_LITERAL("aria-orientation.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMath) {
+ RunTest(FILE_PATH_LITERAL("aria-math.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaNone) {
+ RunTest(FILE_PATH_LITERAL("aria-none.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaPressed) {
+ AccessibilityAriaPresentation) {
+ RunTest(FILE_PATH_LITERAL("aria-presentation.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaPressed) {
RunTest(FILE_PATH_LITERAL("aria-pressed.html"));
}
@@ -321,24 +522,96 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaToolbar) {
- RunTest(FILE_PATH_LITERAL("toolbar.html"));
+ AccessibilityAriaRadiogroup) {
+ RunTest(FILE_PATH_LITERAL("aria-radiogroup.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRelevant) {
+ RunTest(FILE_PATH_LITERAL("aria-relevant.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRequired) {
+ RunTest(FILE_PATH_LITERAL("aria-required.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRow) {
+ RunTest(FILE_PATH_LITERAL("aria-row.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRowGroup) {
+ RunTest(FILE_PATH_LITERAL("aria-rowgroup.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaReadonly) {
+ RunTest(FILE_PATH_LITERAL("aria-readonly.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaRegion) {
+ RunTest(FILE_PATH_LITERAL("aria-region.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSearch) {
+ RunTest(FILE_PATH_LITERAL("aria-search.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSeparator) {
+ RunTest(FILE_PATH_LITERAL("aria-separator.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSort) {
+ RunTest(FILE_PATH_LITERAL("aria-sort.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaValueMin) {
- RunTest(FILE_PATH_LITERAL("aria-valuemin.html"));
+ AccessibilityAriaSpinButton) {
+ RunTest(FILE_PATH_LITERAL("aria-spinbutton.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTextbox) {
+ RunTest(FILE_PATH_LITERAL("aria-textbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTimer) {
+ RunTest(FILE_PATH_LITERAL("aria-timer.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaValueMax) {
+ AccessibilityAriaToggleButton) {
+ RunTest(FILE_PATH_LITERAL("aria-togglebutton.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaToolbar) {
+ RunTest(FILE_PATH_LITERAL("aria-toolbar.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTree) {
+ RunTest(FILE_PATH_LITERAL("aria-tree.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaValueMin) {
+ RunTest(FILE_PATH_LITERAL("aria-valuemin.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaValueMax) {
RunTest(FILE_PATH_LITERAL("aria-valuemax.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaValueNow) {
+ RunTest(FILE_PATH_LITERAL("aria-valuenow.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityArticle) {
RunTest(FILE_PATH_LITERAL("article.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAside) {
+ RunTest(FILE_PATH_LITERAL("aside.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAudio) {
+ RunTest(FILE_PATH_LITERAL("audio.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAWithImg) {
RunTest(FILE_PATH_LITERAL("a-with-img.html"));
}
@@ -347,10 +620,22 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBdo) {
RunTest(FILE_PATH_LITERAL("bdo.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBlockquote) {
+ RunTest(FILE_PATH_LITERAL("blockquote.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBody) {
+ RunTest(FILE_PATH_LITERAL("body.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBR) {
RunTest(FILE_PATH_LITERAL("br.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityButton) {
+ RunTest(FILE_PATH_LITERAL("button.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityButtonNameCalc) {
RunTest(FILE_PATH_LITERAL("button-name-calc.html"));
}
@@ -359,11 +644,39 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCanvas) {
RunTest(FILE_PATH_LITERAL("canvas.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCaption) {
+ RunTest(FILE_PATH_LITERAL("caption.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityCheckboxNameCalc) {
RunTest(FILE_PATH_LITERAL("checkbox-name-calc.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCite) {
+ RunTest(FILE_PATH_LITERAL("cite.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCol) {
+ RunTest(FILE_PATH_LITERAL("col.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityColgroup) {
+ RunTest(FILE_PATH_LITERAL("colgroup.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDel) {
+ RunTest(FILE_PATH_LITERAL("del.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDetails) {
+ RunTest(FILE_PATH_LITERAL("details.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDfn) {
+ RunTest(FILE_PATH_LITERAL("dfn.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDialog) {
RunTest(FILE_PATH_LITERAL("dialog.html"));
}
@@ -376,8 +689,14 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDl) {
RunTest(FILE_PATH_LITERAL("dl.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityDt) {
+ RunTest(FILE_PATH_LITERAL("dt.html"));
+}
+
+//Disabled because of https://codereview.chromium.org/696953002 temporarily.
+//After blink code is merged, it will be enabled.
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityContenteditableDescendants) {
+ DISABLED_AccessibilityContenteditableDescendants) {
RunTest(FILE_PATH_LITERAL("contenteditable-descendants.html"));
}
@@ -385,6 +704,18 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityEm) {
RunTest(FILE_PATH_LITERAL("em.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFieldset) {
+ RunTest(FILE_PATH_LITERAL("fieldset.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFigcaption) {
+ RunTest(FILE_PATH_LITERAL("figcaption.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFigure) {
+ RunTest(FILE_PATH_LITERAL("figure.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFooter) {
RunTest(FILE_PATH_LITERAL("footer.html"));
}
@@ -393,6 +724,18 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityForm) {
RunTest(FILE_PATH_LITERAL("form.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityFrameset) {
+ RunTest(FILE_PATH_LITERAL("frameset.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHead) {
+ RunTest(FILE_PATH_LITERAL("head.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHeader) {
+ RunTest(FILE_PATH_LITERAL("header.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHeading) {
RunTest(FILE_PATH_LITERAL("heading.html"));
}
@@ -401,11 +744,23 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHR) {
RunTest(FILE_PATH_LITERAL("hr.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityI) {
+ RunTest(FILE_PATH_LITERAL("i.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityIframe) {
+ RunTest(FILE_PATH_LITERAL("iframe.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityIframeCoordinates) {
RunTest(FILE_PATH_LITERAL("iframe-coordinates.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityImg) {
+ RunTest(FILE_PATH_LITERAL("img.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputButton) {
RunTest(FILE_PATH_LITERAL("input-button.html"));
}
@@ -415,31 +770,114 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
RunTest(FILE_PATH_LITERAL("input-button-in-menu.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputCheckBox) {
+ RunTest(FILE_PATH_LITERAL("input-checkbox.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityInputCheckBoxInMenu) {
+ RunTest(FILE_PATH_LITERAL("input-checkbox-in-menu.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputColor) {
RunTest(FILE_PATH_LITERAL("input-color.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputDate) {
+ RunTest(FILE_PATH_LITERAL("input-date.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputDateTime) {
+ RunTest(FILE_PATH_LITERAL("input-datetime.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityInputDateTimeLocal) {
+#if defined(OS_MACOSX)
+ // Fails on OS X 10.9 <https://crbug.com/430622>.
+ if (base::mac::IsOSMavericks())
+ return;
+#endif
+ RunTest(FILE_PATH_LITERAL("input-datetime-local.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityInputImageButtonInMenu) {
RunTest(FILE_PATH_LITERAL("input-image-button-in-menu.html"));
}
+// crbug.com/423675 - AX tree is different for Win7 and Win8.
+#if defined(OS_WIN)
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ DISABLED_AccessibilityInputMonth) {
+ RunTest(FILE_PATH_LITERAL("input-month.html"));
+}
+#else
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputMonth) {
+ RunTest(FILE_PATH_LITERAL("input-month.html"));
+}
+#endif
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputRadio) {
+ RunTest(FILE_PATH_LITERAL("input-radio.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputRange) {
RunTest(FILE_PATH_LITERAL("input-range.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputReset) {
+ RunTest(FILE_PATH_LITERAL("input-reset.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputSearch) {
+ RunTest(FILE_PATH_LITERAL("input-search.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputSubmit) {
+ RunTest(FILE_PATH_LITERAL("input-submit.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputTel) {
+ RunTest(FILE_PATH_LITERAL("input-tel.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputText) {
+ RunTest(FILE_PATH_LITERAL("input-text.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityInputTextNameCalc) {
RunTest(FILE_PATH_LITERAL("input-text-name-calc.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputTextValue) {
+ RunTest(FILE_PATH_LITERAL("input-text-value.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputTime) {
+ RunTest(FILE_PATH_LITERAL("input-time.html"));
+}
+
// crbug.com/98976 will cause new elements to be added to the Blink a11y tree
// Re-baseline after the Blink change goes in
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- DISABLED_AccessibilityInputTypes) {
+ AccessibilityInputTypes) {
RunTest(FILE_PATH_LITERAL("input-types.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputUrl) {
+ RunTest(FILE_PATH_LITERAL("input-url.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputWeek) {
+ RunTest(FILE_PATH_LITERAL("input-week.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityIns) {
+ RunTest(FILE_PATH_LITERAL("ins.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLabel) {
RunTest(FILE_PATH_LITERAL("label.html"));
}
@@ -448,10 +886,52 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLandmark) {
RunTest(FILE_PATH_LITERAL("landmark.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityListMarkers) {
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLegend) {
+ RunTest(FILE_PATH_LITERAL("legend.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityLink) {
+ RunTest(FILE_PATH_LITERAL("link.html"));
+}
+
+//Disabled because of https://codereview.chromium.org/696953002 temporarily.
+//After blink code is merged, it will be enabled.
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, DISABLED_AccessibilityList) {
+ RunTest(FILE_PATH_LITERAL("list.html"));
+}
+
+//Disabled because of https://codereview.chromium.org/696953002 temporarily.
+//After blink code is merged, it will be enabled.
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ DISABLED_AccessibilityListMarkers) {
RunTest(FILE_PATH_LITERAL("list-markers.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMain) {
+ RunTest(FILE_PATH_LITERAL("main.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMark) {
+ RunTest(FILE_PATH_LITERAL("mark.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMath) {
+ RunTest(FILE_PATH_LITERAL("math.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityMenutypecontext) {
+ RunTest(FILE_PATH_LITERAL("menu-type-context.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMeta) {
+ RunTest(FILE_PATH_LITERAL("meta.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMeter) {
+ RunTest(FILE_PATH_LITERAL("meter.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityModalDialogClosed) {
RunTest(FILE_PATH_LITERAL("modal-dialog-closed.html"));
@@ -477,29 +957,86 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
RunTest(FILE_PATH_LITERAL("modal-dialog-stack.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityNavigation) {
+ RunTest(FILE_PATH_LITERAL("navigation.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityNoscript) {
+ RunTest(FILE_PATH_LITERAL("noscript.html"));
+}
+
+//Disabled because of https://codereview.chromium.org/696953002 temporarily.
+//After blink code is merged, it will be enabled.
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, DISABLED_AccessibilityOl) {
+ RunTest(FILE_PATH_LITERAL("ol.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityObject) {
+ RunTest(FILE_PATH_LITERAL("object.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityOptionindatalist) {
+ RunTest(FILE_PATH_LITERAL("option-in-datalist.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityOutput) {
+ RunTest(FILE_PATH_LITERAL("output.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityP) {
RunTest(FILE_PATH_LITERAL("p.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityRegion) {
- RunTest(FILE_PATH_LITERAL("region.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityParam) {
+ RunTest(FILE_PATH_LITERAL("param.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityPre) {
+ RunTest(FILE_PATH_LITERAL("pre.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityProgress) {
+ RunTest(FILE_PATH_LITERAL("progress.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityQ) {
+ RunTest(FILE_PATH_LITERAL("q.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityS) {
+ RunTest(FILE_PATH_LITERAL("s.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySamp) {
+ RunTest(FILE_PATH_LITERAL("samp.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySection) {
+ RunTest(FILE_PATH_LITERAL("section.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySelect) {
RunTest(FILE_PATH_LITERAL("select.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySource) {
+ RunTest(FILE_PATH_LITERAL("source.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySpan) {
RunTest(FILE_PATH_LITERAL("span.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySpinButton) {
- RunTest(FILE_PATH_LITERAL("spinbutton.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySub) {
+ RunTest(FILE_PATH_LITERAL("sub.html"));
}
-// TODO(dmazzoni): Rebaseline this test after Blink rolls past r155083.
-// See http://crbug.com/265619
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, DISABLED_AccessibilitySvg) {
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySummary) {
+ RunTest(FILE_PATH_LITERAL("summary.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySvg) {
RunTest(FILE_PATH_LITERAL("svg.html"));
}
@@ -511,26 +1048,48 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTableSimple) {
RunTest(FILE_PATH_LITERAL("table-simple.html"));
}
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityTableThRowHeader) {
+ RunTest(FILE_PATH_LITERAL("table-th-rowheader.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
+ AccessibilityTableTbodyTfoot) {
+ RunTest(FILE_PATH_LITERAL("table-thead-tbody-tfoot.html"));
+}
+
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTableSpans) {
RunTest(FILE_PATH_LITERAL("table-spans.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityToggleButton) {
- RunTest(FILE_PATH_LITERAL("togglebutton.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTextArea) {
+ RunTest(FILE_PATH_LITERAL("textarea.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityUl) {
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTime) {
+ RunTest(FILE_PATH_LITERAL("time.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTitle) {
+ RunTest(FILE_PATH_LITERAL("title.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityTransition) {
+ RunTest(FILE_PATH_LITERAL("transition.html"));
+}
+
+//Disabled because of https://codereview.chromium.org/696953002 temporarily.
+//After blink code is merged, it will be enabled.
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, DISABLED_AccessibilityUl) {
RunTest(FILE_PATH_LITERAL("ul.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityWbr) {
- RunTest(FILE_PATH_LITERAL("wbr.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityVar) {
+ RunTest(FILE_PATH_LITERAL("var.html"));
}
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
- AccessibilityAriaActivedescendant) {
- RunTest(FILE_PATH_LITERAL("aria-activedescendant.html"));
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityWbr) {
+ RunTest(FILE_PATH_LITERAL("wbr.html"));
}
} // namespace content
diff --git a/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc b/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
new file mode 100644
index 00000000000..12cdc89376c
--- /dev/null
+++ b/chromium/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
@@ -0,0 +1,146 @@
+// 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 "base/command_line.h"
+#include "base/strings/stringprintf.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/cross_process_frame_connector.h"
+#include "content/browser/frame_host/frame_tree.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/renderer_host/render_view_host_impl.h"
+#include "content/browser/site_per_process_browsertest.h"
+#include "content/browser/web_contents/web_contents_impl.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/web_contents_observer.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 "content/test/accessibility_browser_test_utils.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "net/dns/mock_host_resolver.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class SitePerProcessAccessibilityBrowserTest
+ : public SitePerProcessBrowserTest {
+ public:
+ SitePerProcessAccessibilityBrowserTest() {}
+};
+
+// TODO(nasko): try enabling this test on more platforms once
+// SitePerProcessBrowserTest.CrossSiteIframe is enabled everywhere.
+// http://crbug.com/399775
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#define MAYBE_CrossSiteIframeAccessibility CrossSiteIframeAccessibility
+#else
+#define MAYBE_CrossSiteIframeAccessibility DISABLED_CrossSiteIframeAccessibility
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessAccessibilityBrowserTest,
+ MAYBE_CrossSiteIframeAccessibility) {
+ // Enable full accessibility for all current and future WebContents.
+ BrowserAccessibilityState::GetInstance()->EnableAccessibility();
+
+ AccessibilityNotificationWaiter main_frame_accessibility_waiter(
+ shell(), AccessibilityModeComplete,
+ ui::AX_EVENT_LOAD_COMPLETE);
+
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+ GURL main_url(test_server()->GetURL("files/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();
+
+ // Load same-site page into iframe.
+ FrameTreeNode* child = root->child_at(0);
+ GURL http_url(test_server()->GetURL("files/title1.html"));
+ NavigateFrameToURL(child, http_url);
+
+ // These must stay in scope with replace_host.
+ GURL::Replacements replace_host;
+ std::string foo_com("foo.com");
+
+ // Load cross-site page into iframe.
+ GURL cross_site_url(test_server()->GetURL("files/title2.html"));
+ replace_host.SetHostStr(foo_com);
+ cross_site_url = cross_site_url.ReplaceComponents(replace_host);
+ NavigateFrameToURL(root->child_at(0), cross_site_url);
+
+ // Ensure that we have created a new process for the subframe.
+ ASSERT_EQ(2U, root->child_count());
+ SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
+
+ // Wait until the accessibility tree from both the main frame and
+ // cross-process iframe load.
+ RenderFrameHostImpl* child_frame = static_cast<RenderFrameHostImpl*>(
+ child->current_frame_host());
+ AccessibilityNotificationWaiter child_frame_accessibility_waiter(
+ child_frame, ui::AX_EVENT_NONE);
+ main_frame_accessibility_waiter.WaitForNotification();
+ child_frame_accessibility_waiter.WaitForNotification();
+
+ RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
+ shell()->web_contents()->GetMainFrame());
+ BrowserAccessibilityManager* main_frame_manager =
+ main_frame->browser_accessibility_manager();
+ VLOG(1) << "Main frame accessibility tree:\n"
+ << main_frame_manager->SnapshotAXTreeForTesting().ToString();
+
+ BrowserAccessibilityManager* child_frame_manager =
+ child_frame->browser_accessibility_manager();
+ VLOG(1) << "Child frame accessibility tree:\n"
+ << child_frame_manager->SnapshotAXTreeForTesting().ToString();
+
+ // Assert that we can walk from the main frame down into the child frame
+ // directly, getting correct roles and data along the way.
+ BrowserAccessibility* ax_root = main_frame_manager->GetRoot();
+ ASSERT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, ax_root->GetRole());
+ ASSERT_EQ(1U, ax_root->PlatformChildCount());
+
+ BrowserAccessibility* ax_group = ax_root->PlatformGetChild(0);
+ ASSERT_EQ(ui::AX_ROLE_GROUP, ax_group->GetRole());
+ ASSERT_EQ(2U, ax_group->PlatformChildCount());
+
+ BrowserAccessibility* ax_iframe = ax_group->PlatformGetChild(0);
+ ASSERT_EQ(ui::AX_ROLE_IFRAME, ax_iframe->GetRole());
+ ASSERT_EQ(1U, ax_iframe->PlatformChildCount());
+
+ BrowserAccessibility* ax_scroll_area = ax_iframe->PlatformGetChild(0);
+ ASSERT_EQ(ui::AX_ROLE_SCROLL_AREA, ax_scroll_area->GetRole());
+ ASSERT_EQ(1U, ax_scroll_area->PlatformChildCount());
+
+ BrowserAccessibility* ax_child_frame_root =
+ ax_scroll_area->PlatformGetChild(0);
+ ASSERT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, ax_child_frame_root->GetRole());
+ ASSERT_EQ(1U, ax_child_frame_root->PlatformChildCount());
+ ASSERT_EQ("Title Of Awesomeness", ax_child_frame_root->name());
+
+ BrowserAccessibility* ax_child_frame_group =
+ ax_child_frame_root->PlatformGetChild(0);
+ ASSERT_EQ(ui::AX_ROLE_GROUP, ax_child_frame_group->GetRole());
+ ASSERT_EQ(1U, ax_child_frame_group->PlatformChildCount());
+
+ BrowserAccessibility* ax_child_frame_static_text =
+ ax_child_frame_group->PlatformGetChild(0);
+ ASSERT_EQ(ui::AX_ROLE_STATIC_TEXT, ax_child_frame_static_text->GetRole());
+ ASSERT_EQ(0U, ax_child_frame_static_text->PlatformChildCount());
+
+ // Last, check that the parent of the child frame root is correct.
+ ASSERT_EQ(ax_child_frame_root->GetParent(), ax_scroll_area);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/DEPS b/chromium/content/browser/android/DEPS
deleted file mode 100644
index 0410b36ac82..00000000000
--- a/chromium/content/browser/android/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+third_party/WebKit/public/web/WebBindings.h", # For java bridge bindings
-]
diff --git a/chromium/content/browser/android/OWNERS b/chromium/content/browser/android/OWNERS
index 4fd5d774a7c..6ba7da7c389 100644
--- a/chromium/content/browser/android/OWNERS
+++ b/chromium/content/browser/android/OWNERS
@@ -1,5 +1,3 @@
-bulach@chromium.org
-sievers@chromium.org
skyostil@chromium.org
tedchoc@chromium.org
yfriedman@chromium.org
diff --git a/chromium/content/browser/android/browser_startup_controller.cc b/chromium/content/browser/android/browser_startup_controller.cc
index 502f198edba..74e38e62839 100644
--- a/chromium/content/browser/android/browser_startup_controller.cc
+++ b/chromium/content/browser/android/browser_startup_controller.cc
@@ -28,13 +28,13 @@ bool RegisterBrowserStartupController(JNIEnv* env) {
static void SetCommandLineFlags(JNIEnv* env,
jclass clazz,
- jint max_render_process_count,
+ jboolean single_process,
jstring plugin_descriptor) {
std::string plugin_str =
(plugin_descriptor == NULL
? std::string()
: base::android::ConvertJavaStringToUTF8(env, plugin_descriptor));
- SetContentCommandLineFlags(max_render_process_count, plugin_str);
+ SetContentCommandLineFlags(static_cast<bool>(single_process), plugin_str);
}
static jboolean IsOfficialBuild(JNIEnv* env, jclass clazz) {
diff --git a/chromium/content/browser/android/browser_surface_texture_manager.cc b/chromium/content/browser/android/browser_surface_texture_manager.cc
new file mode 100644
index 00000000000..44669839f2b
--- /dev/null
+++ b/chromium/content/browser/android/browser_surface_texture_manager.cc
@@ -0,0 +1,136 @@
+// 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/android/browser_surface_texture_manager.h"
+
+#include <android/native_window_jni.h>
+
+#include "base/android/jni_android.h"
+#include "content/browser/android/child_process_launcher_android.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
+#include "content/browser/media/android/browser_media_player_manager.h"
+#include "content/browser/media/media_web_contents_observer.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "media/base/android/media_player_android.h"
+#include "ui/gl/android/scoped_java_surface.h"
+#include "ui/gl/android/surface_texture.h"
+
+namespace content {
+namespace {
+
+// Pass a java surface object to the MediaPlayerAndroid object
+// identified by render process handle, render frame ID and player ID.
+static void SetSurfacePeer(scoped_refptr<gfx::SurfaceTexture> surface_texture,
+ base::ProcessHandle render_process_handle,
+ int render_frame_id,
+ int player_id) {
+ int render_process_id = 0;
+ RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
+ while (!it.IsAtEnd()) {
+ if (it.GetCurrentValue()->GetHandle() == render_process_handle) {
+ render_process_id = it.GetCurrentValue()->GetID();
+ break;
+ }
+ it.Advance();
+ }
+ if (!render_process_id) {
+ DVLOG(1) << "Cannot find render process for render_process_handle "
+ << render_process_handle;
+ return;
+ }
+
+ RenderFrameHostImpl* frame =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
+ if (!frame) {
+ DVLOG(1) << "Cannot find frame for render_frame_id " << render_frame_id;
+ return;
+ }
+
+ RenderViewHostImpl* view =
+ static_cast<RenderViewHostImpl*>(frame->GetRenderViewHost());
+ BrowserMediaPlayerManager* player_manager =
+ view->media_web_contents_observer()->GetMediaPlayerManager(frame);
+ if (!player_manager) {
+ DVLOG(1) << "Cannot find the media player manager for frame " << frame;
+ return;
+ }
+
+ media::MediaPlayerAndroid* player = player_manager->GetPlayer(player_id);
+ if (!player) {
+ DVLOG(1) << "Cannot find media player for player_id " << player_id;
+ return;
+ }
+
+ if (player != player_manager->GetFullscreenPlayer()) {
+ gfx::ScopedJavaSurface scoped_surface(surface_texture.get());
+ player->SetVideoSurface(scoped_surface.Pass());
+ }
+}
+
+} // namespace
+
+BrowserSurfaceTextureManager::BrowserSurfaceTextureManager() {
+ SurfaceTexturePeer::InitInstance(this);
+}
+
+BrowserSurfaceTextureManager::~BrowserSurfaceTextureManager() {
+ SurfaceTexturePeer::InitInstance(NULL);
+}
+
+void BrowserSurfaceTextureManager::RegisterSurfaceTexture(
+ int surface_texture_id,
+ int client_id,
+ gfx::SurfaceTexture* surface_texture) {
+ content::CreateSurfaceTextureSurface(
+ surface_texture_id, client_id, surface_texture);
+}
+
+void BrowserSurfaceTextureManager::UnregisterSurfaceTexture(
+ int surface_texture_id,
+ int client_id) {
+ content::DestroySurfaceTextureSurface(surface_texture_id, client_id);
+}
+
+gfx::AcceleratedWidget
+BrowserSurfaceTextureManager::AcquireNativeWidgetForSurfaceTexture(
+ int surface_texture_id) {
+ gfx::ScopedJavaSurface surface(
+ content::GetSurfaceTextureSurface(
+ surface_texture_id,
+ BrowserGpuChannelHostFactory::instance()->GetGpuChannelId()));
+ if (surface.j_surface().is_null())
+ return NULL;
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ // Note: This ensures that any local references used by
+ // ANativeWindow_fromSurface are released immediately. This is needed as a
+ // workaround for https://code.google.com/p/android/issues/detail?id=68174
+ base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
+ ANativeWindow* native_window =
+ ANativeWindow_fromSurface(env, surface.j_surface().obj());
+
+ return native_window;
+}
+
+void BrowserSurfaceTextureManager::EstablishSurfaceTexturePeer(
+ base::ProcessHandle render_process_handle,
+ scoped_refptr<gfx::SurfaceTexture> surface_texture,
+ int render_frame_id,
+ int player_id) {
+ if (!surface_texture.get())
+ return;
+
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&SetSurfacePeer,
+ surface_texture,
+ render_process_handle,
+ render_frame_id,
+ player_id));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/browser_surface_texture_manager.h b/chromium/content/browser/android/browser_surface_texture_manager.h
new file mode 100644
index 00000000000..7776d30ee7f
--- /dev/null
+++ b/chromium/content/browser/android/browser_surface_texture_manager.h
@@ -0,0 +1,43 @@
+// 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_ANDROID_BROWSER_SURFACE_TEXTURE_MANAGER_H_
+#define CONTENT_BROWSER_ANDROID_BROWSER_SURFACE_TEXTURE_MANAGER_H_
+
+#include "content/common/android/surface_texture_manager.h"
+
+#include "content/common/android/surface_texture_peer.h"
+
+namespace content {
+
+class BrowserSurfaceTextureManager : public SurfaceTextureManager,
+ public SurfaceTexturePeer {
+ public:
+ BrowserSurfaceTextureManager();
+ virtual ~BrowserSurfaceTextureManager();
+
+ // Overridden from SurfaceTextureManager:
+ virtual void RegisterSurfaceTexture(
+ int surface_texture_id,
+ int client_id,
+ gfx::SurfaceTexture* surface_texture) override;
+ virtual void UnregisterSurfaceTexture(int surface_texture_id,
+ int client_id) override;
+ virtual gfx::AcceleratedWidget AcquireNativeWidgetForSurfaceTexture(
+ int surface_texture_id) override;
+
+ // Overridden from SurfaceTexturePeer:
+ virtual void EstablishSurfaceTexturePeer(
+ base::ProcessHandle render_process_handle,
+ scoped_refptr<gfx::SurfaceTexture> surface_texture,
+ int render_frame_id,
+ int player_id) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserSurfaceTextureManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_BROWSER_SURFACE_TEXTURE_MANAGER_H_
diff --git a/chromium/content/browser/android/child_process_launcher_android.cc b/chromium/content/browser/android/child_process_launcher_android.cc
index baac2b0a715..c937fce174a 100644
--- a/chromium/content/browser/android/child_process_launcher_android.cc
+++ b/chromium/content/browser/android/child_process_launcher_android.cc
@@ -18,7 +18,7 @@
#include "content/public/common/content_switches.h"
#include "jni/ChildProcessLauncher_jni.h"
#include "media/base/android/media_player_android.h"
-#include "ui/gl/android/scoped_java_surface.h"
+#include "ui/gl/android/surface_texture.h"
using base::android::AttachCurrentThread;
using base::android::ToJavaArrayOfStrings;
@@ -100,9 +100,9 @@ static void OnChildProcessStarted(JNIEnv*,
}
void StartChildProcess(
- const CommandLine::StringVector& argv,
+ const base::CommandLine::StringVector& argv,
int child_process_id,
- const std::vector<content::FileDescriptorInfo>& files_to_register,
+ scoped_ptr<content::FileDescriptorInfo> files_to_register,
const StartChildProcessCallback& callback) {
JNIEnv* env = AttachCurrentThread();
DCHECK(env);
@@ -110,7 +110,7 @@ void StartChildProcess(
// Create the Command line String[]
ScopedJavaLocalRef<jobjectArray> j_argv = ToJavaArrayOfStrings(env, argv);
- size_t file_count = files_to_register.size();
+ size_t file_count = files_to_register->GetMappingSize();
DCHECK(file_count > 0);
ScopedJavaLocalRef<jintArray> j_file_ids(env, env->NewIntArray(file_count));
@@ -128,10 +128,14 @@ void StartChildProcess(
env->GetBooleanArrayElements(j_file_auto_close.obj(), NULL);
base::android::CheckException(env);
for (size_t i = 0; i < file_count; ++i) {
- const content::FileDescriptorInfo& fd_info = files_to_register[i];
- file_ids[i] = fd_info.id;
- file_fds[i] = fd_info.fd.fd;
- file_auto_close[i] = fd_info.fd.auto_close;
+ // Owners of passed descriptors can outlive this function and we don't know
+ // when it is safe to close() them. So we pass dup()-ed FD and
+ // let ChildProcessLauncher in java take care of their lifetimes.
+ // TODO(morrita): Drop FileDescriptorInfo.mAutoClose on Java side.
+ file_auto_close[i] = true; // This indicates ownership transfer.
+ file_ids[i] = files_to_register->GetIDAt(i);
+ file_fds[i] = dup(files_to_register->GetFDAt(i));
+ PCHECK(0 <= file_fds[i]);
}
env->ReleaseIntArrayElements(j_file_ids.obj(), file_ids, 0);
env->ReleaseIntArrayElements(j_file_fds.obj(), file_fds, 0);
@@ -193,25 +197,37 @@ void UnregisterViewSurface(int surface_id) {
Java_ChildProcessLauncher_unregisterViewSurface(env, surface_id);
}
-void RegisterChildProcessSurfaceTexture(int surface_texture_id,
- int child_process_id,
- jobject j_surface_texture) {
+void CreateSurfaceTextureSurface(int surface_texture_id,
+ int client_id,
+ gfx::SurfaceTexture* surface_texture) {
JNIEnv* env = AttachCurrentThread();
DCHECK(env);
- Java_ChildProcessLauncher_registerSurfaceTexture(
- env, surface_texture_id, child_process_id, j_surface_texture);
+ Java_ChildProcessLauncher_createSurfaceTextureSurface(
+ env,
+ surface_texture_id,
+ client_id,
+ surface_texture->j_surface_texture().obj());
}
-void UnregisterChildProcessSurfaceTexture(int surface_texture_id,
- int child_process_id) {
+void DestroySurfaceTextureSurface(int surface_texture_id, int client_id) {
JNIEnv* env = AttachCurrentThread();
DCHECK(env);
- Java_ChildProcessLauncher_unregisterSurfaceTexture(
- env, surface_texture_id, child_process_id);
+ Java_ChildProcessLauncher_destroySurfaceTextureSurface(
+ env, surface_texture_id, client_id);
+}
+
+gfx::ScopedJavaSurface GetSurfaceTextureSurface(int surface_texture_id,
+ int client_id) {
+ JNIEnv* env = AttachCurrentThread();
+ DCHECK(env);
+ return gfx::ScopedJavaSurface::AcquireExternalSurface(
+ Java_ChildProcessLauncher_getSurfaceTextureSurface(
+ env, surface_texture_id, client_id).obj());
}
jboolean IsSingleProcess(JNIEnv* env, jclass clazz) {
- return CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess);
}
bool RegisterChildProcessLauncher(JNIEnv* env) {
diff --git a/chromium/content/browser/android/child_process_launcher_android.h b/chromium/content/browser/android/child_process_launcher_android.h
index 747649fc7ac..d1de985a8f9 100644
--- a/chromium/content/browser/android/child_process_launcher_android.h
+++ b/chromium/content/browser/android/child_process_launcher_android.h
@@ -11,6 +11,7 @@
#include "base/command_line.h"
#include "base/process/process.h"
#include "content/public/browser/file_descriptor_info.h"
+#include "ui/gl/android/scoped_java_surface.h"
namespace content {
@@ -19,11 +20,10 @@ typedef base::Callback<void(base::ProcessHandle)> StartChildProcessCallback;
// ActivityManager.
// The created process handle is returned to the |callback| on success, 0 is
// retuned if the process could not be created.
-void StartChildProcess(
- const base::CommandLine::StringVector& argv,
- int child_process_id,
- const std::vector<FileDescriptorInfo>& files_to_register,
- const StartChildProcessCallback& callback);
+void StartChildProcess(const base::CommandLine::StringVector& argv,
+ int child_process_id,
+ const scoped_ptr<FileDescriptorInfo> files_to_register,
+ const StartChildProcessCallback& callback);
// Stops a child process based on the handle returned form
// StartChildProcess.
@@ -38,12 +38,14 @@ void RegisterViewSurface(int surface_id, jobject j_surface);
void UnregisterViewSurface(int surface_id);
-void RegisterChildProcessSurfaceTexture(int surface_texture_id,
- int child_process_id,
- jobject j_surface_texture);
+void CreateSurfaceTextureSurface(int surface_texture_id,
+ int client_id,
+ gfx::SurfaceTexture* surface_texture);
-void UnregisterChildProcessSurfaceTexture(int surface_texture_id,
- int child_process_id);
+void DestroySurfaceTextureSurface(int surface_texture_id, int client_id);
+
+gfx::ScopedJavaSurface GetSurfaceTextureSurface(int surface_texture_id,
+ int client_id);
bool RegisterChildProcessLauncher(JNIEnv* env);
diff --git a/chromium/content/browser/android/composited_touch_handle_drawable.cc b/chromium/content/browser/android/composited_touch_handle_drawable.cc
new file mode 100644
index 00000000000..aa7c71920c1
--- /dev/null
+++ b/chromium/content/browser/android/composited_touch_handle_drawable.cc
@@ -0,0 +1,165 @@
+// 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/android/composited_touch_handle_drawable.h"
+
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "cc/layers/ui_resource_layer.h"
+#include "jni/HandleViewResources_jni.h"
+#include "ui/gfx/android/java_bitmap.h"
+
+namespace content {
+
+namespace {
+
+static SkBitmap CreateSkBitmapFromJavaBitmap(
+ base::android::ScopedJavaLocalRef<jobject> jbitmap) {
+ return jbitmap.is_null()
+ ? SkBitmap()
+ : CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(jbitmap.obj()));
+}
+
+class HandleResources {
+ public:
+ HandleResources() : loaded_(false) {
+ }
+
+ void LoadIfNecessary(jobject context) {
+ if (loaded_)
+ return;
+
+ loaded_ = true;
+
+ TRACE_EVENT0("browser", "HandleResources::Create");
+ JNIEnv* env = base::android::AttachCurrentThread();
+ if (!context)
+ context = base::android::GetApplicationContext();
+
+ left_bitmap_ = CreateSkBitmapFromJavaBitmap(
+ Java_HandleViewResources_getLeftHandleBitmap(env, context));
+ right_bitmap_ = CreateSkBitmapFromJavaBitmap(
+ Java_HandleViewResources_getRightHandleBitmap(env, context));
+ center_bitmap_ = CreateSkBitmapFromJavaBitmap(
+ Java_HandleViewResources_getCenterHandleBitmap(env, context));
+
+ left_bitmap_.setImmutable();
+ right_bitmap_.setImmutable();
+ center_bitmap_.setImmutable();
+ }
+
+ const SkBitmap& GetBitmap(TouchHandleOrientation orientation) {
+ DCHECK(loaded_);
+ switch (orientation) {
+ case TOUCH_HANDLE_LEFT:
+ return left_bitmap_;
+ case TOUCH_HANDLE_RIGHT:
+ return right_bitmap_;
+ case TOUCH_HANDLE_CENTER:
+ return center_bitmap_;
+ case TOUCH_HANDLE_ORIENTATION_UNDEFINED:
+ NOTREACHED() << "Invalid touch handle orientation.";
+ };
+ return center_bitmap_;
+ }
+
+ private:
+ SkBitmap left_bitmap_;
+ SkBitmap right_bitmap_;
+ SkBitmap center_bitmap_;
+ bool loaded_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandleResources);
+};
+
+base::LazyInstance<HandleResources>::Leaky g_selection_resources;
+
+} // namespace
+
+CompositedTouchHandleDrawable::CompositedTouchHandleDrawable(
+ cc::Layer* root_layer,
+ float dpi_scale,
+ jobject context)
+ : dpi_scale_(dpi_scale),
+ orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
+ layer_(cc::UIResourceLayer::Create()) {
+ g_selection_resources.Get().LoadIfNecessary(context);
+ DCHECK(root_layer);
+ root_layer->AddChild(layer_.get());
+}
+
+CompositedTouchHandleDrawable::~CompositedTouchHandleDrawable() {
+ Detach();
+}
+
+void CompositedTouchHandleDrawable::SetEnabled(bool enabled) {
+ layer_->SetIsDrawable(enabled);
+}
+
+void CompositedTouchHandleDrawable::SetOrientation(
+ TouchHandleOrientation orientation) {
+ DCHECK(layer_->parent());
+ orientation_ = orientation;
+
+ const SkBitmap& bitmap = g_selection_resources.Get().GetBitmap(orientation);
+ layer_->SetBitmap(bitmap);
+ layer_->SetBounds(gfx::Size(bitmap.width(), bitmap.height()));
+
+ switch (orientation_) {
+ case TOUCH_HANDLE_LEFT:
+ focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.75f, 0);
+ break;
+ case TOUCH_HANDLE_RIGHT:
+ focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.25f, 0);
+ break;
+ case TOUCH_HANDLE_CENTER:
+ focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.5f, 0);
+ break;
+ case TOUCH_HANDLE_ORIENTATION_UNDEFINED:
+ NOTREACHED() << "Invalid touch handle orientation.";
+ break;
+ };
+
+ layer_->SetPosition(focal_position_ - focal_offset_from_origin_);
+}
+
+void CompositedTouchHandleDrawable::SetAlpha(float alpha) {
+ DCHECK(layer_->parent());
+ layer_->SetOpacity(std::max(0.f, std::min(1.f, alpha)));
+}
+
+void CompositedTouchHandleDrawable::SetFocus(const gfx::PointF& position) {
+ DCHECK(layer_->parent());
+ focal_position_ = gfx::ScalePoint(position, dpi_scale_);
+ layer_->SetPosition(focal_position_ - focal_offset_from_origin_);
+}
+
+void CompositedTouchHandleDrawable::SetVisible(bool visible) {
+ DCHECK(layer_->parent());
+ layer_->SetHideLayerAndSubtree(!visible);
+}
+
+bool CompositedTouchHandleDrawable::IntersectsWith(
+ const gfx::RectF& rect) const {
+ return BoundingRect().Intersects(gfx::ScaleRect(rect, dpi_scale_));
+}
+
+void CompositedTouchHandleDrawable::Detach() {
+ layer_->RemoveFromParent();
+}
+
+gfx::RectF CompositedTouchHandleDrawable::BoundingRect() const {
+ return gfx::RectF(layer_->position().x(),
+ layer_->position().y(),
+ layer_->bounds().width(),
+ layer_->bounds().height());
+}
+
+// static
+bool CompositedTouchHandleDrawable::RegisterHandleViewResources(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/composited_touch_handle_drawable.h b/chromium/content/browser/android/composited_touch_handle_drawable.h
new file mode 100644
index 00000000000..c4f5f45b2a1
--- /dev/null
+++ b/chromium/content/browser/android/composited_touch_handle_drawable.h
@@ -0,0 +1,48 @@
+// 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_ANDROID_COMPOSITED_TOUCH_HANDLE_DRAWABLE_H_
+#define CONTENT_BROWSER_ANDROID_COMPOSITED_TOUCH_HANDLE_DRAWABLE_H_
+
+#include "content/browser/renderer_host/input/touch_handle.h"
+
+#include "base/android/jni_android.h"
+#include "cc/layers/ui_resource_layer.h"
+
+namespace content {
+
+// Touch handle drawable implementation backed by a cc layer.
+class CompositedTouchHandleDrawable : public TouchHandleDrawable {
+ public:
+ CompositedTouchHandleDrawable(cc::Layer* root_layer,
+ float dpi_scale,
+ jobject context);
+ virtual ~CompositedTouchHandleDrawable();
+
+ // TouchHandleDrawable implementation.
+ virtual void SetEnabled(bool enabled) override;
+ virtual void SetOrientation(TouchHandleOrientation orientation) override;
+ virtual void SetAlpha(float alpha) override;
+ virtual void SetFocus(const gfx::PointF& position) override;
+ virtual void SetVisible(bool visible) override;
+ virtual bool IntersectsWith(const gfx::RectF& rect) const override;
+
+ static bool RegisterHandleViewResources(JNIEnv* env);
+
+ private:
+ void Detach();
+ gfx::RectF BoundingRect() const;
+
+ const float dpi_scale_;
+ TouchHandleOrientation orientation_;
+ gfx::PointF focal_position_;
+ gfx::Vector2dF focal_offset_from_origin_;
+ scoped_refptr<cc::UIResourceLayer> layer_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompositedTouchHandleDrawable);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_COMPOSITED_TOUCH_HANDLE_DRAWABLE_H_
diff --git a/chromium/content/browser/android/content_readback_handler.cc b/chromium/content/browser/android/content_readback_handler.cc
index 841ef5f051a..414bf0abe67 100644
--- a/chromium/content/browser/android/content_readback_handler.cc
+++ b/chromium/content/browser/android/content_readback_handler.cc
@@ -31,7 +31,7 @@ void OnFinishCopyOutputRequest(
}
scoped_ptr<SkBitmap> bitmap = copy_output_result->TakeBitmap();
- result_callback.Run(true, *bitmap.Pass());
+ result_callback.Run(true, *bitmap);
}
} // anonymous namespace
@@ -54,7 +54,7 @@ void ContentReadbackHandler::GetContentBitmap(JNIEnv* env,
jobject obj,
jint readback_id,
jfloat scale,
- jobject config,
+ jobject color_type,
jfloat x,
jfloat y,
jfloat width,
@@ -69,8 +69,9 @@ void ContentReadbackHandler::GetContentBitmap(JNIEnv* env,
weak_factory_.GetWeakPtr(),
readback_id);
+ SkColorType sk_color_type = gfx::ConvertToSkiaColorType(color_type);
view->GetScaledContentBitmap(
- scale, config, gfx::Rect(x, y, width, height), result_callback);
+ scale, sk_color_type, gfx::Rect(x, y, width, height), result_callback);
}
void ContentReadbackHandler::GetCompositorBitmap(JNIEnv* env,
@@ -112,7 +113,7 @@ void ContentReadbackHandler::OnFinishReadback(int readback_id,
java_bitmap = gfx::ConvertToJavaBitmap(&bitmap);
Java_ContentReadbackHandler_notifyGetBitmapFinished(
- env, java_obj_.obj(), readback_id, success, java_bitmap.obj());
+ env, java_obj_.obj(), readback_id, java_bitmap.obj());
}
// static
diff --git a/chromium/content/browser/android/content_settings.cc b/chromium/content/browser/android/content_settings.cc
index a83169c2ce9..2d32143807a 100644
--- a/chromium/content/browser/android/content_settings.cc
+++ b/chromium/content/browser/android/content_settings.cc
@@ -9,8 +9,8 @@
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/web_preferences.h"
#include "jni/ContentSettings_jni.h"
-#include "webkit/common/webpreferences.h"
namespace content {
@@ -39,7 +39,7 @@ bool ContentSettings::GetJavaScriptEnabled(JNIEnv* env, jobject obj) {
RenderViewHost* render_view_host = web_contents()->GetRenderViewHost();
if (!render_view_host)
return false;
- return render_view_host->GetDelegate()->GetWebkitPrefs().javascript_enabled;
+ return render_view_host->GetWebkitPreferences().javascript_enabled;
}
void ContentSettings::WebContentsDestroyed() {
diff --git a/chromium/content/browser/android/content_settings.h b/chromium/content/browser/android/content_settings.h
index 0728a6afabb..79dd1da4d38 100644
--- a/chromium/content/browser/android/content_settings.h
+++ b/chromium/content/browser/android/content_settings.h
@@ -26,7 +26,7 @@ class ContentSettings : public WebContentsObserver {
virtual ~ContentSettings();
// WebContentsObserver overrides:
- virtual void WebContentsDestroyed() OVERRIDE;
+ virtual void WebContentsDestroyed() override;
// The Java counterpart to this class.
JavaObjectWeakGlobalRef content_settings_;
diff --git a/chromium/content/browser/android/content_startup_flags.cc b/chromium/content/browser/android/content_startup_flags.cc
index a771daa8170..d531dbb65a6 100644
--- a/chromium/content/browser/android/content_startup_flags.cc
+++ b/chromium/content/browser/android/content_startup_flags.cc
@@ -18,7 +18,7 @@
namespace content {
-void SetContentCommandLineFlags(int max_render_process_count,
+void SetContentCommandLineFlags(bool single_process,
const std::string& plugin_descriptor) {
// May be called multiple times, to cover all possible program entry points.
static bool already_initialized = false;
@@ -26,7 +26,8 @@ void SetContentCommandLineFlags(int max_render_process_count,
return;
already_initialized = true;
- CommandLine* parsed_command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* parsed_command_line =
+ base::CommandLine::ForCurrentProcess();
int command_line_renderer_limit = -1;
if (parsed_command_line->HasSwitch(switches::kRendererProcessLimit)) {
@@ -34,9 +35,7 @@ void SetContentCommandLineFlags(int max_render_process_count,
switches::kRendererProcessLimit);
int value;
if (base::StringToInt(limit, &value)) {
- command_line_renderer_limit = value;
- if (value <= 0)
- max_render_process_count = 0;
+ command_line_renderer_limit = std::max(0, value);
}
}
@@ -44,29 +43,22 @@ void SetContentCommandLineFlags(int max_render_process_count,
int limit = std::min(command_line_renderer_limit,
static_cast<int>(kMaxRendererProcessCount));
RenderProcessHost::SetMaxRendererProcessCount(limit);
- } else if (max_render_process_count <= 0) {
+ }
+
+ if (single_process || command_line_renderer_limit == 0) {
// Need to ensure the command line flag is consistent as a lot of chrome
// internal code checks this directly, but it wouldn't normally get set when
// we are implementing an embedded WebView.
parsed_command_line->AppendSwitch(switches::kSingleProcess);
- } else {
- int default_maximum = RenderProcessHost::GetMaxRendererProcessCount();
- DCHECK(default_maximum <= static_cast<int>(kMaxRendererProcessCount));
- if (max_render_process_count < default_maximum)
- RenderProcessHost::SetMaxRendererProcessCount(max_render_process_count);
}
- parsed_command_line->AppendSwitch(switches::kEnableThreadedCompositing);
- parsed_command_line->AppendSwitch(
- switches::kEnableCompositingForFixedPosition);
- parsed_command_line->AppendSwitch(switches::kEnableAcceleratedOverflowScroll);
parsed_command_line->AppendSwitch(switches::kEnableBeginFrameScheduling);
- parsed_command_line->AppendSwitch(switches::kEnableGestureTapHighlight);
parsed_command_line->AppendSwitch(switches::kEnablePinch);
parsed_command_line->AppendSwitch(switches::kEnableOverlayFullscreenVideo);
parsed_command_line->AppendSwitch(switches::kEnableOverlayScrollbar);
parsed_command_line->AppendSwitch(switches::kEnableOverscrollNotifications);
+ parsed_command_line->AppendSwitch(switches::kValidateInputEventStream);
// Run the GPU service as a thread in the browser instead of as a
// standalone process.
diff --git a/chromium/content/browser/android/content_startup_flags.h b/chromium/content/browser/android/content_startup_flags.h
index 836ea3c1206..8f55a0c2cf4 100644
--- a/chromium/content/browser/android/content_startup_flags.h
+++ b/chromium/content/browser/android/content_startup_flags.h
@@ -12,7 +12,7 @@ namespace content {
// Force-appends flags to the command line turning on Android-specific
// features owned by Content. This is called as soon as possible during
// initialization to make sure code sees the new flags.
-void SetContentCommandLineFlags(int max_render_process_count,
+void SetContentCommandLineFlags(bool single_process,
const std::string& plugin_descriptor);
} // namespace content
diff --git a/chromium/content/browser/android/content_video_view.cc b/chromium/content/browser/android/content_video_view.cc
index 5407032441b..68b0b5f0cad 100644
--- a/chromium/content/browser/android/content_video_view.cc
+++ b/chromium/content/browser/android/content_video_view.cc
@@ -7,16 +7,20 @@
#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"
using base::android::AttachCurrentThread;
using base::android::CheckException;
using base::android::ScopedJavaGlobalRef;
+using base::UserMetricsAction;
+using content::RecordAction;
namespace content {
@@ -49,7 +53,6 @@ ContentVideoView::ContentVideoView(
DCHECK(!g_content_video_view);
j_content_video_view_ = CreateJavaObject();
g_content_video_view = this;
- CreatePowerSaveBlocker();
}
ContentVideoView::~ContentVideoView() {
@@ -68,7 +71,6 @@ void ContentVideoView::OpenVideo() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
if (!content_video_view.is_null()) {
- CreatePowerSaveBlocker();
Java_ContentVideoView_openVideo(env, content_video_view.obj());
}
}
@@ -77,7 +79,6 @@ void ContentVideoView::OnMediaPlayerError(int error_type) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
if (!content_video_view.is_null()) {
- power_save_blocker_.reset();
Java_ContentVideoView_onMediaPlayerError(env, content_video_view.obj(),
error_type);
}
@@ -105,7 +106,6 @@ void ContentVideoView::OnPlaybackComplete() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
if (!content_video_view.is_null()) {
- power_save_blocker_.reset();
Java_ContentVideoView_onPlaybackComplete(env, content_video_view.obj());
}
}
@@ -117,6 +117,40 @@ void ContentVideoView::OnExitFullscreen() {
Java_ContentVideoView_onExitFullscreen(env, content_video_view.obj());
}
+void ContentVideoView::RecordFullscreenPlayback(
+ JNIEnv*, jobject, bool is_portrait_video, bool is_orientation_portrait) {
+ UMA_HISTOGRAM_BOOLEAN("MobileFullscreenVideo.OrientationPortrait",
+ is_orientation_portrait);
+ UMA_HISTOGRAM_BOOLEAN("MobileFullscreenVideo.VideoPortrait",
+ is_portrait_video);
+}
+
+void ContentVideoView::RecordExitFullscreenPlayback(
+ JNIEnv*, jobject, bool is_portrait_video,
+ long playback_duration_in_milliseconds_before_orientation_change,
+ long playback_duration_in_milliseconds_after_orientation_change) {
+ bool orientation_changed = (
+ playback_duration_in_milliseconds_after_orientation_change != 0);
+ if (is_portrait_video) {
+ UMA_HISTOGRAM_COUNTS(
+ "MobileFullscreenVideo.PortraitDuration",
+ playback_duration_in_milliseconds_before_orientation_change);
+ UMA_HISTOGRAM_COUNTS(
+ "MobileFullscreenVideo.PortraitRotation", orientation_changed);
+ if (orientation_changed) {
+ UMA_HISTOGRAM_COUNTS(
+ "MobileFullscreenVideo.DurationAfterPotraitRotation",
+ playback_duration_in_milliseconds_after_orientation_change);
+ }
+ } else {
+ UMA_HISTOGRAM_COUNTS(
+ "MobileFullscreenVideo.LandscapeDuration",
+ playback_duration_in_milliseconds_before_orientation_change);
+ UMA_HISTOGRAM_COUNTS(
+ "MobileFullscreenVideo.LandscapeRotation", orientation_changed);
+ }
+}
+
void ContentVideoView::UpdateMediaMetadata() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
@@ -163,18 +197,15 @@ void ContentVideoView::SeekTo(JNIEnv*, jobject obj, jint msec) {
}
void ContentVideoView::Play(JNIEnv*, jobject obj) {
- CreatePowerSaveBlocker();
manager_->FullscreenPlayerPlay();
}
void ContentVideoView::Pause(JNIEnv*, jobject obj) {
- power_save_blocker_.reset();
manager_->FullscreenPlayerPause();
}
void ContentVideoView::ExitFullscreen(
JNIEnv*, jobject, jboolean release_media_player) {
- power_save_blocker_.reset();
j_content_video_view_.reset();
manager_->ExitFullscreen(release_media_player);
}
@@ -196,45 +227,14 @@ ScopedJavaLocalRef<jobject> ContentVideoView::GetJavaObject(JNIEnv* env) {
return j_content_video_view_.get(env);
}
-gfx::NativeView ContentVideoView::GetNativeView() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> content_video_view = GetJavaObject(env);
- if (content_video_view.is_null())
- return NULL;
-
- return reinterpret_cast<gfx::NativeView>(
- Java_ContentVideoView_getNativeViewAndroid(env,
- content_video_view.obj()));
-
-}
-
JavaObjectWeakGlobalRef ContentVideoView::CreateJavaObject() {
ContentViewCoreImpl* content_view_core = manager_->GetContentViewCore();
JNIEnv* env = AttachCurrentThread();
- bool legacyMode = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOverlayFullscreenVideoSubtitle);
return JavaObjectWeakGlobalRef(
env,
Java_ContentVideoView_createContentVideoView(
env,
- content_view_core->GetContext().obj(),
- reinterpret_cast<intptr_t>(this),
- content_view_core->GetContentVideoViewClient().obj(),
- legacyMode).obj());
-}
-
-void ContentVideoView::CreatePowerSaveBlocker() {
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOverlayFullscreenVideoSubtitle)) {
- return;
- }
-
- if (power_save_blocker_) return;
-
- power_save_blocker_ = PowerSaveBlocker::Create(
- PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
- "Playing video").Pass();
- static_cast<PowerSaveBlockerImpl*>(power_save_blocker_.get())->
- InitDisplaySleepBlocker(GetNativeView());
+ content_view_core->GetJavaObject().obj(),
+ reinterpret_cast<intptr_t>(this)).obj());
}
} // namespace content
diff --git a/chromium/content/browser/android/content_video_view.h b/chromium/content/browser/android/content_video_view.h
index faea292b5f0..7946792cf29 100644
--- a/chromium/content/browser/android/content_video_view.h
+++ b/chromium/content/browser/android/content_video_view.h
@@ -13,13 +13,11 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
#include "ui/gfx/native_widget_types.h"
namespace content {
class BrowserMediaPlayerManager;
-class PowerSaveBlocker;
// Native mirror of ContentVideoView.java. This class is responsible for
// creating the Java video view and pass all the player status change to
@@ -72,6 +70,14 @@ class ContentVideoView {
void OnPlaybackComplete();
void OnExitFullscreen();
+ // Functions called to record fullscreen playback UMA metrics.
+ void RecordFullscreenPlayback(
+ JNIEnv*, jobject, bool is_portrait_video, bool is_orientation_portrait);
+ void RecordExitFullscreenPlayback(
+ JNIEnv*, jobject, bool is_portrait_video,
+ 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);
@@ -79,23 +85,10 @@ class ContentVideoView {
// Creates the corresponding ContentVideoView Java object.
JavaObjectWeakGlobalRef CreateJavaObject();
- // Returns the associated NativeView
- gfx::NativeView GetNativeView();
-
- void CreatePowerSaveBlocker();
-
// Object that manages the fullscreen media player. It is responsible for
// handling all the playback controls.
BrowserMediaPlayerManager* manager_;
- // PowerSaveBlock to keep screen on for fullscreen video.
- // There is already blocker when inline video started, and it requires the
- // ContentView's container displayed to take effect; but in WebView, apps
- // could use another container to hold ContentVideoView, and the blocker in
- // ContentView's container can not keep screen on; so we need another blocker
- // here, it is no harm, just an additonal blocker.
- scoped_ptr<PowerSaveBlocker> power_save_blocker_;
-
// Weak reference of corresponding Java object.
JavaObjectWeakGlobalRef j_content_video_view_;
diff --git a/chromium/content/browser/android/content_view_core_impl.cc b/chromium/content/browser/android/content_view_core_impl.cc
index fc0af4c922b..12117bf5dfb 100644
--- a/chromium/content/browser/android/content_view_core_impl.cc
+++ b/chromium/content/browser/android/content_view_core_impl.cc
@@ -9,7 +9,6 @@
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/command_line.h"
-#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
@@ -17,42 +16,40 @@
#include "cc/layers/layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/output/begin_frame_args.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"
+#include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
#include "content/browser/android/load_url_params.h"
+#include "content/browser/android/popup_touch_handle_drawable.h"
#include "content/browser/frame_host/interstitial_page_impl.h"
-#include "content/browser/frame_host/navigation_controller_impl.h"
-#include "content/browser/frame_host/navigation_entry_impl.h"
-#include "content/browser/geolocation/geolocation_dispatcher_host.h"
+#include "content/browser/geolocation/geolocation_service_context.h"
#include "content/browser/media/media_web_contents_observer.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/browser/renderer_host/input/motion_event_android.h"
#include "content/browser/renderer_host/input/web_input_event_builders_android.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
-#include "content/browser/renderer_host/java/java_bound_object.h"
-#include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
-#include "content/browser/screen_orientation/screen_orientation_dispatcher_host.h"
-#include "content/browser/ssl/ssl_host_state.h"
+#include "content/browser/transition_request_manager.h"
#include "content/browser/web_contents/web_contents_view_android.h"
#include "content/common/frame_messages.h"
#include "content/common/input/web_input_event_traits.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
-#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/screen_orientation_dispatcher_host.h"
+#include "content/public/browser/ssl_host_state_delegate.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/menu_item.h"
-#include "content/public/common/page_transition_types.h"
#include "content/public/common/user_agent.h"
#include "jni/ContentViewCore_jni.h"
-#include "third_party/WebKit/public/web/WebBindings.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/base/android/view_android.h"
#include "ui/base/android/window_android.h"
@@ -66,7 +63,6 @@ using base::android::ConvertJavaStringToUTF16;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
-using base::android::ScopedJavaGlobalRef;
using base::android::ScopedJavaLocalRef;
using blink::WebGestureEvent;
using blink::WebInputEvent;
@@ -74,10 +70,17 @@ using blink::WebInputEvent;
// Describes the type and enabled state of a select popup item.
namespace {
-enum {
-#define DEFINE_POPUP_ITEM_TYPE(name, value) POPUP_ITEM_TYPE_##name = value,
-#include "content/browser/android/popup_item_type_list.h"
-#undef DEFINE_POPUP_ITEM_TYPE
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content.browser.input
+enum PopupItemType {
+ // Popup item is of type group
+ POPUP_ITEM_TYPE_GROUP,
+
+ // Popup item is disabled
+ POPUP_ITEM_TYPE_DISABLED,
+
+ // Popup item is enabled
+ POPUP_ITEM_TYPE_ENABLED,
};
} //namespace
@@ -112,37 +115,37 @@ ScopedJavaLocalRef<jobject> CreateJavaRect(
int ToGestureEventType(WebInputEvent::Type type) {
switch (type) {
case WebInputEvent::GestureScrollBegin:
- return SCROLL_START;
+ return GESTURE_EVENT_TYPE_SCROLL_START;
case WebInputEvent::GestureScrollEnd:
- return SCROLL_END;
+ return GESTURE_EVENT_TYPE_SCROLL_END;
case WebInputEvent::GestureScrollUpdate:
- return SCROLL_BY;
+ return GESTURE_EVENT_TYPE_SCROLL_BY;
case WebInputEvent::GestureFlingStart:
- return FLING_START;
+ return GESTURE_EVENT_TYPE_FLING_START;
case WebInputEvent::GestureFlingCancel:
- return FLING_CANCEL;
+ return GESTURE_EVENT_TYPE_FLING_CANCEL;
case WebInputEvent::GestureShowPress:
- return SHOW_PRESS;
+ return GESTURE_EVENT_TYPE_SHOW_PRESS;
case WebInputEvent::GestureTap:
- return SINGLE_TAP_CONFIRMED;
+ return GESTURE_EVENT_TYPE_SINGLE_TAP_CONFIRMED;
case WebInputEvent::GestureTapUnconfirmed:
- return SINGLE_TAP_UNCONFIRMED;
+ return GESTURE_EVENT_TYPE_SINGLE_TAP_UNCONFIRMED;
case WebInputEvent::GestureTapDown:
- return TAP_DOWN;
+ return GESTURE_EVENT_TYPE_TAP_DOWN;
case WebInputEvent::GestureTapCancel:
- return TAP_CANCEL;
+ return GESTURE_EVENT_TYPE_TAP_CANCEL;
case WebInputEvent::GestureDoubleTap:
- return DOUBLE_TAP;
+ return GESTURE_EVENT_TYPE_DOUBLE_TAP;
case WebInputEvent::GestureLongPress:
- return LONG_PRESS;
+ return GESTURE_EVENT_TYPE_LONG_PRESS;
case WebInputEvent::GestureLongTap:
- return LONG_TAP;
+ return GESTURE_EVENT_TYPE_LONG_TAP;
case WebInputEvent::GesturePinchBegin:
- return PINCH_BEGIN;
+ return GESTURE_EVENT_TYPE_PINCH_BEGIN;
case WebInputEvent::GesturePinchEnd:
- return PINCH_END;
+ return GESTURE_EVENT_TYPE_PINCH_END;
case WebInputEvent::GesturePinchUpdate:
- return PINCH_BY;
+ return GESTURE_EVENT_TYPE_PINCH_BY;
case WebInputEvent::GestureTwoFingerTap:
case WebInputEvent::GestureScrollUpdateWithoutPropagation:
default:
@@ -190,7 +193,7 @@ class ContentViewCoreImpl::ContentViewUserData
ContentViewCoreImpl* ContentViewCoreImpl::FromWebContents(
content::WebContents* web_contents) {
ContentViewCoreImpl::ContentViewUserData* data =
- reinterpret_cast<ContentViewCoreImpl::ContentViewUserData*>(
+ static_cast<ContentViewCoreImpl::ContentViewUserData*>(
web_contents->GetUserData(kContentViewUserDataKey));
return data ? data->get() : NULL;
}
@@ -226,6 +229,8 @@ ContentViewCoreImpl::ContentViewCoreImpl(
accessibility_enabled_(false) {
CHECK(web_contents) <<
"A ContentViewCoreImpl should be created with a valid WebContents.";
+ DCHECK(view_android_);
+ DCHECK(window_android_);
root_layer_->SetBackgroundColor(GetBackgroundColor(env, obj));
gfx::Size physical_size(
@@ -244,9 +249,9 @@ ContentViewCoreImpl::ContentViewCoreImpl(
BuildUserAgentFromOSAndProduct(kLinuxInfoStr, product);
web_contents->SetUserAgentOverride(spoofed_ua);
- java_bridge_dispatcher_host_manager_.reset(
- new JavaBridgeDispatcherHostManager(web_contents,
- java_bridge_retained_object_set));
+ java_bridge_dispatcher_host_.reset(
+ new GinJavaBridgeDispatcherHost(web_contents,
+ java_bridge_retained_object_set));
InitWebContents();
}
@@ -270,6 +275,15 @@ void ContentViewCoreImpl::OnJavaContentViewCoreDestroyed(JNIEnv* env,
jobject obj) {
DCHECK(env->IsSameObject(java_ref_.get(env).obj(), obj));
java_ref_.reset();
+ // Java peer has gone, ContentViewCore is not functional and waits to
+ // be destroyed with WebContents.
+ // We need to reset WebContentsViewAndroid's reference, otherwise, there
+ // could have call in when swapping the WebContents,
+ // see http://crbug.com/383939 .
+ DCHECK(web_contents_);
+ static_cast<WebContentsViewAndroid*>(
+ static_cast<WebContentsImpl*>(web_contents_)->GetView())->
+ SetContentViewCore(NULL);
}
void ContentViewCoreImpl::InitWebContents() {
@@ -348,32 +362,11 @@ jint ContentViewCoreImpl::GetBackgroundColor(JNIEnv* env, jobject obj) {
return rwhva->GetCachedBackgroundColor();
}
-void ContentViewCoreImpl::OnHide(JNIEnv* env, jobject obj) {
- Hide();
-}
-
-void ContentViewCoreImpl::OnShow(JNIEnv* env, jobject obj) {
- Show();
-}
-
-void ContentViewCoreImpl::Show() {
- GetWebContents()->WasShown();
-}
-
-void ContentViewCoreImpl::Hide() {
- GetWebContents()->WasHidden();
- PauseVideo();
-}
-
-void ContentViewCoreImpl::PauseVideo() {
- RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
- web_contents_->GetRenderViewHost());
- if (rvhi)
- rvhi->media_web_contents_observer()->PauseVideo();
-}
-
void ContentViewCoreImpl::PauseOrResumeGeolocation(bool should_pause) {
- web_contents_->geolocation_dispatcher_host()->PauseOrResume(should_pause);
+ if (should_pause)
+ web_contents_->GetGeolocationServiceContext()->PauseUpdates();
+ else
+ web_contents_->GetGeolocationServiceContext()->ResumeUpdates();
}
// All positions and sizes are in CSS pixels.
@@ -386,17 +379,14 @@ void ContentViewCoreImpl::UpdateFrameInfo(
const gfx::SizeF& content_size,
const gfx::SizeF& viewport_size,
const gfx::Vector2dF& controls_offset,
- const gfx::Vector2dF& content_offset,
- float overdraw_bottom_height) {
+ const gfx::Vector2dF& content_offset) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
- if (window_android_) {
- window_android_->set_content_offset(
- gfx::ScaleVector2d(content_offset, dpi_scale_));
- }
+ window_android_->set_content_offset(
+ gfx::ScaleVector2d(content_offset, dpi_scale_));
Java_ContentViewCore_updateFrameInfo(
env, obj.obj(),
@@ -410,8 +400,7 @@ void ContentViewCoreImpl::UpdateFrameInfo(
viewport_size.width(),
viewport_size.height(),
controls_offset.y(),
- content_offset.y(),
- overdraw_bottom_height);
+ content_offset.y());
}
void ContentViewCoreImpl::SetTitle(const base::string16& title) {
@@ -434,8 +423,12 @@ void ContentViewCoreImpl::OnBackgroundColorChanged(SkColor color) {
Java_ContentViewCore_onBackgroundColorChanged(env, obj.obj(), color);
}
-void ContentViewCoreImpl::ShowSelectPopupMenu(const gfx::Rect& bounds,
- const std::vector<MenuItem>& items, int selected_item, bool multiple) {
+void ContentViewCoreImpl::ShowSelectPopupMenu(
+ RenderFrameHost* frame,
+ const gfx::Rect& bounds,
+ const std::vector<MenuItem>& items,
+ int selected_item,
+ bool multiple) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
@@ -479,7 +472,9 @@ void ContentViewCoreImpl::ShowSelectPopupMenu(const gfx::Rect& bounds,
}
ScopedJavaLocalRef<jobjectArray> items_array(
base::android::ToJavaArrayOfStrings(env, labels));
- Java_ContentViewCore_showSelectPopup(env, j_obj.obj(),
+ Java_ContentViewCore_showSelectPopup(env,
+ j_obj.obj(),
+ reinterpret_cast<intptr_t>(frame),
bounds_rect.obj(),
items_array.obj(),
enabled_array.obj(),
@@ -549,9 +544,6 @@ void ContentViewCoreImpl::OnGestureEventAck(const blink::WebGestureEvent& event,
event.x * dpi_scale(),
event.y * dpi_scale());
break;
- case WebInputEvent::GestureDoubleTap:
- Java_ContentViewCore_onDoubleTapEventAck(env, j_obj.obj());
- break;
default:
break;
}
@@ -598,37 +590,48 @@ void ContentViewCoreImpl::OnSelectionChanged(const std::string& text) {
Java_ContentViewCore_onSelectionChanged(env, obj.obj(), jtext.obj());
}
-void ContentViewCoreImpl::OnSelectionBoundsChanged(
- const ViewHostMsg_SelectionBounds_Params& params) {
+void ContentViewCoreImpl::OnSelectionEvent(SelectionEventType event,
+ const gfx::PointF& position) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
+ ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
+ if (j_obj.is_null())
return;
- ScopedJavaLocalRef<jobject> anchor_rect_dip(
- CreateJavaRect(env, params.anchor_rect));
- ScopedJavaLocalRef<jobject> focus_rect_dip(
- CreateJavaRect(env, params.focus_rect));
- Java_ContentViewCore_onSelectionBoundsChanged(env, obj.obj(),
- anchor_rect_dip.obj(),
- params.anchor_dir,
- focus_rect_dip.obj(),
- params.focus_dir,
- params.is_anchor_first);
+ Java_ContentViewCore_onSelectionEvent(
+ env, j_obj.obj(), event, position.x(), position.y());
+}
+
+scoped_ptr<TouchHandleDrawable>
+ContentViewCoreImpl::CreatePopupTouchHandleDrawable() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null()) {
+ NOTREACHED();
+ return scoped_ptr<TouchHandleDrawable>();
+ }
+ return scoped_ptr<TouchHandleDrawable>(new PopupTouchHandleDrawable(
+ Java_ContentViewCore_createPopupTouchHandleDrawable(env, obj.obj()),
+ dpi_scale_));
}
void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
+ RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
+ if (!view)
+ return;
+
+ view->OnShowingPastePopup(gfx::PointF(x_dip, y_dip));
+
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
- Java_ContentViewCore_showPastePopup(env, obj.obj(),
- static_cast<jint>(x_dip),
- static_cast<jint>(y_dip));
+ Java_ContentViewCore_showPastePopupWithFeedback(env, obj.obj(),
+ static_cast<jint>(x_dip),
+ static_cast<jint>(y_dip));
}
void ContentViewCoreImpl::GetScaledContentBitmap(
float scale,
- jobject jbitmap_config,
+ SkColorType color_type,
gfx::Rect src_subrect,
const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
@@ -636,8 +639,8 @@ void ContentViewCoreImpl::GetScaledContentBitmap(
result_callback.Run(false, SkBitmap());
return;
}
- SkBitmap::Config skbitmap_format = gfx::ConvertToSkiaConfig(jbitmap_config);
- view->GetScaledContentBitmap(scale, skbitmap_format, src_subrect,
+
+ view->GetScaledContentBitmap(scale, color_type, src_subrect,
result_callback);
}
@@ -654,7 +657,7 @@ void ContentViewCoreImpl::StartContentIntent(const GURL& content_url) {
}
void ContentViewCoreImpl::ShowDisambiguationPopup(
- const gfx::Rect& target_rect,
+ const gfx::Rect& rect_pixels,
const SkBitmap& zoomed_bitmap) {
JNIEnv* env = AttachCurrentThread();
@@ -662,7 +665,7 @@ void ContentViewCoreImpl::ShowDisambiguationPopup(
if (obj.is_null())
return;
- ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, target_rect));
+ ScopedJavaLocalRef<jobject> rect_object(CreateJavaRect(env, rect_pixels));
ScopedJavaLocalRef<jobject> java_bitmap =
gfx::ConvertToJavaBitmap(&zoomed_bitmap);
@@ -683,26 +686,6 @@ ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateTouchEventSynthesizer() {
return Java_ContentViewCore_createTouchEventSynthesizer(env, obj.obj());
}
-ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContentVideoViewClient() {
- JNIEnv* env = AttachCurrentThread();
-
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return ScopedJavaLocalRef<jobject>();
-
- return Java_ContentViewCore_getContentVideoViewClient(env, obj.obj());
-}
-
-ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() {
- JNIEnv* env = AttachCurrentThread();
-
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return ScopedJavaLocalRef<jobject>();
-
- return Java_ContentViewCore_getContext(env, obj.obj());
-}
-
bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) {
JNIEnv* env = AttachCurrentThread();
@@ -722,10 +705,19 @@ void ContentViewCoreImpl::DidStopFlinging() {
Java_ContentViewCore_onNativeFlingStopped(env, obj.obj());
}
+ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContext() const {
+ JNIEnv* env = AttachCurrentThread();
+
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return ScopedJavaLocalRef<jobject>();
+
+ return Java_ContentViewCore_getContext(env, obj.obj());
+}
+
gfx::Size ContentViewCoreImpl::GetViewSize() const {
gfx::Size size = GetViewportSizeDip();
- gfx::Size offset = GetViewportSizeOffsetDip();
- size.Enlarge(-offset.width(), -offset.height());
+ size.Enlarge(0, -GetTopControlsLayoutHeightDip());
return size;
}
@@ -749,14 +741,12 @@ gfx::Size ContentViewCoreImpl::GetViewportSizePix() const {
Java_ContentViewCore_getViewportHeightPix(env, j_obj.obj()));
}
-gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetPix() const {
+int ContentViewCoreImpl::GetTopControlsLayoutHeightPix() const {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (j_obj.is_null())
- return gfx::Size();
- return gfx::Size(
- Java_ContentViewCore_getViewportSizeOffsetWidthPix(env, j_obj.obj()),
- Java_ContentViewCore_getViewportSizeOffsetHeightPix(env, j_obj.obj()));
+ return 0;
+ return Java_ContentViewCore_getTopControlsLayoutHeightPix(env, j_obj.obj());
}
gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
@@ -764,22 +754,12 @@ gfx::Size ContentViewCoreImpl::GetViewportSizeDip() const {
gfx::ScaleSize(GetViewportSizePix(), 1.0f / dpi_scale()));
}
-gfx::Size ContentViewCoreImpl::GetViewportSizeOffsetDip() const {
- return gfx::ToCeiledSize(
- gfx::ScaleSize(GetViewportSizeOffsetPix(), 1.0f / dpi_scale()));
-}
-
-float ContentViewCoreImpl::GetOverdrawBottomHeightDip() const {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
- if (j_obj.is_null())
- return 0.f;
- return Java_ContentViewCore_getOverdrawBottomHeightPix(env, j_obj.obj())
- / dpi_scale();
+float ContentViewCoreImpl::GetTopControlsLayoutHeightDip() const {
+ return GetTopControlsLayoutHeightPix() / dpi_scale();
}
void ContentViewCoreImpl::AttachLayer(scoped_refptr<cc::Layer> layer) {
- root_layer_->AddChild(layer);
+ root_layer_->InsertChild(layer, 0);
root_layer_->SetIsDrawable(false);
}
@@ -790,20 +770,31 @@ void ContentViewCoreImpl::RemoveLayer(scoped_refptr<cc::Layer> layer) {
root_layer_->SetIsDrawable(true);
}
-void ContentViewCoreImpl::LoadUrl(
- NavigationController::LoadURLParams& params) {
- GetWebContents()->GetController().LoadURLWithParams(params);
+void ContentViewCoreImpl::MoveRangeSelectionExtent(const gfx::PointF& extent) {
+ if (!web_contents_)
+ return;
+
+ web_contents_->MoveRangeSelectionExtent(gfx::Point(extent.x(), extent.y()));
+}
+
+void ContentViewCoreImpl::SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) {
+ if (!web_contents_)
+ return;
+
+ gfx::Point base_point = gfx::Point(base.x(), base.y());
+ gfx::Point extent_point = gfx::Point(extent.x(), extent.y());
+ if (base_point == extent_point)
+ return;
+
+ web_contents_->SelectRange(base_point, extent_point);
}
ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const {
- // view_android_ should never be null for Chrome.
- DCHECK(view_android_);
return view_android_;
}
ui::WindowAndroid* ContentViewCoreImpl::GetWindowAndroid() const {
- // This should never be NULL for Chrome, but will be NULL for WebView.
- DCHECK(window_android_);
return window_android_;
}
@@ -815,13 +806,15 @@ scoped_refptr<cc::Layer> ContentViewCoreImpl::GetLayer() const {
// Methods called from Java via JNI
// ----------------------------------------------------------------------------
-void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env, jobject obj,
+void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env,
+ jobject obj,
+ jlong selectPopupSourceFrame,
jintArray indices) {
- RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
- web_contents_->GetRenderViewHost());
- DCHECK(rvhi);
+ RenderFrameHostImpl* rfhi =
+ reinterpret_cast<RenderFrameHostImpl*>(selectPopupSourceFrame);
+ DCHECK(rfhi);
if (indices == NULL) {
- rvhi->DidCancelPopupMenu();
+ rfhi->DidCancelPopupMenu();
return;
}
@@ -831,73 +824,7 @@ void ContentViewCoreImpl::SelectPopupMenuItems(JNIEnv* env, jobject obj,
for (int i = 0; i < selected_count; ++i)
selected_indices.push_back(indices_ptr[i]);
env->ReleaseIntArrayElements(indices, indices_ptr, JNI_ABORT);
- rvhi->DidSelectPopupMenuItems(selected_indices);
-}
-
-void ContentViewCoreImpl::LoadUrl(
- JNIEnv* env, jobject obj,
- jstring url,
- jint load_url_type,
- jint transition_type,
- jstring j_referrer_url,
- jint referrer_policy,
- jint ua_override_option,
- jstring extra_headers,
- jbyteArray post_data,
- jstring base_url_for_data_url,
- jstring virtual_url_for_data_url,
- jboolean can_load_local_resources,
- jboolean is_renderer_initiated) {
- DCHECK(url);
- NavigationController::LoadURLParams params(
- GURL(ConvertJavaStringToUTF8(env, url)));
-
- params.load_type = static_cast<NavigationController::LoadURLType>(
- load_url_type);
- params.transition_type = PageTransitionFromInt(transition_type);
- params.override_user_agent =
- static_cast<NavigationController::UserAgentOverrideOption>(
- ua_override_option);
-
- if (extra_headers)
- params.extra_headers = ConvertJavaStringToUTF8(env, extra_headers);
-
- if (post_data) {
- std::vector<uint8> http_body_vector;
- base::android::JavaByteArrayToByteVector(env, post_data, &http_body_vector);
- params.browser_initiated_post_data =
- base::RefCountedBytes::TakeVector(&http_body_vector);
- }
-
- if (base_url_for_data_url) {
- params.base_url_for_data_url =
- GURL(ConvertJavaStringToUTF8(env, base_url_for_data_url));
- }
-
- if (virtual_url_for_data_url) {
- params.virtual_url_for_data_url =
- GURL(ConvertJavaStringToUTF8(env, virtual_url_for_data_url));
- }
-
- params.can_load_local_resources = can_load_local_resources;
- if (j_referrer_url) {
- params.referrer = content::Referrer(
- GURL(ConvertJavaStringToUTF8(env, j_referrer_url)),
- static_cast<blink::WebReferrerPolicy>(referrer_policy));
- }
-
- params.is_renderer_initiated = is_renderer_initiated;
-
- LoadUrl(params);
-}
-
-ScopedJavaLocalRef<jstring> ContentViewCoreImpl::GetURL(
- JNIEnv* env, jobject) const {
- return ConvertUTF8ToJavaString(env, GetWebContents()->GetURL().spec());
-}
-
-jboolean ContentViewCoreImpl::IsIncognito(JNIEnv* env, jobject obj) {
- return GetWebContents()->GetBrowserContext()->IsOffTheRecord();
+ rfhi->DidSelectPopupMenuItems(selected_indices);
}
WebContents* ContentViewCoreImpl::GetWebContents() const {
@@ -943,13 +870,36 @@ jboolean ContentViewCoreImpl::OnTouchEvent(JNIEnv* env,
jint pointer_id_1,
jfloat touch_major_0,
jfloat touch_major_1,
+ jfloat touch_minor_0,
+ jfloat touch_minor_1,
+ jfloat orientation_0,
+ jfloat orientation_1,
jfloat raw_pos_x,
- jfloat raw_pos_y) {
+ jfloat raw_pos_y,
+ jint android_tool_type_0,
+ jint android_tool_type_1,
+ jint android_button_state,
+ jint android_meta_state,
+ jboolean is_touch_handle_event) {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
// Avoid synthesizing a touch event if it cannot be forwarded.
if (!rwhv)
return false;
+ MotionEventAndroid::Pointer pointer0(pointer_id_0,
+ pos_x_0,
+ pos_y_0,
+ touch_major_0,
+ touch_minor_0,
+ orientation_0,
+ android_tool_type_0);
+ MotionEventAndroid::Pointer pointer1(pointer_id_1,
+ pos_x_1,
+ pos_y_1,
+ touch_major_1,
+ touch_minor_1,
+ orientation_1,
+ android_tool_type_1);
MotionEventAndroid event(1.f / dpi_scale(),
env,
motion_event,
@@ -958,18 +908,15 @@ jboolean ContentViewCoreImpl::OnTouchEvent(JNIEnv* env,
pointer_count,
history_size,
action_index,
- pos_x_0,
- pos_y_0,
- pos_x_1,
- pos_y_1,
- pointer_id_0,
- pointer_id_1,
- touch_major_0,
- touch_major_1,
- raw_pos_x,
- raw_pos_y);
+ android_button_state,
+ android_meta_state,
+ raw_pos_x - pos_x_0,
+ raw_pos_y - pos_y_0,
+ pointer0,
+ pointer1);
- return rwhv->OnTouchEvent(event);
+ return is_touch_handle_event ? rwhv->OnTouchHandleEvent(event)
+ : rwhv->OnTouchEvent(event);
}
float ContentViewCoreImpl::GetDpiScale() const {
@@ -1133,20 +1080,29 @@ void ContentViewCoreImpl::PinchBy(JNIEnv* env, jobject obj, jlong time_ms,
void ContentViewCoreImpl::SelectBetweenCoordinates(JNIEnv* env, jobject obj,
jfloat x1, jfloat y1,
jfloat x2, jfloat y2) {
- if (!web_contents_)
- return;
-
- web_contents_->SelectRange(
- gfx::Point(x1 / dpi_scale(), y1 / dpi_scale()),
- gfx::Point(x2 / dpi_scale(), y2 / dpi_scale()));
+ SelectBetweenCoordinates(gfx::PointF(x1 / dpi_scale(), y1 / dpi_scale()),
+ gfx::PointF(x2 / dpi_scale(), y2 / dpi_scale()));
}
void ContentViewCoreImpl::MoveCaret(JNIEnv* env, jobject obj,
jfloat x, jfloat y) {
- if (GetRenderWidgetHostViewAndroid()) {
- GetRenderWidgetHostViewAndroid()->MoveCaret(
- gfx::Point(x / dpi_scale(), y / dpi_scale()));
- }
+ RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
+ if (rwhv)
+ rwhv->MoveCaret(gfx::Point(x / dpi_scale_, y / dpi_scale_));
+}
+
+void ContentViewCoreImpl::DismissTextHandles(JNIEnv* env, jobject obj) {
+ RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
+ if (rwhv)
+ rwhv->DismissTextHandles();
+}
+
+void ContentViewCoreImpl::SetTextHandlesTemporarilyHidden(JNIEnv* env,
+ jobject obj,
+ jboolean hidden) {
+ RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
+ if (rwhv)
+ rwhv->SetTextHandlesTemporarilyHidden(hidden);
}
void ContentViewCoreImpl::ResetGestureDetection(JNIEnv* env, jobject obj) {
@@ -1171,58 +1127,11 @@ void ContentViewCoreImpl::SetMultiTouchZoomSupportEnabled(JNIEnv* env,
rwhv->SetMultiTouchZoomSupportEnabled(enabled);
}
-void ContentViewCoreImpl::LoadIfNecessary(JNIEnv* env, jobject obj) {
- web_contents_->GetController().LoadIfNecessary();
-}
-
-void ContentViewCoreImpl::RequestRestoreLoad(JNIEnv* env, jobject obj) {
- web_contents_->GetController().SetNeedsReload();
-}
-
-void ContentViewCoreImpl::Reload(JNIEnv* env,
- jobject obj,
- jboolean check_for_repost) {
- if (web_contents_->GetController().NeedsReload())
- web_contents_->GetController().LoadIfNecessary();
- else
- web_contents_->GetController().Reload(check_for_repost);
-}
-
-void ContentViewCoreImpl::ReloadIgnoringCache(JNIEnv* env,
- jobject obj,
- jboolean check_for_repost) {
- web_contents_->GetController().ReloadIgnoringCache(check_for_repost);
-}
-
-void ContentViewCoreImpl::CancelPendingReload(JNIEnv* env, jobject obj) {
- web_contents_->GetController().CancelPendingReload();
-}
-
-void ContentViewCoreImpl::ContinuePendingReload(JNIEnv* env, jobject obj) {
- web_contents_->GetController().ContinuePendingReload();
-}
-
-void ContentViewCoreImpl::ClearHistory(JNIEnv* env, jobject obj) {
- // TODO(creis): Do callers of this need to know if it fails?
- if (web_contents_->GetController().CanPruneAllButLastCommitted())
- web_contents_->GetController().PruneAllButLastCommitted();
-}
-
-void ContentViewCoreImpl::AddStyleSheetByURL(
- JNIEnv* env, jobject obj, jstring url) {
- if (!web_contents_)
- return;
-
- web_contents_->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL(
- web_contents_->GetMainFrame()->GetRoutingID(),
- ConvertJavaStringToUTF8(env, url)));
-}
-
void ContentViewCoreImpl::SetAllowJavascriptInterfacesInspection(
JNIEnv* env,
jobject obj,
jboolean allow) {
- java_bridge_dispatcher_host_manager_->SetAllowObjectContentsInspection(allow);
+ java_bridge_dispatcher_host_->SetAllowObjectContentsInspection(allow);
}
void ContentViewCoreImpl::AddJavascriptInterface(
@@ -1233,24 +1142,15 @@ void ContentViewCoreImpl::AddJavascriptInterface(
jclass safe_annotation_clazz) {
ScopedJavaLocalRef<jobject> scoped_object(env, object);
ScopedJavaLocalRef<jclass> scoped_clazz(env, safe_annotation_clazz);
-
- // JavaBoundObject creates the NPObject with a ref count of 1, and
- // JavaBridgeDispatcherHostManager takes its own ref.
- NPObject* bound_object = JavaBoundObject::Create(
- scoped_object,
- scoped_clazz,
- java_bridge_dispatcher_host_manager_->AsWeakPtr(),
- java_bridge_dispatcher_host_manager_->GetAllowObjectContentsInspection());
- java_bridge_dispatcher_host_manager_->AddNamedObject(
- ConvertJavaStringToUTF16(env, name), bound_object);
- blink::WebBindings::releaseObject(bound_object);
+ java_bridge_dispatcher_host_->AddNamedObject(
+ ConvertJavaStringToUTF8(env, name), scoped_object, scoped_clazz);
}
void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env,
jobject /* obj */,
jstring name) {
- java_bridge_dispatcher_host_manager_->RemoveNamedObject(
- ConvertJavaStringToUTF16(env, name));
+ java_bridge_dispatcher_host_->RemoveNamedObject(
+ ConvertJavaStringToUTF8(env, name));
}
void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) {
@@ -1268,141 +1168,6 @@ void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) {
}
}
-void ContentViewCoreImpl::ShowInterstitialPage(
- JNIEnv* env, jobject obj, jstring jurl, jlong delegate_ptr) {
- GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
- InterstitialPageDelegateAndroid* delegate =
- reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr);
- InterstitialPage* interstitial = InterstitialPage::Create(
- web_contents_, false, url, delegate);
- delegate->set_interstitial_page(interstitial);
- interstitial->Show();
-}
-
-jboolean ContentViewCoreImpl::IsShowingInterstitialPage(JNIEnv* env,
- jobject obj) {
- return web_contents_->ShowingInterstitialPage();
-}
-
-jboolean ContentViewCoreImpl::IsRenderWidgetHostViewReady(JNIEnv* env,
- jobject obj) {
- RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
- return view && view->HasValidFrame();
-}
-
-void ContentViewCoreImpl::ExitFullscreen(JNIEnv* env, jobject obj) {
- RenderViewHost* host = web_contents_->GetRenderViewHost();
- if (!host)
- return;
- host->ExitFullscreen();
-}
-
-void ContentViewCoreImpl::UpdateTopControlsState(JNIEnv* env,
- jobject obj,
- bool enable_hiding,
- bool enable_showing,
- bool animate) {
- RenderViewHost* host = web_contents_->GetRenderViewHost();
- if (!host)
- return;
- host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(),
- enable_hiding,
- enable_showing,
- animate));
-}
-
-void ContentViewCoreImpl::ShowImeIfNeeded(JNIEnv* env, jobject obj) {
- RenderViewHost* host = web_contents_->GetRenderViewHost();
- host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID()));
-}
-
-void ContentViewCoreImpl::ScrollFocusedEditableNodeIntoView(JNIEnv* env,
- jobject obj) {
- RenderViewHost* host = web_contents_->GetRenderViewHost();
- host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
- host->GetRoutingID(), gfx::Rect()));
-}
-
-void ContentViewCoreImpl::SelectWordAroundCaret(JNIEnv* env, jobject obj) {
- RenderViewHost* host = web_contents_->GetRenderViewHost();
- if (!host)
- return;
- host->SelectWordAroundCaret();
-}
-
-namespace {
-
-static void AddNavigationEntryToHistory(JNIEnv* env, jobject obj,
- jobject history,
- NavigationEntry* entry,
- int index) {
- // Get the details of the current entry
- ScopedJavaLocalRef<jstring> j_url(
- ConvertUTF8ToJavaString(env, entry->GetURL().spec()));
- ScopedJavaLocalRef<jstring> j_virtual_url(
- ConvertUTF8ToJavaString(env, entry->GetVirtualURL().spec()));
- ScopedJavaLocalRef<jstring> j_original_url(
- ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()));
- ScopedJavaLocalRef<jstring> j_title(
- ConvertUTF16ToJavaString(env, entry->GetTitle()));
- ScopedJavaLocalRef<jobject> j_bitmap;
- const FaviconStatus& status = entry->GetFavicon();
- if (status.valid && status.image.ToSkBitmap()->getSize() > 0)
- j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap());
-
- // Add the item to the list
- Java_ContentViewCore_addToNavigationHistory(
- env, obj, history, index, j_url.obj(), j_virtual_url.obj(),
- j_original_url.obj(), j_title.obj(), j_bitmap.obj());
-}
-
-} // namespace
-
-int ContentViewCoreImpl::GetNavigationHistory(JNIEnv* env,
- jobject obj,
- jobject history) {
- // Iterate through navigation entries to populate the list
- const NavigationController& controller = web_contents_->GetController();
- int count = controller.GetEntryCount();
- for (int i = 0; i < count; ++i) {
- AddNavigationEntryToHistory(
- env, obj, history, controller.GetEntryAtIndex(i), i);
- }
-
- return controller.GetCurrentEntryIndex();
-}
-
-void ContentViewCoreImpl::GetDirectedNavigationHistory(JNIEnv* env,
- jobject obj,
- jobject history,
- jboolean is_forward,
- jint max_entries) {
- // Iterate through navigation entries to populate the list
- const NavigationController& controller = web_contents_->GetController();
- int count = controller.GetEntryCount();
- int num_added = 0;
- int increment_value = is_forward ? 1 : -1;
- for (int i = controller.GetCurrentEntryIndex() + increment_value;
- i >= 0 && i < count;
- i += increment_value) {
- if (num_added >= max_entries)
- break;
-
- AddNavigationEntryToHistory(
- env, obj, history, controller.GetEntryAtIndex(i), i);
- num_added++;
- }
-}
-
-ScopedJavaLocalRef<jstring>
-ContentViewCoreImpl::GetOriginalUrlForActiveNavigationEntry(JNIEnv* env,
- jobject obj) {
- NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
- if (entry == NULL)
- return ScopedJavaLocalRef<jstring>(env, NULL);
- return ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec());
-}
-
long ContentViewCoreImpl::GetNativeImeAdapter(JNIEnv* env, jobject obj) {
RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
if (!rwhva)
@@ -1410,61 +1175,9 @@ long ContentViewCoreImpl::GetNativeImeAdapter(JNIEnv* env, jobject obj) {
return rwhva->GetNativeImeAdapter();
}
-namespace {
-void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
- const base::Value* result) {
- JNIEnv* env = base::android::AttachCurrentThread();
- std::string json;
- base::JSONWriter::Write(result, &json);
- ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
- Java_ContentViewCore_onEvaluateJavaScriptResult(env,
- j_json.obj(),
- callback.obj());
-}
-} // namespace
-
-void ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env,
- jobject obj,
- jstring script,
- jobject callback,
- jboolean start_renderer) {
- RenderViewHost* rvh = web_contents_->GetRenderViewHost();
- DCHECK(rvh);
-
- if (start_renderer && !rvh->IsRenderViewLive()) {
- if (!web_contents_->CreateRenderViewForInitialEmptyDocument()) {
- LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
- return;
- }
- }
-
- if (!callback) {
- // No callback requested.
- web_contents_->GetMainFrame()->ExecuteJavaScript(
- ConvertJavaStringToUTF16(env, script));
- return;
- }
-
- // 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);
- content::RenderFrameHost::JavaScriptResultCallback c_callback =
- base::Bind(&JavaScriptResultCallback, j_callback);
-
- web_contents_->GetMainFrame()->ExecuteJavaScript(
- ConvertJavaStringToUTF16(env, script),
- c_callback);
-}
-
-bool ContentViewCoreImpl::GetUseDesktopUserAgent(
- JNIEnv* env, jobject obj) {
- NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
- return entry && entry->GetIsOverridingUserAgent();
-}
-
void ContentViewCoreImpl::UpdateImeAdapter(long native_ime_adapter,
int text_input_type,
+ int text_input_flags,
const std::string& text,
int selection_start,
int selection_end,
@@ -1478,44 +1191,18 @@ void ContentViewCoreImpl::UpdateImeAdapter(long native_ime_adapter,
return;
ScopedJavaLocalRef<jstring> jstring_text = ConvertUTF8ToJavaString(env, text);
- Java_ContentViewCore_updateImeAdapter(env, obj.obj(),
- native_ime_adapter, text_input_type,
+ Java_ContentViewCore_updateImeAdapter(env,
+ obj.obj(),
+ native_ime_adapter,
+ text_input_type,
+ text_input_flags,
jstring_text.obj(),
- selection_start, selection_end,
- composition_start, composition_end,
- show_ime_if_needed, is_non_ime_change);
-}
-
-void ContentViewCoreImpl::ClearSslPreferences(JNIEnv* env, jobject obj) {
- SSLHostState* state = SSLHostState::GetFor(
- web_contents_->GetController().GetBrowserContext());
- state->Clear();
-}
-
-void ContentViewCoreImpl::SetUseDesktopUserAgent(
- JNIEnv* env,
- jobject obj,
- jboolean enabled,
- jboolean reload_on_state_change) {
- if (GetUseDesktopUserAgent(env, obj) == enabled)
- return;
-
- // Make sure the navigation entry actually exists.
- NavigationEntry* entry = web_contents_->GetController().GetVisibleEntry();
- if (!entry)
- return;
-
- // Set the flag in the NavigationEntry.
- entry->SetIsOverridingUserAgent(enabled);
-
- // Send the override to the renderer.
- if (reload_on_state_change) {
- // Reloading the page will send the override down as part of the
- // navigation IPC message.
- NavigationControllerImpl& controller =
- static_cast<NavigationControllerImpl&>(web_contents_->GetController());
- controller.ReloadOriginalRequestURL(false);
- }
+ selection_start,
+ selection_end,
+ composition_start,
+ composition_end,
+ show_ime_if_needed,
+ is_non_ime_change);
}
void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj,
@@ -1523,26 +1210,32 @@ void ContentViewCoreImpl::SetAccessibilityEnabled(JNIEnv* env, jobject obj,
SetAccessibilityEnabledInternal(enabled);
}
+bool ContentViewCoreImpl::IsFullscreenRequiredForOrientationLock() const {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+ if (obj.is_null())
+ return true;
+ return Java_ContentViewCore_isFullscreenRequiredForOrientationLock(env,
+ obj.obj());
+}
+
void ContentViewCoreImpl::SetAccessibilityEnabledInternal(bool enabled) {
accessibility_enabled_ = enabled;
- RenderWidgetHostViewAndroid* host_view = GetRenderWidgetHostViewAndroid();
- if (!host_view)
- return;
- RenderWidgetHostImpl* host_impl = RenderWidgetHostImpl::From(
- host_view->GetRenderWidgetHost());
- BrowserAccessibilityState* accessibility_state =
- BrowserAccessibilityState::GetInstance();
+ BrowserAccessibilityStateImpl* accessibility_state =
+ BrowserAccessibilityStateImpl::GetInstance();
if (enabled) {
// This enables accessibility globally unless it was explicitly disallowed
// by a command-line flag.
accessibility_state->OnScreenReaderDetected();
// If it was actually enabled globally, enable it for this RenderWidget now.
- if (accessibility_state->IsAccessibleBrowser() && host_impl)
- host_impl->AddAccessibilityMode(AccessibilityModeComplete);
+ if (accessibility_state->IsAccessibleBrowser() && web_contents_)
+ web_contents_->AddAccessibilityMode(AccessibilityModeComplete);
} else {
accessibility_state->ResetAccessibilityMode();
- if (host_impl)
- host_impl->ResetAccessibilityMode();
+ if (web_contents_) {
+ web_contents_->SetAccessibilityMode(
+ accessibility_state->accessibility_mode());
+ }
}
}
@@ -1550,6 +1243,9 @@ void ContentViewCoreImpl::SendOrientationChangeEventInternal() {
RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
if (rwhv)
rwhv->UpdateScreenInfo(GetViewAndroid());
+
+ static_cast<WebContentsImpl*>(web_contents())->
+ screen_orientation_dispatcher_host()->OnOrientationChange();
}
void ContentViewCoreImpl::ExtractSmartClipData(JNIEnv* env,
@@ -1576,8 +1272,12 @@ jint ContentViewCoreImpl::GetCurrentRenderProcessId(JNIEnv* env, jobject obj) {
void ContentViewCoreImpl::SetBackgroundOpaque(JNIEnv* env, jobject jobj,
jboolean opaque) {
- if (GetRenderWidgetHostViewAndroid())
- GetRenderWidgetHostViewAndroid()->SetBackgroundOpaque(opaque);
+ if (GetRenderWidgetHostViewAndroid()) {
+ if (opaque)
+ GetRenderWidgetHostViewAndroid()->SetBackgroundColorToDefault();
+ else
+ GetRenderWidgetHostViewAndroid()->SetBackgroundColor(SK_ColorTRANSPARENT);
+ }
}
void ContentViewCoreImpl::RequestTextSurroundingSelection(
@@ -1598,14 +1298,18 @@ void ContentViewCoreImpl::RequestTextSurroundingSelection(
}
void ContentViewCoreImpl::OnSmartClipDataExtracted(
- const base::string16& result) {
+ const base::string16& text,
+ const base::string16& html,
+ const gfx::Rect& clip_rect) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
- ScopedJavaLocalRef<jstring> jresult = ConvertUTF16ToJavaString(env, result);
+ ScopedJavaLocalRef<jstring> jtext = ConvertUTF16ToJavaString(env, text);
+ ScopedJavaLocalRef<jstring> jhtml = ConvertUTF16ToJavaString(env, html);
+ ScopedJavaLocalRef<jobject> clip_rect_object(CreateJavaRect(env, clip_rect));
Java_ContentViewCore_onSmartClipDataExtracted(
- env, obj.obj(), jresult.obj());
+ env, obj.obj(), jtext.obj(), jhtml.obj(), clip_rect_object.obj());
}
void ContentViewCoreImpl::WebContentsDestroyed() {
diff --git a/chromium/content/browser/android/content_view_core_impl.h b/chromium/content/browser/android/content_view_core_impl.h
index 3bb12913975..8a823ee72b8 100644
--- a/chromium/content/browser/android/content_view_core_impl.h
+++ b/chromium/content/browser/android/content_view_core_impl.h
@@ -28,7 +28,9 @@ class WindowAndroid;
}
namespace content {
-class JavaBridgeDispatcherHostManager;
+
+class GinJavaBridgeDispatcherHost;
+class RenderFrameHost;
class RenderWidgetHostViewAndroid;
struct MenuItem;
@@ -45,27 +47,25 @@ class ContentViewCoreImpl : public ContentViewCore,
jobject java_bridge_retained_object_set);
// ContentViewCore implementation.
- virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() OVERRIDE;
- virtual WebContents* GetWebContents() const OVERRIDE;
- virtual ui::ViewAndroid* GetViewAndroid() const OVERRIDE;
- virtual ui::WindowAndroid* GetWindowAndroid() const OVERRIDE;
- virtual scoped_refptr<cc::Layer> GetLayer() const OVERRIDE;
- virtual void LoadUrl(NavigationController::LoadURLParams& params) OVERRIDE;
- virtual void ShowPastePopup(int x, int y) OVERRIDE;
+ virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() override;
+ virtual WebContents* GetWebContents() const override;
+ virtual ui::ViewAndroid* GetViewAndroid() const override;
+ virtual ui::WindowAndroid* GetWindowAndroid() const override;
+ virtual scoped_refptr<cc::Layer> GetLayer() const override;
+ virtual void ShowPastePopup(int x, int y) override;
virtual void GetScaledContentBitmap(
float scale,
- jobject bitmap_config,
+ SkColorType color_type,
gfx::Rect src_subrect,
const base::Callback<void(bool, const SkBitmap&)>& result_callback)
- OVERRIDE;
- virtual float GetDpiScale() const OVERRIDE;
- virtual void PauseVideo() OVERRIDE;
- virtual void PauseOrResumeGeolocation(bool should_pause) OVERRIDE;
+ override;
+ virtual float GetDpiScale() const override;
+ virtual void PauseOrResumeGeolocation(bool should_pause) override;
virtual void RequestTextSurroundingSelection(
int max_length,
const base::Callback<void(const base::string16& content,
int start_offset,
- int end_offset)>& callback) OVERRIDE;
+ int end_offset)>& callback) override;
// --------------------------------------------------------------------------
// Methods called from Java via JNI
@@ -78,24 +78,10 @@ class ContentViewCoreImpl : public ContentViewCore,
// Notifies the ContentViewCore that items were selected in the currently
// showing select popup.
- void SelectPopupMenuItems(JNIEnv* env, jobject obj, jintArray indices);
-
- void LoadUrl(
- JNIEnv* env, jobject obj,
- jstring url,
- jint load_url_type,
- jint transition_type,
- jstring j_referrer_url,
- jint referrer_policy,
- jint ua_override_option,
- jstring extra_headers,
- jbyteArray post_data,
- jstring base_url_for_data_url,
- jstring virtual_url_for_data_url,
- jboolean can_load_local_resources,
- jboolean is_renderer_initiated);
- base::android::ScopedJavaLocalRef<jstring> GetURL(JNIEnv* env, jobject) const;
- jboolean IsIncognito(JNIEnv* env, jobject obj);
+ void SelectPopupMenuItems(JNIEnv* env, jobject obj,
+ jlong selectPopupSourceFrame,
+ jintArray indices);
+
void SendOrientationChangeEvent(JNIEnv* env, jobject obj, jint orientation);
jboolean OnTouchEvent(JNIEnv* env,
jobject obj,
@@ -113,8 +99,17 @@ class ContentViewCoreImpl : public ContentViewCore,
jint pointer_id_1,
jfloat touch_major_0,
jfloat touch_major_1,
+ jfloat touch_minor_0,
+ jfloat touch_minor_1,
+ jfloat orientation_0,
+ jfloat orientation_1,
jfloat raw_pos_x,
- jfloat raw_pos_y);
+ jfloat raw_pos_y,
+ jint android_tool_type_0,
+ jint android_tool_type_1,
+ jint android_button_state,
+ jint android_meta_state,
+ jboolean is_touch_handle_event);
jboolean SendMouseMoveEvent(JNIEnv* env,
jobject obj,
jlong time_ms,
@@ -148,6 +143,10 @@ class ContentViewCoreImpl : public ContentViewCore,
jfloat x1, jfloat y1,
jfloat x2, jfloat y2);
void MoveCaret(JNIEnv* env, jobject obj, jfloat x, jfloat y);
+ void DismissTextHandles(JNIEnv* env, jobject obj);
+ void SetTextHandlesTemporarilyHidden(JNIEnv* env,
+ jobject obj,
+ jboolean hidden);
void ResetGestureDetection(JNIEnv* env, jobject obj);
void SetDoubleTapSupportEnabled(JNIEnv* env, jobject obj, jboolean enabled);
@@ -155,36 +154,11 @@ class ContentViewCoreImpl : public ContentViewCore,
jobject obj,
jboolean enabled);
- void LoadIfNecessary(JNIEnv* env, jobject obj);
- void RequestRestoreLoad(JNIEnv* env, jobject obj);
- void Reload(JNIEnv* env, jobject obj, jboolean check_for_repost);
- void ReloadIgnoringCache(JNIEnv* env, jobject obj, jboolean check_for_repost);
- void CancelPendingReload(JNIEnv* env, jobject obj);
- void ContinuePendingReload(JNIEnv* env, jobject obj);
- void AddStyleSheetByURL(JNIEnv* env, jobject obj, jstring url);
- void ClearHistory(JNIEnv* env, jobject obj);
- void EvaluateJavaScript(JNIEnv* env,
- jobject obj,
- jstring script,
- jobject callback,
- jboolean start_renderer);
long GetNativeImeAdapter(JNIEnv* env, jobject obj);
void SetFocus(JNIEnv* env, jobject obj, jboolean focused);
- void ScrollFocusedEditableNodeIntoView(JNIEnv* env, jobject obj);
- void SelectWordAroundCaret(JNIEnv* env, jobject obj);
jint GetBackgroundColor(JNIEnv* env, jobject obj);
void SetBackgroundColor(JNIEnv* env, jobject obj, jint color);
- void OnShow(JNIEnv* env, jobject obj);
- void OnHide(JNIEnv* env, jobject obj);
- void ClearSslPreferences(JNIEnv* env, jobject /* obj */);
- void SetUseDesktopUserAgent(JNIEnv* env,
- jobject /* obj */,
- jboolean state,
- jboolean reload_on_state_change);
- bool GetUseDesktopUserAgent(JNIEnv* env, jobject /* obj */);
- void Show();
- void Hide();
void SetAllowJavascriptInterfacesInspection(JNIEnv* env,
jobject obj,
jboolean allow);
@@ -194,29 +168,7 @@ class ContentViewCoreImpl : public ContentViewCore,
jstring name,
jclass safe_annotation_clazz);
void RemoveJavascriptInterface(JNIEnv* env, jobject obj, jstring name);
- int GetNavigationHistory(JNIEnv* env, jobject obj, jobject history);
- void GetDirectedNavigationHistory(JNIEnv* env,
- jobject obj,
- jobject history,
- jboolean is_forward,
- jint max_entries);
- base::android::ScopedJavaLocalRef<jstring>
- GetOriginalUrlForActiveNavigationEntry(JNIEnv* env, jobject obj);
void WasResized(JNIEnv* env, jobject obj);
- jboolean IsRenderWidgetHostViewReady(JNIEnv* env, jobject obj);
- void ExitFullscreen(JNIEnv* env, jobject obj);
- void UpdateTopControlsState(JNIEnv* env,
- jobject obj,
- bool enable_hiding,
- bool enable_showing,
- bool animate);
- void ShowImeIfNeeded(JNIEnv* env, jobject obj);
-
- void ShowInterstitialPage(JNIEnv* env,
- jobject obj,
- jstring jurl,
- jlong delegate);
- jboolean IsShowingInterstitialPage(JNIEnv* env, jobject obj);
void SetAccessibilityEnabled(JNIEnv* env, jobject obj, bool enabled);
@@ -235,13 +187,16 @@ class ContentViewCoreImpl : public ContentViewCore,
// Public methods that call to Java via JNI
// --------------------------------------------------------------------------
- void OnSmartClipDataExtracted(const base::string16& result);
+ void OnSmartClipDataExtracted(const base::string16& text,
+ const base::string16& html,
+ const gfx::Rect& clip_rect);
// Creates a popup menu with |items|.
// |multiple| defines if it should support multi-select.
// If not |multiple|, |selected_item| sets the initially selected item.
// Otherwise, item's "checked" flag selects it.
- void ShowSelectPopupMenu(const gfx::Rect& bounds,
+ void ShowSelectPopupMenu(RenderFrameHost* frame,
+ const gfx::Rect& bounds,
const std::vector<MenuItem>& items,
int selected_item,
bool multiple);
@@ -255,14 +210,18 @@ class ContentViewCoreImpl : public ContentViewCore,
const gfx::SizeF& content_size,
const gfx::SizeF& viewport_size,
const gfx::Vector2dF& controls_offset,
- const gfx::Vector2dF& content_offset,
- float overdraw_bottom_height);
+ const gfx::Vector2dF& content_offset);
- void UpdateImeAdapter(long native_ime_adapter, int text_input_type,
+ void UpdateImeAdapter(long native_ime_adapter,
+ int text_input_type,
+ int text_input_flags,
const std::string& text,
- int selection_start, int selection_end,
- int composition_start, int composition_end,
- bool show_ime_if_needed, bool is_non_ime_change);
+ int selection_start,
+ int selection_end,
+ int composition_start,
+ int composition_end,
+ bool show_ime_if_needed,
+ bool is_non_ime_change);
void SetTitle(const base::string16& title);
void OnBackgroundColorChanged(SkColor color);
@@ -271,49 +230,54 @@ class ContentViewCoreImpl : public ContentViewCore,
InputEventAckState ack_result);
bool FilterInputEvent(const blink::WebInputEvent& event);
void OnSelectionChanged(const std::string& text);
- void OnSelectionBoundsChanged(
- const ViewHostMsg_SelectionBounds_Params& params);
+ void OnSelectionEvent(SelectionEventType event,
+ const gfx::PointF& anchor_position);
+ scoped_ptr<TouchHandleDrawable> CreatePopupTouchHandleDrawable();
void StartContentIntent(const GURL& content_url);
// Shows the disambiguation popup
- // |target_rect| --> window coordinates which |zoomed_bitmap| represents
+ // |rect_pixels| --> window coordinates which |zoomed_bitmap| represents
// |zoomed_bitmap| --> magnified image of potential touch targets
void ShowDisambiguationPopup(
- const gfx::Rect& target_rect, const SkBitmap& zoomed_bitmap);
+ const gfx::Rect& rect_pixels, const SkBitmap& zoomed_bitmap);
// Creates a java-side touch event, used for injecting touch event for
// testing/benchmarking purposes
base::android::ScopedJavaLocalRef<jobject> CreateTouchEventSynthesizer();
- base::android::ScopedJavaLocalRef<jobject> GetContentVideoViewClient();
-
- // Returns the context that the ContentViewCore was created with, it would
- // typically be an Activity context for an on screen view.
- base::android::ScopedJavaLocalRef<jobject> GetContext();
-
// Returns True if the given media should be blocked to load.
bool ShouldBlockMediaRequest(const GURL& url);
void DidStopFlinging();
+ // Returns the context with which the ContentViewCore was created, typically
+ // the Activity context.
+ base::android::ScopedJavaLocalRef<jobject> GetContext() const;
+
// Returns the viewport size after accounting for the viewport offset.
gfx::Size GetViewSize() const;
void SetAccessibilityEnabledInternal(bool enabled);
+ bool IsFullscreenRequiredForOrientationLock() const;
+
// --------------------------------------------------------------------------
// Methods called from native code
// --------------------------------------------------------------------------
gfx::Size GetPhysicalBackingSize() const;
gfx::Size GetViewportSizeDip() const;
- gfx::Size GetViewportSizeOffsetDip() const;
- float GetOverdrawBottomHeightDip() const;
+ float GetTopControlsLayoutHeightDip() const;
void AttachLayer(scoped_refptr<cc::Layer> layer);
void RemoveLayer(scoped_refptr<cc::Layer> layer);
+ void MoveRangeSelectionExtent(const gfx::PointF& extent);
+
+ void SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent);
+
private:
class ContentViewUserData;
@@ -321,10 +285,10 @@ class ContentViewCoreImpl : public ContentViewCore,
virtual ~ContentViewCoreImpl();
// WebContentsObserver implementation.
- virtual void RenderViewReady() OVERRIDE;
+ virtual void RenderViewReady() override;
virtual void RenderViewHostChanged(RenderViewHost* old_host,
- RenderViewHost* new_host) OVERRIDE;
- virtual void WebContentsDestroyed() OVERRIDE;
+ RenderViewHost* new_host) override;
+ virtual void WebContentsDestroyed() override;
// --------------------------------------------------------------------------
// Other private methods and data
@@ -338,11 +302,8 @@ class ContentViewCoreImpl : public ContentViewCore,
blink::WebInputEvent::Type type, int64 time_ms, float x, float y) const;
gfx::Size GetViewportSizePix() const;
- gfx::Size GetViewportSizeOffsetPix() const;
-
- void DeleteScaledSnapshotTexture();
+ int GetTopControlsLayoutHeightPix() const;
- bool OnMotionEvent(const ui::MotionEvent& event);
void SendGestureEvent(const blink::WebGestureEvent& event);
// Update focus state of the RenderWidgetHostView.
@@ -380,8 +341,8 @@ class ContentViewCoreImpl : public ContentViewCore,
bool accessibility_enabled_;
// Manages injecting Java objects.
- scoped_ptr<JavaBridgeDispatcherHostManager>
- java_bridge_dispatcher_host_manager_;
+ scoped_ptr<GinJavaBridgeDispatcherHost>
+ java_bridge_dispatcher_host_;
DISALLOW_COPY_AND_ASSIGN(ContentViewCoreImpl);
};
diff --git a/chromium/content/browser/android/content_view_render_view.cc b/chromium/content/browser/android/content_view_render_view.cc
index 06590fa7513..deae6733c4e 100644
--- a/chromium/content/browser/android/content_view_render_view.cc
+++ b/chromium/content/browser/android/content_view_render_view.cc
@@ -16,6 +16,7 @@
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/android/content_view_layer_renderer.h"
#include "content/public/browser/android/layer_tree_build_helper.h"
+#include "content/public/browser/android/ui_resource_provider.h"
#include "jni/ContentViewRenderView_jni.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/size.h"
@@ -35,7 +36,7 @@ class LayerTreeBuildHelperImpl : public LayerTreeBuildHelper {
virtual ~LayerTreeBuildHelperImpl() {}
virtual scoped_refptr<cc::Layer> GetLayerTree(
- scoped_refptr<cc::Layer> content_root_layer) OVERRIDE {
+ scoped_refptr<cc::Layer> content_root_layer) override {
return content_root_layer;
}
@@ -70,6 +71,7 @@ void ContentViewRenderView::SetLayerTreeBuildHelper(JNIEnv* env,
LayerTreeBuildHelper* build_helper =
reinterpret_cast<LayerTreeBuildHelper*>(native_build_helper);
layer_tree_build_helper_.reset(build_helper);
+ InitCompositor();
}
// static
static jlong Init(JNIEnv* env,
@@ -120,6 +122,12 @@ void ContentViewRenderView::SurfaceChanged(JNIEnv* env, jobject obj,
void ContentViewRenderView::SetOverlayVideoMode(
JNIEnv* env, jobject obj, bool enabled) {
compositor_->SetHasTransparentBackground(enabled);
+ SetNeedsComposite(env, obj);
+}
+
+void ContentViewRenderView::SetNeedsComposite(JNIEnv* env, jobject obj) {
+ if (compositor_)
+ compositor_->SetNeedsComposite();
}
void ContentViewRenderView::Layout() {
@@ -136,4 +144,11 @@ void ContentViewRenderView::InitCompositor() {
if (!compositor_)
compositor_.reset(Compositor::Create(this, root_window_));
}
+
+jlong ContentViewRenderView::GetUIResourceProvider(JNIEnv* env,
+ 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 2f1bcc1e7c7..ed3f03cc3fa 100644
--- a/chromium/content/browser/android/content_view_render_view.h
+++ b/chromium/content/browser/android/content_view_render_view.h
@@ -19,6 +19,7 @@ class Layer;
namespace content {
class Compositor;
class LayerTreeBuildHelper;
+class UIResourceProvider;
class ContentViewRenderView : public CompositorClient {
public:
@@ -41,10 +42,15 @@ class ContentViewRenderView : public CompositorClient {
jint format, jint width, jint height, jobject surface);
jboolean Composite(JNIEnv* env, jobject obj);
void SetOverlayVideoMode(JNIEnv* env, jobject obj, bool enabled);
+ void SetNeedsComposite(JNIEnv* env, jobject obj);
+
+ // TODO(yusufo): Remove this once the compositor code is
+ // refactored to use a unified system.
+ jlong GetUIResourceProvider(JNIEnv* env, jobject obj);
// CompositorClient implementation
- virtual void Layout() OVERRIDE;
- virtual void OnSwapBuffersCompleted(int pending_swap_buffers) OVERRIDE;
+ virtual void Layout() override;
+ virtual void OnSwapBuffersCompleted(int pending_swap_buffers) override;
private:
virtual ~ContentViewRenderView();
diff --git a/chromium/content/browser/android/content_view_statics.cc b/chromium/content/browser/android/content_view_statics.cc
index 00b5600493c..1c4e9035d15 100644
--- a/chromium/content/browser/android/content_view_statics.cc
+++ b/chromium/content/browser/android/content_view_statics.cc
@@ -32,7 +32,7 @@ namespace {
// This tracks the renderer processes that received a suspend request. It's
// important on resume to only resume the renderer processes that were actually
// suspended as opposed to all the current renderer processes because the
-// suspend calls are refcounted within WebKitPlatformSupport and it expects a
+// suspend calls are refcounted within BlinkPlatformImpl and it expects a
// perfectly matched number of resume calls.
// Note that this class is only accessed from the UI thread.
class SuspendedProcessWatcher : public content::RenderProcessHostObserver {
@@ -41,14 +41,13 @@ class SuspendedProcessWatcher : public content::RenderProcessHostObserver {
// If the process crashes, stop watching the corresponding RenderProcessHost
// and ensure it doesn't get over-resumed.
virtual void RenderProcessExited(content::RenderProcessHost* host,
- base::ProcessHandle handle,
base::TerminationStatus status,
- int exit_code) OVERRIDE {
+ int exit_code) override {
StopWatching(host);
}
virtual void RenderProcessHostDestroyed(
- content::RenderProcessHost* host) OVERRIDE {
+ content::RenderProcessHost* host) override {
StopWatching(host);
}
@@ -84,7 +83,7 @@ class SuspendedProcessWatcher : public content::RenderProcessHostObserver {
std::vector<int>::iterator pos = std::find(suspended_processes_.begin(),
suspended_processes_.end(),
host->GetID());
- DCHECK_NE(pos, suspended_processes_.end());
+ DCHECK(pos != suspended_processes_.end());
host->RemoveObserver(this);
suspended_processes_.erase(pos);
}
diff --git a/chromium/content/browser/android/date_time_chooser_android.cc b/chromium/content/browser/android/date_time_chooser_android.cc
index 58133ba22d9..31ff4656bef 100644
--- a/chromium/content/browser/android/date_time_chooser_android.cc
+++ b/chromium/content/browser/android/date_time_chooser_android.cc
@@ -9,11 +9,11 @@
#include "base/i18n/char_iterator.h"
#include "content/common/date_time_suggestion.h"
#include "content/common/view_messages.h"
-#include "content/public/browser/android/content_view_core.h"
#include "content/public/browser/render_view_host.h"
#include "jni/DateTimeChooserAndroid_jni.h"
#include "third_party/icu/source/common/unicode/uchar.h"
#include "third_party/icu/source/common/unicode/unistr.h"
+#include "ui/base/android/window_android.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF16;
@@ -73,7 +73,7 @@ void DateTimeChooserAndroid::CancelDialog(JNIEnv* env, jobject) {
}
void DateTimeChooserAndroid::ShowDialog(
- ContentViewCore* content,
+ gfx::NativeWindow native_window,
RenderViewHost* host,
ui::TextInputType dialog_type,
double dialog_value,
@@ -104,7 +104,7 @@ void DateTimeChooserAndroid::ShowDialog(
j_date_time_chooser_.Reset(Java_DateTimeChooserAndroid_createDateTimeChooser(
env,
- content->GetJavaObject().obj(),
+ native_window->GetJavaObject().obj(),
reinterpret_cast<intptr_t>(this),
dialog_type,
dialog_value,
@@ -112,6 +112,8 @@ void DateTimeChooserAndroid::ShowDialog(
max,
step,
suggestions_array.obj()));
+ if (j_date_time_chooser_.is_null())
+ ReplaceDateTime(env, j_date_time_chooser_.obj(), dialog_value);
}
// ----------------------------------------------------------------------------
diff --git a/chromium/content/browser/android/date_time_chooser_android.h b/chromium/content/browser/android/date_time_chooser_android.h
index b47ed5ec7c5..1a29b4a0f05 100644
--- a/chromium/content/browser/android/date_time_chooser_android.h
+++ b/chromium/content/browser/android/date_time_chooser_android.h
@@ -11,6 +11,7 @@
#include "base/android/jni_weak_ref.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/ime/text_input_type.h"
+#include "ui/gfx/native_widget_types.h"
namespace content {
@@ -27,7 +28,7 @@ class DateTimeChooserAndroid {
// DateTimeChooser implementation:
// Shows the dialog. |dialog_value| is the date/time value converted to a
// number as defined in HTML. (See blink::InputType::parseToNumber())
- void ShowDialog(ContentViewCore* content,
+ void ShowDialog(gfx::NativeWindow native_window,
RenderViewHost* host,
ui::TextInputType dialog_type,
double dialog_value,
diff --git a/chromium/content/browser/android/devtools_auth.cc b/chromium/content/browser/android/devtools_auth.cc
index c89cdc0cbf1..46314c44768 100644
--- a/chromium/content/browser/android/devtools_auth.cc
+++ b/chromium/content/browser/android/devtools_auth.cc
@@ -4,19 +4,28 @@
#include "content/public/browser/android/devtools_auth.h"
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
#include "base/logging.h"
namespace content {
-bool CanUserConnectToDevTools(uid_t uid, gid_t gid) {
- struct passwd* creds = getpwuid(uid);
+bool CanUserConnectToDevTools(
+ const net::UnixDomainServerSocket::Credentials& credentials) {
+ struct passwd* creds = getpwuid(credentials.user_id);
if (!creds || !creds->pw_name) {
- LOG(WARNING) << "DevTools: can't obtain creds for uid " << uid;
+ LOG(WARNING) << "DevTools: can't obtain creds for uid "
+ << credentials.user_id;
return false;
}
- if (gid == uid &&
- (strcmp("root", creds->pw_name) == 0 || // For rooted devices
- strcmp("shell", creds->pw_name) == 0)) { // For non-rooted devices
+ if (credentials.group_id == credentials.user_id &&
+ (strcmp("root", creds->pw_name) == 0 || // For rooted devices
+ strcmp("shell", creds->pw_name) == 0 || // For non-rooted devices
+
+ // From processes signed with the same key
+ credentials.user_id == getuid())) {
return true;
}
LOG(WARNING) << "DevTools: connection attempt from " << creds->pw_name;
diff --git a/chromium/content/browser/android/download_controller_android_impl.cc b/chromium/content/browser/android/download_controller_android_impl.cc
index 2d042353036..08cea4be685 100644
--- a/chromium/content/browser/android/download_controller_android_impl.cc
+++ b/chromium/content/browser/android/download_controller_android_impl.cc
@@ -22,6 +22,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_url_parameters.h"
#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/resource_request_info.h"
#include "content/public/common/referrer.h"
#include "jni/DownloadController_jni.h"
#include "net/cookies/cookie_options.h"
@@ -230,7 +231,8 @@ void DownloadControllerAndroidImpl::StartAndroidDownload(
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(), jfilename.obj(), info.total_bytes);
+ jcookie.obj(), jreferer.obj(), info.has_user_gesture, jfilename.obj(),
+ info.total_bytes);
}
void DownloadControllerAndroidImpl::OnDownloadStarted(
@@ -401,7 +403,8 @@ void DownloadControllerAndroidImpl::DangerousDownloadValidated(
}
DownloadControllerAndroidImpl::DownloadInfoAndroid::DownloadInfoAndroid(
- net::URLRequest* request) {
+ net::URLRequest* request)
+ : has_user_gesture(false) {
request->GetResponseHeaderByName("content-disposition", &content_disposition);
if (request->response_headers())
@@ -416,6 +419,11 @@ DownloadControllerAndroidImpl::DownloadInfoAndroid::DownloadInfoAndroid(
original_url = request->url_chain().front();
url = request->url_chain().back();
}
+
+ const content::ResourceRequestInfo* info =
+ content::ResourceRequestInfo::ForRequest(request);
+ if (info)
+ has_user_gesture = info->HasUserGesture();
}
DownloadControllerAndroidImpl::DownloadInfoAndroid::~DownloadInfoAndroid() {}
diff --git a/chromium/content/browser/android/download_controller_android_impl.h b/chromium/content/browser/android/download_controller_android_impl.h
index 26bc2a0c4f9..7bc71bf74e2 100644
--- a/chromium/content/browser/android/download_controller_android_impl.h
+++ b/chromium/content/browser/android/download_controller_android_impl.h
@@ -65,6 +65,7 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
std::string user_agent;
std::string cookie;
std::string referer;
+ bool has_user_gesture;
WebContents* web_contents;
// Default copy constructor is used for passing this struct by value.
@@ -76,16 +77,16 @@ class DownloadControllerAndroidImpl : public DownloadControllerAndroid,
// DownloadControllerAndroid implementation.
virtual void CreateGETDownload(int render_process_id, int render_view_id,
- int request_id) OVERRIDE;
- virtual void OnDownloadStarted(DownloadItem* download_item) OVERRIDE;
+ int request_id) override;
+ virtual void OnDownloadStarted(DownloadItem* download_item) override;
virtual void StartContextMenuDownload(
const ContextMenuParams& params, WebContents* web_contents,
- bool is_link) OVERRIDE;
+ bool is_link) override;
virtual void DangerousDownloadValidated(
- WebContents* web_contents, int download_id, bool accept) OVERRIDE;
+ WebContents* web_contents, int download_id, bool accept) override;
// DownloadItem::Observer interface.
- virtual void OnDownloadUpdated(DownloadItem* item) OVERRIDE;
+ virtual void OnDownloadUpdated(DownloadItem* item) override;
typedef base::Callback<void(const DownloadInfoAndroid&)>
GetDownloadInfoCB;
diff --git a/chromium/content/browser/android/edge_effect.cc b/chromium/content/browser/android/edge_effect.cc
index 94e5b512e20..00c1aa51c0c 100644
--- a/chromium/content/browser/android/edge_effect.cc
+++ b/chromium/content/browser/android/edge_effect.cc
@@ -5,27 +5,21 @@
#include "content/browser/android/edge_effect.h"
#include "cc/layers/layer.h"
+#include "cc/layers/ui_resource_layer.h"
+#include "ui/base/android/system_ui_resource_manager.h"
namespace content {
namespace {
-enum State {
- STATE_IDLE = 0,
- STATE_PULL,
- STATE_ABSORB,
- STATE_RECEDE,
- STATE_PULL_DECAY
-};
-
// Time it will take the effect to fully recede in ms
-const int kRecedeTime = 1000;
+const int kRecedeTimeMs = 1000;
// Time it will take before a pulled glow begins receding in ms
-const int kPullTime = 167;
+const int kPullTimeMs = 167;
// Time it will take in ms for a pulled glow to decay before release
-const int kPullDecayTime = 1000;
+const int kPullDecayTimeMs = 1000;
const float kMaxAlpha = 1.f;
const float kHeldEdgeScaleY = .5f;
@@ -41,7 +35,7 @@ const float kMaxVelocity = 10000.f;
const float kEpsilon = 0.001f;
-const float kGlowHeightToWidthRatio = 0.25f;
+const float kGlowHeightWidthRatio = 0.25f;
// How much dragging should effect the height of the edge image.
// Number determined by user testing.
@@ -55,6 +49,9 @@ const float kPullDistanceAlphaGlowFactor = 1.1f;
const int kVelocityEdgeFactor = 8;
const int kVelocityGlowFactor = 12;
+const float kEdgeHeightAtMdpi = 12.f;
+const float kGlowHeightAtMdpi = 128.f;
+
template <typename T>
T Lerp(T a, T b, T t) {
return a + (b - a) * t;
@@ -62,7 +59,7 @@ T Lerp(T a, T b, T t) {
template <typename T>
T Clamp(T value, T low, T high) {
- return value < low ? low : (value > high ? high : value);
+ return value < low ? low : (value > high ? high : value);
}
template <typename T>
@@ -76,110 +73,88 @@ T Damp(T input, T factor) {
return result;
}
-gfx::Transform ComputeTransform(EdgeEffect::Edge edge,
- const gfx::SizeF& window_size,
- int offset,
- int height) {
- // Edge effects that require rotation are translated to the center about which
- // the layer should be rotated to align with the corresponding edge.
- switch (edge) {
- case EdgeEffect::EDGE_TOP:
- return gfx::Transform(1, 0, 0, 1, 0, offset);
- case EdgeEffect::EDGE_LEFT:
- return gfx::Transform(0, 1, -1, 0,
- (-window_size.height() + height) / 2.f + offset,
- (window_size.height() - height) / 2.f);
- case EdgeEffect::EDGE_BOTTOM:
- return gfx::Transform(-1, 0, 0, -1,
- 0, window_size.height() - height + offset);
- case EdgeEffect::EDGE_RIGHT:
- return gfx::Transform(0, -1, 1, 0,
- (-window_size.height() - height) / 2.f + window_size.width() + offset,
- (window_size.height() - height) / 2.f);
- default:
- NOTREACHED() << "Invalid edge: " << edge;
- return gfx::Transform();
- };
-}
+} // namespace
-gfx::Size ComputeBounds(EdgeEffect::Edge edge,
- const gfx::SizeF& window_size,
- int height) {
- switch (edge) {
- case EdgeEffect::EDGE_TOP:
- case EdgeEffect::EDGE_BOTTOM:
- return gfx::Size(window_size.width(), height);
- case EdgeEffect::EDGE_LEFT:
- case EdgeEffect::EDGE_RIGHT:
- return gfx::Size(window_size.height(), height);
- default:
- NOTREACHED() << "Invalid edge: " << edge;
- return gfx::Size();
- };
-}
+class EdgeEffect::EffectLayer {
+ public:
+ EffectLayer(ui::SystemUIResourceManager::ResourceType resource_type,
+ ui::SystemUIResourceManager* resource_manager)
+ : ui_resource_layer_(cc::UIResourceLayer::Create()),
+ resource_type_(resource_type),
+ resource_manager_(resource_manager) {}
-void DisableLayer(cc::Layer* layer) {
- DCHECK(layer);
- layer->SetIsDrawable(false);
- layer->SetTransform(gfx::Transform());
- layer->SetOpacity(1.f);
-}
+ ~EffectLayer() { ui_resource_layer_->RemoveFromParent(); }
-void UpdateLayer(cc::Layer* layer,
- EdgeEffect::Edge edge,
- const gfx::SizeF& window_size,
- int offset,
- int height,
- float opacity) {
- DCHECK(layer);
- layer->SetIsDrawable(true);
- gfx::Size bounds = ComputeBounds(edge, window_size, height);
- layer->SetTransformOrigin(
- gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0));
- layer->SetTransform(ComputeTransform(edge, window_size, offset, height));
- layer->SetBounds(bounds);
- layer->SetOpacity(Clamp(opacity, 0.f, 1.f));
-}
+ void SetParent(cc::Layer* parent) {
+ if (ui_resource_layer_->parent() != parent)
+ parent->AddChild(ui_resource_layer_);
+ ui_resource_layer_->SetUIResourceId(
+ resource_manager_->GetUIResourceId(resource_type_));
+ }
+
+ void Disable() { ui_resource_layer_->SetIsDrawable(false); }
+
+ void Update(const gfx::Size& size,
+ const gfx::Transform& transform,
+ float opacity) {
+ ui_resource_layer_->SetUIResourceId(
+ resource_manager_->GetUIResourceId(resource_type_));
+ ui_resource_layer_->SetIsDrawable(true);
+ ui_resource_layer_->SetTransformOrigin(
+ gfx::Point3F(size.width() * 0.5f, 0, 0));
+ ui_resource_layer_->SetTransform(transform);
+ ui_resource_layer_->SetBounds(size);
+ ui_resource_layer_->SetOpacity(Clamp(opacity, 0.f, 1.f));
+ }
+
+ scoped_refptr<cc::UIResourceLayer> ui_resource_layer_;
+ ui::SystemUIResourceManager::ResourceType resource_type_;
+ ui::SystemUIResourceManager* resource_manager_;
-} // namespace
-
-EdgeEffect::EdgeEffect(scoped_refptr<cc::Layer> edge,
- scoped_refptr<cc::Layer> glow)
- : edge_(edge)
- , glow_(glow)
- , edge_alpha_(0)
- , edge_scale_y_(0)
- , glow_alpha_(0)
- , glow_scale_y_(0)
- , edge_alpha_start_(0)
- , edge_alpha_finish_(0)
- , edge_scale_y_start_(0)
- , edge_scale_y_finish_(0)
- , glow_alpha_start_(0)
- , glow_alpha_finish_(0)
- , glow_scale_y_start_(0)
- , glow_scale_y_finish_(0)
- , state_(STATE_IDLE)
- , pull_distance_(0) {
- // Prevent the provided layers from drawing until the effect is activated.
- DisableLayer(edge_.get());
- DisableLayer(glow_.get());
+ DISALLOW_COPY_AND_ASSIGN(EffectLayer);
+};
+
+EdgeEffect::EdgeEffect(ui::SystemUIResourceManager* resource_manager,
+ float device_scale_factor)
+ : edge_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_EDGE,
+ resource_manager)),
+ glow_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_GLOW,
+ resource_manager)),
+ base_edge_height_(kEdgeHeightAtMdpi * device_scale_factor),
+ base_glow_height_(kGlowHeightAtMdpi * device_scale_factor),
+ edge_alpha_(0),
+ edge_scale_y_(0),
+ glow_alpha_(0),
+ glow_scale_y_(0),
+ edge_alpha_start_(0),
+ edge_alpha_finish_(0),
+ edge_scale_y_start_(0),
+ edge_scale_y_finish_(0),
+ glow_alpha_start_(0),
+ glow_alpha_finish_(0),
+ glow_scale_y_start_(0),
+ glow_scale_y_finish_(0),
+ state_(STATE_IDLE),
+ pull_distance_(0) {
}
-EdgeEffect::~EdgeEffect() { }
+EdgeEffect::~EdgeEffect() {
+}
bool EdgeEffect::IsFinished() const {
return state_ == STATE_IDLE;
}
void EdgeEffect::Finish() {
- DisableLayer(edge_.get());
- DisableLayer(glow_.get());
+ edge_->Disable();
+ glow_->Disable();
pull_distance_ = 0;
state_ = STATE_IDLE;
}
-void EdgeEffect::Pull(base::TimeTicks current_time, float delta_distance) {
+void EdgeEffect::Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) {
if (state_ == STATE_PULL_DECAY && current_time - start_time_ < duration_) {
return;
}
@@ -189,15 +164,15 @@ void EdgeEffect::Pull(base::TimeTicks current_time, float delta_distance) {
state_ = STATE_PULL;
start_time_ = current_time;
- duration_ = base::TimeDelta::FromMilliseconds(kPullTime);
+ duration_ = base::TimeDelta::FromMilliseconds(kPullTimeMs);
float abs_delta_distance = std::abs(delta_distance);
pull_distance_ += delta_distance;
float distance = std::abs(pull_distance_);
edge_alpha_ = edge_alpha_start_ = Clamp(distance, kPullEdgeBegin, kMaxAlpha);
- edge_scale_y_ = edge_scale_y_start_
- = Clamp(distance * kPullDistanceEdgeFactor, kHeldEdgeScaleY, 1.f);
+ edge_scale_y_ = edge_scale_y_start_ =
+ Clamp(distance * kPullDistanceEdgeFactor, kHeldEdgeScaleY, 1.f);
glow_alpha_ = glow_alpha_start_ =
std::min(kMaxAlpha,
@@ -212,7 +187,8 @@ void EdgeEffect::Pull(base::TimeTicks current_time, float delta_distance) {
// Do not allow glow to get larger than kMaxGlowHeight.
glow_scale_y_ = glow_scale_y_start_ =
Clamp(glow_scale_y_ + glow_change * kPullDistanceGlowFactor,
- 0.f, kMaxGlowHeight);
+ 0.f,
+ kMaxGlowHeight);
edge_alpha_finish_ = edge_alpha_;
edge_scale_y_finish_ = edge_scale_y_;
@@ -238,7 +214,7 @@ void EdgeEffect::Release(base::TimeTicks current_time) {
glow_scale_y_finish_ = 0.f;
start_time_ = current_time;
- duration_ = base::TimeDelta::FromMilliseconds(kRecedeTime);
+ duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
}
void EdgeEffect::Absorb(base::TimeTicks current_time, float velocity) {
@@ -262,19 +238,18 @@ void EdgeEffect::Absorb(base::TimeTicks current_time, float velocity) {
// reflect the strength of the user's scrolling.
edge_alpha_finish_ = Clamp(velocity * kVelocityEdgeFactor, 0.f, 1.f);
// Edge should never get larger than the size of its asset.
- edge_scale_y_finish_ = Clamp(velocity * kVelocityEdgeFactor,
- kHeldEdgeScaleY, 1.f);
+ edge_scale_y_finish_ =
+ Clamp(velocity * kVelocityEdgeFactor, kHeldEdgeScaleY, 1.f);
// Growth for the size of the glow should be quadratic to properly
// respond
// to a user's scrolling speed. The faster the scrolling speed, the more
// intense the effect should be for both the size and the saturation.
- glow_scale_y_finish_ = std::min(
- 0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
+ glow_scale_y_finish_ =
+ std::min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
// Alpha should change for the glow as well as size.
- glow_alpha_finish_ = Clamp(glow_alpha_start_,
- velocity * kVelocityGlowFactor * .00001f,
- kMaxAlpha);
+ glow_alpha_finish_ = Clamp(
+ glow_alpha_start_, velocity * kVelocityGlowFactor * .00001f, kMaxAlpha);
}
bool EdgeEffect::Update(base::TimeTicks current_time) {
@@ -295,7 +270,7 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
case STATE_ABSORB:
state_ = STATE_RECEDE;
start_time_ = current_time;
- duration_ = base::TimeDelta::FromMilliseconds(kRecedeTime);
+ duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
edge_alpha_start_ = edge_alpha_;
edge_scale_y_start_ = edge_scale_y_;
@@ -311,7 +286,7 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
case STATE_PULL:
state_ = STATE_PULL_DECAY;
start_time_ = current_time;
- duration_ = base::TimeDelta::FromMilliseconds(kPullDecayTime);
+ duration_ = base::TimeDelta::FromMilliseconds(kPullDecayTimeMs);
edge_alpha_start_ = edge_alpha_;
edge_scale_y_start_ = edge_scale_y_;
@@ -327,10 +302,12 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
case STATE_PULL_DECAY: {
// When receding, we want edge to decrease more slowly
// than the glow.
- const float factor = glow_scale_y_finish_ != 0 ?
- 1 / (glow_scale_y_finish_ * glow_scale_y_finish_) :
- std::numeric_limits<float>::max();
- edge_scale_y_ = edge_scale_y_start_ +
+ const float factor =
+ glow_scale_y_finish_
+ ? 1 / (glow_scale_y_finish_ * glow_scale_y_finish_)
+ : std::numeric_limits<float>::max();
+ edge_scale_y_ =
+ edge_scale_y_start_ +
(edge_scale_y_finish_ - edge_scale_y_start_) * interp * factor;
state_ = STATE_RECEDE;
} break;
@@ -348,33 +325,47 @@ bool EdgeEffect::Update(base::TimeTicks current_time) {
return !IsFinished();
}
-void EdgeEffect::ApplyToLayers(gfx::SizeF window_size,
- Edge edge,
- float edge_height,
- float glow_height,
- float offset) {
+void EdgeEffect::ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) {
if (IsFinished())
return;
// An empty window size, while meaningless, is also relatively harmless, and
// will simply prevent any drawing of the layers.
- if (window_size.IsEmpty()) {
- DisableLayer(edge_.get());
- DisableLayer(glow_.get());
+ if (size.IsEmpty()) {
+ edge_->Disable();
+ glow_->Disable();
return;
}
// Glow
const int scaled_glow_height = static_cast<int>(
- std::min(glow_height * glow_scale_y_ * kGlowHeightToWidthRatio * 0.6f,
- glow_height * kMaxGlowHeight) + 0.5f);
- UpdateLayer(
- glow_.get(), edge, window_size, offset, scaled_glow_height, glow_alpha_);
+ std::min(base_glow_height_ * glow_scale_y_ * kGlowHeightWidthRatio * 0.6f,
+ base_glow_height_ * kMaxGlowHeight) +
+ 0.5f);
+ const gfx::Size glow_size(size.width(), scaled_glow_height);
+ glow_->Update(glow_size, transform, glow_alpha_);
// Edge
- const int scaled_edge_height = static_cast<int>(edge_height * edge_scale_y_);
- UpdateLayer(
- edge_.get(), edge, window_size, offset, scaled_edge_height, edge_alpha_);
+ const int scaled_edge_height =
+ static_cast<int>(base_edge_height_ * edge_scale_y_);
+ const gfx::Size edge_size(size.width(), scaled_edge_height);
+ edge_->Update(edge_size, transform, edge_alpha_);
+}
+
+void EdgeEffect::SetParent(cc::Layer* parent) {
+ edge_->SetParent(parent);
+ glow_->SetParent(parent);
+}
+
+// static
+void EdgeEffect::PreloadResources(
+ ui::SystemUIResourceManager* resource_manager) {
+ DCHECK(resource_manager);
+ resource_manager->PreloadResource(
+ ui::SystemUIResourceManager::OVERSCROLL_EDGE);
+ resource_manager->PreloadResource(
+ ui::SystemUIResourceManager::OVERSCROLL_GLOW);
}
-} // namespace content
+} // namespace content
diff --git a/chromium/content/browser/android/edge_effect.h b/chromium/content/browser/android/edge_effect.h
index b8febba22d2..8fb5c5f55d3 100644
--- a/chromium/content/browser/android/edge_effect.h
+++ b/chromium/content/browser/android/edge_effect.h
@@ -5,63 +5,53 @@
#ifndef CONTENT_BROWSER_ANDROID_EDGE_EFFECT_H_
#define CONTENT_BROWSER_ANDROID_EDGE_EFFECT_H_
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "ui/gfx/size_f.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/android/edge_effect_base.h"
namespace cc {
class Layer;
}
+namespace ui {
+class SystemUIResourceManager;
+}
+
namespace content {
-/* |EdgeEffect| mirrors its Android counterpart, EdgeEffect.java.
- * The primary difference is ownership; the Android version manages render
- * resources directly, while this version simply applies the effect to
- * existing resources. Conscious tradeoffs were made to align this as closely
- * as possible with the original Android java version.
- * All coordinates and dimensions are in device pixels.
- */
-class EdgeEffect {
-public:
- enum Edge {
- EDGE_TOP = 0,
- EDGE_LEFT,
- EDGE_BOTTOM,
- EDGE_RIGHT,
- EDGE_COUNT
- };
-
- EdgeEffect(scoped_refptr<cc::Layer> edge, scoped_refptr<cc::Layer> glow);
- ~EdgeEffect();
-
- void Pull(base::TimeTicks current_time, float delta_distance);
- void Absorb(base::TimeTicks current_time, float velocity);
- bool Update(base::TimeTicks current_time);
- void Release(base::TimeTicks current_time);
-
- void Finish();
- bool IsFinished() const;
-
- void ApplyToLayers(gfx::SizeF window_size,
- Edge edge,
- float edge_height,
- float glow_height,
- float offset);
-
-private:
-
- enum State {
- STATE_IDLE = 0,
- STATE_PULL,
- STATE_ABSORB,
- STATE_RECEDE,
- STATE_PULL_DECAY
- };
-
- scoped_refptr<cc::Layer> edge_;
- scoped_refptr<cc::Layer> glow_;
+// |EdgeEffect| mirrors its Android counterpart, EdgeEffect.java.
+// Conscious tradeoffs were made to align this as closely as possible with the
+// the original Android java version.
+// All coordinates and dimensions are in device pixels.
+class EdgeEffect : public EdgeEffectBase {
+ public:
+ explicit EdgeEffect(ui::SystemUIResourceManager* resource_manager,
+ float device_scale_factor);
+ virtual ~EdgeEffect();
+
+ virtual void Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) override;
+ virtual void Absorb(base::TimeTicks current_time, float velocity) override;
+ virtual bool Update(base::TimeTicks current_time) override;
+ virtual void Release(base::TimeTicks current_time) override;
+
+ virtual void Finish() override;
+ virtual bool IsFinished() const override;
+
+ virtual void ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) override;
+ virtual void SetParent(cc::Layer* parent) override;
+
+ // Thread-safe trigger to load resources.
+ static void PreloadResources(ui::SystemUIResourceManager* resource_manager);
+
+ private:
+ class EffectLayer;
+ scoped_ptr<EffectLayer> edge_;
+ scoped_ptr<EffectLayer> glow_;
+
+ float base_edge_height_;
+ float base_glow_height_;
float edge_alpha_;
float edge_scale_y_;
diff --git a/chromium/content/browser/android/edge_effect_base.h b/chromium/content/browser/android/edge_effect_base.h
new file mode 100644
index 00000000000..f7df20dfe16
--- /dev/null
+++ b/chromium/content/browser/android/edge_effect_base.h
@@ -0,0 +1,49 @@
+// 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_ANDROID_EDGE_EFFECT_BASE_H_
+#define CONTENT_BROWSER_ANDROID_EDGE_EFFECT_BASE_H_
+
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+class Layer;
+}
+
+namespace content {
+
+// A base class for overscroll-related Android effects.
+class EdgeEffectBase {
+ public:
+ enum State {
+ STATE_IDLE = 0,
+ STATE_PULL,
+ STATE_ABSORB,
+ STATE_RECEDE,
+ STATE_PULL_DECAY
+ };
+
+ virtual ~EdgeEffectBase() {}
+
+ virtual void Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) = 0;
+ virtual void Absorb(base::TimeTicks current_time, float velocity) = 0;
+ virtual bool Update(base::TimeTicks current_time) = 0;
+ virtual void Release(base::TimeTicks current_time) = 0;
+
+ virtual void Finish() = 0;
+ virtual bool IsFinished() const = 0;
+
+ virtual void ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) = 0;
+ virtual void SetParent(cc::Layer* parent) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_EDGE_EFFECT_BASE_H_
diff --git a/chromium/content/browser/android/edge_effect_l.cc b/chromium/content/browser/android/edge_effect_l.cc
new file mode 100644
index 00000000000..ccec8a41c47
--- /dev/null
+++ b/chromium/content/browser/android/edge_effect_l.cc
@@ -0,0 +1,286 @@
+// 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/android/edge_effect_l.h"
+
+#include "cc/layers/ui_resource_layer.h"
+#include "ui/base/android/system_ui_resource_manager.h"
+
+namespace content {
+
+namespace {
+
+// Time it will take the effect to fully recede in ms
+const int kRecedeTimeMs = 600;
+
+// Time it will take before a pulled glow begins receding in ms
+const int kPullTimeMs = 167;
+
+// Time it will take for a pulled glow to decay to partial strength before
+// release
+const int kPullDecayTimeMs = 2000;
+
+const float kMaxAlpha = 0.5f;
+
+const float kPullGlowBegin = 0.f;
+
+// Min/max velocity that will be absorbed
+const float kMinVelocity = 100.f;
+const float kMaxVelocity = 10000.f;
+
+const float kEpsilon = 0.001f;
+
+const float kSin = 0.5f; // sin(PI / 6)
+const float kCos = 0.866f; // cos(PI / 6);
+
+// How much dragging should effect the height of the glow image.
+// Number determined by user testing.
+const float kPullDistanceAlphaGlowFactor = 0.8f;
+
+const int kVelocityGlowFactor = 6;
+
+const ui::SystemUIResourceManager::ResourceType kResourceType =
+ ui::SystemUIResourceManager::OVERSCROLL_GLOW_L;
+
+template <typename T>
+T Lerp(T a, T b, T t) {
+ return a + (b - a) * t;
+}
+
+template <typename T>
+T Clamp(T value, T low, T high) {
+ return value < low ? low : (value > high ? high : value);
+}
+
+template <typename T>
+T Damp(T input, T factor) {
+ T result;
+ if (factor == 1) {
+ result = 1 - (1 - input) * (1 - input);
+ } else {
+ result = 1 - std::pow(1 - input, 2 * factor);
+ }
+ return result;
+}
+
+} // namespace
+
+EdgeEffectL::EdgeEffectL(ui::SystemUIResourceManager* resource_manager)
+ : resource_manager_(resource_manager),
+ glow_(cc::UIResourceLayer::Create()),
+ glow_alpha_(0),
+ glow_scale_y_(0),
+ glow_alpha_start_(0),
+ glow_alpha_finish_(0),
+ glow_scale_y_start_(0),
+ glow_scale_y_finish_(0),
+ displacement_(0.5f),
+ target_displacement_(0.5f),
+ state_(STATE_IDLE),
+ pull_distance_(0) {
+ // Prevent the provided layers from drawing until the effect is activated.
+ glow_->SetIsDrawable(false);
+}
+
+EdgeEffectL::~EdgeEffectL() {
+ glow_->RemoveFromParent();
+}
+
+bool EdgeEffectL::IsFinished() const {
+ return state_ == STATE_IDLE;
+}
+
+void EdgeEffectL::Finish() {
+ glow_->SetIsDrawable(false);
+ pull_distance_ = 0;
+ state_ = STATE_IDLE;
+}
+
+void EdgeEffectL::Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) {
+ target_displacement_ = displacement;
+ if (state_ == STATE_PULL_DECAY && current_time - start_time_ < duration_) {
+ return;
+ }
+ if (state_ != STATE_PULL) {
+ glow_scale_y_ = std::max(kPullGlowBegin, glow_scale_y_);
+ }
+ state_ = STATE_PULL;
+
+ start_time_ = current_time;
+ duration_ = base::TimeDelta::FromMilliseconds(kPullTimeMs);
+
+ float abs_delta_distance = std::abs(delta_distance);
+ pull_distance_ += delta_distance;
+
+ glow_alpha_ = glow_alpha_start_ = std::min(
+ kMaxAlpha,
+ glow_alpha_ + (abs_delta_distance * kPullDistanceAlphaGlowFactor));
+
+ if (pull_distance_ == 0) {
+ glow_scale_y_ = glow_scale_y_start_ = 0;
+ } else {
+ float scale = 1.f -
+ 1.f / std::sqrt(std::abs(pull_distance_) * bounds_.height()) -
+ 0.3f;
+ glow_scale_y_ = glow_scale_y_start_ = std::max(0.f, scale) / 0.7f;
+ }
+
+ glow_alpha_finish_ = glow_alpha_;
+ glow_scale_y_finish_ = glow_scale_y_;
+}
+
+void EdgeEffectL::Release(base::TimeTicks current_time) {
+ pull_distance_ = 0;
+
+ if (state_ != STATE_PULL && state_ != STATE_PULL_DECAY)
+ return;
+
+ state_ = STATE_RECEDE;
+ glow_alpha_start_ = glow_alpha_;
+ glow_scale_y_start_ = glow_scale_y_;
+
+ glow_alpha_finish_ = 0.f;
+ glow_scale_y_finish_ = 0.f;
+
+ start_time_ = current_time;
+ duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
+}
+
+void EdgeEffectL::Absorb(base::TimeTicks current_time, float velocity) {
+ state_ = STATE_ABSORB;
+
+ velocity = Clamp(std::abs(velocity), kMinVelocity, kMaxVelocity);
+
+ start_time_ = current_time;
+ // This should never be less than 1 millisecond.
+ duration_ = base::TimeDelta::FromMilliseconds(0.15f + (velocity * 0.02f));
+
+ // The glow depends more on the velocity, and therefore starts out
+ // nearly invisible.
+ glow_alpha_start_ = 0.3f;
+ glow_scale_y_start_ = std::max(glow_scale_y_, 0.f);
+
+ // Growth for the size of the glow should be quadratic to properly respond
+ // to a user's scrolling speed. The faster the scrolling speed, the more
+ // intense the effect should be for both the size and the saturation.
+ glow_scale_y_finish_ =
+ std::min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2.f, 1.f);
+ // Alpha should change for the glow as well as size.
+ glow_alpha_finish_ = Clamp(
+ glow_alpha_start_, velocity * kVelocityGlowFactor * .00001f, kMaxAlpha);
+ target_displacement_ = 0.5;
+}
+
+bool EdgeEffectL::Update(base::TimeTicks current_time) {
+ if (IsFinished())
+ return false;
+
+ const double dt = (current_time - start_time_).InMilliseconds();
+ const double t = std::min(dt / duration_.InMilliseconds(), 1.);
+ const float interp = static_cast<float>(Damp(t, 1.));
+
+ glow_alpha_ = Lerp(glow_alpha_start_, glow_alpha_finish_, interp);
+ glow_scale_y_ = Lerp(glow_scale_y_start_, glow_scale_y_finish_, interp);
+ displacement_ = (displacement_ + target_displacement_) / 2.f;
+
+ if (t >= 1.f - kEpsilon) {
+ switch (state_) {
+ case STATE_ABSORB:
+ state_ = STATE_RECEDE;
+ start_time_ = current_time;
+ duration_ = base::TimeDelta::FromMilliseconds(kRecedeTimeMs);
+
+ glow_alpha_start_ = glow_alpha_;
+ glow_scale_y_start_ = glow_scale_y_;
+
+ glow_alpha_finish_ = 0.f;
+ glow_scale_y_finish_ = 0.f;
+ break;
+ case STATE_PULL:
+ state_ = STATE_PULL_DECAY;
+ start_time_ = current_time;
+ duration_ = base::TimeDelta::FromMilliseconds(kPullDecayTimeMs);
+
+ glow_alpha_start_ = glow_alpha_;
+ glow_scale_y_start_ = glow_scale_y_;
+
+ // After pull, the glow should fade to nothing.
+ glow_alpha_finish_ = 0.f;
+ glow_scale_y_finish_ = 0.f;
+ break;
+ case STATE_PULL_DECAY:
+ state_ = STATE_RECEDE;
+ break;
+ case STATE_RECEDE:
+ Finish();
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool one_last_frame = false;
+ if (state_ == STATE_RECEDE && glow_scale_y_ <= 0) {
+ Finish();
+ one_last_frame = true;
+ }
+
+ return !IsFinished() || one_last_frame;
+}
+
+void EdgeEffectL::ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) {
+ if (IsFinished())
+ return;
+
+ // An empty window size, while meaningless, is also relatively harmless, and
+ // will simply prevent any drawing of the layers.
+ if (size.IsEmpty()) {
+ glow_->SetIsDrawable(false);
+ return;
+ }
+
+ const float r = size.width() * 0.75f / kSin;
+ const float y = kCos * r;
+ const float h = r - y;
+ const float o_r = size.height() * 0.75f / kSin;
+ const float o_y = kCos * o_r;
+ const float o_h = o_r - o_y;
+ const float base_glow_scale = h > 0.f ? std::min(o_h / h, 1.f) : 1.f;
+ bounds_ = gfx::Size(size.width(), (int)std::min(size.height(), h));
+ gfx::Size image_bounds(
+ r, std::min(1.f, glow_scale_y_) * base_glow_scale * bounds_.height());
+
+ glow_->SetIsDrawable(true);
+ glow_->SetUIResourceId(resource_manager_->GetUIResourceId(kResourceType));
+ glow_->SetTransformOrigin(gfx::Point3F(bounds_.width() * 0.5f, 0, 0));
+ glow_->SetBounds(image_bounds);
+ glow_->SetContentsOpaque(false);
+ glow_->SetOpacity(Clamp(glow_alpha_, 0.f, 1.f));
+
+ const float displacement = Clamp(displacement_, 0.f, 1.f) - 0.5f;
+ const float displacement_offset_x = bounds_.width() * displacement * 0.5f;
+ const float image_offset_x = (bounds_.width() - image_bounds.width()) * 0.5f;
+ gfx::Transform offset_transform;
+ offset_transform.Translate(image_offset_x - displacement_offset_x, 0);
+ offset_transform.ConcatTransform(transform);
+ glow_->SetTransform(offset_transform);
+}
+
+void EdgeEffectL::SetParent(cc::Layer* parent) {
+ if (glow_->parent() != parent)
+ parent->AddChild(glow_);
+ glow_->SetUIResourceId(resource_manager_->GetUIResourceId(kResourceType));
+}
+
+// static
+void EdgeEffectL::PreloadResources(
+ ui::SystemUIResourceManager* resource_manager) {
+ DCHECK(resource_manager);
+ resource_manager->PreloadResource(kResourceType);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/edge_effect_l.h b/chromium/content/browser/android/edge_effect_l.h
new file mode 100644
index 00000000000..a24309c8da3
--- /dev/null
+++ b/chromium/content/browser/android/edge_effect_l.h
@@ -0,0 +1,81 @@
+// 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_ANDROID_EDGE_EFFECT_L_H_
+#define CONTENT_BROWSER_ANDROID_EDGE_EFFECT_L_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/android/edge_effect_base.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+class Layer;
+class UIResourceLayer;
+}
+
+namespace ui {
+class SystemUIResourceManager;
+}
+
+namespace content {
+
+// |EdgeEffectL| mirrors its Android L counterpart, EdgeEffect.java.
+// Conscious tradeoffs were made to align this as closely as possible with the
+// the original Android java version.
+// All coordinates and dimensions are in device pixels.
+class EdgeEffectL : public EdgeEffectBase {
+ public:
+ explicit EdgeEffectL(ui::SystemUIResourceManager* resource_manager);
+ virtual ~EdgeEffectL();
+
+ virtual void Pull(base::TimeTicks current_time,
+ float delta_distance,
+ float displacement) override;
+ virtual void Absorb(base::TimeTicks current_time, float velocity) override;
+ virtual bool Update(base::TimeTicks current_time) override;
+ virtual void Release(base::TimeTicks current_time) override;
+
+ virtual void Finish() override;
+ virtual bool IsFinished() const override;
+
+ virtual void ApplyToLayers(const gfx::SizeF& size,
+ const gfx::Transform& transform) override;
+ virtual void SetParent(cc::Layer* parent) override;
+
+ // Thread-safe trigger to load resources.
+ static void PreloadResources(ui::SystemUIResourceManager* resource_manager);
+
+ private:
+ ui::SystemUIResourceManager* const resource_manager_;
+
+ scoped_refptr<cc::UIResourceLayer> glow_;
+
+ float glow_alpha_;
+ float glow_scale_y_;
+
+ float glow_alpha_start_;
+ float glow_alpha_finish_;
+ float glow_scale_y_start_;
+ float glow_scale_y_finish_;
+
+ gfx::RectF arc_rect_;
+ gfx::Size bounds_;
+ float displacement_;
+ float target_displacement_;
+
+ base::TimeTicks start_time_;
+ base::TimeDelta duration_;
+
+ State state_;
+
+ float pull_distance_;
+
+ DISALLOW_COPY_AND_ASSIGN(EdgeEffectL);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_EDGE_EFFECT_L_H_
diff --git a/chromium/content/browser/android/gesture_event_type.h b/chromium/content/browser/android/gesture_event_type.h
index d41311c7598..ce87c901db3 100644
--- a/chromium/content/browser/android/gesture_event_type.h
+++ b/chromium/content/browser/android/gesture_event_type.h
@@ -7,10 +7,31 @@
namespace content {
+// This file contains a list of GestureEventType's usable by ContentViewCore,
+// providing a direct mapping to and from their corresponding
+// blink::WebGestureEvent types.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content.browser
enum GestureEventType {
-#define DEFINE_GESTURE_EVENT_TYPE(name, value) name = value,
-#include "content/browser/android/gesture_event_type_list.h"
-#undef DEFINE_GESTURE_EVENT_TYPE
+ GESTURE_EVENT_TYPE_SHOW_PRESS,
+ GESTURE_EVENT_TYPE_DOUBLE_TAP,
+ GESTURE_EVENT_TYPE_SINGLE_TAP_UP,
+ GESTURE_EVENT_TYPE_SINGLE_TAP_CONFIRMED,
+ GESTURE_EVENT_TYPE_SINGLE_TAP_UNCONFIRMED,
+ GESTURE_EVENT_TYPE_LONG_PRESS,
+ GESTURE_EVENT_TYPE_SCROLL_START,
+ GESTURE_EVENT_TYPE_SCROLL_BY,
+ GESTURE_EVENT_TYPE_SCROLL_END,
+ GESTURE_EVENT_TYPE_FLING_START,
+ GESTURE_EVENT_TYPE_FLING_CANCEL,
+ GESTURE_EVENT_TYPE_FLING_END,
+ GESTURE_EVENT_TYPE_PINCH_BEGIN,
+ GESTURE_EVENT_TYPE_PINCH_BY,
+ GESTURE_EVENT_TYPE_PINCH_END,
+ GESTURE_EVENT_TYPE_TAP_CANCEL,
+ GESTURE_EVENT_TYPE_LONG_TAP,
+ GESTURE_EVENT_TYPE_TAP_DOWN,
};
} // namespace content
diff --git a/chromium/content/browser/android/gesture_event_type_list.h b/chromium/content/browser/android/gesture_event_type_list.h
deleted file mode 100644
index 85af616cb47..00000000000
--- a/chromium/content/browser/android/gesture_event_type_list.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file intentionally does not have header guards because this file
-// is meant to be included inside a macro to generate enum values.
-
-// This file contains a list of GestureEventType's usable by ContentViewCore,
-// providing a direct mapping to and from their corresponding
-// blink::WebGestureEvent types.
-
-#ifndef DEFINE_GESTURE_EVENT_TYPE
-#error "Please define DEFINE_GESTURE_EVENT_TYPE before including this file."
-#endif
-
-DEFINE_GESTURE_EVENT_TYPE(SHOW_PRESS, 0)
-DEFINE_GESTURE_EVENT_TYPE(DOUBLE_TAP, 1)
-DEFINE_GESTURE_EVENT_TYPE(SINGLE_TAP_UP, 2)
-DEFINE_GESTURE_EVENT_TYPE(SINGLE_TAP_CONFIRMED, 3)
-DEFINE_GESTURE_EVENT_TYPE(SINGLE_TAP_UNCONFIRMED, 4)
-DEFINE_GESTURE_EVENT_TYPE(LONG_PRESS, 5)
-DEFINE_GESTURE_EVENT_TYPE(SCROLL_START, 6)
-DEFINE_GESTURE_EVENT_TYPE(SCROLL_BY, 7)
-DEFINE_GESTURE_EVENT_TYPE(SCROLL_END, 8)
-DEFINE_GESTURE_EVENT_TYPE(FLING_START, 9)
-DEFINE_GESTURE_EVENT_TYPE(FLING_CANCEL, 10)
-DEFINE_GESTURE_EVENT_TYPE(FLING_END, 11)
-DEFINE_GESTURE_EVENT_TYPE(PINCH_BEGIN, 12)
-DEFINE_GESTURE_EVENT_TYPE(PINCH_BY, 13)
-DEFINE_GESTURE_EVENT_TYPE(PINCH_END, 14)
-DEFINE_GESTURE_EVENT_TYPE(TAP_CANCEL, 15)
-DEFINE_GESTURE_EVENT_TYPE(LONG_TAP, 16)
-DEFINE_GESTURE_EVENT_TYPE(TAP_DOWN, 17)
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 c19173cd3cc..2bde4a45856 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
@@ -4,9 +4,12 @@
#include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
+#include "base/observer_list.h"
#include "content/browser/android/in_process/synchronous_compositor_output_surface.h"
#include "content/public/browser/browser_thread.h"
+#include "content/renderer/gpu/frame_swap_message_queue.h"
#include "gpu/command_buffer/client/gl_in_process_context.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "ui/gl/android/surface_texture.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_surface_stub.h"
@@ -31,48 +34,55 @@ blink::WebGraphicsContext3D::Attributes GetDefaultAttribs() {
}
using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+using webkit::gpu::WebGraphicsContext3DImpl;
scoped_ptr<gpu::GLInProcessContext> CreateOffscreenContext(
const blink::WebGraphicsContext3D::Attributes& attributes) {
const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
- gpu::GLInProcessContextAttribs in_process_attribs;
- WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
+ gpu::gles2::ContextCreationAttribHelper in_process_attribs;
+ WebGraphicsContext3DImpl::ConvertAttributes(
attributes, &in_process_attribs);
- in_process_attribs.lose_context_when_out_of_memory = 1;
-
- scoped_ptr<gpu::GLInProcessContext> context(
- gpu::GLInProcessContext::Create(NULL /* service */,
- NULL /* surface */,
- true /* is_offscreen */,
- gfx::kNullAcceleratedWidget,
- gfx::Size(1, 1),
- NULL /* share_context */,
- false /* share_resources */,
- in_process_attribs,
- gpu_preference));
+ in_process_attribs.lose_context_when_out_of_memory = true;
+
+ scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
+ NULL /* service */,
+ NULL /* surface */,
+ true /* is_offscreen */,
+ gfx::kNullAcceleratedWidget,
+ gfx::Size(1, 1),
+ NULL /* share_context */,
+ false /* share_resources */,
+ in_process_attribs,
+ gpu_preference,
+ gpu::GLInProcessContextSharedMemoryLimits(),
+ nullptr,
+ nullptr));
return context.Pass();
}
scoped_ptr<gpu::GLInProcessContext> CreateContext(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
- gpu::GLInProcessContext* share_context) {
+ const gpu::GLInProcessContextSharedMemoryLimits& mem_limits) {
const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
- gpu::GLInProcessContextAttribs in_process_attribs;
- WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
+ gpu::gles2::ContextCreationAttribHelper in_process_attribs;
+ WebGraphicsContext3DImpl::ConvertAttributes(
GetDefaultAttribs(), &in_process_attribs);
- in_process_attribs.lose_context_when_out_of_memory = 1;
-
- scoped_ptr<gpu::GLInProcessContext> context(
- gpu::GLInProcessContext::Create(service,
- NULL /* surface */,
- false /* is_offscreen */,
- gfx::kNullAcceleratedWidget,
- gfx::Size(1, 1),
- share_context,
- false /* share_resources */,
- in_process_attribs,
- gpu_preference));
+ in_process_attribs.lose_context_when_out_of_memory = true;
+
+ scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
+ service,
+ NULL /* surface */,
+ false /* is_offscreen */,
+ gfx::kNullAcceleratedWidget,
+ gfx::Size(1, 1),
+ NULL /* share_context */,
+ false /* share_resources */,
+ in_process_attribs,
+ gpu_preference,
+ mem_limits,
+ nullptr,
+ nullptr));
return context.Pass();
}
@@ -98,7 +108,9 @@ WrapContextWithAttributes(
context.Pass(), attributes));
}
-class VideoContextProvider
+} // namespace
+
+class SynchronousCompositorFactoryImpl::VideoContextProvider
: public StreamTextureFactorySynchronousImpl::ContextProvider {
public:
VideoContextProvider(
@@ -112,26 +124,40 @@ class VideoContextProvider
}
virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
- uint32 stream_id) OVERRIDE {
+ uint32 stream_id) override {
return gl_in_process_context_->GetSurfaceTexture(stream_id);
}
- virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE {
+ virtual gpu::gles2::GLES2Interface* ContextGL() override {
return context_provider_->ContextGL();
}
+ virtual void AddObserver(StreamTextureFactoryContextObserver* obs) override {
+ observer_list_.AddObserver(obs);
+ }
+
+ virtual void RemoveObserver(
+ StreamTextureFactoryContextObserver* obs) override {
+ observer_list_.RemoveObserver(obs);
+ }
+
+ void RestoreContext() {
+ FOR_EACH_OBSERVER(StreamTextureFactoryContextObserver,
+ observer_list_,
+ ResetStreamTextureProxy());
+ }
+
private:
friend class base::RefCountedThreadSafe<VideoContextProvider>;
virtual ~VideoContextProvider() {}
scoped_refptr<cc::ContextProvider> context_provider_;
gpu::GLInProcessContext* gl_in_process_context_;
+ ObserverList<StreamTextureFactoryContextObserver> observer_list_;
DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
};
-} // namespace
-
using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl()
@@ -153,10 +179,13 @@ SynchronousCompositorFactoryImpl::RecordFullLayer() {
}
scoped_ptr<cc::OutputSurface>
-SynchronousCompositorFactoryImpl::CreateOutputSurface(int routing_id) {
+SynchronousCompositorFactoryImpl::CreateOutputSurface(
+ int routing_id,
+ scoped_refptr<content::FrameSwapMessageQueue> frame_swap_message_queue) {
scoped_ptr<SynchronousCompositorOutputSurface> output_surface(
- new SynchronousCompositorOutputSurface(routing_id));
- return output_surface.PassAs<cc::OutputSurface>();
+ new SynchronousCompositorOutputSurface(routing_id,
+ frame_swap_message_queue));
+ return output_surface.Pass();
}
InputHandlerManagerClient*
@@ -164,43 +193,29 @@ SynchronousCompositorFactoryImpl::GetInputHandlerManagerClient() {
return synchronous_input_event_filter();
}
-scoped_refptr<ContextProviderWebContext> SynchronousCompositorFactoryImpl::
- GetSharedOffscreenContextProviderForMainThread() {
- bool failed = false;
- if ((!offscreen_context_for_main_thread_.get() ||
- offscreen_context_for_main_thread_->DestroyedOnMainThread())) {
- scoped_ptr<gpu::GLInProcessContext> context =
- CreateOffscreenContext(GetDefaultAttribs());
- offscreen_context_for_main_thread_ =
- webkit::gpu::ContextProviderInProcess::Create(
- WrapContext(context.Pass()),
- "Compositor-Offscreen-main-thread");
- failed = !offscreen_context_for_main_thread_.get() ||
- !offscreen_context_for_main_thread_->BindToCurrentThread();
- }
-
- if (failed) {
- offscreen_context_for_main_thread_ = NULL;
- }
- return offscreen_context_for_main_thread_;
+scoped_refptr<ContextProviderWebContext>
+SynchronousCompositorFactoryImpl::CreateOffscreenContextProvider(
+ const blink::WebGraphicsContext3D::Attributes& attributes,
+ const std::string& debug_name) {
+ scoped_ptr<gpu::GLInProcessContext> context =
+ CreateOffscreenContext(attributes);
+ return webkit::gpu::ContextProviderInProcess::Create(
+ WrapContext(context.Pass()), debug_name);
}
scoped_refptr<cc::ContextProvider> SynchronousCompositorFactoryImpl::
CreateOnscreenContextProviderForCompositorThread() {
- DCHECK(service_);
+ DCHECK(service_.get());
- if (!share_context_.get())
- share_context_ = CreateContext(service_, NULL);
+ gpu::GLInProcessContextSharedMemoryLimits mem_limits;
+ // This is half of what RenderWidget uses because synchronous compositor
+ // pipeline is only one frame deep.
+ mem_limits.mapped_memory_reclaim_limit = 6 * 1024 * 1024;
return webkit::gpu::ContextProviderInProcess::Create(
- WrapContext(CreateContext(service_, share_context_.get())),
+ WrapContext(CreateContext(service_, mem_limits)),
"Child-Compositor");
}
-gpu::GLInProcessContext* SynchronousCompositorFactoryImpl::GetShareContext() {
- DCHECK(share_context_.get());
- return share_context_.get();
-}
-
scoped_refptr<StreamTextureFactory>
SynchronousCompositorFactoryImpl::CreateStreamTextureFactory(int frame_id) {
scoped_refptr<StreamTextureFactorySynchronousImpl> factory(
@@ -212,7 +227,7 @@ SynchronousCompositorFactoryImpl::CreateStreamTextureFactory(int frame_id) {
return factory;
}
-blink::WebGraphicsContext3D*
+webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl*
SynchronousCompositorFactoryImpl::CreateOffscreenGraphicsContext3D(
const blink::WebGraphicsContext3D::Attributes& attributes) {
return WrapContextWithAttributes(CreateOffscreenContext(attributes),
@@ -222,6 +237,13 @@ SynchronousCompositorFactoryImpl::CreateOffscreenGraphicsContext3D(
void SynchronousCompositorFactoryImpl::CompositorInitializedHardwareDraw() {
base::AutoLock lock(num_hardware_compositor_lock_);
num_hardware_compositors_++;
+ if (num_hardware_compositors_ == 1 && main_thread_proxy_.get()) {
+ main_thread_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &SynchronousCompositorFactoryImpl::RestoreContextOnMainThread,
+ base::Unretained(this)));
+ }
}
void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw() {
@@ -230,6 +252,11 @@ void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw() {
num_hardware_compositors_--;
}
+void SynchronousCompositorFactoryImpl::RestoreContextOnMainThread() {
+ if (CanCreateMainThreadContext() && video_context_provider_.get())
+ video_context_provider_->RestoreContext();
+}
+
bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
base::AutoLock lock(num_hardware_compositor_lock_);
return num_hardware_compositors_ > 0;
@@ -237,25 +264,33 @@ bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
- scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
- context_provider;
- // This check only guarantees the main thread context is created after
- // a compositor did successfully initialize hardware draw in the past.
- // In particular this does not guarantee that the main thread context
- // will fail creation when all compositors release hardware draw.
- if (CanCreateMainThreadContext() && !video_context_provider_) {
- DCHECK(service_);
- DCHECK(share_context_.get());
+ {
+ base::AutoLock lock(num_hardware_compositor_lock_);
+ main_thread_proxy_ = base::MessageLoopProxy::current();
+ }
+
+ // Always fail creation even if |video_context_provider_| is not NULL.
+ // This is to avoid synchronous calls that may deadlock. Setting
+ // |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>();
+ }
+
+ if (!video_context_provider_.get()) {
+ DCHECK(service_.get());
video_context_provider_ = new VideoContextProvider(
- CreateContext(service_, share_context_.get()));
+ CreateContext(service_,
+ gpu::GLInProcessContextSharedMemoryLimits()));
}
return video_context_provider_;
}
void SynchronousCompositorFactoryImpl::SetDeferredGpuService(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
- DCHECK(!service_);
+ DCHECK(!service_.get());
service_ = service;
}
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 ddaef409a3d..dd7467a5849 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
@@ -31,18 +31,22 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
// SynchronousCompositorFactory
virtual scoped_refptr<base::MessageLoopProxy> GetCompositorMessageLoop()
- OVERRIDE;
- virtual bool RecordFullLayer() OVERRIDE;
- virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(int routing_id)
- OVERRIDE;
- virtual InputHandlerManagerClient* GetInputHandlerManagerClient() OVERRIDE;
+ override;
+ virtual bool RecordFullLayer() override;
+ virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
+ int routing_id,
+ scoped_refptr<content::FrameSwapMessageQueue> frame_swap_message_queue)
+ override;
+ virtual InputHandlerManagerClient* GetInputHandlerManagerClient() override;
virtual scoped_refptr<webkit::gpu::ContextProviderWebContext>
- GetSharedOffscreenContextProviderForMainThread() OVERRIDE;
+ CreateOffscreenContextProvider(
+ const blink::WebGraphicsContext3D::Attributes& attributes,
+ const std::string& debug_name) override;
virtual scoped_refptr<StreamTextureFactory> CreateStreamTextureFactory(
- int view_id) OVERRIDE;
- virtual blink::WebGraphicsContext3D* CreateOffscreenGraphicsContext3D(
- const blink::WebGraphicsContext3D::Attributes& attributes) OVERRIDE;
-
+ int view_id) override;
+ virtual webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl*
+ CreateOffscreenGraphicsContext3D(
+ const blink::WebGraphicsContext3D::Attributes& attributes) override;
SynchronousInputEventFilter* synchronous_input_event_filter() {
return &synchronous_input_event_filter_;
@@ -56,22 +60,19 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
scoped_refptr<cc::ContextProvider>
CreateOnscreenContextProviderForCompositorThread();
- gpu::GLInProcessContext* GetShareContext();
private:
bool CanCreateMainThreadContext();
scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
TryCreateStreamTextureFactory();
+ void RestoreContextOnMainThread();
SynchronousInputEventFilter synchronous_input_event_filter_;
- scoped_refptr<webkit::gpu::ContextProviderWebContext>
- offscreen_context_for_main_thread_;
-
scoped_refptr<gpu::InProcessCommandBuffer::Service> service_;
- scoped_ptr<gpu::GLInProcessContext> share_context_;
- scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
- video_context_provider_;
+
+ class VideoContextProvider;
+ scoped_refptr<VideoContextProvider> video_context_provider_;
bool record_full_layer_;
@@ -79,6 +80,7 @@ class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
// read on renderer main thread.
base::Lock num_hardware_compositor_lock_;
unsigned int num_hardware_compositors_;
+ scoped_refptr<base::MessageLoopProxy> main_thread_proxy_;
};
} // namespace content
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 1b5ccb74ab5..06be5be5696 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -115,23 +115,26 @@ void SynchronousCompositorImpl::ReleaseHwDraw() {
g_factory.Get().CompositorReleasedHardwareDraw();
}
-gpu::GLInProcessContext* SynchronousCompositorImpl::GetShareContext() {
- DCHECK(CalledOnValidThread());
- return g_factory.Get().GetShareContext();
-}
-
scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
gfx::Size surface_size,
const gfx::Transform& transform,
gfx::Rect viewport,
- gfx::Rect clip) {
+ gfx::Rect clip,
+ gfx::Rect viewport_rect_for_tile_priority,
+ const gfx::Transform& transform_for_tile_priority) {
DCHECK(CalledOnValidThread());
DCHECK(output_surface_);
scoped_ptr<cc::CompositorFrame> frame =
- output_surface_->DemandDrawHw(surface_size, transform, viewport, clip);
+ output_surface_->DemandDrawHw(surface_size,
+ transform,
+ viewport,
+ clip,
+ viewport_rect_for_tile_priority,
+ transform_for_tile_priority);
if (frame.get())
UpdateFrameMetaData(frame->metadata);
+
return frame.Pass();
}
@@ -157,14 +160,14 @@ void SynchronousCompositorImpl::UpdateFrameMetaData(
contents_->GetRenderWidgetHostView());
if (rwhv)
rwhv->SynchronousFrameMetadata(frame_metadata);
+ DeliverMessages();
}
-void SynchronousCompositorImpl::SetMemoryPolicy(
- const SynchronousCompositorMemoryPolicy& policy) {
+void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit) {
DCHECK(CalledOnValidThread());
DCHECK(output_surface_);
- output_surface_->SetMemoryPolicy(policy);
+ output_surface_->SetMemoryPolicy(bytes_limit);
}
void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
@@ -236,16 +239,31 @@ InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
contents_->GetRoutingID(), input_event);
}
+void SynchronousCompositorImpl::DeliverMessages() {
+ ScopedVector<IPC::Message> messages;
+ output_surface_->GetMessagesToDeliver(&messages);
+ RenderProcessHost* rph = contents_->GetRenderProcessHost();
+ for (ScopedVector<IPC::Message>::const_iterator i = messages.begin();
+ i != messages.end();
+ ++i) {
+ rph->OnMessageReceived(**i);
+ }
+}
+
void SynchronousCompositorImpl::DidActivatePendingTree() {
if (compositor_client_)
compositor_client_->DidUpdateContent();
}
-gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() {
+gfx::ScrollOffset SynchronousCompositorImpl::GetTotalScrollOffset() {
DCHECK(CalledOnValidThread());
- if (compositor_client_)
- return compositor_client_->GetTotalRootLayerScrollOffset();
- return gfx::Vector2dF();
+ if (compositor_client_) {
+ // TODO(miletus): Make GetTotalRootLayerScrollOffset return
+ // ScrollOffset. crbug.com/414283.
+ return gfx::ScrollOffset(
+ compositor_client_->GetTotalRootLayerScrollOffset());
+ }
+ return gfx::ScrollOffset();
}
bool SynchronousCompositorImpl::IsExternalFlingActive() const {
@@ -256,8 +274,8 @@ bool SynchronousCompositorImpl::IsExternalFlingActive() const {
}
void SynchronousCompositorImpl::UpdateRootLayerState(
- const gfx::Vector2dF& total_scroll_offset,
- const gfx::Vector2dF& max_scroll_offset,
+ const gfx::ScrollOffset& total_scroll_offset,
+ const gfx::ScrollOffset& max_scroll_offset,
const gfx::SizeF& scrollable_size,
float page_scale_factor,
float min_page_scale_factor,
@@ -266,12 +284,14 @@ void SynchronousCompositorImpl::UpdateRootLayerState(
if (!compositor_client_)
return;
- compositor_client_->UpdateRootLayerState(total_scroll_offset,
- max_scroll_offset,
- scrollable_size,
- page_scale_factor,
- min_page_scale_factor,
- max_page_scale_factor);
+ // TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
+ compositor_client_->UpdateRootLayerState(
+ gfx::ScrollOffsetToVector2dF(total_scroll_offset),
+ gfx::ScrollOffsetToVector2dF(max_scroll_offset),
+ scrollable_size,
+ page_scale_factor,
+ min_page_scale_factor,
+ max_page_scale_factor);
}
// Not using base::NonThreadSafe as we want to enforce a more exacting threading
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 6ac80cb92e6..9b92cef3781 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_impl.h
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_impl.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_IMPL_H_
#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_IMPL_H_
+#include <vector>
+
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
@@ -13,6 +15,7 @@
#include "content/common/input/input_event_ack_state.h"
#include "content/public/browser/android/synchronous_compositor.h"
#include "content/public/browser/web_contents_user_data.h"
+#include "ipc/ipc_message.h"
namespace cc {
class InputHandler;
@@ -47,39 +50,40 @@ class SynchronousCompositorImpl
// SynchronousCompositor
virtual void SetClient(SynchronousCompositorClient* compositor_client)
- OVERRIDE;
- virtual bool InitializeHwDraw() OVERRIDE;
- virtual void ReleaseHwDraw() OVERRIDE;
- virtual gpu::GLInProcessContext* GetShareContext() OVERRIDE;
+ override;
+ virtual bool InitializeHwDraw() override;
+ virtual void ReleaseHwDraw() override;
virtual scoped_ptr<cc::CompositorFrame> DemandDrawHw(
gfx::Size surface_size,
const gfx::Transform& transform,
gfx::Rect viewport,
- gfx::Rect clip) OVERRIDE;
- virtual bool DemandDrawSw(SkCanvas* canvas) OVERRIDE;
+ gfx::Rect clip,
+ gfx::Rect viewport_rect_for_tile_priority,
+ const gfx::Transform& transform_for_tile_priority) override;
+ virtual bool DemandDrawSw(SkCanvas* canvas) override;
virtual void ReturnResources(
- const cc::CompositorFrameAck& frame_ack) OVERRIDE;
- virtual void SetMemoryPolicy(
- const SynchronousCompositorMemoryPolicy& policy) OVERRIDE;
- virtual void DidChangeRootLayerScrollOffset() OVERRIDE;
+ const cc::CompositorFrameAck& frame_ack) override;
+ virtual void SetMemoryPolicy(size_t bytes_limit) override;
+ virtual void DidChangeRootLayerScrollOffset() override;
// SynchronousCompositorOutputSurfaceDelegate
virtual void DidBindOutputSurface(
- SynchronousCompositorOutputSurface* output_surface) OVERRIDE;
+ SynchronousCompositorOutputSurface* output_surface) override;
virtual void DidDestroySynchronousOutputSurface(
- SynchronousCompositorOutputSurface* output_surface) OVERRIDE;
- virtual void SetContinuousInvalidate(bool enable) OVERRIDE;
- virtual void DidActivatePendingTree() OVERRIDE;
+ SynchronousCompositorOutputSurface* output_surface) override;
+ virtual void SetContinuousInvalidate(bool enable) override;
+ virtual void DidActivatePendingTree() override;
// LayerScrollOffsetDelegate
- virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE;
- virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset,
- const gfx::Vector2dF& max_scroll_offset,
- const gfx::SizeF& scrollable_size,
- float page_scale_factor,
- float min_page_scale_factor,
- float max_page_scale_factor) OVERRIDE;
- virtual bool IsExternalFlingActive() const OVERRIDE;
+ virtual gfx::ScrollOffset GetTotalScrollOffset() override;
+ virtual void UpdateRootLayerState(
+ const gfx::ScrollOffset& total_scroll_offset,
+ const gfx::ScrollOffset& max_scroll_offset,
+ const gfx::SizeF& scrollable_size,
+ float page_scale_factor,
+ float min_page_scale_factor,
+ float max_page_scale_factor) override;
+ virtual bool IsExternalFlingActive() const override;
void SetInputHandler(cc::InputHandler* input_handler);
void DidOverscroll(const DidOverscrollParams& params);
@@ -91,6 +95,7 @@ class SynchronousCompositorImpl
friend class WebContentsUserData<SynchronousCompositorImpl>;
void UpdateFrameMetaData(const cc::CompositorFrameMetadata& frame_info);
+ void DeliverMessages();
bool CalledOnValidThread() const;
SynchronousCompositorClient* compositor_client_;
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/chromium/content/browser/android/in_process/synchronous_compositor_output_surface.cc
index 041de4ddfec..1c87cc34dac 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_output_surface.cc
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_output_surface.cc
@@ -14,6 +14,7 @@
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/public/browser/browser_thread.h"
+#include "content/renderer/gpu/frame_swap_message_queue.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -25,6 +26,9 @@ namespace content {
namespace {
+// Do not limit number of resources, so use an unrealistically high value.
+const size_t kNumResourcesLimit = 10 * 1000 * 1000;
+
void DidActivatePendingTree(int routing_id) {
SynchronousCompositorOutputSurfaceDelegate* delegate =
SynchronousCompositorImpl::FromRoutingID(routing_id);
@@ -41,10 +45,10 @@ class SynchronousCompositorOutputSurface::SoftwareDevice
: surface_(surface) {
}
virtual void Resize(const gfx::Size& pixel_size,
- float scale_factor) OVERRIDE {
+ float scale_factor) override {
// Intentional no-op: canvas size is controlled by the embedder.
}
- virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) OVERRIDE {
+ virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
if (!surface_->current_sw_canvas_) {
NOTREACHED() << "BeginPaint with no canvas set";
return &null_canvas_;
@@ -53,9 +57,9 @@ class SynchronousCompositorOutputSurface::SoftwareDevice
<< "Mutliple calls to BeginPaint per frame";
return surface_->current_sw_canvas_;
}
- virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE {
+ virtual void EndPaint(cc::SoftwareFrameData* frame_data) override {
}
- virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) OVERRIDE {
+ virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) override {
NOTIMPLEMENTED();
}
@@ -67,7 +71,8 @@ class SynchronousCompositorOutputSurface::SoftwareDevice
};
SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
- int routing_id)
+ int routing_id,
+ scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue)
: cc::OutputSurface(
scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareDevice(this))),
routing_id_(routing_id),
@@ -75,7 +80,8 @@ SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
invoking_composite_(false),
current_sw_canvas_(NULL),
memory_policy_(0),
- output_surface_client_(NULL) {
+ output_surface_client_(NULL),
+ frame_swap_message_queue_(frame_swap_message_queue) {
capabilities_.deferred_gl_initialization = true;
capabilities_.draw_and_swap_full_viewport_every_frame = true;
capabilities_.adjust_deadline_for_parent = false;
@@ -95,14 +101,6 @@ SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {
delegate->DidDestroySynchronousOutputSurface(this);
}
-bool SynchronousCompositorOutputSurface::ForcedDrawToSoftwareDevice() const {
- // |current_sw_canvas_| indicates we're in a DemandDrawSw call. In addition
- // |invoking_composite_| == false indicates an attempt to draw outside of
- // the synchronous compositor's control: force it into SW path and hence to
- // the null canvas (and will log a warning there).
- return current_sw_canvas_ != NULL || !invoking_composite_;
-}
-
bool SynchronousCompositorOutputSurface::BindToClient(
cc::OutputSurfaceClient* surface_client) {
DCHECK(CalledOnValidThread());
@@ -155,7 +153,7 @@ bool SynchronousCompositorOutputSurface::InitializeHwDraw(
scoped_refptr<cc::ContextProvider> onscreen_context_provider) {
DCHECK(CalledOnValidThread());
DCHECK(HasClient());
- DCHECK(!context_provider_);
+ DCHECK(!context_provider_.get());
return InitializeAndSetContext3d(onscreen_context_provider);
}
@@ -170,13 +168,20 @@ SynchronousCompositorOutputSurface::DemandDrawHw(
gfx::Size surface_size,
const gfx::Transform& transform,
gfx::Rect viewport,
- gfx::Rect clip) {
+ gfx::Rect clip,
+ gfx::Rect viewport_rect_for_tile_priority,
+ const gfx::Transform& transform_for_tile_priority) {
DCHECK(CalledOnValidThread());
DCHECK(HasClient());
- DCHECK(context_provider_);
+ DCHECK(context_provider_.get());
surface_size_ = surface_size;
- InvokeComposite(transform, viewport, clip, true);
+ InvokeComposite(transform,
+ viewport,
+ clip,
+ viewport_rect_for_tile_priority,
+ transform_for_tile_priority,
+ true);
return frame_holder_.Pass();
}
@@ -198,7 +203,15 @@ SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
surface_size_ = gfx::Size(canvas->getDeviceSize().width(),
canvas->getDeviceSize().height());
- InvokeComposite(transform, clip, clip, false);
+ // Pass in the cached hw viewport and transform for tile priority to avoid
+ // tile thrashing when the WebView is alternating between hardware and
+ // software draws.
+ InvokeComposite(transform,
+ clip,
+ clip,
+ cached_hw_viewport_rect_for_tile_priority_,
+ cached_hw_transform_for_tile_priority_,
+ false);
return frame_holder_.Pass();
}
@@ -207,28 +220,42 @@ void SynchronousCompositorOutputSurface::InvokeComposite(
const gfx::Transform& transform,
gfx::Rect viewport,
gfx::Rect clip,
- bool valid_for_tile_management) {
+ gfx::Rect viewport_rect_for_tile_priority,
+ gfx::Transform transform_for_tile_priority,
+ bool hardware_draw) {
DCHECK(!invoking_composite_);
DCHECK(!frame_holder_.get());
base::AutoReset<bool> invoking_composite_resetter(&invoking_composite_, true);
gfx::Transform adjusted_transform = transform;
AdjustTransform(&adjusted_transform, viewport);
- SetExternalDrawConstraints(
- adjusted_transform, viewport, clip, valid_for_tile_management);
+ SetExternalDrawConstraints(adjusted_transform,
+ viewport,
+ clip,
+ viewport_rect_for_tile_priority,
+ transform_for_tile_priority,
+ !hardware_draw);
SetNeedsRedrawRect(gfx::Rect(viewport.size()));
client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
// After software draws (which might move the viewport arbitrarily), restore
// the previous hardware viewport to allow CC's tile manager to prioritize
// properly.
- if (valid_for_tile_management) {
+ if (hardware_draw) {
cached_hw_transform_ = adjusted_transform;
cached_hw_viewport_ = viewport;
cached_hw_clip_ = clip;
+ cached_hw_viewport_rect_for_tile_priority_ =
+ viewport_rect_for_tile_priority;
+ cached_hw_transform_for_tile_priority_ = transform_for_tile_priority;
} else {
- SetExternalDrawConstraints(
- cached_hw_transform_, cached_hw_viewport_, cached_hw_clip_, true);
+ bool resourceless_software_draw = false;
+ SetExternalDrawConstraints(cached_hw_transform_,
+ cached_hw_viewport_,
+ cached_hw_clip_,
+ cached_hw_viewport_rect_for_tile_priority_,
+ cached_hw_transform_for_tile_priority_,
+ resourceless_software_draw);
}
if (frame_holder_.get())
@@ -244,16 +271,23 @@ void SynchronousCompositorOutputSurface::ReturnResources(
ReclaimResources(&frame_ack);
}
-void SynchronousCompositorOutputSurface::SetMemoryPolicy(
- const SynchronousCompositorMemoryPolicy& policy) {
+void SynchronousCompositorOutputSurface::SetMemoryPolicy(size_t bytes_limit) {
DCHECK(CalledOnValidThread());
- memory_policy_.bytes_limit_when_visible = policy.bytes_limit;
- memory_policy_.num_resources_limit = policy.num_resources_limit;
+ memory_policy_.bytes_limit_when_visible = bytes_limit;
+ memory_policy_.num_resources_limit = kNumResourcesLimit;
if (output_surface_client_)
output_surface_client_->SetMemoryPolicy(memory_policy_);
}
+void SynchronousCompositorOutputSurface::GetMessagesToDeliver(
+ ScopedVector<IPC::Message>* messages) {
+ DCHECK(CalledOnValidThread());
+ scoped_ptr<FrameSwapMessageQueue::SendMessageScope> send_message_scope =
+ frame_swap_message_queue_->AcquireSendMessageScope();
+ frame_swap_message_queue_->DrainMessages(messages);
+}
+
// Not using base::NonThreadSafe as we want to enforce a more exacting threading
// requirement: SynchronousCompositorOutputSurface() must only be used on the UI
// thread.
diff --git a/chromium/content/browser/android/in_process/synchronous_compositor_output_surface.h b/chromium/content/browser/android/in_process/synchronous_compositor_output_surface.h
index 3a456a433f0..d01d88b6b36 100644
--- a/chromium/content/browser/android/in_process/synchronous_compositor_output_surface.h
+++ b/chromium/content/browser/android/in_process/synchronous_compositor_output_surface.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_OUTPUT_SURFACE_H_
#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_OUTPUT_SURFACE_H_
+#include <vector>
+
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
@@ -13,6 +15,7 @@
#include "cc/output/managed_memory_policy.h"
#include "cc/output/output_surface.h"
#include "content/public/browser/android/synchronous_compositor.h"
+#include "ipc/ipc_message.h"
#include "ui/gfx/transform.h"
namespace cc {
@@ -20,8 +23,13 @@ class ContextProvider;
class CompositorFrameMetadata;
}
+namespace IPC {
+class Message;
+}
+
namespace content {
+class FrameSwapMessageQueue;
class SynchronousCompositorClient;
class SynchronousCompositorOutputSurface;
class WebGraphicsContext3DCommandBufferImpl;
@@ -51,27 +59,32 @@ class SynchronousCompositorOutputSurfaceDelegate {
class SynchronousCompositorOutputSurface
: NON_EXPORTED_BASE(public cc::OutputSurface) {
public:
- explicit SynchronousCompositorOutputSurface(int routing_id);
+ explicit SynchronousCompositorOutputSurface(
+ int routing_id,
+ scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue);
virtual ~SynchronousCompositorOutputSurface();
// OutputSurface.
- virtual bool ForcedDrawToSoftwareDevice() const OVERRIDE;
- virtual bool BindToClient(cc::OutputSurfaceClient* surface_client) OVERRIDE;
- virtual void Reshape(const gfx::Size& size, float scale_factor) OVERRIDE;
- virtual void SetNeedsBeginFrame(bool enable) OVERRIDE;
- virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE;
+ virtual bool BindToClient(cc::OutputSurfaceClient* surface_client) override;
+ virtual void Reshape(const gfx::Size& size, float scale_factor) override;
+ virtual void SetNeedsBeginFrame(bool enable) override;
+ virtual void SwapBuffers(cc::CompositorFrame* frame) override;
// Partial SynchronousCompositor API implementation.
bool InitializeHwDraw(
scoped_refptr<cc::ContextProvider> onscreen_context_provider);
void ReleaseHwDraw();
- scoped_ptr<cc::CompositorFrame> DemandDrawHw(gfx::Size surface_size,
- const gfx::Transform& transform,
- gfx::Rect viewport,
- gfx::Rect clip);
+ scoped_ptr<cc::CompositorFrame> DemandDrawHw(
+ gfx::Size surface_size,
+ const gfx::Transform& transform,
+ gfx::Rect viewport,
+ gfx::Rect clip,
+ gfx::Rect viewport_rect_for_tile_priority,
+ const gfx::Transform& transform_for_tile_priority);
void ReturnResources(const cc::CompositorFrameAck& frame_ack);
scoped_ptr<cc::CompositorFrame> DemandDrawSw(SkCanvas* canvas);
- void SetMemoryPolicy(const SynchronousCompositorMemoryPolicy& policy);
+ void SetMemoryPolicy(size_t bytes_limit);
+ void GetMessagesToDeliver(ScopedVector<IPC::Message>* messages);
private:
class SoftwareDevice;
@@ -80,7 +93,9 @@ class SynchronousCompositorOutputSurface
void InvokeComposite(const gfx::Transform& transform,
gfx::Rect viewport,
gfx::Rect clip,
- bool valid_for_tile_management);
+ gfx::Rect viewport_rect_for_tile_priority,
+ gfx::Transform transform_for_tile_priority,
+ bool hardware_draw);
bool CalledOnValidThread() const;
SynchronousCompositorOutputSurfaceDelegate* GetDelegate();
@@ -91,6 +106,8 @@ class SynchronousCompositorOutputSurface
gfx::Transform cached_hw_transform_;
gfx::Rect cached_hw_viewport_;
gfx::Rect cached_hw_clip_;
+ gfx::Rect cached_hw_viewport_rect_for_tile_priority_;
+ gfx::Transform cached_hw_transform_for_tile_priority_;
// Only valid (non-NULL) during a DemandDrawSw() call.
SkCanvas* current_sw_canvas_;
@@ -100,6 +117,8 @@ class SynchronousCompositorOutputSurface
cc::OutputSurfaceClient* output_surface_client_;
scoped_ptr<cc::CompositorFrame> frame_holder_;
+ scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_;
+
DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorOutputSurface);
};
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 3b81fa6f889..33200e8068e 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
@@ -32,13 +32,13 @@ class SynchronousInputEventFilter : public InputHandlerManagerClient {
const blink::WebInputEvent& input_event);
// InputHandlerManagerClient implementation.
- virtual void SetBoundHandler(const Handler& handler) OVERRIDE;
+ virtual void SetBoundHandler(const Handler& handler) override;
virtual void DidAddInputHandler(int routing_id,
- cc::InputHandler* input_handler) OVERRIDE;
- virtual void DidRemoveInputHandler(int routing_id) OVERRIDE;
+ cc::InputHandler* input_handler) override;
+ virtual void DidRemoveInputHandler(int routing_id) override;
virtual void DidOverscroll(int routing_id,
- const DidOverscrollParams& params) OVERRIDE;
- virtual void DidStopFlinging(int routing_id) OVERRIDE;
+ const DidOverscrollParams& params) override;
+ virtual void DidStopFlinging(int routing_id) override;
private:
void SetBoundHandlerOnUIThread(const Handler& handler);
diff --git a/chromium/content/browser/android/interstitial_page_delegate_android.h b/chromium/content/browser/android/interstitial_page_delegate_android.h
index 208717e8787..5121be161f5 100644
--- a/chromium/content/browser/android/interstitial_page_delegate_android.h
+++ b/chromium/content/browser/android/interstitial_page_delegate_android.h
@@ -35,10 +35,10 @@ class InterstitialPageDelegateAndroid : public InterstitialPageDelegate {
void DontProceed(JNIEnv* env, jobject obj);
// Implementation of InterstitialPageDelegate
- virtual std::string GetHTMLContents() OVERRIDE;
- virtual void OnProceed() OVERRIDE;
- virtual void OnDontProceed() OVERRIDE;
- virtual void CommandReceived(const std::string& command) OVERRIDE;
+ virtual std::string GetHTMLContents() override;
+ virtual void OnProceed() override;
+ virtual void OnDontProceed() override;
+ virtual void CommandReceived(const std::string& command) override;
static bool RegisterInterstitialPageDelegateAndroid(JNIEnv* env);
diff --git a/chromium/content/browser/android/java/DEPS b/chromium/content/browser/android/java/DEPS
new file mode 100644
index 00000000000..430199d518c
--- /dev/null
+++ b/chromium/content/browser/android/java/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+content/child", # For java bridge bindings
+]
diff --git a/chromium/content/browser/renderer_host/java/OWNERS b/chromium/content/browser/android/java/OWNERS
index 0cebb68c10c..0cebb68c10c 100644
--- a/chromium/content/browser/renderer_host/java/OWNERS
+++ b/chromium/content/browser/android/java/OWNERS
diff --git a/chromium/content/browser/renderer_host/java/gin_java_bound_object.cc b/chromium/content/browser/android/java/gin_java_bound_object.cc
index 70abba842c9..99c8b5d14e3 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_bound_object.cc
+++ b/chromium/content/browser/android/java/gin_java_bound_object.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/renderer_host/java/gin_java_bound_object.h"
+#include "content/browser/android/java/gin_java_bound_object.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/strings/utf_string_conversions.h"
-#include "content/browser/renderer_host/java/jni_helper.h"
+#include "content/browser/android/java/jni_helper.h"
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
@@ -185,7 +185,7 @@ void GinJavaBoundObject::EnsureMethodsAreSetUp() {
}
JavaMethod* method = new JavaMethod(java_method);
- methods_.insert(std::make_pair(method->name(), method));
+ methods_.insert(std::make_pair(method->name(), make_linked_ptr(method)));
}
}
diff --git a/chromium/content/browser/renderer_host/java/gin_java_bound_object.h b/chromium/content/browser/android/java/gin_java_bound_object.h
index 610b0c42899..ce1d403e7f6 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_bound_object.h
+++ b/chromium/content/browser/android/java/gin_java_bound_object.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_RENDERER_HOST_JAVA_GIN_JAVA_BOUND_OBJECT_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_GIN_JAVA_BOUND_OBJECT_H_
+#ifndef CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_BOUND_OBJECT_H_
+#define CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_BOUND_OBJECT_H_
#include <map>
#include <set>
@@ -15,7 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/values.h"
-#include "content/browser/renderer_host/java/java_method.h"
+#include "content/browser/android/java/java_method.h"
namespace content {
@@ -93,4 +93,4 @@ class GinJavaBoundObject
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_GIN_JAVA_BOUND_OBJECT_H_
+#endif // CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_BOUND_OBJECT_H_
diff --git a/chromium/content/browser/renderer_host/java/gin_java_bound_object_delegate.cc b/chromium/content/browser/android/java/gin_java_bound_object_delegate.cc
index 92b1ccc2fc1..bf964d7592f 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_bound_object_delegate.cc
+++ b/chromium/content/browser/android/java/gin_java_bound_object_delegate.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/renderer_host/java/gin_java_bound_object_delegate.h"
+#include "content/browser/android/java/gin_java_bound_object_delegate.h"
namespace content {
diff --git a/chromium/content/browser/renderer_host/java/gin_java_bound_object_delegate.h b/chromium/content/browser/android/java/gin_java_bound_object_delegate.h
index 9852d91e733..49ff4bbca4f 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_bound_object_delegate.h
+++ b/chromium/content/browser/android/java/gin_java_bound_object_delegate.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_RENDERER_HOST_JAVA_GIN_JAVA_BOUND_OBJECT_DELEGATE_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_GIN_JAVA_BOUND_OBJECT_DELEGATE_H_
+#ifndef CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_BOUND_OBJECT_DELEGATE_H_
+#define CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_BOUND_OBJECT_DELEGATE_H_
#include "base/memory/ref_counted.h"
-#include "content/browser/renderer_host/java/gin_java_bound_object.h"
-#include "content/browser/renderer_host/java/gin_java_method_invocation_helper.h"
+#include "content/browser/android/java/gin_java_bound_object.h"
+#include "content/browser/android/java/gin_java_method_invocation_helper.h"
namespace content {
@@ -18,14 +18,14 @@ class GinJavaBoundObjectDelegate
virtual ~GinJavaBoundObjectDelegate();
virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef(
- JNIEnv* env) OVERRIDE;
+ JNIEnv* env) override;
virtual base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef(
- JNIEnv* env) OVERRIDE;
+ JNIEnv* env) override;
virtual const JavaMethod* FindMethod(const std::string& method_name,
- size_t num_parameters) OVERRIDE;
- virtual bool IsObjectGetClassMethod(const JavaMethod* method) OVERRIDE;
+ size_t num_parameters) override;
+ virtual bool IsObjectGetClassMethod(const JavaMethod* method) override;
virtual const base::android::JavaRef<jclass>& GetSafeAnnotationClass()
- OVERRIDE;
+ override;
private:
scoped_refptr<GinJavaBoundObject> object_;
@@ -35,4 +35,4 @@ class GinJavaBoundObjectDelegate
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_GIN_JAVA_BOUND_OBJECT_DELEGATE_H_
+#endif // CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_BOUND_OBJECT_DELEGATE_H_
diff --git a/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.cc b/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
new file mode 100644
index 00000000000..c8fb2fd9899
--- /dev/null
+++ b/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
@@ -0,0 +1,564 @@
+// 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/android/java/gin_java_bridge_dispatcher_host.h"
+
+#include "base/android/java_handler_thread.h"
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task_runner_util.h"
+#include "content/browser/android/java/gin_java_bound_object_delegate.h"
+#include "content/browser/android/java/jni_helper.h"
+#include "content/common/android/gin_java_bridge_value.h"
+#include "content/common/android/hash_set.h"
+#include "content/common/gin_java_bridge_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "ipc/ipc_message_utils.h"
+
+#if !defined(OS_ANDROID)
+#error "JavaBridge only supports OS_ANDROID"
+#endif
+
+namespace content {
+
+namespace {
+// The JavaBridge needs to use a Java thread so the callback
+// will happen on a thread with a prepared Looper.
+class JavaBridgeThread : public base::android::JavaHandlerThread {
+ public:
+ JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
+ Start();
+ }
+ virtual ~JavaBridgeThread() {
+ Stop();
+ }
+};
+
+base::LazyInstance<JavaBridgeThread> g_background_thread =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+GinJavaBridgeDispatcherHost::GinJavaBridgeDispatcherHost(
+ WebContents* web_contents,
+ jobject retained_object_set)
+ : WebContentsObserver(web_contents),
+ retained_object_set_(base::android::AttachCurrentThread(),
+ retained_object_set),
+ allow_object_contents_inspection_(true) {
+ DCHECK(retained_object_set);
+}
+
+GinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() {
+ DCHECK(pending_replies_.empty());
+}
+
+void GinJavaBridgeDispatcherHost::RenderFrameCreated(
+ RenderFrameHost* render_frame_host) {
+ for (NamedObjectMap::const_iterator iter = named_objects_.begin();
+ iter != named_objects_.end();
+ ++iter) {
+ render_frame_host->Send(new GinJavaBridgeMsg_AddNamedObject(
+ render_frame_host->GetRoutingID(), iter->first, iter->second));
+ }
+}
+
+void GinJavaBridgeDispatcherHost::RenderFrameDeleted(
+ RenderFrameHost* render_frame_host) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+ if (reply_msg != NULL) {
+ base::ListValue result;
+ result.Append(base::Value::CreateNullValue());
+ IPC::WriteParam(reply_msg, result);
+ IPC::WriteParam(reply_msg, kGinJavaBridgeRenderFrameDeleted);
+ render_frame_host->Send(reply_msg);
+ }
+ RemoveHolder(render_frame_host,
+ GinJavaBoundObject::ObjectMap::iterator(&objects_),
+ objects_.size());
+}
+
+GinJavaBoundObject::ObjectID GinJavaBridgeDispatcherHost::AddObject(
+ const base::android::JavaRef<jobject>& object,
+ const base::android::JavaRef<jclass>& safe_annotation_clazz,
+ bool is_named,
+ RenderFrameHost* holder) {
+ DCHECK(is_named || holder);
+ GinJavaBoundObject::ObjectID object_id;
+ JNIEnv* env = base::android::AttachCurrentThread();
+ JavaObjectWeakGlobalRef ref(env, object.obj());
+ if (is_named) {
+ object_id = objects_.Add(new scoped_refptr<GinJavaBoundObject>(
+ GinJavaBoundObject::CreateNamed(ref, safe_annotation_clazz)));
+ } else {
+ object_id = objects_.Add(new scoped_refptr<GinJavaBoundObject>(
+ GinJavaBoundObject::CreateTransient(
+ ref, safe_annotation_clazz, holder)));
+ }
+#if DCHECK_IS_ON
+ {
+ GinJavaBoundObject::ObjectID added_object_id;
+ DCHECK(FindObjectId(object, &added_object_id));
+ DCHECK_EQ(object_id, added_object_id);
+ }
+#endif // DCHECK_IS_ON
+ base::android::ScopedJavaLocalRef<jobject> retained_object_set =
+ retained_object_set_.get(env);
+ if (!retained_object_set.is_null()) {
+ JNI_Java_HashSet_add(env, retained_object_set, object);
+ }
+ return object_id;
+}
+
+bool GinJavaBridgeDispatcherHost::FindObjectId(
+ const base::android::JavaRef<jobject>& object,
+ GinJavaBoundObject::ObjectID* object_id) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ for (GinJavaBoundObject::ObjectMap::iterator it(&objects_); !it.IsAtEnd();
+ it.Advance()) {
+ if (env->IsSameObject(
+ object.obj(),
+ it.GetCurrentValue()->get()->GetLocalRef(env).obj())) {
+ *object_id = it.GetCurrentKey();
+ return true;
+ }
+ }
+ return false;
+}
+
+JavaObjectWeakGlobalRef GinJavaBridgeDispatcherHost::GetObjectWeakRef(
+ GinJavaBoundObject::ObjectID object_id) {
+ scoped_refptr<GinJavaBoundObject>* result = objects_.Lookup(object_id);
+ scoped_refptr<GinJavaBoundObject> object(result ? *result : NULL);
+ if (object.get())
+ return object->GetWeakRef();
+ else
+ return JavaObjectWeakGlobalRef();
+}
+
+void GinJavaBridgeDispatcherHost::RemoveHolder(
+ RenderFrameHost* holder,
+ const GinJavaBoundObject::ObjectMap::iterator& from,
+ size_t count) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jobject> retained_object_set =
+ retained_object_set_.get(env);
+ size_t i = 0;
+ for (GinJavaBoundObject::ObjectMap::iterator it(from);
+ !it.IsAtEnd() && i < count;
+ it.Advance(), ++i) {
+ scoped_refptr<GinJavaBoundObject> object(*it.GetCurrentValue());
+ if (object->IsNamed())
+ continue;
+ object->RemoveHolder(holder);
+ if (!object->HasHolders()) {
+ if (!retained_object_set.is_null()) {
+ JNI_Java_HashSet_remove(
+ env, retained_object_set, object->GetLocalRef(env));
+ }
+ objects_.Remove(it.GetCurrentKey());
+ }
+ }
+}
+
+void GinJavaBridgeDispatcherHost::AddNamedObject(
+ const std::string& name,
+ const base::android::JavaRef<jobject>& object,
+ const base::android::JavaRef<jclass>& safe_annotation_clazz) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ GinJavaBoundObject::ObjectID object_id;
+ NamedObjectMap::iterator iter = named_objects_.find(name);
+ bool existing_object = FindObjectId(object, &object_id);
+ if (existing_object && iter != named_objects_.end() &&
+ iter->second == object_id) {
+ // Nothing to do.
+ return;
+ }
+ if (iter != named_objects_.end()) {
+ RemoveNamedObject(iter->first);
+ }
+ if (existing_object) {
+ (*objects_.Lookup(object_id))->AddName();
+ } else {
+ object_id = AddObject(object, safe_annotation_clazz, true, NULL);
+ }
+ named_objects_[name] = object_id;
+
+ web_contents()->SendToAllFrames(
+ new GinJavaBridgeMsg_AddNamedObject(MSG_ROUTING_NONE, name, object_id));
+}
+
+void GinJavaBridgeDispatcherHost::RemoveNamedObject(
+ const std::string& name) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ NamedObjectMap::iterator iter = named_objects_.find(name);
+ if (iter == named_objects_.end())
+ return;
+
+ // |name| may come from |named_objects_|. Make a copy of name so that if
+ // |name| is from |named_objects_| it'll be valid after the remove below.
+ const std::string copied_name(name);
+
+ scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(iter->second));
+ named_objects_.erase(iter);
+ object->RemoveName();
+
+ // As the object isn't going to be removed from the JavaScript side until the
+ // next page reload, calls to it must still work, thus we should continue to
+ // hold it. All the transient objects and removed named objects will be purged
+ // during the cleansing caused by DocumentAvailableInMainFrame event.
+
+ web_contents()->SendToAllFrames(
+ new GinJavaBridgeMsg_RemoveNamedObject(MSG_ROUTING_NONE, copied_name));
+}
+
+void GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection(bool allow) {
+ allow_object_contents_inspection_ = allow;
+}
+
+void GinJavaBridgeDispatcherHost::DocumentAvailableInMainFrame() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Called when the window object has been cleared in the main frame.
+ // That means, all sub-frames have also been cleared, so only named
+ // objects survived.
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::ScopedJavaLocalRef<jobject> retained_object_set =
+ retained_object_set_.get(env);
+ if (!retained_object_set.is_null()) {
+ JNI_Java_HashSet_clear(env, retained_object_set);
+ }
+
+ // We also need to add back the named objects we have so far as they
+ // should survive navigations.
+ for (GinJavaBoundObject::ObjectMap::iterator it(&objects_); !it.IsAtEnd();
+ it.Advance()) {
+ scoped_refptr<GinJavaBoundObject> object(*it.GetCurrentValue());
+ if (object->IsNamed()) {
+ if (!retained_object_set.is_null()) {
+ JNI_Java_HashSet_add(
+ env, retained_object_set, object->GetLocalRef(env));
+ }
+ } else {
+ objects_.Remove(it.GetCurrentKey());
+ }
+ }
+}
+
+namespace {
+
+// TODO(mnaganov): Implement passing of a parameter into sync message handlers.
+class MessageForwarder : public IPC::Sender {
+ public:
+ MessageForwarder(GinJavaBridgeDispatcherHost* gjbdh,
+ RenderFrameHost* render_frame_host)
+ : gjbdh_(gjbdh), render_frame_host_(render_frame_host) {}
+ void OnGetMethods(GinJavaBoundObject::ObjectID object_id,
+ IPC::Message* reply_msg) {
+ gjbdh_->OnGetMethods(render_frame_host_,
+ object_id,
+ reply_msg);
+ }
+ void OnHasMethod(GinJavaBoundObject::ObjectID object_id,
+ const std::string& method_name,
+ IPC::Message* reply_msg) {
+ gjbdh_->OnHasMethod(render_frame_host_,
+ object_id,
+ method_name,
+ reply_msg);
+ }
+ void OnInvokeMethod(GinJavaBoundObject::ObjectID object_id,
+ const std::string& method_name,
+ const base::ListValue& arguments,
+ IPC::Message* reply_msg) {
+ gjbdh_->OnInvokeMethod(render_frame_host_,
+ object_id,
+ method_name,
+ arguments,
+ reply_msg);
+ }
+ virtual bool Send(IPC::Message* msg) override {
+ NOTREACHED();
+ return false;
+ }
+ private:
+ GinJavaBridgeDispatcherHost* gjbdh_;
+ RenderFrameHost* render_frame_host_;
+};
+
+}
+
+bool GinJavaBridgeDispatcherHost::OnMessageReceived(
+ const IPC::Message& message,
+ RenderFrameHost* render_frame_host) {
+ DCHECK(render_frame_host);
+ bool handled = true;
+ MessageForwarder forwarder(this, render_frame_host);
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(GinJavaBridgeDispatcherHost, message,
+ render_frame_host)
+ IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_GetMethods,
+ &forwarder,
+ MessageForwarder::OnGetMethods)
+ IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_HasMethod,
+ &forwarder,
+ MessageForwarder::OnHasMethod)
+ IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_InvokeMethod,
+ &forwarder,
+ MessageForwarder::OnInvokeMethod)
+ IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_ObjectWrapperDeleted,
+ OnObjectWrapperDeleted)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+namespace {
+
+class IsValidRenderFrameHostHelper
+ : public base::RefCounted<IsValidRenderFrameHostHelper> {
+ public:
+ explicit IsValidRenderFrameHostHelper(RenderFrameHost* rfh_to_match)
+ : rfh_to_match_(rfh_to_match), rfh_found_(false) {}
+
+ bool rfh_found() { return rfh_found_; }
+
+ void OnFrame(RenderFrameHost* rfh) {
+ if (rfh_to_match_ == rfh) rfh_found_ = true;
+ }
+
+ private:
+ friend class base::RefCounted<IsValidRenderFrameHostHelper>;
+
+ ~IsValidRenderFrameHostHelper() {}
+
+ RenderFrameHost* rfh_to_match_;
+ bool rfh_found_;
+
+ DISALLOW_COPY_AND_ASSIGN(IsValidRenderFrameHostHelper);
+};
+
+} // namespace
+
+bool GinJavaBridgeDispatcherHost::IsValidRenderFrameHost(
+ RenderFrameHost* render_frame_host) {
+ scoped_refptr<IsValidRenderFrameHostHelper> helper =
+ new IsValidRenderFrameHostHelper(render_frame_host);
+ web_contents()->ForEachFrame(
+ base::Bind(&IsValidRenderFrameHostHelper::OnFrame, helper));
+ return helper->rfh_found();
+}
+
+void GinJavaBridgeDispatcherHost::OnGetMethods(
+ RenderFrameHost* render_frame_host,
+ GinJavaBoundObject::ObjectID object_id,
+ IPC::Message* reply_msg) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(render_frame_host);
+ if (!allow_object_contents_inspection_) {
+ IPC::WriteParam(reply_msg, std::set<std::string>());
+ render_frame_host->Send(reply_msg);
+ return;
+ }
+ scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id));
+ if (!object.get()) {
+ LOG(ERROR) << "WebView: Unknown object: " << object_id;
+ IPC::WriteParam(reply_msg, std::set<std::string>());
+ render_frame_host->Send(reply_msg);
+ return;
+ }
+ DCHECK(!HasPendingReply(render_frame_host));
+ pending_replies_[render_frame_host] = reply_msg;
+ base::PostTaskAndReplyWithResult(
+ g_background_thread.Get().message_loop()->message_loop_proxy().get(),
+ FROM_HERE,
+ base::Bind(&GinJavaBoundObject::GetMethodNames, object),
+ base::Bind(&GinJavaBridgeDispatcherHost::SendMethods,
+ AsWeakPtr(),
+ render_frame_host));
+}
+
+void GinJavaBridgeDispatcherHost::SendMethods(
+ RenderFrameHost* render_frame_host,
+ const std::set<std::string>& method_names) {
+ IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+ if (!reply_msg) {
+ return;
+ }
+ IPC::WriteParam(reply_msg, method_names);
+ render_frame_host->Send(reply_msg);
+}
+
+void GinJavaBridgeDispatcherHost::OnHasMethod(
+ RenderFrameHost* render_frame_host,
+ GinJavaBoundObject::ObjectID object_id,
+ const std::string& method_name,
+ IPC::Message* reply_msg) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(render_frame_host);
+ scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id));
+ if (!object.get()) {
+ LOG(ERROR) << "WebView: Unknown object: " << object_id;
+ IPC::WriteParam(reply_msg, false);
+ render_frame_host->Send(reply_msg);
+ return;
+ }
+ DCHECK(!HasPendingReply(render_frame_host));
+ pending_replies_[render_frame_host] = reply_msg;
+ base::PostTaskAndReplyWithResult(
+ g_background_thread.Get().message_loop()->message_loop_proxy().get(),
+ FROM_HERE,
+ base::Bind(&GinJavaBoundObject::HasMethod, object, method_name),
+ base::Bind(&GinJavaBridgeDispatcherHost::SendHasMethodReply,
+ AsWeakPtr(),
+ render_frame_host));
+}
+
+void GinJavaBridgeDispatcherHost::SendHasMethodReply(
+ RenderFrameHost* render_frame_host,
+ bool result) {
+ IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+ if (!reply_msg) {
+ return;
+ }
+ IPC::WriteParam(reply_msg, result);
+ render_frame_host->Send(reply_msg);
+}
+
+void GinJavaBridgeDispatcherHost::OnInvokeMethod(
+ RenderFrameHost* render_frame_host,
+ GinJavaBoundObject::ObjectID object_id,
+ const std::string& method_name,
+ const base::ListValue& arguments,
+ IPC::Message* reply_msg) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(render_frame_host);
+ scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id));
+ if (!object.get()) {
+ LOG(ERROR) << "WebView: Unknown object: " << object_id;
+ base::ListValue result;
+ result.Append(base::Value::CreateNullValue());
+ IPC::WriteParam(reply_msg, result);
+ IPC::WriteParam(reply_msg, kGinJavaBridgeUnknownObjectId);
+ render_frame_host->Send(reply_msg);
+ return;
+ }
+ DCHECK(!HasPendingReply(render_frame_host));
+ pending_replies_[render_frame_host] = reply_msg;
+ scoped_refptr<GinJavaMethodInvocationHelper> result =
+ new GinJavaMethodInvocationHelper(
+ make_scoped_ptr(new GinJavaBoundObjectDelegate(object)),
+ method_name,
+ arguments);
+ result->Init(this);
+ g_background_thread.Get()
+ .message_loop()
+ ->message_loop_proxy()
+ ->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&GinJavaMethodInvocationHelper::Invoke, result),
+ base::Bind(
+ &GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult,
+ AsWeakPtr(),
+ render_frame_host,
+ result));
+}
+
+void GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult(
+ RenderFrameHost* render_frame_host,
+ scoped_refptr<GinJavaMethodInvocationHelper> result) {
+ if (result->HoldsPrimitiveResult()) {
+ IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+ if (!reply_msg) {
+ return;
+ }
+ IPC::WriteParam(reply_msg, result->GetPrimitiveResult());
+ IPC::WriteParam(reply_msg, result->GetInvocationError());
+ render_frame_host->Send(reply_msg);
+ } else {
+ ProcessMethodInvocationObjectResult(render_frame_host, result);
+ }
+}
+
+void GinJavaBridgeDispatcherHost::ProcessMethodInvocationObjectResult(
+ RenderFrameHost* render_frame_host,
+ scoped_refptr<GinJavaMethodInvocationHelper> result) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (!IsValidRenderFrameHost(render_frame_host)) {
+ // In this case, we must've already sent the reply when the render frame
+ // was destroyed.
+ DCHECK(!HasPendingReply(render_frame_host));
+ return;
+ }
+
+ base::ListValue wrapped_result;
+ if (!result->GetObjectResult().is_null()) {
+ GinJavaBoundObject::ObjectID returned_object_id;
+ if (FindObjectId(result->GetObjectResult(), &returned_object_id)) {
+ (*objects_.Lookup(returned_object_id))->AddHolder(render_frame_host);
+ } else {
+ returned_object_id = AddObject(result->GetObjectResult(),
+ result->GetSafeAnnotationClass(),
+ false,
+ render_frame_host);
+ }
+ wrapped_result.Append(
+ GinJavaBridgeValue::CreateObjectIDValue(
+ returned_object_id).release());
+ } else {
+ wrapped_result.Append(base::Value::CreateNullValue());
+ }
+ IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+ if (!reply_msg) {
+ return;
+ }
+ IPC::WriteParam(reply_msg, wrapped_result);
+ IPC::WriteParam(reply_msg, result->GetInvocationError());
+ render_frame_host->Send(reply_msg);
+}
+
+void GinJavaBridgeDispatcherHost::OnObjectWrapperDeleted(
+ RenderFrameHost* render_frame_host,
+ GinJavaBoundObject::ObjectID object_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(render_frame_host);
+ if (objects_.Lookup(object_id)) {
+ GinJavaBoundObject::ObjectMap::iterator iter(&objects_);
+ while (!iter.IsAtEnd() && iter.GetCurrentKey() != object_id)
+ iter.Advance();
+ DCHECK(!iter.IsAtEnd());
+ RemoveHolder(render_frame_host, iter, 1);
+ }
+}
+
+IPC::Message* GinJavaBridgeDispatcherHost::TakePendingReply(
+ RenderFrameHost* render_frame_host) {
+ if (!IsValidRenderFrameHost(render_frame_host)) {
+ DCHECK(!HasPendingReply(render_frame_host));
+ return NULL;
+ }
+
+ PendingReplyMap::iterator it = pending_replies_.find(render_frame_host);
+ // There may be no pending reply if we're called from RenderFrameDeleted and
+ // we already sent the reply through the regular route.
+ if (it == pending_replies_.end()) {
+ return NULL;
+ }
+
+ IPC::Message* reply_msg = it->second;
+ pending_replies_.erase(it);
+ return reply_msg;
+}
+
+bool GinJavaBridgeDispatcherHost::HasPendingReply(
+ RenderFrameHost* render_frame_host) const {
+ return pending_replies_.find(render_frame_host) != pending_replies_.end();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h b/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h
new file mode 100644
index 00000000000..c57ba260f1e
--- /dev/null
+++ b/chromium/content/browser/android/java/gin_java_bridge_dispatcher_host.h
@@ -0,0 +1,126 @@
+// 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_ANDROID_JAVA_GIN_JAVA_BRIDGE_DISPATCHER_HOST_H_
+#define CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_BRIDGE_DISPATCHER_HOST_H_
+
+#include <map>
+#include <set>
+
+#include "base/android/jni_weak_ref.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/android/java/gin_java_bound_object.h"
+#include "content/browser/android/java/gin_java_method_invocation_helper.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace content {
+
+// This class handles injecting Java objects into a single RenderView. The Java
+// object itself lives in the browser process on a background thread, while a
+// proxy object is created in the renderer. An instance of this class exists
+// for each RenderFrameHost.
+class GinJavaBridgeDispatcherHost
+ : public base::SupportsWeakPtr<GinJavaBridgeDispatcherHost>,
+ public WebContentsObserver,
+ public GinJavaMethodInvocationHelper::DispatcherDelegate {
+ public:
+
+ GinJavaBridgeDispatcherHost(WebContents* web_contents,
+ jobject retained_object_set);
+ virtual ~GinJavaBridgeDispatcherHost();
+
+ void AddNamedObject(
+ const std::string& name,
+ const base::android::JavaRef<jobject>& object,
+ const base::android::JavaRef<jclass>& safe_annotation_clazz);
+ void RemoveNamedObject(const std::string& name);
+ void SetAllowObjectContentsInspection(bool allow);
+
+ // WebContentsObserver
+ virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
+ virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+ virtual void DocumentAvailableInMainFrame() override;
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) override;
+
+ // GinJavaMethodInvocationHelper::DispatcherDelegate
+ virtual JavaObjectWeakGlobalRef GetObjectWeakRef(
+ GinJavaBoundObject::ObjectID object_id) override;
+
+ void OnGetMethods(RenderFrameHost* render_frame_host,
+ GinJavaBoundObject::ObjectID object_id,
+ IPC::Message* reply_msg);
+ void OnHasMethod(RenderFrameHost* render_frame_host,
+ GinJavaBoundObject::ObjectID object_id,
+ const std::string& method_name,
+ IPC::Message* reply_msg);
+ void OnInvokeMethod(RenderFrameHost* render_frame_host,
+ GinJavaBoundObject::ObjectID object_id,
+ const std::string& method_name,
+ const base::ListValue& arguments,
+ IPC::Message* reply_msg);
+
+ private:
+ void OnObjectWrapperDeleted(RenderFrameHost* render_frame_host,
+ GinJavaBoundObject::ObjectID object_id);
+
+ bool IsValidRenderFrameHost(RenderFrameHost* render_frame_host);
+ void SendMethods(RenderFrameHost* render_frame_host,
+ const std::set<std::string>& method_names);
+ void SendHasMethodReply(RenderFrameHost* render_frame_host,
+ bool result);
+ void ProcessMethodInvocationResult(
+ RenderFrameHost* render_frame_host,
+ scoped_refptr<GinJavaMethodInvocationHelper> result);
+ void ProcessMethodInvocationObjectResult(
+ RenderFrameHost* render_frame_host,
+ scoped_refptr<GinJavaMethodInvocationHelper> result);
+ GinJavaBoundObject::ObjectID AddObject(
+ const base::android::JavaRef<jobject>& object,
+ const base::android::JavaRef<jclass>& safe_annotation_clazz,
+ bool is_named,
+ RenderFrameHost* holder);
+ bool FindObjectId(const base::android::JavaRef<jobject>& object,
+ GinJavaBoundObject::ObjectID* object_id);
+ void RemoveHolder(RenderFrameHost* holder,
+ const GinJavaBoundObject::ObjectMap::iterator& from,
+ size_t count);
+ bool HasPendingReply(RenderFrameHost* render_frame_host) const;
+ IPC::Message* TakePendingReply(RenderFrameHost* render_frame_host);
+
+ // Every time a GinJavaBoundObject backed by a real Java object is
+ // created/destroyed, we insert/remove a strong ref to that Java object into
+ // this set so that it doesn't get garbage collected while it's still
+ // potentially in use. Although the set is managed native side, it's owned
+ // and defined in Java so that pushing refs into it does not create new GC
+ // roots that would prevent ContentViewCore from being garbage collected.
+ JavaObjectWeakGlobalRef retained_object_set_;
+ bool allow_object_contents_inspection_;
+ GinJavaBoundObject::ObjectMap objects_;
+ typedef std::map<std::string, GinJavaBoundObject::ObjectID> NamedObjectMap;
+ NamedObjectMap named_objects_;
+
+ // Keep track of pending calls out to Java such that we can send a synchronous
+ // reply to the renderer waiting on the response should the RenderFrame be
+ // destroyed while the reply is pending.
+ // Only used on the UI thread.
+ typedef std::map<RenderFrameHost*, IPC::Message*> PendingReplyMap;
+ PendingReplyMap pending_replies_;
+
+ DISALLOW_COPY_AND_ASSIGN(GinJavaBridgeDispatcherHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_BRIDGE_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper.cc b/chromium/content/browser/android/java/gin_java_method_invocation_helper.cc
index d3fb1386544..ae1c798fe52 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper.cc
+++ b/chromium/content/browser/android/java/gin_java_method_invocation_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/renderer_host/java/gin_java_method_invocation_helper.h"
+#include "content/browser/android/java/gin_java_method_invocation_helper.h"
#include <unistd.h>
@@ -10,9 +10,9 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/float_util.h"
-#include "content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.h"
-#include "content/browser/renderer_host/java/java_method.h"
-#include "content/browser/renderer_host/java/jni_helper.h"
+#include "content/browser/android/java/gin_java_script_to_java_types_coercion.h"
+#include "content/browser/android/java/java_method.h"
+#include "content/browser/android/java/jni_helper.h"
#include "content/common/android/gin_java_bridge_value.h"
#include "content/public/browser/browser_thread.h"
@@ -23,13 +23,6 @@ namespace content {
namespace {
-const char kObjectIsGone[] = "Java object is gone";
-const char kMethodNotFound[] = "Method not found";
-const char kAccessToObjectGetClassIsBlocked[] =
- "Access to java.lang.Object.getClass is blocked";
-const char kJavaExceptionRaised[] =
- "Java exception has been raised during method invocation";
-
// See frameworks/base/core/java/android/webkit/EventLogTags.logtags
const int kObjectGetClassInvocationAttemptLogTag = 70151;
@@ -41,7 +34,8 @@ GinJavaMethodInvocationHelper::GinJavaMethodInvocationHelper(
const base::ListValue& arguments)
: object_(object.Pass()),
method_name_(method_name),
- arguments_(arguments.DeepCopy()) {
+ arguments_(arguments.DeepCopy()),
+ invocation_error_(kGinJavaBridgeNoError) {
}
GinJavaMethodInvocationHelper::~GinJavaMethodInvocationHelper() {}
@@ -121,14 +115,14 @@ void GinJavaMethodInvocationHelper::Invoke() {
const JavaMethod* method =
object_->FindMethod(method_name_, arguments_->GetSize());
if (!method) {
- SetInvocationFailure(kMethodNotFound);
+ SetInvocationError(kGinJavaBridgeMethodNotFound);
return;
}
if (object_->IsObjectGetClassMethod(method)) {
base::android::EventLogWriteInt(kObjectGetClassInvocationAttemptLogTag,
getuid());
- SetInvocationFailure(kAccessToObjectGetClassIsBlocked);
+ SetInvocationError(kGinJavaBridgeAccessToObjectGetClassIsBlocked);
return;
}
@@ -140,23 +134,33 @@ void GinJavaMethodInvocationHelper::Invoke() {
obj = object_->GetLocalRef(env);
}
if (obj.is_null() && cls.is_null()) {
- SetInvocationFailure(kObjectIsGone);
+ SetInvocationError(kGinJavaBridgeObjectIsGone);
return;
}
+ GinJavaBridgeError coercion_error = kGinJavaBridgeNoError;
std::vector<jvalue> parameters(method->num_parameters());
for (size_t i = 0; i < method->num_parameters(); ++i) {
const base::Value* argument;
arguments_->Get(i, &argument);
- parameters[i] = CoerceJavaScriptValueToJavaValue(
- env, argument, method->parameter_type(i), true, object_refs_);
+ parameters[i] = CoerceJavaScriptValueToJavaValue(env,
+ argument,
+ method->parameter_type(i),
+ true,
+ object_refs_,
+ &coercion_error);
}
- if (method->is_static()) {
- InvokeMethod(
- NULL, cls.obj(), method->return_type(), method->id(), &parameters[0]);
+
+ if (coercion_error == kGinJavaBridgeNoError) {
+ if (method->is_static()) {
+ InvokeMethod(
+ NULL, cls.obj(), method->return_type(), method->id(), &parameters[0]);
+ } else {
+ InvokeMethod(
+ obj.obj(), NULL, method->return_type(), method->id(), &parameters[0]);
+ }
} else {
- InvokeMethod(
- obj.obj(), NULL, method->return_type(), method->id(), &parameters[0]);
+ SetInvocationError(coercion_error);
}
// Now that we're done with the jvalue, release any local references created
@@ -166,11 +170,11 @@ void GinJavaMethodInvocationHelper::Invoke() {
}
}
-void GinJavaMethodInvocationHelper::SetInvocationFailure(
- const char* error_message) {
+void GinJavaMethodInvocationHelper::SetInvocationError(
+ GinJavaBridgeError error) {
holds_primitive_result_ = true;
primitive_result_.reset(new base::ListValue());
- error_message_ = error_message;
+ invocation_error_ = error;
}
void GinJavaMethodInvocationHelper::SetPrimitiveResult(
@@ -205,8 +209,8 @@ GinJavaMethodInvocationHelper::GetSafeAnnotationClass() {
return safe_annotation_clazz_;
}
-const std::string& GinJavaMethodInvocationHelper::GetErrorMessage() {
- return error_message_;
+const GinJavaBridgeError GinJavaMethodInvocationHelper::GetInvocationError() {
+ return invocation_error_;
}
void GinJavaMethodInvocationHelper::InvokeMethod(jobject object,
@@ -295,7 +299,7 @@ void GinJavaMethodInvocationHelper::InvokeMethod(jobject object,
// methods. ScopedJavaLocalRef is liable to make such calls, so we test
// first.
if (base::android::ClearException(env)) {
- SetInvocationFailure(kJavaExceptionRaised);
+ SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
return;
}
ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string);
@@ -318,7 +322,7 @@ void GinJavaMethodInvocationHelper::InvokeMethod(jobject object,
object ? env->CallObjectMethodA(object, id, parameters)
: env->CallStaticObjectMethodA(clazz, id, parameters);
if (base::android::ClearException(env)) {
- SetInvocationFailure(kJavaExceptionRaised);
+ SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
return;
}
ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object);
@@ -334,7 +338,7 @@ void GinJavaMethodInvocationHelper::InvokeMethod(jobject object,
if (!base::android::ClearException(env)) {
SetPrimitiveResult(result_wrapper);
} else {
- SetInvocationFailure(kJavaExceptionRaised);
+ SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
}
}
diff --git a/chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper.h b/chromium/content/browser/android/java/gin_java_method_invocation_helper.h
index 89805ca0696..014e3113194 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper.h
+++ b/chromium/content/browser/android/java/gin_java_method_invocation_helper.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_RENDERER_HOST_JAVA_GIN_JAVA_METHOD_INVOCATION_HELPER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_GIN_JAVA_METHOD_INVOCATION_HELPER_H_
+#ifndef CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_METHOD_INVOCATION_HELPER_H_
+#define CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_METHOD_INVOCATION_HELPER_H_
#include <map>
@@ -11,8 +11,9 @@
#include "base/android/scoped_java_ref.h"
#include "base/memory/ref_counted.h"
#include "base/values.h"
-#include "content/browser/renderer_host/java/gin_java_bound_object.h"
-#include "content/browser/renderer_host/java/java_type.h"
+#include "content/browser/android/java/gin_java_bound_object.h"
+#include "content/browser/android/java/java_type.h"
+#include "content/common/android/gin_java_bridge_errors.h"
#include "content/common/content_export.h"
namespace content {
@@ -68,7 +69,7 @@ class CONTENT_EXPORT GinJavaMethodInvocationHelper
const base::ListValue& GetPrimitiveResult();
const base::android::JavaRef<jobject>& GetObjectResult();
const base::android::JavaRef<jclass>& GetSafeAnnotationClass();
- const std::string& GetErrorMessage();
+ const GinJavaBridgeError GetInvocationError();
private:
friend class base::RefCountedThreadSafe<GinJavaMethodInvocationHelper>;
@@ -89,7 +90,7 @@ class CONTENT_EXPORT GinJavaMethodInvocationHelper
const JavaType& return_type,
jmethodID id,
jvalue* parameters);
- void SetInvocationFailure(const char* error_message);
+ void SetInvocationError(GinJavaBridgeError error);
void SetPrimitiveResult(const base::ListValue& result_wrapper);
void SetObjectResult(
const base::android::JavaRef<jobject>& object,
@@ -104,7 +105,7 @@ class CONTENT_EXPORT GinJavaMethodInvocationHelper
ObjectRefs object_refs_;
bool holds_primitive_result_;
scoped_ptr<base::ListValue> primitive_result_;
- std::string error_message_;
+ GinJavaBridgeError invocation_error_;
base::android::ScopedJavaGlobalRef<jobject> object_result_;
base::android::ScopedJavaGlobalRef<jclass> safe_annotation_clazz_;
@@ -113,4 +114,4 @@ class CONTENT_EXPORT GinJavaMethodInvocationHelper
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_GIN_JAVA_METHOD_INVOCATION_HELPER_H_
+#endif // CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_METHOD_INVOCATION_HELPER_H_
diff --git a/chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper_unittest.cc b/chromium/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc
index d7634410dee..ccd508355bb 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_method_invocation_helper_unittest.cc
+++ b/chromium/content/browser/android/java/gin_java_method_invocation_helper_unittest.cc
@@ -2,9 +2,10 @@
// 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/java/gin_java_method_invocation_helper.h"
+#include "content/browser/android/java/gin_java_method_invocation_helper.h"
#include "base/android/jni_android.h"
+#include "content/browser/android/java/jni_helper.h"
#include "content/common/android/gin_java_bridge_value.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,26 +21,26 @@ class NullObjectDelegate
virtual ~NullObjectDelegate() {}
virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef(
- JNIEnv* env) OVERRIDE {
+ JNIEnv* env) override {
return base::android::ScopedJavaLocalRef<jobject>();
}
virtual base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef(
- JNIEnv* env) OVERRIDE {
+ JNIEnv* env) override {
return base::android::ScopedJavaLocalRef<jclass>();
}
virtual const JavaMethod* FindMethod(const std::string& method_name,
- size_t num_parameters) OVERRIDE {
+ size_t num_parameters) override {
return NULL;
}
- virtual bool IsObjectGetClassMethod(const JavaMethod* method) OVERRIDE {
+ virtual bool IsObjectGetClassMethod(const JavaMethod* method) override {
return false;
}
virtual const base::android::JavaRef<jclass>& GetSafeAnnotationClass()
- OVERRIDE {
+ override {
return safe_annotation_class_;
}
@@ -57,7 +58,7 @@ class NullDispatcherDelegate
virtual ~NullDispatcherDelegate() {}
virtual JavaObjectWeakGlobalRef GetObjectWeakRef(
- GinJavaBoundObject::ObjectID object_id) OVERRIDE {
+ GinJavaBoundObject::ObjectID object_id) override {
return JavaObjectWeakGlobalRef();
}
@@ -79,7 +80,7 @@ class CountingDispatcherDelegate
virtual ~CountingDispatcherDelegate() {}
virtual JavaObjectWeakGlobalRef GetObjectWeakRef(
- GinJavaBoundObject::ObjectID object_id) OVERRIDE {
+ GinJavaBoundObject::ObjectID object_id) override {
counters_[object_id]++;
return JavaObjectWeakGlobalRef();
}
@@ -154,21 +155,73 @@ TEST_F(GinJavaMethodInvocationHelperTest, RetrievalOfObjectsHaveObjects) {
counter.AssertInvocationsCount(1, 6);
}
+namespace {
+
+class ObjectIsGoneObjectDelegate : public NullObjectDelegate {
+ public:
+ ObjectIsGoneObjectDelegate() :
+ get_local_ref_called_(false) {
+ // We need a Java Method object to create a valid JavaMethod instance.
+ JNIEnv* env = base::android::AttachCurrentThread();
+ jmethodID method_id =
+ GetMethodIDFromClassName(env, "java/lang/Object", "hashCode", "()I");
+ EXPECT_TRUE(method_id);
+ base::android::ScopedJavaLocalRef<jobject> method_obj(
+ env,
+ env->ToReflectedMethod(
+ base::android::GetClass(env, "java/lang/Object").obj(),
+ method_id,
+ false));
+ EXPECT_TRUE(method_obj.obj());
+ method_.reset(new JavaMethod(method_obj));
+ }
+
+ virtual ~ObjectIsGoneObjectDelegate() {}
+
+ virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef(
+ JNIEnv* env) override {
+ get_local_ref_called_ = true;
+ return NullObjectDelegate::GetLocalRef(env);
+ }
+
+ virtual const JavaMethod* FindMethod(const std::string& method_name,
+ size_t num_parameters) override {
+ return method_.get();
+ }
+
+ bool get_local_ref_called() { return get_local_ref_called_; }
+
+ const std::string& get_method_name() { return method_->name(); }
+
+ protected:
+ scoped_ptr<JavaMethod> method_;
+ bool get_local_ref_called_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ObjectIsGoneObjectDelegate);
+};
+
+} // namespace
+
TEST_F(GinJavaMethodInvocationHelperTest, HandleObjectIsGone) {
base::ListValue no_objects;
+ ObjectIsGoneObjectDelegate* object_delegate =
+ new ObjectIsGoneObjectDelegate();
scoped_refptr<GinJavaMethodInvocationHelper> helper =
new GinJavaMethodInvocationHelper(
scoped_ptr<GinJavaMethodInvocationHelper::ObjectDelegate>(
- new NullObjectDelegate()),
- "foo",
+ object_delegate),
+ object_delegate->get_method_name(),
no_objects);
NullDispatcherDelegate dispatcher;
helper->Init(&dispatcher);
- EXPECT_TRUE(helper->GetErrorMessage().empty());
+ EXPECT_FALSE(object_delegate->get_local_ref_called());
+ EXPECT_EQ(kGinJavaBridgeNoError, helper->GetInvocationError());
helper->Invoke();
+ EXPECT_TRUE(object_delegate->get_local_ref_called());
EXPECT_TRUE(helper->HoldsPrimitiveResult());
EXPECT_TRUE(helper->GetPrimitiveResult().empty());
- EXPECT_FALSE(helper->GetErrorMessage().empty());
+ EXPECT_EQ(kGinJavaBridgeObjectIsGone, helper->GetInvocationError());
}
namespace {
@@ -180,13 +233,13 @@ class MethodNotFoundObjectDelegate : public NullObjectDelegate {
virtual ~MethodNotFoundObjectDelegate() {}
virtual base::android::ScopedJavaLocalRef<jobject> GetLocalRef(
- JNIEnv* env) OVERRIDE {
+ JNIEnv* env) override {
return base::android::ScopedJavaLocalRef<jobject>(
env, static_cast<jobject>(env->FindClass("java/lang/String")));
}
virtual const JavaMethod* FindMethod(const std::string& method_name,
- size_t num_parameters) OVERRIDE {
+ size_t num_parameters) override {
find_method_called_ = true;
return NULL;
}
@@ -215,12 +268,12 @@ TEST_F(GinJavaMethodInvocationHelperTest, HandleMethodNotFound) {
NullDispatcherDelegate dispatcher;
helper->Init(&dispatcher);
EXPECT_FALSE(object_delegate->find_method_called());
- EXPECT_TRUE(helper->GetErrorMessage().empty());
+ EXPECT_EQ(kGinJavaBridgeNoError, helper->GetInvocationError());
helper->Invoke();
EXPECT_TRUE(object_delegate->find_method_called());
EXPECT_TRUE(helper->HoldsPrimitiveResult());
EXPECT_TRUE(helper->GetPrimitiveResult().empty());
- EXPECT_FALSE(helper->GetErrorMessage().empty());
+ EXPECT_EQ(kGinJavaBridgeMethodNotFound, helper->GetInvocationError());
}
namespace {
@@ -232,12 +285,12 @@ class GetClassObjectDelegate : public MethodNotFoundObjectDelegate {
virtual ~GetClassObjectDelegate() {}
virtual const JavaMethod* FindMethod(const std::string& method_name,
- size_t num_parameters) OVERRIDE {
+ size_t num_parameters) override {
find_method_called_ = true;
return kFakeGetClass;
}
- virtual bool IsObjectGetClassMethod(const JavaMethod* method) OVERRIDE {
+ virtual bool IsObjectGetClassMethod(const JavaMethod* method) override {
get_class_called_ = true;
return kFakeGetClass == method;
}
@@ -273,13 +326,14 @@ TEST_F(GinJavaMethodInvocationHelperTest, HandleGetClassInvocation) {
helper->Init(&dispatcher);
EXPECT_FALSE(object_delegate->find_method_called());
EXPECT_FALSE(object_delegate->get_class_called());
- EXPECT_TRUE(helper->GetErrorMessage().empty());
+ EXPECT_EQ(kGinJavaBridgeNoError, helper->GetInvocationError());
helper->Invoke();
EXPECT_TRUE(object_delegate->find_method_called());
EXPECT_TRUE(object_delegate->get_class_called());
EXPECT_TRUE(helper->HoldsPrimitiveResult());
EXPECT_TRUE(helper->GetPrimitiveResult().empty());
- EXPECT_FALSE(helper->GetErrorMessage().empty());
+ EXPECT_EQ(kGinJavaBridgeAccessToObjectGetClassIsBlocked,
+ helper->GetInvocationError());
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc b/chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
index 8f7c29f16eb..cb4e51776b4 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.cc
+++ b/chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.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/renderer_host/java/gin_java_script_to_java_types_coercion.h"
+#include "content/browser/android/java/gin_java_script_to_java_types_coercion.h"
#include <unistd.h>
@@ -14,6 +14,7 @@
#include "content/common/android/gin_java_bridge_value.h"
using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaLocalRef;
namespace content {
@@ -61,7 +62,8 @@ jint RoundDoubleToInt(const double& x) {
jvalue CoerceJavaScriptIntegerToJavaValue(JNIEnv* env,
const base::Value* value,
const JavaType& target_type,
- bool coerce_to_string) {
+ bool coerce_to_string,
+ GinJavaBridgeError* error) {
// See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES.
// For conversion to numeric types, we need to replicate Java's type
@@ -125,7 +127,8 @@ jvalue CoerceJavaScriptIntegerToJavaValue(JNIEnv* env,
jvalue CoerceJavaScriptDoubleToJavaValue(JNIEnv* env,
double double_value,
const JavaType& target_type,
- bool coerce_to_string) {
+ bool coerce_to_string,
+ GinJavaBridgeError* error) {
// See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES.
// For conversion to numeric types, we need to replicate Java's type
// conversion rules.
@@ -188,7 +191,8 @@ jvalue CoerceJavaScriptDoubleToJavaValue(JNIEnv* env,
jvalue CoerceJavaScriptBooleanToJavaValue(JNIEnv* env,
const base::Value* value,
const JavaType& target_type,
- bool coerce_to_string) {
+ bool coerce_to_string,
+ GinJavaBridgeError* error) {
// See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES.
bool boolean_value;
value->GetAsBoolean(&boolean_value);
@@ -236,7 +240,8 @@ jvalue CoerceJavaScriptBooleanToJavaValue(JNIEnv* env,
jvalue CoerceJavaScriptStringToJavaValue(JNIEnv* env,
const base::Value* value,
- const JavaType& target_type) {
+ const JavaType& target_type,
+ GinJavaBridgeError* error) {
// See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES.
jvalue result;
switch (target_type.type) {
@@ -306,7 +311,7 @@ jobject CreateJavaArray(JNIEnv* env, const JavaType& type, jsize length) {
case JavaType::TypeDouble:
return env->NewDoubleArray(length);
case JavaType::TypeString: {
- base::android::ScopedJavaLocalRef<jclass> clazz(
+ ScopedJavaLocalRef<jclass> clazz(
base::android::GetClass(env, kJavaLangString));
return env->NewObjectArray(length, clazz.obj(), NULL);
}
@@ -379,7 +384,8 @@ void SetArrayElement(JNIEnv* env,
jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(JNIEnv* env,
const base::Value* value,
const JavaType& target_type,
- bool coerce_to_string) {
+ bool coerce_to_string,
+ GinJavaBridgeError* error) {
bool is_undefined = false;
scoped_ptr<const GinJavaBridgeValue> gin_value;
if (GinJavaBridgeValue::ContainsGinJavaBridgeValue(value)) {
@@ -430,7 +436,8 @@ jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(JNIEnv* env,
jobject CoerceJavaScriptListToArray(JNIEnv* env,
const base::Value* value,
const JavaType& target_type,
- const ObjectRefs& object_refs) {
+ const ObjectRefs& object_refs,
+ GinJavaBridgeError* error) {
DCHECK_EQ(JavaType::TypeArray, target_type.type);
const JavaType& target_inner_type = *target_type.inner_type.get();
// LIVECONNECT_COMPLIANCE: Existing behavior is to return null for
@@ -458,7 +465,7 @@ jobject CoerceJavaScriptListToArray(JNIEnv* env,
const base::Value* value_element = null_value.get();
list_value->Get(i, &value_element);
jvalue element = CoerceJavaScriptValueToJavaValue(
- env, value_element, target_inner_type, false, object_refs);
+ env, value_element, target_inner_type, false, object_refs, error);
SetArrayElement(env, result, target_inner_type, i, element);
// CoerceJavaScriptValueToJavaValue() creates new local references to
// strings, objects and arrays. Of these, only strings can occur here.
@@ -475,7 +482,8 @@ jobject CoerceJavaScriptListToArray(JNIEnv* env,
jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env,
const base::Value* value,
const JavaType& target_type,
- const ObjectRefs& object_refs) {
+ const ObjectRefs& object_refs,
+ GinJavaBridgeError* error) {
DCHECK_EQ(JavaType::TypeArray, target_type.type);
const JavaType& target_inner_type = *target_type.inner_type.get();
@@ -531,7 +539,7 @@ jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env,
dictionary_value->Get(key, &value_element);
}
jvalue element = CoerceJavaScriptValueToJavaValue(
- env, value_element, target_inner_type, false, object_refs);
+ env, value_element, target_inner_type, false, object_refs, error);
SetArrayElement(env, result, target_inner_type, i, element);
// CoerceJavaScriptValueToJavaValue() creates new local references to
// strings, objects and arrays. Of these, only strings can occur here.
@@ -545,11 +553,29 @@ jobject CoerceJavaScriptDictionaryToArray(JNIEnv* env,
return result;
}
+// Returns 'true' if it is possible to cast an object of class |src| to
+// an object of class |dst|.
+bool CanAssignClassVariables(JNIEnv* env,
+ const ScopedJavaLocalRef<jclass>& dst,
+ const ScopedJavaLocalRef<jclass>& src) {
+ if (dst.is_null() || src.is_null())
+ return false;
+ return env->IsAssignableFrom(src.obj(), dst.obj()) == JNI_TRUE;
+}
+
+ScopedJavaLocalRef<jclass> GetObjectClass(
+ JNIEnv* env,
+ const ScopedJavaLocalRef<jobject>& obj) {
+ jclass clazz = env->GetObjectClass(obj.obj());
+ return ScopedJavaLocalRef<jclass>(env, clazz);
+}
+
jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env,
const base::Value* value,
const JavaType& target_type,
bool coerce_to_string,
- const ObjectRefs& object_refs) {
+ const ObjectRefs& object_refs,
+ GinJavaBridgeError* error) {
// This covers both JavaScript objects (including arrays) and Java objects.
// See http://jdk6.java.net/plugin2/liveconnect/#JS_OTHER_OBJECTS,
// http://jdk6.java.net/plugin2/liveconnect/#JS_ARRAY_VALUES and
@@ -562,7 +588,7 @@ jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env,
GinJavaBridgeValue::FromValue(value));
DCHECK(gin_value);
DCHECK(gin_value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID));
- base::android::ScopedJavaLocalRef<jobject> obj;
+ ScopedJavaLocalRef<jobject> obj;
GinJavaBoundObject::ObjectID object_id;
if (gin_value->GetAsObjectID(&object_id)) {
ObjectRefs::const_iterator iter = object_refs.find(object_id);
@@ -570,7 +596,17 @@ jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env,
obj.Reset(iter->second.get(env));
}
}
- result.l = obj.Release();
+ DCHECK(!target_type.class_jni_name.empty());
+ DCHECK(!obj.is_null());
+ if (CanAssignClassVariables(
+ env,
+ base::android::GetClass(env, target_type.JNIName().c_str()),
+ GetObjectClass(env, obj))) {
+ result.l = obj.Release();
+ } else {
+ result.l = NULL;
+ *error = kGinJavaBridgeNonAssignableTypes;
+ }
} else {
// LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec
// requires converting if the target type is
@@ -608,10 +644,10 @@ jvalue CoerceJavaScriptObjectToJavaValue(JNIEnv* env,
case JavaType::TypeArray:
if (value->IsType(base::Value::TYPE_DICTIONARY)) {
result.l = CoerceJavaScriptDictionaryToArray(
- env, value, target_type, object_refs);
+ env, value, target_type, object_refs, error);
} else if (value->IsType(base::Value::TYPE_LIST)) {
- result.l =
- CoerceJavaScriptListToArray(env, value, target_type, object_refs);
+ result.l = CoerceJavaScriptListToArray(
+ env, value, target_type, object_refs, error);
} else {
result.l = NULL;
}
@@ -628,23 +664,24 @@ jvalue CoerceGinJavaBridgeValueToJavaValue(JNIEnv* env,
const base::Value* value,
const JavaType& target_type,
bool coerce_to_string,
- const ObjectRefs& object_refs) {
+ const ObjectRefs& object_refs,
+ GinJavaBridgeError* error) {
DCHECK(GinJavaBridgeValue::ContainsGinJavaBridgeValue(value));
scoped_ptr<const GinJavaBridgeValue> gin_value(
GinJavaBridgeValue::FromValue(value));
switch (gin_value->GetType()) {
case GinJavaBridgeValue::TYPE_UNDEFINED:
return CoerceJavaScriptNullOrUndefinedToJavaValue(
- env, value, target_type, coerce_to_string);
+ env, value, target_type, coerce_to_string, error);
case GinJavaBridgeValue::TYPE_NONFINITE: {
float float_value;
gin_value->GetAsNonFinite(&float_value);
return CoerceJavaScriptDoubleToJavaValue(
- env, float_value, target_type, coerce_to_string);
+ env, float_value, target_type, coerce_to_string, error);
}
case GinJavaBridgeValue::TYPE_OBJECT_ID:
return CoerceJavaScriptObjectToJavaValue(
- env, value, target_type, coerce_to_string, object_refs);
+ env, value, target_type, coerce_to_string, object_refs, error);
default:
NOTREACHED();
}
@@ -668,35 +705,36 @@ jvalue CoerceJavaScriptValueToJavaValue(JNIEnv* env,
const base::Value* value,
const JavaType& target_type,
bool coerce_to_string,
- const ObjectRefs& object_refs) {
+ const ObjectRefs& object_refs,
+ GinJavaBridgeError* error) {
// Note that in all these conversions, the relevant field of the jvalue must
// always be explicitly set, as jvalue does not initialize its fields.
switch (value->GetType()) {
case base::Value::TYPE_INTEGER:
return CoerceJavaScriptIntegerToJavaValue(
- env, value, target_type, coerce_to_string);
+ env, value, target_type, coerce_to_string, error);
case base::Value::TYPE_DOUBLE: {
double double_value;
value->GetAsDouble(&double_value);
return CoerceJavaScriptDoubleToJavaValue(
- env, double_value, target_type, coerce_to_string);
+ env, double_value, target_type, coerce_to_string, error);
}
case base::Value::TYPE_BOOLEAN:
return CoerceJavaScriptBooleanToJavaValue(
- env, value, target_type, coerce_to_string);
+ env, value, target_type, coerce_to_string, error);
case base::Value::TYPE_STRING:
- return CoerceJavaScriptStringToJavaValue(env, value, target_type);
+ return CoerceJavaScriptStringToJavaValue(env, value, target_type, error);
case base::Value::TYPE_DICTIONARY:
case base::Value::TYPE_LIST:
return CoerceJavaScriptObjectToJavaValue(
- env, value, target_type, coerce_to_string, object_refs);
+ env, value, target_type, coerce_to_string, object_refs, error);
case base::Value::TYPE_NULL:
return CoerceJavaScriptNullOrUndefinedToJavaValue(
- env, value, target_type, coerce_to_string);
+ env, value, target_type, coerce_to_string, error);
case base::Value::TYPE_BINARY:
return CoerceGinJavaBridgeValueToJavaValue(
- env, value, target_type, coerce_to_string, object_refs);
+ env, value, target_type, coerce_to_string, object_refs, error);
}
NOTREACHED();
return jvalue();
diff --git a/chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.h b/chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.h
index 1df7345ecc6..5b8fc7514b6 100644
--- a/chromium/content/browser/renderer_host/java/gin_java_script_to_java_types_coercion.h
+++ b/chromium/content/browser/android/java/gin_java_script_to_java_types_coercion.h
@@ -2,15 +2,16 @@
// 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_JAVA_GIN_JAVA_SCRIPT_TO_JAVA_TYPES_COERCION_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_GIN_JAVA_SCRIPT_TO_JAVA_TYPES_COERCION_H_
+#ifndef CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_SCRIPT_TO_JAVA_TYPES_COERCION_H_
+#define CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_SCRIPT_TO_JAVA_TYPES_COERCION_H_
#include <map>
#include "base/android/jni_weak_ref.h"
#include "base/values.h"
-#include "content/browser/renderer_host/java/gin_java_bound_object.h"
-#include "content/browser/renderer_host/java/java_type.h"
+#include "content/browser/android/java/gin_java_bound_object.h"
+#include "content/browser/android/java/java_type.h"
+#include "content/common/android/gin_java_bridge_errors.h"
namespace content {
@@ -22,7 +23,8 @@ jvalue CoerceJavaScriptValueToJavaValue(
const base::Value* value,
const JavaType& target_type,
bool coerce_to_string,
- const ObjectRefs& object_refs);
+ const ObjectRefs& object_refs,
+ GinJavaBridgeError* error);
void ReleaseJavaValueIfRequired(JNIEnv* env,
jvalue* value,
@@ -30,4 +32,4 @@ void ReleaseJavaValueIfRequired(JNIEnv* env,
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_GIN_JAVA_SCRIPT_TO_JAVA_TYPES_COERCION_H_
+#endif // CONTENT_BROWSER_ANDROID_JAVA_GIN_JAVA_SCRIPT_TO_JAVA_TYPES_COERCION_H_
diff --git a/chromium/content/browser/renderer_host/java/java_method.cc b/chromium/content/browser/android/java/java_method.cc
index 03bdb2d7e06..9da0102cf33 100644
--- a/chromium/content/browser/renderer_host/java/java_method.cc
+++ b/chromium/content/browser/android/java/java_method.cc
@@ -1,15 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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/renderer_host/java/java_method.h"
+#include "content/browser/android/java/java_method.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
-#include "base/strings/string_util.h" // For ReplaceSubstringsAfterOffset
-#include "content/browser/renderer_host/java/jni_helper.h"
+#include "content/browser/android/java/jni_helper.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
@@ -50,43 +49,11 @@ struct ModifierClassTraits :
base::LazyInstance<ScopedJavaGlobalRef<jclass>, ModifierClassTraits>
g_java_lang_reflect_modifier_class = LAZY_INSTANCE_INITIALIZER;
-std::string BinaryNameToJNIName(const std::string& binary_name,
- JavaType* type) {
+std::string BinaryNameToJNISignature(const std::string& binary_name,
+ JavaType* type) {
DCHECK(type);
*type = JavaType::CreateFromBinaryName(binary_name);
- switch (type->type) {
- case JavaType::TypeBoolean:
- return "Z";
- case JavaType::TypeByte:
- return "B";
- case JavaType::TypeChar:
- return "C";
- case JavaType::TypeShort:
- return "S";
- case JavaType::TypeInt:
- return "I";
- case JavaType::TypeLong:
- return "J";
- case JavaType::TypeFloat:
- return "F";
- case JavaType::TypeDouble:
- return "D";
- case JavaType::TypeVoid:
- return "V";
- case JavaType::TypeArray: {
- // For array types, the binary name uses the JNI name encodings.
- std::string jni_name = binary_name;
- ReplaceSubstringsAfterOffset(&jni_name, 0, ".", "/");
- return jni_name;
- }
- case JavaType::TypeString:
- case JavaType::TypeObject:
- std::string jni_name = "L" + binary_name + ";";
- ReplaceSubstringsAfterOffset(&jni_name, 0, ".", "/");
- return jni_name;
- }
- NOTREACHED();
- return std::string();
+ return type->JNISignature();
}
} // namespace
@@ -191,7 +158,7 @@ void JavaMethod::EnsureTypesAndIDAreSetUp() const {
kGetName,
kReturningJavaLangString))));
std::string name_utf8 = ConvertJavaStringToUTF8(name);
- signature += BinaryNameToJNIName(name_utf8, &parameter_types_[i]);
+ signature += BinaryNameToJNISignature(name_utf8, &parameter_types_[i]);
}
signature += ")";
@@ -208,8 +175,8 @@ void JavaMethod::EnsureTypesAndIDAreSetUp() const {
kJavaLangClass,
kGetName,
kReturningJavaLangString))));
- signature += BinaryNameToJNIName(ConvertJavaStringToUTF8(name),
- &return_type_);
+ signature += BinaryNameToJNISignature(ConvertJavaStringToUTF8(name),
+ &return_type_);
// Determine whether the method is static.
jint modifiers = env->CallIntMethod(
diff --git a/chromium/content/browser/renderer_host/java/java_method.h b/chromium/content/browser/android/java/java_method.h
index 1d59bacc5a0..b5ba26a6f5f 100644
--- a/chromium/content/browser/renderer_host/java/java_method.h
+++ b/chromium/content/browser/android/java/java_method.h
@@ -1,22 +1,23 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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_RENDERER_HOST_JAVA_JAVA_METHOD_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_METHOD_H_
+#ifndef CONTENT_BROWSER_ANDROID_JAVA_JAVA_METHOD_H_
+#define CONTENT_BROWSER_ANDROID_JAVA_JAVA_METHOD_H_
#include <jni.h>
#include <string>
#include <vector>
#include "base/android/scoped_java_ref.h"
-#include "content/browser/renderer_host/java/java_type.h"
+#include "content/browser/android/java/java_type.h"
+#include "content/common/content_export.h"
namespace content {
// Wrapper around java.lang.reflect.Method. This class must be used on a single
// thread only.
-class JavaMethod {
+class CONTENT_EXPORT JavaMethod {
public:
explicit JavaMethod(const base::android::JavaRef<jobject>& method);
~JavaMethod();
@@ -46,4 +47,4 @@ class JavaMethod {
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_METHOD_H_
+#endif // CONTENT_BROWSER_ANDROID_JAVA_JAVA_METHOD_H_
diff --git a/chromium/content/browser/android/java/java_type.cc b/chromium/content/browser/android/java/java_type.cc
new file mode 100644
index 00000000000..5cd9b545435
--- /dev/null
+++ b/chromium/content/browser/android/java/java_type.cc
@@ -0,0 +1,165 @@
+// 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/android/java/java_type.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h" // For ReplaceSubstringsAfterOffset
+
+namespace content {
+namespace {
+
+// Array component type names are similar to JNI type names, except for using
+// dots as namespace separators in class names.
+scoped_ptr<JavaType> CreateFromArrayComponentTypeName(
+ const std::string& type_name) {
+ scoped_ptr<JavaType> result(new JavaType());
+ DCHECK(!type_name.empty());
+ switch (type_name[0]) {
+ case 'Z':
+ result->type = JavaType::TypeBoolean;
+ break;
+ case 'B':
+ result->type = JavaType::TypeByte;
+ break;
+ case 'C':
+ result->type = JavaType::TypeChar;
+ break;
+ case 'S':
+ result->type = JavaType::TypeShort;
+ break;
+ case 'I':
+ result->type = JavaType::TypeInt;
+ break;
+ case 'J':
+ result->type = JavaType::TypeLong;
+ break;
+ case 'F':
+ result->type = JavaType::TypeFloat;
+ break;
+ case 'D':
+ result->type = JavaType::TypeDouble;
+ break;
+ case '[':
+ result->type = JavaType::TypeArray;
+ result->inner_type =
+ CreateFromArrayComponentTypeName(type_name.substr(1));
+ break;
+ case 'L':
+ if (type_name == "Ljava.lang.String;") {
+ result->type = JavaType::TypeString;
+ result->class_jni_name = "java/lang/String";
+ } else {
+ result->type = JavaType::TypeObject;
+ result->class_jni_name = type_name.substr(1, type_name.length() - 2);
+ ReplaceSubstringsAfterOffset(&result->class_jni_name, 0, ".", "/");
+ }
+ break;
+ default:
+ // Includes void (V).
+ NOTREACHED();
+ }
+ return result.Pass();
+}
+
+} // namespace
+
+JavaType::JavaType() {
+}
+
+JavaType::JavaType(const JavaType& other) {
+ *this = other;
+}
+
+JavaType::~JavaType() {
+}
+
+JavaType& JavaType::operator=(const JavaType& other) {
+ if (this == &other)
+ return *this;
+ type = other.type;
+ if (other.inner_type) {
+ DCHECK_EQ(JavaType::TypeArray, type);
+ inner_type.reset(new JavaType(*other.inner_type));
+ } else {
+ inner_type.reset();
+ }
+ class_jni_name = other.class_jni_name;
+ return *this;
+}
+
+// static
+JavaType JavaType::CreateFromBinaryName(const std::string& binary_name) {
+ JavaType result;
+ DCHECK(!binary_name.empty());
+ if (binary_name == "boolean") {
+ result.type = JavaType::TypeBoolean;
+ } else if (binary_name == "byte") {
+ result.type = JavaType::TypeByte;
+ } else if (binary_name == "char") {
+ result.type = JavaType::TypeChar;
+ } else if (binary_name == "short") {
+ result.type = JavaType::TypeShort;
+ } else if (binary_name == "int") {
+ result.type = JavaType::TypeInt;
+ } else if (binary_name == "long") {
+ result.type = JavaType::TypeLong;
+ } else if (binary_name == "float") {
+ result.type = JavaType::TypeFloat;
+ } else if (binary_name == "double") {
+ result.type = JavaType::TypeDouble;
+ } else if (binary_name == "void") {
+ result.type = JavaType::TypeVoid;
+ } else if (binary_name[0] == '[') {
+ result.type = JavaType::TypeArray;
+ result.inner_type = CreateFromArrayComponentTypeName(binary_name.substr(1));
+ } else if (binary_name == "java.lang.String") {
+ result.type = JavaType::TypeString;
+ result.class_jni_name = "java/lang/String";
+ } else {
+ result.type = JavaType::TypeObject;
+ result.class_jni_name = binary_name;
+ ReplaceSubstringsAfterOffset(&result.class_jni_name, 0, ".", "/");
+ }
+ return result;
+}
+
+std::string JavaType::JNIName() const {
+ switch (type) {
+ case JavaType::TypeBoolean:
+ return "Z";
+ case JavaType::TypeByte:
+ return "B";
+ case JavaType::TypeChar:
+ return "C";
+ case JavaType::TypeShort:
+ return "S";
+ case JavaType::TypeInt:
+ return "I";
+ case JavaType::TypeLong:
+ return "J";
+ case JavaType::TypeFloat:
+ return "F";
+ case JavaType::TypeDouble:
+ return "D";
+ case JavaType::TypeVoid:
+ return "V";
+ case JavaType::TypeArray:
+ return "[" + inner_type->JNISignature();
+ case JavaType::TypeString:
+ case JavaType::TypeObject:
+ return class_jni_name;
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+std::string JavaType::JNISignature() const {
+ if (type == JavaType::TypeString || type == JavaType::TypeObject)
+ return "L" + JNIName() + ";";
+ else
+ return JNIName();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/java/java_type.h b/chromium/content/browser/android/java/java_type.h
index fe7845eeaa6..0ad12d69840 100644
--- a/chromium/content/browser/renderer_host/java/java_type.h
+++ b/chromium/content/browser/android/java/java_type.h
@@ -1,19 +1,20 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_RENDERER_HOST_JAVA_JAVA_TYPE_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_TYPE_H_
+#ifndef CONTENT_BROWSER_ANDROID_JAVA_JAVA_TYPE_H_
+#define CONTENT_BROWSER_ANDROID_JAVA_JAVA_TYPE_H_
#include <string>
#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
namespace content {
// The type of a Java value. A light-weight enum-like structure intended for
// use by value and in STL containers.
-struct JavaType {
+struct CONTENT_EXPORT JavaType {
JavaType();
JavaType(const JavaType& other);
~JavaType();
@@ -23,6 +24,11 @@ struct JavaType {
// 'binary name'.
static JavaType CreateFromBinaryName(const std::string& binary_name);
+ // JNIName is used with FindClass.
+ std::string JNIName() const;
+ // JNISignature is used for creating method signatures.
+ std::string JNISignature() const;
+
enum Type {
TypeBoolean,
TypeByte,
@@ -43,8 +49,9 @@ struct JavaType {
Type type;
scoped_ptr<JavaType> inner_type; // Used for TypeArray only.
+ std::string class_jni_name; // Used for TypeString and TypeObject only.
};
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_TYPE_H_
+#endif // CONTENT_BROWSER_ANDROID_JAVA_JAVA_TYPE_H_
diff --git a/chromium/content/browser/android/java/java_type_unittest.cc b/chromium/content/browser/android/java/java_type_unittest.cc
new file mode 100644
index 00000000000..484b3eb43a9
--- /dev/null
+++ b/chromium/content/browser/android/java/java_type_unittest.cc
@@ -0,0 +1,86 @@
+// 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/android/java/java_type.h"
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class JavaTypeTest : public testing::Test {
+};
+
+TEST_F(JavaTypeTest, ScalarTypes) {
+ struct {
+ const char* binary_type;
+ JavaType::Type java_type;
+ const char* jni_name;
+ const char* jni_signature;
+ } scalar_types[] = {
+ {"boolean", JavaType::TypeBoolean, "Z", "Z"},
+ {"byte", JavaType::TypeByte, "B", "B"},
+ {"char", JavaType::TypeChar, "C", "C"},
+ {"short", JavaType::TypeShort, "S", "S"},
+ {"int", JavaType::TypeInt, "I", "I"},
+ {"long", JavaType::TypeLong, "J", "J"},
+ {"float", JavaType::TypeFloat, "F", "F"},
+ {"double", JavaType::TypeDouble, "D", "D"},
+ {"void", JavaType::TypeVoid, "V", "V"},
+ {"java.lang.String", JavaType::TypeString, "java/lang/String",
+ "Ljava/lang/String;"},
+ {"java.lang.Object", JavaType::TypeObject, "java/lang/Object",
+ "Ljava/lang/Object;"},
+ {"my.nested.Type$Foo", JavaType::TypeObject, "my/nested/Type$Foo",
+ "Lmy/nested/Type$Foo;"}};
+ for (size_t i = 0; i < arraysize(scalar_types); ++i) {
+ JavaType jt = JavaType::CreateFromBinaryName(scalar_types[i].binary_type);
+ EXPECT_EQ(scalar_types[i].java_type, jt.type);
+ EXPECT_FALSE(jt.inner_type);
+ EXPECT_EQ(scalar_types[i].jni_name, jt.JNIName());
+ EXPECT_EQ(scalar_types[i].jni_signature, jt.JNISignature());
+ }
+}
+
+TEST_F(JavaTypeTest, ArrayTypes) {
+ JavaType array_of_boolean = JavaType::CreateFromBinaryName("[Z");
+ EXPECT_EQ(JavaType::TypeArray, array_of_boolean.type);
+ EXPECT_TRUE(array_of_boolean.inner_type);
+ EXPECT_EQ(JavaType::TypeBoolean, array_of_boolean.inner_type->type);
+ EXPECT_FALSE(array_of_boolean.inner_type->inner_type);
+ EXPECT_EQ("[Z", array_of_boolean.JNIName());
+ EXPECT_EQ("[Z", array_of_boolean.JNISignature());
+
+ JavaType array_of_boolean_2d = JavaType::CreateFromBinaryName("[[Z");
+ EXPECT_EQ(JavaType::TypeArray, array_of_boolean_2d.type);
+ EXPECT_TRUE(array_of_boolean_2d.inner_type);
+ EXPECT_EQ(JavaType::TypeArray, array_of_boolean_2d.inner_type->type);
+ EXPECT_TRUE(array_of_boolean_2d.inner_type->inner_type);
+ EXPECT_EQ(JavaType::TypeBoolean,
+ array_of_boolean_2d.inner_type->inner_type->type);
+ EXPECT_FALSE(array_of_boolean_2d.inner_type->inner_type->inner_type);
+ EXPECT_EQ("[[Z", array_of_boolean_2d.JNIName());
+ EXPECT_EQ("[[Z", array_of_boolean_2d.JNISignature());
+
+ JavaType array_of_string =
+ JavaType::CreateFromBinaryName("[Ljava.lang.String;");
+ EXPECT_EQ(JavaType::TypeArray, array_of_string.type);
+ EXPECT_TRUE(array_of_string.inner_type);
+ EXPECT_EQ(JavaType::TypeString, array_of_string.inner_type->type);
+ EXPECT_FALSE(array_of_string.inner_type->inner_type);
+ EXPECT_EQ("[Ljava/lang/String;", array_of_string.JNIName());
+ EXPECT_EQ("[Ljava/lang/String;", array_of_string.JNISignature());
+
+ JavaType array_of_object =
+ JavaType::CreateFromBinaryName("[Ljava.lang.Object;");
+ EXPECT_EQ(JavaType::TypeArray, array_of_object.type);
+ EXPECT_TRUE(array_of_object.inner_type);
+ EXPECT_EQ(JavaType::TypeObject, array_of_object.inner_type->type);
+ EXPECT_FALSE(array_of_object.inner_type->inner_type);
+ EXPECT_EQ("[Ljava/lang/Object;", array_of_object.JNIName());
+ EXPECT_EQ("[Ljava/lang/Object;", array_of_object.JNISignature());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/overscroll_glow.cc b/chromium/content/browser/android/overscroll_glow.cc
index fb491f3ebaa..6df795a2db2 100644
--- a/chromium/content/browser/android/overscroll_glow.cc
+++ b/chromium/content/browser/android/overscroll_glow.cc
@@ -4,13 +4,8 @@
#include "content/browser/android/overscroll_glow.h"
-#include "base/debug/trace_event.h"
-#include "base/lazy_instance.h"
-#include "base/threading/worker_pool.h"
-#include "cc/layers/image_layer.h"
-#include "content/browser/android/edge_effect.h"
-#include "skia/ext/image_operations.h"
-#include "ui/gfx/android/java_bitmap.h"
+#include "cc/layers/layer.h"
+#include "content/browser/android/edge_effect_base.h"
using std::max;
using std::min;
@@ -20,56 +15,6 @@ namespace content {
namespace {
const float kEpsilon = 1e-3f;
-const int kScaledEdgeHeight = 12;
-const int kScaledGlowHeight = 64;
-const float kEdgeHeightAtMdpi = 12.f;
-const float kGlowHeightAtMdpi = 128.f;
-
-SkBitmap CreateSkBitmapFromAndroidResource(const char* name, gfx::Size size) {
- base::android::ScopedJavaLocalRef<jobject> jobj =
- gfx::CreateJavaBitmapFromAndroidResource(name, size);
- if (jobj.is_null())
- return SkBitmap();
-
- SkBitmap bitmap = CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(jobj.obj()));
- if (bitmap.isNull())
- return bitmap;
-
- return skia::ImageOperations::Resize(
- bitmap, skia::ImageOperations::RESIZE_BOX, size.width(), size.height());
-}
-
-class OverscrollResources {
- public:
- OverscrollResources() {
- TRACE_EVENT0("browser", "OverscrollResources::Create");
- edge_bitmap_ =
- CreateSkBitmapFromAndroidResource("android:drawable/overscroll_edge",
- gfx::Size(128, kScaledEdgeHeight));
- glow_bitmap_ =
- CreateSkBitmapFromAndroidResource("android:drawable/overscroll_glow",
- gfx::Size(128, kScaledGlowHeight));
- }
-
- const SkBitmap& edge_bitmap() const { return edge_bitmap_; }
- const SkBitmap& glow_bitmap() const { return glow_bitmap_; }
-
- private:
- SkBitmap edge_bitmap_;
- SkBitmap glow_bitmap_;
-
- DISALLOW_COPY_AND_ASSIGN(OverscrollResources);
-};
-
-// Leaky to allow access from a worker thread.
-base::LazyInstance<OverscrollResources>::Leaky g_overscroll_resources =
- LAZY_INSTANCE_INITIALIZER;
-
-scoped_refptr<cc::Layer> CreateImageLayer(const SkBitmap& bitmap) {
- scoped_refptr<cc::ImageLayer> layer = cc::ImageLayer::Create();
- layer->SetBitmap(bitmap);
- return layer;
-}
bool IsApproxZero(float value) {
return std::abs(value) < kEpsilon;
@@ -83,26 +28,60 @@ gfx::Vector2dF ZeroSmallComponents(gfx::Vector2dF vector) {
return vector;
}
-// Force loading of any necessary resources. This function is thread-safe.
-void EnsureResources() {
- g_overscroll_resources.Get();
+gfx::Transform ComputeTransform(OverscrollGlow::Edge edge,
+ const gfx::SizeF& window_size,
+ float offset) {
+ // Transforms assume the edge layers are anchored to their *top center point*.
+ switch (edge) {
+ case OverscrollGlow::EDGE_TOP:
+ return gfx::Transform(1, 0, 0, 1, 0, offset);
+ case OverscrollGlow::EDGE_LEFT:
+ return gfx::Transform(0,
+ 1,
+ -1,
+ 0,
+ -window_size.height() / 2.f + offset,
+ window_size.height() / 2.f);
+ case OverscrollGlow::EDGE_BOTTOM:
+ return gfx::Transform(-1, 0, 0, -1, 0, window_size.height() + offset);
+ case OverscrollGlow::EDGE_RIGHT:
+ return gfx::Transform(
+ 0,
+ -1,
+ 1,
+ 0,
+ -window_size.height() / 2.f + window_size.width() + offset,
+ window_size.height() / 2.f);
+ default:
+ NOTREACHED() << "Invalid edge: " << edge;
+ return gfx::Transform();
+ };
}
-} // namespace
+gfx::SizeF ComputeSize(OverscrollGlow::Edge edge,
+ const gfx::SizeF& window_size) {
+ switch (edge) {
+ case OverscrollGlow::EDGE_TOP:
+ case OverscrollGlow::EDGE_BOTTOM:
+ return window_size;
+ case OverscrollGlow::EDGE_LEFT:
+ case OverscrollGlow::EDGE_RIGHT:
+ return gfx::SizeF(window_size.height(), window_size.width());
+ default:
+ NOTREACHED() << "Invalid edge: " << edge;
+ return gfx::SizeF();
+ };
+}
-scoped_ptr<OverscrollGlow> OverscrollGlow::Create(bool enabled) {
- // Don't block the main thread with effect resource loading during creation.
- // Effect instantiation is deferred until the effect overscrolls, in which
- // case the main thread may block until the resource has loaded.
- if (enabled && g_overscroll_resources == NULL)
- base::WorkerPool::PostTask(FROM_HERE, base::Bind(EnsureResources), true);
+} // namespace
- return make_scoped_ptr(new OverscrollGlow(enabled));
+OverscrollGlow::OverscrollGlow(const EdgeEffectProvider& edge_effect_provider)
+ : edge_effect_provider_(edge_effect_provider),
+ enabled_(true),
+ initialized_(false) {
+ DCHECK(!edge_effect_provider_.is_null());
}
-OverscrollGlow::OverscrollGlow(bool enabled)
- : enabled_(enabled), initialized_(false) {}
-
OverscrollGlow::~OverscrollGlow() {
Detach();
}
@@ -117,7 +96,7 @@ void OverscrollGlow::Disable() {
enabled_ = false;
if (!enabled_ && initialized_) {
Detach();
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i)
+ for (size_t i = 0; i < EDGE_COUNT; ++i)
edge_effects_[i]->Finish();
}
}
@@ -126,7 +105,8 @@ bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer,
base::TimeTicks current_time,
gfx::Vector2dF accumulated_overscroll,
gfx::Vector2dF overscroll_delta,
- gfx::Vector2dF velocity) {
+ gfx::Vector2dF velocity,
+ gfx::Vector2dF displacement) {
DCHECK(overscrolling_layer);
if (!enabled_)
@@ -156,16 +136,11 @@ bool OverscrollGlow::OnOverscrolled(cc::Layer* overscrolling_layer,
bool y_overscroll_started =
!IsApproxZero(overscroll_delta.y()) && IsApproxZero(old_overscroll.y());
- if (x_overscroll_started)
- ReleaseAxis(AXIS_X, current_time);
- if (y_overscroll_started)
- ReleaseAxis(AXIS_Y, current_time);
-
velocity = ZeroSmallComponents(velocity);
if (!velocity.IsZero())
Absorb(current_time, velocity, x_overscroll_started, y_overscroll_started);
else
- Pull(current_time, overscroll_delta);
+ Pull(current_time, overscroll_delta, displacement);
UpdateLayerAttachment(overscrolling_layer);
return NeedsAnimate();
@@ -177,14 +152,13 @@ bool OverscrollGlow::Animate(base::TimeTicks current_time) {
return false;
}
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
if (edge_effects_[i]->Update(current_time)) {
+ Edge edge = static_cast<Edge>(i);
edge_effects_[i]->ApplyToLayers(
- display_params_.size,
- static_cast<EdgeEffect::Edge>(i),
- kEdgeHeightAtMdpi * display_params_.device_scale_factor,
- kGlowHeightAtMdpi * display_params_.device_scale_factor,
- display_params_.edge_offsets[i]);
+ ComputeSize(edge, display_params_.size),
+ ComputeTransform(
+ edge, display_params_.size, display_params_.edge_offsets[i]));
}
}
@@ -203,7 +177,7 @@ void OverscrollGlow::UpdateDisplayParameters(const DisplayParameters& params) {
bool OverscrollGlow::NeedsAnimate() const {
if (!enabled_ || !initialized_)
return false;
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
if (!edge_effects_[i]->IsFinished())
return true;
}
@@ -212,7 +186,7 @@ bool OverscrollGlow::NeedsAnimate() const {
void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) {
DCHECK(parent);
- if (!root_layer_)
+ if (!root_layer_.get())
return;
if (!NeedsAnimate()) {
@@ -222,10 +196,13 @@ void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) {
if (root_layer_->parent() != parent)
parent->AddChild(root_layer_);
+
+ for (size_t i = 0; i < EDGE_COUNT; ++i)
+ edge_effects_[i]->SetParent(root_layer_.get());
}
void OverscrollGlow::Detach() {
- if (root_layer_)
+ if (root_layer_.get())
root_layer_->RemoveFromParent();
}
@@ -234,21 +211,11 @@ bool OverscrollGlow::InitializeIfNecessary() {
if (initialized_)
return true;
- const SkBitmap& edge = g_overscroll_resources.Get().edge_bitmap();
- const SkBitmap& glow = g_overscroll_resources.Get().glow_bitmap();
- if (edge.isNull() || glow.isNull()) {
- Disable();
- return false;
- }
-
- DCHECK(!root_layer_);
+ DCHECK(!root_layer_.get());
root_layer_ = cc::Layer::Create();
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
- scoped_refptr<cc::Layer> edge_layer = CreateImageLayer(edge);
- scoped_refptr<cc::Layer> glow_layer = CreateImageLayer(glow);
- root_layer_->AddChild(edge_layer);
- root_layer_->AddChild(glow_layer);
- edge_effects_[i] = make_scoped_ptr(new EdgeEffect(edge_layer, glow_layer));
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
+ edge_effects_[i] = edge_effect_provider_.Run();
+ DCHECK(edge_effects_[i]);
}
initialized_ = true;
@@ -256,49 +223,59 @@ bool OverscrollGlow::InitializeIfNecessary() {
}
void OverscrollGlow::Pull(base::TimeTicks current_time,
- gfx::Vector2dF overscroll_delta) {
+ const gfx::Vector2dF& overscroll_delta,
+ const gfx::Vector2dF& overscroll_location) {
DCHECK(enabled_ && initialized_);
- overscroll_delta = ZeroSmallComponents(overscroll_delta);
- if (overscroll_delta.IsZero())
- return;
+ DCHECK(!overscroll_delta.IsZero());
+ const float inv_width = 1.f / display_params_.size.width();
+ const float inv_height = 1.f / display_params_.size.height();
gfx::Vector2dF overscroll_pull =
- gfx::ScaleVector2d(overscroll_delta,
- 1.f / display_params_.size.width(),
- 1.f / display_params_.size.height());
- float edge_overscroll_pull[EdgeEffect::EDGE_COUNT] = {
+ gfx::ScaleVector2d(overscroll_delta, inv_width, inv_height);
+ const float edge_pull[EDGE_COUNT] = {
min(overscroll_pull.y(), 0.f), // Top
min(overscroll_pull.x(), 0.f), // Left
max(overscroll_pull.y(), 0.f), // Bottom
max(overscroll_pull.x(), 0.f) // Right
};
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
- if (!edge_overscroll_pull[i])
+ gfx::Vector2dF displacement =
+ gfx::ScaleVector2d(overscroll_location, inv_width, inv_height);
+ displacement.set_x(max(0.f, min(1.f, displacement.x())));
+ displacement.set_y(max(0.f, min(1.f, displacement.y())));
+ const float edge_displacement[EDGE_COUNT] = {
+ 1.f - displacement.x(), // Top
+ displacement.y(), // Left
+ displacement.x(), // Bottom
+ 1.f - displacement.y() // Right
+ };
+
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
+ if (!edge_pull[i])
continue;
- edge_effects_[i]->Pull(current_time, std::abs(edge_overscroll_pull[i]));
+ edge_effects_[i]->Pull(
+ current_time, std::abs(edge_pull[i]), edge_displacement[i]);
GetOppositeEdge(i)->Release(current_time);
}
}
void OverscrollGlow::Absorb(base::TimeTicks current_time,
- gfx::Vector2dF velocity,
+ const gfx::Vector2dF& velocity,
bool x_overscroll_started,
bool y_overscroll_started) {
DCHECK(enabled_ && initialized_);
- if (velocity.IsZero())
- return;
+ DCHECK(!velocity.IsZero());
// Only trigger on initial overscroll at a non-zero velocity
- const float overscroll_velocities[EdgeEffect::EDGE_COUNT] = {
+ const float overscroll_velocities[EDGE_COUNT] = {
y_overscroll_started ? min(velocity.y(), 0.f) : 0, // Top
x_overscroll_started ? min(velocity.x(), 0.f) : 0, // Left
y_overscroll_started ? max(velocity.y(), 0.f) : 0, // Bottom
x_overscroll_started ? max(velocity.x(), 0.f) : 0 // Right
};
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) {
+ for (size_t i = 0; i < EDGE_COUNT; ++i) {
if (!overscroll_velocities[i])
continue;
@@ -309,31 +286,16 @@ void OverscrollGlow::Absorb(base::TimeTicks current_time,
void OverscrollGlow::Release(base::TimeTicks current_time) {
DCHECK(initialized_);
- for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i)
+ for (size_t i = 0; i < EDGE_COUNT; ++i)
edge_effects_[i]->Release(current_time);
}
-void OverscrollGlow::ReleaseAxis(Axis axis, base::TimeTicks current_time) {
- DCHECK(initialized_);
- switch (axis) {
- case AXIS_X:
- edge_effects_[EdgeEffect::EDGE_LEFT]->Release(current_time);
- edge_effects_[EdgeEffect::EDGE_RIGHT]->Release(current_time);
- break;
- case AXIS_Y:
- edge_effects_[EdgeEffect::EDGE_TOP]->Release(current_time);
- edge_effects_[EdgeEffect::EDGE_BOTTOM]->Release(current_time);
- break;
- };
-}
-
-EdgeEffect* OverscrollGlow::GetOppositeEdge(int edge_index) {
+EdgeEffectBase* OverscrollGlow::GetOppositeEdge(int edge_index) {
DCHECK(initialized_);
- return edge_effects_[(edge_index + 2) % EdgeEffect::EDGE_COUNT].get();
+ return edge_effects_[(edge_index + 2) % EDGE_COUNT].get();
}
-OverscrollGlow::DisplayParameters::DisplayParameters()
- : device_scale_factor(1) {
+OverscrollGlow::DisplayParameters::DisplayParameters() {
edge_offsets[0] = edge_offsets[1] = edge_offsets[2] = edge_offsets[3] = 0.f;
}
diff --git a/chromium/content/browser/android/overscroll_glow.h b/chromium/content/browser/android/overscroll_glow.h
index 0a555d41b7a..878d39aec12 100644
--- a/chromium/content/browser/android/overscroll_glow.h
+++ b/chromium/content/browser/android/overscroll_glow.h
@@ -5,32 +5,36 @@
#ifndef CONTENT_BROWSER_ANDROID_OVERSCROLL_GLOW_H_
#define CONTENT_BROWSER_ANDROID_OVERSCROLL_GLOW_H_
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
-#include "content/browser/android/edge_effect.h"
#include "ui/gfx/size_f.h"
#include "ui/gfx/vector2d_f.h"
-class SkBitmap;
-
namespace cc {
class Layer;
}
namespace content {
+class EdgeEffectBase;
+
/* |OverscrollGlow| mirrors its Android counterpart, OverscrollGlow.java.
* Conscious tradeoffs were made to align this as closely as possible with the
* original Android Java version.
*/
class OverscrollGlow {
public:
- // Create a new effect. If |enabled| is false, the effect will remain
- // deactivated until explicitly enabled.
- // Note: No resources will be allocated until the effect is both
- // enabled and an overscroll event has occurred.
- static scoped_ptr<OverscrollGlow> Create(bool enabled);
+ enum Edge { EDGE_TOP = 0, EDGE_LEFT, EDGE_BOTTOM, EDGE_RIGHT, EDGE_COUNT };
+
+ // Allows lazy creation of the edge effects.
+ typedef base::Callback<scoped_ptr<EdgeEffectBase>(void)> EdgeEffectProvider;
+
+ // |edge_effect_provider| must be valid for the duration of the effect's
+ // lifetime. The effect is enabled by default, but will remain dormant until
+ // the first overscroll event.
+ explicit OverscrollGlow(const EdgeEffectProvider& edge_effect_provider);
~OverscrollGlow();
@@ -50,7 +54,8 @@ class OverscrollGlow {
base::TimeTicks current_time,
gfx::Vector2dF accumulated_overscroll,
gfx::Vector2dF overscroll_delta,
- gfx::Vector2dF velocity);
+ gfx::Vector2dF velocity,
+ gfx::Vector2dF overscroll_location);
// Returns true if the effect still needs animation ticks.
// Note: The effect will detach itself when no further animation is required.
@@ -61,33 +66,31 @@ class OverscrollGlow {
struct DisplayParameters {
DisplayParameters();
gfx::SizeF size;
- float edge_offsets[EdgeEffect::EDGE_COUNT];
- float device_scale_factor;
+ float edge_offsets[EDGE_COUNT];
};
void UpdateDisplayParameters(const DisplayParameters& params);
-
private:
enum Axis { AXIS_X, AXIS_Y };
- OverscrollGlow(bool enabled);
-
// Returns whether the effect is initialized.
bool InitializeIfNecessary();
bool NeedsAnimate() const;
void UpdateLayerAttachment(cc::Layer* parent);
void Detach();
- void Pull(base::TimeTicks current_time, gfx::Vector2dF overscroll_delta);
+ void Pull(base::TimeTicks current_time,
+ const gfx::Vector2dF& overscroll_delta,
+ const gfx::Vector2dF& overscroll_location);
void Absorb(base::TimeTicks current_time,
- gfx::Vector2dF velocity,
+ const gfx::Vector2dF& velocity,
bool x_overscroll_started,
bool y_overscroll_started);
void Release(base::TimeTicks current_time);
- void ReleaseAxis(Axis axis, base::TimeTicks current_time);
- EdgeEffect* GetOppositeEdge(int edge_index);
+ EdgeEffectBase* GetOppositeEdge(int edge_index);
- scoped_ptr<EdgeEffect> edge_effects_[EdgeEffect::EDGE_COUNT];
+ EdgeEffectProvider edge_effect_provider_;
+ scoped_ptr<EdgeEffectBase> edge_effects_[EDGE_COUNT];
DisplayParameters display_params_;
bool enabled_;
diff --git a/chromium/content/browser/android/popup_item_type_list.h b/chromium/content/browser/android/popup_item_type_list.h
deleted file mode 100644
index 3f50490f610..00000000000
--- a/chromium/content/browser/android/popup_item_type_list.h
+++ /dev/null
@@ -1,23 +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 file intentionally does not have header guards because this file
-// is meant to be included inside a macro to generate enum values.
-
-// This file contains a list of sync PopupItemTypes which describe the type
-// and enabled state of a select popup item. List is used by Android when
-// displaying a new select popup menu.
-
-#ifndef DEFINE_POPUP_ITEM_TYPE
-#error "Please define DEFINE_POPUP_ITEM_TYPE before including this file."
-#endif
-
-// Popup item is of type group
-DEFINE_POPUP_ITEM_TYPE(GROUP, 0)
-
-// Popup item is disabled
-DEFINE_POPUP_ITEM_TYPE(DISABLED, 1)
-
-// Popup item is enabled
-DEFINE_POPUP_ITEM_TYPE(ENABLED, 2)
diff --git a/chromium/content/browser/android/popup_touch_handle_drawable.cc b/chromium/content/browser/android/popup_touch_handle_drawable.cc
new file mode 100644
index 00000000000..8a7cf845f70
--- /dev/null
+++ b/chromium/content/browser/android/popup_touch_handle_drawable.cc
@@ -0,0 +1,87 @@
+// 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/android/popup_touch_handle_drawable.h"
+
+#include "jni/PopupTouchHandleDrawable_jni.h"
+
+namespace content {
+
+PopupTouchHandleDrawable::PopupTouchHandleDrawable(
+ base::android::ScopedJavaLocalRef<jobject> drawable,
+ float dpi_scale)
+ : dpi_scale_(dpi_scale), drawable_(drawable) {
+ DCHECK(drawable.obj());
+}
+
+PopupTouchHandleDrawable::~PopupTouchHandleDrawable() {
+ // Explicitly disabling ensures that any external references to the Java
+ // object are cleared, allowing it to be GC'ed in a timely fashion.
+ SetEnabled(false);
+}
+
+void PopupTouchHandleDrawable::SetEnabled(bool enabled) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ if (enabled)
+ Java_PopupTouchHandleDrawable_show(env, drawable_.obj());
+ else
+ Java_PopupTouchHandleDrawable_hide(env, drawable_.obj());
+}
+
+void PopupTouchHandleDrawable::SetOrientation(
+ TouchHandleOrientation orientation) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ jobject obj = drawable_.obj();
+ switch (orientation) {
+ case TOUCH_HANDLE_LEFT:
+ Java_PopupTouchHandleDrawable_setLeftOrientation(env, obj);
+ break;
+
+ case TOUCH_HANDLE_RIGHT:
+ Java_PopupTouchHandleDrawable_setRightOrientation(env, obj);
+ break;
+
+ case TOUCH_HANDLE_CENTER:
+ Java_PopupTouchHandleDrawable_setCenterOrientation(env, obj);
+ break;
+
+ case TOUCH_HANDLE_ORIENTATION_UNDEFINED:
+ NOTREACHED() << "Invalid touch handle orientation.";
+ };
+}
+
+void PopupTouchHandleDrawable::SetAlpha(float alpha) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_PopupTouchHandleDrawable_setOpacity(env, drawable_.obj(), alpha);
+}
+
+void PopupTouchHandleDrawable::SetFocus(const gfx::PointF& position) {
+ const gfx::PointF position_pix = gfx::ScalePoint(position, dpi_scale_);
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_PopupTouchHandleDrawable_setFocus(
+ env, drawable_.obj(), position_pix.x(), position_pix.y());
+}
+
+void PopupTouchHandleDrawable::SetVisible(bool visible) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_PopupTouchHandleDrawable_setVisible(env, drawable_.obj(), visible);
+}
+
+bool PopupTouchHandleDrawable::IntersectsWith(const gfx::RectF& rect) const {
+ const gfx::RectF rect_pix = gfx::ScaleRect(rect, dpi_scale_);
+ JNIEnv* env = base::android::AttachCurrentThread();
+ return Java_PopupTouchHandleDrawable_intersectsWith(env,
+ drawable_.obj(),
+ rect_pix.x(),
+ rect_pix.y(),
+ rect_pix.width(),
+ rect_pix.height());
+}
+
+// static
+bool PopupTouchHandleDrawable::RegisterPopupTouchHandleDrawable(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/popup_touch_handle_drawable.h b/chromium/content/browser/android/popup_touch_handle_drawable.h
new file mode 100644
index 00000000000..0e1a8ea4d1c
--- /dev/null
+++ b/chromium/content/browser/android/popup_touch_handle_drawable.h
@@ -0,0 +1,40 @@
+// 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_ANDROID_POPUP_TOUCH_HANDLE_DRAWABLE_H_
+#define CONTENT_BROWSER_ANDROID_POPUP_TOUCH_HANDLE_DRAWABLE_H_
+
+#include "content/browser/renderer_host/input/touch_handle.h"
+
+#include "base/android/jni_android.h"
+
+namespace content {
+
+// Touch handle drawable backed by an Android PopupWindow.
+class PopupTouchHandleDrawable : public TouchHandleDrawable {
+ public:
+ PopupTouchHandleDrawable(base::android::ScopedJavaLocalRef<jobject> drawable,
+ float dpi_scale);
+ virtual ~PopupTouchHandleDrawable();
+
+ // TouchHandleDrawable implementation.
+ virtual void SetEnabled(bool enabled) override;
+ virtual void SetOrientation(TouchHandleOrientation orientation) override;
+ virtual void SetAlpha(float alpha) override;
+ virtual void SetFocus(const gfx::PointF& position) override;
+ virtual void SetVisible(bool visible) override;
+ virtual bool IntersectsWith(const gfx::RectF& rect) const override;
+
+ static bool RegisterPopupTouchHandleDrawable(JNIEnv* env);
+
+ private:
+ const float dpi_scale_;
+ base::android::ScopedJavaGlobalRef<jobject> drawable_;
+
+ DISALLOW_COPY_AND_ASSIGN(PopupTouchHandleDrawable);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_POPUP_TOUCH_HANDLE_DRAWABLE_H_
diff --git a/chromium/content/browser/android/surface_texture_peer_browser_impl.cc b/chromium/content/browser/android/surface_texture_peer_browser_impl.cc
deleted file mode 100644
index 4f61887f880..00000000000
--- a/chromium/content/browser/android/surface_texture_peer_browser_impl.cc
+++ /dev/null
@@ -1,91 +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/android/surface_texture_peer_browser_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/media_web_contents_observer.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
-#include "media/base/android/media_player_android.h"
-#include "ui/gl/android/scoped_java_surface.h"
-
-namespace content {
-
-namespace {
-
-// Pass a java surface object to the MediaPlayerAndroid object
-// identified by render process handle, render frame ID and player ID.
-static void SetSurfacePeer(
- scoped_refptr<gfx::SurfaceTexture> surface_texture,
- base::ProcessHandle render_process_handle,
- int render_frame_id,
- int player_id) {
- int render_process_id = 0;
- RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
- while (!it.IsAtEnd()) {
- if (it.GetCurrentValue()->GetHandle() == render_process_handle) {
- render_process_id = it.GetCurrentValue()->GetID();
- break;
- }
- it.Advance();
- }
- if (!render_process_id) {
- DVLOG(1) << "Cannot find render process for render_process_handle "
- << render_process_handle;
- return;
- }
-
- RenderFrameHostImpl* frame =
- RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
- if (!frame) {
- DVLOG(1) << "Cannot find frame for render_frame_id " << render_frame_id;
- return;
- }
-
- RenderViewHostImpl* view =
- static_cast<RenderViewHostImpl*>(frame->GetRenderViewHost());
- BrowserMediaPlayerManager* player_manager =
- view->media_web_contents_observer()->GetMediaPlayerManager(frame);
- if (!player_manager) {
- DVLOG(1) << "Cannot find the media player manager for frame " << frame;
- return;
- }
-
- media::MediaPlayerAndroid* player = player_manager->GetPlayer(player_id);
- if (!player) {
- DVLOG(1) << "Cannot find media player for player_id " << player_id;
- return;
- }
-
- if (player != player_manager->GetFullscreenPlayer()) {
- gfx::ScopedJavaSurface scoped_surface(surface_texture);
- player->SetVideoSurface(scoped_surface.Pass());
- }
-}
-
-} // anonymous namespace
-
-SurfaceTexturePeerBrowserImpl::SurfaceTexturePeerBrowserImpl() {
-}
-
-SurfaceTexturePeerBrowserImpl::~SurfaceTexturePeerBrowserImpl() {
-}
-
-void SurfaceTexturePeerBrowserImpl::EstablishSurfaceTexturePeer(
- base::ProcessHandle render_process_handle,
- scoped_refptr<gfx::SurfaceTexture> surface_texture,
- int render_frame_id,
- int player_id) {
- if (!surface_texture.get())
- return;
-
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
- &SetSurfacePeer, surface_texture, render_process_handle,
- render_frame_id, player_id));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/android/surface_texture_peer_browser_impl.h b/chromium/content/browser/android/surface_texture_peer_browser_impl.h
deleted file mode 100644
index ea3fd046553..00000000000
--- a/chromium/content/browser/android/surface_texture_peer_browser_impl.h
+++ /dev/null
@@ -1,37 +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_ANDROID_SURFACE_TEXTURE_PEER_BROWSER_IMPL_H_
-#define CONTENT_BROWSER_ANDROID_SURFACE_TEXTURE_PEER_BROWSER_IMPL_H_
-
-#include "base/compiler_specific.h"
-#include "content/common/android/surface_texture_peer.h"
-
-namespace content {
-
-// The SurfaceTexturePeer implementation for browser process.
-class SurfaceTexturePeerBrowserImpl : public SurfaceTexturePeer {
- public:
- // Construct a SurfaceTexturePeerBrowserImpl object. If
- // |player_in_render_process| is true, calling EstablishSurfaceTexturePeer()
- // will send the java surface texture object to the render process through
- // ChildProcessService. Otherwise, it will pass the surface texture
- // to the MediaPlayerBridge object in the browser process.
- SurfaceTexturePeerBrowserImpl();
- virtual ~SurfaceTexturePeerBrowserImpl();
-
- // SurfaceTexturePeer implementation.
- virtual void EstablishSurfaceTexturePeer(
- base::ProcessHandle render_process_handle,
- scoped_refptr<gfx::SurfaceTexture> surface_texture,
- int render_frame_id,
- int player_id) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SurfaceTexturePeerBrowserImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_ANDROID_SURFACE_TEXTURE_PEER_BROWSER_IMPL_H_
diff --git a/chromium/content/browser/android/system_ui_resource_manager_impl.cc b/chromium/content/browser/android/system_ui_resource_manager_impl.cc
new file mode 100644
index 00000000000..57ef6f2055d
--- /dev/null
+++ b/chromium/content/browser/android/system_ui_resource_manager_impl.cc
@@ -0,0 +1,178 @@
+// 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/android/system_ui_resource_manager_impl.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/debug/trace_event.h"
+#include "base/location.h"
+#include "base/observer_list.h"
+#include "base/threading/worker_pool.h"
+#include "cc/resources/ui_resource_bitmap.h"
+#include "content/public/browser/android/ui_resource_client_android.h"
+#include "content/public/browser/android/ui_resource_provider.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/screen.h"
+
+namespace content {
+namespace {
+
+SkBitmap CreateOverscrollGlowLBitmap(const gfx::Size& screen_size) {
+ const float kSin = 0.5f; // sin(PI / 6)
+ const float kCos = 0.866f; // cos(PI / 6);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setAlpha(0xBB);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ const float arc_width =
+ std::min(screen_size.width(), screen_size.height()) * 0.5f / kSin;
+ const float y = kCos * arc_width;
+ const float height = arc_width - y;
+ gfx::Size bounds(arc_width, height);
+ SkRect arc_rect = SkRect::MakeXYWH(
+ -arc_width / 2.f, -arc_width - y, arc_width * 2.f, arc_width * 2.f);
+ SkBitmap glow_bitmap;
+ glow_bitmap.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
+ glow_bitmap.eraseColor(SK_ColorTRANSPARENT);
+
+ SkCanvas canvas(glow_bitmap);
+ canvas.clipRect(SkRect::MakeXYWH(0, 0, bounds.width(), bounds.height()));
+ canvas.drawArc(arc_rect, 45, 90, true, paint);
+ return glow_bitmap;
+}
+
+void LoadBitmap(ui::SystemUIResourceManager::ResourceType type,
+ SkBitmap* bitmap_holder,
+ const gfx::Size& screen_size) {
+ TRACE_EVENT1(
+ "browser", "SystemUIResourceManagerImpl::LoadBitmap", "type", type);
+ SkBitmap bitmap;
+ switch (type) {
+ case ui::SystemUIResourceManager::OVERSCROLL_EDGE:
+ bitmap = gfx::CreateSkBitmapFromAndroidResource(
+ "android:drawable/overscroll_edge", gfx::Size(128, 12));
+ break;
+ case ui::SystemUIResourceManager::OVERSCROLL_GLOW:
+ bitmap = gfx::CreateSkBitmapFromAndroidResource(
+ "android:drawable/overscroll_glow", gfx::Size(128, 64));
+ break;
+ case ui::SystemUIResourceManager::OVERSCROLL_GLOW_L:
+ bitmap = CreateOverscrollGlowLBitmap(screen_size);
+ break;
+ }
+ bitmap.setImmutable();
+ *bitmap_holder = bitmap;
+}
+
+} // namespace
+
+class SystemUIResourceManagerImpl::Entry
+ : public content::UIResourceClientAndroid {
+ public:
+ explicit Entry(UIResourceProvider* provider) : id_(0), provider_(provider) {
+ DCHECK(provider);
+ }
+
+ virtual ~Entry() {
+ if (id_)
+ provider_->DeleteUIResource(id_);
+ id_ = 0;
+ }
+
+ void SetBitmap(const SkBitmap& bitmap) {
+ DCHECK(!bitmap.empty());
+ DCHECK(bitmap_.empty());
+ DCHECK(!id_);
+ bitmap_ = bitmap;
+ }
+
+ cc::UIResourceId GetUIResourceId() {
+ if (bitmap_.empty())
+ return 0;
+ if (!id_)
+ id_ = provider_->CreateUIResource(this);
+ return id_;
+ }
+
+ // content::UIResourceClient implementation.
+ virtual cc::UIResourceBitmap GetBitmap(cc::UIResourceId uid,
+ bool resource_lost) override {
+ DCHECK(!bitmap_.empty());
+ return cc::UIResourceBitmap(bitmap_);
+ }
+
+ // content::UIResourceClientAndroid implementation.
+ virtual void UIResourceIsInvalid() override { id_ = 0; }
+
+ const SkBitmap& bitmap() const { return bitmap_; }
+
+ private:
+ SkBitmap bitmap_;
+ cc::UIResourceId id_;
+ UIResourceProvider* provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(Entry);
+};
+
+SystemUIResourceManagerImpl::SystemUIResourceManagerImpl(
+ UIResourceProvider* ui_resource_provider)
+ : ui_resource_provider_(ui_resource_provider), weak_factory_(this) {
+}
+
+SystemUIResourceManagerImpl::~SystemUIResourceManagerImpl() {
+}
+
+void SystemUIResourceManagerImpl::PreloadResource(ResourceType type) {
+ GetEntry(type);
+}
+
+cc::UIResourceId SystemUIResourceManagerImpl::GetUIResourceId(
+ ResourceType type) {
+ return GetEntry(type)->GetUIResourceId();
+}
+
+SystemUIResourceManagerImpl::Entry* SystemUIResourceManagerImpl::GetEntry(
+ ResourceType type) {
+ DCHECK_GE(type, RESOURCE_TYPE_FIRST);
+ DCHECK_LE(type, RESOURCE_TYPE_LAST);
+ if (!resource_map_[type]) {
+ resource_map_[type].reset(new Entry(ui_resource_provider_));
+ // Lazily build the resource.
+ BuildResource(type);
+ }
+ return resource_map_[type].get();
+}
+
+void SystemUIResourceManagerImpl::BuildResource(ResourceType type) {
+ DCHECK(GetEntry(type)->bitmap().empty());
+
+ // Instead of blocking the main thread, we post a task to load the bitmap.
+ SkBitmap* bitmap = new SkBitmap();
+ gfx::Size screen_size =
+ gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().GetSizeInPixel();
+ base::Closure load_bitmap =
+ base::Bind(&LoadBitmap, type, bitmap, screen_size);
+ base::Closure finished_load =
+ base::Bind(&SystemUIResourceManagerImpl::OnFinishedLoadBitmap,
+ weak_factory_.GetWeakPtr(),
+ type,
+ base::Owned(bitmap));
+ base::WorkerPool::PostTaskAndReply(
+ FROM_HERE, load_bitmap, finished_load, true);
+}
+
+void SystemUIResourceManagerImpl::OnFinishedLoadBitmap(
+ ResourceType type,
+ SkBitmap* bitmap_holder) {
+ DCHECK(bitmap_holder);
+ GetEntry(type)->SetBitmap(*bitmap_holder);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/system_ui_resource_manager_impl.h b/chromium/content/browser/android/system_ui_resource_manager_impl.h
new file mode 100644
index 00000000000..54b2bd39d95
--- /dev/null
+++ b/chromium/content/browser/android/system_ui_resource_manager_impl.h
@@ -0,0 +1,54 @@
+// 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_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_IMPL_H_
+#define CONTENT_BROWSER_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "ui/base/android/system_ui_resource_manager.h"
+
+class SkBitmap;
+
+namespace cc {
+class UIResourceBitmap;
+}
+
+namespace content {
+
+class UIResourceProvider;
+
+class CONTENT_EXPORT SystemUIResourceManagerImpl
+ : public ui::SystemUIResourceManager {
+ public:
+ explicit SystemUIResourceManagerImpl(
+ UIResourceProvider* ui_resource_provider);
+ virtual ~SystemUIResourceManagerImpl();
+
+ virtual void PreloadResource(ResourceType type) override;
+ virtual cc::UIResourceId GetUIResourceId(ResourceType type) override;
+
+ private:
+ friend class TestSystemUIResourceManagerImpl;
+ class Entry;
+
+ // Start loading the resource bitmap. virtual for testing.
+ virtual void BuildResource(ResourceType type);
+
+ Entry* GetEntry(ResourceType type);
+ void OnFinishedLoadBitmap(ResourceType, SkBitmap* bitmap_holder);
+
+ scoped_ptr<Entry> resource_map_[RESOURCE_TYPE_LAST + 1];
+ UIResourceProvider* ui_resource_provider_;
+
+ base::WeakPtrFactory<SystemUIResourceManagerImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemUIResourceManagerImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_IMPL_H_
diff --git a/chromium/content/browser/android/system_ui_resource_manager_impl_unittest.cc b/chromium/content/browser/android/system_ui_resource_manager_impl_unittest.cc
new file mode 100644
index 00000000000..5ab07fc3aa1
--- /dev/null
+++ b/chromium/content/browser/android/system_ui_resource_manager_impl_unittest.cc
@@ -0,0 +1,169 @@
+// 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 "cc/resources/ui_resource_bitmap.h"
+#include "content/browser/android/system_ui_resource_manager_impl.h"
+#include "content/public/browser/android/ui_resource_client_android.h"
+#include "content/public/browser/android/ui_resource_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace content {
+
+class TestSystemUIResourceManagerImpl
+ : public content::SystemUIResourceManagerImpl {
+ public:
+ TestSystemUIResourceManagerImpl(content::UIResourceProvider* provider)
+ : SystemUIResourceManagerImpl(provider) {}
+
+ virtual ~TestSystemUIResourceManagerImpl() {}
+
+ virtual void BuildResource(
+ ui::SystemUIResourceManager::ResourceType type) override {}
+
+ void SetResourceAsLoaded(ui::SystemUIResourceManager::ResourceType type) {
+ SkBitmap small_bitmap;
+ SkCanvas canvas(small_bitmap);
+ small_bitmap.allocPixels(
+ SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kOpaque_SkAlphaType));
+ canvas.drawColor(SK_ColorWHITE);
+ small_bitmap.setImmutable();
+ OnFinishedLoadBitmap(type, &small_bitmap);
+ }
+};
+
+namespace {
+
+const ui::SystemUIResourceManager::ResourceType TEST_RESOURCE_TYPE =
+ ui::SystemUIResourceManager::OVERSCROLL_GLOW;
+
+class MockUIResourceProvider : public content::UIResourceProvider {
+ public:
+ MockUIResourceProvider()
+ : next_ui_resource_id_(1),
+ has_layer_tree_host_(true),
+ system_ui_resource_manager_(this) {}
+
+ virtual ~MockUIResourceProvider() {}
+
+ virtual cc::UIResourceId CreateUIResource(
+ content::UIResourceClientAndroid* client) override {
+ if (!has_layer_tree_host_)
+ return 0;
+ cc::UIResourceId id = next_ui_resource_id_++;
+ client->GetBitmap(id, false);
+ ui_resource_client_map_[id] = client;
+ return id;
+ }
+
+ virtual void DeleteUIResource(cc::UIResourceId id) override {
+ CHECK(has_layer_tree_host_);
+ ui_resource_client_map_.erase(id);
+ }
+
+ virtual bool SupportsETC1NonPowerOfTwo() const override { return true; }
+
+ void LayerTreeHostCleared() {
+ has_layer_tree_host_ = false;
+ UIResourceClientMap client_map = ui_resource_client_map_;
+ ui_resource_client_map_.clear();
+ for (UIResourceClientMap::iterator iter = client_map.begin();
+ iter != client_map.end();
+ iter++) {
+ iter->second->UIResourceIsInvalid();
+ }
+ }
+
+ void LayerTreeHostReturned() { has_layer_tree_host_ = true; }
+
+ TestSystemUIResourceManagerImpl& GetSystemUIResourceManager() {
+ return system_ui_resource_manager_;
+ }
+
+ cc::UIResourceId next_ui_resource_id() const { return next_ui_resource_id_; }
+
+ private:
+ typedef base::hash_map<cc::UIResourceId, content::UIResourceClientAndroid*>
+ UIResourceClientMap;
+
+ cc::UIResourceId next_ui_resource_id_;
+ UIResourceClientMap ui_resource_client_map_;
+ bool has_layer_tree_host_;
+
+ // The UIResourceProvider owns the SystemUIResourceManager.
+ TestSystemUIResourceManagerImpl system_ui_resource_manager_;
+};
+
+} // namespace
+
+class SystemUIResourceManagerImplTest : public testing::Test {
+ public:
+ void PreloadResource(ui::SystemUIResourceManager::ResourceType type) {
+ ui_resource_provider_.GetSystemUIResourceManager().PreloadResource(type);
+ }
+
+ cc::UIResourceId GetUIResourceId(
+ ui::SystemUIResourceManager::ResourceType type) {
+ return ui_resource_provider_.GetSystemUIResourceManager().GetUIResourceId(
+ type);
+ }
+
+ void LayerTreeHostCleared() { ui_resource_provider_.LayerTreeHostCleared(); }
+
+ void LayerTreeHostReturned() {
+ ui_resource_provider_.LayerTreeHostReturned();
+ }
+
+ void SetResourceAsLoaded(ui::SystemUIResourceManager::ResourceType type) {
+ ui_resource_provider_.GetSystemUIResourceManager().SetResourceAsLoaded(
+ type);
+ }
+
+ cc::UIResourceId GetNextUIResourceId() const {
+ return ui_resource_provider_.next_ui_resource_id();
+ }
+
+ private:
+ MockUIResourceProvider ui_resource_provider_;
+};
+
+TEST_F(SystemUIResourceManagerImplTest, GetResourceAfterBitmapLoaded) {
+ SetResourceAsLoaded(TEST_RESOURCE_TYPE);
+ EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+}
+
+TEST_F(SystemUIResourceManagerImplTest, GetResourceBeforeLoadBitmap) {
+ EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+ SetResourceAsLoaded(TEST_RESOURCE_TYPE);
+ EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+}
+
+TEST_F(SystemUIResourceManagerImplTest, PreloadEnsureResource) {
+ // Preloading the resource should trigger bitmap loading, but the actual
+ // resource id will not be generated until it is explicitly requested.
+ cc::UIResourceId first_resource_id = GetNextUIResourceId();
+ PreloadResource(TEST_RESOURCE_TYPE);
+ SetResourceAsLoaded(TEST_RESOURCE_TYPE);
+ EXPECT_EQ(first_resource_id, GetNextUIResourceId());
+ EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+ EXPECT_NE(first_resource_id, GetNextUIResourceId());
+}
+
+TEST_F(SystemUIResourceManagerImplTest, ResetLayerTreeHost) {
+ EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+ LayerTreeHostCleared();
+ EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+ LayerTreeHostReturned();
+ EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+
+ SetResourceAsLoaded(TEST_RESOURCE_TYPE);
+ EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+ LayerTreeHostCleared();
+ EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+ LayerTreeHostReturned();
+ EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/android/tracing_controller_android.cc b/chromium/content/browser/android/tracing_controller_android.cc
index a9c5b408147..4c40bb74297 100644
--- a/chromium/content/browser/android/tracing_controller_android.cc
+++ b/chromium/content/browser/android/tracing_controller_android.cc
@@ -32,17 +32,19 @@ void TracingControllerAndroid::Destroy(JNIEnv* env, jobject obj) {
bool TracingControllerAndroid::StartTracing(JNIEnv* env,
jobject obj,
jstring jcategories,
- jboolean record_continuously) {
+ jstring jtraceoptions) {
std::string categories =
base::android::ConvertJavaStringToUTF8(env, jcategories);
+ base::debug::TraceOptions trace_options;
+ trace_options.SetFromString(
+ base::android::ConvertJavaStringToUTF8(env, jtraceoptions));
// This log is required by adb_profile_chrome.py.
LOG(WARNING) << "Logging performance trace to file";
return TracingController::GetInstance()->EnableRecording(
- categories,
- record_continuously ? TracingController::RECORD_CONTINUOUSLY
- : TracingController::DEFAULT_OPTIONS,
+ base::debug::CategoryFilter(categories),
+ trace_options,
TracingController::EnableRecordingDoneCallback());
}
@@ -52,11 +54,12 @@ void TracingControllerAndroid::StopTracing(JNIEnv* env,
base::FilePath file_path(
base::android::ConvertJavaStringToUTF8(env, jfilepath));
if (!TracingController::GetInstance()->DisableRecording(
- file_path,
- base::Bind(&TracingControllerAndroid::OnTracingStopped,
- weak_factory_.GetWeakPtr()))) {
+ TracingController::CreateFileSink(
+ file_path,
+ base::Bind(&TracingControllerAndroid::OnTracingStopped,
+ weak_factory_.GetWeakPtr())))) {
LOG(ERROR) << "EndTracingAsync failed, forcing an immediate stop";
- OnTracingStopped(file_path);
+ OnTracingStopped();
}
}
@@ -69,8 +72,7 @@ void TracingControllerAndroid::GenerateTracingFilePath(
base::android::ConvertJavaStringToUTF8(env, jfilename.obj()));
}
-void TracingControllerAndroid::OnTracingStopped(
- const base::FilePath& file_path) {
+void TracingControllerAndroid::OnTracingStopped() {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env);
if (obj.obj())
diff --git a/chromium/content/browser/android/tracing_controller_android.h b/chromium/content/browser/android/tracing_controller_android.h
index ab426d78997..58e6b94d36b 100644
--- a/chromium/content/browser/android/tracing_controller_android.h
+++ b/chromium/content/browser/android/tracing_controller_android.h
@@ -22,14 +22,14 @@ class TracingControllerAndroid {
bool StartTracing(JNIEnv* env,
jobject obj,
jstring categories,
- jboolean record_continuously);
+ jstring trace_options);
void StopTracing(JNIEnv* env, jobject obj, jstring jfilepath);
bool GetKnownCategoryGroupsAsync(JNIEnv* env, jobject obj);
static void GenerateTracingFilePath(base::FilePath* file_path);
private:
~TracingControllerAndroid();
- void OnTracingStopped(const base::FilePath& file_path);
+ void OnTracingStopped();
void OnKnownCategoriesReceived(
const std::set<std::string>& categories_received);
diff --git a/chromium/content/browser/android/ui_resource_provider_impl.cc b/chromium/content/browser/android/ui_resource_provider_impl.cc
index f97975cc81e..cd45d7cc634 100644
--- a/chromium/content/browser/android/ui_resource_provider_impl.cc
+++ b/chromium/content/browser/android/ui_resource_provider_impl.cc
@@ -10,7 +10,10 @@
namespace content {
-UIResourceProviderImpl::UIResourceProviderImpl() : host_(NULL) {
+UIResourceProviderImpl::UIResourceProviderImpl()
+ : system_ui_resource_manager_(this), host_(NULL),
+ supports_etc1_npot_(false) {
+
}
UIResourceProviderImpl::~UIResourceProviderImpl() {
@@ -57,4 +60,13 @@ void UIResourceProviderImpl::DeleteUIResource(cc::UIResourceId ui_resource_id) {
host_->DeleteUIResource(ui_resource_id);
}
+ui::SystemUIResourceManager&
+UIResourceProviderImpl::GetSystemUIResourceManager() {
+ return system_ui_resource_manager_;
+}
+
+bool UIResourceProviderImpl::SupportsETC1NonPowerOfTwo() const {
+ return supports_etc1_npot_;
+}
+
} // namespace content
diff --git a/chromium/content/browser/android/ui_resource_provider_impl.h b/chromium/content/browser/android/ui_resource_provider_impl.h
index 79c23014d2d..1c29a3ed117 100644
--- a/chromium/content/browser/android/ui_resource_provider_impl.h
+++ b/chromium/content/browser/android/ui_resource_provider_impl.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_ANDROID_UI_RESOURCE_PROVIDER_IMPL_H_
#include "base/containers/hash_tables.h"
+#include "content/browser/android/system_ui_resource_manager_impl.h"
#include "content/public/browser/android/ui_resource_provider.h"
namespace cc {
@@ -27,16 +28,24 @@ class UIResourceProviderImpl : public UIResourceProvider {
void UIResourcesAreInvalid();
virtual cc::UIResourceId CreateUIResource(
- UIResourceClientAndroid* client) OVERRIDE;
+ UIResourceClientAndroid* client) override;
- virtual void DeleteUIResource(cc::UIResourceId resource_id) OVERRIDE;
+ virtual void DeleteUIResource(cc::UIResourceId resource_id) override;
+
+ ui::SystemUIResourceManager& GetSystemUIResourceManager();
+
+ void SetSupportsETC1NonPowerOfTwo(bool supports_etc1_npot) {
+ supports_etc1_npot_ = supports_etc1_npot;
+ }
+ virtual bool SupportsETC1NonPowerOfTwo() const override;
private:
typedef base::hash_map<cc::UIResourceId, UIResourceClientAndroid*>
UIResourceClientMap;
UIResourceClientMap ui_resource_client_map_;
-
+ SystemUIResourceManagerImpl system_ui_resource_manager_;
cc::LayerTreeHost* host_;
+ bool supports_etc1_npot_;
DISALLOW_COPY_AND_ASSIGN(UIResourceProviderImpl);
};
diff --git a/chromium/content/browser/android/web_contents_observer_android.cc b/chromium/content/browser/android/web_contents_observer_android.cc
index 0aa9c0b3dee..acadf8d85a3 100644
--- a/chromium/content/browser/android/web_contents_observer_android.cc
+++ b/chromium/content/browser/android/web_contents_observer_android.cc
@@ -15,7 +15,7 @@
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
-#include "jni/WebContentsObserverAndroid_jni.h"
+#include "jni/WebContentsObserver_jni.h"
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
@@ -24,6 +24,9 @@ using base::android::ConvertUTF16ToJavaString;
namespace content {
+// TODO(dcheng): File a bug. This class incorrectly passes just a frame ID,
+// which is not sufficient to identify a frame (since frame IDs are scoped per
+// render process, and so may collide).
WebContentsObserverAndroid::WebContentsObserverAndroid(
JNIEnv* env,
jobject obj,
@@ -36,8 +39,8 @@ WebContentsObserverAndroid::~WebContentsObserverAndroid() {
}
jlong Init(JNIEnv* env, jobject obj, jobject java_web_contents) {
- content::WebContents* web_contents =
- content::WebContents::FromJavaWebContents(java_web_contents);
+ WebContents* web_contents =
+ WebContents::FromJavaWebContents(java_web_contents);
CHECK(web_contents);
WebContentsObserverAndroid* native_observer = new WebContentsObserverAndroid(
@@ -56,7 +59,7 @@ void WebContentsObserverAndroid::WebContentsDestroyed() {
delete this;
} else {
// The java side will destroy |this|
- Java_WebContentsObserverAndroid_detachFromWebContents(env, obj.obj());
+ Java_WebContentsObserver_detachFromWebContents(env, obj.obj());
}
}
@@ -68,7 +71,7 @@ void WebContentsObserverAndroid::RenderProcessGone(
return;
jboolean was_oom_protected =
termination_status == base::TERMINATION_STATUS_OOM_PROTECTED;
- Java_WebContentsObserverAndroid_renderProcessGone(
+ Java_WebContentsObserver_renderProcessGone(
env, obj.obj(), was_oom_protected);
}
@@ -80,7 +83,7 @@ void WebContentsObserverAndroid::DidStartLoading(
return;
ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
env, web_contents()->GetVisibleURL().spec()));
- Java_WebContentsObserverAndroid_didStartLoading(
+ Java_WebContentsObserver_didStartLoading(
env, obj.obj(), jstring_url.obj());
}
@@ -92,31 +95,32 @@ void WebContentsObserverAndroid::DidStopLoading(
return;
ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
env, web_contents()->GetLastCommittedURL().spec()));
- Java_WebContentsObserverAndroid_didStopLoading(
+ Java_WebContentsObserver_didStopLoading(
env, obj.obj(), jstring_url.obj());
}
void WebContentsObserverAndroid::DidFailProvisionalLoad(
- int64 frame_id,
- const base::string16& frame_unique_name,
- bool is_main_frame,
+ RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
- const base::string16& error_description,
- RenderViewHost* render_view_host) {
- DidFailLoadInternal(
- true, is_main_frame, error_code, error_description, validated_url);
+ const base::string16& error_description) {
+ DidFailLoadInternal(true,
+ !render_frame_host->GetParent(),
+ error_code,
+ error_description,
+ validated_url);
}
void WebContentsObserverAndroid::DidFailLoad(
- int64 frame_id,
+ RenderFrameHost* render_frame_host,
const GURL& validated_url,
- bool is_main_frame,
int error_code,
- const base::string16& error_description,
- RenderViewHost* render_view_host) {
- DidFailLoadInternal(
- false, is_main_frame, error_code, error_description, validated_url);
+ const base::string16& error_description) {
+ DidFailLoadInternal(false,
+ !render_frame_host->GetParent(),
+ error_code,
+ error_description,
+ validated_url);
}
void WebContentsObserverAndroid::DidNavigateMainFrame(
@@ -144,12 +148,14 @@ void WebContentsObserverAndroid::DidNavigateMainFrame(
// that would also be valid for a fragment navigation.
bool is_fragment_navigation = urls_same_ignoring_fragment &&
(details.type == NAVIGATION_TYPE_IN_PAGE || details.is_in_page);
- Java_WebContentsObserverAndroid_didNavigateMainFrame(
+ Java_WebContentsObserver_didNavigateMainFrame(
env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
- details.is_navigation_to_different_page(), is_fragment_navigation);
+ details.is_navigation_to_different_page(), is_fragment_navigation,
+ details.http_status_code);
}
void WebContentsObserverAndroid::DidNavigateAnyFrame(
+ RenderFrameHost* render_frame_host,
const LoadCommittedDetails& details,
const FrameNavigateParams& params) {
JNIEnv* env = AttachCurrentThread();
@@ -160,56 +166,62 @@ void WebContentsObserverAndroid::DidNavigateAnyFrame(
ConvertUTF8ToJavaString(env, params.url.spec()));
ScopedJavaLocalRef<jstring> jstring_base_url(
ConvertUTF8ToJavaString(env, params.base_url.spec()));
- jboolean jboolean_is_reload =
- PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_RELOAD);
+ jboolean jboolean_is_reload = ui::PageTransitionCoreTypeIs(
+ params.transition, ui::PAGE_TRANSITION_RELOAD);
- Java_WebContentsObserverAndroid_didNavigateAnyFrame(
+ Java_WebContentsObserver_didNavigateAnyFrame(
env, obj.obj(), jstring_url.obj(), jstring_base_url.obj(),
jboolean_is_reload);
}
void WebContentsObserverAndroid::DidStartProvisionalLoadForFrame(
- int64 frame_id,
- int64 parent_frame_id,
- bool is_main_frame,
- const GURL& validated_url,
- bool is_error_page,
- bool is_iframe_srcdoc,
- RenderViewHost* render_view_host) {
+ RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ bool is_error_page,
+ bool is_iframe_srcdoc) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
return;
ScopedJavaLocalRef<jstring> jstring_url(
ConvertUTF8ToJavaString(env, validated_url.spec()));
- Java_WebContentsObserverAndroid_didStartProvisionalLoadForFrame(
- env, obj.obj(), frame_id, parent_frame_id, is_main_frame,
- jstring_url.obj(), is_error_page, is_iframe_srcdoc);
+ // TODO(dcheng): Does Java really need the parent frame ID? It doesn't appear
+ // to be used at all, and it just adds complexity here.
+ Java_WebContentsObserver_didStartProvisionalLoadForFrame(
+ env,
+ obj.obj(),
+ render_frame_host->GetRoutingID(),
+ render_frame_host->GetParent()
+ ? render_frame_host->GetParent()->GetRoutingID()
+ : -1,
+ !render_frame_host->GetParent(),
+ jstring_url.obj(),
+ is_error_page,
+ is_iframe_srcdoc);
}
void WebContentsObserverAndroid::DidCommitProvisionalLoadForFrame(
- int64 frame_id,
- const base::string16& frame_unique_name,
- bool is_main_frame,
- const GURL& url,
- PageTransition transition_type,
- RenderViewHost* render_view_host) {
+ RenderFrameHost* render_frame_host,
+ const GURL& url,
+ ui::PageTransition transition_type) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
return;
ScopedJavaLocalRef<jstring> jstring_url(
ConvertUTF8ToJavaString(env, url.spec()));
- Java_WebContentsObserverAndroid_didCommitProvisionalLoadForFrame(
- env, obj.obj(), frame_id, is_main_frame, jstring_url.obj(),
+ Java_WebContentsObserver_didCommitProvisionalLoadForFrame(
+ env,
+ obj.obj(),
+ render_frame_host->GetRoutingID(),
+ !render_frame_host->GetParent(),
+ jstring_url.obj(),
transition_type);
}
void WebContentsObserverAndroid::DidFinishLoad(
- int64 frame_id,
- const GURL& validated_url,
- bool is_main_frame,
- RenderViewHost* render_view_host) {
+ RenderFrameHost* render_frame_host,
+ const GURL& validated_url) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
@@ -224,19 +236,22 @@ void WebContentsObserverAndroid::DidFinishLoad(
ScopedJavaLocalRef<jstring> jstring_url(
ConvertUTF8ToJavaString(env, url_string));
- Java_WebContentsObserverAndroid_didFinishLoad(
- env, obj.obj(), frame_id, jstring_url.obj(), is_main_frame);
+ Java_WebContentsObserver_didFinishLoad(
+ env,
+ obj.obj(),
+ render_frame_host->GetRoutingID(),
+ jstring_url.obj(),
+ !render_frame_host->GetParent());
}
void WebContentsObserverAndroid::DocumentLoadedInFrame(
- int64 frame_id,
- RenderViewHost* render_view_host) {
+ RenderFrameHost* render_frame_host) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
return;
- Java_WebContentsObserverAndroid_documentLoadedInFrame(
- env, obj.obj(), frame_id);
+ Java_WebContentsObserver_documentLoadedInFrame(
+ env, obj.obj(), render_frame_host->GetRoutingID());
}
void WebContentsObserverAndroid::NavigationEntryCommitted(
@@ -245,7 +260,7 @@ void WebContentsObserverAndroid::NavigationEntryCommitted(
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
return;
- Java_WebContentsObserverAndroid_navigationEntryCommitted(env, obj.obj());
+ Java_WebContentsObserver_navigationEntryCommitted(env, obj.obj());
}
void WebContentsObserverAndroid::DidAttachInterstitialPage() {
@@ -253,7 +268,7 @@ void WebContentsObserverAndroid::DidAttachInterstitialPage() {
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
return;
- Java_WebContentsObserverAndroid_didAttachInterstitialPage(env, obj.obj());
+ Java_WebContentsObserver_didAttachInterstitialPage(env, obj.obj());
}
void WebContentsObserverAndroid::DidDetachInterstitialPage() {
@@ -261,7 +276,7 @@ void WebContentsObserverAndroid::DidDetachInterstitialPage() {
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
return;
- Java_WebContentsObserverAndroid_didDetachInterstitialPage(env, obj.obj());
+ Java_WebContentsObserver_didDetachInterstitialPage(env, obj.obj());
}
void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) {
@@ -269,7 +284,7 @@ void WebContentsObserverAndroid::DidChangeThemeColor(SkColor color) {
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
return;
- Java_WebContentsObserverAndroid_didChangeThemeColor(env, obj.obj(), color);
+ Java_WebContentsObserver_didChangeThemeColor(env, obj.obj(), color);
}
void WebContentsObserverAndroid::DidFailLoadInternal(
@@ -287,7 +302,7 @@ void WebContentsObserverAndroid::DidFailLoadInternal(
ScopedJavaLocalRef<jstring> jstring_url(
ConvertUTF8ToJavaString(env, url.spec()));
- Java_WebContentsObserverAndroid_didFailLoad(
+ Java_WebContentsObserver_didFailLoad(
env, obj.obj(),
is_provisional_load,
is_main_frame,
@@ -300,7 +315,7 @@ void WebContentsObserverAndroid::DidFirstVisuallyNonEmptyPaint() {
ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
if (obj.is_null())
return;
- Java_WebContentsObserverAndroid_didFirstVisuallyNonEmptyPaint(
+ Java_WebContentsObserver_didFirstVisuallyNonEmptyPaint(
env, obj.obj());
}
diff --git a/chromium/content/browser/android/web_contents_observer_android.h b/chromium/content/browser/android/web_contents_observer_android.h
index e13606c3812..429290321ff 100644
--- a/chromium/content/browser/android/web_contents_observer_android.h
+++ b/chromium/content/browser/android/web_contents_observer_android.h
@@ -33,55 +33,43 @@ class WebContentsObserverAndroid : public WebContentsObserver {
private:
virtual void RenderProcessGone(
- base::TerminationStatus termination_status) OVERRIDE;
- virtual void DidStartLoading(RenderViewHost* render_view_host) OVERRIDE;
- virtual void DidStopLoading(RenderViewHost* render_view_host) OVERRIDE;
+ base::TerminationStatus termination_status) override;
+ virtual void DidStartLoading(RenderViewHost* render_view_host) override;
+ virtual void DidStopLoading(RenderViewHost* render_view_host) override;
virtual void DidFailProvisionalLoad(
- int64 frame_id,
- const base::string16& frame_unique_name,
- bool is_main_frame,
+ RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
- const base::string16& error_description,
- RenderViewHost* render_view_host) OVERRIDE;
- virtual void DidFailLoad(int64 frame_id,
+ const base::string16& error_description) override;
+ virtual void DidFailLoad(RenderFrameHost* render_frame_host,
const GURL& validated_url,
- bool is_main_frame,
int error_code,
- const base::string16& error_description,
- RenderViewHost* render_view_host) OVERRIDE;
+ const base::string16& error_description) override;
virtual void DidNavigateMainFrame(const LoadCommittedDetails& details,
- const FrameNavigateParams& params) OVERRIDE;
- virtual void DidNavigateAnyFrame(const LoadCommittedDetails& details,
- const FrameNavigateParams& params) OVERRIDE;
- virtual void DidFirstVisuallyNonEmptyPaint() OVERRIDE;
+ const FrameNavigateParams& params) override;
+ virtual void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override;
+ virtual void DidFirstVisuallyNonEmptyPaint() override;
virtual void DidStartProvisionalLoadForFrame(
- int64 frame_id,
- int64 parent_frame_id,
- bool is_main_frame,
+ RenderFrameHost* render_frame_host,
const GURL& validated_url,
bool is_error_page,
- bool is_iframe_srcdoc,
- RenderViewHost* render_view_host) OVERRIDE;
+ bool is_iframe_srcdoc) override;
virtual void DidCommitProvisionalLoadForFrame(
- int64 frame_id,
- const base::string16& frame_unique_name,
- bool is_main_frame,
+ RenderFrameHost* render_frame_host,
const GURL& url,
- PageTransition transition_type,
- RenderViewHost* render_view_host) OVERRIDE;
- virtual void DidFinishLoad(int64 frame_id,
- const GURL& validated_url,
- bool is_main_frame,
- RenderViewHost* render_view_host) OVERRIDE;
- virtual void DocumentLoadedInFrame(int64 frame_id,
- RenderViewHost* render_view_host) OVERRIDE;
+ ui::PageTransition transition_type) override;
+ virtual void DidFinishLoad(RenderFrameHost* render_frame_host,
+ const GURL& validated_url) override;
+ virtual void DocumentLoadedInFrame(
+ RenderFrameHost* render_frame_host) override;
virtual void NavigationEntryCommitted(
- const LoadCommittedDetails& load_details) OVERRIDE;
- virtual void WebContentsDestroyed() OVERRIDE;
- virtual void DidAttachInterstitialPage() OVERRIDE;
- virtual void DidDetachInterstitialPage() OVERRIDE;
- virtual void DidChangeThemeColor(SkColor color) OVERRIDE;
+ const LoadCommittedDetails& load_details) override;
+ virtual void WebContentsDestroyed() override;
+ virtual void DidAttachInterstitialPage() override;
+ virtual void DidDetachInterstitialPage() override;
+ virtual void DidChangeThemeColor(SkColor color) override;
void DidFailLoadInternal(bool is_provisional_load,
bool is_main_frame,
diff --git a/chromium/content/browser/appcache/DEPS b/chromium/content/browser/appcache/DEPS
new file mode 100644
index 00000000000..8608d5ff001
--- /dev/null
+++ b/chromium/content/browser/appcache/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+net/disk_cache",
+]
diff --git a/chromium/content/browser/appcache/appcache.cc b/chromium/content/browser/appcache/appcache.cc
new file mode 100644
index 00000000000..aa0b224bd7e
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache.cc
@@ -0,0 +1,327 @@
+// 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/appcache/appcache.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "content/browser/appcache/appcache_executable_handler.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/browser/appcache/appcache_storage.h"
+#include "content/common/appcache_interfaces.h"
+
+namespace content {
+
+AppCache::AppCache(AppCacheStorage* storage, int64 cache_id)
+ : cache_id_(cache_id),
+ owning_group_(NULL),
+ online_whitelist_all_(false),
+ is_complete_(false),
+ cache_size_(0),
+ storage_(storage) {
+ storage_->working_set()->AddCache(this);
+}
+
+AppCache::~AppCache() {
+ DCHECK(associated_hosts_.empty());
+ if (owning_group_.get()) {
+ DCHECK(is_complete_);
+ owning_group_->RemoveCache(this);
+ }
+ DCHECK(!owning_group_.get());
+ storage_->working_set()->RemoveCache(this);
+ STLDeleteContainerPairSecondPointers(
+ executable_handlers_.begin(), executable_handlers_.end());
+}
+
+void AppCache::UnassociateHost(AppCacheHost* host) {
+ associated_hosts_.erase(host);
+}
+
+void AppCache::AddEntry(const GURL& url, const AppCacheEntry& entry) {
+ DCHECK(entries_.find(url) == entries_.end());
+ entries_.insert(EntryMap::value_type(url, entry));
+ cache_size_ += entry.response_size();
+}
+
+bool AppCache::AddOrModifyEntry(const GURL& url, const AppCacheEntry& entry) {
+ std::pair<EntryMap::iterator, bool> ret =
+ entries_.insert(EntryMap::value_type(url, entry));
+
+ // Entry already exists. Merge the types of the new and existing entries.
+ if (!ret.second)
+ ret.first->second.add_types(entry.types());
+ else
+ cache_size_ += entry.response_size(); // New entry. Add to cache size.
+ return ret.second;
+}
+
+void AppCache::RemoveEntry(const GURL& url) {
+ EntryMap::iterator found = entries_.find(url);
+ DCHECK(found != entries_.end());
+ cache_size_ -= found->second.response_size();
+ entries_.erase(found);
+}
+
+AppCacheEntry* AppCache::GetEntry(const GURL& url) {
+ EntryMap::iterator it = entries_.find(url);
+ return (it != entries_.end()) ? &(it->second) : NULL;
+}
+
+const AppCacheEntry* AppCache::GetEntryAndUrlWithResponseId(
+ int64 response_id, GURL* optional_url_out) {
+ for (EntryMap::const_iterator iter = entries_.begin();
+ iter != entries_.end(); ++iter) {
+ if (iter->second.response_id() == response_id) {
+ if (optional_url_out)
+ *optional_url_out = iter->first;
+ return &iter->second;
+ }
+ }
+ return NULL;
+}
+
+AppCacheExecutableHandler* AppCache::GetExecutableHandler(int64 response_id) {
+ HandlerMap::const_iterator found = executable_handlers_.find(response_id);
+ if (found != executable_handlers_.end())
+ return found->second;
+ return NULL;
+}
+
+AppCacheExecutableHandler* AppCache::GetOrCreateExecutableHandler(
+ int64 response_id, net::IOBuffer* handler_source) {
+ AppCacheExecutableHandler* handler = GetExecutableHandler(response_id);
+ if (handler)
+ return handler;
+
+ GURL handler_url;
+ const AppCacheEntry* entry = GetEntryAndUrlWithResponseId(
+ response_id, &handler_url);
+ if (!entry || !entry->IsExecutable())
+ return NULL;
+
+ DCHECK(storage_->service()->handler_factory());
+ scoped_ptr<AppCacheExecutableHandler> own_ptr =
+ storage_->service()->handler_factory()->
+ CreateHandler(handler_url, handler_source);
+ handler = own_ptr.release();
+ if (!handler)
+ return NULL;
+ executable_handlers_[response_id] = handler;
+ return handler;
+}
+
+GURL AppCache::GetNamespaceEntryUrl(const AppCacheNamespaceVector& namespaces,
+ const GURL& namespace_url) const {
+ size_t count = namespaces.size();
+ for (size_t i = 0; i < count; ++i) {
+ if (namespaces[i].namespace_url == namespace_url)
+ return namespaces[i].target_url;
+ }
+ NOTREACHED();
+ return GURL();
+}
+
+namespace {
+bool SortNamespacesByLength(
+ const AppCacheNamespace& lhs, const AppCacheNamespace& rhs) {
+ return lhs.namespace_url.spec().length() > rhs.namespace_url.spec().length();
+}
+}
+
+void AppCache::InitializeWithManifest(AppCacheManifest* manifest) {
+ DCHECK(manifest);
+ intercept_namespaces_.swap(manifest->intercept_namespaces);
+ fallback_namespaces_.swap(manifest->fallback_namespaces);
+ online_whitelist_namespaces_.swap(manifest->online_whitelist_namespaces);
+ online_whitelist_all_ = manifest->online_whitelist_all;
+
+ // Sort the namespaces by url string length, longest to shortest,
+ // since longer matches trump when matching a url to a namespace.
+ std::sort(intercept_namespaces_.begin(), intercept_namespaces_.end(),
+ SortNamespacesByLength);
+ std::sort(fallback_namespaces_.begin(), fallback_namespaces_.end(),
+ SortNamespacesByLength);
+}
+
+void AppCache::InitializeWithDatabaseRecords(
+ const AppCacheDatabase::CacheRecord& cache_record,
+ const std::vector<AppCacheDatabase::EntryRecord>& entries,
+ const std::vector<AppCacheDatabase::NamespaceRecord>& intercepts,
+ const std::vector<AppCacheDatabase::NamespaceRecord>& fallbacks,
+ const std::vector<AppCacheDatabase::OnlineWhiteListRecord>& whitelists) {
+ DCHECK(cache_id_ == cache_record.cache_id);
+ online_whitelist_all_ = cache_record.online_wildcard;
+ update_time_ = cache_record.update_time;
+
+ for (size_t i = 0; i < entries.size(); ++i) {
+ const AppCacheDatabase::EntryRecord& entry = entries.at(i);
+ AddEntry(entry.url, AppCacheEntry(entry.flags, entry.response_id,
+ entry.response_size));
+ }
+ DCHECK(cache_size_ == cache_record.cache_size);
+
+ for (size_t i = 0; i < intercepts.size(); ++i)
+ intercept_namespaces_.push_back(intercepts.at(i).namespace_);
+
+ for (size_t i = 0; i < fallbacks.size(); ++i)
+ fallback_namespaces_.push_back(fallbacks.at(i).namespace_);
+
+ // Sort the fallback namespaces by url string length, longest to shortest,
+ // since longer matches trump when matching a url to a namespace.
+ std::sort(intercept_namespaces_.begin(), intercept_namespaces_.end(),
+ SortNamespacesByLength);
+ std::sort(fallback_namespaces_.begin(), fallback_namespaces_.end(),
+ SortNamespacesByLength);
+
+ for (size_t i = 0; i < whitelists.size(); ++i) {
+ const AppCacheDatabase::OnlineWhiteListRecord& record = whitelists.at(i);
+ online_whitelist_namespaces_.push_back(
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE,
+ record.namespace_url,
+ GURL(),
+ record.is_pattern));
+ }
+}
+
+void AppCache::ToDatabaseRecords(
+ const AppCacheGroup* group,
+ AppCacheDatabase::CacheRecord* cache_record,
+ std::vector<AppCacheDatabase::EntryRecord>* entries,
+ std::vector<AppCacheDatabase::NamespaceRecord>* intercepts,
+ std::vector<AppCacheDatabase::NamespaceRecord>* fallbacks,
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord>* whitelists) {
+ DCHECK(group && cache_record && entries && fallbacks && whitelists);
+ DCHECK(entries->empty() && fallbacks->empty() && whitelists->empty());
+
+ cache_record->cache_id = cache_id_;
+ cache_record->group_id = group->group_id();
+ cache_record->online_wildcard = online_whitelist_all_;
+ cache_record->update_time = update_time_;
+ cache_record->cache_size = 0;
+
+ for (EntryMap::const_iterator iter = entries_.begin();
+ iter != entries_.end(); ++iter) {
+ entries->push_back(AppCacheDatabase::EntryRecord());
+ AppCacheDatabase::EntryRecord& record = entries->back();
+ record.url = iter->first;
+ record.cache_id = cache_id_;
+ record.flags = iter->second.types();
+ record.response_id = iter->second.response_id();
+ record.response_size = iter->second.response_size();
+ cache_record->cache_size += record.response_size;
+ }
+
+ GURL origin = group->manifest_url().GetOrigin();
+
+ for (size_t i = 0; i < intercept_namespaces_.size(); ++i) {
+ intercepts->push_back(AppCacheDatabase::NamespaceRecord());
+ AppCacheDatabase::NamespaceRecord& record = intercepts->back();
+ record.cache_id = cache_id_;
+ record.origin = origin;
+ record.namespace_ = intercept_namespaces_[i];
+ }
+
+ for (size_t i = 0; i < fallback_namespaces_.size(); ++i) {
+ fallbacks->push_back(AppCacheDatabase::NamespaceRecord());
+ AppCacheDatabase::NamespaceRecord& record = fallbacks->back();
+ record.cache_id = cache_id_;
+ record.origin = origin;
+ record.namespace_ = fallback_namespaces_[i];
+ }
+
+ for (size_t i = 0; i < online_whitelist_namespaces_.size(); ++i) {
+ whitelists->push_back(AppCacheDatabase::OnlineWhiteListRecord());
+ AppCacheDatabase::OnlineWhiteListRecord& record = whitelists->back();
+ record.cache_id = cache_id_;
+ record.namespace_url = online_whitelist_namespaces_[i].namespace_url;
+ record.is_pattern = online_whitelist_namespaces_[i].is_pattern;
+ }
+}
+
+bool AppCache::FindResponseForRequest(const GURL& url,
+ AppCacheEntry* found_entry, GURL* found_intercept_namespace,
+ AppCacheEntry* found_fallback_entry, GURL* found_fallback_namespace,
+ bool* found_network_namespace) {
+ // Ignore fragments when looking up URL in the cache.
+ GURL url_no_ref;
+ if (url.has_ref()) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ url_no_ref = url.ReplaceComponents(replacements);
+ } else {
+ url_no_ref = url;
+ }
+
+ // 6.6.6 Changes to the networking model
+
+ AppCacheEntry* entry = GetEntry(url_no_ref);
+ if (entry) {
+ *found_entry = *entry;
+ return true;
+ }
+
+ *found_network_namespace = IsInNetworkNamespace(url_no_ref);
+ if (*found_network_namespace)
+ return true;
+
+ const AppCacheNamespace* intercept_namespace =
+ FindInterceptNamespace(url_no_ref);
+ if (intercept_namespace) {
+ entry = GetEntry(intercept_namespace->target_url);
+ DCHECK(entry);
+ *found_entry = *entry;
+ *found_intercept_namespace = intercept_namespace->namespace_url;
+ return true;
+ }
+
+ const AppCacheNamespace* fallback_namespace =
+ FindFallbackNamespace(url_no_ref);
+ if (fallback_namespace) {
+ entry = GetEntry(fallback_namespace->target_url);
+ DCHECK(entry);
+ *found_fallback_entry = *entry;
+ *found_fallback_namespace = fallback_namespace->namespace_url;
+ return true;
+ }
+
+ *found_network_namespace = online_whitelist_all_;
+ return *found_network_namespace;
+}
+
+
+void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const {
+ DCHECK(infos && infos->empty());
+ for (EntryMap::const_iterator iter = entries_.begin();
+ iter != entries_.end(); ++iter) {
+ infos->push_back(AppCacheResourceInfo());
+ AppCacheResourceInfo& info = infos->back();
+ info.url = iter->first;
+ info.is_master = iter->second.IsMaster();
+ info.is_manifest = iter->second.IsManifest();
+ info.is_intercept = iter->second.IsIntercept();
+ info.is_fallback = iter->second.IsFallback();
+ info.is_foreign = iter->second.IsForeign();
+ info.is_explicit = iter->second.IsExplicit();
+ info.size = iter->second.response_size();
+ info.response_id = iter->second.response_id();
+ }
+}
+
+// static
+const AppCacheNamespace* AppCache::FindNamespace(
+ const AppCacheNamespaceVector& namespaces,
+ const GURL& url) {
+ size_t count = namespaces.size();
+ for (size_t i = 0; i < count; ++i) {
+ if (namespaces[i].IsMatch(url))
+ return &namespaces[i];
+ }
+ return NULL;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache.h b/chromium/content/browser/appcache/appcache.h
new file mode 100644
index 00000000000..a444579a64d
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache.h
@@ -0,0 +1,210 @@
+// 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_APPCACHE_APPCACHE_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "content/browser/appcache/appcache_database.h"
+#include "content/browser/appcache/appcache_entry.h"
+#include "content/browser/appcache/appcache_manifest_parser.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace net {
+class IOBuffer;
+}
+
+namespace content {
+FORWARD_DECLARE_TEST(AppCacheTest, InitializeWithManifest);
+FORWARD_DECLARE_TEST(AppCacheTest, ToFromDatabaseRecords);
+class AppCacheExecutableHandler;
+class AppCacheGroup;
+class AppCacheHost;
+class AppCacheStorage;
+class AppCacheTest;
+class AppCacheStorageImplTest;
+class AppCacheUpdateJobTest;
+
+// Set of cached resources for an application. A cache exists as long as a
+// host is associated with it, the cache is in an appcache group or the
+// cache is being created during an appcache upate.
+class CONTENT_EXPORT AppCache
+ : public base::RefCounted<AppCache> {
+ public:
+ typedef std::map<GURL, AppCacheEntry> EntryMap;
+ typedef std::set<AppCacheHost*> AppCacheHosts;
+
+ AppCache(AppCacheStorage* storage, int64 cache_id);
+
+ int64 cache_id() const { return cache_id_; }
+
+ AppCacheGroup* owning_group() const { return owning_group_.get(); }
+
+ bool is_complete() const { return is_complete_; }
+ void set_complete(bool value) { is_complete_ = value; }
+
+ // Adds a new entry. Entry must not already be in cache.
+ void AddEntry(const GURL& url, const AppCacheEntry& entry);
+
+ // Adds a new entry or modifies an existing entry by merging the types
+ // of the new entry with the existing entry. Returns true if a new entry
+ // is added, false if the flags are merged into an existing entry.
+ bool AddOrModifyEntry(const GURL& url, const AppCacheEntry& entry);
+
+ // Removes an entry from the EntryMap, the URL must be in the set.
+ void RemoveEntry(const GURL& url);
+
+ // Do not store or delete the returned ptr, they're owned by 'this'.
+ AppCacheEntry* GetEntry(const GURL& url);
+ const AppCacheEntry* GetEntryWithResponseId(int64 response_id) {
+ return GetEntryAndUrlWithResponseId(response_id, NULL);
+ }
+ const AppCacheEntry* GetEntryAndUrlWithResponseId(
+ int64 response_id, GURL* optional_url);
+ const EntryMap& entries() const { return entries_; }
+
+ // The AppCache owns the collection of executable handlers that have
+ // been started for this instance. The getter looks up an existing
+ // handler returning null if not found, the GetOrCreate method will
+ // cons one up if not found.
+ // Do not store the returned ptrs, they're owned by 'this'.
+ AppCacheExecutableHandler* GetExecutableHandler(int64 response_id);
+ AppCacheExecutableHandler* GetOrCreateExecutableHandler(
+ int64 response_id, net::IOBuffer* handler_source);
+
+ // Returns the URL of the resource used as entry for 'namespace_url'.
+ GURL GetFallbackEntryUrl(const GURL& namespace_url) const {
+ return GetNamespaceEntryUrl(fallback_namespaces_, namespace_url);
+ }
+ GURL GetInterceptEntryUrl(const GURL& namespace_url) const {
+ return GetNamespaceEntryUrl(intercept_namespaces_, namespace_url);
+ }
+
+ AppCacheHosts& associated_hosts() { return associated_hosts_; }
+
+ bool IsNewerThan(AppCache* cache) const {
+ // TODO(michaeln): revisit, the system clock can be set
+ // back in time which would confuse this logic.
+ if (update_time_ > cache->update_time_)
+ return true;
+
+ // Tie breaker. Newer caches have a larger cache ID.
+ if (update_time_ == cache->update_time_)
+ return cache_id_ > cache->cache_id_;
+
+ return false;
+ }
+
+ base::Time update_time() const { return update_time_; }
+
+ int64 cache_size() const { return cache_size_; }
+
+ void set_update_time(base::Time ticks) { update_time_ = ticks; }
+
+ // Initializes the cache with information in the manifest.
+ // Do not use the manifest after this call.
+ void InitializeWithManifest(AppCacheManifest* manifest);
+
+ // Initializes the cache with the information in the database records.
+ void InitializeWithDatabaseRecords(
+ const AppCacheDatabase::CacheRecord& cache_record,
+ const std::vector<AppCacheDatabase::EntryRecord>& entries,
+ const std::vector<AppCacheDatabase::NamespaceRecord>& intercepts,
+ const std::vector<AppCacheDatabase::NamespaceRecord>& fallbacks,
+ const std::vector<AppCacheDatabase::OnlineWhiteListRecord>& whitelists);
+
+ // Returns the database records to be stored in the AppCacheDatabase
+ // to represent this cache.
+ void ToDatabaseRecords(
+ const AppCacheGroup* group,
+ AppCacheDatabase::CacheRecord* cache_record,
+ std::vector<AppCacheDatabase::EntryRecord>* entries,
+ std::vector<AppCacheDatabase::NamespaceRecord>* intercepts,
+ std::vector<AppCacheDatabase::NamespaceRecord>* fallbacks,
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord>* whitelists);
+
+ bool FindResponseForRequest(const GURL& url,
+ AppCacheEntry* found_entry, GURL* found_intercept_namespace,
+ AppCacheEntry* found_fallback_entry, GURL* found_fallback_namespace,
+ bool* found_network_namespace);
+
+ // Populates the 'infos' vector with an element per entry in the appcache.
+ void ToResourceInfoVector(AppCacheResourceInfoVector* infos) const;
+
+ static const AppCacheNamespace* FindNamespace(
+ const AppCacheNamespaceVector& namespaces,
+ const GURL& url);
+
+ private:
+ friend class AppCacheGroup;
+ friend class AppCacheHost;
+ friend class content::AppCacheTest;
+ friend class content::AppCacheStorageImplTest;
+ friend class content::AppCacheUpdateJobTest;
+ friend class base::RefCounted<AppCache>;
+
+ ~AppCache();
+
+ // Use AppCacheGroup::Add/RemoveCache() to manipulate owning group.
+ void set_owning_group(AppCacheGroup* group) { owning_group_ = group; }
+
+ // FindResponseForRequest helpers
+ const AppCacheNamespace* FindInterceptNamespace(const GURL& url) {
+ return FindNamespace(intercept_namespaces_, url);
+ }
+ const AppCacheNamespace* FindFallbackNamespace(const GURL& url) {
+ return FindNamespace(fallback_namespaces_, url);
+ }
+ bool IsInNetworkNamespace(const GURL& url) {
+ return FindNamespace(online_whitelist_namespaces_, url) != NULL;
+ }
+
+ GURL GetNamespaceEntryUrl(const AppCacheNamespaceVector& namespaces,
+ const GURL& namespace_url) const;
+
+ // Use AppCacheHost::Associate*Cache() to manipulate host association.
+ void AssociateHost(AppCacheHost* host) {
+ associated_hosts_.insert(host);
+ }
+ void UnassociateHost(AppCacheHost* host);
+
+ const int64 cache_id_;
+ scoped_refptr<AppCacheGroup> owning_group_;
+ AppCacheHosts associated_hosts_;
+
+ EntryMap entries_; // contains entries of all types
+
+ AppCacheNamespaceVector intercept_namespaces_;
+ AppCacheNamespaceVector fallback_namespaces_;
+ AppCacheNamespaceVector online_whitelist_namespaces_;
+ bool online_whitelist_all_;
+
+ bool is_complete_;
+
+ // when this cache was last updated
+ base::Time update_time_;
+
+ int64 cache_size_;
+
+ typedef std::map<int64, AppCacheExecutableHandler*> HandlerMap;
+ HandlerMap executable_handlers_;
+
+ // to notify storage when cache is deleted
+ AppCacheStorage* storage_;
+
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, InitializeWithManifest);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, ToFromDatabaseRecords);
+ DISALLOW_COPY_AND_ASSIGN(AppCache);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_H_
diff --git a/chromium/content/browser/appcache/appcache_backend_impl.cc b/chromium/content/browser/appcache/appcache_backend_impl.cc
new file mode 100644
index 00000000000..099c54e55ad
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_backend_impl.cc
@@ -0,0 +1,182 @@
+// 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 "content/browser/appcache/appcache_backend_impl.h"
+
+#include "base/stl_util.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+
+namespace content {
+
+AppCacheBackendImpl::AppCacheBackendImpl()
+ : service_(NULL),
+ frontend_(NULL),
+ process_id_(0) {
+}
+
+AppCacheBackendImpl::~AppCacheBackendImpl() {
+ STLDeleteValues(&hosts_);
+ if (service_)
+ service_->UnregisterBackend(this);
+}
+
+void AppCacheBackendImpl::Initialize(AppCacheServiceImpl* service,
+ AppCacheFrontend* frontend,
+ int process_id) {
+ DCHECK(!service_ && !frontend_ && frontend && service);
+ service_ = service;
+ frontend_ = frontend;
+ process_id_ = process_id;
+ service_->RegisterBackend(this);
+}
+
+bool AppCacheBackendImpl::RegisterHost(int id) {
+ if (GetHost(id))
+ return false;
+
+ hosts_.insert(
+ HostMap::value_type(id, new AppCacheHost(id, frontend_, service_)));
+ return true;
+}
+
+bool AppCacheBackendImpl::UnregisterHost(int id) {
+ HostMap::iterator found = hosts_.find(id);
+ if (found == hosts_.end())
+ return false;
+
+ delete found->second;
+ hosts_.erase(found);
+ return true;
+}
+
+bool AppCacheBackendImpl::SetSpawningHostId(
+ int host_id,
+ int spawning_host_id) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return false;
+ host->SetSpawningHostId(process_id_, spawning_host_id);
+ return true;
+}
+
+bool AppCacheBackendImpl::SelectCache(
+ int host_id,
+ const GURL& document_url,
+ const int64 cache_document_was_loaded_from,
+ const GURL& manifest_url) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return false;
+
+ host->SelectCache(document_url, cache_document_was_loaded_from,
+ manifest_url);
+ return true;
+}
+
+bool AppCacheBackendImpl::SelectCacheForWorker(
+ int host_id, int parent_process_id, int parent_host_id) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return false;
+
+ host->SelectCacheForWorker(parent_process_id, parent_host_id);
+ return true;
+}
+
+bool AppCacheBackendImpl::SelectCacheForSharedWorker(
+ int host_id, int64 appcache_id) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return false;
+
+ host->SelectCacheForSharedWorker(appcache_id);
+ return true;
+}
+
+bool AppCacheBackendImpl::MarkAsForeignEntry(
+ int host_id,
+ const GURL& document_url,
+ int64 cache_document_was_loaded_from) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return false;
+
+ host->MarkAsForeignEntry(document_url, cache_document_was_loaded_from);
+ return true;
+}
+
+bool AppCacheBackendImpl::GetStatusWithCallback(
+ int host_id, const GetStatusCallback& callback, void* callback_param) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return false;
+
+ host->GetStatusWithCallback(callback, callback_param);
+ return true;
+}
+
+bool AppCacheBackendImpl::StartUpdateWithCallback(
+ int host_id, const StartUpdateCallback& callback, void* callback_param) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return false;
+
+ host->StartUpdateWithCallback(callback, callback_param);
+ return true;
+}
+
+bool AppCacheBackendImpl::SwapCacheWithCallback(
+ int host_id, const SwapCacheCallback& callback, void* callback_param) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return false;
+
+ host->SwapCacheWithCallback(callback, callback_param);
+ return true;
+}
+
+void AppCacheBackendImpl::GetResourceList(
+ int host_id, std::vector<AppCacheResourceInfo>* resource_infos) {
+ AppCacheHost* host = GetHost(host_id);
+ if (!host)
+ return;
+
+ host->GetResourceList(resource_infos);
+}
+
+scoped_ptr<AppCacheHost> AppCacheBackendImpl::TransferHostOut(int host_id) {
+ HostMap::iterator found = hosts_.find(host_id);
+ if (found == hosts_.end()) {
+ NOTREACHED();
+ return scoped_ptr<AppCacheHost>();
+ }
+
+ AppCacheHost* transferree = found->second;
+
+ // Put a new empty host in its place.
+ found->second = new AppCacheHost(host_id, frontend_, service_);
+
+ // We give up ownership.
+ transferree->PrepareForTransfer();
+ return scoped_ptr<AppCacheHost>(transferree);
+}
+
+void AppCacheBackendImpl::TransferHostIn(
+ int new_host_id, scoped_ptr<AppCacheHost> host) {
+ HostMap::iterator found = hosts_.find(new_host_id);
+ if (found == hosts_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ delete found->second;
+
+ // We take onwership.
+ host->CompleteTransfer(new_host_id, frontend_);
+ found->second = host.release();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_backend_impl.h b/chromium/content/browser/appcache/appcache_backend_impl.h
new file mode 100644
index 00000000000..bd6f440823e
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_backend_impl.h
@@ -0,0 +1,75 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_BACKEND_IMPL_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_BACKEND_IMPL_H_
+
+#include "base/containers/hash_tables.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class AppCacheServiceImpl;
+
+class CONTENT_EXPORT AppCacheBackendImpl {
+ public:
+ AppCacheBackendImpl();
+ ~AppCacheBackendImpl();
+
+ void Initialize(AppCacheServiceImpl* service,
+ AppCacheFrontend* frontend,
+ int process_id);
+
+ int process_id() const { return process_id_; }
+
+ // Methods to support the AppCacheBackend interface. A false return
+ // value indicates an invalid host_id and that no action was taken
+ // by the backend impl.
+ bool RegisterHost(int host_id);
+ bool UnregisterHost(int host_id);
+ bool SetSpawningHostId(int host_id, int spawning_host_id);
+ bool SelectCache(int host_id,
+ const GURL& document_url,
+ const int64 cache_document_was_loaded_from,
+ const GURL& manifest_url);
+ void GetResourceList(
+ int host_id, std::vector<AppCacheResourceInfo>* resource_infos);
+ bool SelectCacheForWorker(int host_id, int parent_process_id,
+ int parent_host_id);
+ bool SelectCacheForSharedWorker(int host_id, int64 appcache_id);
+ bool MarkAsForeignEntry(int host_id, const GURL& document_url,
+ int64 cache_document_was_loaded_from);
+ bool GetStatusWithCallback(int host_id, const GetStatusCallback& callback,
+ void* callback_param);
+ bool StartUpdateWithCallback(int host_id, const StartUpdateCallback& callback,
+ void* callback_param);
+ bool SwapCacheWithCallback(int host_id, const SwapCacheCallback& callback,
+ void* callback_param);
+
+ // Returns a pointer to a registered host. The backend retains ownership.
+ AppCacheHost* GetHost(int host_id) {
+ HostMap::iterator it = hosts_.find(host_id);
+ return (it != hosts_.end()) ? (it->second) : NULL;
+ }
+
+ typedef base::hash_map<int, AppCacheHost*> HostMap;
+ const HostMap& hosts() { return hosts_; }
+
+ // Methods to support cross site navigations. Hosts are transferred
+ // from process to process accordingly, deparented from the old
+ // processes backend and reparented to the new.
+ scoped_ptr<AppCacheHost> TransferHostOut(int host_id);
+ void TransferHostIn(int new_host_id, scoped_ptr<AppCacheHost> host);
+
+ private:
+ AppCacheServiceImpl* service_;
+ AppCacheFrontend* frontend_;
+ int process_id_;
+ HostMap hosts_;
+};
+
+} // namespace
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_BACKEND_IMPL_H_
diff --git a/chromium/content/browser/appcache/appcache_database.cc b/chromium/content/browser/appcache/appcache_database.cc
new file mode 100644
index 00000000000..3e502813a1b
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_database.cc
@@ -0,0 +1,1228 @@
+// 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/appcache/appcache_database.h"
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/appcache/appcache_entry.h"
+#include "content/browser/appcache/appcache_histograms.h"
+#include "sql/connection.h"
+#include "sql/error_delegate_util.h"
+#include "sql/meta_table.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace content {
+
+// Schema -------------------------------------------------------------------
+namespace {
+
+#if defined(APPCACHE_USE_SIMPLE_CACHE)
+const int kCurrentVersion = 6;
+const int kCompatibleVersion = 6;
+#else
+const int kCurrentVersion = 5;
+const int kCompatibleVersion = 5;
+#endif
+
+// A mechanism to run experiments that may affect in data being persisted
+// in different ways such that when the experiment is toggled on/off via
+// cmd line flags, the database gets reset. The active flags are stored at
+// the time of database creation and compared when reopening. If different
+// the database is reset.
+const char kExperimentFlagsKey[] = "ExperimentFlags";
+
+const char kGroupsTable[] = "Groups";
+const char kCachesTable[] = "Caches";
+const char kEntriesTable[] = "Entries";
+const char kNamespacesTable[] = "Namespaces";
+const char kOnlineWhiteListsTable[] = "OnlineWhiteLists";
+const char kDeletableResponseIdsTable[] = "DeletableResponseIds";
+
+struct TableInfo {
+ const char* table_name;
+ const char* columns;
+};
+
+struct IndexInfo {
+ const char* index_name;
+ const char* table_name;
+ const char* columns;
+ bool unique;
+};
+
+const TableInfo kTables[] = {
+ { kGroupsTable,
+ "(group_id INTEGER PRIMARY KEY,"
+ " origin TEXT,"
+ " manifest_url TEXT,"
+ " creation_time INTEGER,"
+ " last_access_time INTEGER)" },
+
+ { kCachesTable,
+ "(cache_id INTEGER PRIMARY KEY,"
+ " group_id INTEGER,"
+ " online_wildcard INTEGER CHECK(online_wildcard IN (0, 1)),"
+ " update_time INTEGER,"
+ " cache_size INTEGER)" }, // intentionally not normalized
+
+ { kEntriesTable,
+ "(cache_id INTEGER,"
+ " url TEXT,"
+ " flags INTEGER,"
+ " response_id INTEGER,"
+ " response_size INTEGER)" },
+
+ { kNamespacesTable,
+ "(cache_id INTEGER,"
+ " origin TEXT," // intentionally not normalized
+ " type INTEGER,"
+ " namespace_url TEXT,"
+ " target_url TEXT,"
+ " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" },
+
+ { kOnlineWhiteListsTable,
+ "(cache_id INTEGER,"
+ " namespace_url TEXT,"
+ " is_pattern INTEGER CHECK(is_pattern IN (0, 1)))" },
+
+ { kDeletableResponseIdsTable,
+ "(response_id INTEGER NOT NULL)" },
+};
+
+const IndexInfo kIndexes[] = {
+ { "GroupsOriginIndex",
+ kGroupsTable,
+ "(origin)",
+ false },
+
+ { "GroupsManifestIndex",
+ kGroupsTable,
+ "(manifest_url)",
+ true },
+
+ { "CachesGroupIndex",
+ kCachesTable,
+ "(group_id)",
+ false },
+
+ { "EntriesCacheIndex",
+ kEntriesTable,
+ "(cache_id)",
+ false },
+
+ { "EntriesCacheAndUrlIndex",
+ kEntriesTable,
+ "(cache_id, url)",
+ true },
+
+ { "EntriesResponseIdIndex",
+ kEntriesTable,
+ "(response_id)",
+ true },
+
+ { "NamespacesCacheIndex",
+ kNamespacesTable,
+ "(cache_id)",
+ false },
+
+ { "NamespacesOriginIndex",
+ kNamespacesTable,
+ "(origin)",
+ false },
+
+ { "NamespacesCacheAndUrlIndex",
+ kNamespacesTable,
+ "(cache_id, namespace_url)",
+ true },
+
+ { "OnlineWhiteListCacheIndex",
+ kOnlineWhiteListsTable,
+ "(cache_id)",
+ false },
+
+ { "DeletableResponsesIdIndex",
+ kDeletableResponseIdsTable,
+ "(response_id)",
+ true },
+};
+
+const int kTableCount = arraysize(kTables);
+const int kIndexCount = arraysize(kIndexes);
+
+bool CreateTable(sql::Connection* db, const TableInfo& info) {
+ std::string sql("CREATE TABLE ");
+ sql += info.table_name;
+ sql += info.columns;
+ return db->Execute(sql.c_str());
+}
+
+bool CreateIndex(sql::Connection* db, const IndexInfo& info) {
+ std::string sql;
+ if (info.unique)
+ sql += "CREATE UNIQUE INDEX ";
+ else
+ sql += "CREATE INDEX ";
+ sql += info.index_name;
+ sql += " ON ";
+ sql += info.table_name;
+ sql += info.columns;
+ return db->Execute(sql.c_str());
+}
+
+std::string GetActiveExperimentFlags() {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ kEnableExecutableHandlers))
+ return std::string("executableHandlersEnabled");
+ return std::string();
+}
+
+} // anon namespace
+
+// AppCacheDatabase ----------------------------------------------------------
+
+AppCacheDatabase::GroupRecord::GroupRecord()
+ : group_id(0) {
+}
+
+AppCacheDatabase::GroupRecord::~GroupRecord() {
+}
+
+AppCacheDatabase::NamespaceRecord::NamespaceRecord()
+ : cache_id(0) {
+}
+
+AppCacheDatabase::NamespaceRecord::~NamespaceRecord() {
+}
+
+
+AppCacheDatabase::AppCacheDatabase(const base::FilePath& path)
+ : db_file_path_(path),
+ is_disabled_(false),
+ is_recreating_(false),
+ was_corruption_detected_(false) {
+}
+
+AppCacheDatabase::~AppCacheDatabase() {
+}
+
+void AppCacheDatabase::Disable() {
+ VLOG(1) << "Disabling appcache database.";
+ is_disabled_ = true;
+ ResetConnectionAndTables();
+}
+
+int64 AppCacheDatabase::GetOriginUsage(const GURL& origin) {
+ std::vector<CacheRecord> records;
+ if (!FindCachesForOrigin(origin, &records))
+ return 0;
+
+ int64 origin_usage = 0;
+ std::vector<CacheRecord>::const_iterator iter = records.begin();
+ while (iter != records.end()) {
+ origin_usage += iter->cache_size;
+ ++iter;
+ }
+ return origin_usage;
+}
+
+bool AppCacheDatabase::GetAllOriginUsage(std::map<GURL, int64>* usage_map) {
+ std::set<GURL> origins;
+ if (!FindOriginsWithGroups(&origins))
+ return false;
+ for (std::set<GURL>::const_iterator origin = origins.begin();
+ origin != origins.end(); ++origin) {
+ (*usage_map)[*origin] = GetOriginUsage(*origin);
+ }
+ return true;
+}
+
+bool AppCacheDatabase::FindOriginsWithGroups(std::set<GURL>* origins) {
+ DCHECK(origins && origins->empty());
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT DISTINCT(origin) FROM Groups";
+
+ sql::Statement statement(db_->GetUniqueStatement(kSql));
+
+ while (statement.Step())
+ origins->insert(GURL(statement.ColumnString(0)));
+
+ return statement.Succeeded();
+}
+
+bool AppCacheDatabase::FindLastStorageIds(
+ int64* last_group_id, int64* last_cache_id, int64* last_response_id,
+ int64* last_deletable_response_rowid) {
+ DCHECK(last_group_id && last_cache_id && last_response_id &&
+ last_deletable_response_rowid);
+
+ *last_group_id = 0;
+ *last_cache_id = 0;
+ *last_response_id = 0;
+ *last_deletable_response_rowid = 0;
+
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kMaxGroupIdSql = "SELECT MAX(group_id) FROM Groups";
+ const char* kMaxCacheIdSql = "SELECT MAX(cache_id) FROM Caches";
+ const char* kMaxResponseIdFromEntriesSql =
+ "SELECT MAX(response_id) FROM Entries";
+ const char* kMaxResponseIdFromDeletablesSql =
+ "SELECT MAX(response_id) FROM DeletableResponseIds";
+ const char* kMaxDeletableResponseRowIdSql =
+ "SELECT MAX(rowid) FROM DeletableResponseIds";
+ int64 max_group_id;
+ int64 max_cache_id;
+ int64 max_response_id_from_entries;
+ int64 max_response_id_from_deletables;
+ int64 max_deletable_response_rowid;
+ if (!RunUniqueStatementWithInt64Result(kMaxGroupIdSql, &max_group_id) ||
+ !RunUniqueStatementWithInt64Result(kMaxCacheIdSql, &max_cache_id) ||
+ !RunUniqueStatementWithInt64Result(kMaxResponseIdFromEntriesSql,
+ &max_response_id_from_entries) ||
+ !RunUniqueStatementWithInt64Result(kMaxResponseIdFromDeletablesSql,
+ &max_response_id_from_deletables) ||
+ !RunUniqueStatementWithInt64Result(kMaxDeletableResponseRowIdSql,
+ &max_deletable_response_rowid)) {
+ return false;
+ }
+
+ *last_group_id = max_group_id;
+ *last_cache_id = max_cache_id;
+ *last_response_id = std::max(max_response_id_from_entries,
+ max_response_id_from_deletables);
+ *last_deletable_response_rowid = max_deletable_response_rowid;
+ return true;
+}
+
+bool AppCacheDatabase::FindGroup(int64 group_id, GroupRecord* record) {
+ DCHECK(record);
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT group_id, origin, manifest_url,"
+ " creation_time, last_access_time"
+ " FROM Groups WHERE group_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+
+ statement.BindInt64(0, group_id);
+ if (!statement.Step())
+ return false;
+
+ ReadGroupRecord(statement, record);
+ DCHECK(record->group_id == group_id);
+ return true;
+}
+
+bool AppCacheDatabase::FindGroupForManifestUrl(
+ const GURL& manifest_url, GroupRecord* record) {
+ DCHECK(record);
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT group_id, origin, manifest_url,"
+ " creation_time, last_access_time"
+ " FROM Groups WHERE manifest_url = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindString(0, manifest_url.spec());
+
+ if (!statement.Step())
+ return false;
+
+ ReadGroupRecord(statement, record);
+ DCHECK(record->manifest_url == manifest_url);
+ return true;
+}
+
+bool AppCacheDatabase::FindGroupsForOrigin(
+ const GURL& origin, std::vector<GroupRecord>* records) {
+ DCHECK(records && records->empty());
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT group_id, origin, manifest_url,"
+ " creation_time, last_access_time"
+ " FROM Groups WHERE origin = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindString(0, origin.spec());
+
+ while (statement.Step()) {
+ records->push_back(GroupRecord());
+ ReadGroupRecord(statement, &records->back());
+ DCHECK(records->back().origin == origin);
+ }
+
+ return statement.Succeeded();
+}
+
+bool AppCacheDatabase::FindGroupForCache(int64 cache_id, GroupRecord* record) {
+ DCHECK(record);
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT g.group_id, g.origin, g.manifest_url,"
+ " g.creation_time, g.last_access_time"
+ " FROM Groups g, Caches c"
+ " WHERE c.cache_id = ? AND c.group_id = g.group_id";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ if (!statement.Step())
+ return false;
+
+ ReadGroupRecord(statement, record);
+ return true;
+}
+
+bool AppCacheDatabase::UpdateGroupLastAccessTime(
+ int64 group_id, base::Time time) {
+ if (!LazyOpen(true))
+ return false;
+
+ const char* kSql =
+ "UPDATE Groups SET last_access_time = ? WHERE group_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, time.ToInternalValue());
+ statement.BindInt64(1, group_id);
+
+ return statement.Run() && db_->GetLastChangeCount();
+}
+
+bool AppCacheDatabase::InsertGroup(const GroupRecord* record) {
+ if (!LazyOpen(true))
+ return false;
+
+ const char* kSql =
+ "INSERT INTO Groups"
+ " (group_id, origin, manifest_url, creation_time, last_access_time)"
+ " VALUES(?, ?, ?, ?, ?)";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, record->group_id);
+ statement.BindString(1, record->origin.spec());
+ statement.BindString(2, record->manifest_url.spec());
+ statement.BindInt64(3, record->creation_time.ToInternalValue());
+ statement.BindInt64(4, record->last_access_time.ToInternalValue());
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::DeleteGroup(int64 group_id) {
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "DELETE FROM Groups WHERE group_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, group_id);
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::FindCache(int64 cache_id, CacheRecord* record) {
+ DCHECK(record);
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT cache_id, group_id, online_wildcard, update_time, cache_size"
+ " FROM Caches WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ if (!statement.Step())
+ return false;
+
+ ReadCacheRecord(statement, record);
+ return true;
+}
+
+bool AppCacheDatabase::FindCacheForGroup(int64 group_id, CacheRecord* record) {
+ DCHECK(record);
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT cache_id, group_id, online_wildcard, update_time, cache_size"
+ " FROM Caches WHERE group_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, group_id);
+
+ if (!statement.Step())
+ return false;
+
+ ReadCacheRecord(statement, record);
+ return true;
+}
+
+bool AppCacheDatabase::FindCachesForOrigin(
+ const GURL& origin, std::vector<CacheRecord>* records) {
+ DCHECK(records);
+ std::vector<GroupRecord> group_records;
+ if (!FindGroupsForOrigin(origin, &group_records))
+ return false;
+
+ CacheRecord cache_record;
+ std::vector<GroupRecord>::const_iterator iter = group_records.begin();
+ while (iter != group_records.end()) {
+ if (FindCacheForGroup(iter->group_id, &cache_record))
+ records->push_back(cache_record);
+ ++iter;
+ }
+ return true;
+}
+
+bool AppCacheDatabase::InsertCache(const CacheRecord* record) {
+ if (!LazyOpen(true))
+ return false;
+
+ const char* kSql =
+ "INSERT INTO Caches (cache_id, group_id, online_wildcard,"
+ " update_time, cache_size)"
+ " VALUES(?, ?, ?, ?, ?)";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, record->cache_id);
+ statement.BindInt64(1, record->group_id);
+ statement.BindBool(2, record->online_wildcard);
+ statement.BindInt64(3, record->update_time.ToInternalValue());
+ statement.BindInt64(4, record->cache_size);
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::DeleteCache(int64 cache_id) {
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "DELETE FROM Caches WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::FindEntriesForCache(
+ int64 cache_id, std::vector<EntryRecord>* records) {
+ DCHECK(records && records->empty());
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT cache_id, url, flags, response_id, response_size FROM Entries"
+ " WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ while (statement.Step()) {
+ records->push_back(EntryRecord());
+ ReadEntryRecord(statement, &records->back());
+ DCHECK(records->back().cache_id == cache_id);
+ }
+
+ return statement.Succeeded();
+}
+
+bool AppCacheDatabase::FindEntriesForUrl(
+ const GURL& url, std::vector<EntryRecord>* records) {
+ DCHECK(records && records->empty());
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT cache_id, url, flags, response_id, response_size FROM Entries"
+ " WHERE url = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindString(0, url.spec());
+
+ while (statement.Step()) {
+ records->push_back(EntryRecord());
+ ReadEntryRecord(statement, &records->back());
+ DCHECK(records->back().url == url);
+ }
+
+ return statement.Succeeded();
+}
+
+bool AppCacheDatabase::FindEntry(
+ int64 cache_id, const GURL& url, EntryRecord* record) {
+ DCHECK(record);
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT cache_id, url, flags, response_id, response_size FROM Entries"
+ " WHERE cache_id = ? AND url = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+ statement.BindString(1, url.spec());
+
+ if (!statement.Step())
+ return false;
+
+ ReadEntryRecord(statement, record);
+ DCHECK(record->cache_id == cache_id);
+ DCHECK(record->url == url);
+ return true;
+}
+
+bool AppCacheDatabase::InsertEntry(const EntryRecord* record) {
+ if (!LazyOpen(true))
+ return false;
+
+ const char* kSql =
+ "INSERT INTO Entries (cache_id, url, flags, response_id, response_size)"
+ " VALUES(?, ?, ?, ?, ?)";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, record->cache_id);
+ statement.BindString(1, record->url.spec());
+ statement.BindInt(2, record->flags);
+ statement.BindInt64(3, record->response_id);
+ statement.BindInt64(4, record->response_size);
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::InsertEntryRecords(
+ const std::vector<EntryRecord>& records) {
+ if (records.empty())
+ return true;
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ std::vector<EntryRecord>::const_iterator iter = records.begin();
+ while (iter != records.end()) {
+ if (!InsertEntry(&(*iter)))
+ return false;
+ ++iter;
+ }
+ return transaction.Commit();
+}
+
+bool AppCacheDatabase::DeleteEntriesForCache(int64 cache_id) {
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "DELETE FROM Entries WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::AddEntryFlags(
+ const GURL& entry_url, int64 cache_id, int additional_flags) {
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "UPDATE Entries SET flags = flags | ? WHERE cache_id = ? AND url = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt(0, additional_flags);
+ statement.BindInt64(1, cache_id);
+ statement.BindString(2, entry_url.spec());
+
+ return statement.Run() && db_->GetLastChangeCount();
+}
+
+bool AppCacheDatabase::FindNamespacesForOrigin(
+ const GURL& origin,
+ std::vector<NamespaceRecord>* intercepts,
+ std::vector<NamespaceRecord>* fallbacks) {
+ DCHECK(intercepts && intercepts->empty());
+ DCHECK(fallbacks && fallbacks->empty());
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT cache_id, origin, type, namespace_url, target_url, is_pattern"
+ " FROM Namespaces WHERE origin = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindString(0, origin.spec());
+
+ ReadNamespaceRecords(&statement, intercepts, fallbacks);
+
+ return statement.Succeeded();
+}
+
+bool AppCacheDatabase::FindNamespacesForCache(
+ int64 cache_id,
+ std::vector<NamespaceRecord>* intercepts,
+ std::vector<NamespaceRecord>* fallbacks) {
+ DCHECK(intercepts && intercepts->empty());
+ DCHECK(fallbacks && fallbacks->empty());
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT cache_id, origin, type, namespace_url, target_url, is_pattern"
+ " FROM Namespaces WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ ReadNamespaceRecords(&statement, intercepts, fallbacks);
+
+ return statement.Succeeded();
+}
+
+bool AppCacheDatabase::InsertNamespace(
+ const NamespaceRecord* record) {
+ if (!LazyOpen(true))
+ return false;
+
+ const char* kSql =
+ "INSERT INTO Namespaces"
+ " (cache_id, origin, type, namespace_url, target_url, is_pattern)"
+ " VALUES (?, ?, ?, ?, ?, ?)";
+
+ // Note: quick and dirty storage for the 'executable' bit w/o changing
+ // schemas, we use the high bit of 'type' field.
+ int type_with_executable_bit = record->namespace_.type;
+ if (record->namespace_.is_executable) {
+ type_with_executable_bit |= 0x8000000;
+ DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ kEnableExecutableHandlers));
+ }
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, record->cache_id);
+ statement.BindString(1, record->origin.spec());
+ statement.BindInt(2, type_with_executable_bit);
+ statement.BindString(3, record->namespace_.namespace_url.spec());
+ statement.BindString(4, record->namespace_.target_url.spec());
+ statement.BindBool(5, record->namespace_.is_pattern);
+ return statement.Run();
+}
+
+bool AppCacheDatabase::InsertNamespaceRecords(
+ const std::vector<NamespaceRecord>& records) {
+ if (records.empty())
+ return true;
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ std::vector<NamespaceRecord>::const_iterator iter = records.begin();
+ while (iter != records.end()) {
+ if (!InsertNamespace(&(*iter)))
+ return false;
+ ++iter;
+ }
+ return transaction.Commit();
+}
+
+bool AppCacheDatabase::DeleteNamespacesForCache(int64 cache_id) {
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "DELETE FROM Namespaces WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::FindOnlineWhiteListForCache(
+ int64 cache_id, std::vector<OnlineWhiteListRecord>* records) {
+ DCHECK(records && records->empty());
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT cache_id, namespace_url, is_pattern FROM OnlineWhiteLists"
+ " WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ while (statement.Step()) {
+ records->push_back(OnlineWhiteListRecord());
+ this->ReadOnlineWhiteListRecord(statement, &records->back());
+ DCHECK(records->back().cache_id == cache_id);
+ }
+ return statement.Succeeded();
+}
+
+bool AppCacheDatabase::InsertOnlineWhiteList(
+ const OnlineWhiteListRecord* record) {
+ if (!LazyOpen(true))
+ return false;
+
+ const char* kSql =
+ "INSERT INTO OnlineWhiteLists (cache_id, namespace_url, is_pattern)"
+ " VALUES (?, ?, ?)";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, record->cache_id);
+ statement.BindString(1, record->namespace_url.spec());
+ statement.BindBool(2, record->is_pattern);
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::InsertOnlineWhiteListRecords(
+ const std::vector<OnlineWhiteListRecord>& records) {
+ if (records.empty())
+ return true;
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ std::vector<OnlineWhiteListRecord>::const_iterator iter = records.begin();
+ while (iter != records.end()) {
+ if (!InsertOnlineWhiteList(&(*iter)))
+ return false;
+ ++iter;
+ }
+ return transaction.Commit();
+}
+
+bool AppCacheDatabase::DeleteOnlineWhiteListForCache(int64 cache_id) {
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "DELETE FROM OnlineWhiteLists WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, cache_id);
+
+ return statement.Run();
+}
+
+bool AppCacheDatabase::GetDeletableResponseIds(
+ std::vector<int64>* response_ids, int64 max_rowid, int limit) {
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT response_id FROM DeletableResponseIds "
+ " WHERE rowid <= ?"
+ " LIMIT ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, max_rowid);
+ statement.BindInt64(1, limit);
+
+ while (statement.Step())
+ response_ids->push_back(statement.ColumnInt64(0));
+ return statement.Succeeded();
+}
+
+bool AppCacheDatabase::InsertDeletableResponseIds(
+ const std::vector<int64>& response_ids) {
+ const char* kSql =
+ "INSERT INTO DeletableResponseIds (response_id) VALUES (?)";
+ return RunCachedStatementWithIds(SQL_FROM_HERE, kSql, response_ids);
+}
+
+bool AppCacheDatabase::DeleteDeletableResponseIds(
+ const std::vector<int64>& response_ids) {
+ const char* kSql =
+ "DELETE FROM DeletableResponseIds WHERE response_id = ?";
+ return RunCachedStatementWithIds(SQL_FROM_HERE, kSql, response_ids);
+}
+
+bool AppCacheDatabase::RunCachedStatementWithIds(
+ const sql::StatementID& statement_id, const char* sql,
+ const std::vector<int64>& ids) {
+ DCHECK(sql);
+ if (!LazyOpen(true))
+ return false;
+
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+
+ sql::Statement statement(db_->GetCachedStatement(statement_id, sql));
+
+ std::vector<int64>::const_iterator iter = ids.begin();
+ while (iter != ids.end()) {
+ statement.BindInt64(0, *iter);
+ if (!statement.Run())
+ return false;
+ statement.Reset(true);
+ ++iter;
+ }
+
+ return transaction.Commit();
+}
+
+bool AppCacheDatabase::RunUniqueStatementWithInt64Result(
+ const char* sql, int64* result) {
+ DCHECK(sql);
+ sql::Statement statement(db_->GetUniqueStatement(sql));
+ if (!statement.Step()) {
+ return false;
+ }
+ *result = statement.ColumnInt64(0);
+ return true;
+}
+
+bool AppCacheDatabase::FindResponseIdsForCacheHelper(
+ int64 cache_id, std::vector<int64>* ids_vector,
+ std::set<int64>* ids_set) {
+ DCHECK(ids_vector || ids_set);
+ DCHECK(!(ids_vector && ids_set));
+ if (!LazyOpen(false))
+ return false;
+
+ const char* kSql =
+ "SELECT response_id FROM Entries WHERE cache_id = ?";
+
+ sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
+
+ statement.BindInt64(0, cache_id);
+ while (statement.Step()) {
+ int64 id = statement.ColumnInt64(0);
+ if (ids_set)
+ ids_set->insert(id);
+ else
+ ids_vector->push_back(id);
+ }
+
+ return statement.Succeeded();
+}
+
+void AppCacheDatabase::ReadGroupRecord(
+ const sql::Statement& statement, GroupRecord* record) {
+ record->group_id = statement.ColumnInt64(0);
+ record->origin = GURL(statement.ColumnString(1));
+ record->manifest_url = GURL(statement.ColumnString(2));
+ record->creation_time =
+ base::Time::FromInternalValue(statement.ColumnInt64(3));
+ record->last_access_time =
+ base::Time::FromInternalValue(statement.ColumnInt64(4));
+}
+
+void AppCacheDatabase::ReadCacheRecord(
+ const sql::Statement& statement, CacheRecord* record) {
+ record->cache_id = statement.ColumnInt64(0);
+ record->group_id = statement.ColumnInt64(1);
+ record->online_wildcard = statement.ColumnBool(2);
+ record->update_time =
+ base::Time::FromInternalValue(statement.ColumnInt64(3));
+ record->cache_size = statement.ColumnInt64(4);
+}
+
+void AppCacheDatabase::ReadEntryRecord(
+ const sql::Statement& statement, EntryRecord* record) {
+ record->cache_id = statement.ColumnInt64(0);
+ record->url = GURL(statement.ColumnString(1));
+ record->flags = statement.ColumnInt(2);
+ record->response_id = statement.ColumnInt64(3);
+ record->response_size = statement.ColumnInt64(4);
+}
+
+void AppCacheDatabase::ReadNamespaceRecords(
+ sql::Statement* statement,
+ NamespaceRecordVector* intercepts,
+ NamespaceRecordVector* fallbacks) {
+ while (statement->Step()) {
+ AppCacheNamespaceType type = static_cast<AppCacheNamespaceType>(
+ statement->ColumnInt(2));
+ NamespaceRecordVector* records =
+ (type == APPCACHE_FALLBACK_NAMESPACE) ? fallbacks : intercepts;
+ records->push_back(NamespaceRecord());
+ ReadNamespaceRecord(statement, &records->back());
+ }
+}
+
+void AppCacheDatabase::ReadNamespaceRecord(
+ const sql::Statement* statement, NamespaceRecord* record) {
+ record->cache_id = statement->ColumnInt64(0);
+ record->origin = GURL(statement->ColumnString(1));
+ int type_with_executable_bit = statement->ColumnInt(2);
+ record->namespace_.namespace_url = GURL(statement->ColumnString(3));
+ record->namespace_.target_url = GURL(statement->ColumnString(4));
+ record->namespace_.is_pattern = statement->ColumnBool(5);
+
+ // Note: quick and dirty storage for the 'executable' bit w/o changing
+ // schemas, we use the high bit of 'type' field.
+ record->namespace_.type = static_cast<AppCacheNamespaceType>
+ (type_with_executable_bit & 0x7ffffff);
+ record->namespace_.is_executable =
+ (type_with_executable_bit & 0x80000000) != 0;
+ DCHECK(!record->namespace_.is_executable ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ kEnableExecutableHandlers));
+}
+
+void AppCacheDatabase::ReadOnlineWhiteListRecord(
+ const sql::Statement& statement, OnlineWhiteListRecord* record) {
+ record->cache_id = statement.ColumnInt64(0);
+ record->namespace_url = GURL(statement.ColumnString(1));
+ record->is_pattern = statement.ColumnBool(2);
+}
+
+bool AppCacheDatabase::LazyOpen(bool create_if_needed) {
+ if (db_)
+ return true;
+
+ // If we tried and failed once, don't try again in the same session
+ // to avoid creating an incoherent mess on disk.
+ if (is_disabled_)
+ return false;
+
+ // Avoid creating a database at all if we can.
+ bool use_in_memory_db = db_file_path_.empty();
+ if (!create_if_needed &&
+ (use_in_memory_db || !base::PathExists(db_file_path_))) {
+ return false;
+ }
+
+ db_.reset(new sql::Connection);
+ meta_table_.reset(new sql::MetaTable);
+
+ db_->set_histogram_tag("AppCache");
+
+ bool opened = false;
+ if (use_in_memory_db) {
+ opened = db_->OpenInMemory();
+ } else if (!base::CreateDirectory(db_file_path_.DirName())) {
+ LOG(ERROR) << "Failed to create appcache directory.";
+ } else {
+ opened = db_->Open(db_file_path_);
+ if (opened)
+ db_->Preload();
+ }
+
+ if (!opened || !db_->QuickIntegrityCheck() || !EnsureDatabaseVersion()) {
+ LOG(ERROR) << "Failed to open the appcache database.";
+ AppCacheHistograms::CountInitResult(
+ AppCacheHistograms::SQL_DATABASE_ERROR);
+
+ // We're unable to open the database. This is a fatal error
+ // which we can't recover from. We try to handle it by deleting
+ // the existing appcache data and starting with a clean slate in
+ // this browser session.
+ if (!use_in_memory_db && DeleteExistingAndCreateNewDatabase())
+ return true;
+
+ Disable();
+ return false;
+ }
+
+ AppCacheHistograms::CountInitResult(AppCacheHistograms::INIT_OK);
+ was_corruption_detected_ = false;
+ db_->set_error_callback(
+ base::Bind(&AppCacheDatabase::OnDatabaseError, base::Unretained(this)));
+ return true;
+}
+
+bool AppCacheDatabase::EnsureDatabaseVersion() {
+ if (!sql::MetaTable::DoesTableExist(db_.get()))
+ return CreateSchema();
+
+ if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion))
+ return false;
+
+ if (meta_table_->GetCompatibleVersionNumber() > kCurrentVersion) {
+ LOG(WARNING) << "AppCache database is too new.";
+ return false;
+ }
+
+ std::string stored_flags;
+ meta_table_->GetValue(kExperimentFlagsKey, &stored_flags);
+ if (stored_flags != GetActiveExperimentFlags())
+ return false;
+
+ if (meta_table_->GetVersionNumber() < kCurrentVersion)
+ return UpgradeSchema();
+
+#ifndef NDEBUG
+ DCHECK(sql::MetaTable::DoesTableExist(db_.get()));
+ for (int i = 0; i < kTableCount; ++i) {
+ DCHECK(db_->DoesTableExist(kTables[i].table_name));
+ }
+ for (int i = 0; i < kIndexCount; ++i) {
+ DCHECK(db_->DoesIndexExist(kIndexes[i].index_name));
+ }
+#endif
+
+ return true;
+}
+
+bool AppCacheDatabase::CreateSchema() {
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+
+ if (!meta_table_->Init(db_.get(), kCurrentVersion, kCompatibleVersion))
+ return false;
+
+ if (!meta_table_->SetValue(kExperimentFlagsKey,
+ GetActiveExperimentFlags())) {
+ return false;
+ }
+
+ for (int i = 0; i < kTableCount; ++i) {
+ if (!CreateTable(db_.get(), kTables[i]))
+ return false;
+ }
+
+ for (int i = 0; i < kIndexCount; ++i) {
+ if (!CreateIndex(db_.get(), kIndexes[i]))
+ return false;
+ }
+
+ return transaction.Commit();
+}
+
+bool AppCacheDatabase::UpgradeSchema() {
+#if defined(APPCACHE_USE_SIMPLE_CACHE)
+ return DeleteExistingAndCreateNewDatabase();
+#else
+ if (meta_table_->GetVersionNumber() == 3) {
+ // version 3 was pre 12/17/2011
+ DCHECK_EQ(strcmp(kNamespacesTable, kTables[3].table_name), 0);
+ DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[6].table_name), 0);
+ DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[7].table_name), 0);
+ DCHECK_EQ(strcmp(kNamespacesTable, kIndexes[8].table_name), 0);
+
+ const TableInfo kNamespaceTable_v4 = {
+ kNamespacesTable,
+ "(cache_id INTEGER,"
+ " origin TEXT," // intentionally not normalized
+ " type INTEGER,"
+ " namespace_url TEXT,"
+ " target_url TEXT)"
+ };
+
+ // Migrate from the old FallbackNameSpaces to the newer Namespaces table,
+ // but without the is_pattern column added in v5.
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin() ||
+ !CreateTable(db_.get(), kNamespaceTable_v4)) {
+ return false;
+ }
+
+ // Move data from the old table to the new table, setting the
+ // 'type' for all current records to the value for
+ // APPCACHE_FALLBACK_NAMESPACE.
+ DCHECK_EQ(0, static_cast<int>(APPCACHE_FALLBACK_NAMESPACE));
+ if (!db_->Execute(
+ "INSERT INTO Namespaces"
+ " SELECT cache_id, origin, 0, namespace_url, fallback_entry_url"
+ " FROM FallbackNameSpaces")) {
+ return false;
+ }
+
+ // Drop the old table, indexes on that table are also removed by this.
+ if (!db_->Execute("DROP TABLE FallbackNameSpaces"))
+ return false;
+
+ // Create new indexes.
+ if (!CreateIndex(db_.get(), kIndexes[6]) ||
+ !CreateIndex(db_.get(), kIndexes[7]) ||
+ !CreateIndex(db_.get(), kIndexes[8])) {
+ return false;
+ }
+
+ meta_table_->SetVersionNumber(4);
+ meta_table_->SetCompatibleVersionNumber(4);
+ if (!transaction.Commit())
+ return false;
+ }
+
+ if (meta_table_->GetVersionNumber() == 4) {
+ // version 4 pre 3/30/2013
+ // Add the is_pattern column to the Namespaces and OnlineWhitelists tables.
+ DCHECK_EQ(strcmp(kNamespacesTable, "Namespaces"), 0);
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ if (!db_->Execute(
+ "ALTER TABLE Namespaces ADD COLUMN"
+ " is_pattern INTEGER CHECK(is_pattern IN (0, 1))")) {
+ return false;
+ }
+ if (!db_->Execute(
+ "ALTER TABLE OnlineWhitelists ADD COLUMN"
+ " is_pattern INTEGER CHECK(is_pattern IN (0, 1))")) {
+ return false;
+ }
+ meta_table_->SetVersionNumber(5);
+ meta_table_->SetCompatibleVersionNumber(5);
+ return transaction.Commit();
+ }
+
+ // If there is no upgrade path for the version on disk to the current
+ // version, nuke everything and start over.
+ return DeleteExistingAndCreateNewDatabase();
+#endif
+}
+
+void AppCacheDatabase::ResetConnectionAndTables() {
+ meta_table_.reset();
+ db_.reset();
+}
+
+bool AppCacheDatabase::DeleteExistingAndCreateNewDatabase() {
+ DCHECK(!db_file_path_.empty());
+ DCHECK(base::PathExists(db_file_path_));
+ VLOG(1) << "Deleting existing appcache data and starting over.";
+
+ ResetConnectionAndTables();
+
+ // This also deletes the disk cache data.
+ base::FilePath directory = db_file_path_.DirName();
+ if (!base::DeleteFile(directory, true))
+ return false;
+
+ // Make sure the steps above actually deleted things.
+ if (base::PathExists(directory))
+ return false;
+
+ if (!base::CreateDirectory(directory))
+ return false;
+
+ // So we can't go recursive.
+ if (is_recreating_)
+ return false;
+
+ base::AutoReset<bool> auto_reset(&is_recreating_, true);
+ return LazyOpen(true);
+}
+
+void AppCacheDatabase::OnDatabaseError(int err, sql::Statement* stmt) {
+ was_corruption_detected_ |= sql::IsErrorCatastrophic(err);
+ if (!db_->ShouldIgnoreSqliteError(err))
+ DLOG(ERROR) << db_->GetErrorMessage();
+ // TODO: Maybe use non-catostrophic errors to trigger a full integrity check?
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_database.h b/chromium/content/browser/appcache/appcache_database.h
new file mode 100644
index 00000000000..ee1c52d8be3
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_database.h
@@ -0,0 +1,251 @@
+// 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_APPCACHE_APPCACHE_DATABASE_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_DATABASE_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "content/common/appcache_interfaces.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace sql {
+class Connection;
+class MetaTable;
+class Statement;
+class StatementID;
+}
+
+namespace content {
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, CacheRecords);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, EntryRecords);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, QuickIntegrityCheck);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, NamespaceRecords);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, GroupRecords);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, LazyOpen);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, ExperimentalFlags);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, OnlineWhiteListRecords);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, ReCreate);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, DeletableResponseIds);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, OriginUsage);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, UpgradeSchema3to5);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, UpgradeSchema4to5);
+FORWARD_DECLARE_TEST(AppCacheDatabaseTest, WasCorrutionDetected);
+class AppCacheDatabaseTest;
+class AppCacheStorageImplTest;
+
+class CONTENT_EXPORT AppCacheDatabase {
+ public:
+ struct CONTENT_EXPORT GroupRecord {
+ GroupRecord();
+ ~GroupRecord();
+
+ int64 group_id;
+ GURL origin;
+ GURL manifest_url;
+ base::Time creation_time;
+ base::Time last_access_time;
+ };
+
+ struct CONTENT_EXPORT CacheRecord {
+ CacheRecord()
+ : cache_id(0), group_id(0), online_wildcard(false), cache_size(0) {}
+
+ int64 cache_id;
+ int64 group_id;
+ bool online_wildcard;
+ base::Time update_time;
+ int64 cache_size; // the sum of all response sizes in this cache
+ };
+
+ struct EntryRecord {
+ EntryRecord() : cache_id(0), flags(0), response_id(0), response_size(0) {}
+
+ int64 cache_id;
+ GURL url;
+ int flags;
+ int64 response_id;
+ int64 response_size;
+ };
+
+ struct CONTENT_EXPORT NamespaceRecord {
+ NamespaceRecord();
+ ~NamespaceRecord();
+
+ int64 cache_id;
+ GURL origin;
+ AppCacheNamespace namespace_;
+ };
+
+ typedef std::vector<NamespaceRecord> NamespaceRecordVector;
+
+ struct OnlineWhiteListRecord {
+ OnlineWhiteListRecord() : cache_id(0), is_pattern(false) {}
+
+ int64 cache_id;
+ GURL namespace_url;
+ bool is_pattern;
+ };
+
+ explicit AppCacheDatabase(const base::FilePath& path);
+ ~AppCacheDatabase();
+
+ void Disable();
+ bool is_disabled() const { return is_disabled_; }
+ bool was_corruption_detected() const { return was_corruption_detected_; }
+
+ int64 GetOriginUsage(const GURL& origin);
+ bool GetAllOriginUsage(std::map<GURL, int64>* usage_map);
+
+ bool FindOriginsWithGroups(std::set<GURL>* origins);
+ bool FindLastStorageIds(
+ int64* last_group_id, int64* last_cache_id, int64* last_response_id,
+ int64* last_deletable_response_rowid);
+
+ bool FindGroup(int64 group_id, GroupRecord* record);
+ bool FindGroupForManifestUrl(const GURL& manifest_url, GroupRecord* record);
+ bool FindGroupsForOrigin(
+ const GURL& origin, std::vector<GroupRecord>* records);
+ bool FindGroupForCache(int64 cache_id, GroupRecord* record);
+ bool UpdateGroupLastAccessTime(
+ int64 group_id, base::Time last_access_time);
+ bool InsertGroup(const GroupRecord* record);
+ bool DeleteGroup(int64 group_id);
+
+ bool FindCache(int64 cache_id, CacheRecord* record);
+ bool FindCacheForGroup(int64 group_id, CacheRecord* record);
+ bool FindCachesForOrigin(
+ const GURL& origin, std::vector<CacheRecord>* records);
+ bool InsertCache(const CacheRecord* record);
+ bool DeleteCache(int64 cache_id);
+
+ bool FindEntriesForCache(
+ int64 cache_id, std::vector<EntryRecord>* records);
+ bool FindEntriesForUrl(
+ const GURL& url, std::vector<EntryRecord>* records);
+ bool FindEntry(int64 cache_id, const GURL& url, EntryRecord* record);
+ bool InsertEntry(const EntryRecord* record);
+ bool InsertEntryRecords(
+ const std::vector<EntryRecord>& records);
+ bool DeleteEntriesForCache(int64 cache_id);
+ bool AddEntryFlags(const GURL& entry_url, int64 cache_id,
+ int additional_flags);
+ bool FindResponseIdsForCacheAsVector(
+ int64 cache_id, std::vector<int64>* response_ids) {
+ return FindResponseIdsForCacheHelper(cache_id, response_ids, NULL);
+ }
+ bool FindResponseIdsForCacheAsSet(
+ int64 cache_id, std::set<int64>* response_ids) {
+ return FindResponseIdsForCacheHelper(cache_id, NULL, response_ids);
+ }
+
+ bool FindNamespacesForOrigin(
+ const GURL& origin,
+ NamespaceRecordVector* intercepts,
+ NamespaceRecordVector* fallbacks);
+ bool FindNamespacesForCache(
+ int64 cache_id,
+ NamespaceRecordVector* intercepts,
+ std::vector<NamespaceRecord>* fallbacks);
+ bool InsertNamespaceRecords(
+ const NamespaceRecordVector& records);
+ bool InsertNamespace(const NamespaceRecord* record);
+ bool DeleteNamespacesForCache(int64 cache_id);
+
+ bool FindOnlineWhiteListForCache(
+ int64 cache_id, std::vector<OnlineWhiteListRecord>* records);
+ bool InsertOnlineWhiteList(const OnlineWhiteListRecord* record);
+ bool InsertOnlineWhiteListRecords(
+ const std::vector<OnlineWhiteListRecord>& records);
+ bool DeleteOnlineWhiteListForCache(int64 cache_id);
+
+ bool GetDeletableResponseIds(std::vector<int64>* response_ids,
+ int64 max_rowid, int limit);
+ bool InsertDeletableResponseIds(const std::vector<int64>& response_ids);
+ bool DeleteDeletableResponseIds(const std::vector<int64>& response_ids);
+
+ // So our callers can wrap operations in transactions.
+ sql::Connection* db_connection() {
+ LazyOpen(true);
+ return db_.get();
+ }
+
+ private:
+ bool RunCachedStatementWithIds(
+ const sql::StatementID& statement_id, const char* sql,
+ const std::vector<int64>& ids);
+ bool RunUniqueStatementWithInt64Result(const char* sql, int64* result);
+
+ bool FindResponseIdsForCacheHelper(
+ int64 cache_id, std::vector<int64>* ids_vector,
+ std::set<int64>* ids_set);
+
+ // Record retrieval helpers
+ void ReadGroupRecord(const sql::Statement& statement, GroupRecord* record);
+ void ReadCacheRecord(const sql::Statement& statement, CacheRecord* record);
+ void ReadEntryRecord(const sql::Statement& statement, EntryRecord* record);
+ void ReadNamespaceRecords(
+ sql::Statement* statement,
+ NamespaceRecordVector* intercepts,
+ NamespaceRecordVector* fallbacks);
+ void ReadNamespaceRecord(
+ const sql::Statement* statement, NamespaceRecord* record);
+ void ReadOnlineWhiteListRecord(
+ const sql::Statement& statement, OnlineWhiteListRecord* record);
+
+ // Database creation
+ bool LazyOpen(bool create_if_needed);
+ bool EnsureDatabaseVersion();
+ bool CreateSchema();
+ bool UpgradeSchema();
+
+ void ResetConnectionAndTables();
+
+ // Deletes the existing database file and the entire directory containing
+ // the database file including the disk cache in which response headers
+ // and bodies are stored, and then creates a new database file.
+ bool DeleteExistingAndCreateNewDatabase();
+
+ void OnDatabaseError(int err, sql::Statement* stmt);
+
+ base::FilePath db_file_path_;
+ scoped_ptr<sql::Connection> db_;
+ scoped_ptr<sql::MetaTable> meta_table_;
+ bool is_disabled_;
+ bool is_recreating_;
+ bool was_corruption_detected_;
+
+ friend class content::AppCacheDatabaseTest;
+ friend class content::AppCacheStorageImplTest;
+
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, CacheRecords);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, EntryRecords);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, QuickIntegrityCheck);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, NamespaceRecords);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, GroupRecords);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, LazyOpen);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, ExperimentalFlags);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest,
+ OnlineWhiteListRecords);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, ReCreate);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, DeletableResponseIds);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, OriginUsage);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, UpgradeSchema3to5);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, UpgradeSchema4to5);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, WasCorrutionDetected);
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheDatabase);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_DATABASE_H_
diff --git a/chromium/content/browser/appcache/appcache_database_unittest.cc b/chromium/content/browser/appcache/appcache_database_unittest.cc
index 92fa6a57d91..11aa683c87a 100644
--- a/chromium/content/browser/appcache/appcache_database_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_database_unittest.cc
@@ -3,9 +3,11 @@
// found in the LICENSE file.
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/stringprintf.h"
+#include "content/browser/appcache/appcache_database.h"
+#include "content/browser/appcache/appcache_entry.h"
#include "sql/connection.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
@@ -14,14 +16,6 @@
#include "sql/transaction.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h"
-#include "webkit/browser/appcache/appcache_database.h"
-#include "webkit/browser/appcache/appcache_entry.h"
-
-using appcache::AppCacheDatabase;
-using appcache::AppCacheEntry;
-using appcache::APPCACHE_FALLBACK_NAMESPACE;
-using appcache::APPCACHE_INTERCEPT_NAMESPACE;
-using appcache::APPCACHE_NETWORK_NAMESPACE;
namespace {
@@ -873,8 +867,8 @@ TEST(AppCacheDatabaseTest, UpgradeSchema3to5) {
true },
};
- const int kTableCount3 = ARRAYSIZE_UNSAFE(kTables3);
- const int kIndexCount3 = ARRAYSIZE_UNSAFE(kIndexes3);
+ const int kTableCount3 = arraysize(kTables3);
+ const int kIndexCount3 = arraysize(kIndexes3);
sql::Connection connection;
EXPECT_TRUE(connection.Open(kDbFile));
@@ -1103,8 +1097,8 @@ TEST(AppCacheDatabaseTest, UpgradeSchema4to5) {
true },
};
- const int kTableCount4 = ARRAYSIZE_UNSAFE(kTables4);
- const int kIndexCount4 = ARRAYSIZE_UNSAFE(kIndexes4);
+ const int kTableCount4 = arraysize(kTables4);
+ const int kIndexCount4 = arraysize(kIndexes4);
sql::Connection connection;
EXPECT_TRUE(connection.Open(kDbFile));
diff --git a/chromium/content/browser/appcache/appcache_disk_cache.cc b/chromium/content/browser/appcache/appcache_disk_cache.cc
new file mode 100644
index 00000000000..382ed45fed2
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_disk_cache.cc
@@ -0,0 +1,372 @@
+// 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/appcache/appcache_disk_cache.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/base/cache_type.h"
+#include "net/base/net_errors.h"
+
+namespace content {
+
+// A callback shim that provides storage for the 'backend_ptr' value
+// and will delete a resulting ptr if completion occurs after its
+// been canceled.
+class AppCacheDiskCache::CreateBackendCallbackShim
+ : public base::RefCounted<CreateBackendCallbackShim> {
+ public:
+ explicit CreateBackendCallbackShim(AppCacheDiskCache* object)
+ : appcache_diskcache_(object) {
+ }
+
+ void Cancel() {
+ appcache_diskcache_ = NULL;
+ }
+
+ void Callback(int rv) {
+ if (appcache_diskcache_)
+ appcache_diskcache_->OnCreateBackendComplete(rv);
+ }
+
+ scoped_ptr<disk_cache::Backend> backend_ptr_; // Accessed directly.
+
+ private:
+ friend class base::RefCounted<CreateBackendCallbackShim>;
+
+ ~CreateBackendCallbackShim() {
+ }
+
+ AppCacheDiskCache* appcache_diskcache_; // Unowned pointer.
+};
+
+// An implementation of AppCacheDiskCacheInterface::Entry that's a thin
+// wrapper around disk_cache::Entry.
+class AppCacheDiskCache::EntryImpl : public Entry {
+ public:
+ EntryImpl(disk_cache::Entry* disk_cache_entry,
+ AppCacheDiskCache* owner)
+ : disk_cache_entry_(disk_cache_entry), owner_(owner) {
+ DCHECK(disk_cache_entry);
+ DCHECK(owner);
+ owner_->AddOpenEntry(this);
+ }
+
+ // Entry implementation.
+ int Read(int index,
+ int64 offset,
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) override {
+ if (offset < 0 || offset > kint32max)
+ return net::ERR_INVALID_ARGUMENT;
+ if (!disk_cache_entry_)
+ return net::ERR_ABORTED;
+ return disk_cache_entry_->ReadData(
+ index, static_cast<int>(offset), buf, buf_len, callback);
+ }
+
+ int Write(int index,
+ int64 offset,
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) override {
+ if (offset < 0 || offset > kint32max)
+ return net::ERR_INVALID_ARGUMENT;
+ if (!disk_cache_entry_)
+ return net::ERR_ABORTED;
+ const bool kTruncate = true;
+ return disk_cache_entry_->WriteData(
+ index, static_cast<int>(offset), buf, buf_len, callback, kTruncate);
+ }
+
+ int64 GetSize(int index) override {
+ return disk_cache_entry_ ? disk_cache_entry_->GetDataSize(index) : 0L;
+ }
+
+ void Close() override {
+ if (disk_cache_entry_)
+ disk_cache_entry_->Close();
+ delete this;
+ }
+
+ void Abandon() {
+ owner_ = NULL;
+ disk_cache_entry_->Close();
+ disk_cache_entry_ = NULL;
+ }
+
+ private:
+ ~EntryImpl() override {
+ if (owner_)
+ owner_->RemoveOpenEntry(this);
+ }
+
+ disk_cache::Entry* disk_cache_entry_;
+ AppCacheDiskCache* owner_;
+};
+
+// Separate object to hold state for each Create, Delete, or Doom call
+// while the call is in-flight and to produce an EntryImpl upon completion.
+class AppCacheDiskCache::ActiveCall {
+ public:
+ explicit ActiveCall(AppCacheDiskCache* owner)
+ : entry_(NULL),
+ owner_(owner),
+ entry_ptr_(NULL) {
+ }
+
+ int CreateEntry(int64 key, Entry** entry,
+ const net::CompletionCallback& callback) {
+ int rv = owner_->disk_cache()->CreateEntry(
+ base::Int64ToString(key), &entry_ptr_,
+ base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
+ return HandleImmediateReturnValue(rv, entry, callback);
+ }
+
+ int OpenEntry(int64 key, Entry** entry,
+ const net::CompletionCallback& callback) {
+ int rv = owner_->disk_cache()->OpenEntry(
+ base::Int64ToString(key), &entry_ptr_,
+ base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
+ return HandleImmediateReturnValue(rv, entry, callback);
+ }
+
+ int DoomEntry(int64 key, const net::CompletionCallback& callback) {
+ int rv = owner_->disk_cache()->DoomEntry(
+ base::Int64ToString(key),
+ base::Bind(&ActiveCall::OnAsyncCompletion, base::Unretained(this)));
+ return HandleImmediateReturnValue(rv, NULL, callback);
+ }
+
+ private:
+ int HandleImmediateReturnValue(int rv, Entry** entry,
+ const net::CompletionCallback& callback) {
+ if (rv == net::ERR_IO_PENDING) {
+ // OnAsyncCompletion will be called later.
+ callback_ = callback;
+ entry_ = entry;
+ owner_->AddActiveCall(this);
+ return net::ERR_IO_PENDING;
+ }
+ if (rv == net::OK && entry)
+ *entry = new EntryImpl(entry_ptr_, owner_);
+ delete this;
+ return rv;
+ }
+
+ void OnAsyncCompletion(int rv) {
+ owner_->RemoveActiveCall(this);
+ if (rv == net::OK && entry_)
+ *entry_ = new EntryImpl(entry_ptr_, owner_);
+ callback_.Run(rv);
+ callback_.Reset();
+ delete this;
+ }
+
+ Entry** entry_;
+ net::CompletionCallback callback_;
+ AppCacheDiskCache* owner_;
+ disk_cache::Entry* entry_ptr_;
+};
+
+AppCacheDiskCache::AppCacheDiskCache()
+ : is_disabled_(false) {
+}
+
+AppCacheDiskCache::~AppCacheDiskCache() {
+ Disable();
+}
+
+int AppCacheDiskCache::InitWithDiskBackend(
+ const base::FilePath& disk_cache_directory,
+ int disk_cache_size,
+ bool force,
+ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
+ const net::CompletionCallback& callback) {
+ return Init(net::APP_CACHE,
+ disk_cache_directory,
+ disk_cache_size,
+ force,
+ cache_thread,
+ callback);
+}
+
+int AppCacheDiskCache::InitWithMemBackend(
+ int mem_cache_size, const net::CompletionCallback& callback) {
+ return Init(net::MEMORY_CACHE, base::FilePath(), mem_cache_size, false, NULL,
+ callback);
+}
+
+void AppCacheDiskCache::Disable() {
+ if (is_disabled_)
+ return;
+
+ is_disabled_ = true;
+
+ if (create_backend_callback_.get()) {
+ create_backend_callback_->Cancel();
+ create_backend_callback_ = NULL;
+ OnCreateBackendComplete(net::ERR_ABORTED);
+ }
+
+ // We need to close open file handles in order to reinitalize the
+ // appcache system on the fly. File handles held in both entries and in
+ // the main disk_cache::Backend class need to be released.
+ for (OpenEntries::const_iterator iter = open_entries_.begin();
+ iter != open_entries_.end(); ++iter) {
+ (*iter)->Abandon();
+ }
+ open_entries_.clear();
+ disk_cache_.reset();
+ STLDeleteElements(&active_calls_);
+}
+
+int AppCacheDiskCache::CreateEntry(int64 key, Entry** entry,
+ const net::CompletionCallback& callback) {
+ DCHECK(entry);
+ DCHECK(!callback.is_null());
+ if (is_disabled_)
+ return net::ERR_ABORTED;
+
+ if (is_initializing()) {
+ pending_calls_.push_back(PendingCall(CREATE, key, entry, callback));
+ return net::ERR_IO_PENDING;
+ }
+
+ if (!disk_cache_)
+ return net::ERR_FAILED;
+
+ return (new ActiveCall(this))->CreateEntry(key, entry, callback);
+}
+
+int AppCacheDiskCache::OpenEntry(int64 key, Entry** entry,
+ const net::CompletionCallback& callback) {
+ DCHECK(entry);
+ DCHECK(!callback.is_null());
+ if (is_disabled_)
+ return net::ERR_ABORTED;
+
+ if (is_initializing()) {
+ pending_calls_.push_back(PendingCall(OPEN, key, entry, callback));
+ return net::ERR_IO_PENDING;
+ }
+
+ if (!disk_cache_)
+ return net::ERR_FAILED;
+
+ return (new ActiveCall(this))->OpenEntry(key, entry, callback);
+}
+
+int AppCacheDiskCache::DoomEntry(int64 key,
+ const net::CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+ if (is_disabled_)
+ return net::ERR_ABORTED;
+
+ if (is_initializing()) {
+ pending_calls_.push_back(PendingCall(DOOM, key, NULL, callback));
+ return net::ERR_IO_PENDING;
+ }
+
+ if (!disk_cache_)
+ return net::ERR_FAILED;
+
+ return (new ActiveCall(this))->DoomEntry(key, callback);
+}
+
+AppCacheDiskCache::PendingCall::PendingCall()
+ : call_type(CREATE),
+ key(0),
+ entry(NULL) {
+}
+
+AppCacheDiskCache::PendingCall::PendingCall(PendingCallType call_type,
+ int64 key,
+ Entry** entry,
+ const net::CompletionCallback& callback)
+ : call_type(call_type),
+ key(key),
+ entry(entry),
+ callback(callback) {
+}
+
+AppCacheDiskCache::PendingCall::~PendingCall() {}
+
+int AppCacheDiskCache::Init(
+ net::CacheType cache_type,
+ const base::FilePath& cache_directory,
+ int cache_size,
+ bool force,
+ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
+ const net::CompletionCallback& callback) {
+ DCHECK(!is_initializing() && !disk_cache_.get());
+ is_disabled_ = false;
+ create_backend_callback_ = new CreateBackendCallbackShim(this);
+
+#if defined(APPCACHE_USE_SIMPLE_CACHE)
+ const net::BackendType backend_type = net::CACHE_BACKEND_SIMPLE;
+#else
+ const net::BackendType backend_type = net::CACHE_BACKEND_DEFAULT;
+#endif
+ int rv = disk_cache::CreateCacheBackend(
+ cache_type,
+ backend_type,
+ cache_directory,
+ cache_size,
+ force,
+ cache_thread,
+ NULL,
+ &(create_backend_callback_->backend_ptr_),
+ base::Bind(&CreateBackendCallbackShim::Callback,
+ create_backend_callback_));
+ if (rv == net::ERR_IO_PENDING)
+ init_callback_ = callback;
+ else
+ OnCreateBackendComplete(rv);
+ return rv;
+}
+
+void AppCacheDiskCache::OnCreateBackendComplete(int rv) {
+ if (rv == net::OK) {
+ disk_cache_ = create_backend_callback_->backend_ptr_.Pass();
+ }
+ create_backend_callback_ = NULL;
+
+ // Invoke our clients callback function.
+ if (!init_callback_.is_null()) {
+ init_callback_.Run(rv);
+ init_callback_.Reset();
+ }
+
+ // Service pending calls that were queued up while we were initializing.
+ for (PendingCalls::const_iterator iter = pending_calls_.begin();
+ iter < pending_calls_.end(); ++iter) {
+ int rv = net::ERR_FAILED;
+ switch (iter->call_type) {
+ case CREATE:
+ rv = CreateEntry(iter->key, iter->entry, iter->callback);
+ break;
+ case OPEN:
+ rv = OpenEntry(iter->key, iter->entry, iter->callback);
+ break;
+ case DOOM:
+ rv = DoomEntry(iter->key, iter->callback);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ if (rv != net::ERR_IO_PENDING)
+ iter->callback.Run(rv);
+ }
+ pending_calls_.clear();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_disk_cache.h b/chromium/content/browser/appcache/appcache_disk_cache.h
new file mode 100644
index 00000000000..8995e83cf71
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_disk_cache.h
@@ -0,0 +1,115 @@
+// 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_APPCACHE_APPCACHE_DISK_CACHE_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_DISK_CACHE_H_
+
+#include <set>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/common/content_export.h"
+#include "net/disk_cache/disk_cache.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace content {
+
+// An implementation of AppCacheDiskCacheInterface that
+// uses net::DiskCache as the backing store.
+class CONTENT_EXPORT AppCacheDiskCache
+ : public AppCacheDiskCacheInterface {
+ public:
+ AppCacheDiskCache();
+ ~AppCacheDiskCache() override;
+
+ // Initializes the object to use disk backed storage.
+ int InitWithDiskBackend(
+ const base::FilePath& disk_cache_directory,
+ int disk_cache_size,
+ bool force,
+ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
+ const net::CompletionCallback& callback);
+
+ // Initializes the object to use memory only storage.
+ // This is used for Chrome's incognito browsing.
+ int InitWithMemBackend(int disk_cache_size,
+ const net::CompletionCallback& callback);
+
+ void Disable();
+ bool is_disabled() const { return is_disabled_; }
+
+ int CreateEntry(int64 key,
+ Entry** entry,
+ const net::CompletionCallback& callback) override;
+ int OpenEntry(int64 key,
+ Entry** entry,
+ const net::CompletionCallback& callback) override;
+ int DoomEntry(int64 key, const net::CompletionCallback& callback) override;
+
+ private:
+ class CreateBackendCallbackShim;
+ class EntryImpl;
+
+ // PendingCalls allow CreateEntry, OpenEntry, and DoomEntry to be called
+ // immediately after construction, without waiting for the
+ // underlying disk_cache::Backend to be fully constructed. Early
+ // calls are queued up and serviced once the disk_cache::Backend is
+ // really ready to go.
+ enum PendingCallType {
+ CREATE,
+ OPEN,
+ DOOM
+ };
+ struct PendingCall {
+ PendingCallType call_type;
+ int64 key;
+ Entry** entry;
+ net::CompletionCallback callback;
+
+ PendingCall();
+
+ PendingCall(PendingCallType call_type, int64 key,
+ Entry** entry, const net::CompletionCallback& callback);
+
+ ~PendingCall();
+ };
+ typedef std::vector<PendingCall> PendingCalls;
+
+ class ActiveCall;
+ typedef std::set<ActiveCall*> ActiveCalls;
+ typedef std::set<EntryImpl*> OpenEntries;
+
+ bool is_initializing() const {
+ return create_backend_callback_.get() != NULL;
+ }
+ disk_cache::Backend* disk_cache() { return disk_cache_.get(); }
+ int Init(net::CacheType cache_type,
+ const base::FilePath& directory,
+ int cache_size,
+ bool force,
+ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread,
+ const net::CompletionCallback& callback);
+ void OnCreateBackendComplete(int rv);
+ void AddActiveCall(ActiveCall* call) { active_calls_.insert(call); }
+ void RemoveActiveCall(ActiveCall* call) { active_calls_.erase(call); }
+ void AddOpenEntry(EntryImpl* entry) { open_entries_.insert(entry); }
+ void RemoveOpenEntry(EntryImpl* entry) { open_entries_.erase(entry); }
+
+ bool is_disabled_;
+ net::CompletionCallback init_callback_;
+ scoped_refptr<CreateBackendCallbackShim> create_backend_callback_;
+ PendingCalls pending_calls_;
+ ActiveCalls active_calls_;
+ OpenEntries open_entries_;
+ scoped_ptr<disk_cache::Backend> disk_cache_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_DISK_CACHE_H_
diff --git a/chromium/content/browser/appcache/appcache_disk_cache_unittest.cc b/chromium/content/browser/appcache/appcache_disk_cache_unittest.cc
index 5e1e083ebdc..b9c67cf9a97 100644
--- a/chromium/content/browser/appcache/appcache_disk_cache_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_disk_cache_unittest.cc
@@ -3,16 +3,15 @@
// found in the LICENSE file.
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/browser/appcache/appcache_disk_cache.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache_disk_cache.h"
-
-using appcache::AppCacheDiskCache;
namespace content {
@@ -20,17 +19,17 @@ class AppCacheDiskCacheTest : public testing::Test {
public:
AppCacheDiskCacheTest() {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
// Use the current thread for the DiskCache's cache_thread.
message_loop_.reset(new base::MessageLoopForIO());
- cache_thread_ = base::MessageLoopProxy::current();
+ cache_thread_ = base::ThreadTaskRunnerHandle::Get();
ASSERT_TRUE(directory_.CreateUniqueTempDir());
completion_callback_ = base::Bind(
&AppCacheDiskCacheTest::OnComplete,
base::Unretained(this));
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
base::RunLoop().RunUntilIdle();
message_loop_.reset(NULL);
}
@@ -45,7 +44,7 @@ class AppCacheDiskCacheTest : public testing::Test {
base::ScopedTempDir directory_;
scoped_ptr<base::MessageLoop> message_loop_;
- scoped_refptr<base::MessageLoopProxy> cache_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> cache_thread_;
net::CompletionCallback completion_callback_;
std::vector<int> completion_results_;
@@ -60,8 +59,7 @@ TEST_F(AppCacheDiskCacheTest, DisablePriorToInitCompletion) {
scoped_ptr<AppCacheDiskCache> disk_cache(new AppCacheDiskCache);
EXPECT_FALSE(disk_cache->is_disabled());
disk_cache->InitWithDiskBackend(
- directory_.path(), k10MBytes, false, cache_thread_,
- completion_callback_);
+ directory_.path(), k10MBytes, false, cache_thread_, completion_callback_);
disk_cache->CreateEntry(1, &entry, completion_callback_);
disk_cache->OpenEntry(2, &entry, completion_callback_);
disk_cache->DoomEntry(3, completion_callback_);
@@ -92,8 +90,7 @@ TEST_F(AppCacheDiskCacheTest, DisableAfterInitted) {
scoped_ptr<AppCacheDiskCache> disk_cache(new AppCacheDiskCache);
EXPECT_FALSE(disk_cache->is_disabled());
disk_cache->InitWithDiskBackend(
- directory_.path(), k10MBytes, false, cache_thread_,
- completion_callback_);
+ directory_.path(), k10MBytes, false, cache_thread_, completion_callback_);
FlushCacheTasks();
EXPECT_EQ(1u, completion_results_.size());
EXPECT_EQ(net::OK, completion_results_[0]);
@@ -128,8 +125,7 @@ TEST_F(AppCacheDiskCacheTest, DISABLED_DisableWithEntriesOpen) {
scoped_ptr<AppCacheDiskCache> disk_cache(new AppCacheDiskCache);
EXPECT_FALSE(disk_cache->is_disabled());
disk_cache->InitWithDiskBackend(
- directory_.path(), k10MBytes, false, cache_thread_,
- completion_callback_);
+ directory_.path(), k10MBytes, false, cache_thread_, completion_callback_);
FlushCacheTasks();
EXPECT_EQ(1u, completion_results_.size());
EXPECT_EQ(net::OK, completion_results_[0]);
@@ -155,7 +151,7 @@ TEST_F(AppCacheDiskCacheTest, DISABLED_DisableWithEntriesOpen) {
const char* kData = "Hello";
const int kDataLen = strlen(kData) + 1;
scoped_refptr<net::IOBuffer> write_buf(new net::WrappedIOBuffer(kData));
- entry1->Write(0, 0, write_buf, kDataLen, completion_callback_);
+ entry1->Write(0, 0, write_buf.get(), kDataLen, completion_callback_);
FlushCacheTasks();
// Queue up a read and a write.
diff --git a/chromium/content/browser/appcache/appcache_dispatcher_host.cc b/chromium/content/browser/appcache/appcache_dispatcher_host.cc
index 64e46b188a5..eac1effaf97 100644
--- a/chromium/content/browser/appcache/appcache_dispatcher_host.cc
+++ b/chromium/content/browser/appcache/appcache_dispatcher_host.cc
@@ -103,7 +103,7 @@ void AppCacheDispatcherHost::OnSelectCache(
BadMessageReceived();
}
} else {
- frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
+ frontend_proxy_.OnCacheSelected(host_id, AppCacheInfo());
}
}
@@ -115,7 +115,7 @@ void AppCacheDispatcherHost::OnSelectCacheForWorker(
BadMessageReceived();
}
} else {
- frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
+ frontend_proxy_.OnCacheSelected(host_id, AppCacheInfo());
}
}
@@ -125,7 +125,7 @@ void AppCacheDispatcherHost::OnSelectCacheForSharedWorker(
if (!backend_impl_.SelectCacheForSharedWorker(host_id, appcache_id))
BadMessageReceived();
} else {
- frontend_proxy_.OnCacheSelected(host_id, appcache::AppCacheInfo());
+ frontend_proxy_.OnCacheSelected(host_id, AppCacheInfo());
}
}
@@ -141,7 +141,7 @@ void AppCacheDispatcherHost::OnMarkAsForeignEntry(
}
void AppCacheDispatcherHost::OnGetResourceList(
- int host_id, std::vector<appcache::AppCacheResourceInfo>* params) {
+ int host_id, std::vector<AppCacheResourceInfo>* params) {
if (appcache_service_.get())
backend_impl_.GetResourceList(host_id, params);
}
@@ -162,7 +162,7 @@ void AppCacheDispatcherHost::OnGetStatus(int host_id, IPC::Message* reply_msg) {
return;
}
- GetStatusCallback(appcache::APPCACHE_STATUS_UNCACHED, reply_msg);
+ GetStatusCallback(APPCACHE_STATUS_UNCACHED, reply_msg);
}
void AppCacheDispatcherHost::OnStartUpdate(int host_id,
@@ -205,7 +205,7 @@ void AppCacheDispatcherHost::OnSwapCache(int host_id, IPC::Message* reply_msg) {
}
void AppCacheDispatcherHost::GetStatusCallback(
- appcache::AppCacheStatus status, void* param) {
+ AppCacheStatus status, void* param) {
IPC::Message* reply_msg = reinterpret_cast<IPC::Message*>(param);
DCHECK_EQ(pending_reply_msg_.get(), reply_msg);
AppCacheHostMsg_GetStatus::WriteReplyParams(reply_msg, status);
diff --git a/chromium/content/browser/appcache/appcache_dispatcher_host.h b/chromium/content/browser/appcache/appcache_dispatcher_host.h
index 8bad796d29e..c0a615ed259 100644
--- a/chromium/content/browser/appcache/appcache_dispatcher_host.h
+++ b/chromium/content/browser/appcache/appcache_dispatcher_host.h
@@ -10,9 +10,9 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
+#include "content/browser/appcache/appcache_backend_impl.h"
#include "content/browser/appcache/appcache_frontend_proxy.h"
#include "content/public/browser/browser_message_filter.h"
-#include "webkit/browser/appcache/appcache_backend_impl.h"
namespace content {
class ChromeAppCacheService;
@@ -27,14 +27,14 @@ class AppCacheDispatcherHost : public BrowserMessageFilter {
int process_id);
// BrowserIOMessageFilter implementation
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelConnected(int32 peer_pid) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
protected:
- virtual ~AppCacheDispatcherHost();
+ ~AppCacheDispatcherHost() override;
// BrowserMessageFilter override.
- virtual void BadMessageReceived() OVERRIDE;
+ void BadMessageReceived() override;
private:
// IPC message handlers
@@ -54,19 +54,19 @@ class AppCacheDispatcherHost : public BrowserMessageFilter {
void OnSwapCache(int host_id, IPC::Message* reply_msg);
void OnGetResourceList(
int host_id,
- std::vector<appcache::AppCacheResourceInfo>* resource_infos);
- void GetStatusCallback(appcache::AppCacheStatus status, void* param);
+ std::vector<AppCacheResourceInfo>* resource_infos);
+ void GetStatusCallback(AppCacheStatus status, void* param);
void StartUpdateCallback(bool result, void* param);
void SwapCacheCallback(bool result, void* param);
scoped_refptr<ChromeAppCacheService> appcache_service_;
AppCacheFrontendProxy frontend_proxy_;
- appcache::AppCacheBackendImpl backend_impl_;
+ AppCacheBackendImpl backend_impl_;
- appcache::GetStatusCallback get_status_callback_;
- appcache::StartUpdateCallback start_update_callback_;
- appcache::SwapCacheCallback swap_cache_callback_;
+ content::GetStatusCallback get_status_callback_;
+ content::StartUpdateCallback start_update_callback_;
+ content::SwapCacheCallback swap_cache_callback_;
scoped_ptr<IPC::Message> pending_reply_msg_;
// The corresponding ChildProcessHost object's id().
diff --git a/chromium/content/browser/appcache/appcache_entry.h b/chromium/content/browser/appcache/appcache_entry.h
new file mode 100644
index 00000000000..5c4fffd2ff5
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_entry.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2009 The Chromium Authors. 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_APPCACHE_APPCACHE_ENTRY_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_ENTRY_H_
+
+#include "content/common/appcache_interfaces.h"
+
+namespace content {
+
+// A cached entry is identified by a URL and is classified into one
+// (or more) categories. URL is not stored here as this class is stored
+// with the URL as a map key or the user of this class already knows the URL.
+class AppCacheEntry {
+ public:
+
+ // An entry can be of more than one type so use a bitmask.
+ // Note: These bit values are stored on disk.
+ enum Type {
+ MASTER = 1 << 0,
+ MANIFEST = 1 << 1,
+ EXPLICIT = 1 << 2,
+ FOREIGN = 1 << 3,
+ FALLBACK = 1 << 4,
+ INTERCEPT = 1 << 5,
+ EXECUTABLE = 1 << 6,
+ };
+
+ AppCacheEntry()
+ : types_(0), response_id_(kAppCacheNoResponseId), response_size_(0) {}
+
+ explicit AppCacheEntry(int type)
+ : types_(type), response_id_(kAppCacheNoResponseId), response_size_(0) {}
+
+ AppCacheEntry(int type, int64 response_id)
+ : types_(type), response_id_(response_id), response_size_(0) {}
+
+ AppCacheEntry(int type, int64 response_id, int64 response_size)
+ : types_(type), response_id_(response_id), response_size_(response_size) {}
+
+ int types() const { return types_; }
+ void add_types(int added_types) { types_ |= added_types; }
+ bool IsMaster() const { return (types_ & MASTER) != 0; }
+ bool IsManifest() const { return (types_ & MANIFEST) != 0; }
+ bool IsExplicit() const { return (types_ & EXPLICIT) != 0; }
+ bool IsForeign() const { return (types_ & FOREIGN) != 0; }
+ bool IsFallback() const { return (types_ & FALLBACK) != 0; }
+ bool IsIntercept() const { return (types_ & INTERCEPT) != 0; }
+ bool IsExecutable() const { return (types_ & EXECUTABLE) != 0; }
+
+ int64 response_id() const { return response_id_; }
+ void set_response_id(int64 id) { response_id_ = id; }
+ bool has_response_id() const { return response_id_ != kAppCacheNoResponseId; }
+
+ int64 response_size() const { return response_size_; }
+ void set_response_size(int64 size) { response_size_ = size; }
+
+ private:
+ int types_;
+ int64 response_id_;
+ int64 response_size_;
+};
+
+} // namespace content
+
+#endif // WEBKIT_APPCACHE_APPCACHE_RESOURCE_H_
diff --git a/chromium/content/browser/appcache/appcache_executable_handler.h b/chromium/content/browser/appcache/appcache_executable_handler.h
new file mode 100644
index 00000000000..445a6cd12a3
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_executable_handler.h
@@ -0,0 +1,54 @@
+// 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_APPCACHE_APPCACHE_EXECUTABLE_HANDLER_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_EXECUTABLE_HANDLER_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace net {
+class IOBuffer;
+class URLRequest;
+}
+
+namespace content {
+
+// An interface that must be provided by the embedder to support this feature.
+class CONTENT_EXPORT AppCacheExecutableHandler {
+ public:
+ // A handler can respond in one of 4 ways, if each of the GURL fields
+ // in 'Response' are empty and use_network is false, an error response is
+ // synthesized.
+ struct Response {
+ GURL cached_resource_url;
+ GURL redirect_url;
+ bool use_network;
+ // TODO: blob + headers would be a good one to provide as well, as it would
+ // make templating possible.
+ };
+ typedef base::Callback<void(const Response&)> ResponseCallback;
+
+ // Deletion of the handler cancels all pending callbacks.
+ virtual ~AppCacheExecutableHandler() {}
+
+ virtual void HandleRequest(net::URLRequest* req,
+ ResponseCallback callback) = 0;
+};
+
+// A factory to produce instances.
+class CONTENT_EXPORT AppCacheExecutableHandlerFactory {
+ public:
+ virtual scoped_ptr<AppCacheExecutableHandler> CreateHandler(
+ const GURL& handler_url, net::IOBuffer* handler_source) = 0;
+
+ protected:
+ virtual ~AppCacheExecutableHandlerFactory() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_EXECUTABLE_HANDLER_H_
diff --git a/chromium/content/browser/appcache/appcache_frontend_proxy.cc b/chromium/content/browser/appcache/appcache_frontend_proxy.cc
index ea693e9d71e..4242304acb0 100644
--- a/chromium/content/browser/appcache/appcache_frontend_proxy.cc
+++ b/chromium/content/browser/appcache/appcache_frontend_proxy.cc
@@ -13,18 +13,18 @@ AppCacheFrontendProxy::AppCacheFrontendProxy(IPC::Sender* sender)
}
void AppCacheFrontendProxy::OnCacheSelected(
- int host_id, const appcache::AppCacheInfo& info) {
+ int host_id, const AppCacheInfo& info) {
sender_->Send(new AppCacheMsg_CacheSelected(host_id, info));
}
void AppCacheFrontendProxy::OnStatusChanged(const std::vector<int>& host_ids,
- appcache::AppCacheStatus status) {
+ AppCacheStatus status) {
sender_->Send(new AppCacheMsg_StatusChanged(host_ids, status));
}
void AppCacheFrontendProxy::OnEventRaised(const std::vector<int>& host_ids,
- appcache::AppCacheEventID event_id) {
- DCHECK_NE(appcache::APPCACHE_PROGRESS_EVENT,
+ AppCacheEventID event_id) {
+ DCHECK_NE(APPCACHE_PROGRESS_EVENT,
event_id); // See OnProgressEventRaised.
sender_->Send(new AppCacheMsg_EventRaised(host_ids, event_id));
}
@@ -38,12 +38,12 @@ void AppCacheFrontendProxy::OnProgressEventRaised(
void AppCacheFrontendProxy::OnErrorEventRaised(
const std::vector<int>& host_ids,
- const appcache::AppCacheErrorDetails& details) {
+ const AppCacheErrorDetails& details) {
sender_->Send(new AppCacheMsg_ErrorEventRaised(host_ids, details));
}
void AppCacheFrontendProxy::OnLogMessage(int host_id,
- appcache::AppCacheLogLevel log_level,
+ AppCacheLogLevel log_level,
const std::string& message) {
sender_->Send(new AppCacheMsg_LogMessage(host_id, log_level, message));
}
diff --git a/chromium/content/browser/appcache/appcache_frontend_proxy.h b/chromium/content/browser/appcache/appcache_frontend_proxy.h
index 904c8aed5c1..65d03ee8d2e 100644
--- a/chromium/content/browser/appcache/appcache_frontend_proxy.h
+++ b/chromium/content/browser/appcache/appcache_frontend_proxy.h
@@ -8,33 +8,32 @@
#include <string>
#include <vector>
+#include "content/common/appcache_interfaces.h"
#include "ipc/ipc_sender.h"
-#include "webkit/common/appcache/appcache_interfaces.h"
namespace content {
// Sends appcache related messages to a child process.
-class AppCacheFrontendProxy : public appcache::AppCacheFrontend {
+class AppCacheFrontendProxy : public AppCacheFrontend {
public:
explicit AppCacheFrontendProxy(IPC::Sender* sender);
// AppCacheFrontend methods
- virtual void OnCacheSelected(int host_id,
- const appcache::AppCacheInfo& info) OVERRIDE;
- virtual void OnStatusChanged(const std::vector<int>& host_ids,
- appcache::AppCacheStatus status) OVERRIDE;
- virtual void OnEventRaised(const std::vector<int>& host_ids,
- appcache::AppCacheEventID event_id) OVERRIDE;
- virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
- const GURL& url,
- int num_total, int num_complete) OVERRIDE;
- virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
- const appcache::AppCacheErrorDetails& details)
- OVERRIDE;
- virtual void OnLogMessage(int host_id, appcache::AppCacheLogLevel log_level,
- const std::string& message) OVERRIDE;
- virtual void OnContentBlocked(int host_id,
- const GURL& manifest_url) OVERRIDE;
+ void OnCacheSelected(int host_id, const AppCacheInfo& info) override;
+ void OnStatusChanged(const std::vector<int>& host_ids,
+ AppCacheStatus status) override;
+ void OnEventRaised(const std::vector<int>& host_ids,
+ AppCacheEventID event_id) override;
+ void OnProgressEventRaised(const std::vector<int>& host_ids,
+ const GURL& url,
+ int num_total,
+ int num_complete) override;
+ void OnErrorEventRaised(const std::vector<int>& host_ids,
+ const AppCacheErrorDetails& details) override;
+ void OnLogMessage(int host_id,
+ AppCacheLogLevel log_level,
+ const std::string& message) override;
+ void OnContentBlocked(int host_id, const GURL& manifest_url) override;
private:
IPC::Sender* sender_;
diff --git a/chromium/content/browser/appcache/appcache_group.cc b/chromium/content/browser/appcache/appcache_group.cc
new file mode 100644
index 00000000000..7ebd2890ba4
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_group.cc
@@ -0,0 +1,264 @@
+// 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/appcache/appcache_group.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "content/browser/appcache/appcache_storage.h"
+#include "content/browser/appcache/appcache_update_job.h"
+
+namespace content {
+
+class AppCacheGroup;
+
+// Use this helper class because we cannot make AppCacheGroup a derived class
+// of AppCacheHost::Observer as it would create a circular dependency between
+// AppCacheHost and AppCacheGroup.
+class AppCacheGroup::HostObserver : public AppCacheHost::Observer {
+ public:
+ explicit HostObserver(AppCacheGroup* group) : group_(group) {}
+
+ // Methods for AppCacheHost::Observer.
+ void OnCacheSelectionComplete(AppCacheHost* host) override {} // N/A
+ void OnDestructionImminent(AppCacheHost* host) override {
+ group_->HostDestructionImminent(host);
+ }
+ private:
+ AppCacheGroup* group_;
+};
+
+AppCacheGroup::AppCacheGroup(AppCacheStorage* storage,
+ const GURL& manifest_url,
+ int64 group_id)
+ : group_id_(group_id),
+ manifest_url_(manifest_url),
+ update_status_(IDLE),
+ is_obsolete_(false),
+ is_being_deleted_(false),
+ newest_complete_cache_(NULL),
+ update_job_(NULL),
+ storage_(storage),
+ is_in_dtor_(false) {
+ storage_->working_set()->AddGroup(this);
+ host_observer_.reset(new HostObserver(this));
+}
+
+AppCacheGroup::~AppCacheGroup() {
+ DCHECK(old_caches_.empty());
+ DCHECK(!newest_complete_cache_);
+ DCHECK(restart_update_task_.IsCancelled());
+ DCHECK(queued_updates_.empty());
+
+ is_in_dtor_ = true;
+
+ if (update_job_)
+ delete update_job_;
+ DCHECK_EQ(IDLE, update_status_);
+
+ storage_->working_set()->RemoveGroup(this);
+ storage_->DeleteResponses(manifest_url_, newly_deletable_response_ids_);
+}
+
+void AppCacheGroup::AddUpdateObserver(UpdateObserver* observer) {
+ // If observer being added is a host that has been queued for later update,
+ // add observer to a different observer list.
+ AppCacheHost* host = static_cast<AppCacheHost*>(observer);
+ if (queued_updates_.find(host) != queued_updates_.end())
+ queued_observers_.AddObserver(observer);
+ else
+ observers_.AddObserver(observer);
+}
+
+void AppCacheGroup::RemoveUpdateObserver(UpdateObserver* observer) {
+ observers_.RemoveObserver(observer);
+ queued_observers_.RemoveObserver(observer);
+}
+
+void AppCacheGroup::AddCache(AppCache* complete_cache) {
+ DCHECK(complete_cache->is_complete());
+ complete_cache->set_owning_group(this);
+
+ if (!newest_complete_cache_) {
+ newest_complete_cache_ = complete_cache;
+ return;
+ }
+
+ if (complete_cache->IsNewerThan(newest_complete_cache_)) {
+ old_caches_.push_back(newest_complete_cache_);
+ newest_complete_cache_ = complete_cache;
+
+ // Update hosts of older caches to add a reference to the newest cache.
+ for (Caches::iterator it = old_caches_.begin();
+ it != old_caches_.end(); ++it) {
+ AppCache::AppCacheHosts& hosts = (*it)->associated_hosts();
+ for (AppCache::AppCacheHosts::iterator host_it = hosts.begin();
+ host_it != hosts.end(); ++host_it) {
+ (*host_it)->SetSwappableCache(this);
+ }
+ }
+ } else {
+ old_caches_.push_back(complete_cache);
+ }
+}
+
+void AppCacheGroup::RemoveCache(AppCache* cache) {
+ DCHECK(cache->associated_hosts().empty());
+ if (cache == newest_complete_cache_) {
+ AppCache* tmp_cache = newest_complete_cache_;
+ newest_complete_cache_ = NULL;
+ tmp_cache->set_owning_group(NULL); // may cause this group to be deleted
+ } else {
+ scoped_refptr<AppCacheGroup> protect(this);
+
+ Caches::iterator it =
+ std::find(old_caches_.begin(), old_caches_.end(), cache);
+ if (it != old_caches_.end()) {
+ AppCache* tmp_cache = *it;
+ old_caches_.erase(it);
+ tmp_cache->set_owning_group(NULL); // may cause group to be released
+ }
+
+ if (!is_obsolete() && old_caches_.empty() &&
+ !newly_deletable_response_ids_.empty()) {
+ storage_->DeleteResponses(manifest_url_, newly_deletable_response_ids_);
+ newly_deletable_response_ids_.clear();
+ }
+ }
+}
+
+void AppCacheGroup::AddNewlyDeletableResponseIds(
+ std::vector<int64>* response_ids) {
+ if (is_being_deleted() || (!is_obsolete() && old_caches_.empty())) {
+ storage_->DeleteResponses(manifest_url_, *response_ids);
+ response_ids->clear();
+ return;
+ }
+
+ if (newly_deletable_response_ids_.empty()) {
+ newly_deletable_response_ids_.swap(*response_ids);
+ return;
+ }
+ newly_deletable_response_ids_.insert(
+ newly_deletable_response_ids_.end(),
+ response_ids->begin(), response_ids->end());
+ response_ids->clear();
+}
+
+void AppCacheGroup::StartUpdateWithNewMasterEntry(
+ AppCacheHost* host, const GURL& new_master_resource) {
+ DCHECK(!is_obsolete() && !is_being_deleted());
+ if (is_in_dtor_)
+ return;
+
+ if (!update_job_)
+ update_job_ = new AppCacheUpdateJob(storage_->service(), this);
+
+ update_job_->StartUpdate(host, new_master_resource);
+
+ // Run queued update immediately as an update has been started manually.
+ if (!restart_update_task_.IsCancelled()) {
+ restart_update_task_.Cancel();
+ RunQueuedUpdates();
+ }
+}
+
+void AppCacheGroup::CancelUpdate() {
+ if (update_job_) {
+ delete update_job_;
+ DCHECK(!update_job_);
+ DCHECK_EQ(IDLE, update_status_);
+ }
+}
+
+void AppCacheGroup::QueueUpdate(AppCacheHost* host,
+ const GURL& new_master_resource) {
+ DCHECK(update_job_ && host && !new_master_resource.is_empty());
+ queued_updates_.insert(QueuedUpdates::value_type(host, new_master_resource));
+
+ // Need to know when host is destroyed.
+ host->AddObserver(host_observer_.get());
+
+ // If host is already observing for updates, move host to queued observers
+ // list so that host is not notified when the current update completes.
+ if (FindObserver(host, observers_)) {
+ observers_.RemoveObserver(host);
+ queued_observers_.AddObserver(host);
+ }
+}
+
+void AppCacheGroup::RunQueuedUpdates() {
+ if (!restart_update_task_.IsCancelled())
+ restart_update_task_.Cancel();
+
+ if (queued_updates_.empty())
+ return;
+
+ QueuedUpdates updates_to_run;
+ queued_updates_.swap(updates_to_run);
+ DCHECK(queued_updates_.empty());
+
+ for (QueuedUpdates::iterator it = updates_to_run.begin();
+ it != updates_to_run.end(); ++it) {
+ AppCacheHost* host = it->first;
+ host->RemoveObserver(host_observer_.get());
+ if (FindObserver(host, queued_observers_)) {
+ queued_observers_.RemoveObserver(host);
+ observers_.AddObserver(host);
+ }
+
+ if (!is_obsolete() && !is_being_deleted())
+ StartUpdateWithNewMasterEntry(host, it->second);
+ }
+}
+
+bool AppCacheGroup::FindObserver(UpdateObserver* find_me,
+ const ObserverList<UpdateObserver>& observer_list) {
+ return observer_list.HasObserver(find_me);
+}
+
+void AppCacheGroup::ScheduleUpdateRestart(int delay_ms) {
+ DCHECK(restart_update_task_.IsCancelled());
+ restart_update_task_.Reset(
+ base::Bind(&AppCacheGroup::RunQueuedUpdates, this));
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ restart_update_task_.callback(),
+ base::TimeDelta::FromMilliseconds(delay_ms));
+}
+
+void AppCacheGroup::HostDestructionImminent(AppCacheHost* host) {
+ queued_updates_.erase(host);
+ if (queued_updates_.empty() && !restart_update_task_.IsCancelled())
+ restart_update_task_.Cancel();
+}
+
+void AppCacheGroup::SetUpdateAppCacheStatus(UpdateAppCacheStatus status) {
+ if (status == update_status_)
+ return;
+
+ update_status_ = status;
+
+ if (status != IDLE) {
+ DCHECK(update_job_);
+ } else {
+ update_job_ = NULL;
+
+ // Observers may release us in these callbacks, so we protect against
+ // deletion by adding an extra ref in this scope (but only if we're not
+ // in our destructor).
+ scoped_refptr<AppCacheGroup> protect(is_in_dtor_ ? NULL : this);
+ FOR_EACH_OBSERVER(UpdateObserver, observers_, OnUpdateComplete(this));
+ if (!queued_updates_.empty())
+ ScheduleUpdateRestart(kUpdateRestartDelayMs);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_group.h b/chromium/content/browser/appcache/appcache_group.h
new file mode 100644
index 00000000000..3c54cfec5a2
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_group.h
@@ -0,0 +1,173 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_GROUP_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_GROUP_H_
+
+#include <map>
+#include <vector>
+
+#include "base/cancelable_callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace content {
+FORWARD_DECLARE_TEST(AppCacheGroupTest, StartUpdate);
+FORWARD_DECLARE_TEST(AppCacheGroupTest, CancelUpdate);
+FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate);
+FORWARD_DECLARE_TEST(AppCacheUpdateJobTest, AlreadyChecking);
+FORWARD_DECLARE_TEST(AppCacheUpdateJobTest, AlreadyDownloading);
+class AppCache;
+class AppCacheHost;
+class AppCacheStorage;
+class AppCacheUpdateJob;
+class AppCacheUpdateJobTest;
+class HostObserver;
+class MockAppCacheStorage;
+
+// Collection of application caches identified by the same manifest URL.
+// A group exists as long as it is in use by a host or is being updated.
+class CONTENT_EXPORT AppCacheGroup
+ : public base::RefCounted<AppCacheGroup> {
+ public:
+
+ class CONTENT_EXPORT UpdateObserver {
+ public:
+ // Called just after an appcache update has completed.
+ virtual void OnUpdateComplete(AppCacheGroup* group) = 0;
+ virtual ~UpdateObserver() {}
+ };
+
+ enum UpdateAppCacheStatus {
+ IDLE,
+ CHECKING,
+ DOWNLOADING,
+ };
+
+ AppCacheGroup(AppCacheStorage* storage, const GURL& manifest_url,
+ int64 group_id);
+
+ // Adds/removes an update observer, the AppCacheGroup does not take
+ // ownership of the observer.
+ void AddUpdateObserver(UpdateObserver* observer);
+ void RemoveUpdateObserver(UpdateObserver* observer);
+
+ int64 group_id() const { return group_id_; }
+ const GURL& manifest_url() const { return manifest_url_; }
+ const base::Time& creation_time() const { return creation_time_; }
+ void set_creation_time(const base::Time& time) { creation_time_ = time; }
+ bool is_obsolete() const { return is_obsolete_; }
+ void set_obsolete(bool value) { is_obsolete_ = value; }
+
+ bool is_being_deleted() const { return is_being_deleted_; }
+ void set_being_deleted(bool value) { is_being_deleted_ = value; }
+
+ AppCache* newest_complete_cache() const { return newest_complete_cache_; }
+
+ void AddCache(AppCache* complete_cache);
+ void RemoveCache(AppCache* cache);
+ bool HasCache() const { return newest_complete_cache_ != NULL; }
+
+ void AddNewlyDeletableResponseIds(std::vector<int64>* response_ids);
+
+ UpdateAppCacheStatus update_status() const { return update_status_; }
+
+ // Starts an update via update() javascript API.
+ void StartUpdate() {
+ StartUpdateWithHost(NULL);
+ }
+
+ // Starts an update for a doc loaded from an application cache.
+ void StartUpdateWithHost(AppCacheHost* host) {
+ StartUpdateWithNewMasterEntry(host, GURL());
+ }
+
+ // Starts an update for a doc loaded using HTTP GET or equivalent with
+ // an <html> tag manifest attribute value that matches this group's
+ // manifest url.
+ void StartUpdateWithNewMasterEntry(AppCacheHost* host,
+ const GURL& new_master_resource);
+
+ // Cancels an update if one is running.
+ void CancelUpdate();
+
+ private:
+ class HostObserver;
+
+ friend class base::RefCounted<AppCacheGroup>;
+ friend class content::AppCacheUpdateJobTest;
+ friend class content::MockAppCacheStorage; // for old_caches()
+ friend class AppCacheUpdateJob;
+
+ ~AppCacheGroup();
+
+ typedef std::vector<AppCache*> Caches;
+ typedef std::map<AppCacheHost*, GURL> QueuedUpdates;
+
+ static const int kUpdateRestartDelayMs = 1000;
+
+ AppCacheUpdateJob* update_job() { return update_job_; }
+ void SetUpdateAppCacheStatus(UpdateAppCacheStatus status);
+
+ void NotifyContentBlocked();
+
+ const Caches& old_caches() const { return old_caches_; }
+
+ // Update cannot be processed at this time. Queue it for a later run.
+ void QueueUpdate(AppCacheHost* host, const GURL& new_master_resource);
+ void RunQueuedUpdates();
+ bool FindObserver(UpdateObserver* find_me,
+ const ObserverList<UpdateObserver>& observer_list);
+ void ScheduleUpdateRestart(int delay_ms);
+ void HostDestructionImminent(AppCacheHost* host);
+
+ const int64 group_id_;
+ const GURL manifest_url_;
+ base::Time creation_time_;
+ UpdateAppCacheStatus update_status_;
+ bool is_obsolete_;
+ bool is_being_deleted_;
+ std::vector<int64> newly_deletable_response_ids_;
+
+ // Old complete app caches.
+ Caches old_caches_;
+
+ // Newest cache in this group to be complete, aka relevant cache.
+ AppCache* newest_complete_cache_;
+
+ // Current update job for this group, if any.
+ AppCacheUpdateJob* update_job_;
+
+ // Central storage object.
+ AppCacheStorage* storage_;
+
+ // List of objects observing this group.
+ ObserverList<UpdateObserver> observers_;
+
+ // Updates that have been queued for the next run.
+ QueuedUpdates queued_updates_;
+ ObserverList<UpdateObserver> queued_observers_;
+ base::CancelableClosure restart_update_task_;
+ scoped_ptr<HostObserver> host_observer_;
+
+ // True if we're in our destructor.
+ bool is_in_dtor_;
+
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, StartUpdate);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, CancelUpdate);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, QueueUpdate);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheUpdateJobTest, AlreadyChecking);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheUpdateJobTest, AlreadyDownloading);
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheGroup);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_GROUP_H_
diff --git a/chromium/content/browser/appcache/appcache_group_unittest.cc b/chromium/content/browser/appcache/appcache_group_unittest.cc
index cec20fa8c62..64e321d5525 100644
--- a/chromium/content/browser/appcache/appcache_group_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_group_unittest.cc
@@ -5,65 +5,54 @@
#include <string>
#include "base/message_loop/message_loop.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/browser/appcache/appcache_update_job.h"
#include "content/browser/appcache/mock_appcache_service.h"
+#include "content/common/appcache_interfaces.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_host.h"
-#include "webkit/browser/appcache/appcache_update_job.h"
-#include "webkit/common/appcache/appcache_interfaces.h"
-
-using appcache::AppCache;
-using appcache::AppCacheFrontend;
-using appcache::AppCacheGroup;
-using appcache::AppCacheHost;
-using appcache::AppCacheServiceImpl;
-using appcache::AppCacheUpdateJob;
namespace {
-class TestAppCacheFrontend : public appcache::AppCacheFrontend {
+class TestAppCacheFrontend : public content::AppCacheFrontend {
public:
TestAppCacheFrontend()
: last_host_id_(-1), last_cache_id_(-1),
- last_status_(appcache::APPCACHE_STATUS_OBSOLETE) {
+ last_status_(content::APPCACHE_STATUS_OBSOLETE) {
}
- virtual void OnCacheSelected(
- int host_id, const appcache::AppCacheInfo& info) OVERRIDE {
+ void OnCacheSelected(int host_id,
+ const content::AppCacheInfo& info) override {
last_host_id_ = host_id;
last_cache_id_ = info.cache_id;
last_status_ = info.status;
}
- virtual void OnStatusChanged(const std::vector<int>& host_ids,
- appcache::AppCacheStatus status) OVERRIDE {
- }
+ void OnStatusChanged(const std::vector<int>& host_ids,
+ content::AppCacheStatus status) override {}
- virtual void OnEventRaised(const std::vector<int>& host_ids,
- appcache::AppCacheEventID event_id) OVERRIDE {
- }
+ void OnEventRaised(const std::vector<int>& host_ids,
+ content::AppCacheEventID event_id) override {}
- virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
- const appcache::AppCacheErrorDetails& details)
- OVERRIDE {}
+ void OnErrorEventRaised(
+ const std::vector<int>& host_ids,
+ const content::AppCacheErrorDetails& details) override {}
- virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
- const GURL& url,
- int num_total, int num_complete) OVERRIDE {
- }
+ void OnProgressEventRaised(const std::vector<int>& host_ids,
+ const GURL& url,
+ int num_total,
+ int num_complete) override {}
- virtual void OnLogMessage(int host_id, appcache::AppCacheLogLevel log_level,
- const std::string& message) OVERRIDE {
- }
+ void OnLogMessage(int host_id,
+ content::AppCacheLogLevel log_level,
+ const std::string& message) override {}
- virtual void OnContentBlocked(int host_id,
- const GURL& manifest_url) OVERRIDE {
- }
+ void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
int last_host_id_;
int64 last_cache_id_;
- appcache::AppCacheStatus last_status_;
+ content::AppCacheStatus last_status_;
};
} // namespace anon
@@ -75,7 +64,7 @@ class TestUpdateObserver : public AppCacheGroup::UpdateObserver {
TestUpdateObserver() : update_completed_(false), group_has_cache_(false) {
}
- virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
+ void OnUpdateComplete(AppCacheGroup* group) override {
update_completed_ = true;
group_has_cache_ = group->HasCache();
}
@@ -95,7 +84,7 @@ class TestAppCacheHost : public AppCacheHost {
update_completed_(false) {
}
- virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
+ void OnUpdateComplete(AppCacheGroup* group) override {
update_completed_ = true;
}
@@ -118,60 +107,60 @@ TEST_F(AppCacheGroupTest, AddRemoveCache) {
cache1->set_complete(true);
cache1->set_update_time(now);
group->AddCache(cache1.get());
- EXPECT_EQ(cache1, group->newest_complete_cache());
+ EXPECT_EQ(cache1.get(), group->newest_complete_cache());
// Adding older cache does not change newest complete cache.
scoped_refptr<AppCache> cache2(new AppCache(service.storage(), 222));
cache2->set_complete(true);
cache2->set_update_time(now - base::TimeDelta::FromDays(1));
group->AddCache(cache2.get());
- EXPECT_EQ(cache1, group->newest_complete_cache());
+ EXPECT_EQ(cache1.get(), group->newest_complete_cache());
// Adding newer cache does change newest complete cache.
scoped_refptr<AppCache> cache3(new AppCache(service.storage(), 333));
cache3->set_complete(true);
cache3->set_update_time(now + base::TimeDelta::FromDays(1));
group->AddCache(cache3.get());
- EXPECT_EQ(cache3, group->newest_complete_cache());
+ EXPECT_EQ(cache3.get(), group->newest_complete_cache());
// Adding cache with same update time uses one with larger ID.
scoped_refptr<AppCache> cache4(new AppCache(service.storage(), 444));
cache4->set_complete(true);
cache4->set_update_time(now + base::TimeDelta::FromDays(1)); // same as 3
group->AddCache(cache4.get());
- EXPECT_EQ(cache4, group->newest_complete_cache());
+ EXPECT_EQ(cache4.get(), group->newest_complete_cache());
// smaller id
scoped_refptr<AppCache> cache5(new AppCache(service.storage(), 55));
cache5->set_complete(true);
cache5->set_update_time(now + base::TimeDelta::FromDays(1)); // same as 4
group->AddCache(cache5.get());
- EXPECT_EQ(cache4, group->newest_complete_cache()); // no change
+ EXPECT_EQ(cache4.get(), group->newest_complete_cache()); // no change
// Old caches can always be removed.
group->RemoveCache(cache1.get());
EXPECT_FALSE(cache1->owning_group());
- EXPECT_EQ(cache4, group->newest_complete_cache()); // newest unchanged
+ EXPECT_EQ(cache4.get(), group->newest_complete_cache()); // newest unchanged
// Remove rest of caches.
group->RemoveCache(cache2.get());
EXPECT_FALSE(cache2->owning_group());
- EXPECT_EQ(cache4, group->newest_complete_cache()); // newest unchanged
+ EXPECT_EQ(cache4.get(), group->newest_complete_cache()); // newest unchanged
group->RemoveCache(cache3.get());
EXPECT_FALSE(cache3->owning_group());
- EXPECT_EQ(cache4, group->newest_complete_cache()); // newest unchanged
+ EXPECT_EQ(cache4.get(), group->newest_complete_cache()); // newest unchanged
group->RemoveCache(cache5.get());
EXPECT_FALSE(cache5->owning_group());
- EXPECT_EQ(cache4, group->newest_complete_cache()); // newest unchanged
+ EXPECT_EQ(cache4.get(), group->newest_complete_cache()); // newest unchanged
group->RemoveCache(cache4.get()); // newest removed
EXPECT_FALSE(cache4->owning_group());
EXPECT_FALSE(group->newest_complete_cache()); // no more newest cache
// Can remove newest cache if there are older caches.
group->AddCache(cache1.get());
- EXPECT_EQ(cache1, group->newest_complete_cache());
+ EXPECT_EQ(cache1.get(), group->newest_complete_cache());
group->AddCache(cache4.get());
- EXPECT_EQ(cache4, group->newest_complete_cache());
+ EXPECT_EQ(cache4.get(), group->newest_complete_cache());
group->RemoveCache(cache4.get()); // remove newest
EXPECT_FALSE(cache4->owning_group());
EXPECT_FALSE(group->newest_complete_cache()); // newest removed
@@ -197,12 +186,12 @@ TEST_F(AppCacheGroupTest, CleanupUnusedGroup) {
host1.AssociateCompleteCache(cache1);
EXPECT_EQ(frontend.last_host_id_, host1.host_id());
EXPECT_EQ(frontend.last_cache_id_, cache1->cache_id());
- EXPECT_EQ(frontend.last_status_, appcache::APPCACHE_STATUS_IDLE);
+ EXPECT_EQ(frontend.last_status_, APPCACHE_STATUS_IDLE);
host2.AssociateCompleteCache(cache1);
EXPECT_EQ(frontend.last_host_id_, host2.host_id());
EXPECT_EQ(frontend.last_cache_id_, cache1->cache_id());
- EXPECT_EQ(frontend.last_status_, appcache::APPCACHE_STATUS_IDLE);
+ EXPECT_EQ(frontend.last_status_, APPCACHE_STATUS_IDLE);
AppCache* cache2 = new AppCache(service.storage(), 222);
cache2->set_complete(true);
@@ -214,8 +203,8 @@ TEST_F(AppCacheGroupTest, CleanupUnusedGroup) {
host1.AssociateNoCache(GURL());
host2.AssociateNoCache(GURL());
EXPECT_EQ(frontend.last_host_id_, host2.host_id());
- EXPECT_EQ(frontend.last_cache_id_, appcache::kAppCacheNoCacheId);
- EXPECT_EQ(frontend.last_status_, appcache::APPCACHE_STATUS_UNCACHED);
+ EXPECT_EQ(frontend.last_cache_id_, kAppCacheNoCacheId);
+ EXPECT_EQ(frontend.last_status_, APPCACHE_STATUS_UNCACHED);
}
TEST_F(AppCacheGroupTest, StartUpdate) {
diff --git a/chromium/content/browser/appcache/appcache_histograms.cc b/chromium/content/browser/appcache/appcache_histograms.cc
new file mode 100644
index 00000000000..ff221b075af
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_histograms.cc
@@ -0,0 +1,154 @@
+// 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/appcache/appcache_histograms.h"
+
+#include "base/metrics/histogram.h"
+
+namespace content {
+
+static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) {
+ if (origin_url.host() == "docs.google.com")
+ return ".Docs";
+ return std::string();
+}
+
+void AppCacheHistograms::CountInitResult(InitResultType init_result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "appcache.InitResult",
+ init_result, NUM_INIT_RESULT_TYPES);
+}
+
+void AppCacheHistograms::CountReinitAttempt(bool repeated_attempt) {
+ UMA_HISTOGRAM_BOOLEAN("appcache.ReinitAttempt", repeated_attempt);
+}
+
+void AppCacheHistograms::CountCorruptionDetected() {
+ UMA_HISTOGRAM_BOOLEAN("appcache.CorruptionDetected", true);
+}
+
+void AppCacheHistograms::CountUpdateJobResult(
+ AppCacheUpdateJob::ResultType result,
+ const GURL& origin_url) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "appcache.UpdateJobResult",
+ result, AppCacheUpdateJob::NUM_UPDATE_JOB_RESULT_TYPES);
+
+ const std::string suffix = OriginToCustomHistogramSuffix(origin_url);
+ if (!suffix.empty()) {
+ base::LinearHistogram::FactoryGet(
+ "appcache.UpdateJobResult" + suffix,
+ 1,
+ AppCacheUpdateJob::NUM_UPDATE_JOB_RESULT_TYPES,
+ AppCacheUpdateJob::NUM_UPDATE_JOB_RESULT_TYPES + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag)->Add(result);
+ }
+}
+
+void AppCacheHistograms::CountCheckResponseResult(
+ CheckResponseResultType result) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "appcache.CheckResponseResult",
+ result, NUM_CHECK_RESPONSE_RESULT_TYPES);
+}
+
+void AppCacheHistograms::CountResponseRetrieval(
+ bool success, bool is_main_resource, const GURL& origin_url) {
+ std::string label;
+ if (is_main_resource) {
+ label = "appcache.MainResourceResponseRetrieval";
+ UMA_HISTOGRAM_BOOLEAN(label, success);
+ } else {
+ label = "appcache.SubResourceResponseRetrieval";
+ UMA_HISTOGRAM_BOOLEAN(label, success);
+ }
+ const std::string suffix = OriginToCustomHistogramSuffix(origin_url);
+ if (!suffix.empty()) {
+ base::BooleanHistogram::FactoryGet(
+ label + suffix,
+ base::HistogramBase::kUmaTargetedHistogramFlag)->Add(success);
+ }
+}
+
+void AppCacheHistograms::LogUpdateFailureStats(
+ const GURL& origin_url,
+ int percent_complete,
+ bool was_stalled,
+ bool was_off_origin_resource_failure) {
+ const std::string suffix = OriginToCustomHistogramSuffix(origin_url);
+
+ std::string label = "appcache.UpdateProgressAtPointOfFaliure";
+ UMA_HISTOGRAM_PERCENTAGE(label, percent_complete);
+ if (!suffix.empty()) {
+ base::LinearHistogram::FactoryGet(
+ label + suffix,
+ 1, 101, 102,
+ base::HistogramBase::kUmaTargetedHistogramFlag)->Add(percent_complete);
+ }
+
+ label = "appcache.UpdateWasStalledAtPointOfFailure";
+ UMA_HISTOGRAM_BOOLEAN(label, was_stalled);
+ if (!suffix.empty()) {
+ base::BooleanHistogram::FactoryGet(
+ label + suffix,
+ base::HistogramBase::kUmaTargetedHistogramFlag)->Add(was_stalled);
+ }
+
+ label = "appcache.UpdateWasOffOriginAtPointOfFailure";
+ UMA_HISTOGRAM_BOOLEAN(label, was_off_origin_resource_failure);
+ if (!suffix.empty()) {
+ base::BooleanHistogram::FactoryGet(
+ label + suffix,
+ base::HistogramBase::kUmaTargetedHistogramFlag)->Add(
+ was_off_origin_resource_failure);
+ }
+}
+
+void AppCacheHistograms::AddTaskQueueTimeSample(
+ const base::TimeDelta& duration) {
+ UMA_HISTOGRAM_TIMES("appcache.TaskQueueTime", duration);
+}
+
+void AppCacheHistograms::AddTaskRunTimeSample(
+ const base::TimeDelta& duration) {
+ UMA_HISTOGRAM_TIMES("appcache.TaskRunTime", duration);
+}
+
+void AppCacheHistograms::AddCompletionQueueTimeSample(
+ const base::TimeDelta& duration) {
+ UMA_HISTOGRAM_TIMES("appcache.CompletionQueueTime", duration);
+}
+
+void AppCacheHistograms::AddCompletionRunTimeSample(
+ const base::TimeDelta& duration) {
+ UMA_HISTOGRAM_TIMES("appcache.CompletionRunTime", duration);
+}
+
+void AppCacheHistograms::AddNetworkJobStartDelaySample(
+ const base::TimeDelta& duration) {
+ UMA_HISTOGRAM_TIMES("appcache.JobStartDelay.Network", duration);
+}
+
+void AppCacheHistograms::AddErrorJobStartDelaySample(
+ const base::TimeDelta& duration) {
+ UMA_HISTOGRAM_TIMES("appcache.JobStartDelay.Error", duration);
+}
+
+void AppCacheHistograms::AddAppCacheJobStartDelaySample(
+ const base::TimeDelta& duration) {
+ UMA_HISTOGRAM_TIMES("appcache.JobStartDelay.AppCache", duration);
+}
+
+void AppCacheHistograms::AddMissingManifestEntrySample() {
+ UMA_HISTOGRAM_BOOLEAN("appcache.MissingManifestEntry", true);
+}
+
+void AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
+ MissingManifestCallsiteType callsite) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "appcache.MissingManifestDetectedAtCallsite",
+ callsite, NUM_MISSING_MANIFEST_CALLSITE_TYPES);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_histograms.h b/chromium/content/browser/appcache/appcache_histograms.h
new file mode 100644
index 00000000000..0fcc54cf65f
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_histograms.h
@@ -0,0 +1,63 @@
+// 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_APPCACHE_APPCACHE_HISTOGRAMS_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_HISTOGRAMS_H_
+
+#include "base/basictypes.h"
+#include "content/browser/appcache/appcache_update_job.h"
+
+namespace base {
+class TimeDelta;
+}
+
+namespace content {
+
+class AppCacheHistograms {
+ public:
+ enum InitResultType {
+ INIT_OK, SQL_DATABASE_ERROR, DISK_CACHE_ERROR,
+ NUM_INIT_RESULT_TYPES
+ };
+ static void CountInitResult(InitResultType init_result);
+ static void CountReinitAttempt(bool repeated_attempt);
+ static void CountCorruptionDetected();
+ static void CountUpdateJobResult(AppCacheUpdateJob::ResultType result,
+ const GURL& origin_url);
+ enum CheckResponseResultType {
+ RESPONSE_OK, MANIFEST_OUT_OF_DATE, RESPONSE_OUT_OF_DATE, ENTRY_NOT_FOUND,
+ READ_HEADERS_ERROR, READ_DATA_ERROR, UNEXPECTED_DATA_SIZE, CHECK_CANCELED,
+ NUM_CHECK_RESPONSE_RESULT_TYPES
+ };
+ static void CountCheckResponseResult(CheckResponseResultType result);
+ static void CountResponseRetrieval(
+ bool success, bool is_main_resource, const GURL& origin_url);
+ static void LogUpdateFailureStats(
+ const GURL& origin_url,
+ int percent_complete,
+ bool was_making_progress,
+ bool off_origin_resource_failure);
+ static void AddTaskQueueTimeSample(const base::TimeDelta& duration);
+ static void AddTaskRunTimeSample(const base::TimeDelta& duration);
+ static void AddCompletionQueueTimeSample(const base::TimeDelta& duration);
+ static void AddCompletionRunTimeSample(const base::TimeDelta& duration);
+ static void AddNetworkJobStartDelaySample(const base::TimeDelta& duration);
+ static void AddErrorJobStartDelaySample(const base::TimeDelta& duration);
+ static void AddAppCacheJobStartDelaySample(const base::TimeDelta& duration);
+ static void AddMissingManifestEntrySample();
+
+ enum MissingManifestCallsiteType {
+ CALLSITE_0, CALLSITE_1, CALLSITE_2, CALLSITE_3,
+ NUM_MISSING_MANIFEST_CALLSITE_TYPES
+ };
+ static void AddMissingManifestDetectedAtCallsite(
+ MissingManifestCallsiteType type);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AppCacheHistograms);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_HISTOGRAMS_H_
diff --git a/chromium/content/browser/appcache/appcache_host.cc b/chromium/content/browser/appcache/appcache_host.cc
new file mode 100644
index 00000000000..52213a3a14e
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_host.cc
@@ -0,0 +1,552 @@
+// 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 "content/browser/appcache/appcache_host.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_backend_impl.h"
+#include "content/browser/appcache/appcache_policy.h"
+#include "content/browser/appcache/appcache_request_handler.h"
+#include "net/url_request/url_request.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+
+namespace content {
+
+namespace {
+
+void FillCacheInfo(const AppCache* cache,
+ const GURL& manifest_url,
+ AppCacheStatus status, AppCacheInfo* info) {
+ info->manifest_url = manifest_url;
+ info->status = status;
+
+ if (!cache)
+ return;
+
+ info->cache_id = cache->cache_id();
+
+ if (!cache->is_complete())
+ return;
+
+ DCHECK(cache->owning_group());
+ info->is_complete = true;
+ info->group_id = cache->owning_group()->group_id();
+ info->last_update_time = cache->update_time();
+ info->creation_time = cache->owning_group()->creation_time();
+ info->size = cache->cache_size();
+}
+
+} // Anonymous namespace
+
+AppCacheHost::AppCacheHost(int host_id, AppCacheFrontend* frontend,
+ AppCacheServiceImpl* service)
+ : host_id_(host_id),
+ spawning_host_id_(kAppCacheNoHostId), spawning_process_id_(0),
+ parent_host_id_(kAppCacheNoHostId), parent_process_id_(0),
+ pending_main_resource_cache_id_(kAppCacheNoCacheId),
+ pending_selected_cache_id_(kAppCacheNoCacheId),
+ is_cache_selection_enabled_(true),
+ frontend_(frontend), service_(service),
+ storage_(service->storage()),
+ pending_callback_param_(NULL),
+ main_resource_was_namespace_entry_(false),
+ main_resource_blocked_(false),
+ associated_cache_info_pending_(false) {
+ service_->AddObserver(this);
+}
+
+AppCacheHost::~AppCacheHost() {
+ service_->RemoveObserver(this);
+ FOR_EACH_OBSERVER(Observer, observers_, OnDestructionImminent(this));
+ if (associated_cache_.get())
+ associated_cache_->UnassociateHost(this);
+ if (group_being_updated_.get())
+ group_being_updated_->RemoveUpdateObserver(this);
+ storage()->CancelDelegateCallbacks(this);
+ if (service()->quota_manager_proxy() && !origin_in_use_.is_empty())
+ service()->quota_manager_proxy()->NotifyOriginNoLongerInUse(origin_in_use_);
+}
+
+void AppCacheHost::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void AppCacheHost::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void AppCacheHost::SelectCache(const GURL& document_url,
+ const int64 cache_document_was_loaded_from,
+ const GURL& manifest_url) {
+ DCHECK(pending_start_update_callback_.is_null() &&
+ pending_swap_cache_callback_.is_null() &&
+ pending_get_status_callback_.is_null() &&
+ !is_selection_pending());
+
+ if (!is_cache_selection_enabled_) {
+ FinishCacheSelection(NULL, NULL);
+ return;
+ }
+
+ origin_in_use_ = document_url.GetOrigin();
+ if (service()->quota_manager_proxy() && !origin_in_use_.is_empty())
+ service()->quota_manager_proxy()->NotifyOriginInUse(origin_in_use_);
+
+ if (main_resource_blocked_)
+ frontend_->OnContentBlocked(host_id_,
+ blocked_manifest_url_);
+
+ // 6.9.6 The application cache selection algorithm.
+ // The algorithm is started here and continues in FinishCacheSelection,
+ // after cache or group loading is complete.
+ // Note: Foreign entries are detected on the client side and
+ // MarkAsForeignEntry is called in that case, so that detection
+ // step is skipped here. See WebApplicationCacheHostImpl.cc
+
+ if (cache_document_was_loaded_from != kAppCacheNoCacheId) {
+ LoadSelectedCache(cache_document_was_loaded_from);
+ return;
+ }
+
+ if (!manifest_url.is_empty() &&
+ (manifest_url.GetOrigin() == document_url.GetOrigin())) {
+ DCHECK(!first_party_url_.is_empty());
+ AppCachePolicy* policy = service()->appcache_policy();
+ if (policy &&
+ !policy->CanCreateAppCache(manifest_url, first_party_url_)) {
+ FinishCacheSelection(NULL, NULL);
+ std::vector<int> host_ids(1, host_id_);
+ frontend_->OnEventRaised(host_ids, APPCACHE_CHECKING_EVENT);
+ frontend_->OnErrorEventRaised(
+ host_ids,
+ AppCacheErrorDetails(
+ "Cache creation was blocked by the content policy",
+ APPCACHE_POLICY_ERROR,
+ GURL(),
+ 0,
+ false /*is_cross_origin*/));
+ frontend_->OnContentBlocked(host_id_, manifest_url);
+ return;
+ }
+
+ // Note: The client detects if the document was not loaded using HTTP GET
+ // and invokes SelectCache without a manifest url, so that detection step
+ // is also skipped here. See WebApplicationCacheHostImpl.cc
+ set_preferred_manifest_url(manifest_url);
+ new_master_entry_url_ = document_url;
+ LoadOrCreateGroup(manifest_url);
+ return;
+ }
+
+ // TODO(michaeln): If there was a manifest URL, the user agent may report
+ // to the user that it was ignored, to aid in application development.
+ FinishCacheSelection(NULL, NULL);
+}
+
+void AppCacheHost::SelectCacheForWorker(int parent_process_id,
+ int parent_host_id) {
+ DCHECK(pending_start_update_callback_.is_null() &&
+ pending_swap_cache_callback_.is_null() &&
+ pending_get_status_callback_.is_null() &&
+ !is_selection_pending());
+
+ parent_process_id_ = parent_process_id;
+ parent_host_id_ = parent_host_id;
+ FinishCacheSelection(NULL, NULL);
+}
+
+void AppCacheHost::SelectCacheForSharedWorker(int64 appcache_id) {
+ DCHECK(pending_start_update_callback_.is_null() &&
+ pending_swap_cache_callback_.is_null() &&
+ pending_get_status_callback_.is_null() &&
+ !is_selection_pending());
+
+ if (appcache_id != kAppCacheNoCacheId) {
+ LoadSelectedCache(appcache_id);
+ return;
+ }
+ FinishCacheSelection(NULL, NULL);
+}
+
+// TODO(michaeln): change method name to MarkEntryAsForeign for consistency
+void AppCacheHost::MarkAsForeignEntry(const GURL& document_url,
+ int64 cache_document_was_loaded_from) {
+ // The document url is not the resource url in the fallback case.
+ storage()->MarkEntryAsForeign(
+ main_resource_was_namespace_entry_ ? namespace_entry_url_ : document_url,
+ cache_document_was_loaded_from);
+ SelectCache(document_url, kAppCacheNoCacheId, GURL());
+}
+
+void AppCacheHost::GetStatusWithCallback(const GetStatusCallback& callback,
+ void* callback_param) {
+ DCHECK(pending_start_update_callback_.is_null() &&
+ pending_swap_cache_callback_.is_null() &&
+ pending_get_status_callback_.is_null());
+
+ pending_get_status_callback_ = callback;
+ pending_callback_param_ = callback_param;
+ if (is_selection_pending())
+ return;
+
+ DoPendingGetStatus();
+}
+
+void AppCacheHost::DoPendingGetStatus() {
+ DCHECK_EQ(false, pending_get_status_callback_.is_null());
+
+ pending_get_status_callback_.Run(GetStatus(), pending_callback_param_);
+ pending_get_status_callback_.Reset();
+ pending_callback_param_ = NULL;
+}
+
+void AppCacheHost::StartUpdateWithCallback(const StartUpdateCallback& callback,
+ void* callback_param) {
+ DCHECK(pending_start_update_callback_.is_null() &&
+ pending_swap_cache_callback_.is_null() &&
+ pending_get_status_callback_.is_null());
+
+ pending_start_update_callback_ = callback;
+ pending_callback_param_ = callback_param;
+ if (is_selection_pending())
+ return;
+
+ DoPendingStartUpdate();
+}
+
+void AppCacheHost::DoPendingStartUpdate() {
+ DCHECK_EQ(false, pending_start_update_callback_.is_null());
+
+ // 6.9.8 Application cache API
+ bool success = false;
+ if (associated_cache_.get() && associated_cache_->owning_group()) {
+ AppCacheGroup* group = associated_cache_->owning_group();
+ if (!group->is_obsolete() && !group->is_being_deleted()) {
+ success = true;
+ group->StartUpdate();
+ }
+ }
+
+ pending_start_update_callback_.Run(success, pending_callback_param_);
+ pending_start_update_callback_.Reset();
+ pending_callback_param_ = NULL;
+}
+
+void AppCacheHost::SwapCacheWithCallback(const SwapCacheCallback& callback,
+ void* callback_param) {
+ DCHECK(pending_start_update_callback_.is_null() &&
+ pending_swap_cache_callback_.is_null() &&
+ pending_get_status_callback_.is_null());
+
+ pending_swap_cache_callback_ = callback;
+ pending_callback_param_ = callback_param;
+ if (is_selection_pending())
+ return;
+
+ DoPendingSwapCache();
+}
+
+void AppCacheHost::DoPendingSwapCache() {
+ DCHECK_EQ(false, pending_swap_cache_callback_.is_null());
+
+ // 6.9.8 Application cache API
+ bool success = false;
+ if (associated_cache_.get() && associated_cache_->owning_group()) {
+ if (associated_cache_->owning_group()->is_obsolete()) {
+ success = true;
+ AssociateNoCache(GURL());
+ } else if (swappable_cache_.get()) {
+ DCHECK(swappable_cache_.get() ==
+ swappable_cache_->owning_group()->newest_complete_cache());
+ success = true;
+ AssociateCompleteCache(swappable_cache_.get());
+ }
+ }
+
+ pending_swap_cache_callback_.Run(success, pending_callback_param_);
+ pending_swap_cache_callback_.Reset();
+ pending_callback_param_ = NULL;
+}
+
+void AppCacheHost::SetSpawningHostId(
+ int spawning_process_id, int spawning_host_id) {
+ spawning_process_id_ = spawning_process_id;
+ spawning_host_id_ = spawning_host_id;
+}
+
+const AppCacheHost* AppCacheHost::GetSpawningHost() const {
+ AppCacheBackendImpl* backend = service_->GetBackend(spawning_process_id_);
+ return backend ? backend->GetHost(spawning_host_id_) : NULL;
+}
+
+AppCacheHost* AppCacheHost::GetParentAppCacheHost() const {
+ DCHECK(is_for_dedicated_worker());
+ AppCacheBackendImpl* backend = service_->GetBackend(parent_process_id_);
+ return backend ? backend->GetHost(parent_host_id_) : NULL;
+}
+
+AppCacheRequestHandler* AppCacheHost::CreateRequestHandler(
+ net::URLRequest* request,
+ ResourceType resource_type) {
+ if (is_for_dedicated_worker()) {
+ AppCacheHost* parent_host = GetParentAppCacheHost();
+ if (parent_host)
+ return parent_host->CreateRequestHandler(request, resource_type);
+ return NULL;
+ }
+
+ if (AppCacheRequestHandler::IsMainResourceType(resource_type)) {
+ // Store the first party origin so that it can be used later in SelectCache
+ // for checking whether the creation of the appcache is allowed.
+ first_party_url_ = request->first_party_for_cookies();
+ return new AppCacheRequestHandler(this, resource_type);
+ }
+
+ if ((associated_cache() && associated_cache()->is_complete()) ||
+ is_selection_pending()) {
+ return new AppCacheRequestHandler(this, resource_type);
+ }
+ return NULL;
+}
+
+void AppCacheHost::GetResourceList(
+ AppCacheResourceInfoVector* resource_infos) {
+ if (associated_cache_.get() && associated_cache_->is_complete())
+ associated_cache_->ToResourceInfoVector(resource_infos);
+}
+
+AppCacheStatus AppCacheHost::GetStatus() {
+ // 6.9.8 Application cache API
+ AppCache* cache = associated_cache();
+ if (!cache)
+ return APPCACHE_STATUS_UNCACHED;
+
+ // A cache without an owning group represents the cache being constructed
+ // during the application cache update process.
+ if (!cache->owning_group())
+ return APPCACHE_STATUS_DOWNLOADING;
+
+ if (cache->owning_group()->is_obsolete())
+ return APPCACHE_STATUS_OBSOLETE;
+ if (cache->owning_group()->update_status() == AppCacheGroup::CHECKING)
+ return APPCACHE_STATUS_CHECKING;
+ if (cache->owning_group()->update_status() == AppCacheGroup::DOWNLOADING)
+ return APPCACHE_STATUS_DOWNLOADING;
+ if (swappable_cache_.get())
+ return APPCACHE_STATUS_UPDATE_READY;
+ return APPCACHE_STATUS_IDLE;
+}
+
+void AppCacheHost::LoadOrCreateGroup(const GURL& manifest_url) {
+ DCHECK(manifest_url.is_valid());
+ pending_selected_manifest_url_ = manifest_url;
+ storage()->LoadOrCreateGroup(manifest_url, this);
+}
+
+void AppCacheHost::OnGroupLoaded(AppCacheGroup* group,
+ const GURL& manifest_url) {
+ DCHECK(manifest_url == pending_selected_manifest_url_);
+ pending_selected_manifest_url_ = GURL();
+ FinishCacheSelection(NULL, group);
+}
+
+void AppCacheHost::LoadSelectedCache(int64 cache_id) {
+ DCHECK(cache_id != kAppCacheNoCacheId);
+ pending_selected_cache_id_ = cache_id;
+ storage()->LoadCache(cache_id, this);
+}
+
+void AppCacheHost::OnCacheLoaded(AppCache* cache, int64 cache_id) {
+ if (cache_id == pending_main_resource_cache_id_) {
+ pending_main_resource_cache_id_ = kAppCacheNoCacheId;
+ main_resource_cache_ = cache;
+ } else if (cache_id == pending_selected_cache_id_) {
+ pending_selected_cache_id_ = kAppCacheNoCacheId;
+ FinishCacheSelection(cache, NULL);
+ }
+}
+
+void AppCacheHost::FinishCacheSelection(
+ AppCache *cache, AppCacheGroup* group) {
+ DCHECK(!associated_cache());
+
+ // 6.9.6 The application cache selection algorithm
+ if (cache) {
+ // If document was loaded from an application cache, Associate document
+ // with the application cache from which it was loaded. Invoke the
+ // application cache update process for that cache and with the browsing
+ // context being navigated.
+ DCHECK(cache->owning_group());
+ DCHECK(new_master_entry_url_.is_empty());
+ DCHECK_EQ(cache->owning_group()->manifest_url(), preferred_manifest_url_);
+ AppCacheGroup* owing_group = cache->owning_group();
+ const char* kFormatString =
+ "Document was loaded from Application Cache with manifest %s";
+ frontend_->OnLogMessage(
+ host_id_, APPCACHE_LOG_INFO,
+ base::StringPrintf(
+ kFormatString, owing_group->manifest_url().spec().c_str()));
+ AssociateCompleteCache(cache);
+ if (!owing_group->is_obsolete() && !owing_group->is_being_deleted()) {
+ owing_group->StartUpdateWithHost(this);
+ ObserveGroupBeingUpdated(owing_group);
+ }
+ } else if (group && !group->is_being_deleted()) {
+ // If document was loaded using HTTP GET or equivalent, and, there is a
+ // manifest URL, and manifest URL has the same origin as document.
+ // Invoke the application cache update process for manifest URL, with
+ // the browsing context being navigated, and with document and the
+ // resource from which document was loaded as the new master resourse.
+ DCHECK(!group->is_obsolete());
+ DCHECK(new_master_entry_url_.is_valid());
+ DCHECK_EQ(group->manifest_url(), preferred_manifest_url_);
+ const char* kFormatString = group->HasCache() ?
+ "Adding master entry to Application Cache with manifest %s" :
+ "Creating Application Cache with manifest %s";
+ frontend_->OnLogMessage(
+ host_id_, APPCACHE_LOG_INFO,
+ base::StringPrintf(kFormatString,
+ group->manifest_url().spec().c_str()));
+ // The UpdateJob may produce one for us later.
+ AssociateNoCache(preferred_manifest_url_);
+ group->StartUpdateWithNewMasterEntry(this, new_master_entry_url_);
+ ObserveGroupBeingUpdated(group);
+ } else {
+ // Otherwise, the Document is not associated with any application cache.
+ new_master_entry_url_ = GURL();
+ AssociateNoCache(GURL());
+ }
+
+ // Respond to pending callbacks now that we have a selection.
+ if (!pending_get_status_callback_.is_null())
+ DoPendingGetStatus();
+ else if (!pending_start_update_callback_.is_null())
+ DoPendingStartUpdate();
+ else if (!pending_swap_cache_callback_.is_null())
+ DoPendingSwapCache();
+
+ FOR_EACH_OBSERVER(Observer, observers_, OnCacheSelectionComplete(this));
+}
+
+void AppCacheHost::OnServiceReinitialized(
+ AppCacheStorageReference* old_storage_ref) {
+ // We continue to use the disabled instance, but arrange for its
+ // deletion when its no longer needed.
+ if (old_storage_ref->storage() == storage())
+ disabled_storage_reference_ = old_storage_ref;
+}
+
+void AppCacheHost::ObserveGroupBeingUpdated(AppCacheGroup* group) {
+ DCHECK(!group_being_updated_.get());
+ group_being_updated_ = group;
+ newest_cache_of_group_being_updated_ = group->newest_complete_cache();
+ group->AddUpdateObserver(this);
+}
+
+void AppCacheHost::OnUpdateComplete(AppCacheGroup* group) {
+ DCHECK_EQ(group, group_being_updated_.get());
+ group->RemoveUpdateObserver(this);
+
+ // Add a reference to the newest complete cache.
+ SetSwappableCache(group);
+
+ group_being_updated_ = NULL;
+ newest_cache_of_group_being_updated_ = NULL;
+
+ if (associated_cache_info_pending_ && associated_cache_.get() &&
+ associated_cache_->is_complete()) {
+ AppCacheInfo info;
+ FillCacheInfo(
+ associated_cache_.get(), preferred_manifest_url_, GetStatus(), &info);
+ associated_cache_info_pending_ = false;
+ frontend_->OnCacheSelected(host_id_, info);
+ }
+}
+
+void AppCacheHost::SetSwappableCache(AppCacheGroup* group) {
+ if (!group) {
+ swappable_cache_ = NULL;
+ } else {
+ AppCache* new_cache = group->newest_complete_cache();
+ if (new_cache != associated_cache_.get())
+ swappable_cache_ = new_cache;
+ else
+ swappable_cache_ = NULL;
+ }
+}
+
+void AppCacheHost::LoadMainResourceCache(int64 cache_id) {
+ DCHECK(cache_id != kAppCacheNoCacheId);
+ if (pending_main_resource_cache_id_ == cache_id ||
+ (main_resource_cache_.get() &&
+ main_resource_cache_->cache_id() == cache_id)) {
+ return;
+ }
+ pending_main_resource_cache_id_ = cache_id;
+ storage()->LoadCache(cache_id, this);
+}
+
+void AppCacheHost::NotifyMainResourceIsNamespaceEntry(
+ const GURL& namespace_entry_url) {
+ main_resource_was_namespace_entry_ = true;
+ namespace_entry_url_ = namespace_entry_url;
+}
+
+void AppCacheHost::NotifyMainResourceBlocked(const GURL& manifest_url) {
+ main_resource_blocked_ = true;
+ blocked_manifest_url_ = manifest_url;
+}
+
+void AppCacheHost::PrepareForTransfer() {
+ // This can only happen prior to the document having been loaded.
+ DCHECK(!associated_cache());
+ DCHECK(!is_selection_pending());
+ DCHECK(!group_being_updated_.get());
+ host_id_ = kAppCacheNoHostId;
+ frontend_ = NULL;
+}
+
+void AppCacheHost::CompleteTransfer(int host_id, AppCacheFrontend* frontend) {
+ host_id_ = host_id;
+ frontend_ = frontend;
+}
+
+void AppCacheHost::AssociateNoCache(const GURL& manifest_url) {
+ // manifest url can be empty.
+ AssociateCacheHelper(NULL, manifest_url);
+}
+
+void AppCacheHost::AssociateIncompleteCache(AppCache* cache,
+ const GURL& manifest_url) {
+ DCHECK(cache && !cache->is_complete());
+ DCHECK(!manifest_url.is_empty());
+ AssociateCacheHelper(cache, manifest_url);
+}
+
+void AppCacheHost::AssociateCompleteCache(AppCache* cache) {
+ DCHECK(cache && cache->is_complete());
+ AssociateCacheHelper(cache, cache->owning_group()->manifest_url());
+}
+
+void AppCacheHost::AssociateCacheHelper(AppCache* cache,
+ const GURL& manifest_url) {
+ if (associated_cache_.get()) {
+ associated_cache_->UnassociateHost(this);
+ }
+
+ associated_cache_ = cache;
+ SetSwappableCache(cache ? cache->owning_group() : NULL);
+ associated_cache_info_pending_ = cache && !cache->is_complete();
+ AppCacheInfo info;
+ if (cache)
+ cache->AssociateHost(this);
+
+ FillCacheInfo(cache, manifest_url, GetStatus(), &info);
+ frontend_->OnCacheSelected(host_id_, info);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_host.h b/chromium/content/browser/appcache/appcache_host.h
new file mode 100644
index 00000000000..9f014fbb471
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_host.h
@@ -0,0 +1,341 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_HOST_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_HOST_H_
+
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "content/browser/appcache/appcache_storage.h"
+#include "content/common/appcache_interfaces.h"
+#include "content/common/content_export.h"
+#include "content/public/common/resource_type.h"
+#include "url/gurl.h"
+
+namespace net {
+class URLRequest;
+} // namespace net
+
+namespace content {
+FORWARD_DECLARE_TEST(AppCacheGroupTest, CleanupUnusedGroup);
+FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate);
+FORWARD_DECLARE_TEST(AppCacheHostTest, Basic);
+FORWARD_DECLARE_TEST(AppCacheHostTest, SelectNoCache);
+FORWARD_DECLARE_TEST(AppCacheHostTest, ForeignEntry);
+FORWARD_DECLARE_TEST(AppCacheHostTest, FailedCacheLoad);
+FORWARD_DECLARE_TEST(AppCacheHostTest, FailedGroupLoad);
+FORWARD_DECLARE_TEST(AppCacheHostTest, SetSwappableCache);
+FORWARD_DECLARE_TEST(AppCacheHostTest, ForDedicatedWorker);
+FORWARD_DECLARE_TEST(AppCacheHostTest, SelectCacheAllowed);
+FORWARD_DECLARE_TEST(AppCacheHostTest, SelectCacheBlocked);
+FORWARD_DECLARE_TEST(AppCacheTest, CleanupUnusedCache);
+class AppCache;
+class AppCacheFrontend;
+class AppCacheGroupTest;
+class AppCacheHostTest;
+class AppCacheRequestHandler;
+class AppCacheRequestHandlerTest;
+class AppCacheStorageImplTest;
+class AppCacheTest;
+class AppCacheUpdateJobTest;
+
+typedef base::Callback<void(AppCacheStatus, void*)> GetStatusCallback;
+typedef base::Callback<void(bool, void*)> StartUpdateCallback;
+typedef base::Callback<void(bool, void*)> SwapCacheCallback;
+
+// Server-side representation of an application cache host.
+class CONTENT_EXPORT AppCacheHost
+ : public AppCacheStorage::Delegate,
+ public AppCacheGroup::UpdateObserver,
+ public AppCacheServiceImpl::Observer {
+ public:
+
+ class CONTENT_EXPORT Observer {
+ public:
+ // Called just after the cache selection algorithm completes.
+ virtual void OnCacheSelectionComplete(AppCacheHost* host) = 0;
+
+ // Called just prior to the instance being deleted.
+ virtual void OnDestructionImminent(AppCacheHost* host) = 0;
+
+ virtual ~Observer() {}
+ };
+
+ AppCacheHost(int host_id, AppCacheFrontend* frontend,
+ AppCacheServiceImpl* service);
+ ~AppCacheHost() override;
+
+ // Adds/removes an observer, the AppCacheHost does not take
+ // ownership of the observer.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Support for cache selection and scriptable method calls.
+ void SelectCache(const GURL& document_url,
+ const int64 cache_document_was_loaded_from,
+ const GURL& manifest_url);
+ void SelectCacheForWorker(int parent_process_id,
+ int parent_host_id);
+ void SelectCacheForSharedWorker(int64 appcache_id);
+ void MarkAsForeignEntry(const GURL& document_url,
+ int64 cache_document_was_loaded_from);
+ void GetStatusWithCallback(const GetStatusCallback& callback,
+ void* callback_param);
+ void StartUpdateWithCallback(const StartUpdateCallback& callback,
+ void* callback_param);
+ void SwapCacheWithCallback(const SwapCacheCallback& callback,
+ void* callback_param);
+
+ // Called prior to the main resource load. When the system contains multiple
+ // candidates for a main resource load, the appcache preferred by the host
+ // that created this host is used to break ties.
+ void SetSpawningHostId(int spawning_process_id, int spawning_host_id);
+
+ // May return NULL if the spawning host context has been closed, or if a
+ // spawning host context was never identified.
+ const AppCacheHost* GetSpawningHost() const;
+
+ const GURL& preferred_manifest_url() const {
+ return preferred_manifest_url_;
+ }
+ void set_preferred_manifest_url(const GURL& url) {
+ preferred_manifest_url_ = url;
+ }
+
+ // Support for loading resources out of the appcache.
+ // May return NULL if the request isn't subject to retrieval from an appache.
+ AppCacheRequestHandler* CreateRequestHandler(
+ net::URLRequest* request,
+ ResourceType resource_type);
+
+ // Support for devtools inspecting appcache resources.
+ void GetResourceList(std::vector<AppCacheResourceInfo>* resource_infos);
+
+ // Breaks any existing association between this host and a cache.
+ // 'manifest_url' is sent to DevTools as the manifest url that could have
+ // been associated before or could be associated later with this host.
+ // Associations are broken either thru the cache selection algorithm
+ // implemented in this class, or by the update algorithm (see
+ // AppCacheUpdateJob).
+ void AssociateNoCache(const GURL& manifest_url);
+
+ // Establishes an association between this host and an incomplete cache.
+ // 'manifest_url' is manifest url of the cache group being updated.
+ // Associations with incomplete caches are established by the update algorithm
+ // (see AppCacheUpdateJob).
+ void AssociateIncompleteCache(AppCache* cache, const GURL& manifest_url);
+
+ // Establishes an association between this host and a complete cache.
+ // Associations with complete caches are established either thru the cache
+ // selection algorithm implemented (in this class), or by the update algorithm
+ // (see AppCacheUpdateJob).
+ void AssociateCompleteCache(AppCache* cache);
+
+ // Adds a reference to the newest complete cache in a group, unless it's the
+ // same as the cache that is currently associated with the host.
+ void SetSwappableCache(AppCacheGroup* group);
+
+ // Used to ensure that a loaded appcache survives a frame navigation.
+ void LoadMainResourceCache(int64 cache_id);
+
+ // Used to notify the host that a namespace resource is being delivered as
+ // the main resource of the page and to provide its url.
+ void NotifyMainResourceIsNamespaceEntry(const GURL& namespace_entry_url);
+
+ // Used to notify the host that the main resource was blocked by a policy. To
+ // work properly, this method needs to by invoked prior to cache selection.
+ void NotifyMainResourceBlocked(const GURL& manifest_url);
+
+ // Used by the update job to keep track of which hosts are associated
+ // with which pending master entries.
+ const GURL& pending_master_entry_url() const {
+ return new_master_entry_url_;
+ }
+
+ int host_id() const { return host_id_; }
+ AppCacheServiceImpl* service() const { return service_; }
+ AppCacheStorage* storage() const { return storage_; }
+ AppCacheFrontend* frontend() const { return frontend_; }
+ AppCache* associated_cache() const { return associated_cache_.get(); }
+
+ void enable_cache_selection(bool enable) {
+ is_cache_selection_enabled_ = enable;
+ }
+
+ bool is_selection_pending() const {
+ return pending_selected_cache_id_ != kAppCacheNoCacheId ||
+ !pending_selected_manifest_url_.is_empty();
+ }
+
+ const GURL& first_party_url() const { return first_party_url_; }
+
+ // Methods to support cross site navigations.
+ void PrepareForTransfer();
+ void CompleteTransfer(int host_id, AppCacheFrontend* frontend);
+
+ private:
+ friend class content::AppCacheHostTest;
+ friend class content::AppCacheStorageImplTest;
+ friend class content::AppCacheRequestHandlerTest;
+ friend class content::AppCacheUpdateJobTest;
+
+ AppCacheStatus GetStatus();
+ void LoadSelectedCache(int64 cache_id);
+ void LoadOrCreateGroup(const GURL& manifest_url);
+
+ // See public Associate*Host() methods above.
+ void AssociateCacheHelper(AppCache* cache, const GURL& manifest_url);
+
+ // AppCacheStorage::Delegate impl
+ void OnCacheLoaded(AppCache* cache, int64 cache_id) override;
+ void OnGroupLoaded(AppCacheGroup* group, const GURL& manifest_url) override;
+ // AppCacheServiceImpl::Observer impl
+ void OnServiceReinitialized(
+ AppCacheStorageReference* old_storage_ref) override;
+
+ void FinishCacheSelection(AppCache* cache, AppCacheGroup* group);
+ void DoPendingGetStatus();
+ void DoPendingStartUpdate();
+ void DoPendingSwapCache();
+
+ void ObserveGroupBeingUpdated(AppCacheGroup* group);
+
+ // AppCacheGroup::UpdateObserver methods.
+ void OnUpdateComplete(AppCacheGroup* group) override;
+
+ // Returns true if this host is for a dedicated worker context.
+ bool is_for_dedicated_worker() const {
+ return parent_host_id_ != kAppCacheNoHostId;
+ }
+
+ // Returns the parent context's host instance. This is only valid
+ // to call when this instance is_for_dedicated_worker.
+ AppCacheHost* GetParentAppCacheHost() const;
+
+ // Identifies the corresponding appcache host in the child process.
+ int host_id_;
+
+ // Information about the host that created this one; the manifest
+ // preferred by our creator influences which cache our main resource
+ // should be loaded from.
+ int spawning_host_id_;
+ int spawning_process_id_;
+ GURL preferred_manifest_url_;
+
+ // Hosts for dedicated workers are special cased to shunt
+ // request handling off to the dedicated worker's parent.
+ // The scriptable api is not accessible in dedicated workers
+ // so the other aspects of this class are not relevant for
+ // these special case instances.
+ int parent_host_id_;
+ int parent_process_id_;
+
+ // Defined prior to refs to AppCaches and Groups because destruction
+ // order matters, the disabled_storage_reference_ must outlive those
+ // objects. See additional comments for the storage_ member.
+ scoped_refptr<AppCacheStorageReference> disabled_storage_reference_;
+
+ // The cache associated with this host, if any.
+ scoped_refptr<AppCache> associated_cache_;
+
+ // Hold a reference to the newest complete cache (if associated cache is
+ // not the newest) to keep the newest cache in existence while the app cache
+ // group is in use. The newest complete cache may have no associated hosts
+ // holding any references to it and would otherwise be deleted prematurely.
+ scoped_refptr<AppCache> swappable_cache_;
+
+ // Keep a reference to the group being updated until the update completes.
+ scoped_refptr<AppCacheGroup> group_being_updated_;
+
+ // Similarly, keep a reference to the newest cache of the group until the
+ // update completes. When adding a new master entry to a cache that is not
+ // in use in any other host, this reference keeps the cache in memory.
+ scoped_refptr<AppCache> newest_cache_of_group_being_updated_;
+
+ // Keep a reference to the cache of the main resource so it survives frame
+ // navigations.
+ scoped_refptr<AppCache> main_resource_cache_;
+ int64 pending_main_resource_cache_id_;
+
+ // Cache loading is async, if we're loading a specific cache or group
+ // for the purposes of cache selection, one or the other of these will
+ // indicate which cache or group is being loaded.
+ int64 pending_selected_cache_id_;
+ GURL pending_selected_manifest_url_;
+
+ // Used to avoid stepping on pages controlled by ServiceWorkers.
+ bool is_cache_selection_enabled_;
+
+ // A new master entry to be added to the cache, may be empty.
+ GURL new_master_entry_url_;
+
+ // The frontend proxy to deliver notifications to the child process.
+ AppCacheFrontend* frontend_;
+
+ // Our central service object.
+ AppCacheServiceImpl* service_;
+
+ // And the equally central storage object, with a twist. In some error
+ // conditions the storage object gets recreated and reinitialized. The
+ // disabled_storage_reference_ (defined earlier) allows for cleanup of an
+ // instance that got disabled after we had latched onto it. In normal
+ // circumstances, disabled_storage_reference_ is expected to be NULL.
+ // When non-NULL both storage_ and disabled_storage_reference_ refer to the
+ // same instance.
+ AppCacheStorage* storage_;
+
+ // Since these are synchronous scriptable API calls in the client, there can
+ // only be one type of callback pending. Also, we have to wait until we have a
+ // cache selection prior to responding to these calls, as cache selection
+ // involves async loading of a cache or a group from storage.
+ GetStatusCallback pending_get_status_callback_;
+ StartUpdateCallback pending_start_update_callback_;
+ SwapCacheCallback pending_swap_cache_callback_;
+ void* pending_callback_param_;
+
+ // True if an intercept or fallback namespace resource was
+ // delivered as the main resource.
+ bool main_resource_was_namespace_entry_;
+ GURL namespace_entry_url_;
+
+ // True if requests for this host were blocked by a policy.
+ bool main_resource_blocked_;
+ GURL blocked_manifest_url_;
+
+ // Tells if info about associated cache is pending. Info is pending
+ // when update job has not returned success yet.
+ bool associated_cache_info_pending_;
+
+ // List of objects observing us.
+ ObserverList<Observer> observers_;
+
+ // Used to inform the QuotaManager of what origins are currently in use.
+ GURL origin_in_use_;
+
+ // First party url to be used in policy checks.
+ GURL first_party_url_;
+
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, CleanupUnusedGroup);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, QueueUpdate);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, Basic);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectNoCache);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, ForeignEntry);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, FailedCacheLoad);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, FailedGroupLoad);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SetSwappableCache);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, ForDedicatedWorker);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectCacheAllowed);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectCacheBlocked);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, CleanupUnusedCache);
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_HOST_H_
diff --git a/chromium/content/browser/appcache/appcache_host_unittest.cc b/chromium/content/browser/appcache/appcache_host_unittest.cc
index 6b9970dc4ff..817e8c0c924 100644
--- a/chromium/content/browser/appcache/appcache_host_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_host_unittest.cc
@@ -6,29 +6,15 @@
#include "base/bind_helpers.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_backend_impl.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_host.h"
#include "content/browser/appcache/mock_appcache_policy.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "net/url_request/url_request.h"
+#include "storage/browser/quota/quota_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_backend_impl.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_host.h"
-#include "webkit/browser/quota/quota_manager.h"
-
-using appcache::AppCache;
-using appcache::AppCacheBackendImpl;
-using appcache::AppCacheEntry;
-using appcache::AppCacheFrontend;
-using appcache::AppCacheGroup;
-using appcache::AppCacheHost;
-using appcache::kAppCacheNoCacheId;
-using appcache::APPCACHE_ERROR_EVENT;
-using appcache::APPCACHE_STATUS_OBSOLETE;
-using appcache::APPCACHE_OBSOLETE_EVENT;
-using appcache::APPCACHE_PROGRESS_EVENT;
-using appcache::AppCacheStatus;
-using appcache::APPCACHE_STATUS_UNCACHED;
namespace content {
@@ -50,88 +36,81 @@ class AppCacheHostTest : public testing::Test {
public:
MockFrontend()
: last_host_id_(-222), last_cache_id_(-222),
- last_status_(appcache::APPCACHE_STATUS_OBSOLETE),
- last_status_changed_(appcache::APPCACHE_STATUS_OBSOLETE),
- last_event_id_(appcache::APPCACHE_OBSOLETE_EVENT),
+ last_status_(APPCACHE_STATUS_OBSOLETE),
+ last_status_changed_(APPCACHE_STATUS_OBSOLETE),
+ last_event_id_(APPCACHE_OBSOLETE_EVENT),
content_blocked_(false) {
}
- virtual void OnCacheSelected(
- int host_id, const appcache::AppCacheInfo& info) OVERRIDE {
+ void OnCacheSelected(int host_id, const AppCacheInfo& info) override {
last_host_id_ = host_id;
last_cache_id_ = info.cache_id;
last_status_ = info.status;
}
- virtual void OnStatusChanged(const std::vector<int>& host_ids,
- appcache::AppCacheStatus status) OVERRIDE {
+ void OnStatusChanged(const std::vector<int>& host_ids,
+ AppCacheStatus status) override {
last_status_changed_ = status;
}
- virtual void OnEventRaised(const std::vector<int>& host_ids,
- appcache::AppCacheEventID event_id) OVERRIDE {
+ void OnEventRaised(const std::vector<int>& host_ids,
+ AppCacheEventID event_id) override {
last_event_id_ = event_id;
}
- virtual void OnErrorEventRaised(
- const std::vector<int>& host_ids,
- const appcache::AppCacheErrorDetails& details) OVERRIDE {
+ void OnErrorEventRaised(const std::vector<int>& host_ids,
+ const AppCacheErrorDetails& details) override {
last_event_id_ = APPCACHE_ERROR_EVENT;
}
- virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
- const GURL& url,
- int num_total,
- int num_complete) OVERRIDE {
+ void OnProgressEventRaised(const std::vector<int>& host_ids,
+ const GURL& url,
+ int num_total,
+ int num_complete) override {
last_event_id_ = APPCACHE_PROGRESS_EVENT;
}
- virtual void OnLogMessage(int host_id,
- appcache::AppCacheLogLevel log_level,
- const std::string& message) OVERRIDE {
- }
+ void OnLogMessage(int host_id,
+ AppCacheLogLevel log_level,
+ const std::string& message) override {}
- virtual void OnContentBlocked(int host_id,
- const GURL& manifest_url) OVERRIDE {
+ void OnContentBlocked(int host_id, const GURL& manifest_url) override {
content_blocked_ = true;
}
int last_host_id_;
int64 last_cache_id_;
- appcache::AppCacheStatus last_status_;
- appcache::AppCacheStatus last_status_changed_;
- appcache::AppCacheEventID last_event_id_;
+ AppCacheStatus last_status_;
+ AppCacheStatus last_status_changed_;
+ AppCacheEventID last_event_id_;
bool content_blocked_;
};
- class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
+ class MockQuotaManagerProxy : public storage::QuotaManagerProxy {
public:
MockQuotaManagerProxy() : QuotaManagerProxy(NULL, NULL) {}
// Not needed for our tests.
- virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {}
- virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type) OVERRIDE {}
- virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type,
- int64 delta) OVERRIDE {}
- virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type,
- bool enabled) OVERRIDE {}
- virtual void GetUsageAndQuota(
- base::SequencedTaskRunner* original_task_runner,
- const GURL& origin,
- quota::StorageType type,
- const GetUsageAndQuotaCallback& callback) OVERRIDE {}
-
- virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {
- inuse_[origin] += 1;
- }
-
- virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {
+ void RegisterClient(storage::QuotaClient* client) override {}
+ void NotifyStorageAccessed(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type) override {}
+ void NotifyStorageModified(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type,
+ int64 delta) override {}
+ void SetUsageCacheEnabled(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type,
+ bool enabled) override {}
+ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
+ const GURL& origin,
+ storage::StorageType type,
+ const GetUsageAndQuotaCallback& callback) override {}
+
+ void NotifyOriginInUse(const GURL& origin) override { inuse_[origin] += 1; }
+
+ void NotifyOriginNoLongerInUse(const GURL& origin) override {
inuse_[origin] -= 1;
}
@@ -147,7 +126,7 @@ class AppCacheHostTest : public testing::Test {
std::map<GURL, int> inuse_;
protected:
- virtual ~MockQuotaManagerProxy() {}
+ ~MockQuotaManagerProxy() override {}
};
void GetStatusCallback(AppCacheStatus status, void* param) {
@@ -172,9 +151,9 @@ class AppCacheHostTest : public testing::Test {
MockFrontend mock_frontend_;
// Mock callbacks we expect to receive from the 'host'
- appcache::GetStatusCallback get_status_callback_;
- appcache::StartUpdateCallback start_update_callback_;
- appcache::SwapCacheCallback swap_cache_callback_;
+ content::GetStatusCallback get_status_callback_;
+ content::StartUpdateCallback start_update_callback_;
+ content::SwapCacheCallback swap_cache_callback_;
AppCacheStatus last_status_result_;
bool last_swap_result_;
@@ -387,11 +366,11 @@ TEST_F(AppCacheHostTest, SetSwappableCache) {
host.AssociateCompleteCache(cache1);
EXPECT_FALSE(host.swappable_cache_.get()); // was same as associated cache
- EXPECT_EQ(appcache::APPCACHE_STATUS_IDLE, host.GetStatus());
+ EXPECT_EQ(APPCACHE_STATUS_IDLE, host.GetStatus());
// verify OnCacheSelected was called
EXPECT_EQ(host.host_id(), mock_frontend_.last_host_id_);
EXPECT_EQ(cache1->cache_id(), mock_frontend_.last_cache_id_);
- EXPECT_EQ(appcache::APPCACHE_STATUS_IDLE, mock_frontend_.last_status_);
+ EXPECT_EQ(APPCACHE_STATUS_IDLE, mock_frontend_.last_status_);
AppCache* cache2 = new AppCache(service_.storage(), 222);
cache2->set_complete(true);
diff --git a/chromium/content/browser/appcache/appcache_interceptor.cc b/chromium/content/browser/appcache/appcache_interceptor.cc
index ac7dbc3b607..adc6d2c6979 100644
--- a/chromium/content/browser/appcache/appcache_interceptor.cc
+++ b/chromium/content/browser/appcache/appcache_interceptor.cc
@@ -4,41 +4,63 @@
#include "content/browser/appcache/appcache_interceptor.h"
-#include "webkit/browser/appcache/appcache_backend_impl.h"
-#include "webkit/browser/appcache/appcache_host.h"
-#include "webkit/browser/appcache/appcache_request_handler.h"
-#include "webkit/browser/appcache/appcache_service_impl.h"
-#include "webkit/browser/appcache/appcache_url_request_job.h"
-#include "webkit/common/appcache/appcache_interfaces.h"
-
-using appcache::AppCacheBackendImpl;
-using appcache::AppCacheHost;
-using appcache::AppCacheRequestHandler;
-using appcache::AppCacheServiceImpl;
-using appcache::kAppCacheNoCacheId;
-using appcache::kAppCacheNoHostId;
+#include "content/browser/appcache/appcache_backend_impl.h"
+#include "content/browser/appcache/appcache_host.h"
+#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/common/appcache_interfaces.h"
namespace content {
+class AppCacheInterceptor::StartInterceptor
+ : public net::URLRequestInterceptor {
+ public:
+ StartInterceptor() {}
+ ~StartInterceptor() override {}
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (!handler)
+ return NULL;
+ return handler->MaybeLoadResource(request, network_delegate);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StartInterceptor);
+};
+
+
// static
AppCacheInterceptor* AppCacheInterceptor::GetInstance() {
return Singleton<AppCacheInterceptor>::get();
}
-void AppCacheInterceptor::SetHandler(
- net::URLRequest* request, AppCacheRequestHandler* handler) {
+// static
+scoped_ptr<net::URLRequestInterceptor>
+AppCacheInterceptor::CreateStartInterceptor() {
+ return scoped_ptr<net::URLRequestInterceptor>(
+ new StartInterceptor);
+}
+
+void AppCacheInterceptor::SetHandler(net::URLRequest* request,
+ AppCacheRequestHandler* handler) {
request->SetUserData(GetInstance(), handler); // request takes ownership
}
AppCacheRequestHandler* AppCacheInterceptor::GetHandler(
net::URLRequest* request) {
- return reinterpret_cast<AppCacheRequestHandler*>(
+ return static_cast<AppCacheRequestHandler*>(
request->GetUserData(GetInstance()));
}
void AppCacheInterceptor::SetExtraRequestInfo(
- net::URLRequest* request, AppCacheServiceImpl* service, int process_id,
- int host_id, ResourceType::Type resource_type) {
+ net::URLRequest* request,
+ AppCacheServiceImpl* service,
+ int process_id,
+ int host_id,
+ ResourceType resource_type) {
if (!service || (host_id == kAppCacheNoHostId))
return;
@@ -100,10 +122,8 @@ AppCacheInterceptor::~AppCacheInterceptor() {
net::URLRequestJob* AppCacheInterceptor::MaybeIntercept(
net::URLRequest* request, net::NetworkDelegate* network_delegate) {
- AppCacheRequestHandler* handler = GetHandler(request);
- if (!handler)
- return NULL;
- return handler->MaybeLoadResource(request, network_delegate);
+ // Intentionally empty, handled by class StartInterceptor.
+ return NULL;
}
net::URLRequestJob* AppCacheInterceptor::MaybeInterceptRedirect(
diff --git a/chromium/content/browser/appcache/appcache_interceptor.h b/chromium/content/browser/appcache/appcache_interceptor.h
index d8da18190f4..049fd7a5732 100644
--- a/chromium/content/browser/appcache/appcache_interceptor.h
+++ b/chromium/content/browser/appcache/appcache_interceptor.h
@@ -7,16 +7,14 @@
#include "base/memory/singleton.h"
#include "content/common/content_export.h"
+#include "content/public/common/resource_type.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_interceptor.h"
#include "url/gurl.h"
-#include "webkit/common/resource_type.h"
-namespace appcache {
+namespace content {
class AppCacheRequestHandler;
class AppCacheServiceImpl;
-}
-
-namespace content {
// An interceptor to hijack requests and potentially service them out of
// the appcache.
@@ -31,10 +29,10 @@ class CONTENT_EXPORT AppCacheInterceptor
// Must be called to make a request eligible for retrieval from an appcache.
static void SetExtraRequestInfo(net::URLRequest* request,
- appcache::AppCacheServiceImpl* service,
+ AppCacheServiceImpl* service,
int process_id,
int host_id,
- ResourceType::Type resource_type);
+ ResourceType resource_type);
// May be called after response headers are complete to retrieve extra
// info about the response.
@@ -51,28 +49,37 @@ class CONTENT_EXPORT AppCacheInterceptor
static AppCacheInterceptor* GetInstance();
+ // The appcache system employs two different interceptors. The singleton
+ // AppCacheInterceptor derives URLRequest::Interceptor and is used
+ // to hijack request handling upon receipt of the response or a redirect.
+ // A separate URLRequestInterceptor derivative is used to hijack handling
+ // at the very start of request processing. The separate handler allows the
+ // content lib to order its collection of net::URLRequestInterceptors.
+ static scoped_ptr<net::URLRequestInterceptor> CreateStartInterceptor();
+
protected:
// Override from net::URLRequest::Interceptor:
- virtual net::URLRequestJob* MaybeIntercept(
+ net::URLRequestJob* MaybeIntercept(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) OVERRIDE;
- virtual net::URLRequestJob* MaybeInterceptResponse(
+ net::NetworkDelegate* network_delegate) override;
+ net::URLRequestJob* MaybeInterceptResponse(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) OVERRIDE;
- virtual net::URLRequestJob* MaybeInterceptRedirect(
+ net::NetworkDelegate* network_delegate) override;
+ net::URLRequestJob* MaybeInterceptRedirect(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
- const GURL& location) OVERRIDE;
+ const GURL& location) override;
private:
friend struct DefaultSingletonTraits<AppCacheInterceptor>;
+ class StartInterceptor;
AppCacheInterceptor();
- virtual ~AppCacheInterceptor();
+ ~AppCacheInterceptor() override;
static void SetHandler(net::URLRequest* request,
- appcache::AppCacheRequestHandler* handler);
- static appcache::AppCacheRequestHandler* GetHandler(net::URLRequest* request);
+ AppCacheRequestHandler* handler);
+ static AppCacheRequestHandler* GetHandler(net::URLRequest* request);
DISALLOW_COPY_AND_ASSIGN(AppCacheInterceptor);
};
diff --git a/chromium/content/browser/appcache/appcache_manifest_parser.cc b/chromium/content/browser/appcache/appcache_manifest_parser.cc
new file mode 100644
index 00000000000..99f5e87f379
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_manifest_parser.cc
@@ -0,0 +1,382 @@
+// 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.
+//
+// This is a port of ManifestParser.cc from WebKit/WebCore/loader/appcache.
+
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "content/browser/appcache/appcache_manifest_parser.h"
+
+#include "base/command_line.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+// Helper function used to identify 'isPattern' annotations.
+bool HasPatternMatchingAnnotation(const wchar_t* line_p,
+ const wchar_t* line_end) {
+ // Skip whitespace separating the resource url from the annotation.
+ // Note: trailing whitespace has already been trimmed from the line.
+ while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
+ ++line_p;
+ if (line_p == line_end)
+ return false;
+ std::wstring annotation(line_p, line_end - line_p);
+ return annotation == L"isPattern";
+}
+
+}
+
+enum Mode {
+ EXPLICIT,
+ INTERCEPT,
+ FALLBACK,
+ ONLINE_WHITELIST,
+ UNKNOWN_MODE,
+};
+
+enum InterceptVerb {
+ RETURN,
+ EXECUTE,
+ UNKNOWN_VERB,
+};
+
+AppCacheManifest::AppCacheManifest()
+ : online_whitelist_all(false),
+ did_ignore_intercept_namespaces(false) {
+}
+
+AppCacheManifest::~AppCacheManifest() {}
+
+bool ParseManifest(const GURL& manifest_url, const char* data, int length,
+ ParseMode parse_mode, AppCacheManifest& manifest) {
+ // This is an implementation of the parsing algorithm specified in
+ // the HTML5 offline web application docs:
+ // http://www.w3.org/TR/html5/offline.html
+ // Do not modify it without consulting those docs.
+ // Though you might be tempted to convert these wstrings to UTF-8 or
+ // base::string16, this implementation seems simpler given the constraints.
+
+ const wchar_t kSignature[] = L"CACHE MANIFEST";
+ const size_t kSignatureLength = arraysize(kSignature) - 1;
+ const wchar_t kChromiumSignature[] = L"CHROMIUM CACHE MANIFEST";
+ const size_t kChromiumSignatureLength = arraysize(kChromiumSignature) - 1;
+
+ DCHECK(manifest.explicit_urls.empty());
+ DCHECK(manifest.fallback_namespaces.empty());
+ DCHECK(manifest.online_whitelist_namespaces.empty());
+ DCHECK(!manifest.online_whitelist_all);
+ DCHECK(!manifest.did_ignore_intercept_namespaces);
+
+ Mode mode = EXPLICIT;
+
+ std::wstring data_string;
+ // TODO(jennb): cannot do UTF8ToWide(data, length, &data_string);
+ // until UTF8ToWide uses 0xFFFD Unicode replacement character.
+ base::CodepageToWide(std::string(data, length), base::kCodepageUTF8,
+ base::OnStringConversionError::SUBSTITUTE, &data_string);
+ const wchar_t* p = data_string.c_str();
+ const wchar_t* end = p + data_string.length();
+
+ // Look for the magic signature: "^\xFEFF?CACHE MANIFEST[ \t]?"
+ // Example: "CACHE MANIFEST #comment" is a valid signature.
+ // Example: "CACHE MANIFEST;V2" is not.
+
+ // When the input data starts with a UTF-8 Byte-Order-Mark
+ // (0xEF, 0xBB, 0xBF), the UTF8ToWide() function converts it to a
+ // Unicode BOM (U+FEFF). Skip a converted Unicode BOM if it exists.
+ int bom_offset = 0;
+ if (!data_string.empty() && data_string[0] == 0xFEFF) {
+ bom_offset = 1;
+ ++p;
+ }
+
+ if (p >= end)
+ return false;
+
+ // Check for a supported signature and skip p past it.
+ if (0 == data_string.compare(bom_offset, kSignatureLength,
+ kSignature)) {
+ p += kSignatureLength;
+ } else if (0 == data_string.compare(bom_offset, kChromiumSignatureLength,
+ kChromiumSignature)) {
+ p += kChromiumSignatureLength;
+ } else {
+ return false;
+ }
+
+ // Character after "CACHE MANIFEST" must be whitespace.
+ if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
+ return false;
+
+ // Skip to the end of the line.
+ while (p < end && *p != '\r' && *p != '\n')
+ ++p;
+
+ while (1) {
+ // Skip whitespace
+ while (p < end && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t'))
+ ++p;
+
+ if (p == end)
+ break;
+
+ const wchar_t* line_start = p;
+
+ // Find the end of the line
+ while (p < end && *p != '\r' && *p != '\n')
+ ++p;
+
+ // Check if we have a comment
+ if (*line_start == '#')
+ continue;
+
+ // Get rid of trailing whitespace
+ const wchar_t* tmp = p - 1;
+ while (tmp > line_start && (*tmp == ' ' || *tmp == '\t'))
+ --tmp;
+
+ std::wstring line(line_start, tmp - line_start + 1);
+
+ if (line == L"CACHE:") {
+ mode = EXPLICIT;
+ } else if (line == L"FALLBACK:") {
+ mode = FALLBACK;
+ } else if (line == L"NETWORK:") {
+ mode = ONLINE_WHITELIST;
+ } else if (line == L"CHROMIUM-INTERCEPT:") {
+ mode = INTERCEPT;
+ } else if (*(line.end() - 1) == ':') {
+ mode = UNKNOWN_MODE;
+ } else if (mode == UNKNOWN_MODE) {
+ continue;
+ } else if (line == L"*" && mode == ONLINE_WHITELIST) {
+ manifest.online_whitelist_all = true;
+ continue;
+ } else if (mode == EXPLICIT || mode == ONLINE_WHITELIST) {
+ const wchar_t *line_p = line.c_str();
+ const wchar_t *line_end = line_p + line.length();
+
+ // Look for whitespace separating the URL from subsequent ignored tokens.
+ while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
+ ++line_p;
+
+ base::string16 url16;
+ base::WideToUTF16(line.c_str(), line_p - line.c_str(), &url16);
+ GURL url = manifest_url.Resolve(url16);
+ if (!url.is_valid())
+ continue;
+ if (url.has_ref()) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ url = url.ReplaceComponents(replacements);
+ }
+
+ // Scheme component must be the same as the manifest URL's.
+ if (url.scheme() != manifest_url.scheme()) {
+ continue;
+ }
+
+ // See http://code.google.com/p/chromium/issues/detail?id=69594
+ // We willfully violate the HTML5 spec at this point in order
+ // to support the appcaching of cross-origin HTTPS resources.
+ // Per the spec, EXPLICIT cross-origin HTTS resources should be
+ // ignored here. We've opted for a milder constraint and allow
+ // caching unless the resource has a "no-store" header. That
+ // condition is enforced in AppCacheUpdateJob.
+
+ if (mode == EXPLICIT) {
+ manifest.explicit_urls.insert(url.spec());
+ } else {
+ bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
+ manifest.online_whitelist_namespaces.push_back(
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, url, GURL(),
+ is_pattern));
+ }
+ } else if (mode == INTERCEPT) {
+ if (parse_mode != PARSE_MANIFEST_ALLOWING_INTERCEPTS) {
+ manifest.did_ignore_intercept_namespaces = true;
+ continue;
+ }
+
+ // Lines of the form,
+ // <urlnamespace> <intercept_type> <targeturl>
+ const wchar_t* line_p = line.c_str();
+ const wchar_t* line_end = line_p + line.length();
+
+ // Look for first whitespace separating the url namespace from
+ // the intercept type.
+ while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
+ ++line_p;
+
+ if (line_p == line_end)
+ continue; // There was no whitespace separating the URLs.
+
+ base::string16 namespace_url16;
+ base::WideToUTF16(line.c_str(), line_p - line.c_str(), &namespace_url16);
+ GURL namespace_url = manifest_url.Resolve(namespace_url16);
+ if (!namespace_url.is_valid())
+ continue;
+ if (namespace_url.has_ref()) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ namespace_url = namespace_url.ReplaceComponents(replacements);
+ }
+
+ // The namespace URL must have the same scheme, host and port
+ // as the manifest's URL.
+ if (manifest_url.GetOrigin() != namespace_url.GetOrigin())
+ continue;
+
+ // Skip whitespace separating namespace from the type.
+ while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
+ ++line_p;
+
+ // Look for whitespace separating the type from the target url.
+ const wchar_t* type_start = line_p;
+ while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
+ ++line_p;
+
+ // Look for a type value we understand, otherwise skip the line.
+ InterceptVerb verb = UNKNOWN_VERB;
+ std::wstring type(type_start, line_p - type_start);
+ if (type == L"return") {
+ verb = RETURN;
+ } else if (type == L"execute" &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ kEnableExecutableHandlers)) {
+ verb = EXECUTE;
+ }
+ if (verb == UNKNOWN_VERB)
+ continue;
+
+ // Skip whitespace separating type from the target_url.
+ while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
+ ++line_p;
+
+ // Look for whitespace separating the URL from subsequent ignored tokens.
+ const wchar_t* target_url_start = line_p;
+ while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
+ ++line_p;
+
+ base::string16 target_url16;
+ base::WideToUTF16(target_url_start, line_p - target_url_start,
+ &target_url16);
+ GURL target_url = manifest_url.Resolve(target_url16);
+ if (!target_url.is_valid())
+ continue;
+
+ if (target_url.has_ref()) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ target_url = target_url.ReplaceComponents(replacements);
+ }
+ if (manifest_url.GetOrigin() != target_url.GetOrigin())
+ continue;
+
+ bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
+ manifest.intercept_namespaces.push_back(
+ AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, namespace_url,
+ target_url, is_pattern, verb == EXECUTE));
+ } else if (mode == FALLBACK) {
+ const wchar_t* line_p = line.c_str();
+ const wchar_t* line_end = line_p + line.length();
+
+ // Look for whitespace separating the two URLs
+ while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
+ ++line_p;
+
+ if (line_p == line_end) {
+ // There was no whitespace separating the URLs.
+ continue;
+ }
+
+ base::string16 namespace_url16;
+ base::WideToUTF16(line.c_str(), line_p - line.c_str(), &namespace_url16);
+ GURL namespace_url = manifest_url.Resolve(namespace_url16);
+ if (!namespace_url.is_valid())
+ continue;
+ if (namespace_url.has_ref()) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ namespace_url = namespace_url.ReplaceComponents(replacements);
+ }
+
+ // Fallback namespace URL must have the same scheme, host and port
+ // as the manifest's URL.
+ if (manifest_url.GetOrigin() != namespace_url.GetOrigin()) {
+ continue;
+ }
+
+ // Skip whitespace separating fallback namespace from URL.
+ while (line_p < line_end && (*line_p == '\t' || *line_p == ' '))
+ ++line_p;
+
+ // Look for whitespace separating the URL from subsequent ignored tokens.
+ const wchar_t* fallback_start = line_p;
+ while (line_p < line_end && *line_p != '\t' && *line_p != ' ')
+ ++line_p;
+
+ base::string16 fallback_url16;
+ base::WideToUTF16(fallback_start, line_p - fallback_start,
+ &fallback_url16);
+ GURL fallback_url = manifest_url.Resolve(fallback_url16);
+ if (!fallback_url.is_valid())
+ continue;
+ if (fallback_url.has_ref()) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ fallback_url = fallback_url.ReplaceComponents(replacements);
+ }
+
+ // Fallback entry URL must have the same scheme, host and port
+ // as the manifest's URL.
+ if (manifest_url.GetOrigin() != fallback_url.GetOrigin()) {
+ continue;
+ }
+
+ bool is_pattern = HasPatternMatchingAnnotation(line_p, line_end);
+
+ // Store regardless of duplicate namespace URL. Only first match
+ // will ever be used.
+ manifest.fallback_namespaces.push_back(
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, namespace_url,
+ fallback_url, is_pattern));
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ return true;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_manifest_parser.h b/chromium/content/browser/appcache/appcache_manifest_parser.h
new file mode 100644
index 00000000000..19685f8e705
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_manifest_parser.h
@@ -0,0 +1,72 @@
+// 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.
+//
+// This is a port of ManifestParser.h from WebKit/WebCore/loader/appcache.
+
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_MANIFEST_PARSER_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_MANIFEST_PARSER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "content/common/appcache_interfaces.h"
+#include "content/common/content_export.h"
+
+class GURL;
+
+namespace content {
+
+struct CONTENT_EXPORT AppCacheManifest {
+ AppCacheManifest();
+ ~AppCacheManifest();
+
+ base::hash_set<std::string> explicit_urls;
+ AppCacheNamespaceVector intercept_namespaces;
+ AppCacheNamespaceVector fallback_namespaces;
+ AppCacheNamespaceVector online_whitelist_namespaces;
+ bool online_whitelist_all;
+ bool did_ignore_intercept_namespaces;
+};
+
+enum ParseMode {
+ PARSE_MANIFEST_PER_STANDARD,
+ PARSE_MANIFEST_ALLOWING_INTERCEPTS
+};
+
+CONTENT_EXPORT bool ParseManifest(
+ const GURL& manifest_url,
+ const char* data,
+ int length,
+ ParseMode parse_mode,
+ AppCacheManifest& manifest);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_MANIFEST_PARSER_H_
diff --git a/chromium/content/browser/appcache/manifest_parser_unittest.cc b/chromium/content/browser/appcache/appcache_manifest_parser_unittest.cc
index 8a44376d774..6dd8c279121 100644
--- a/chromium/content/browser/appcache/manifest_parser_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_manifest_parser_unittest.cc
@@ -4,17 +4,9 @@
#include <string>
+#include "content/browser/appcache/appcache_manifest_parser.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/appcache/manifest_parser.h"
-
-using appcache::Manifest;
-using appcache::NamespaceVector;
-using appcache::APPCACHE_FALLBACK_NAMESPACE;
-using appcache::APPCACHE_INTERCEPT_NAMESPACE;
-using appcache::APPCACHE_NETWORK_NAMESPACE;
-using appcache::PARSE_MANIFEST_ALLOWING_INTERCEPTS;
-using appcache::PARSE_MANIFEST_PER_STANDARD;
namespace content {
@@ -23,7 +15,7 @@ class AppCacheManifestParserTest : public testing::Test {
TEST(AppCacheManifestParserTest, NoData) {
GURL url;
- Manifest manifest;
+ AppCacheManifest manifest;
EXPECT_FALSE(ParseManifest(url, "", 0,
PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
EXPECT_FALSE(ParseManifest(url, "CACHE MANIFEST\r", 0, // Len is 0.
@@ -32,7 +24,7 @@ TEST(AppCacheManifestParserTest, NoData) {
TEST(AppCacheManifestParserTest, CheckSignature) {
GURL url;
- Manifest manifest;
+ AppCacheManifest manifest;
const std::string kBadSignatures[] = {
"foo",
@@ -71,7 +63,7 @@ TEST(AppCacheManifestParserTest, CheckSignature) {
}
TEST(AppCacheManifestParserTest, NoManifestUrl) {
- Manifest manifest;
+ AppCacheManifest manifest;
const std::string kData("CACHE MANIFEST\r"
"relative/tobase.com\r"
"http://absolute.com/addme.com");
@@ -85,7 +77,7 @@ TEST(AppCacheManifestParserTest, NoManifestUrl) {
}
TEST(AppCacheManifestParserTest, ExplicitUrls) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("http://www.foo.com");
const std::string kData("CACHE MANIFEST\r"
"relative/one\r"
@@ -122,7 +114,7 @@ TEST(AppCacheManifestParserTest, ExplicitUrls) {
EXPECT_TRUE(urls.find("http://www.foo.com/*") != urls.end());
// We should get the same results with intercepts disallowed.
- manifest = Manifest();
+ manifest = AppCacheManifest();
EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
PARSE_MANIFEST_PER_STANDARD, manifest));
EXPECT_TRUE(manifest.fallback_namespaces.empty());
@@ -141,7 +133,7 @@ TEST(AppCacheManifestParserTest, ExplicitUrls) {
}
TEST(AppCacheManifestParserTest, WhitelistUrls) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("http://www.bar.com");
const std::string kData("CACHE MANIFEST\r"
"NETWORK:\r"
@@ -167,7 +159,7 @@ TEST(AppCacheManifestParserTest, WhitelistUrls) {
EXPECT_TRUE(manifest.intercept_namespaces.empty());
EXPECT_FALSE(manifest.online_whitelist_all);
- const NamespaceVector& online = manifest.online_whitelist_namespaces;
+ const AppCacheNamespaceVector& online = manifest.online_whitelist_namespaces;
const size_t kExpected = 6;
ASSERT_EQ(kExpected, online.size());
EXPECT_EQ(APPCACHE_NETWORK_NAMESPACE, online[0].type);
@@ -182,7 +174,7 @@ TEST(AppCacheManifestParserTest, WhitelistUrls) {
}
TEST(AppCacheManifestParserTest, FallbackUrls) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("http://glorp.com");
const std::string kData("CACHE MANIFEST\r"
"# a comment\r"
@@ -213,7 +205,7 @@ TEST(AppCacheManifestParserTest, FallbackUrls) {
EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
EXPECT_FALSE(manifest.online_whitelist_all);
- const NamespaceVector& fallbacks = manifest.fallback_namespaces;
+ const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
const size_t kExpected = 5;
ASSERT_EQ(kExpected, fallbacks.size());
EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
@@ -246,7 +238,7 @@ TEST(AppCacheManifestParserTest, FallbackUrls) {
}
TEST(AppCacheManifestParserTest, FallbackUrlsWithPort) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("http://www.portme.com:1234");
const std::string kData("CACHE MANIFEST\r"
"FALLBACK:\r"
@@ -264,7 +256,7 @@ TEST(AppCacheManifestParserTest, FallbackUrlsWithPort) {
EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
EXPECT_FALSE(manifest.online_whitelist_all);
- const NamespaceVector& fallbacks = manifest.fallback_namespaces;
+ const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
const size_t kExpected = 3;
ASSERT_EQ(kExpected, fallbacks.size());
EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
@@ -287,7 +279,7 @@ TEST(AppCacheManifestParserTest, FallbackUrlsWithPort) {
}
TEST(AppCacheManifestParserTest, InterceptUrls) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("http://www.portme.com:1234");
const std::string kData("CHROMIUM CACHE MANIFEST\r"
"CHROMIUM-INTERCEPT:\r"
@@ -308,7 +300,7 @@ TEST(AppCacheManifestParserTest, InterceptUrls) {
EXPECT_TRUE(manifest.online_whitelist_namespaces.empty());
EXPECT_FALSE(manifest.online_whitelist_all);
- const NamespaceVector& intercepts = manifest.intercept_namespaces;
+ const AppCacheNamespaceVector& intercepts = manifest.intercept_namespaces;
const size_t kExpected = 3;
ASSERT_EQ(kExpected, intercepts.size());
EXPECT_EQ(APPCACHE_INTERCEPT_NAMESPACE, intercepts[0].type);
@@ -328,7 +320,7 @@ TEST(AppCacheManifestParserTest, InterceptUrls) {
intercepts[2].target_url);
// Disallow intercepts ths time.
- manifest = Manifest();
+ manifest = AppCacheManifest();
EXPECT_TRUE(ParseManifest(kUrl, kData.c_str(), kData.length(),
PARSE_MANIFEST_PER_STANDARD, manifest));
EXPECT_TRUE(manifest.fallback_namespaces.empty());
@@ -339,7 +331,7 @@ TEST(AppCacheManifestParserTest, InterceptUrls) {
}
TEST(AppCacheManifestParserTest, ComboUrls) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("http://combo.com:42");
const std::string kData("CACHE MANIFEST\r"
"relative/explicit-1\r"
@@ -372,7 +364,7 @@ TEST(AppCacheManifestParserTest, ComboUrls) {
EXPECT_TRUE(urls.find("http://combo.com:99/explicit-2") != urls.end());
EXPECT_TRUE(urls.find("http://www.diff.com/explicit-3") != urls.end());
- const NamespaceVector& online = manifest.online_whitelist_namespaces;
+ const AppCacheNamespaceVector& online = manifest.online_whitelist_namespaces;
expected = 4;
ASSERT_EQ(expected, online.size());
EXPECT_EQ(GURL("http://combo.com/whitelist-1"),
@@ -384,7 +376,7 @@ TEST(AppCacheManifestParserTest, ComboUrls) {
EXPECT_EQ(GURL("http://combo.com:99/whitelist-4"),
online[3].namespace_url);
- const NamespaceVector& fallbacks = manifest.fallback_namespaces;
+ const AppCacheNamespaceVector& fallbacks = manifest.fallback_namespaces;
expected = 2;
ASSERT_EQ(expected, fallbacks.size());
EXPECT_EQ(APPCACHE_FALLBACK_NAMESPACE, fallbacks[0].type);
@@ -402,7 +394,7 @@ TEST(AppCacheManifestParserTest, ComboUrls) {
}
TEST(AppCacheManifestParserTest, UnusualUtf8) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("http://bad.com");
const std::string kData("CACHE MANIFEST\r"
"\xC0" "invalidutf8\r"
@@ -415,7 +407,7 @@ TEST(AppCacheManifestParserTest, UnusualUtf8) {
}
TEST(AppCacheManifestParserTest, IgnoreAfterSpace) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("http://smorg.borg");
const std::string kData(
"CACHE MANIFEST\r"
@@ -428,7 +420,7 @@ TEST(AppCacheManifestParserTest, IgnoreAfterSpace) {
}
TEST(AppCacheManifestParserTest, DifferentOriginUrlWithSecureScheme) {
- Manifest manifest;
+ AppCacheManifest manifest;
const GURL kUrl("https://www.foo.com");
const std::string kData("CACHE MANIFEST\r"
"CACHE: \r"
@@ -474,7 +466,7 @@ TEST(AppCacheManifestParserTest, PatternMatching) {
"http://foo.com/network_pattern* isPattern\r");
- Manifest manifest;
+ AppCacheManifest manifest;
EXPECT_TRUE(ParseManifest(kUrl, kManifestBody.c_str(),
kManifestBody.length(),
PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
diff --git a/chromium/content/browser/appcache/appcache_policy.h b/chromium/content/browser/appcache/appcache_policy.h
new file mode 100644
index 00000000000..e7ef6f1b7e5
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_policy.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_POLICY_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_POLICY_H_
+
+class GURL;
+
+namespace content {
+
+class AppCachePolicy {
+ public:
+ AppCachePolicy() {}
+
+ // Called prior to loading a main resource from the appache.
+ // Returns true if allowed. This is expected to return immediately
+ // without any user prompt.
+ virtual bool CanLoadAppCache(const GURL& manifest_url,
+ const GURL& first_party) = 0;
+
+ // Called prior to creating a new appcache. Returns true if allowed.
+ virtual bool CanCreateAppCache(const GURL& manifest_url,
+ const GURL& first_party) = 0;
+
+ protected:
+ ~AppCachePolicy() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_POLICY_H_
diff --git a/chromium/content/browser/appcache/appcache_quota_client.cc b/chromium/content/browser/appcache/appcache_quota_client.cc
new file mode 100644
index 00000000000..cff86402674
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_quota_client.cc
@@ -0,0 +1,251 @@
+// 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/appcache/appcache_quota_client.h"
+
+#include <algorithm>
+#include <map>
+#include <set>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+
+using storage::QuotaClient;
+
+namespace {
+storage::QuotaStatusCode NetErrorCodeToQuotaStatus(int code) {
+ if (code == net::OK)
+ return storage::kQuotaStatusOk;
+ else if (code == net::ERR_ABORTED)
+ return storage::kQuotaErrorAbort;
+ else
+ return storage::kQuotaStatusUnknown;
+}
+
+void RunFront(content::AppCacheQuotaClient::RequestQueue* queue) {
+ base::Closure request = queue->front();
+ queue->pop_front();
+ request.Run();
+}
+} // namespace
+
+namespace content {
+
+AppCacheQuotaClient::AppCacheQuotaClient(AppCacheServiceImpl* service)
+ : service_(service),
+ appcache_is_ready_(false),
+ quota_manager_is_destroyed_(false) {
+}
+
+AppCacheQuotaClient::~AppCacheQuotaClient() {
+ DCHECK(pending_batch_requests_.empty());
+ DCHECK(pending_serial_requests_.empty());
+ DCHECK(current_delete_request_callback_.is_null());
+}
+
+QuotaClient::ID AppCacheQuotaClient::id() const {
+ return kAppcache;
+}
+
+void AppCacheQuotaClient::OnQuotaManagerDestroyed() {
+ DeletePendingRequests();
+ if (!current_delete_request_callback_.is_null()) {
+ current_delete_request_callback_.Reset();
+ GetServiceDeleteCallback()->Cancel();
+ }
+
+ quota_manager_is_destroyed_ = true;
+ if (!service_)
+ delete this;
+}
+
+void AppCacheQuotaClient::GetOriginUsage(const GURL& origin,
+ storage::StorageType type,
+ const GetUsageCallback& callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(!quota_manager_is_destroyed_);
+
+ if (!service_) {
+ callback.Run(0);
+ return;
+ }
+
+ if (!appcache_is_ready_) {
+ pending_batch_requests_.push_back(
+ base::Bind(&AppCacheQuotaClient::GetOriginUsage,
+ base::Unretained(this), origin, type, callback));
+ return;
+ }
+
+ if (type != storage::kStorageTypeTemporary) {
+ callback.Run(0);
+ return;
+ }
+
+ const AppCacheStorage::UsageMap* map = GetUsageMap();
+ AppCacheStorage::UsageMap::const_iterator found = map->find(origin);
+ if (found == map->end()) {
+ callback.Run(0);
+ return;
+ }
+ callback.Run(found->second);
+}
+
+void AppCacheQuotaClient::GetOriginsForType(
+ storage::StorageType type,
+ const GetOriginsCallback& callback) {
+ GetOriginsHelper(type, std::string(), callback);
+}
+
+void AppCacheQuotaClient::GetOriginsForHost(
+ storage::StorageType type,
+ const std::string& host,
+ const GetOriginsCallback& callback) {
+ DCHECK(!callback.is_null());
+ if (host.empty()) {
+ callback.Run(std::set<GURL>());
+ return;
+ }
+ GetOriginsHelper(type, host, callback);
+}
+
+void AppCacheQuotaClient::DeleteOriginData(const GURL& origin,
+ storage::StorageType type,
+ const DeletionCallback& callback) {
+ DCHECK(!quota_manager_is_destroyed_);
+
+ if (!service_) {
+ callback.Run(storage::kQuotaErrorAbort);
+ return;
+ }
+
+ if (!appcache_is_ready_ || !current_delete_request_callback_.is_null()) {
+ pending_serial_requests_.push_back(
+ base::Bind(&AppCacheQuotaClient::DeleteOriginData,
+ base::Unretained(this), origin, type, callback));
+ return;
+ }
+
+ current_delete_request_callback_ = callback;
+ if (type != storage::kStorageTypeTemporary) {
+ DidDeleteAppCachesForOrigin(net::OK);
+ return;
+ }
+
+ service_->DeleteAppCachesForOrigin(
+ origin, GetServiceDeleteCallback()->callback());
+}
+
+bool AppCacheQuotaClient::DoesSupport(storage::StorageType type) const {
+ return type == storage::kStorageTypeTemporary;
+}
+
+void AppCacheQuotaClient::DidDeleteAppCachesForOrigin(int rv) {
+ DCHECK(service_);
+ if (quota_manager_is_destroyed_)
+ return;
+
+ // Finish the request by calling our callers callback.
+ current_delete_request_callback_.Run(NetErrorCodeToQuotaStatus(rv));
+ current_delete_request_callback_.Reset();
+ if (pending_serial_requests_.empty())
+ return;
+
+ // Start the next in the queue.
+ RunFront(&pending_serial_requests_);
+}
+
+void AppCacheQuotaClient::GetOriginsHelper(storage::StorageType type,
+ const std::string& opt_host,
+ const GetOriginsCallback& callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(!quota_manager_is_destroyed_);
+
+ if (!service_) {
+ callback.Run(std::set<GURL>());
+ return;
+ }
+
+ if (!appcache_is_ready_) {
+ pending_batch_requests_.push_back(
+ base::Bind(&AppCacheQuotaClient::GetOriginsHelper,
+ base::Unretained(this), type, opt_host, callback));
+ return;
+ }
+
+ if (type != storage::kStorageTypeTemporary) {
+ callback.Run(std::set<GURL>());
+ return;
+ }
+
+ const AppCacheStorage::UsageMap* map = GetUsageMap();
+ std::set<GURL> origins;
+ for (AppCacheStorage::UsageMap::const_iterator iter = map->begin();
+ iter != map->end(); ++iter) {
+ if (opt_host.empty() || iter->first.host() == opt_host)
+ origins.insert(iter->first);
+ }
+ callback.Run(origins);
+}
+
+void AppCacheQuotaClient::ProcessPendingRequests() {
+ DCHECK(appcache_is_ready_);
+ while (!pending_batch_requests_.empty())
+ RunFront(&pending_batch_requests_);
+
+ if (!pending_serial_requests_.empty())
+ RunFront(&pending_serial_requests_);
+}
+
+void AppCacheQuotaClient::DeletePendingRequests() {
+ pending_batch_requests_.clear();
+ pending_serial_requests_.clear();
+}
+
+const AppCacheStorage::UsageMap* AppCacheQuotaClient::GetUsageMap() {
+ DCHECK(service_);
+ return service_->storage()->usage_map();
+}
+
+net::CancelableCompletionCallback*
+AppCacheQuotaClient::GetServiceDeleteCallback() {
+ // Lazily created due to CancelableCompletionCallback's threading
+ // restrictions, there is no way to detach from the thread created on.
+ if (!service_delete_callback_) {
+ service_delete_callback_.reset(
+ new net::CancelableCompletionCallback(
+ base::Bind(&AppCacheQuotaClient::DidDeleteAppCachesForOrigin,
+ base::Unretained(this))));
+ }
+ return service_delete_callback_.get();
+}
+
+void AppCacheQuotaClient::NotifyAppCacheReady() {
+ // Can reoccur during reinitialization.
+ if (!appcache_is_ready_) {
+ appcache_is_ready_ = true;
+ ProcessPendingRequests();
+ }
+}
+
+void AppCacheQuotaClient::NotifyAppCacheDestroyed() {
+ service_ = NULL;
+ while (!pending_batch_requests_.empty())
+ RunFront(&pending_batch_requests_);
+
+ while (!pending_serial_requests_.empty())
+ RunFront(&pending_serial_requests_);
+
+ if (!current_delete_request_callback_.is_null()) {
+ current_delete_request_callback_.Run(storage::kQuotaErrorAbort);
+ current_delete_request_callback_.Reset();
+ GetServiceDeleteCallback()->Cancel();
+ }
+
+ if (quota_manager_is_destroyed_)
+ delete this;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_quota_client.h b/chromium/content/browser/appcache/appcache_quota_client.h
new file mode 100644
index 00000000000..2af0fbe29bc
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_quota_client.h
@@ -0,0 +1,94 @@
+// 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_APPCACHE_APPCACHE_QUOTA_CLIENT_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_QUOTA_CLIENT_H_
+
+#include <deque>
+#include <map>
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/appcache/appcache_storage.h"
+#include "content/common/content_export.h"
+#include "net/base/completion_callback.h"
+#include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_task.h"
+#include "storage/common/quota/quota_types.h"
+
+namespace content {
+class AppCacheQuotaClientTest;
+class AppCacheServiceImpl;
+class AppCacheStorageImpl;
+
+// A QuotaClient implementation to integrate the appcache service
+// with the quota management system. The QuotaClient interface is
+// used on the IO thread by the quota manager. This class deletes
+// itself when both the quota manager and the appcache service have
+// been destroyed.
+class AppCacheQuotaClient : public storage::QuotaClient {
+ public:
+ typedef std::deque<base::Closure> RequestQueue;
+
+ ~AppCacheQuotaClient() override;
+
+ // QuotaClient method overrides
+ ID id() const override;
+ void OnQuotaManagerDestroyed() override;
+ void GetOriginUsage(const GURL& origin,
+ storage::StorageType type,
+ const GetUsageCallback& callback) override;
+ void GetOriginsForType(storage::StorageType type,
+ const GetOriginsCallback& callback) override;
+ void GetOriginsForHost(storage::StorageType type,
+ const std::string& host,
+ const GetOriginsCallback& callback) override;
+ void DeleteOriginData(const GURL& origin,
+ storage::StorageType type,
+ const DeletionCallback& callback) override;
+ bool DoesSupport(storage::StorageType type) const override;
+
+ private:
+ friend class content::AppCacheQuotaClientTest;
+ friend class AppCacheServiceImpl; // for NotifyAppCacheIsDestroyed
+ friend class AppCacheStorageImpl; // for NotifyAppCacheIsReady
+
+ CONTENT_EXPORT
+ explicit AppCacheQuotaClient(AppCacheServiceImpl* service);
+
+ void DidDeleteAppCachesForOrigin(int rv);
+ void GetOriginsHelper(storage::StorageType type,
+ const std::string& opt_host,
+ const GetOriginsCallback& callback);
+ void ProcessPendingRequests();
+ void DeletePendingRequests();
+ const AppCacheStorage::UsageMap* GetUsageMap();
+ net::CancelableCompletionCallback* GetServiceDeleteCallback();
+
+ // For use by appcache internals during initialization and shutdown.
+ CONTENT_EXPORT void NotifyAppCacheReady();
+ CONTENT_EXPORT void NotifyAppCacheDestroyed();
+
+ // Prior to appcache service being ready, we have to queue
+ // up reqeusts and defer acting on them until we're ready.
+ RequestQueue pending_batch_requests_;
+ RequestQueue pending_serial_requests_;
+
+ // And once it's ready, we can only handle one delete request at a time,
+ // so we queue up additional requests while one is in already in progress.
+ DeletionCallback current_delete_request_callback_;
+ scoped_ptr<net::CancelableCompletionCallback> service_delete_callback_;
+
+ AppCacheServiceImpl* service_;
+ bool appcache_is_ready_;
+ bool quota_manager_is_destroyed_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheQuotaClient);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_QUOTA_CLIENT_H_
diff --git a/chromium/content/browser/appcache/appcache_quota_client_unittest.cc b/chromium/content/browser/appcache/appcache_quota_client_unittest.cc
index 3a32e95dd2f..a453ee1c773 100644
--- a/chromium/content/browser/appcache/appcache_quota_client_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_quota_client_unittest.cc
@@ -8,18 +8,16 @@
#include "base/bind.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
+#include "content/browser/appcache/appcache_quota_client.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache_quota_client.h"
-
-using appcache::AppCacheQuotaClient;
namespace content {
// Declared to shorten the line lengths.
-static const quota::StorageType kTemp = quota::kStorageTypeTemporary;
-static const quota::StorageType kPerm = quota::kStorageTypePersistent;
+static const storage::StorageType kTemp = storage::kStorageTypeTemporary;
+static const storage::StorageType kPerm = storage::kStorageTypePersistent;
// Base class for our test fixtures.
class AppCacheQuotaClientTest : public testing::Test {
@@ -33,85 +31,76 @@ class AppCacheQuotaClientTest : public testing::Test {
kOriginB("http://host:8000"),
kOriginOther("http://other"),
usage_(0),
- delete_status_(quota::kQuotaStatusUnknown),
+ delete_status_(storage::kQuotaStatusUnknown),
num_get_origin_usage_completions_(0),
num_get_origins_completions_(0),
num_delete_origins_completions_(0),
- weak_factory_(this) {
- }
+ weak_factory_(this) {}
- int64 GetOriginUsage(
- quota::QuotaClient* client,
- const GURL& origin,
- quota::StorageType type) {
+ int64 GetOriginUsage(storage::QuotaClient* client,
+ const GURL& origin,
+ storage::StorageType type) {
usage_ = -1;
AsyncGetOriginUsage(client, origin, type);
base::RunLoop().RunUntilIdle();
return usage_;
}
- const std::set<GURL>& GetOriginsForType(
- quota::QuotaClient* client,
- quota::StorageType type) {
+ const std::set<GURL>& GetOriginsForType(storage::QuotaClient* client,
+ storage::StorageType type) {
origins_.clear();
AsyncGetOriginsForType(client, type);
base::RunLoop().RunUntilIdle();
return origins_;
}
- const std::set<GURL>& GetOriginsForHost(
- quota::QuotaClient* client,
- quota::StorageType type,
- const std::string& host) {
+ const std::set<GURL>& GetOriginsForHost(storage::QuotaClient* client,
+ storage::StorageType type,
+ const std::string& host) {
origins_.clear();
AsyncGetOriginsForHost(client, type, host);
base::RunLoop().RunUntilIdle();
return origins_;
}
- quota::QuotaStatusCode DeleteOriginData(
- quota::QuotaClient* client,
- quota::StorageType type,
- const GURL& origin) {
- delete_status_ = quota::kQuotaStatusUnknown;
+ storage::QuotaStatusCode DeleteOriginData(storage::QuotaClient* client,
+ storage::StorageType type,
+ const GURL& origin) {
+ delete_status_ = storage::kQuotaStatusUnknown;
AsyncDeleteOriginData(client, type, origin);
base::RunLoop().RunUntilIdle();
return delete_status_;
}
- void AsyncGetOriginUsage(
- quota::QuotaClient* client,
- const GURL& origin,
- quota::StorageType type) {
+ void AsyncGetOriginUsage(storage::QuotaClient* client,
+ const GURL& origin,
+ storage::StorageType type) {
client->GetOriginUsage(
origin, type,
base::Bind(&AppCacheQuotaClientTest::OnGetOriginUsageComplete,
weak_factory_.GetWeakPtr()));
}
- void AsyncGetOriginsForType(
- quota::QuotaClient* client,
- quota::StorageType type) {
+ void AsyncGetOriginsForType(storage::QuotaClient* client,
+ storage::StorageType type) {
client->GetOriginsForType(
type,
base::Bind(&AppCacheQuotaClientTest::OnGetOriginsComplete,
weak_factory_.GetWeakPtr()));
}
- void AsyncGetOriginsForHost(
- quota::QuotaClient* client,
- quota::StorageType type,
- const std::string& host) {
+ void AsyncGetOriginsForHost(storage::QuotaClient* client,
+ storage::StorageType type,
+ const std::string& host) {
client->GetOriginsForHost(
type, host,
base::Bind(&AppCacheQuotaClientTest::OnGetOriginsComplete,
weak_factory_.GetWeakPtr()));
}
- void AsyncDeleteOriginData(
- quota::QuotaClient* client,
- quota::StorageType type,
- const GURL& origin) {
+ void AsyncDeleteOriginData(storage::QuotaClient* client,
+ storage::StorageType type,
+ const GURL& origin) {
client->DeleteOriginData(
origin, type,
base::Bind(&AppCacheQuotaClientTest::OnDeleteOriginDataComplete,
@@ -149,7 +138,7 @@ class AppCacheQuotaClientTest : public testing::Test {
origins_ = origins;
}
- void OnDeleteOriginDataComplete(quota::QuotaStatusCode status) {
+ void OnDeleteOriginDataComplete(storage::QuotaStatusCode status) {
++num_delete_origins_completions_;
delete_status_ = status;
}
@@ -157,7 +146,7 @@ class AppCacheQuotaClientTest : public testing::Test {
base::MessageLoop message_loop_;
int64 usage_;
std::set<GURL> origins_;
- quota::QuotaStatusCode delete_status_;
+ storage::QuotaStatusCode delete_status_;
int num_get_origin_usage_completions_;
int num_get_origins_completions_;
int num_delete_origins_completions_;
@@ -183,8 +172,8 @@ TEST_F(AppCacheQuotaClientTest, EmptyService) {
EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginA.host()).empty());
EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty());
- EXPECT_EQ(quota::kQuotaStatusOk, DeleteOriginData(client, kTemp, kOriginA));
- EXPECT_EQ(quota::kQuotaStatusOk, DeleteOriginData(client, kPerm, kOriginA));
+ EXPECT_EQ(storage::kQuotaStatusOk, DeleteOriginData(client, kTemp, kOriginA));
+ EXPECT_EQ(storage::kQuotaStatusOk, DeleteOriginData(client, kPerm, kOriginA));
Call_NotifyAppCacheDestroyed(client);
Call_OnQuotaManagerDestroyed(client);
@@ -201,9 +190,9 @@ TEST_F(AppCacheQuotaClientTest, NoService) {
EXPECT_TRUE(GetOriginsForType(client, kPerm).empty());
EXPECT_TRUE(GetOriginsForHost(client, kTemp, kOriginA.host()).empty());
EXPECT_TRUE(GetOriginsForHost(client, kPerm, kOriginA.host()).empty());
- EXPECT_EQ(quota::kQuotaErrorAbort,
+ EXPECT_EQ(storage::kQuotaErrorAbort,
DeleteOriginData(client, kTemp, kOriginA));
- EXPECT_EQ(quota::kQuotaErrorAbort,
+ EXPECT_EQ(storage::kQuotaErrorAbort,
DeleteOriginData(client, kPerm, kOriginA));
Call_OnQuotaManagerDestroyed(client);
@@ -278,17 +267,15 @@ TEST_F(AppCacheQuotaClientTest, DeleteOriginData) {
// Perm deletions are short circuited in the Client and
// should not reach the AppCacheServiceImpl.
- EXPECT_EQ(quota::kQuotaStatusOk,
- DeleteOriginData(client, kPerm, kOriginA));
+ EXPECT_EQ(storage::kQuotaStatusOk, DeleteOriginData(client, kPerm, kOriginA));
EXPECT_EQ(0, mock_service_.delete_called_count());
- EXPECT_EQ(quota::kQuotaStatusOk,
- DeleteOriginData(client, kTemp, kOriginA));
+ EXPECT_EQ(storage::kQuotaStatusOk, DeleteOriginData(client, kTemp, kOriginA));
EXPECT_EQ(1, mock_service_.delete_called_count());
mock_service_.set_mock_delete_appcaches_for_origin_result(
net::ERR_ABORTED);
- EXPECT_EQ(quota::kQuotaErrorAbort,
+ EXPECT_EQ(storage::kQuotaErrorAbort,
DeleteOriginData(client, kTemp, kOriginA));
EXPECT_EQ(2, mock_service_.delete_called_count());
@@ -370,7 +357,7 @@ TEST_F(AppCacheQuotaClientTest, DestroyServiceWithPending) {
EXPECT_EQ(3, num_delete_origins_completions_);
EXPECT_EQ(0, usage_);
EXPECT_TRUE(origins_.empty());
- EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_);
+ EXPECT_EQ(storage::kQuotaErrorAbort, delete_status_);
Call_OnQuotaManagerDestroyed(client);
}
@@ -423,13 +410,13 @@ TEST_F(AppCacheQuotaClientTest, DestroyWithDeleteInProgress) {
// Should have been aborted.
EXPECT_EQ(1, num_delete_origins_completions_);
- EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_);
+ EXPECT_EQ(storage::kQuotaErrorAbort, delete_status_);
// A real completion callback from the service should
// be dropped if it comes in after NotifyAppCacheDestroyed.
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, num_delete_origins_completions_);
- EXPECT_EQ(quota::kQuotaErrorAbort, delete_status_);
+ EXPECT_EQ(storage::kQuotaErrorAbort, delete_status_);
Call_OnQuotaManagerDestroyed(client);
}
diff --git a/chromium/content/browser/appcache/appcache_request_handler.cc b/chromium/content/browser/appcache/appcache_request_handler.cc
new file mode 100644
index 00000000000..a21337c1111
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_request_handler.cc
@@ -0,0 +1,417 @@
+// 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 "content/browser/appcache/appcache_request_handler.h"
+
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_backend_impl.h"
+#include "content/browser/appcache/appcache_policy.h"
+#include "content/browser/appcache/appcache_url_request_job.h"
+#include "content/browser/service_worker/service_worker_request_handler.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_job.h"
+
+namespace content {
+
+AppCacheRequestHandler::AppCacheRequestHandler(AppCacheHost* host,
+ ResourceType resource_type)
+ : host_(host),
+ resource_type_(resource_type),
+ is_waiting_for_cache_selection_(false),
+ found_group_id_(0),
+ found_cache_id_(0),
+ found_network_namespace_(false),
+ cache_entry_not_found_(false),
+ maybe_load_resource_executed_(false) {
+ DCHECK(host_);
+ host_->AddObserver(this);
+}
+
+AppCacheRequestHandler::~AppCacheRequestHandler() {
+ if (host_) {
+ storage()->CancelDelegateCallbacks(this);
+ host_->RemoveObserver(this);
+ }
+}
+
+AppCacheStorage* AppCacheRequestHandler::storage() const {
+ DCHECK(host_);
+ return host_->storage();
+}
+
+AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadResource(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+ maybe_load_resource_executed_ = true;
+ if (!host_ || !IsSchemeAndMethodSupportedForAppCache(request) ||
+ cache_entry_not_found_)
+ return NULL;
+
+ // This method can get called multiple times over the life
+ // of a request. The case we detect here is having scheduled
+ // delivery of a "network response" using a job setup on an
+ // earlier call thru this method. To send the request thru
+ // to the network involves restarting the request altogether,
+ // which will call thru to our interception layer again.
+ // This time thru, we return NULL so the request hits the wire.
+ if (job_.get()) {
+ DCHECK(job_->is_delivering_network_response() ||
+ job_->cache_entry_not_found());
+ if (job_->cache_entry_not_found())
+ cache_entry_not_found_ = true;
+ job_ = NULL;
+ storage()->CancelDelegateCallbacks(this);
+ return NULL;
+ }
+
+ // Clear out our 'found' fields since we're starting a request for a
+ // new resource, any values in those fields are no longer valid.
+ found_entry_ = AppCacheEntry();
+ found_fallback_entry_ = AppCacheEntry();
+ found_cache_id_ = kAppCacheNoCacheId;
+ found_manifest_url_ = GURL();
+ found_network_namespace_ = false;
+
+ if (is_main_resource())
+ MaybeLoadMainResource(request, network_delegate);
+ else
+ MaybeLoadSubResource(request, network_delegate);
+
+ // If its been setup to deliver a network response, we can just delete
+ // it now and return NULL instead to achieve that since it couldn't
+ // have been started yet.
+ if (job_.get() && job_->is_delivering_network_response()) {
+ DCHECK(!job_->has_been_started());
+ job_ = NULL;
+ }
+
+ return job_.get();
+}
+
+AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadFallbackForRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) {
+ if (!host_ || !IsSchemeAndMethodSupportedForAppCache(request) ||
+ cache_entry_not_found_)
+ return NULL;
+ if (is_main_resource())
+ return NULL;
+ // TODO(vabr) This is a temporary fix (see crbug/141114). We should get rid of
+ // it once a more general solution to crbug/121325 is in place.
+ if (!maybe_load_resource_executed_)
+ return NULL;
+ if (request->url().GetOrigin() == location.GetOrigin())
+ return NULL;
+
+ DCHECK(!job_.get()); // our jobs never generate redirects
+
+ if (found_fallback_entry_.has_response_id()) {
+ // 6.9.6, step 4: If this results in a redirect to another origin,
+ // get the resource of the fallback entry.
+ job_ = new AppCacheURLRequestJob(request, network_delegate,
+ storage(), host_, is_main_resource());
+ DeliverAppCachedResponse(
+ found_fallback_entry_, found_cache_id_, found_group_id_,
+ found_manifest_url_, true, found_namespace_entry_url_);
+ } else if (!found_network_namespace_) {
+ // 6.9.6, step 6: Fail the resource load.
+ job_ = new AppCacheURLRequestJob(request, network_delegate,
+ storage(), host_, is_main_resource());
+ DeliverErrorResponse();
+ } else {
+ // 6.9.6 step 3 and 5: Fetch the resource normally.
+ }
+
+ return job_.get();
+}
+
+AppCacheURLRequestJob* AppCacheRequestHandler::MaybeLoadFallbackForResponse(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+ if (!host_ || !IsSchemeAndMethodSupportedForAppCache(request) ||
+ cache_entry_not_found_)
+ return NULL;
+ if (!found_fallback_entry_.has_response_id())
+ return NULL;
+
+ if (request->status().status() == net::URLRequestStatus::CANCELED) {
+ // 6.9.6, step 4: But not if the user canceled the download.
+ return NULL;
+ }
+
+ // We don't fallback for responses that we delivered.
+ if (job_.get()) {
+ DCHECK(!job_->is_delivering_network_response());
+ return NULL;
+ }
+
+ if (request->status().is_success()) {
+ int code_major = request->GetResponseCode() / 100;
+ if (code_major !=4 && code_major != 5)
+ return NULL;
+
+ // Servers can override the fallback behavior with a response header.
+ const std::string kFallbackOverrideHeader(
+ "x-chromium-appcache-fallback-override");
+ const std::string kFallbackOverrideValue(
+ "disallow-fallback");
+ std::string header_value;
+ request->GetResponseHeaderByName(kFallbackOverrideHeader, &header_value);
+ if (header_value == kFallbackOverrideValue)
+ return NULL;
+ }
+
+ // 6.9.6, step 4: If this results in a 4xx or 5xx status code
+ // or there were network errors, get the resource of the fallback entry.
+ job_ = new AppCacheURLRequestJob(request, network_delegate,
+ storage(), host_, is_main_resource());
+ DeliverAppCachedResponse(
+ found_fallback_entry_, found_cache_id_, found_group_id_,
+ found_manifest_url_, true, found_namespace_entry_url_);
+ return job_.get();
+}
+
+void AppCacheRequestHandler::GetExtraResponseInfo(
+ int64* cache_id, GURL* manifest_url) {
+ if (job_.get() && job_->is_delivering_appcache_response()) {
+ *cache_id = job_->cache_id();
+ *manifest_url = job_->manifest_url();
+ }
+}
+
+void AppCacheRequestHandler::PrepareForCrossSiteTransfer(int old_process_id) {
+ if (!host_)
+ return;
+ AppCacheBackendImpl* backend = host_->service()->GetBackend(old_process_id);
+ host_for_cross_site_transfer_ = backend->TransferHostOut(host_->host_id());
+ DCHECK_EQ(host_, host_for_cross_site_transfer_.get());
+}
+
+void AppCacheRequestHandler::CompleteCrossSiteTransfer(
+ int new_process_id, int new_host_id) {
+ if (!host_for_cross_site_transfer_.get())
+ return;
+ DCHECK_EQ(host_, host_for_cross_site_transfer_.get());
+ AppCacheBackendImpl* backend = host_->service()->GetBackend(new_process_id);
+ backend->TransferHostIn(new_host_id, host_for_cross_site_transfer_.Pass());
+}
+
+void AppCacheRequestHandler::OnDestructionImminent(AppCacheHost* host) {
+ storage()->CancelDelegateCallbacks(this);
+ host_ = NULL; // no need to RemoveObserver, the host is being deleted
+
+ // Since the host is being deleted, we don't have to complete any job
+ // that is current running. It's destined for the bit bucket anyway.
+ if (job_.get()) {
+ job_->Kill();
+ job_ = NULL;
+ }
+}
+
+void AppCacheRequestHandler::DeliverAppCachedResponse(
+ const AppCacheEntry& entry, int64 cache_id, int64 group_id,
+ const GURL& manifest_url, bool is_fallback,
+ const GURL& namespace_entry_url) {
+ DCHECK(host_ && job_.get() && job_->is_waiting());
+ DCHECK(entry.has_response_id());
+
+ if (IsResourceTypeFrame(resource_type_) && !namespace_entry_url.is_empty())
+ host_->NotifyMainResourceIsNamespaceEntry(namespace_entry_url);
+
+ job_->DeliverAppCachedResponse(manifest_url, group_id, cache_id,
+ entry, is_fallback);
+}
+
+void AppCacheRequestHandler::DeliverErrorResponse() {
+ DCHECK(job_.get() && job_->is_waiting());
+ job_->DeliverErrorResponse();
+}
+
+void AppCacheRequestHandler::DeliverNetworkResponse() {
+ DCHECK(job_.get() && job_->is_waiting());
+ job_->DeliverNetworkResponse();
+}
+
+// Main-resource handling ----------------------------------------------
+
+void AppCacheRequestHandler::MaybeLoadMainResource(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+ DCHECK(!job_.get());
+ DCHECK(host_);
+
+ // If a page falls into the scope of a ServiceWorker, any matching AppCaches
+ // should be ignored. This depends on the ServiceWorker handler being invoked
+ // prior to the AppCache handler.
+ if (ServiceWorkerRequestHandler::IsControlledByServiceWorker(request)) {
+ host_->enable_cache_selection(false);
+ return;
+ }
+
+ host_->enable_cache_selection(true);
+
+ const AppCacheHost* spawning_host =
+ (resource_type_ == RESOURCE_TYPE_SHARED_WORKER) ?
+ host_ : host_->GetSpawningHost();
+ GURL preferred_manifest_url = spawning_host ?
+ spawning_host->preferred_manifest_url() : GURL();
+
+ // We may have to wait for our storage query to complete, but
+ // this query can also complete syncrhonously.
+ job_ = new AppCacheURLRequestJob(request, network_delegate,
+ storage(), host_, is_main_resource());
+ storage()->FindResponseForMainRequest(
+ request->url(), preferred_manifest_url, this);
+}
+
+void AppCacheRequestHandler::OnMainResponseFound(
+ const GURL& url, const AppCacheEntry& entry,
+ const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
+ int64 cache_id, int64 group_id, const GURL& manifest_url) {
+ DCHECK(job_.get());
+ DCHECK(host_);
+ DCHECK(is_main_resource());
+ DCHECK(!entry.IsForeign());
+ DCHECK(!fallback_entry.IsForeign());
+ DCHECK(!(entry.has_response_id() && fallback_entry.has_response_id()));
+
+ if (!job_.get())
+ return;
+
+ AppCachePolicy* policy = host_->service()->appcache_policy();
+ bool was_blocked_by_policy = !manifest_url.is_empty() && policy &&
+ !policy->CanLoadAppCache(manifest_url, host_->first_party_url());
+
+ if (was_blocked_by_policy) {
+ if (IsResourceTypeFrame(resource_type_)) {
+ host_->NotifyMainResourceBlocked(manifest_url);
+ } else {
+ DCHECK_EQ(resource_type_, RESOURCE_TYPE_SHARED_WORKER);
+ host_->frontend()->OnContentBlocked(host_->host_id(), manifest_url);
+ }
+ DeliverNetworkResponse();
+ return;
+ }
+
+ if (IsResourceTypeFrame(resource_type_) && cache_id != kAppCacheNoCacheId) {
+ // AppCacheHost loads and holds a reference to the main resource cache
+ // for two reasons, firstly to preload the cache into the working set
+ // in advance of subresource loads happening, secondly to prevent the
+ // AppCache from falling out of the working set on frame navigations.
+ host_->LoadMainResourceCache(cache_id);
+ host_->set_preferred_manifest_url(manifest_url);
+ }
+
+ // 6.11.1 Navigating across documents, steps 10 and 14.
+
+ found_entry_ = entry;
+ found_namespace_entry_url_ = namespace_entry_url;
+ found_fallback_entry_ = fallback_entry;
+ found_cache_id_ = cache_id;
+ found_group_id_ = group_id;
+ found_manifest_url_ = manifest_url;
+ found_network_namespace_ = false; // not applicable to main requests
+
+ if (found_entry_.has_response_id()) {
+ DCHECK(!found_fallback_entry_.has_response_id());
+ DeliverAppCachedResponse(
+ found_entry_, found_cache_id_, found_group_id_, found_manifest_url_,
+ false, found_namespace_entry_url_);
+ } else {
+ DeliverNetworkResponse();
+ }
+}
+
+// Sub-resource handling ----------------------------------------------
+
+void AppCacheRequestHandler::MaybeLoadSubResource(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+ DCHECK(!job_.get());
+
+ if (host_->is_selection_pending()) {
+ // We have to wait until cache selection is complete and the
+ // selected cache is loaded.
+ is_waiting_for_cache_selection_ = true;
+ job_ = new AppCacheURLRequestJob(request, network_delegate,
+ storage(), host_, is_main_resource());
+ return;
+ }
+
+ if (!host_->associated_cache() ||
+ !host_->associated_cache()->is_complete() ||
+ host_->associated_cache()->owning_group()->is_being_deleted()) {
+ return;
+ }
+
+ job_ = new AppCacheURLRequestJob(request, network_delegate,
+ storage(), host_, is_main_resource());
+ ContinueMaybeLoadSubResource();
+}
+
+void AppCacheRequestHandler::ContinueMaybeLoadSubResource() {
+ // 6.9.6 Changes to the networking model
+ // If the resource is not to be fetched using the HTTP GET mechanism or
+ // equivalent ... then fetch the resource normally.
+ DCHECK(job_.get());
+ DCHECK(host_->associated_cache() && host_->associated_cache()->is_complete());
+
+ const GURL& url = job_->request()->url();
+ AppCache* cache = host_->associated_cache();
+ storage()->FindResponseForSubRequest(
+ host_->associated_cache(), url,
+ &found_entry_, &found_fallback_entry_, &found_network_namespace_);
+
+ if (found_entry_.has_response_id()) {
+ // Step 2: If there's an entry, get it instead.
+ DCHECK(!found_network_namespace_ &&
+ !found_fallback_entry_.has_response_id());
+ found_cache_id_ = cache->cache_id();
+ found_group_id_ = cache->owning_group()->group_id();
+ found_manifest_url_ = cache->owning_group()->manifest_url();
+ DeliverAppCachedResponse(
+ found_entry_, found_cache_id_, found_group_id_, found_manifest_url_,
+ false, GURL());
+ return;
+ }
+
+ if (found_fallback_entry_.has_response_id()) {
+ // Step 4: Fetch the resource normally, if this results
+ // in certain conditions, then use the fallback.
+ DCHECK(!found_network_namespace_ &&
+ !found_entry_.has_response_id());
+ found_cache_id_ = cache->cache_id();
+ found_manifest_url_ = cache->owning_group()->manifest_url();
+ DeliverNetworkResponse();
+ return;
+ }
+
+ if (found_network_namespace_) {
+ // Step 3 and 5: Fetch the resource normally.
+ DCHECK(!found_entry_.has_response_id() &&
+ !found_fallback_entry_.has_response_id());
+ DeliverNetworkResponse();
+ return;
+ }
+
+ // Step 6: Fail the resource load.
+ DeliverErrorResponse();
+}
+
+void AppCacheRequestHandler::OnCacheSelectionComplete(AppCacheHost* host) {
+ DCHECK(host == host_);
+ if (is_main_resource())
+ return;
+ if (!is_waiting_for_cache_selection_)
+ return;
+
+ is_waiting_for_cache_selection_ = false;
+
+ if (!host_->associated_cache() ||
+ !host_->associated_cache()->is_complete()) {
+ DeliverNetworkResponse();
+ return;
+ }
+
+ ContinueMaybeLoadSubResource();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_request_handler.h b/chromium/content/browser/appcache/appcache_request_handler.h
new file mode 100644
index 00000000000..cf0297b35dd
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_request_handler.h
@@ -0,0 +1,151 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_REQUEST_HANDLER_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_REQUEST_HANDLER_H_
+
+#include "base/compiler_specific.h"
+#include "base/supports_user_data.h"
+#include "content/browser/appcache/appcache_entry.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/common/content_export.h"
+#include "content/public/common/resource_type.h"
+
+namespace net {
+class NetworkDelegate;
+class URLRequest;
+class URLRequestJob;
+} // namespace net
+
+namespace content {
+class AppCacheRequestHandlerTest;
+class AppCacheURLRequestJob;
+
+// An instance is created for each net::URLRequest. The instance survives all
+// http transactions involved in the processing of its net::URLRequest, and is
+// given the opportunity to hijack the request along the way. Callers
+// should use AppCacheHost::CreateRequestHandler to manufacture instances
+// that can retrieve resources for a particular host.
+class CONTENT_EXPORT AppCacheRequestHandler
+ : public base::SupportsUserData::Data,
+ public AppCacheHost::Observer,
+ public AppCacheStorage::Delegate {
+ public:
+ ~AppCacheRequestHandler() override;
+
+ // These are called on each request intercept opportunity.
+ AppCacheURLRequestJob* MaybeLoadResource(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate);
+ AppCacheURLRequestJob* MaybeLoadFallbackForRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location);
+ AppCacheURLRequestJob* MaybeLoadFallbackForResponse(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate);
+
+ void GetExtraResponseInfo(int64* cache_id, GURL* manifest_url);
+
+ // Methods to support cross site navigations.
+ void PrepareForCrossSiteTransfer(int old_process_id);
+ void CompleteCrossSiteTransfer(int new_process_id, int new_host_id);
+
+ static bool IsMainResourceType(ResourceType type) {
+ return IsResourceTypeFrame(type) ||
+ type == RESOURCE_TYPE_SHARED_WORKER;
+ }
+
+ private:
+ friend class AppCacheHost;
+
+ // Callers should use AppCacheHost::CreateRequestHandler.
+ AppCacheRequestHandler(AppCacheHost* host, ResourceType resource_type);
+
+ // AppCacheHost::Observer override
+ void OnDestructionImminent(AppCacheHost* host) override;
+
+ // Helpers to instruct a waiting job with what response to
+ // deliver for the request we're handling.
+ void DeliverAppCachedResponse(const AppCacheEntry& entry, int64 cache_id,
+ int64 group_id, const GURL& manifest_url,
+ bool is_fallback,
+ const GURL& namespace_entry_url);
+ void DeliverNetworkResponse();
+ void DeliverErrorResponse();
+
+ // Helper to retrieve a pointer to the storage object.
+ AppCacheStorage* storage() const;
+
+ bool is_main_resource() const {
+ return IsMainResourceType(resource_type_);
+ }
+
+ // Main-resource loading -------------------------------------
+ // Frame and SharedWorker main resources are handled here.
+
+ void MaybeLoadMainResource(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate);
+
+ // AppCacheStorage::Delegate methods
+ void OnMainResponseFound(const GURL& url,
+ const AppCacheEntry& entry,
+ const GURL& fallback_url,
+ const AppCacheEntry& fallback_entry,
+ int64 cache_id,
+ int64 group_id,
+ const GURL& mainfest_url) override;
+
+ // Sub-resource loading -------------------------------------
+ // Dedicated worker and all manner of sub-resources are handled here.
+
+ void MaybeLoadSubResource(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate);
+ void ContinueMaybeLoadSubResource();
+
+ // AppCacheHost::Observer override
+ void OnCacheSelectionComplete(AppCacheHost* host) override;
+
+ // Data members -----------------------------------------------
+
+ // What host we're servicing a request for.
+ AppCacheHost* host_;
+
+ // Frame vs subresource vs sharedworker loads are somewhat different.
+ ResourceType resource_type_;
+
+ // Subresource requests wait until after cache selection completes.
+ bool is_waiting_for_cache_selection_;
+
+ // Info about the type of response we found for delivery.
+ // These are relevant for both main and subresource requests.
+ int64 found_group_id_;
+ int64 found_cache_id_;
+ AppCacheEntry found_entry_;
+ AppCacheEntry found_fallback_entry_;
+ GURL found_namespace_entry_url_;
+ GURL found_manifest_url_;
+ bool found_network_namespace_;
+
+ // True if a cache entry this handler attempted to return was
+ // not found in the disk cache. Once set, the handler will take
+ // no action on all subsequent intercept opportunities, so the
+ // request and any redirects will be handled by the network library.
+ bool cache_entry_not_found_;
+
+ // True if this->MaybeLoadResource(...) has been called in the past.
+ bool maybe_load_resource_executed_;
+
+ // The job we use to deliver a response.
+ scoped_refptr<AppCacheURLRequestJob> job_;
+
+ // During a cross site navigation, we transfer ownership the AppcacheHost
+ // from the old processes structures over to the new structures.
+ scoped_ptr<AppCacheHost> host_for_cross_site_transfer_;
+
+ friend class content::AppCacheRequestHandlerTest;
+ DISALLOW_COPY_AND_ASSIGN(AppCacheRequestHandler);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_REQUEST_HANDLER_H_
diff --git a/chromium/content/browser/appcache/appcache_request_handler_unittest.cc b/chromium/content/browser/appcache/appcache_request_handler_unittest.cc
index df6fb330d24..9543f7e65d7 100644
--- a/chromium/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -12,6 +12,10 @@
#include "base/message_loop/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_backend_impl.h"
+#include "content/browser/appcache/appcache_request_handler.h"
+#include "content/browser/appcache/appcache_url_request_job.h"
#include "content/browser/appcache/mock_appcache_policy.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "net/base/net_errors.h"
@@ -22,21 +26,6 @@
#include "net/url_request/url_request_error_job.h"
#include "net/url_request/url_request_job_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_backend_impl.h"
-#include "webkit/browser/appcache/appcache_request_handler.h"
-#include "webkit/browser/appcache/appcache_url_request_job.h"
-
-using appcache::AppCache;
-using appcache::AppCacheBackendImpl;
-using appcache::AppCacheEntry;
-using appcache::AppCacheFrontend;
-using appcache::AppCacheGroup;
-using appcache::AppCacheHost;
-using appcache::AppCacheInfo;
-using appcache::AppCacheRequestHandler;
-using appcache::AppCacheURLRequestJob;
-using appcache::kAppCacheNoCacheId;
namespace content {
@@ -46,32 +35,27 @@ class AppCacheRequestHandlerTest : public testing::Test {
public:
class MockFrontend : public AppCacheFrontend {
public:
- virtual void OnCacheSelected(
- int host_id, const appcache::AppCacheInfo& info) OVERRIDE {}
+ void OnCacheSelected(int host_id, const AppCacheInfo& info) override {}
- virtual void OnStatusChanged(const std::vector<int>& host_ids,
- appcache::AppCacheStatus status) OVERRIDE {}
+ void OnStatusChanged(const std::vector<int>& host_ids,
+ AppCacheStatus status) override {}
- virtual void OnEventRaised(const std::vector<int>& host_ids,
- appcache::AppCacheEventID event_id) OVERRIDE {}
+ void OnEventRaised(const std::vector<int>& host_ids,
+ AppCacheEventID event_id) override {}
- virtual void OnErrorEventRaised(
- const std::vector<int>& host_ids,
- const appcache::AppCacheErrorDetails& details) OVERRIDE {}
+ void OnErrorEventRaised(const std::vector<int>& host_ids,
+ const AppCacheErrorDetails& details) override {}
- virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
- const GURL& url,
- int num_total,
- int num_complete) OVERRIDE {
- }
+ void OnProgressEventRaised(const std::vector<int>& host_ids,
+ const GURL& url,
+ int num_total,
+ int num_complete) override {}
- virtual void OnLogMessage(int host_id,
- appcache::AppCacheLogLevel log_level,
- const std::string& message) OVERRIDE {
- }
+ void OnLogMessage(int host_id,
+ AppCacheLogLevel log_level,
+ const std::string& message) override {}
- virtual void OnContentBlocked(int host_id,
- const GURL& manifest_url) OVERRIDE {}
+ void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
};
// Helper callback to run a test on our io_thread. The io_thread is spun up
@@ -86,10 +70,8 @@ class AppCacheRequestHandlerTest : public testing::Test {
// exercise fallback code paths.
class MockURLRequestDelegate : public net::URLRequest::Delegate {
- virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {}
- virtual void OnReadCompleted(net::URLRequest* request,
- int bytes_read) OVERRIDE {
- }
+ void OnResponseStarted(net::URLRequest* request) override {}
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override {}
};
class MockURLRequestJob : public net::URLRequestJob {
@@ -108,22 +90,17 @@ class AppCacheRequestHandlerTest : public testing::Test {
has_response_info_(true),
response_info_(info) {}
- protected:
- virtual ~MockURLRequestJob() {}
- virtual void Start() OVERRIDE {
- NotifyHeadersComplete();
- }
- virtual int GetResponseCode() const OVERRIDE {
- return response_code_;
- }
- virtual void GetResponseInfo(
- net::HttpResponseInfo* info) OVERRIDE {
+ protected:
+ ~MockURLRequestJob() override {}
+ void Start() override { NotifyHeadersComplete(); }
+ int GetResponseCode() const override { return response_code_; }
+ void GetResponseInfo(net::HttpResponseInfo* info) override {
if (!has_response_info_)
return;
*info = response_info_;
}
- private:
+ private:
int response_code_;
bool has_response_info_;
net::HttpResponseInfo response_info_;
@@ -134,18 +111,16 @@ class AppCacheRequestHandlerTest : public testing::Test {
MockURLRequestJobFactory() : job_(NULL) {
}
- virtual ~MockURLRequestJobFactory() {
- DCHECK(!job_);
- }
+ ~MockURLRequestJobFactory() override { DCHECK(!job_); }
void SetJob(net::URLRequestJob* job) {
job_ = job;
}
- virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+ net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
if (job_) {
net::URLRequestJob* temp = job_;
job_ = NULL;
@@ -159,15 +134,28 @@ class AppCacheRequestHandlerTest : public testing::Test {
}
}
- virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
+ net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const override {
+ return nullptr;
+ }
+
+ net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return nullptr;
+ }
+
+ bool IsHandledProtocol(const std::string& scheme) const override {
return scheme == "http";
};
- virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
+ bool IsHandledURL(const GURL& url) const override {
return url.SchemeIs("http");
}
- virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
+ bool IsSafeRedirectTarget(const GURL& location) const override {
return false;
}
@@ -175,15 +163,6 @@ class AppCacheRequestHandlerTest : public testing::Test {
mutable net::URLRequestJob* job_;
};
- class MockURLRequest : public net::URLRequest {
- public:
- MockURLRequest(const GURL& url, net::URLRequestContext* context)
- : net::URLRequest(url, net::DEFAULT_PRIORITY, NULL, context) {}
-
-
- MockURLRequestDelegate delegate_;
- };
-
static void SetUpTestCase() {
io_thread_.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
@@ -274,9 +253,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss,
base::Unretained(this)));
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
@@ -321,9 +301,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit,
base::Unretained(this)));
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME));
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
@@ -369,9 +350,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback,
base::Unretained(this)));
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME));
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
@@ -406,7 +388,6 @@ class AppCacheRequestHandlerTest : public testing::Test {
new MockURLRequestJob(
request_.get(),
request_->context()->network_delegate(), info));
- request_->set_delegate(&request_->delegate_);
request_->Start();
}
@@ -450,10 +431,11 @@ class AppCacheRequestHandlerTest : public testing::Test {
&AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride,
base::Unretained(this)));
- request_.reset(new MockURLRequest(GURL("http://blah/fallback-override"),
- &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY,
+ &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME));
EXPECT_TRUE(handler_.get());
mock_storage()->SimulateFindMainResource(
@@ -503,9 +485,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
// SubResource_Miss_WithNoCacheSelected ----------------------------------
void SubResource_Miss_WithNoCacheSelected() {
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
// We avoid creating handler when possible, sub-resource requests are not
// subject to retrieval from an appcache when there's no associated cache.
@@ -521,9 +504,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
// in a network or fallback namespace, should result in a failed request.
host_->AssociateCompleteCache(MakeNewCache());
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
@@ -552,9 +536,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
host_->pending_selected_cache_id_ = cache->cache_id();
host_->set_preferred_manifest_url(cache->owning_group()->manifest_url());
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -586,9 +571,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
mock_storage()->SimulateFindSubResource(
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -618,9 +604,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
mock_storage()->SimulateFindSubResource(
AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -651,9 +638,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
mock_storage()->SimulateFindSubResource(
AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -685,9 +673,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
mock_storage()->SimulateFindSubResource(
AppCacheEntry(), AppCacheEntry(), true);
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
request_->context()->network_delegate());
@@ -714,9 +703,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
mock_storage()->SimulateFindSubResource(
AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get());
backend_impl_->UnregisterHost(1);
@@ -740,9 +730,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
// Precondition, the host is waiting on cache selection.
host_->pending_selected_cache_id_ = 1;
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
@@ -772,9 +763,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
// Precondition, the host is waiting on cache selection.
host_->pending_selected_cache_id_ = 1;
- request_.reset(new MockURLRequest(GURL("ftp://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("ftp://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::SUB_RESOURCE));
+ RESOURCE_TYPE_SUB_RESOURCE));
EXPECT_TRUE(handler_.get()); // we could redirect to http (conceivably)
EXPECT_FALSE(handler_->MaybeLoadResource(
@@ -792,9 +784,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
// CanceledRequest -----------------------------
void CanceledRequest() {
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME));
EXPECT_TRUE(handler_.get());
job_ = handler_->MaybeLoadResource(request_.get(),
@@ -803,7 +796,7 @@ class AppCacheRequestHandlerTest : public testing::Test {
EXPECT_TRUE(job_->is_waiting());
EXPECT_FALSE(job_->has_been_started());
- job_factory_->SetJob(job_);
+ job_factory_->SetJob(job_.get());
request_->Start();
EXPECT_TRUE(job_->has_been_started());
@@ -820,15 +813,16 @@ class AppCacheRequestHandlerTest : public testing::Test {
void WorkerRequest() {
EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
- ResourceType::MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME));
EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
- ResourceType::SUB_FRAME));
+ RESOURCE_TYPE_SUB_FRAME));
EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
- ResourceType::SHARED_WORKER));
+ RESOURCE_TYPE_SHARED_WORKER));
EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
- ResourceType::WORKER));
+ RESOURCE_TYPE_WORKER));
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
const int kParentHostId = host_->host_id();
const int kWorkerHostId = 2;
@@ -839,7 +833,7 @@ class AppCacheRequestHandlerTest : public testing::Test {
AppCacheHost* worker_host = backend_impl_->GetHost(kWorkerHostId);
worker_host->SelectCacheForWorker(kParentHostId, kMockProcessId);
handler_.reset(worker_host->CreateRequestHandler(
- request_.get(), ResourceType::SHARED_WORKER));
+ request_.get(), RESOURCE_TYPE_SHARED_WORKER));
EXPECT_TRUE(handler_.get());
// Verify that the handler is associated with the parent host.
EXPECT_EQ(host_, handler_->host_);
@@ -852,7 +846,7 @@ class AppCacheRequestHandlerTest : public testing::Test {
EXPECT_EQ(NULL, backend_impl_->GetHost(kNonExsitingHostId));
worker_host->SelectCacheForWorker(kNonExsitingHostId, kMockProcessId);
handler_.reset(worker_host->CreateRequestHandler(
- request_.get(), ResourceType::SHARED_WORKER));
+ request_.get(), RESOURCE_TYPE_SHARED_WORKER));
EXPECT_FALSE(handler_.get());
TestFinished();
@@ -865,9 +859,10 @@ class AppCacheRequestHandlerTest : public testing::Test {
base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked,
base::Unretained(this)));
- request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
+ request_ = empty_context_.CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
handler_.reset(host_->CreateRequestHandler(request_.get(),
- ResourceType::MAIN_FRAME));
+ RESOURCE_TYPE_MAIN_FRAME));
EXPECT_TRUE(handler_.get());
mock_policy_->can_load_return_value_ = false;
@@ -927,7 +922,8 @@ class AppCacheRequestHandlerTest : public testing::Test {
AppCacheHost* host_;
net::URLRequestContext empty_context_;
scoped_ptr<MockURLRequestJobFactory> job_factory_;
- scoped_ptr<MockURLRequest> request_;
+ MockURLRequestDelegate delegate_;
+ scoped_ptr<net::URLRequest> request_;
scoped_ptr<AppCacheRequestHandler> handler_;
scoped_refptr<AppCacheURLRequestJob> job_;
diff --git a/chromium/content/browser/appcache/appcache_response.cc b/chromium/content/browser/appcache/appcache_response.cc
new file mode 100644
index 00000000000..0d8b5b4039d
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_response.cc
@@ -0,0 +1,423 @@
+// 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/appcache/appcache_response.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/pickle.h"
+#include "base/strings/string_util.h"
+#include "content/browser/appcache/appcache_storage.h"
+#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace content {
+
+namespace {
+
+// Disk cache entry data indices.
+enum {
+ kResponseInfoIndex,
+ kResponseContentIndex
+};
+
+// An IOBuffer that wraps a pickle's data. Ownership of the
+// pickle is transfered to the WrappedPickleIOBuffer object.
+class WrappedPickleIOBuffer : public net::WrappedIOBuffer {
+ public:
+ explicit WrappedPickleIOBuffer(const Pickle* pickle) :
+ net::WrappedIOBuffer(reinterpret_cast<const char*>(pickle->data())),
+ pickle_(pickle) {
+ DCHECK(pickle->data());
+ }
+
+ private:
+ ~WrappedPickleIOBuffer() override {}
+
+ scoped_ptr<const Pickle> pickle_;
+};
+
+} // anon namespace
+
+
+// AppCacheResponseInfo ----------------------------------------------
+
+AppCacheResponseInfo::AppCacheResponseInfo(
+ AppCacheStorage* storage, const GURL& manifest_url,
+ int64 response_id, net::HttpResponseInfo* http_info,
+ int64 response_data_size)
+ : manifest_url_(manifest_url), response_id_(response_id),
+ http_response_info_(http_info), response_data_size_(response_data_size),
+ storage_(storage) {
+ DCHECK(http_info);
+ DCHECK(response_id != kAppCacheNoResponseId);
+ storage_->working_set()->AddResponseInfo(this);
+}
+
+AppCacheResponseInfo::~AppCacheResponseInfo() {
+ storage_->working_set()->RemoveResponseInfo(this);
+}
+
+// HttpResponseInfoIOBuffer ------------------------------------------
+
+HttpResponseInfoIOBuffer::HttpResponseInfoIOBuffer()
+ : response_data_size(kUnkownResponseDataSize) {}
+
+HttpResponseInfoIOBuffer::HttpResponseInfoIOBuffer(net::HttpResponseInfo* info)
+ : http_info(info), response_data_size(kUnkownResponseDataSize) {}
+
+HttpResponseInfoIOBuffer::~HttpResponseInfoIOBuffer() {}
+
+// AppCacheResponseIO ----------------------------------------------
+
+AppCacheResponseIO::AppCacheResponseIO(
+ int64 response_id, int64 group_id, AppCacheDiskCacheInterface* disk_cache)
+ : response_id_(response_id),
+ group_id_(group_id),
+ disk_cache_(disk_cache),
+ entry_(NULL),
+ buffer_len_(0),
+ weak_factory_(this) {
+}
+
+AppCacheResponseIO::~AppCacheResponseIO() {
+ if (entry_)
+ entry_->Close();
+}
+
+void AppCacheResponseIO::ScheduleIOCompletionCallback(int result) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&AppCacheResponseIO::OnIOComplete,
+ weak_factory_.GetWeakPtr(), result));
+}
+
+void AppCacheResponseIO::InvokeUserCompletionCallback(int result) {
+ // Clear the user callback and buffers prior to invoking the callback
+ // so the caller can schedule additional operations in the callback.
+ buffer_ = NULL;
+ info_buffer_ = NULL;
+ net::CompletionCallback cb = callback_;
+ callback_.Reset();
+ cb.Run(result);
+}
+
+void AppCacheResponseIO::ReadRaw(int index, int offset,
+ net::IOBuffer* buf, int buf_len) {
+ DCHECK(entry_);
+ int rv = entry_->Read(
+ index, offset, buf, buf_len,
+ base::Bind(&AppCacheResponseIO::OnRawIOComplete,
+ weak_factory_.GetWeakPtr()));
+ if (rv != net::ERR_IO_PENDING)
+ ScheduleIOCompletionCallback(rv);
+}
+
+void AppCacheResponseIO::WriteRaw(int index, int offset,
+ net::IOBuffer* buf, int buf_len) {
+ DCHECK(entry_);
+ int rv = entry_->Write(
+ index, offset, buf, buf_len,
+ base::Bind(&AppCacheResponseIO::OnRawIOComplete,
+ weak_factory_.GetWeakPtr()));
+ if (rv != net::ERR_IO_PENDING)
+ ScheduleIOCompletionCallback(rv);
+}
+
+void AppCacheResponseIO::OnRawIOComplete(int result) {
+ DCHECK_NE(net::ERR_IO_PENDING, result);
+ OnIOComplete(result);
+}
+
+
+// AppCacheResponseReader ----------------------------------------------
+
+AppCacheResponseReader::AppCacheResponseReader(
+ int64 response_id, int64 group_id, AppCacheDiskCacheInterface* disk_cache)
+ : AppCacheResponseIO(response_id, group_id, disk_cache),
+ range_offset_(0),
+ range_length_(kint32max),
+ read_position_(0),
+ weak_factory_(this) {
+}
+
+AppCacheResponseReader::~AppCacheResponseReader() {
+}
+
+void AppCacheResponseReader::ReadInfo(HttpResponseInfoIOBuffer* info_buf,
+ const net::CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(!IsReadPending());
+ DCHECK(info_buf);
+ DCHECK(!info_buf->http_info.get());
+ DCHECK(!buffer_.get());
+ DCHECK(!info_buffer_.get());
+
+ info_buffer_ = info_buf;
+ callback_ = callback; // cleared on completion
+ OpenEntryIfNeededAndContinue();
+}
+
+void AppCacheResponseReader::ContinueReadInfo() {
+ if (!entry_) {
+ ScheduleIOCompletionCallback(net::ERR_CACHE_MISS);
+ return;
+ }
+
+ int size = entry_->GetSize(kResponseInfoIndex);
+ if (size <= 0) {
+ ScheduleIOCompletionCallback(net::ERR_CACHE_MISS);
+ return;
+ }
+
+ buffer_ = new net::IOBuffer(size);
+ ReadRaw(kResponseInfoIndex, 0, buffer_.get(), size);
+}
+
+void AppCacheResponseReader::ReadData(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(!IsReadPending());
+ DCHECK(buf);
+ DCHECK(buf_len >= 0);
+ DCHECK(!buffer_.get());
+ DCHECK(!info_buffer_.get());
+
+ buffer_ = buf;
+ buffer_len_ = buf_len;
+ callback_ = callback; // cleared on completion
+ OpenEntryIfNeededAndContinue();
+}
+
+void AppCacheResponseReader::ContinueReadData() {
+ if (!entry_) {
+ ScheduleIOCompletionCallback(net::ERR_CACHE_MISS);
+ return;
+ }
+
+ if (read_position_ + buffer_len_ > range_length_) {
+ // TODO(michaeln): What about integer overflows?
+ DCHECK(range_length_ >= read_position_);
+ buffer_len_ = range_length_ - read_position_;
+ }
+ ReadRaw(kResponseContentIndex,
+ range_offset_ + read_position_,
+ buffer_.get(),
+ buffer_len_);
+}
+
+void AppCacheResponseReader::SetReadRange(int offset, int length) {
+ DCHECK(!IsReadPending() && !read_position_);
+ range_offset_ = offset;
+ range_length_ = length;
+}
+
+void AppCacheResponseReader::OnIOComplete(int result) {
+ if (result >= 0) {
+ if (info_buffer_.get()) {
+ // Deserialize the http info structure, ensuring we got headers.
+ Pickle pickle(buffer_->data(), result);
+ scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
+ bool response_truncated = false;
+ if (!info->InitFromPickle(pickle, &response_truncated) ||
+ !info->headers.get()) {
+ InvokeUserCompletionCallback(net::ERR_FAILED);
+ return;
+ }
+ DCHECK(!response_truncated);
+ info_buffer_->http_info.reset(info.release());
+
+ // Also return the size of the response body
+ DCHECK(entry_);
+ info_buffer_->response_data_size =
+ entry_->GetSize(kResponseContentIndex);
+ } else {
+ read_position_ += result;
+ }
+ }
+ InvokeUserCompletionCallback(result);
+}
+
+void AppCacheResponseReader::OpenEntryIfNeededAndContinue() {
+ int rv;
+ AppCacheDiskCacheInterface::Entry** entry_ptr = NULL;
+ if (entry_) {
+ rv = net::OK;
+ } else if (!disk_cache_) {
+ rv = net::ERR_FAILED;
+ } else {
+ entry_ptr = new AppCacheDiskCacheInterface::Entry*;
+ open_callback_ =
+ base::Bind(&AppCacheResponseReader::OnOpenEntryComplete,
+ weak_factory_.GetWeakPtr(), base::Owned(entry_ptr));
+ rv = disk_cache_->OpenEntry(response_id_, entry_ptr, open_callback_);
+ }
+
+ if (rv != net::ERR_IO_PENDING)
+ OnOpenEntryComplete(entry_ptr, rv);
+}
+
+void AppCacheResponseReader::OnOpenEntryComplete(
+ AppCacheDiskCacheInterface::Entry** entry, int rv) {
+ DCHECK(info_buffer_.get() || buffer_.get());
+
+ if (!open_callback_.is_null()) {
+ if (rv == net::OK) {
+ DCHECK(entry);
+ entry_ = *entry;
+ }
+ open_callback_.Reset();
+ }
+
+ if (info_buffer_.get())
+ ContinueReadInfo();
+ else
+ ContinueReadData();
+}
+
+// AppCacheResponseWriter ----------------------------------------------
+
+AppCacheResponseWriter::AppCacheResponseWriter(
+ int64 response_id, int64 group_id, AppCacheDiskCacheInterface* disk_cache)
+ : AppCacheResponseIO(response_id, group_id, disk_cache),
+ info_size_(0),
+ write_position_(0),
+ write_amount_(0),
+ creation_phase_(INITIAL_ATTEMPT),
+ weak_factory_(this) {
+}
+
+AppCacheResponseWriter::~AppCacheResponseWriter() {
+}
+
+void AppCacheResponseWriter::WriteInfo(
+ HttpResponseInfoIOBuffer* info_buf,
+ const net::CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(!IsWritePending());
+ DCHECK(info_buf);
+ DCHECK(info_buf->http_info.get());
+ DCHECK(!buffer_.get());
+ DCHECK(!info_buffer_.get());
+ DCHECK(info_buf->http_info->headers.get());
+
+ info_buffer_ = info_buf;
+ callback_ = callback; // cleared on completion
+ CreateEntryIfNeededAndContinue();
+}
+
+void AppCacheResponseWriter::ContinueWriteInfo() {
+ if (!entry_) {
+ ScheduleIOCompletionCallback(net::ERR_FAILED);
+ return;
+ }
+
+ const bool kSkipTransientHeaders = true;
+ const bool kTruncated = false;
+ Pickle* pickle = new Pickle;
+ info_buffer_->http_info->Persist(pickle, kSkipTransientHeaders, kTruncated);
+ write_amount_ = static_cast<int>(pickle->size());
+ buffer_ = new WrappedPickleIOBuffer(pickle); // takes ownership of pickle
+ WriteRaw(kResponseInfoIndex, 0, buffer_.get(), write_amount_);
+}
+
+void AppCacheResponseWriter::WriteData(
+ net::IOBuffer* buf, int buf_len, const net::CompletionCallback& callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(!IsWritePending());
+ DCHECK(buf);
+ DCHECK(buf_len >= 0);
+ DCHECK(!buffer_.get());
+ DCHECK(!info_buffer_.get());
+
+ buffer_ = buf;
+ write_amount_ = buf_len;
+ callback_ = callback; // cleared on completion
+ CreateEntryIfNeededAndContinue();
+}
+
+void AppCacheResponseWriter::ContinueWriteData() {
+ if (!entry_) {
+ ScheduleIOCompletionCallback(net::ERR_FAILED);
+ return;
+ }
+ WriteRaw(
+ kResponseContentIndex, write_position_, buffer_.get(), write_amount_);
+}
+
+void AppCacheResponseWriter::OnIOComplete(int result) {
+ if (result >= 0) {
+ DCHECK(write_amount_ == result);
+ if (!info_buffer_.get())
+ write_position_ += result;
+ else
+ info_size_ = result;
+ }
+ InvokeUserCompletionCallback(result);
+}
+
+void AppCacheResponseWriter::CreateEntryIfNeededAndContinue() {
+ int rv;
+ AppCacheDiskCacheInterface::Entry** entry_ptr = NULL;
+ if (entry_) {
+ creation_phase_ = NO_ATTEMPT;
+ rv = net::OK;
+ } else if (!disk_cache_) {
+ creation_phase_ = NO_ATTEMPT;
+ rv = net::ERR_FAILED;
+ } else {
+ creation_phase_ = INITIAL_ATTEMPT;
+ entry_ptr = new AppCacheDiskCacheInterface::Entry*;
+ create_callback_ =
+ base::Bind(&AppCacheResponseWriter::OnCreateEntryComplete,
+ weak_factory_.GetWeakPtr(), base::Owned(entry_ptr));
+ rv = disk_cache_->CreateEntry(response_id_, entry_ptr, create_callback_);
+ }
+ if (rv != net::ERR_IO_PENDING)
+ OnCreateEntryComplete(entry_ptr, rv);
+}
+
+void AppCacheResponseWriter::OnCreateEntryComplete(
+ AppCacheDiskCacheInterface::Entry** entry, int rv) {
+ DCHECK(info_buffer_.get() || buffer_.get());
+
+ if (creation_phase_ == INITIAL_ATTEMPT) {
+ if (rv != net::OK) {
+ // We may try to overwrite existing entries.
+ creation_phase_ = DOOM_EXISTING;
+ rv = disk_cache_->DoomEntry(response_id_, create_callback_);
+ if (rv != net::ERR_IO_PENDING)
+ OnCreateEntryComplete(NULL, rv);
+ return;
+ }
+ } else if (creation_phase_ == DOOM_EXISTING) {
+ creation_phase_ = SECOND_ATTEMPT;
+ AppCacheDiskCacheInterface::Entry** entry_ptr =
+ new AppCacheDiskCacheInterface::Entry*;
+ create_callback_ =
+ base::Bind(&AppCacheResponseWriter::OnCreateEntryComplete,
+ weak_factory_.GetWeakPtr(), base::Owned(entry_ptr));
+ rv = disk_cache_->CreateEntry(response_id_, entry_ptr, create_callback_);
+ if (rv != net::ERR_IO_PENDING)
+ OnCreateEntryComplete(entry_ptr, rv);
+ return;
+ }
+
+ if (!create_callback_.is_null()) {
+ if (rv == net::OK)
+ entry_ = *entry;
+
+ create_callback_.Reset();
+ }
+
+ if (info_buffer_.get())
+ ContinueWriteInfo();
+ else
+ ContinueWriteData();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_response.h b/chromium/content/browser/appcache/appcache_response.h
new file mode 100644
index 00000000000..4b7a32c6767
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_response.h
@@ -0,0 +1,262 @@
+// 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_APPCACHE_APPCACHE_RESPONSE_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_RESPONSE_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/appcache_interfaces.h"
+#include "content/common/content_export.h"
+#include "net/base/completion_callback.h"
+#include "net/http/http_response_info.h"
+#include "url/gurl.h"
+
+namespace net {
+class IOBuffer;
+}
+
+namespace content {
+class AppCacheStorage;
+class MockAppCacheStorage;
+
+static const int kUnkownResponseDataSize = -1;
+
+// Response info for a particular response id. Instances are tracked in
+// the working set.
+class CONTENT_EXPORT AppCacheResponseInfo
+ : public base::RefCounted<AppCacheResponseInfo> {
+ public:
+ // AppCacheResponseInfo takes ownership of the http_info.
+ AppCacheResponseInfo(AppCacheStorage* storage, const GURL& manifest_url,
+ int64 response_id, net::HttpResponseInfo* http_info,
+ int64 response_data_size);
+
+ const GURL& manifest_url() const { return manifest_url_; }
+ int64 response_id() const { return response_id_; }
+ const net::HttpResponseInfo* http_response_info() const {
+ return http_response_info_.get();
+ }
+ int64 response_data_size() const { return response_data_size_; }
+
+ private:
+ friend class base::RefCounted<AppCacheResponseInfo>;
+ virtual ~AppCacheResponseInfo();
+
+ const GURL manifest_url_;
+ const int64 response_id_;
+ const scoped_ptr<net::HttpResponseInfo> http_response_info_;
+ const int64 response_data_size_;
+ AppCacheStorage* storage_;
+};
+
+// A refcounted wrapper for HttpResponseInfo so we can apply the
+// refcounting semantics used with IOBuffer with these structures too.
+struct CONTENT_EXPORT HttpResponseInfoIOBuffer
+ : public base::RefCountedThreadSafe<HttpResponseInfoIOBuffer> {
+ scoped_ptr<net::HttpResponseInfo> http_info;
+ int response_data_size;
+
+ HttpResponseInfoIOBuffer();
+ explicit HttpResponseInfoIOBuffer(net::HttpResponseInfo* info);
+
+ protected:
+ friend class base::RefCountedThreadSafe<HttpResponseInfoIOBuffer>;
+ virtual ~HttpResponseInfoIOBuffer();
+};
+
+// Low level storage API used by the response reader and writer.
+class CONTENT_EXPORT AppCacheDiskCacheInterface {
+ public:
+ class Entry {
+ public:
+ virtual int Read(int index, int64 offset, net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) = 0;
+ virtual int Write(int index, int64 offset, net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback) = 0;
+ virtual int64 GetSize(int index) = 0;
+ virtual void Close() = 0;
+ protected:
+ virtual ~Entry() {}
+ };
+
+ virtual int CreateEntry(int64 key, Entry** entry,
+ const net::CompletionCallback& callback) = 0;
+ virtual int OpenEntry(int64 key, Entry** entry,
+ const net::CompletionCallback& callback) = 0;
+ virtual int DoomEntry(int64 key, const net::CompletionCallback& callback) = 0;
+
+ protected:
+ friend class base::RefCounted<AppCacheDiskCacheInterface>;
+ virtual ~AppCacheDiskCacheInterface() {}
+};
+
+// Common base class for response reader and writer.
+class CONTENT_EXPORT AppCacheResponseIO {
+ public:
+ virtual ~AppCacheResponseIO();
+ int64 response_id() const { return response_id_; }
+
+ protected:
+ AppCacheResponseIO(int64 response_id,
+ int64 group_id,
+ AppCacheDiskCacheInterface* disk_cache);
+
+ virtual void OnIOComplete(int result) = 0;
+
+ bool IsIOPending() { return !callback_.is_null(); }
+ void ScheduleIOCompletionCallback(int result);
+ void InvokeUserCompletionCallback(int result);
+ void ReadRaw(int index, int offset, net::IOBuffer* buf, int buf_len);
+ void WriteRaw(int index, int offset, net::IOBuffer* buf, int buf_len);
+
+ const int64 response_id_;
+ const int64 group_id_;
+ AppCacheDiskCacheInterface* disk_cache_;
+ AppCacheDiskCacheInterface::Entry* entry_;
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
+ scoped_refptr<net::IOBuffer> buffer_;
+ int buffer_len_;
+ net::CompletionCallback callback_;
+ base::WeakPtrFactory<AppCacheResponseIO> weak_factory_;
+
+ private:
+ void OnRawIOComplete(int result);
+};
+
+// Reads existing response data from storage. If the object is deleted
+// and there is a read in progress, the implementation will return
+// immediately but will take care of any side effect of cancelling the
+// operation. In other words, instances are safe to delete at will.
+class CONTENT_EXPORT AppCacheResponseReader
+ : public AppCacheResponseIO {
+ public:
+ ~AppCacheResponseReader() override;
+
+ // Reads http info from storage. Always returns the result of the read
+ // asynchronously through the 'callback'. Returns the number of bytes read
+ // or a net:: error code. Guaranteed to not perform partial reads of
+ // the info data. The reader acquires a reference to the 'info_buf' until
+ // completion at which time the callback is invoked with either a negative
+ // error code or the number of bytes read. The 'info_buf' argument should
+ // contain a NULL http_info when ReadInfo is called. The 'callback' is a
+ // required parameter.
+ // Should only be called where there is no Read operation in progress.
+ // (virtual for testing)
+ virtual void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
+ const net::CompletionCallback& callback);
+
+ // Reads data from storage. Always returns the result of the read
+ // asynchronously through the 'callback'. Returns the number of bytes read
+ // or a net:: error code. EOF is indicated with a return value of zero.
+ // The reader acquires a reference to the provided 'buf' until completion
+ // at which time the callback is invoked with either a negative error code
+ // or the number of bytes read. The 'callback' is a required parameter.
+ // Should only be called where there is no Read operation in progress.
+ // (virtual for testing)
+ virtual void ReadData(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback);
+
+ // Returns true if there is a read operation, for data or info, pending.
+ bool IsReadPending() { return IsIOPending(); }
+
+ // Used to support range requests. If not called, the reader will
+ // read the entire response body. If called, this must be called prior
+ // to the first call to the ReadData method.
+ void SetReadRange(int offset, int length);
+
+ protected:
+ friend class AppCacheStorageImpl;
+ friend class content::MockAppCacheStorage;
+
+ // Should only be constructed by the storage class and derivatives.
+ AppCacheResponseReader(int64 response_id,
+ int64 group_id,
+ AppCacheDiskCacheInterface* disk_cache);
+
+ void OnIOComplete(int result) override;
+ void ContinueReadInfo();
+ void ContinueReadData();
+ void OpenEntryIfNeededAndContinue();
+ void OnOpenEntryComplete(AppCacheDiskCacheInterface::Entry** entry, int rv);
+
+ int range_offset_;
+ int range_length_;
+ int read_position_;
+ net::CompletionCallback open_callback_;
+ base::WeakPtrFactory<AppCacheResponseReader> weak_factory_;
+};
+
+// Writes new response data to storage. If the object is deleted
+// and there is a write in progress, the implementation will return
+// immediately but will take care of any side effect of cancelling the
+// operation. In other words, instances are safe to delete at will.
+class CONTENT_EXPORT AppCacheResponseWriter
+ : public AppCacheResponseIO {
+ public:
+ ~AppCacheResponseWriter() override;
+
+ // Writes the http info to storage. Always returns the result of the write
+ // asynchronously through the 'callback'. Returns the number of bytes written
+ // or a net:: error code. The writer acquires a reference to the 'info_buf'
+ // until completion at which time the callback is invoked with either a
+ // negative error code or the number of bytes written. The 'callback' is a
+ // required parameter. The contents of 'info_buf' are not modified.
+ // Should only be called where there is no Write operation in progress.
+ void WriteInfo(HttpResponseInfoIOBuffer* info_buf,
+ const net::CompletionCallback& callback);
+
+ // Writes data to storage. Always returns the result of the write
+ // asynchronously through the 'callback'. Returns the number of bytes written
+ // or a net:: error code. Guaranteed to not perform partial writes.
+ // The writer acquires a reference to the provided 'buf' until completion at
+ // which time the callback is invoked with either a negative error code or
+ // the number of bytes written. The 'callback' is a required parameter.
+ // The contents of 'buf' are not modified.
+ // Should only be called where there is no Write operation in progress.
+ void WriteData(net::IOBuffer* buf, int buf_len,
+ const net::CompletionCallback& callback);
+
+ // Returns true if there is a write pending.
+ bool IsWritePending() { return IsIOPending(); }
+
+ // Returns the amount written, info and data.
+ int64 amount_written() { return info_size_ + write_position_; }
+
+ protected:
+ // Should only be constructed by the storage class and derivatives.
+ AppCacheResponseWriter(int64 response_id,
+ int64 group_id,
+ AppCacheDiskCacheInterface* disk_cache);
+
+ private:
+ friend class AppCacheStorageImpl;
+ friend class content::MockAppCacheStorage;
+
+ enum CreationPhase {
+ NO_ATTEMPT,
+ INITIAL_ATTEMPT,
+ DOOM_EXISTING,
+ SECOND_ATTEMPT
+ };
+
+ void OnIOComplete(int result) override;
+ void ContinueWriteInfo();
+ void ContinueWriteData();
+ void CreateEntryIfNeededAndContinue();
+ void OnCreateEntryComplete(AppCacheDiskCacheInterface::Entry** entry, int rv);
+
+ int info_size_;
+ int write_position_;
+ int write_amount_;
+ CreationPhase creation_phase_;
+ net::CompletionCallback create_callback_;
+ base::WeakPtrFactory<AppCacheResponseWriter> weak_factory_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_RESPONSE_H_
diff --git a/chromium/content/browser/appcache/appcache_response_unittest.cc b/chromium/content/browser/appcache/appcache_response_unittest.cc
index 935fd7cd773..815e69789c8 100644
--- a/chromium/content/browser/appcache/appcache_response_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_response_unittest.cc
@@ -13,18 +13,13 @@
#include "base/pickle.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
+#include "content/browser/appcache/appcache_response.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache_response.h"
-using appcache::AppCacheStorage;
-using appcache::AppCacheResponseInfo;
-using appcache::AppCacheResponseReader;
-using appcache::AppCacheResponseWriter;
-using appcache::HttpResponseInfoIOBuffer;
using net::IOBuffer;
using net::WrappedIOBuffer;
@@ -36,7 +31,6 @@ static const int kNoSuchResponseId = 123;
class AppCacheResponseTest : public testing::Test {
public:
-
// Test Harness -------------------------------------------------------------
// Helper class used to verify test results
@@ -46,8 +40,8 @@ class AppCacheResponseTest : public testing::Test {
: loaded_info_id_(0), test_(test) {
}
- virtual void OnResponseInfoLoaded(AppCacheResponseInfo* info,
- int64 response_id) OVERRIDE {
+ void OnResponseInfoLoaded(AppCacheResponseInfo* info,
+ int64 response_id) override {
loaded_info_ = info;
loaded_info_id_ = response_id;
test_->ScheduleNextTask();
@@ -160,7 +154,7 @@ class AppCacheResponseTest : public testing::Test {
void WriteBasicResponse() {
static const char kHttpHeaders[] =
"HTTP/1.0 200 OK\0Content-Length: 5\0\0";
- static const char* kHttpBody = "Hello";
+ static const char kHttpBody[] = "Hello";
scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBody));
std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
WriteResponse(
@@ -382,8 +376,7 @@ class AppCacheResponseTest : public testing::Test {
// AmountWritten ----------------------------------------------------
void AmountWritten() {
- static const char kHttpHeaders[] =
- "HTTP/1.0 200 OK\0\0";
+ static const char kHttpHeaders[] = "HTTP/1.0 200 OK\0\0";
std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
net::HttpResponseInfo* head = MakeHttpResponseInfo(raw_headers);
int expected_amount_written =
diff --git a/chromium/content/browser/appcache/appcache_service_impl.cc b/chromium/content/browser/appcache/appcache_service_impl.cc
new file mode 100644
index 00000000000..0c784dfd3dc
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_service_impl.cc
@@ -0,0 +1,580 @@
+// 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/appcache/appcache_service_impl.h"
+
+#include <functional>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_backend_impl.h"
+#include "content/browser/appcache/appcache_entry.h"
+#include "content/browser/appcache/appcache_executable_handler.h"
+#include "content/browser/appcache/appcache_histograms.h"
+#include "content/browser/appcache/appcache_policy.h"
+#include "content/browser/appcache/appcache_quota_client.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "content/browser/appcache/appcache_storage_impl.h"
+#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
+#include "storage/browser/quota/special_storage_policy.h"
+
+namespace content {
+
+namespace {
+
+void DeferredCallback(const net::CompletionCallback& callback, int rv) {
+ callback.Run(rv);
+}
+
+} // namespace
+
+AppCacheInfoCollection::AppCacheInfoCollection() {}
+
+AppCacheInfoCollection::~AppCacheInfoCollection() {}
+
+// AsyncHelper -------
+
+class AppCacheServiceImpl::AsyncHelper
+ : public AppCacheStorage::Delegate {
+ public:
+ AsyncHelper(AppCacheServiceImpl* service,
+ const net::CompletionCallback& callback)
+ : service_(service), callback_(callback) {
+ service_->pending_helpers_.insert(this);
+ }
+
+ ~AsyncHelper() override {
+ if (service_)
+ service_->pending_helpers_.erase(this);
+ }
+
+ virtual void Start() = 0;
+ virtual void Cancel();
+
+ protected:
+ void CallCallback(int rv) {
+ if (!callback_.is_null()) {
+ // Defer to guarantee async completion.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE, base::Bind(&DeferredCallback, callback_, rv));
+ }
+ callback_.Reset();
+ }
+
+ AppCacheServiceImpl* service_;
+ net::CompletionCallback callback_;
+};
+
+void AppCacheServiceImpl::AsyncHelper::Cancel() {
+ if (!callback_.is_null()) {
+ callback_.Run(net::ERR_ABORTED);
+ callback_.Reset();
+ }
+ service_->storage()->CancelDelegateCallbacks(this);
+ service_ = NULL;
+}
+
+// CanHandleOfflineHelper -------
+
+class AppCacheServiceImpl::CanHandleOfflineHelper : AsyncHelper {
+ public:
+ CanHandleOfflineHelper(
+ AppCacheServiceImpl* service, const GURL& url,
+ const GURL& first_party, const net::CompletionCallback& callback)
+ : AsyncHelper(service, callback),
+ url_(url),
+ first_party_(first_party) {
+ }
+
+ void Start() override {
+ AppCachePolicy* policy = service_->appcache_policy();
+ if (policy && !policy->CanLoadAppCache(url_, first_party_)) {
+ CallCallback(net::ERR_FAILED);
+ delete this;
+ return;
+ }
+
+ service_->storage()->FindResponseForMainRequest(url_, GURL(), this);
+ }
+
+ private:
+ // AppCacheStorage::Delegate implementation.
+ void OnMainResponseFound(const GURL& url,
+ const AppCacheEntry& entry,
+ const GURL& fallback_url,
+ const AppCacheEntry& fallback_entry,
+ int64 cache_id,
+ int64 group_id,
+ const GURL& mainfest_url) override;
+
+ GURL url_;
+ GURL first_party_;
+
+ DISALLOW_COPY_AND_ASSIGN(CanHandleOfflineHelper);
+};
+
+void AppCacheServiceImpl::CanHandleOfflineHelper::OnMainResponseFound(
+ const GURL& url, const AppCacheEntry& entry,
+ const GURL& fallback_url, const AppCacheEntry& fallback_entry,
+ int64 cache_id, int64 group_id, const GURL& manifest_url) {
+ bool can = (entry.has_response_id() || fallback_entry.has_response_id());
+ CallCallback(can ? net::OK : net::ERR_FAILED);
+ delete this;
+}
+
+// DeleteHelper -------
+
+class AppCacheServiceImpl::DeleteHelper : public AsyncHelper {
+ public:
+ DeleteHelper(
+ AppCacheServiceImpl* service, const GURL& manifest_url,
+ const net::CompletionCallback& callback)
+ : AsyncHelper(service, callback), manifest_url_(manifest_url) {
+ }
+
+ void Start() override {
+ service_->storage()->LoadOrCreateGroup(manifest_url_, this);
+ }
+
+ private:
+ // AppCacheStorage::Delegate implementation.
+ void OnGroupLoaded(AppCacheGroup* group, const GURL& manifest_url) override;
+ void OnGroupMadeObsolete(AppCacheGroup* group,
+ bool success,
+ int response_code) override;
+
+ GURL manifest_url_;
+ DISALLOW_COPY_AND_ASSIGN(DeleteHelper);
+};
+
+void AppCacheServiceImpl::DeleteHelper::OnGroupLoaded(
+ AppCacheGroup* group, const GURL& manifest_url) {
+ if (group) {
+ group->set_being_deleted(true);
+ group->CancelUpdate();
+ service_->storage()->MakeGroupObsolete(group, this, 0);
+ } else {
+ CallCallback(net::ERR_FAILED);
+ delete this;
+ }
+}
+
+void AppCacheServiceImpl::DeleteHelper::OnGroupMadeObsolete(
+ AppCacheGroup* group,
+ bool success,
+ int response_code) {
+ CallCallback(success ? net::OK : net::ERR_FAILED);
+ delete this;
+}
+
+// DeleteOriginHelper -------
+
+class AppCacheServiceImpl::DeleteOriginHelper : public AsyncHelper {
+ public:
+ DeleteOriginHelper(
+ AppCacheServiceImpl* service, const GURL& origin,
+ const net::CompletionCallback& callback)
+ : AsyncHelper(service, callback), origin_(origin),
+ num_caches_to_delete_(0), successes_(0), failures_(0) {
+ }
+
+ void Start() override {
+ // We start by listing all caches, continues in OnAllInfo().
+ service_->storage()->GetAllInfo(this);
+ }
+
+ private:
+ // AppCacheStorage::Delegate implementation.
+ void OnAllInfo(AppCacheInfoCollection* collection) override;
+ void OnGroupLoaded(AppCacheGroup* group, const GURL& manifest_url) override;
+ void OnGroupMadeObsolete(AppCacheGroup* group,
+ bool success,
+ int response_code) override;
+
+ void CacheCompleted(bool success);
+
+ GURL origin_;
+ int num_caches_to_delete_;
+ int successes_;
+ int failures_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeleteOriginHelper);
+};
+
+void AppCacheServiceImpl::DeleteOriginHelper::OnAllInfo(
+ AppCacheInfoCollection* collection) {
+ if (!collection) {
+ // Failed to get a listing.
+ CallCallback(net::ERR_FAILED);
+ delete this;
+ return;
+ }
+
+ std::map<GURL, AppCacheInfoVector>::iterator found =
+ collection->infos_by_origin.find(origin_);
+ if (found == collection->infos_by_origin.end() || found->second.empty()) {
+ // No caches for this origin.
+ CallCallback(net::OK);
+ delete this;
+ return;
+ }
+
+ // We have some caches to delete.
+ const AppCacheInfoVector& caches_to_delete = found->second;
+ successes_ = 0;
+ failures_ = 0;
+ num_caches_to_delete_ = static_cast<int>(caches_to_delete.size());
+ for (AppCacheInfoVector::const_iterator iter = caches_to_delete.begin();
+ iter != caches_to_delete.end(); ++iter) {
+ service_->storage()->LoadOrCreateGroup(iter->manifest_url, this);
+ }
+}
+
+void AppCacheServiceImpl::DeleteOriginHelper::OnGroupLoaded(
+ AppCacheGroup* group, const GURL& manifest_url) {
+ if (group) {
+ group->set_being_deleted(true);
+ group->CancelUpdate();
+ service_->storage()->MakeGroupObsolete(group, this, 0);
+ } else {
+ CacheCompleted(false);
+ }
+}
+
+void AppCacheServiceImpl::DeleteOriginHelper::OnGroupMadeObsolete(
+ AppCacheGroup* group,
+ bool success,
+ int response_code) {
+ CacheCompleted(success);
+}
+
+void AppCacheServiceImpl::DeleteOriginHelper::CacheCompleted(bool success) {
+ if (success)
+ ++successes_;
+ else
+ ++failures_;
+ if ((successes_ + failures_) < num_caches_to_delete_)
+ return;
+
+ CallCallback(!failures_ ? net::OK : net::ERR_FAILED);
+ delete this;
+}
+
+
+// GetInfoHelper -------
+
+class AppCacheServiceImpl::GetInfoHelper : AsyncHelper {
+ public:
+ GetInfoHelper(
+ AppCacheServiceImpl* service, AppCacheInfoCollection* collection,
+ const net::CompletionCallback& callback)
+ : AsyncHelper(service, callback), collection_(collection) {
+ }
+
+ void Start() override { service_->storage()->GetAllInfo(this); }
+
+ private:
+ // AppCacheStorage::Delegate implementation.
+ void OnAllInfo(AppCacheInfoCollection* collection) override;
+
+ scoped_refptr<AppCacheInfoCollection> collection_;
+
+ DISALLOW_COPY_AND_ASSIGN(GetInfoHelper);
+};
+
+void AppCacheServiceImpl::GetInfoHelper::OnAllInfo(
+ AppCacheInfoCollection* collection) {
+ if (collection)
+ collection->infos_by_origin.swap(collection_->infos_by_origin);
+ CallCallback(collection ? net::OK : net::ERR_FAILED);
+ delete this;
+}
+
+// CheckResponseHelper -------
+
+class AppCacheServiceImpl::CheckResponseHelper : AsyncHelper {
+ public:
+ CheckResponseHelper(
+ AppCacheServiceImpl* service, const GURL& manifest_url, int64 cache_id,
+ int64 response_id)
+ : AsyncHelper(service, net::CompletionCallback()),
+ manifest_url_(manifest_url),
+ cache_id_(cache_id),
+ response_id_(response_id),
+ kIOBufferSize(32 * 1024),
+ expected_total_size_(0),
+ amount_headers_read_(0),
+ amount_data_read_(0) {
+ }
+
+ void Start() override {
+ service_->storage()->LoadOrCreateGroup(manifest_url_, this);
+ }
+
+ void Cancel() override {
+ AppCacheHistograms::CountCheckResponseResult(
+ AppCacheHistograms::CHECK_CANCELED);
+ response_reader_.reset();
+ AsyncHelper::Cancel();
+ }
+
+ private:
+ void OnGroupLoaded(AppCacheGroup* group, const GURL& manifest_url) override;
+ void OnReadInfoComplete(int result);
+ void OnReadDataComplete(int result);
+
+ // Inputs describing what to check.
+ GURL manifest_url_;
+ int64 cache_id_;
+ int64 response_id_;
+
+ // Internals used to perform the checks.
+ const int kIOBufferSize;
+ scoped_refptr<AppCache> cache_;
+ scoped_ptr<AppCacheResponseReader> response_reader_;
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
+ scoped_refptr<net::IOBuffer> data_buffer_;
+ int64 expected_total_size_;
+ int amount_headers_read_;
+ int amount_data_read_;
+ DISALLOW_COPY_AND_ASSIGN(CheckResponseHelper);
+};
+
+void AppCacheServiceImpl::CheckResponseHelper::OnGroupLoaded(
+ AppCacheGroup* group, const GURL& manifest_url) {
+ DCHECK_EQ(manifest_url_, manifest_url);
+ if (!group || !group->newest_complete_cache() || group->is_being_deleted() ||
+ group->is_obsolete()) {
+ AppCacheHistograms::CountCheckResponseResult(
+ AppCacheHistograms::MANIFEST_OUT_OF_DATE);
+ delete this;
+ return;
+ }
+
+ cache_ = group->newest_complete_cache();
+ const AppCacheEntry* entry = cache_->GetEntryWithResponseId(response_id_);
+ if (!entry) {
+ if (cache_->cache_id() == cache_id_) {
+ AppCacheHistograms::CountCheckResponseResult(
+ AppCacheHistograms::ENTRY_NOT_FOUND);
+ service_->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+ } else {
+ AppCacheHistograms::CountCheckResponseResult(
+ AppCacheHistograms::RESPONSE_OUT_OF_DATE);
+ }
+ delete this;
+ return;
+ }
+
+ // Verify that we can read the response info and data.
+ expected_total_size_ = entry->response_size();
+ response_reader_.reset(service_->storage()->CreateResponseReader(
+ manifest_url_, group->group_id(), response_id_));
+ info_buffer_ = new HttpResponseInfoIOBuffer();
+ response_reader_->ReadInfo(
+ info_buffer_.get(),
+ base::Bind(&CheckResponseHelper::OnReadInfoComplete,
+ base::Unretained(this)));
+}
+
+void AppCacheServiceImpl::CheckResponseHelper::OnReadInfoComplete(int result) {
+ if (result < 0) {
+ AppCacheHistograms::CountCheckResponseResult(
+ AppCacheHistograms::READ_HEADERS_ERROR);
+ service_->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+ delete this;
+ return;
+ }
+ amount_headers_read_ = result;
+
+ // Start reading the data.
+ data_buffer_ = new net::IOBuffer(kIOBufferSize);
+ response_reader_->ReadData(
+ data_buffer_.get(),
+ kIOBufferSize,
+ base::Bind(&CheckResponseHelper::OnReadDataComplete,
+ base::Unretained(this)));
+}
+
+void AppCacheServiceImpl::CheckResponseHelper::OnReadDataComplete(int result) {
+ if (result > 0) {
+ // Keep reading until we've read thru everything or failed to read.
+ amount_data_read_ += result;
+ response_reader_->ReadData(
+ data_buffer_.get(),
+ kIOBufferSize,
+ base::Bind(&CheckResponseHelper::OnReadDataComplete,
+ base::Unretained(this)));
+ return;
+ }
+
+ AppCacheHistograms::CheckResponseResultType check_result;
+ if (result < 0)
+ check_result = AppCacheHistograms::READ_DATA_ERROR;
+ else if (info_buffer_->response_data_size != amount_data_read_ ||
+ expected_total_size_ != amount_data_read_ + amount_headers_read_)
+ check_result = AppCacheHistograms::UNEXPECTED_DATA_SIZE;
+ else
+ check_result = AppCacheHistograms::RESPONSE_OK;
+ AppCacheHistograms::CountCheckResponseResult(check_result);
+
+ if (check_result != AppCacheHistograms::RESPONSE_OK)
+ service_->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+ delete this;
+}
+
+// AppCacheStorageReference ------
+
+AppCacheStorageReference::AppCacheStorageReference(
+ scoped_ptr<AppCacheStorage> storage)
+ : storage_(storage.Pass()) {}
+AppCacheStorageReference::~AppCacheStorageReference() {}
+
+// AppCacheServiceImpl -------
+
+AppCacheServiceImpl::AppCacheServiceImpl(
+ storage::QuotaManagerProxy* quota_manager_proxy)
+ : appcache_policy_(NULL),
+ quota_client_(NULL),
+ handler_factory_(NULL),
+ quota_manager_proxy_(quota_manager_proxy),
+ request_context_(NULL),
+ force_keep_session_state_(false) {
+ if (quota_manager_proxy_.get()) {
+ quota_client_ = new AppCacheQuotaClient(this);
+ quota_manager_proxy_->RegisterClient(quota_client_);
+ }
+}
+
+AppCacheServiceImpl::~AppCacheServiceImpl() {
+ DCHECK(backends_.empty());
+ std::for_each(pending_helpers_.begin(),
+ pending_helpers_.end(),
+ std::mem_fun(&AsyncHelper::Cancel));
+ STLDeleteElements(&pending_helpers_);
+ if (quota_client_)
+ quota_client_->NotifyAppCacheDestroyed();
+
+ // Destroy storage_ first; ~AppCacheStorageImpl accesses other data members
+ // (special_storage_policy_).
+ storage_.reset();
+}
+
+void AppCacheServiceImpl::Initialize(
+ const base::FilePath& cache_directory,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread) {
+ DCHECK(!storage_.get());
+ cache_directory_ = cache_directory;
+ db_thread_ = db_thread;
+ cache_thread_ = cache_thread;
+ AppCacheStorageImpl* storage = new AppCacheStorageImpl(this);
+ storage->Initialize(cache_directory, db_thread, cache_thread);
+ storage_.reset(storage);
+}
+
+void AppCacheServiceImpl::ScheduleReinitialize() {
+ if (reinit_timer_.IsRunning())
+ return;
+
+ // Reinitialization only happens when corruption has been noticed.
+ // We don't want to thrash the disk but we also don't want to
+ // leave the appcache disabled for an indefinite period of time. Some
+ // users never shutdown the browser.
+
+ const base::TimeDelta kZeroDelta;
+ const base::TimeDelta kOneHour(base::TimeDelta::FromHours(1));
+ const base::TimeDelta k30Seconds(base::TimeDelta::FromSeconds(30));
+
+ // If the system managed to stay up for long enough, reset the
+ // delay so a new failure won't incur a long wait to get going again.
+ base::TimeDelta up_time = base::Time::Now() - last_reinit_time_;
+ if (next_reinit_delay_ != kZeroDelta && up_time > kOneHour)
+ next_reinit_delay_ = kZeroDelta;
+
+ reinit_timer_.Start(FROM_HERE, next_reinit_delay_,
+ this, &AppCacheServiceImpl::Reinitialize);
+
+ // Adjust the delay for next time.
+ base::TimeDelta increment = std::max(k30Seconds, next_reinit_delay_);
+ next_reinit_delay_ = std::min(next_reinit_delay_ + increment, kOneHour);
+}
+
+void AppCacheServiceImpl::Reinitialize() {
+ AppCacheHistograms::CountReinitAttempt(!last_reinit_time_.is_null());
+ last_reinit_time_ = base::Time::Now();
+
+ // Inform observers of about this and give them a chance to
+ // defer deletion of the old storage object.
+ scoped_refptr<AppCacheStorageReference>
+ old_storage_ref(new AppCacheStorageReference(storage_.Pass()));
+ FOR_EACH_OBSERVER(Observer, observers_,
+ OnServiceReinitialized(old_storage_ref.get()));
+
+ Initialize(cache_directory_, db_thread_, cache_thread_);
+}
+
+void AppCacheServiceImpl::CanHandleMainResourceOffline(
+ const GURL& url,
+ const GURL& first_party,
+ const net::CompletionCallback& callback) {
+ CanHandleOfflineHelper* helper =
+ new CanHandleOfflineHelper(this, url, first_party, callback);
+ helper->Start();
+}
+
+void AppCacheServiceImpl::GetAllAppCacheInfo(
+ AppCacheInfoCollection* collection,
+ const net::CompletionCallback& callback) {
+ DCHECK(collection);
+ GetInfoHelper* helper = new GetInfoHelper(this, collection, callback);
+ helper->Start();
+}
+
+void AppCacheServiceImpl::DeleteAppCacheGroup(
+ const GURL& manifest_url,
+ const net::CompletionCallback& callback) {
+ DeleteHelper* helper = new DeleteHelper(this, manifest_url, callback);
+ helper->Start();
+}
+
+void AppCacheServiceImpl::DeleteAppCachesForOrigin(
+ const GURL& origin, const net::CompletionCallback& callback) {
+ DeleteOriginHelper* helper = new DeleteOriginHelper(this, origin, callback);
+ helper->Start();
+}
+
+void AppCacheServiceImpl::CheckAppCacheResponse(const GURL& manifest_url,
+ int64 cache_id,
+ int64 response_id) {
+ CheckResponseHelper* helper = new CheckResponseHelper(
+ this, manifest_url, cache_id, response_id);
+ helper->Start();
+}
+
+void AppCacheServiceImpl::set_special_storage_policy(
+ storage::SpecialStoragePolicy* policy) {
+ special_storage_policy_ = policy;
+}
+
+void AppCacheServiceImpl::RegisterBackend(
+ AppCacheBackendImpl* backend_impl) {
+ DCHECK(backends_.find(backend_impl->process_id()) == backends_.end());
+ backends_.insert(
+ BackendMap::value_type(backend_impl->process_id(), backend_impl));
+}
+
+void AppCacheServiceImpl::UnregisterBackend(
+ AppCacheBackendImpl* backend_impl) {
+ backends_.erase(backend_impl->process_id());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_service_impl.h b/chromium/content/browser/appcache/appcache_service_impl.h
new file mode 100644
index 00000000000..cb61f3a47d6
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_service_impl.h
@@ -0,0 +1,222 @@
+// 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_APPCACHE_APPCACHE_SERVICE_IMPL_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_SERVICE_IMPL_H_
+
+#include <map>
+#include <set>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "content/common/appcache_interfaces.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/appcache_service.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+
+namespace base {
+class FilePath;
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace net {
+class URLRequestContext;
+} // namespace net
+
+namespace storage {
+class SpecialStoragePolicy;
+} // namespace storage
+
+namespace content {
+FORWARD_DECLARE_TEST(AppCacheServiceImplTest, ScheduleReinitialize);
+class AppCacheBackendImpl;
+class AppCacheExecutableHandlerFactory;
+class AppCacheQuotaClient;
+class AppCachePolicy;
+class AppCacheServiceImplTest;
+class AppCacheStorageImplTest;
+class AppCacheStorage;
+
+// Refcounted container to manage the lifetime of the old storage instance
+// during Reinitialization.
+class CONTENT_EXPORT AppCacheStorageReference
+ : public base::RefCounted<AppCacheStorageReference> {
+public:
+ AppCacheStorage* storage() const { return storage_.get(); }
+private:
+ friend class AppCacheServiceImpl;
+ friend class base::RefCounted<AppCacheStorageReference>;
+ AppCacheStorageReference(scoped_ptr<AppCacheStorage> storage);
+ ~AppCacheStorageReference();
+
+ scoped_ptr<AppCacheStorage> storage_;
+};
+
+// Class that manages the application cache service. Sends notifications
+// to many frontends. One instance per user-profile. Each instance has
+// exclusive access to its cache_directory on disk.
+class CONTENT_EXPORT AppCacheServiceImpl
+ : public AppCacheService {
+ public:
+
+ class CONTENT_EXPORT Observer {
+ public:
+ // An observer method to inform consumers of reinitialzation. Managing
+ // the lifetime of the old storage instance is a delicate process.
+ // Consumers can keep the old disabled instance alive by hanging on to the
+ // ref provided.
+ virtual void OnServiceReinitialized(
+ AppCacheStorageReference* old_storage_ref) = 0;
+ virtual ~Observer() {}
+ };
+
+ // If not using quota management, the proxy may be NULL.
+ explicit AppCacheServiceImpl(storage::QuotaManagerProxy* quota_manager_proxy);
+ ~AppCacheServiceImpl() override;
+
+ void Initialize(
+ const base::FilePath& cache_directory,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread);
+
+ void AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+ }
+
+ // For use in catastrophic failure modes to reboot the appcache system
+ // without relaunching the browser.
+ void ScheduleReinitialize();
+
+ // AppCacheService implementation:
+ void CanHandleMainResourceOffline(
+ const GURL& url,
+ const GURL& first_party,
+ const net::CompletionCallback& callback) override;
+ void GetAllAppCacheInfo(AppCacheInfoCollection* collection,
+ const net::CompletionCallback& callback) override;
+ void DeleteAppCacheGroup(const GURL& manifest_url,
+ const net::CompletionCallback& callback) override;
+
+ // Deletes all appcaches for the origin, 'callback' is invoked upon
+ // completion. This method always completes asynchronously.
+ // (virtual for unit testing)
+ virtual void DeleteAppCachesForOrigin(
+ const GURL& origin, const net::CompletionCallback& callback);
+
+ // Checks the integrity of 'response_id' by reading the headers and data.
+ // If it cannot be read, the cache group for 'manifest_url' is deleted.
+ void CheckAppCacheResponse(const GURL& manifest_url, int64 cache_id,
+ int64 response_id);
+
+ // Context for use during cache updates, should only be accessed
+ // on the IO thread. We do NOT add a reference to the request context,
+ // it is the callers responsibility to ensure that the pointer
+ // remains valid while set.
+ net::URLRequestContext* request_context() const { return request_context_; }
+ void set_request_context(net::URLRequestContext* context) {
+ request_context_ = context;
+ }
+
+ // The appcache policy, may be null, in which case access is always allowed.
+ // The service does NOT assume ownership of the policy, it is the callers
+ // responsibility to ensure that the pointer remains valid while set.
+ AppCachePolicy* appcache_policy() const { return appcache_policy_; }
+ void set_appcache_policy(AppCachePolicy* policy) {
+ appcache_policy_ = policy;
+ }
+
+ // The factory may be null, in which case invocations of exe handlers
+ // will result in an error response.
+ // The service does NOT assume ownership of the factory, it is the callers
+ // responsibility to ensure that the pointer remains valid while set.
+ AppCacheExecutableHandlerFactory* handler_factory() const {
+ return handler_factory_;
+ }
+ void set_handler_factory(
+ AppCacheExecutableHandlerFactory* factory) {
+ handler_factory_ = factory;
+ }
+
+ storage::SpecialStoragePolicy* special_storage_policy() const {
+ return special_storage_policy_.get();
+ }
+ void set_special_storage_policy(storage::SpecialStoragePolicy* policy);
+
+ storage::QuotaManagerProxy* quota_manager_proxy() const {
+ return quota_manager_proxy_.get();
+ }
+
+ AppCacheQuotaClient* quota_client() const {
+ return quota_client_;
+ }
+
+ // Each child process in chrome uses a distinct backend instance.
+ // See chrome/browser/AppCacheDispatcherHost.
+ void RegisterBackend(AppCacheBackendImpl* backend_impl);
+ void UnregisterBackend(AppCacheBackendImpl* backend_impl);
+ AppCacheBackendImpl* GetBackend(int id) const {
+ BackendMap::const_iterator it = backends_.find(id);
+ return (it != backends_.end()) ? it->second : NULL;
+ }
+
+ AppCacheStorage* storage() const { return storage_.get(); }
+
+ // Disables the exit-time deletion of session-only data.
+ void set_force_keep_session_state() { force_keep_session_state_ = true; }
+ bool force_keep_session_state() const { return force_keep_session_state_; }
+
+ protected:
+ friend class content::AppCacheServiceImplTest;
+ friend class content::AppCacheStorageImplTest;
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheServiceImplTest,
+ ScheduleReinitialize);
+
+ class AsyncHelper;
+ class CanHandleOfflineHelper;
+ class DeleteHelper;
+ class DeleteOriginHelper;
+ class GetInfoHelper;
+ class CheckResponseHelper;
+
+ typedef std::set<AsyncHelper*> PendingAsyncHelpers;
+ typedef std::map<int, AppCacheBackendImpl*> BackendMap;
+
+ void Reinitialize();
+
+ base::FilePath cache_directory_;
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> cache_thread_;
+ AppCachePolicy* appcache_policy_;
+ AppCacheQuotaClient* quota_client_;
+ AppCacheExecutableHandlerFactory* handler_factory_;
+ scoped_ptr<AppCacheStorage> storage_;
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+ PendingAsyncHelpers pending_helpers_;
+ BackendMap backends_; // One 'backend' per child process.
+ // Context for use during cache updates.
+ net::URLRequestContext* request_context_;
+ // If true, nothing (not even session-only data) should be deleted on exit.
+ bool force_keep_session_state_;
+ base::Time last_reinit_time_;
+ base::TimeDelta next_reinit_delay_;
+ base::OneShotTimer<AppCacheServiceImpl> reinit_timer_;
+ ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheServiceImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_SERVICE_IMPL_H_
diff --git a/chromium/content/browser/appcache/appcache_service_unittest.cc b/chromium/content/browser/appcache/appcache_service_unittest.cc
index 80016a94784..b3532f5a25a 100644
--- a/chromium/content/browser/appcache/appcache_service_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_service_unittest.cc
@@ -8,23 +8,13 @@
#include "base/bind_helpers.h"
#include "base/pickle.h"
#include "base/run_loop.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_service_impl.h"
#include "content/browser/appcache/mock_appcache_storage.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_service_impl.h"
-
-using appcache::AppCache;
-using appcache::AppCacheEntry;
-using appcache::AppCacheGroup;
-using appcache::AppCacheInfo;
-using appcache::AppCacheInfoCollection;
-using appcache::AppCacheInfoVector;
-using appcache::AppCacheResponseReader;
-using appcache::AppCacheServiceImpl;
-using appcache::HttpResponseInfoIOBuffer;
namespace content {
namespace {
@@ -48,8 +38,8 @@ class MockResponseReader : public AppCacheResponseReader {
info_(info), info_size_(info_size),
data_(data), data_size_(data_size) {
}
- virtual void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
- const net::CompletionCallback& callback) OVERRIDE {
+ void ReadInfo(HttpResponseInfoIOBuffer* info_buf,
+ const net::CompletionCallback& callback) override {
info_buffer_ = info_buf;
callback_ = callback; // Cleared on completion.
@@ -58,8 +48,9 @@ class MockResponseReader : public AppCacheResponseReader {
info_buffer_->response_data_size = data_size_;
ScheduleUserCallback(rv);
}
- virtual void ReadData(net::IOBuffer* buf, int buf_len,
- const net::CompletionCallback& callback) OVERRIDE {
+ void ReadData(net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) override {
buffer_ = buf;
buffer_len_ = buf_len;
callback_ = callback; // Cleared on completion.
@@ -199,7 +190,7 @@ TEST_F(AppCacheServiceImplTest, DeleteAppCachesForOrigin) {
delete_completion_count_ = 0;
// Should succeed given an empty info collection.
- mock_storage()->SimulateGetAllInfo(new AppCacheInfoCollection);
+ mock_storage()->SimulateGetAllInfo(new content::AppCacheInfoCollection);
service_->DeleteAppCachesForOrigin(kOrigin, deletion_callback_);
EXPECT_EQ(0, delete_completion_count_);
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/appcache/appcache_storage.cc b/chromium/content/browser/appcache/appcache_storage.cc
new file mode 100644
index 00000000000..077000616ae
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_storage.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2009 The Chromium Authors. 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/appcache/appcache_storage.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/stl_util.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+
+namespace content {
+
+// static
+const int64 AppCacheStorage::kUnitializedId = -1;
+
+AppCacheStorage::AppCacheStorage(AppCacheServiceImpl* service)
+ : last_cache_id_(kUnitializedId), last_group_id_(kUnitializedId),
+ last_response_id_(kUnitializedId), service_(service) {
+}
+
+AppCacheStorage::~AppCacheStorage() {
+ STLDeleteValues(&pending_info_loads_);
+ DCHECK(delegate_references_.empty());
+}
+
+AppCacheStorage::DelegateReference::DelegateReference(
+ Delegate* delegate, AppCacheStorage* storage)
+ : delegate(delegate), storage(storage) {
+ storage->delegate_references_.insert(
+ DelegateReferenceMap::value_type(delegate, this));
+}
+
+AppCacheStorage::DelegateReference::~DelegateReference() {
+ if (delegate)
+ storage->delegate_references_.erase(delegate);
+}
+
+AppCacheStorage::ResponseInfoLoadTask::ResponseInfoLoadTask(
+ const GURL& manifest_url,
+ int64 group_id,
+ int64 response_id,
+ AppCacheStorage* storage)
+ : storage_(storage),
+ manifest_url_(manifest_url),
+ group_id_(group_id),
+ response_id_(response_id),
+ info_buffer_(new HttpResponseInfoIOBuffer) {
+ storage_->pending_info_loads_.insert(
+ PendingResponseInfoLoads::value_type(response_id, this));
+}
+
+AppCacheStorage::ResponseInfoLoadTask::~ResponseInfoLoadTask() {
+}
+
+void AppCacheStorage::ResponseInfoLoadTask::StartIfNeeded() {
+ if (reader_)
+ return;
+ reader_.reset(
+ storage_->CreateResponseReader(manifest_url_, group_id_, response_id_));
+ reader_->ReadInfo(info_buffer_.get(),
+ base::Bind(&ResponseInfoLoadTask::OnReadComplete,
+ base::Unretained(this)));
+}
+
+void AppCacheStorage::ResponseInfoLoadTask::OnReadComplete(int result) {
+ storage_->pending_info_loads_.erase(response_id_);
+ scoped_refptr<AppCacheResponseInfo> info;
+ if (result >= 0) {
+ info = new AppCacheResponseInfo(storage_, manifest_url_,
+ response_id_,
+ info_buffer_->http_info.release(),
+ info_buffer_->response_data_size);
+ }
+ FOR_EACH_DELEGATE(delegates_, OnResponseInfoLoaded(info.get(), response_id_));
+ delete this;
+}
+
+void AppCacheStorage::LoadResponseInfo(
+ const GURL& manifest_url, int64 group_id, int64 id, Delegate* delegate) {
+ AppCacheResponseInfo* info = working_set_.GetResponseInfo(id);
+ if (info) {
+ delegate->OnResponseInfoLoaded(info, id);
+ return;
+ }
+ ResponseInfoLoadTask* info_load =
+ GetOrCreateResponseInfoLoadTask(manifest_url, group_id, id);
+ DCHECK(manifest_url == info_load->manifest_url());
+ DCHECK(group_id == info_load->group_id());
+ DCHECK(id == info_load->response_id());
+ info_load->AddDelegate(GetOrCreateDelegateReference(delegate));
+ info_load->StartIfNeeded();
+}
+
+void AppCacheStorage::UpdateUsageMapAndNotify(
+ const GURL& origin, int64 new_usage) {
+ DCHECK_GE(new_usage, 0);
+ int64 old_usage = usage_map_[origin];
+ if (new_usage > 0)
+ usage_map_[origin] = new_usage;
+ else
+ usage_map_.erase(origin);
+ if (new_usage != old_usage && service()->quota_manager_proxy()) {
+ service()->quota_manager_proxy()->NotifyStorageModified(
+ storage::QuotaClient::kAppcache,
+ origin,
+ storage::kStorageTypeTemporary,
+ new_usage - old_usage);
+ }
+}
+
+void AppCacheStorage::ClearUsageMapAndNotify() {
+ if (service()->quota_manager_proxy()) {
+ for (UsageMap::const_iterator iter = usage_map_.begin();
+ iter != usage_map_.end(); ++iter) {
+ service()->quota_manager_proxy()->NotifyStorageModified(
+ storage::QuotaClient::kAppcache,
+ iter->first,
+ storage::kStorageTypeTemporary,
+ -(iter->second));
+ }
+ }
+ usage_map_.clear();
+}
+
+void AppCacheStorage::NotifyStorageAccessed(const GURL& origin) {
+ if (service()->quota_manager_proxy() &&
+ usage_map_.find(origin) != usage_map_.end())
+ service()->quota_manager_proxy()->NotifyStorageAccessed(
+ storage::QuotaClient::kAppcache,
+ origin,
+ storage::kStorageTypeTemporary);
+}
+
+} // namespace content
+
diff --git a/chromium/content/browser/appcache/appcache_storage.h b/chromium/content/browser/appcache/appcache_storage.h
new file mode 100644
index 00000000000..edc059b9381
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_storage.h
@@ -0,0 +1,327 @@
+// 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_APPCACHE_APPCACHE_STORAGE_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_
+
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/appcache/appcache_working_set.h"
+#include "content/common/content_export.h"
+#include "net/base/completion_callback.h"
+
+class GURL;
+
+namespace content {
+FORWARD_DECLARE_TEST(AppCacheStorageTest, DelegateReferences);
+FORWARD_DECLARE_TEST(AppCacheStorageTest, UsageMap);
+class AppCache;
+class AppCacheEntry;
+class AppCacheGroup;
+class AppCacheQuotaClientTest;
+class AppCacheResponseReader;
+class AppCacheResponseTest;
+class AppCacheResponseWriter;
+class AppCacheServiceImpl;
+class AppCacheStorageTest;
+struct AppCacheInfoCollection;
+struct HttpResponseInfoIOBuffer;
+
+class CONTENT_EXPORT AppCacheStorage {
+ public:
+ typedef std::map<GURL, int64> UsageMap;
+
+ class CONTENT_EXPORT Delegate {
+ public:
+ // If retrieval fails, 'collection' will be NULL.
+ virtual void OnAllInfo(AppCacheInfoCollection* collection) {}
+
+ // If a load fails the 'cache' will be NULL.
+ virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) {}
+
+ // If a load fails the 'group' will be NULL.
+ virtual void OnGroupLoaded(
+ AppCacheGroup* group, const GURL& manifest_url) {}
+
+ // If successfully stored 'success' will be true.
+ virtual void OnGroupAndNewestCacheStored(
+ AppCacheGroup* group, AppCache* newest_cache, bool success,
+ bool would_exceed_quota) {}
+
+ // If the operation fails, success will be false.
+ virtual void OnGroupMadeObsolete(AppCacheGroup* group,
+ bool success,
+ int response_code) {}
+
+ // If a load fails the 'response_info' will be NULL.
+ virtual void OnResponseInfoLoaded(
+ AppCacheResponseInfo* response_info, int64 response_id) {}
+
+ // If no response is found, entry.response_id() and
+ // fallback_entry.response_id() will be kAppCacheNoResponseId.
+ // If the response is the entry for an intercept or fallback
+ // namespace, the url of the namespece entry is returned.
+ // If a response is found, the cache id and manifest url of the
+ // containing cache and group are also returned.
+ virtual void OnMainResponseFound(
+ const GURL& url, const AppCacheEntry& entry,
+ const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
+ int64 cache_id, int64 group_id, const GURL& mainfest_url) {}
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ explicit AppCacheStorage(AppCacheServiceImpl* service);
+ virtual ~AppCacheStorage();
+
+ // Schedules a task to retrieve basic info about all groups and caches
+ // stored in the system. Upon completion the delegate will be called
+ // with the results.
+ virtual void GetAllInfo(Delegate* delegate) = 0;
+
+ // Schedules a cache to be loaded from storage. Upon load completion
+ // the delegate will be called back. If the cache already resides in
+ // memory, the delegate will be called back immediately without returning
+ // to the message loop. If the load fails, the delegate will be called
+ // back with a NULL cache pointer.
+ virtual void LoadCache(int64 id, Delegate* delegate) = 0;
+
+ // Schedules a group and its newest cache, if any, to be loaded from storage.
+ // Upon load completion the delegate will be called back. If the group
+ // and newest cache already reside in memory, the delegate will be called
+ // back immediately without returning to the message loop. If the load fails,
+ // the delegate will be called back with a NULL group pointer.
+ virtual void LoadOrCreateGroup(
+ const GURL& manifest_url, Delegate* delegate) = 0;
+
+ // Schedules response info to be loaded from storage.
+ // Upon load completion the delegate will be called back. If the data
+ // already resides in memory, the delegate will be called back
+ // immediately without returning to the message loop. If the load fails,
+ // the delegate will be called back with a NULL pointer.
+ virtual void LoadResponseInfo(
+ const GURL& manifest_url, int64 group_id, int64 response_id,
+ Delegate* delegate);
+
+ // Schedules a group and its newest complete cache to be initially stored or
+ // incrementally updated with new changes. Upon completion the delegate
+ // will be called back. A group without a newest cache cannot be stored.
+ // It's a programming error to call this method without a newest cache. A
+ // side effect of storing a new newest cache is the removal of the group's
+ // old caches and responses from persistent storage (although they may still
+ // linger in the in-memory working set until no longer needed). The new
+ // cache will be added as the group's newest complete cache only if storage
+ // succeeds.
+ virtual void StoreGroupAndNewestCache(
+ AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate) = 0;
+
+ // Schedules a query to identify a response for a main request. Upon
+ // completion the delegate will be called back.
+ virtual void FindResponseForMainRequest(
+ const GURL& url,
+ const GURL& preferred_manifest_url,
+ Delegate* delegate) = 0;
+
+ // Performs an immediate lookup of the in-memory cache to
+ // identify a response for a sub resource request.
+ virtual void FindResponseForSubRequest(
+ AppCache* cache, const GURL& url,
+ AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
+ bool* found_network_namespace) = 0;
+
+ // Immediately updates in-memory storage, if the cache is in memory,
+ // and schedules a task to update persistent storage. If the cache is
+ // already scheduled to be loaded, upon loading completion the entry
+ // will be marked. There is no delegate completion callback.
+ virtual void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id) = 0;
+
+ // Schedules a task to update persistent storage and doom the group and all
+ // related caches and responses for deletion. Upon completion the in-memory
+ // instance is marked as obsolete and the delegate callback is called.
+ virtual void MakeGroupObsolete(AppCacheGroup* group,
+ Delegate* delegate,
+ int response_code) = 0;
+
+ // Cancels all pending callbacks for the delegate. The delegate callbacks
+ // will not be invoked after, however any scheduled operations will still
+ // take place. The callbacks for subsequently scheduled operations are
+ // unaffected.
+ void CancelDelegateCallbacks(Delegate* delegate) {
+ DelegateReference* delegate_reference = GetDelegateReference(delegate);
+ if (delegate_reference)
+ delegate_reference->CancelReference();
+ }
+
+ // Creates a reader to read a response from storage.
+ virtual AppCacheResponseReader* CreateResponseReader(
+ const GURL& manifest_url, int64 group_id, int64 response_id) = 0;
+
+ // Creates a writer to write a new response to storage. This call
+ // establishes a new response id.
+ virtual AppCacheResponseWriter* CreateResponseWriter(
+ const GURL& manifest_url, int64 group_id) = 0;
+
+ // Schedules the lazy deletion of responses and saves the ids
+ // persistently such that the responses will be deleted upon restart
+ // if they aren't deleted prior to shutdown.
+ virtual void DoomResponses(
+ const GURL& manifest_url, const std::vector<int64>& response_ids) = 0;
+
+ // Schedules the lazy deletion of responses without persistently saving
+ // the response ids.
+ virtual void DeleteResponses(
+ const GURL& manifest_url, const std::vector<int64>& response_ids) = 0;
+
+ // Generates unique storage ids for different object types.
+ int64 NewCacheId() {
+ return ++last_cache_id_;
+ }
+ int64 NewGroupId() {
+ return ++last_group_id_;
+ }
+
+ // The working set of object instances currently in memory.
+ AppCacheWorkingSet* working_set() { return &working_set_; }
+
+ // A map of origins to usage.
+ const UsageMap* usage_map() { return &usage_map_; }
+
+ // Simple ptr back to the service object that owns us.
+ AppCacheServiceImpl* service() { return service_; }
+
+ protected:
+ friend class content::AppCacheQuotaClientTest;
+ friend class content::AppCacheResponseTest;
+ friend class content::AppCacheStorageTest;
+
+ // Helper to call a collection of delegates.
+ #define FOR_EACH_DELEGATE(delegates, func_and_args) \
+ do { \
+ for (DelegateReferenceVector::iterator it = delegates.begin(); \
+ it != delegates.end(); ++it) { \
+ if (it->get()->delegate) \
+ it->get()->delegate->func_and_args; \
+ } \
+ } while (0)
+
+ // Helper used to manage multiple references to a 'delegate' and to
+ // allow all pending callbacks to that delegate to be easily cancelled.
+ struct CONTENT_EXPORT DelegateReference :
+ public base::RefCounted<DelegateReference> {
+ Delegate* delegate;
+ AppCacheStorage* storage;
+
+ DelegateReference(Delegate* delegate, AppCacheStorage* storage);
+
+ void CancelReference() {
+ storage->delegate_references_.erase(delegate);
+ storage = NULL;
+ delegate = NULL;
+ }
+
+ private:
+ friend class base::RefCounted<DelegateReference>;
+
+ virtual ~DelegateReference();
+ };
+ typedef std::map<Delegate*, DelegateReference*> DelegateReferenceMap;
+ typedef std::vector<scoped_refptr<DelegateReference> >
+ DelegateReferenceVector;
+
+ // Helper used to manage an async LoadResponseInfo calls on behalf of
+ // multiple callers.
+ class ResponseInfoLoadTask {
+ public:
+ ResponseInfoLoadTask(const GURL& manifest_url, int64 group_id,
+ int64 response_id, AppCacheStorage* storage);
+ ~ResponseInfoLoadTask();
+
+ int64 response_id() const { return response_id_; }
+ const GURL& manifest_url() const { return manifest_url_; }
+ int64 group_id() const { return group_id_; }
+
+ void AddDelegate(DelegateReference* delegate_reference) {
+ delegates_.push_back(delegate_reference);
+ }
+
+ void StartIfNeeded();
+
+ private:
+ void OnReadComplete(int result);
+
+ AppCacheStorage* storage_;
+ GURL manifest_url_;
+ int64 group_id_;
+ int64 response_id_;
+ scoped_ptr<AppCacheResponseReader> reader_;
+ DelegateReferenceVector delegates_;
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
+ };
+
+ typedef std::map<int64, ResponseInfoLoadTask*> PendingResponseInfoLoads;
+
+ DelegateReference* GetDelegateReference(Delegate* delegate) {
+ DelegateReferenceMap::iterator iter =
+ delegate_references_.find(delegate);
+ if (iter != delegate_references_.end())
+ return iter->second;
+ return NULL;
+ }
+
+ DelegateReference* GetOrCreateDelegateReference(Delegate* delegate) {
+ DelegateReference* reference = GetDelegateReference(delegate);
+ if (reference)
+ return reference;
+ return new DelegateReference(delegate, this);
+ }
+
+ ResponseInfoLoadTask* GetOrCreateResponseInfoLoadTask(
+ const GURL& manifest_url, int64 group_id, int64 response_id) {
+ PendingResponseInfoLoads::iterator iter =
+ pending_info_loads_.find(response_id);
+ if (iter != pending_info_loads_.end())
+ return iter->second;
+ return new ResponseInfoLoadTask(manifest_url, group_id, response_id, this);
+ }
+
+ // Should only be called when creating a new response writer.
+ int64 NewResponseId() {
+ return ++last_response_id_;
+ }
+
+ // Helpers to query and notify the QuotaManager.
+ void UpdateUsageMapAndNotify(const GURL& origin, int64 new_usage);
+ void ClearUsageMapAndNotify();
+ void NotifyStorageAccessed(const GURL& origin);
+
+ // The last storage id used for different object types.
+ int64 last_cache_id_;
+ int64 last_group_id_;
+ int64 last_response_id_;
+
+ UsageMap usage_map_; // maps origin to usage
+ AppCacheWorkingSet working_set_;
+ AppCacheServiceImpl* service_;
+ DelegateReferenceMap delegate_references_;
+ PendingResponseInfoLoads pending_info_loads_;
+
+ // The set of last ids must be retrieved from storage prior to being used.
+ static const int64 kUnitializedId;
+
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheStorageTest, DelegateReferences);
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheStorageTest, UsageMap);
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheStorage);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_STORAGE_H_
diff --git a/chromium/content/browser/appcache/appcache_storage_impl.cc b/chromium/content/browser/appcache/appcache_storage_impl.cc
new file mode 100644
index 00000000000..5df1d3ebdd1
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_storage_impl.cc
@@ -0,0 +1,1866 @@
+// 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/appcache/appcache_storage_impl.h"
+
+#include <algorithm>
+#include <functional>
+#include <set>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_database.h"
+#include "content/browser/appcache/appcache_entry.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_histograms.h"
+#include "content/browser/appcache/appcache_quota_client.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "net/base/cache_type.h"
+#include "net/base/net_errors.h"
+#include "sql/connection.h"
+#include "sql/transaction.h"
+#include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/browser/quota/special_storage_policy.h"
+
+namespace content {
+
+// Hard coded default when not using quota management.
+static const int kDefaultQuota = 5 * 1024 * 1024;
+
+static const int kMaxDiskCacheSize = 250 * 1024 * 1024;
+static const int kMaxMemDiskCacheSize = 10 * 1024 * 1024;
+static const base::FilePath::CharType kDiskCacheDirectoryName[] =
+ FILE_PATH_LITERAL("Cache");
+
+namespace {
+
+// Helpers for clearing data from the AppCacheDatabase.
+bool DeleteGroupAndRelatedRecords(AppCacheDatabase* database,
+ int64 group_id,
+ std::vector<int64>* deletable_response_ids) {
+ AppCacheDatabase::CacheRecord cache_record;
+ bool success = false;
+ if (database->FindCacheForGroup(group_id, &cache_record)) {
+ database->FindResponseIdsForCacheAsVector(cache_record.cache_id,
+ deletable_response_ids);
+ success =
+ database->DeleteGroup(group_id) &&
+ database->DeleteCache(cache_record.cache_id) &&
+ database->DeleteEntriesForCache(cache_record.cache_id) &&
+ database->DeleteNamespacesForCache(cache_record.cache_id) &&
+ database->DeleteOnlineWhiteListForCache(cache_record.cache_id) &&
+ database->InsertDeletableResponseIds(*deletable_response_ids);
+ } else {
+ NOTREACHED() << "A existing group without a cache is unexpected";
+ success = database->DeleteGroup(group_id);
+ }
+ return success;
+}
+
+// Destroys |database|. If there is appcache data to be deleted
+// (|force_keep_session_state| is false), deletes session-only appcache data.
+void ClearSessionOnlyOrigins(
+ AppCacheDatabase* database,
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ bool force_keep_session_state) {
+ scoped_ptr<AppCacheDatabase> database_to_delete(database);
+
+ // If saving session state, only delete the database.
+ if (force_keep_session_state)
+ return;
+
+ bool has_session_only_appcaches =
+ special_storage_policy.get() &&
+ special_storage_policy->HasSessionOnlyOrigins();
+
+ // Clearning only session-only databases, and there are none.
+ if (!has_session_only_appcaches)
+ return;
+
+ std::set<GURL> origins;
+ database->FindOriginsWithGroups(&origins);
+ if (origins.empty())
+ return; // nothing to delete
+
+ sql::Connection* connection = database->db_connection();
+ if (!connection) {
+ NOTREACHED() << "Missing database connection.";
+ return;
+ }
+
+ std::set<GURL>::const_iterator origin;
+ DCHECK(special_storage_policy.get());
+ for (origin = origins.begin(); origin != origins.end(); ++origin) {
+ if (!special_storage_policy->IsStorageSessionOnly(*origin))
+ continue;
+ if (special_storage_policy->IsStorageProtected(*origin))
+ continue;
+
+ std::vector<AppCacheDatabase::GroupRecord> groups;
+ database->FindGroupsForOrigin(*origin, &groups);
+ std::vector<AppCacheDatabase::GroupRecord>::const_iterator group;
+ for (group = groups.begin(); group != groups.end(); ++group) {
+ sql::Transaction transaction(connection);
+ if (!transaction.Begin()) {
+ NOTREACHED() << "Failed to start transaction";
+ return;
+ }
+ std::vector<int64> deletable_response_ids;
+ bool success = DeleteGroupAndRelatedRecords(database,
+ group->group_id,
+ &deletable_response_ids);
+ success = success && transaction.Commit();
+ DCHECK(success);
+ } // for each group
+ } // for each origin
+}
+
+} // namespace
+
+// DatabaseTask -----------------------------------------
+
+class AppCacheStorageImpl::DatabaseTask
+ : public base::RefCountedThreadSafe<DatabaseTask> {
+ public:
+ explicit DatabaseTask(AppCacheStorageImpl* storage)
+ : storage_(storage), database_(storage->database_),
+ io_thread_(base::MessageLoopProxy::current()) {
+ DCHECK(io_thread_.get());
+ }
+
+ void AddDelegate(DelegateReference* delegate_reference) {
+ delegates_.push_back(make_scoped_refptr(delegate_reference));
+ }
+
+ // Schedules a task to be Run() on the DB thread. Tasks
+ // are run in the order in which they are scheduled.
+ void Schedule();
+
+ // Called on the DB thread.
+ virtual void Run() = 0;
+
+ // Called on the IO thread after Run() has completed.
+ virtual void RunCompleted() {}
+
+ // Once scheduled a task cannot be cancelled, but the
+ // call to RunCompleted may be. This method should only be
+ // called on the IO thread. This is used by AppCacheStorageImpl
+ // to cancel the completion calls when AppCacheStorageImpl is
+ // destructed. This method may be overriden to release or delete
+ // additional data associated with the task that is not DB thread
+ // safe. If overriden, this base class method must be called from
+ // within the override.
+ virtual void CancelCompletion();
+
+ protected:
+ friend class base::RefCountedThreadSafe<DatabaseTask>;
+ virtual ~DatabaseTask() {}
+
+ AppCacheStorageImpl* storage_;
+ AppCacheDatabase* database_;
+ DelegateReferenceVector delegates_;
+
+ private:
+ void CallRun(base::TimeTicks schedule_time);
+ void CallRunCompleted(base::TimeTicks schedule_time);
+ void OnFatalError();
+
+ scoped_refptr<base::MessageLoopProxy> io_thread_;
+};
+
+void AppCacheStorageImpl::DatabaseTask::Schedule() {
+ DCHECK(storage_);
+ DCHECK(io_thread_->BelongsToCurrentThread());
+ if (!storage_->database_)
+ return;
+
+ if (storage_->db_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&DatabaseTask::CallRun, this, base::TimeTicks::Now()))) {
+ storage_->scheduled_database_tasks_.push_back(this);
+ } else {
+ NOTREACHED() << "Thread for database tasks is not running.";
+ }
+}
+
+void AppCacheStorageImpl::DatabaseTask::CancelCompletion() {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+ delegates_.clear();
+ storage_ = NULL;
+}
+
+void AppCacheStorageImpl::DatabaseTask::CallRun(
+ base::TimeTicks schedule_time) {
+ AppCacheHistograms::AddTaskQueueTimeSample(
+ base::TimeTicks::Now() - schedule_time);
+ if (!database_->is_disabled()) {
+ base::TimeTicks run_time = base::TimeTicks::Now();
+ Run();
+ AppCacheHistograms::AddTaskRunTimeSample(
+ base::TimeTicks::Now() - run_time);
+
+ if (database_->was_corruption_detected()) {
+ AppCacheHistograms::CountCorruptionDetected();
+ database_->Disable();
+ }
+ if (database_->is_disabled()) {
+ io_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&DatabaseTask::OnFatalError, this));
+ }
+ }
+ io_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&DatabaseTask::CallRunCompleted, this,
+ base::TimeTicks::Now()));
+}
+
+void AppCacheStorageImpl::DatabaseTask::CallRunCompleted(
+ base::TimeTicks schedule_time) {
+ AppCacheHistograms::AddCompletionQueueTimeSample(
+ base::TimeTicks::Now() - schedule_time);
+ if (storage_) {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+ DCHECK(storage_->scheduled_database_tasks_.front() == this);
+ storage_->scheduled_database_tasks_.pop_front();
+ base::TimeTicks run_time = base::TimeTicks::Now();
+ RunCompleted();
+ AppCacheHistograms::AddCompletionRunTimeSample(
+ base::TimeTicks::Now() - run_time);
+ delegates_.clear();
+ }
+}
+
+void AppCacheStorageImpl::DatabaseTask::OnFatalError() {
+ if (storage_) {
+ DCHECK(io_thread_->BelongsToCurrentThread());
+ storage_->Disable();
+ storage_->DeleteAndStartOver();
+ }
+}
+
+// InitTask -------
+
+class AppCacheStorageImpl::InitTask : public DatabaseTask {
+ public:
+ explicit InitTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage), last_group_id_(0),
+ last_cache_id_(0), last_response_id_(0),
+ last_deletable_response_rowid_(0) {
+ if (!storage->is_incognito_) {
+ db_file_path_ =
+ storage->cache_directory_.Append(kAppCacheDatabaseName);
+ disk_cache_directory_ =
+ storage->cache_directory_.Append(kDiskCacheDirectoryName);
+ }
+ }
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+
+ protected:
+ ~InitTask() override {}
+
+ private:
+ base::FilePath db_file_path_;
+ base::FilePath disk_cache_directory_;
+ int64 last_group_id_;
+ int64 last_cache_id_;
+ int64 last_response_id_;
+ int64 last_deletable_response_rowid_;
+ std::map<GURL, int64> usage_map_;
+};
+
+void AppCacheStorageImpl::InitTask::Run() {
+ // If there is no sql database, ensure there is no disk cache either.
+ if (!db_file_path_.empty() &&
+ !base::PathExists(db_file_path_) &&
+ base::DirectoryExists(disk_cache_directory_)) {
+ base::DeleteFile(disk_cache_directory_, true);
+ if (base::DirectoryExists(disk_cache_directory_)) {
+ database_->Disable(); // This triggers OnFatalError handling.
+ return;
+ }
+ }
+
+ database_->FindLastStorageIds(
+ &last_group_id_, &last_cache_id_, &last_response_id_,
+ &last_deletable_response_rowid_);
+ database_->GetAllOriginUsage(&usage_map_);
+}
+
+void AppCacheStorageImpl::InitTask::RunCompleted() {
+ storage_->last_group_id_ = last_group_id_;
+ storage_->last_cache_id_ = last_cache_id_;
+ storage_->last_response_id_ = last_response_id_;
+ storage_->last_deletable_response_rowid_ = last_deletable_response_rowid_;
+
+ if (!storage_->is_disabled()) {
+ storage_->usage_map_.swap(usage_map_);
+ const base::TimeDelta kDelay = base::TimeDelta::FromMinutes(5);
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&AppCacheStorageImpl::DelayedStartDeletingUnusedResponses,
+ storage_->weak_factory_.GetWeakPtr()),
+ kDelay);
+ }
+
+ if (storage_->service()->quota_client())
+ storage_->service()->quota_client()->NotifyAppCacheReady();
+}
+
+// DisableDatabaseTask -------
+
+class AppCacheStorageImpl::DisableDatabaseTask : public DatabaseTask {
+ public:
+ explicit DisableDatabaseTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage) {}
+
+ // DatabaseTask:
+ void Run() override { database_->Disable(); }
+
+ protected:
+ ~DisableDatabaseTask() override {}
+};
+
+// GetAllInfoTask -------
+
+class AppCacheStorageImpl::GetAllInfoTask : public DatabaseTask {
+ public:
+ explicit GetAllInfoTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage),
+ info_collection_(new AppCacheInfoCollection()) {
+ }
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+
+ protected:
+ ~GetAllInfoTask() override {}
+
+ private:
+ scoped_refptr<AppCacheInfoCollection> info_collection_;
+};
+
+void AppCacheStorageImpl::GetAllInfoTask::Run() {
+ std::set<GURL> origins;
+ database_->FindOriginsWithGroups(&origins);
+ for (std::set<GURL>::const_iterator origin = origins.begin();
+ origin != origins.end(); ++origin) {
+ AppCacheInfoVector& infos =
+ info_collection_->infos_by_origin[*origin];
+ std::vector<AppCacheDatabase::GroupRecord> groups;
+ database_->FindGroupsForOrigin(*origin, &groups);
+ for (std::vector<AppCacheDatabase::GroupRecord>::const_iterator
+ group = groups.begin();
+ group != groups.end(); ++group) {
+ AppCacheDatabase::CacheRecord cache_record;
+ database_->FindCacheForGroup(group->group_id, &cache_record);
+ AppCacheInfo info;
+ info.manifest_url = group->manifest_url;
+ info.creation_time = group->creation_time;
+ info.size = cache_record.cache_size;
+ info.last_access_time = group->last_access_time;
+ info.last_update_time = cache_record.update_time;
+ info.cache_id = cache_record.cache_id;
+ info.group_id = group->group_id;
+ info.is_complete = true;
+ infos.push_back(info);
+ }
+ }
+}
+
+void AppCacheStorageImpl::GetAllInfoTask::RunCompleted() {
+ DCHECK_EQ(1U, delegates_.size());
+ FOR_EACH_DELEGATE(delegates_, OnAllInfo(info_collection_.get()));
+}
+
+// StoreOrLoadTask -------
+
+class AppCacheStorageImpl::StoreOrLoadTask : public DatabaseTask {
+ protected:
+ explicit StoreOrLoadTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage) {}
+ ~StoreOrLoadTask() override {}
+
+ bool FindRelatedCacheRecords(int64 cache_id);
+ void CreateCacheAndGroupFromRecords(
+ scoped_refptr<AppCache>* cache, scoped_refptr<AppCacheGroup>* group);
+
+ AppCacheDatabase::GroupRecord group_record_;
+ AppCacheDatabase::CacheRecord cache_record_;
+ std::vector<AppCacheDatabase::EntryRecord> entry_records_;
+ std::vector<AppCacheDatabase::NamespaceRecord>
+ intercept_namespace_records_;
+ std::vector<AppCacheDatabase::NamespaceRecord>
+ fallback_namespace_records_;
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord>
+ online_whitelist_records_;
+};
+
+bool AppCacheStorageImpl::StoreOrLoadTask::FindRelatedCacheRecords(
+ int64 cache_id) {
+ return database_->FindEntriesForCache(cache_id, &entry_records_) &&
+ database_->FindNamespacesForCache(
+ cache_id, &intercept_namespace_records_,
+ &fallback_namespace_records_) &&
+ database_->FindOnlineWhiteListForCache(
+ cache_id, &online_whitelist_records_);
+}
+
+void AppCacheStorageImpl::StoreOrLoadTask::CreateCacheAndGroupFromRecords(
+ scoped_refptr<AppCache>* cache, scoped_refptr<AppCacheGroup>* group) {
+ DCHECK(storage_ && cache && group);
+
+ (*cache) = storage_->working_set_.GetCache(cache_record_.cache_id);
+ if (cache->get()) {
+ (*group) = cache->get()->owning_group();
+ DCHECK(group->get());
+ DCHECK_EQ(group_record_.group_id, group->get()->group_id());
+
+ // TODO(michaeln): histogram is fishing for clues to crbug/95101
+ if (!cache->get()->GetEntry(group_record_.manifest_url)) {
+ AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
+ AppCacheHistograms::CALLSITE_0);
+ }
+
+ storage_->NotifyStorageAccessed(group_record_.origin);
+ return;
+ }
+
+ (*cache) = new AppCache(storage_, cache_record_.cache_id);
+ cache->get()->InitializeWithDatabaseRecords(
+ cache_record_, entry_records_,
+ intercept_namespace_records_,
+ fallback_namespace_records_,
+ online_whitelist_records_);
+ cache->get()->set_complete(true);
+
+ (*group) = storage_->working_set_.GetGroup(group_record_.manifest_url);
+ if (group->get()) {
+ DCHECK(group_record_.group_id == group->get()->group_id());
+ group->get()->AddCache(cache->get());
+
+ // TODO(michaeln): histogram is fishing for clues to crbug/95101
+ if (!cache->get()->GetEntry(group_record_.manifest_url)) {
+ AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
+ AppCacheHistograms::CALLSITE_1);
+ }
+ } else {
+ (*group) = new AppCacheGroup(
+ storage_, group_record_.manifest_url,
+ group_record_.group_id);
+ group->get()->set_creation_time(group_record_.creation_time);
+ group->get()->AddCache(cache->get());
+
+ // TODO(michaeln): histogram is fishing for clues to crbug/95101
+ if (!cache->get()->GetEntry(group_record_.manifest_url)) {
+ AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
+ AppCacheHistograms::CALLSITE_2);
+ }
+ }
+ DCHECK(group->get()->newest_complete_cache() == cache->get());
+
+ // We have to update foriegn entries if MarkEntryAsForeignTasks
+ // are in flight.
+ std::vector<GURL> urls;
+ storage_->GetPendingForeignMarkingsForCache(cache->get()->cache_id(), &urls);
+ for (std::vector<GURL>::iterator iter = urls.begin();
+ iter != urls.end(); ++iter) {
+ DCHECK(cache->get()->GetEntry(*iter));
+ cache->get()->GetEntry(*iter)->add_types(AppCacheEntry::FOREIGN);
+ }
+
+ storage_->NotifyStorageAccessed(group_record_.origin);
+
+ // TODO(michaeln): Maybe verify that the responses we expect to exist
+ // do actually exist in the disk_cache (and if not then what?)
+}
+
+// CacheLoadTask -------
+
+class AppCacheStorageImpl::CacheLoadTask : public StoreOrLoadTask {
+ public:
+ CacheLoadTask(int64 cache_id, AppCacheStorageImpl* storage)
+ : StoreOrLoadTask(storage), cache_id_(cache_id),
+ success_(false) {}
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+
+ protected:
+ ~CacheLoadTask() override {}
+
+ private:
+ int64 cache_id_;
+ bool success_;
+};
+
+void AppCacheStorageImpl::CacheLoadTask::Run() {
+ success_ =
+ database_->FindCache(cache_id_, &cache_record_) &&
+ database_->FindGroup(cache_record_.group_id, &group_record_) &&
+ FindRelatedCacheRecords(cache_id_);
+
+ if (success_)
+ database_->UpdateGroupLastAccessTime(group_record_.group_id,
+ base::Time::Now());
+}
+
+void AppCacheStorageImpl::CacheLoadTask::RunCompleted() {
+ storage_->pending_cache_loads_.erase(cache_id_);
+ scoped_refptr<AppCache> cache;
+ scoped_refptr<AppCacheGroup> group;
+ if (success_ && !storage_->is_disabled()) {
+ DCHECK(cache_record_.cache_id == cache_id_);
+ CreateCacheAndGroupFromRecords(&cache, &group);
+ }
+ FOR_EACH_DELEGATE(delegates_, OnCacheLoaded(cache.get(), cache_id_));
+}
+
+// GroupLoadTask -------
+
+class AppCacheStorageImpl::GroupLoadTask : public StoreOrLoadTask {
+ public:
+ GroupLoadTask(GURL manifest_url, AppCacheStorageImpl* storage)
+ : StoreOrLoadTask(storage), manifest_url_(manifest_url),
+ success_(false) {}
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+
+ protected:
+ ~GroupLoadTask() override {}
+
+ private:
+ GURL manifest_url_;
+ bool success_;
+};
+
+void AppCacheStorageImpl::GroupLoadTask::Run() {
+ success_ =
+ database_->FindGroupForManifestUrl(manifest_url_, &group_record_) &&
+ database_->FindCacheForGroup(group_record_.group_id, &cache_record_) &&
+ FindRelatedCacheRecords(cache_record_.cache_id);
+
+ if (success_)
+ database_->UpdateGroupLastAccessTime(group_record_.group_id,
+ base::Time::Now());
+}
+
+void AppCacheStorageImpl::GroupLoadTask::RunCompleted() {
+ storage_->pending_group_loads_.erase(manifest_url_);
+ scoped_refptr<AppCacheGroup> group;
+ scoped_refptr<AppCache> cache;
+ if (!storage_->is_disabled()) {
+ if (success_) {
+ DCHECK(group_record_.manifest_url == manifest_url_);
+ CreateCacheAndGroupFromRecords(&cache, &group);
+ } else {
+ group = storage_->working_set_.GetGroup(manifest_url_);
+ if (!group.get()) {
+ group =
+ new AppCacheGroup(storage_, manifest_url_, storage_->NewGroupId());
+ }
+ }
+ }
+ FOR_EACH_DELEGATE(delegates_, OnGroupLoaded(group.get(), manifest_url_));
+}
+
+// StoreGroupAndCacheTask -------
+
+class AppCacheStorageImpl::StoreGroupAndCacheTask : public StoreOrLoadTask {
+ public:
+ StoreGroupAndCacheTask(AppCacheStorageImpl* storage, AppCacheGroup* group,
+ AppCache* newest_cache);
+
+ void GetQuotaThenSchedule();
+ void OnQuotaCallback(storage::QuotaStatusCode status,
+ int64 usage,
+ int64 quota);
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+ void CancelCompletion() override;
+
+ protected:
+ ~StoreGroupAndCacheTask() override {}
+
+ private:
+ scoped_refptr<AppCacheGroup> group_;
+ scoped_refptr<AppCache> cache_;
+ bool success_;
+ bool would_exceed_quota_;
+ int64 space_available_;
+ int64 new_origin_usage_;
+ std::vector<int64> newly_deletable_response_ids_;
+};
+
+AppCacheStorageImpl::StoreGroupAndCacheTask::StoreGroupAndCacheTask(
+ AppCacheStorageImpl* storage, AppCacheGroup* group, AppCache* newest_cache)
+ : StoreOrLoadTask(storage), group_(group), cache_(newest_cache),
+ success_(false), would_exceed_quota_(false),
+ space_available_(-1), new_origin_usage_(-1) {
+ group_record_.group_id = group->group_id();
+ group_record_.manifest_url = group->manifest_url();
+ group_record_.origin = group_record_.manifest_url.GetOrigin();
+ newest_cache->ToDatabaseRecords(
+ group,
+ &cache_record_, &entry_records_,
+ &intercept_namespace_records_,
+ &fallback_namespace_records_,
+ &online_whitelist_records_);
+}
+
+void AppCacheStorageImpl::StoreGroupAndCacheTask::GetQuotaThenSchedule() {
+ storage::QuotaManager* quota_manager = NULL;
+ if (storage_->service()->quota_manager_proxy()) {
+ quota_manager =
+ storage_->service()->quota_manager_proxy()->quota_manager();
+ }
+
+ if (!quota_manager) {
+ if (storage_->service()->special_storage_policy() &&
+ storage_->service()->special_storage_policy()->IsStorageUnlimited(
+ group_record_.origin))
+ space_available_ = kint64max;
+ Schedule();
+ return;
+ }
+
+ // We have to ask the quota manager for the value.
+ storage_->pending_quota_queries_.insert(this);
+ quota_manager->GetUsageAndQuota(
+ group_record_.origin,
+ storage::kStorageTypeTemporary,
+ base::Bind(&StoreGroupAndCacheTask::OnQuotaCallback, this));
+}
+
+void AppCacheStorageImpl::StoreGroupAndCacheTask::OnQuotaCallback(
+ storage::QuotaStatusCode status,
+ int64 usage,
+ int64 quota) {
+ if (storage_) {
+ if (status == storage::kQuotaStatusOk)
+ space_available_ = std::max(static_cast<int64>(0), quota - usage);
+ else
+ space_available_ = 0;
+ storage_->pending_quota_queries_.erase(this);
+ Schedule();
+ }
+}
+
+void AppCacheStorageImpl::StoreGroupAndCacheTask::Run() {
+ DCHECK(!success_);
+ sql::Connection* connection = database_->db_connection();
+ if (!connection)
+ return;
+
+ sql::Transaction transaction(connection);
+ if (!transaction.Begin())
+ return;
+
+ int64 old_origin_usage = database_->GetOriginUsage(group_record_.origin);
+
+ AppCacheDatabase::GroupRecord existing_group;
+ success_ = database_->FindGroup(group_record_.group_id, &existing_group);
+ if (!success_) {
+ group_record_.creation_time = base::Time::Now();
+ group_record_.last_access_time = base::Time::Now();
+ success_ = database_->InsertGroup(&group_record_);
+ } else {
+ DCHECK(group_record_.group_id == existing_group.group_id);
+ DCHECK(group_record_.manifest_url == existing_group.manifest_url);
+ DCHECK(group_record_.origin == existing_group.origin);
+
+ database_->UpdateGroupLastAccessTime(group_record_.group_id,
+ base::Time::Now());
+
+ AppCacheDatabase::CacheRecord cache;
+ if (database_->FindCacheForGroup(group_record_.group_id, &cache)) {
+ // Get the set of response ids in the old cache.
+ std::set<int64> existing_response_ids;
+ database_->FindResponseIdsForCacheAsSet(cache.cache_id,
+ &existing_response_ids);
+
+ // Remove those that remain in the new cache.
+ std::vector<AppCacheDatabase::EntryRecord>::const_iterator entry_iter =
+ entry_records_.begin();
+ while (entry_iter != entry_records_.end()) {
+ existing_response_ids.erase(entry_iter->response_id);
+ ++entry_iter;
+ }
+
+ // The rest are deletable.
+ std::set<int64>::const_iterator id_iter = existing_response_ids.begin();
+ while (id_iter != existing_response_ids.end()) {
+ newly_deletable_response_ids_.push_back(*id_iter);
+ ++id_iter;
+ }
+
+ success_ =
+ database_->DeleteCache(cache.cache_id) &&
+ database_->DeleteEntriesForCache(cache.cache_id) &&
+ database_->DeleteNamespacesForCache(cache.cache_id) &&
+ database_->DeleteOnlineWhiteListForCache(cache.cache_id) &&
+ database_->InsertDeletableResponseIds(newly_deletable_response_ids_);
+ // TODO(michaeln): store group_id too with deletable ids
+ } else {
+ NOTREACHED() << "A existing group without a cache is unexpected";
+ }
+ }
+
+ success_ =
+ success_ &&
+ database_->InsertCache(&cache_record_) &&
+ database_->InsertEntryRecords(entry_records_) &&
+ database_->InsertNamespaceRecords(intercept_namespace_records_) &&
+ database_->InsertNamespaceRecords(fallback_namespace_records_) &&
+ database_->InsertOnlineWhiteListRecords(online_whitelist_records_);
+
+ if (!success_)
+ return;
+
+ new_origin_usage_ = database_->GetOriginUsage(group_record_.origin);
+
+ // Only check quota when the new usage exceeds the old usage.
+ if (new_origin_usage_ <= old_origin_usage) {
+ success_ = transaction.Commit();
+ return;
+ }
+
+ // Use a simple hard-coded value when not using quota management.
+ if (space_available_ == -1) {
+ if (new_origin_usage_ > kDefaultQuota) {
+ would_exceed_quota_ = true;
+ success_ = false;
+ return;
+ }
+ success_ = transaction.Commit();
+ return;
+ }
+
+ // Check limits based on the space availbable given to us via the
+ // quota system.
+ int64 delta = new_origin_usage_ - old_origin_usage;
+ if (delta > space_available_) {
+ would_exceed_quota_ = true;
+ success_ = false;
+ return;
+ }
+
+ success_ = transaction.Commit();
+}
+
+void AppCacheStorageImpl::StoreGroupAndCacheTask::RunCompleted() {
+ if (success_) {
+ storage_->UpdateUsageMapAndNotify(
+ group_->manifest_url().GetOrigin(), new_origin_usage_);
+ if (cache_.get() != group_->newest_complete_cache()) {
+ cache_->set_complete(true);
+ group_->AddCache(cache_.get());
+ }
+ if (group_->creation_time().is_null())
+ group_->set_creation_time(group_record_.creation_time);
+ group_->AddNewlyDeletableResponseIds(&newly_deletable_response_ids_);
+ }
+ FOR_EACH_DELEGATE(
+ delegates_,
+ OnGroupAndNewestCacheStored(
+ group_.get(), cache_.get(), success_, would_exceed_quota_));
+ group_ = NULL;
+ cache_ = NULL;
+
+ // TODO(michaeln): if (would_exceed_quota_) what if the current usage
+ // also exceeds the quota? http://crbug.com/83968
+}
+
+void AppCacheStorageImpl::StoreGroupAndCacheTask::CancelCompletion() {
+ // Overriden to safely drop our reference to the group and cache
+ // which are not thread safe refcounted.
+ DatabaseTask::CancelCompletion();
+ group_ = NULL;
+ cache_ = NULL;
+}
+
+// FindMainResponseTask -------
+
+// Helpers for FindMainResponseTask::Run()
+namespace {
+class SortByCachePreference
+ : public std::binary_function<
+ AppCacheDatabase::EntryRecord,
+ AppCacheDatabase::EntryRecord,
+ bool> {
+ public:
+ SortByCachePreference(int64 preferred_id, const std::set<int64>& in_use_ids)
+ : preferred_id_(preferred_id), in_use_ids_(in_use_ids) {
+ }
+ bool operator()(
+ const AppCacheDatabase::EntryRecord& lhs,
+ const AppCacheDatabase::EntryRecord& rhs) {
+ return compute_value(lhs) > compute_value(rhs);
+ }
+ private:
+ int compute_value(const AppCacheDatabase::EntryRecord& entry) {
+ if (entry.cache_id == preferred_id_)
+ return 100;
+ else if (in_use_ids_.find(entry.cache_id) != in_use_ids_.end())
+ return 50;
+ return 0;
+ }
+ int64 preferred_id_;
+ const std::set<int64>& in_use_ids_;
+};
+
+bool SortByLength(
+ const AppCacheDatabase::NamespaceRecord& lhs,
+ const AppCacheDatabase::NamespaceRecord& rhs) {
+ return lhs.namespace_.namespace_url.spec().length() >
+ rhs.namespace_.namespace_url.spec().length();
+}
+
+class NetworkNamespaceHelper {
+ public:
+ explicit NetworkNamespaceHelper(AppCacheDatabase* database)
+ : database_(database) {
+ }
+
+ bool IsInNetworkNamespace(const GURL& url, int64 cache_id) {
+ typedef std::pair<WhiteListMap::iterator, bool> InsertResult;
+ InsertResult result = namespaces_map_.insert(
+ WhiteListMap::value_type(cache_id, AppCacheNamespaceVector()));
+ if (result.second)
+ GetOnlineWhiteListForCache(cache_id, &result.first->second);
+ return AppCache::FindNamespace(result.first->second, url) != NULL;
+ }
+
+ private:
+ void GetOnlineWhiteListForCache(
+ int64 cache_id, AppCacheNamespaceVector* namespaces) {
+ DCHECK(namespaces && namespaces->empty());
+ typedef std::vector<AppCacheDatabase::OnlineWhiteListRecord>
+ WhiteListVector;
+ WhiteListVector records;
+ if (!database_->FindOnlineWhiteListForCache(cache_id, &records))
+ return;
+ WhiteListVector::const_iterator iter = records.begin();
+ while (iter != records.end()) {
+ namespaces->push_back(
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, iter->namespace_url,
+ GURL(), iter->is_pattern));
+ ++iter;
+ }
+ }
+
+ // Key is cache id
+ typedef std::map<int64, AppCacheNamespaceVector> WhiteListMap;
+ WhiteListMap namespaces_map_;
+ AppCacheDatabase* database_;
+};
+
+} // namespace
+
+class AppCacheStorageImpl::FindMainResponseTask : public DatabaseTask {
+ public:
+ FindMainResponseTask(AppCacheStorageImpl* storage,
+ const GURL& url,
+ const GURL& preferred_manifest_url,
+ const AppCacheWorkingSet::GroupMap* groups_in_use)
+ : DatabaseTask(storage), url_(url),
+ preferred_manifest_url_(preferred_manifest_url),
+ cache_id_(kAppCacheNoCacheId), group_id_(0) {
+ if (groups_in_use) {
+ for (AppCacheWorkingSet::GroupMap::const_iterator it =
+ groups_in_use->begin();
+ it != groups_in_use->end(); ++it) {
+ AppCacheGroup* group = it->second;
+ AppCache* cache = group->newest_complete_cache();
+ if (group->is_obsolete() || !cache)
+ continue;
+ cache_ids_in_use_.insert(cache->cache_id());
+ }
+ }
+ }
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+
+ protected:
+ ~FindMainResponseTask() override {}
+
+ private:
+ typedef std::vector<AppCacheDatabase::NamespaceRecord*>
+ NamespaceRecordPtrVector;
+
+ bool FindExactMatch(int64 preferred_id);
+ bool FindNamespaceMatch(int64 preferred_id);
+ bool FindNamespaceHelper(
+ int64 preferred_cache_id,
+ AppCacheDatabase::NamespaceRecordVector* namespaces,
+ NetworkNamespaceHelper* network_namespace_helper);
+ bool FindFirstValidNamespace(const NamespaceRecordPtrVector& namespaces);
+
+ GURL url_;
+ GURL preferred_manifest_url_;
+ std::set<int64> cache_ids_in_use_;
+ AppCacheEntry entry_;
+ AppCacheEntry fallback_entry_;
+ GURL namespace_entry_url_;
+ int64 cache_id_;
+ int64 group_id_;
+ GURL manifest_url_;
+};
+
+void AppCacheStorageImpl::FindMainResponseTask::Run() {
+ // NOTE: The heuristics around choosing amoungst multiple candidates
+ // is underspecified, and just plain not fully understood. This needs
+ // to be refined.
+
+ // The 'preferred_manifest_url' is the url of the manifest associated
+ // with the page that opened or embedded the page being loaded now.
+ // We have a strong preference to use resources from that cache.
+ // We also have a lesser bias to use resources from caches that are currently
+ // being used by other unrelated pages.
+ // TODO(michaeln): come up with a 'preferred_manifest_url' in more cases
+ // - when navigating a frame whose current contents are from an appcache
+ // - when clicking an href in a frame that is appcached
+ int64 preferred_cache_id = kAppCacheNoCacheId;
+ if (!preferred_manifest_url_.is_empty()) {
+ AppCacheDatabase::GroupRecord preferred_group;
+ AppCacheDatabase::CacheRecord preferred_cache;
+ if (database_->FindGroupForManifestUrl(
+ preferred_manifest_url_, &preferred_group) &&
+ database_->FindCacheForGroup(
+ preferred_group.group_id, &preferred_cache)) {
+ preferred_cache_id = preferred_cache.cache_id;
+ }
+ }
+
+ if (FindExactMatch(preferred_cache_id) ||
+ FindNamespaceMatch(preferred_cache_id)) {
+ // We found something.
+ DCHECK(cache_id_ != kAppCacheNoCacheId && !manifest_url_.is_empty() &&
+ group_id_ != 0);
+ return;
+ }
+
+ // We didn't find anything.
+ DCHECK(cache_id_ == kAppCacheNoCacheId && manifest_url_.is_empty() &&
+ group_id_ == 0);
+}
+
+bool AppCacheStorageImpl::
+FindMainResponseTask::FindExactMatch(int64 preferred_cache_id) {
+ std::vector<AppCacheDatabase::EntryRecord> entries;
+ if (database_->FindEntriesForUrl(url_, &entries) && !entries.empty()) {
+ // Sort them in order of preference, from the preferred_cache first,
+ // followed by hits from caches that are 'in use', then the rest.
+ std::sort(entries.begin(), entries.end(),
+ SortByCachePreference(preferred_cache_id, cache_ids_in_use_));
+
+ // Take the first with a valid, non-foreign entry.
+ std::vector<AppCacheDatabase::EntryRecord>::iterator iter;
+ for (iter = entries.begin(); iter < entries.end(); ++iter) {
+ AppCacheDatabase::GroupRecord group_record;
+ if ((iter->flags & AppCacheEntry::FOREIGN) ||
+ !database_->FindGroupForCache(iter->cache_id, &group_record)) {
+ continue;
+ }
+ manifest_url_ = group_record.manifest_url;
+ group_id_ = group_record.group_id;
+ entry_ = AppCacheEntry(iter->flags, iter->response_id);
+ cache_id_ = iter->cache_id;
+ return true; // We found an exact match.
+ }
+ }
+ return false;
+}
+
+bool AppCacheStorageImpl::
+FindMainResponseTask::FindNamespaceMatch(int64 preferred_cache_id) {
+ AppCacheDatabase::NamespaceRecordVector all_intercepts;
+ AppCacheDatabase::NamespaceRecordVector all_fallbacks;
+ if (!database_->FindNamespacesForOrigin(
+ url_.GetOrigin(), &all_intercepts, &all_fallbacks)
+ || (all_intercepts.empty() && all_fallbacks.empty())) {
+ return false;
+ }
+
+ NetworkNamespaceHelper network_namespace_helper(database_);
+ if (FindNamespaceHelper(preferred_cache_id,
+ &all_intercepts,
+ &network_namespace_helper) ||
+ FindNamespaceHelper(preferred_cache_id,
+ &all_fallbacks,
+ &network_namespace_helper)) {
+ return true;
+ }
+ return false;
+}
+
+bool AppCacheStorageImpl::
+FindMainResponseTask::FindNamespaceHelper(
+ int64 preferred_cache_id,
+ AppCacheDatabase::NamespaceRecordVector* namespaces,
+ NetworkNamespaceHelper* network_namespace_helper) {
+ // Sort them by length, longer matches within the same cache/bucket take
+ // precedence.
+ std::sort(namespaces->begin(), namespaces->end(), SortByLength);
+
+ NamespaceRecordPtrVector preferred_namespaces;
+ NamespaceRecordPtrVector inuse_namespaces;
+ NamespaceRecordPtrVector other_namespaces;
+ std::vector<AppCacheDatabase::NamespaceRecord>::iterator iter;
+ for (iter = namespaces->begin(); iter < namespaces->end(); ++iter) {
+ // Skip those that aren't a match.
+ if (!iter->namespace_.IsMatch(url_))
+ continue;
+
+ // Skip namespaces where the requested url falls into a network
+ // namespace of its containing appcache.
+ if (network_namespace_helper->IsInNetworkNamespace(url_, iter->cache_id))
+ continue;
+
+ // Bin them into one of our three buckets.
+ if (iter->cache_id == preferred_cache_id)
+ preferred_namespaces.push_back(&(*iter));
+ else if (cache_ids_in_use_.find(iter->cache_id) != cache_ids_in_use_.end())
+ inuse_namespaces.push_back(&(*iter));
+ else
+ other_namespaces.push_back(&(*iter));
+ }
+
+ if (FindFirstValidNamespace(preferred_namespaces) ||
+ FindFirstValidNamespace(inuse_namespaces) ||
+ FindFirstValidNamespace(other_namespaces))
+ return true; // We found one.
+
+ // We didn't find anything.
+ return false;
+}
+
+bool AppCacheStorageImpl::
+FindMainResponseTask::FindFirstValidNamespace(
+ const NamespaceRecordPtrVector& namespaces) {
+ // Take the first with a valid, non-foreign entry.
+ NamespaceRecordPtrVector::const_iterator iter;
+ for (iter = namespaces.begin(); iter < namespaces.end(); ++iter) {
+ AppCacheDatabase::EntryRecord entry_record;
+ if (database_->FindEntry((*iter)->cache_id, (*iter)->namespace_.target_url,
+ &entry_record)) {
+ AppCacheDatabase::GroupRecord group_record;
+ if ((entry_record.flags & AppCacheEntry::FOREIGN) ||
+ !database_->FindGroupForCache(entry_record.cache_id, &group_record)) {
+ continue;
+ }
+ manifest_url_ = group_record.manifest_url;
+ group_id_ = group_record.group_id;
+ cache_id_ = (*iter)->cache_id;
+ namespace_entry_url_ = (*iter)->namespace_.target_url;
+ if ((*iter)->namespace_.type == APPCACHE_FALLBACK_NAMESPACE)
+ fallback_entry_ = AppCacheEntry(entry_record.flags,
+ entry_record.response_id);
+ else
+ entry_ = AppCacheEntry(entry_record.flags, entry_record.response_id);
+ return true; // We found one.
+ }
+ }
+ return false; // We didn't find a match.
+}
+
+void AppCacheStorageImpl::FindMainResponseTask::RunCompleted() {
+ storage_->CallOnMainResponseFound(
+ &delegates_, url_, entry_, namespace_entry_url_, fallback_entry_,
+ cache_id_, group_id_, manifest_url_);
+}
+
+// MarkEntryAsForeignTask -------
+
+class AppCacheStorageImpl::MarkEntryAsForeignTask : public DatabaseTask {
+ public:
+ MarkEntryAsForeignTask(
+ AppCacheStorageImpl* storage, const GURL& url, int64 cache_id)
+ : DatabaseTask(storage), cache_id_(cache_id), entry_url_(url) {}
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+
+ protected:
+ ~MarkEntryAsForeignTask() override {}
+
+ private:
+ int64 cache_id_;
+ GURL entry_url_;
+};
+
+void AppCacheStorageImpl::MarkEntryAsForeignTask::Run() {
+ database_->AddEntryFlags(entry_url_, cache_id_, AppCacheEntry::FOREIGN);
+}
+
+void AppCacheStorageImpl::MarkEntryAsForeignTask::RunCompleted() {
+ DCHECK(storage_->pending_foreign_markings_.front().first == entry_url_ &&
+ storage_->pending_foreign_markings_.front().second == cache_id_);
+ storage_->pending_foreign_markings_.pop_front();
+}
+
+// MakeGroupObsoleteTask -------
+
+class AppCacheStorageImpl::MakeGroupObsoleteTask : public DatabaseTask {
+ public:
+ MakeGroupObsoleteTask(AppCacheStorageImpl* storage,
+ AppCacheGroup* group,
+ int response_code);
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+ void CancelCompletion() override;
+
+ protected:
+ ~MakeGroupObsoleteTask() override {}
+
+ private:
+ scoped_refptr<AppCacheGroup> group_;
+ int64 group_id_;
+ GURL origin_;
+ bool success_;
+ int response_code_;
+ int64 new_origin_usage_;
+ std::vector<int64> newly_deletable_response_ids_;
+};
+
+AppCacheStorageImpl::MakeGroupObsoleteTask::MakeGroupObsoleteTask(
+ AppCacheStorageImpl* storage,
+ AppCacheGroup* group,
+ int response_code)
+ : DatabaseTask(storage),
+ group_(group),
+ group_id_(group->group_id()),
+ origin_(group->manifest_url().GetOrigin()),
+ success_(false),
+ response_code_(response_code),
+ new_origin_usage_(-1) {}
+
+void AppCacheStorageImpl::MakeGroupObsoleteTask::Run() {
+ DCHECK(!success_);
+ sql::Connection* connection = database_->db_connection();
+ if (!connection)
+ return;
+
+ sql::Transaction transaction(connection);
+ if (!transaction.Begin())
+ return;
+
+ AppCacheDatabase::GroupRecord group_record;
+ if (!database_->FindGroup(group_id_, &group_record)) {
+ // This group doesn't exists in the database, nothing todo here.
+ new_origin_usage_ = database_->GetOriginUsage(origin_);
+ success_ = true;
+ return;
+ }
+
+ DCHECK_EQ(group_record.origin, origin_);
+ success_ = DeleteGroupAndRelatedRecords(database_,
+ group_id_,
+ &newly_deletable_response_ids_);
+
+ new_origin_usage_ = database_->GetOriginUsage(origin_);
+ success_ = success_ && transaction.Commit();
+}
+
+void AppCacheStorageImpl::MakeGroupObsoleteTask::RunCompleted() {
+ if (success_) {
+ group_->set_obsolete(true);
+ if (!storage_->is_disabled()) {
+ storage_->UpdateUsageMapAndNotify(origin_, new_origin_usage_);
+ group_->AddNewlyDeletableResponseIds(&newly_deletable_response_ids_);
+
+ // Also remove from the working set, caches for an 'obsolete' group
+ // may linger in use, but the group itself cannot be looked up by
+ // 'manifest_url' in the working set any longer.
+ storage_->working_set()->RemoveGroup(group_.get());
+ }
+ }
+ FOR_EACH_DELEGATE(
+ delegates_, OnGroupMadeObsolete(group_.get(), success_, response_code_));
+ group_ = NULL;
+}
+
+void AppCacheStorageImpl::MakeGroupObsoleteTask::CancelCompletion() {
+ // Overriden to safely drop our reference to the group
+ // which is not thread safe refcounted.
+ DatabaseTask::CancelCompletion();
+ group_ = NULL;
+}
+
+// GetDeletableResponseIdsTask -------
+
+class AppCacheStorageImpl::GetDeletableResponseIdsTask : public DatabaseTask {
+ public:
+ GetDeletableResponseIdsTask(AppCacheStorageImpl* storage, int64 max_rowid)
+ : DatabaseTask(storage), max_rowid_(max_rowid) {}
+
+ // DatabaseTask:
+ void Run() override;
+ void RunCompleted() override;
+
+ protected:
+ ~GetDeletableResponseIdsTask() override {}
+
+ private:
+ int64 max_rowid_;
+ std::vector<int64> response_ids_;
+};
+
+void AppCacheStorageImpl::GetDeletableResponseIdsTask::Run() {
+ const int kSqlLimit = 1000;
+ database_->GetDeletableResponseIds(&response_ids_, max_rowid_, kSqlLimit);
+ // TODO(michaeln): retrieve group_ids too
+}
+
+void AppCacheStorageImpl::GetDeletableResponseIdsTask::RunCompleted() {
+ if (!response_ids_.empty())
+ storage_->StartDeletingResponses(response_ids_);
+}
+
+// InsertDeletableResponseIdsTask -------
+
+class AppCacheStorageImpl::InsertDeletableResponseIdsTask
+ : public DatabaseTask {
+ public:
+ explicit InsertDeletableResponseIdsTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage) {}
+
+ // DatabaseTask:
+ void Run() override;
+
+ std::vector<int64> response_ids_;
+
+ protected:
+ ~InsertDeletableResponseIdsTask() override {}
+};
+
+void AppCacheStorageImpl::InsertDeletableResponseIdsTask::Run() {
+ database_->InsertDeletableResponseIds(response_ids_);
+ // TODO(michaeln): store group_ids too
+}
+
+// DeleteDeletableResponseIdsTask -------
+
+class AppCacheStorageImpl::DeleteDeletableResponseIdsTask
+ : public DatabaseTask {
+ public:
+ explicit DeleteDeletableResponseIdsTask(AppCacheStorageImpl* storage)
+ : DatabaseTask(storage) {}
+
+ // DatabaseTask:
+ void Run() override;
+
+ std::vector<int64> response_ids_;
+
+ protected:
+ ~DeleteDeletableResponseIdsTask() override {}
+};
+
+void AppCacheStorageImpl::DeleteDeletableResponseIdsTask::Run() {
+ database_->DeleteDeletableResponseIds(response_ids_);
+}
+
+// UpdateGroupLastAccessTimeTask -------
+
+class AppCacheStorageImpl::UpdateGroupLastAccessTimeTask
+ : public DatabaseTask {
+ public:
+ UpdateGroupLastAccessTimeTask(
+ AppCacheStorageImpl* storage, AppCacheGroup* group, base::Time time)
+ : DatabaseTask(storage), group_id_(group->group_id()),
+ last_access_time_(time) {
+ storage->NotifyStorageAccessed(group->manifest_url().GetOrigin());
+ }
+
+ // DatabaseTask:
+ void Run() override;
+
+ protected:
+ ~UpdateGroupLastAccessTimeTask() override {}
+
+ private:
+ int64 group_id_;
+ base::Time last_access_time_;
+};
+
+void AppCacheStorageImpl::UpdateGroupLastAccessTimeTask::Run() {
+ database_->UpdateGroupLastAccessTime(group_id_, last_access_time_);
+}
+
+
+// AppCacheStorageImpl ---------------------------------------------------
+
+AppCacheStorageImpl::AppCacheStorageImpl(AppCacheServiceImpl* service)
+ : AppCacheStorage(service),
+ is_incognito_(false),
+ is_response_deletion_scheduled_(false),
+ did_start_deleting_responses_(false),
+ last_deletable_response_rowid_(0),
+ database_(NULL),
+ is_disabled_(false),
+ weak_factory_(this) {
+}
+
+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));
+
+ if (database_ &&
+ !db_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&ClearSessionOnlyOrigins,
+ database_,
+ make_scoped_refptr(service_->special_storage_policy()),
+ service()->force_keep_session_state()))) {
+ delete database_;
+ }
+ database_ = NULL; // So no further database tasks can be scheduled.
+}
+
+void AppCacheStorageImpl::Initialize(
+ const base::FilePath& cache_directory,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread) {
+ DCHECK(db_thread.get());
+
+ cache_directory_ = cache_directory;
+ is_incognito_ = cache_directory_.empty();
+
+ base::FilePath db_file_path;
+ if (!is_incognito_)
+ db_file_path = cache_directory_.Append(kAppCacheDatabaseName);
+ database_ = new AppCacheDatabase(db_file_path);
+
+ db_thread_ = db_thread;
+ cache_thread_ = cache_thread;
+
+ scoped_refptr<InitTask> task(new InitTask(this));
+ task->Schedule();
+}
+
+void AppCacheStorageImpl::Disable() {
+ if (is_disabled_)
+ return;
+ VLOG(1) << "Disabling appcache storage.";
+ is_disabled_ = true;
+ ClearUsageMapAndNotify();
+ working_set()->Disable();
+ if (disk_cache_)
+ disk_cache_->Disable();
+ scoped_refptr<DisableDatabaseTask> task(new DisableDatabaseTask(this));
+ task->Schedule();
+}
+
+void AppCacheStorageImpl::GetAllInfo(Delegate* delegate) {
+ DCHECK(delegate);
+ scoped_refptr<GetAllInfoTask> task(new GetAllInfoTask(this));
+ task->AddDelegate(GetOrCreateDelegateReference(delegate));
+ task->Schedule();
+}
+
+void AppCacheStorageImpl::LoadCache(int64 id, Delegate* delegate) {
+ DCHECK(delegate);
+ if (is_disabled_) {
+ delegate->OnCacheLoaded(NULL, id);
+ return;
+ }
+
+ AppCache* cache = working_set_.GetCache(id);
+ if (cache) {
+ delegate->OnCacheLoaded(cache, id);
+ if (cache->owning_group()) {
+ scoped_refptr<DatabaseTask> update_task(
+ new UpdateGroupLastAccessTimeTask(
+ this, cache->owning_group(), base::Time::Now()));
+ update_task->Schedule();
+ }
+ return;
+ }
+ scoped_refptr<CacheLoadTask> task(GetPendingCacheLoadTask(id));
+ if (task.get()) {
+ task->AddDelegate(GetOrCreateDelegateReference(delegate));
+ return;
+ }
+ task = new CacheLoadTask(id, this);
+ task->AddDelegate(GetOrCreateDelegateReference(delegate));
+ task->Schedule();
+ pending_cache_loads_[id] = task.get();
+}
+
+void AppCacheStorageImpl::LoadOrCreateGroup(
+ const GURL& manifest_url, Delegate* delegate) {
+ DCHECK(delegate);
+ if (is_disabled_) {
+ delegate->OnGroupLoaded(NULL, manifest_url);
+ return;
+ }
+
+ AppCacheGroup* group = working_set_.GetGroup(manifest_url);
+ if (group) {
+ delegate->OnGroupLoaded(group, manifest_url);
+ scoped_refptr<DatabaseTask> update_task(
+ new UpdateGroupLastAccessTimeTask(
+ this, group, base::Time::Now()));
+ update_task->Schedule();
+ return;
+ }
+
+ scoped_refptr<GroupLoadTask> task(GetPendingGroupLoadTask(manifest_url));
+ if (task.get()) {
+ task->AddDelegate(GetOrCreateDelegateReference(delegate));
+ return;
+ }
+
+ if (usage_map_.find(manifest_url.GetOrigin()) == usage_map_.end()) {
+ // No need to query the database, return a new group immediately.
+ scoped_refptr<AppCacheGroup> group(new AppCacheGroup(
+ this, manifest_url, NewGroupId()));
+ delegate->OnGroupLoaded(group.get(), manifest_url);
+ return;
+ }
+
+ task = new GroupLoadTask(manifest_url, this);
+ task->AddDelegate(GetOrCreateDelegateReference(delegate));
+ task->Schedule();
+ pending_group_loads_[manifest_url] = task.get();
+}
+
+void AppCacheStorageImpl::StoreGroupAndNewestCache(
+ AppCacheGroup* group, AppCache* newest_cache, Delegate* delegate) {
+ // TODO(michaeln): distinguish between a simple update of an existing
+ // cache that just adds new master entry(s), and the insertion of a
+ // whole new cache. The StoreGroupAndCacheTask as written will handle
+ // the simple update case in a very heavy weight way (delete all and
+ // the reinsert all over again).
+ DCHECK(group && delegate && newest_cache);
+ scoped_refptr<StoreGroupAndCacheTask> task(
+ new StoreGroupAndCacheTask(this, group, newest_cache));
+ task->AddDelegate(GetOrCreateDelegateReference(delegate));
+ task->GetQuotaThenSchedule();
+
+ // TODO(michaeln): histogram is fishing for clues to crbug/95101
+ if (!newest_cache->GetEntry(group->manifest_url())) {
+ AppCacheHistograms::AddMissingManifestDetectedAtCallsite(
+ AppCacheHistograms::CALLSITE_3);
+ }
+}
+
+void AppCacheStorageImpl::FindResponseForMainRequest(
+ const GURL& url, const GURL& preferred_manifest_url,
+ Delegate* delegate) {
+ DCHECK(delegate);
+
+ const GURL* url_ptr = &url;
+ GURL url_no_ref;
+ if (url.has_ref()) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ url_no_ref = url.ReplaceComponents(replacements);
+ url_ptr = &url_no_ref;
+ }
+
+ const GURL origin = url.GetOrigin();
+
+ // First look in our working set for a direct hit without having to query
+ // the database.
+ const AppCacheWorkingSet::GroupMap* groups_in_use =
+ working_set()->GetGroupsInOrigin(origin);
+ if (groups_in_use) {
+ if (!preferred_manifest_url.is_empty()) {
+ AppCacheWorkingSet::GroupMap::const_iterator found =
+ groups_in_use->find(preferred_manifest_url);
+ if (found != groups_in_use->end() &&
+ FindResponseForMainRequestInGroup(
+ found->second, *url_ptr, delegate)) {
+ return;
+ }
+ } else {
+ for (AppCacheWorkingSet::GroupMap::const_iterator it =
+ groups_in_use->begin();
+ it != groups_in_use->end(); ++it) {
+ if (FindResponseForMainRequestInGroup(
+ it->second, *url_ptr, delegate)) {
+ return;
+ }
+ }
+ }
+ }
+
+ if (IsInitTaskComplete() && usage_map_.find(origin) == usage_map_.end()) {
+ // No need to query the database, return async'ly but without going thru
+ // the DB thread.
+ scoped_refptr<AppCacheGroup> no_group;
+ scoped_refptr<AppCache> no_cache;
+ ScheduleSimpleTask(
+ base::Bind(&AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse,
+ weak_factory_.GetWeakPtr(), url, AppCacheEntry(), no_group,
+ no_cache,
+ make_scoped_refptr(GetOrCreateDelegateReference(delegate))));
+ return;
+ }
+
+ // We have to query the database, schedule a database task to do so.
+ scoped_refptr<FindMainResponseTask> task(
+ new FindMainResponseTask(this, *url_ptr, preferred_manifest_url,
+ groups_in_use));
+ task->AddDelegate(GetOrCreateDelegateReference(delegate));
+ task->Schedule();
+}
+
+bool AppCacheStorageImpl::FindResponseForMainRequestInGroup(
+ AppCacheGroup* group, const GURL& url, Delegate* delegate) {
+ AppCache* cache = group->newest_complete_cache();
+ if (group->is_obsolete() || !cache)
+ return false;
+
+ AppCacheEntry* entry = cache->GetEntry(url);
+ if (!entry || entry->IsForeign())
+ return false;
+
+ ScheduleSimpleTask(
+ base::Bind(&AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse,
+ weak_factory_.GetWeakPtr(), url, *entry,
+ make_scoped_refptr(group), make_scoped_refptr(cache),
+ make_scoped_refptr(GetOrCreateDelegateReference(delegate))));
+ return true;
+}
+
+void AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse(
+ const GURL& url,
+ const AppCacheEntry& found_entry,
+ scoped_refptr<AppCacheGroup> group,
+ scoped_refptr<AppCache> cache,
+ scoped_refptr<DelegateReference> delegate_ref) {
+ if (delegate_ref->delegate) {
+ DelegateReferenceVector delegates(1, delegate_ref);
+ CallOnMainResponseFound(
+ &delegates, url, found_entry,
+ GURL(), AppCacheEntry(),
+ cache.get() ? cache->cache_id() : kAppCacheNoCacheId,
+ group.get() ? group->group_id() : kAppCacheNoCacheId,
+ group.get() ? group->manifest_url() : GURL());
+ }
+}
+
+void AppCacheStorageImpl::CallOnMainResponseFound(
+ DelegateReferenceVector* delegates,
+ const GURL& url, const AppCacheEntry& entry,
+ const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
+ int64 cache_id, int64 group_id, const GURL& manifest_url) {
+ FOR_EACH_DELEGATE(
+ (*delegates),
+ OnMainResponseFound(url, entry,
+ namespace_entry_url, fallback_entry,
+ cache_id, group_id, manifest_url));
+}
+
+void AppCacheStorageImpl::FindResponseForSubRequest(
+ AppCache* cache, const GURL& url,
+ AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
+ bool* found_network_namespace) {
+ DCHECK(cache && cache->is_complete());
+
+ // When a group is forcibly deleted, all subresource loads for pages
+ // using caches in the group will result in a synthesized network errors.
+ // Forcible deletion is not a function that is covered by the HTML5 spec.
+ if (cache->owning_group()->is_being_deleted()) {
+ *found_entry = AppCacheEntry();
+ *found_fallback_entry = AppCacheEntry();
+ *found_network_namespace = false;
+ return;
+ }
+
+ GURL fallback_namespace_not_used;
+ GURL intercept_namespace_not_used;
+ cache->FindResponseForRequest(
+ url, found_entry, &intercept_namespace_not_used,
+ found_fallback_entry, &fallback_namespace_not_used,
+ found_network_namespace);
+}
+
+void AppCacheStorageImpl::MarkEntryAsForeign(
+ const GURL& entry_url, int64 cache_id) {
+ AppCache* cache = working_set_.GetCache(cache_id);
+ if (cache) {
+ AppCacheEntry* entry = cache->GetEntry(entry_url);
+ DCHECK(entry);
+ if (entry)
+ entry->add_types(AppCacheEntry::FOREIGN);
+ }
+ scoped_refptr<MarkEntryAsForeignTask> task(
+ new MarkEntryAsForeignTask(this, entry_url, cache_id));
+ task->Schedule();
+ pending_foreign_markings_.push_back(std::make_pair(entry_url, cache_id));
+}
+
+void AppCacheStorageImpl::MakeGroupObsolete(AppCacheGroup* group,
+ Delegate* delegate,
+ int response_code) {
+ DCHECK(group && delegate);
+ scoped_refptr<MakeGroupObsoleteTask> task(
+ new MakeGroupObsoleteTask(this, group, response_code));
+ task->AddDelegate(GetOrCreateDelegateReference(delegate));
+ task->Schedule();
+}
+
+AppCacheResponseReader* AppCacheStorageImpl::CreateResponseReader(
+ const GURL& manifest_url, int64 group_id, int64 response_id) {
+ return new AppCacheResponseReader(response_id, group_id, disk_cache());
+}
+
+AppCacheResponseWriter* AppCacheStorageImpl::CreateResponseWriter(
+ const GURL& manifest_url, int64 group_id) {
+ return new AppCacheResponseWriter(NewResponseId(), group_id, disk_cache());
+}
+
+void AppCacheStorageImpl::DoomResponses(
+ const GURL& manifest_url, const std::vector<int64>& response_ids) {
+ if (response_ids.empty())
+ return;
+
+ // Start deleting them from the disk cache lazily.
+ StartDeletingResponses(response_ids);
+
+ // Also schedule a database task to record these ids in the
+ // deletable responses table.
+ // TODO(michaeln): There is a race here. If the browser crashes
+ // prior to committing these rows to the database and prior to us
+ // having deleted them from the disk cache, we'll never delete them.
+ scoped_refptr<InsertDeletableResponseIdsTask> task(
+ new InsertDeletableResponseIdsTask(this));
+ task->response_ids_ = response_ids;
+ task->Schedule();
+}
+
+void AppCacheStorageImpl::DeleteResponses(
+ const GURL& manifest_url, const std::vector<int64>& response_ids) {
+ if (response_ids.empty())
+ return;
+ StartDeletingResponses(response_ids);
+}
+
+void AppCacheStorageImpl::DelayedStartDeletingUnusedResponses() {
+ // Only if we haven't already begun.
+ if (!did_start_deleting_responses_) {
+ scoped_refptr<GetDeletableResponseIdsTask> task(
+ new GetDeletableResponseIdsTask(this, last_deletable_response_rowid_));
+ task->Schedule();
+ }
+}
+
+void AppCacheStorageImpl::StartDeletingResponses(
+ const std::vector<int64>& response_ids) {
+ DCHECK(!response_ids.empty());
+ did_start_deleting_responses_ = true;
+ deletable_response_ids_.insert(
+ deletable_response_ids_.end(),
+ response_ids.begin(), response_ids.end());
+ if (!is_response_deletion_scheduled_)
+ ScheduleDeleteOneResponse();
+}
+
+void AppCacheStorageImpl::ScheduleDeleteOneResponse() {
+ DCHECK(!is_response_deletion_scheduled_);
+ const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&AppCacheStorageImpl::DeleteOneResponse,
+ weak_factory_.GetWeakPtr()),
+ kDelay);
+ is_response_deletion_scheduled_ = true;
+}
+
+void AppCacheStorageImpl::DeleteOneResponse() {
+ DCHECK(is_response_deletion_scheduled_);
+ DCHECK(!deletable_response_ids_.empty());
+
+ if (!disk_cache()) {
+ DCHECK(is_disabled_);
+ deletable_response_ids_.clear();
+ deleted_response_ids_.clear();
+ is_response_deletion_scheduled_ = false;
+ return;
+ }
+
+ // TODO(michaeln): add group_id to DoomEntry args
+ int64 id = deletable_response_ids_.front();
+ int rv = disk_cache_->DoomEntry(
+ id, base::Bind(&AppCacheStorageImpl::OnDeletedOneResponse,
+ base::Unretained(this)));
+ if (rv != net::ERR_IO_PENDING)
+ OnDeletedOneResponse(rv);
+}
+
+void AppCacheStorageImpl::OnDeletedOneResponse(int rv) {
+ is_response_deletion_scheduled_ = false;
+ if (is_disabled_)
+ return;
+
+ int64 id = deletable_response_ids_.front();
+ deletable_response_ids_.pop_front();
+ if (rv != net::ERR_ABORTED)
+ deleted_response_ids_.push_back(id);
+
+ const size_t kBatchSize = 50U;
+ if (deleted_response_ids_.size() >= kBatchSize ||
+ deletable_response_ids_.empty()) {
+ scoped_refptr<DeleteDeletableResponseIdsTask> task(
+ new DeleteDeletableResponseIdsTask(this));
+ task->response_ids_.swap(deleted_response_ids_);
+ task->Schedule();
+ }
+
+ if (deletable_response_ids_.empty()) {
+ scoped_refptr<GetDeletableResponseIdsTask> task(
+ new GetDeletableResponseIdsTask(this, last_deletable_response_rowid_));
+ task->Schedule();
+ return;
+ }
+
+ ScheduleDeleteOneResponse();
+}
+
+AppCacheStorageImpl::CacheLoadTask*
+AppCacheStorageImpl::GetPendingCacheLoadTask(int64 cache_id) {
+ PendingCacheLoads::iterator found = pending_cache_loads_.find(cache_id);
+ if (found != pending_cache_loads_.end())
+ return found->second;
+ return NULL;
+}
+
+AppCacheStorageImpl::GroupLoadTask*
+AppCacheStorageImpl::GetPendingGroupLoadTask(const GURL& manifest_url) {
+ PendingGroupLoads::iterator found = pending_group_loads_.find(manifest_url);
+ if (found != pending_group_loads_.end())
+ return found->second;
+ return NULL;
+}
+
+void AppCacheStorageImpl::GetPendingForeignMarkingsForCache(
+ int64 cache_id, std::vector<GURL>* urls) {
+ PendingForeignMarkings::iterator iter = pending_foreign_markings_.begin();
+ while (iter != pending_foreign_markings_.end()) {
+ if (iter->second == cache_id)
+ urls->push_back(iter->first);
+ ++iter;
+ }
+}
+
+void AppCacheStorageImpl::ScheduleSimpleTask(const base::Closure& task) {
+ pending_simple_tasks_.push_back(task);
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&AppCacheStorageImpl::RunOnePendingSimpleTask,
+ weak_factory_.GetWeakPtr()));
+}
+
+void AppCacheStorageImpl::RunOnePendingSimpleTask() {
+ DCHECK(!pending_simple_tasks_.empty());
+ base::Closure task = pending_simple_tasks_.front();
+ pending_simple_tasks_.pop_front();
+ task.Run();
+}
+
+AppCacheDiskCache* AppCacheStorageImpl::disk_cache() {
+ DCHECK(IsInitTaskComplete());
+
+ if (is_disabled_)
+ return NULL;
+
+ if (!disk_cache_) {
+ int rv = net::OK;
+ disk_cache_.reset(new AppCacheDiskCache);
+ if (is_incognito_) {
+ rv = disk_cache_->InitWithMemBackend(
+ kMaxMemDiskCacheSize,
+ base::Bind(&AppCacheStorageImpl::OnDiskCacheInitialized,
+ base::Unretained(this)));
+ } else {
+ rv = disk_cache_->InitWithDiskBackend(
+ cache_directory_.Append(kDiskCacheDirectoryName),
+ kMaxDiskCacheSize,
+ false,
+ cache_thread_.get(),
+ base::Bind(&AppCacheStorageImpl::OnDiskCacheInitialized,
+ base::Unretained(this)));
+ }
+
+ if (rv != net::ERR_IO_PENDING)
+ OnDiskCacheInitialized(rv);
+ }
+ return disk_cache_.get();
+}
+
+void AppCacheStorageImpl::OnDiskCacheInitialized(int rv) {
+ if (rv != net::OK) {
+ LOG(ERROR) << "Failed to open the appcache diskcache.";
+ AppCacheHistograms::CountInitResult(AppCacheHistograms::DISK_CACHE_ERROR);
+
+ // We're unable to open the disk cache, this is a fatal error that we can't
+ // really recover from. We handle it by temporarily disabling the appcache
+ // deleting the directory on disk and reinitializing the appcache system.
+ Disable();
+ if (rv != net::ERR_ABORTED)
+ DeleteAndStartOver();
+ }
+}
+
+void AppCacheStorageImpl::DeleteAndStartOver() {
+ DCHECK(is_disabled_);
+ if (!is_incognito_) {
+ VLOG(1) << "Deleting existing appcache data and starting over.";
+ // We can have tasks in flight to close file handles on both the db
+ // and cache threads, we need to allow those tasks to cycle thru
+ // prior to deleting the files and calling reinit.
+ cache_thread_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&base::DoNothing),
+ base::Bind(&AppCacheStorageImpl::DeleteAndStartOverPart2,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void AppCacheStorageImpl::DeleteAndStartOverPart2() {
+ db_thread_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&base::DeleteFile), cache_directory_, true),
+ base::Bind(&AppCacheStorageImpl::CallScheduleReinitialize,
+ weak_factory_.GetWeakPtr()));
+}
+
+void AppCacheStorageImpl::CallScheduleReinitialize() {
+ service_->ScheduleReinitialize();
+ // note: 'this' may be deleted at this point.
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_storage_impl.h b/chromium/content/browser/appcache/appcache_storage_impl.h
new file mode 100644
index 00000000000..ca6d76b314b
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_storage_impl.h
@@ -0,0 +1,183 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_STORAGE_IMPL_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_STORAGE_IMPL_H_
+
+#include <deque>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/appcache/appcache_database.h"
+#include "content/browser/appcache/appcache_disk_cache.h"
+#include "content/browser/appcache/appcache_storage.h"
+#include "content/common/content_export.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace content {
+class AppCacheStorageImplTest;
+class ChromeAppCacheServiceTest;
+
+class AppCacheStorageImpl : public AppCacheStorage {
+ public:
+ explicit AppCacheStorageImpl(AppCacheServiceImpl* service);
+ ~AppCacheStorageImpl() override;
+
+ void Initialize(
+ const base::FilePath& cache_directory,
+ const scoped_refptr<base::SingleThreadTaskRunner>& db_thread,
+ const scoped_refptr<base::SingleThreadTaskRunner>& cache_thread);
+ void Disable();
+ bool is_disabled() const { return is_disabled_; }
+
+ // AppCacheStorage methods, see the base class for doc comments.
+ void GetAllInfo(Delegate* delegate) override;
+ void LoadCache(int64 id, Delegate* delegate) override;
+ void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate) override;
+ void StoreGroupAndNewestCache(AppCacheGroup* group,
+ AppCache* newest_cache,
+ Delegate* delegate) override;
+ void FindResponseForMainRequest(const GURL& url,
+ const GURL& preferred_manifest_url,
+ Delegate* delegate) override;
+ void FindResponseForSubRequest(AppCache* cache,
+ const GURL& url,
+ AppCacheEntry* found_entry,
+ AppCacheEntry* found_fallback_entry,
+ bool* found_network_namespace) override;
+ void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id) override;
+ void MakeGroupObsolete(AppCacheGroup* group,
+ Delegate* delegate,
+ int response_code) override;
+ AppCacheResponseReader* CreateResponseReader(const GURL& manifest_url,
+ int64 group_id,
+ int64 response_id) override;
+ AppCacheResponseWriter* CreateResponseWriter(const GURL& manifest_url,
+ int64 group_id) override;
+ void DoomResponses(const GURL& manifest_url,
+ const std::vector<int64>& response_ids) override;
+ void DeleteResponses(const GURL& manifest_url,
+ const std::vector<int64>& response_ids) override;
+
+ private:
+ // The AppCacheStorageImpl class methods and datamembers may only be
+ // accessed on the IO thread. This class manufactures seperate DatabaseTasks
+ // which access the DB on a seperate background thread.
+ class DatabaseTask;
+ class InitTask;
+ class DisableDatabaseTask;
+ class GetAllInfoTask;
+ class StoreOrLoadTask;
+ class CacheLoadTask;
+ class GroupLoadTask;
+ class StoreGroupAndCacheTask;
+ class FindMainResponseTask;
+ class MarkEntryAsForeignTask;
+ class MakeGroupObsoleteTask;
+ class GetDeletableResponseIdsTask;
+ class InsertDeletableResponseIdsTask;
+ class DeleteDeletableResponseIdsTask;
+ class UpdateGroupLastAccessTimeTask;
+
+ typedef std::deque<DatabaseTask*> DatabaseTaskQueue;
+ typedef std::map<int64, CacheLoadTask*> PendingCacheLoads;
+ typedef std::map<GURL, GroupLoadTask*> PendingGroupLoads;
+ typedef std::deque<std::pair<GURL, int64> > PendingForeignMarkings;
+ typedef std::set<StoreGroupAndCacheTask*> PendingQuotaQueries;
+
+ bool IsInitTaskComplete() {
+ return last_cache_id_ != AppCacheStorage::kUnitializedId;
+ }
+
+ CacheLoadTask* GetPendingCacheLoadTask(int64 cache_id);
+ GroupLoadTask* GetPendingGroupLoadTask(const GURL& manifest_url);
+ void GetPendingForeignMarkingsForCache(
+ int64 cache_id, std::vector<GURL>* urls);
+
+ void ScheduleSimpleTask(const base::Closure& task);
+ void RunOnePendingSimpleTask();
+
+ void DelayedStartDeletingUnusedResponses();
+ void StartDeletingResponses(const std::vector<int64>& response_ids);
+ void ScheduleDeleteOneResponse();
+ void DeleteOneResponse();
+
+ void OnDeletedOneResponse(int rv);
+ void OnDiskCacheInitialized(int rv);
+ void DeleteAndStartOver();
+ void DeleteAndStartOverPart2();
+ void CallScheduleReinitialize();
+
+ // Sometimes we can respond without having to query the database.
+ bool FindResponseForMainRequestInGroup(
+ AppCacheGroup* group, const GURL& url, Delegate* delegate);
+ void DeliverShortCircuitedFindMainResponse(
+ const GURL& url,
+ const AppCacheEntry& found_entry,
+ scoped_refptr<AppCacheGroup> group,
+ scoped_refptr<AppCache> newest_cache,
+ scoped_refptr<DelegateReference> delegate_ref);
+
+ void CallOnMainResponseFound(
+ DelegateReferenceVector* delegates,
+ const GURL& url, const AppCacheEntry& entry,
+ const GURL& namespace_entry_url, const AppCacheEntry& fallback_entry,
+ int64 cache_id, int64 group_id, const GURL& manifest_url);
+
+ CONTENT_EXPORT AppCacheDiskCache* disk_cache();
+
+ // The directory in which we place files in the file system.
+ base::FilePath cache_directory_;
+ bool is_incognito_;
+
+ // This class operates primarily on the IO thread, but schedules
+ // its DatabaseTasks on the db thread. Separately, the disk_cache uses
+ // the cache thread.
+ scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> cache_thread_;
+
+ // Structures to keep track of DatabaseTasks that are in-flight.
+ DatabaseTaskQueue scheduled_database_tasks_;
+ PendingCacheLoads pending_cache_loads_;
+ PendingGroupLoads pending_group_loads_;
+ PendingForeignMarkings pending_foreign_markings_;
+ PendingQuotaQueries pending_quota_queries_;
+
+ // Structures to keep track of lazy response deletion.
+ std::deque<int64> deletable_response_ids_;
+ std::vector<int64> deleted_response_ids_;
+ bool is_response_deletion_scheduled_;
+ bool did_start_deleting_responses_;
+ int64 last_deletable_response_rowid_;
+
+ // Created on the IO thread, but only used on the DB thread.
+ AppCacheDatabase* database_;
+
+ // Set if we discover a fatal error like a corrupt SQL database or
+ // disk cache and cannot continue.
+ bool is_disabled_;
+
+ scoped_ptr<AppCacheDiskCache> disk_cache_;
+
+ // Used to short-circuit certain operations without having to schedule
+ // any tasks on the background database thread.
+ std::deque<base::Closure> pending_simple_tasks_;
+ base::WeakPtrFactory<AppCacheStorageImpl> weak_factory_;
+
+ friend class content::AppCacheStorageImplTest;
+ friend class content::ChromeAppCacheServiceTest;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_STORAGE_IMPL_H_
diff --git a/chromium/content/browser/appcache/appcache_storage_impl_unittest.cc b/chromium/content/browser/appcache/appcache_storage_impl_unittest.cc
index 4c467a1a2dc..330d9aba390 100644
--- a/chromium/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -7,13 +7,22 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_backend_impl.h"
+#include "content/browser/appcache/appcache_database.h"
+#include "content/browser/appcache/appcache_entry.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_host.h"
#include "content/browser/appcache/appcache_interceptor.h"
+#include "content/browser/appcache/appcache_request_handler.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "content/browser/appcache/appcache_storage_impl.h"
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/http/http_response_headers.h"
@@ -22,40 +31,8 @@
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
#include "sql/test/test_helpers.h"
+#include "storage/browser/quota/quota_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_backend_impl.h"
-#include "webkit/browser/appcache/appcache_database.h"
-#include "webkit/browser/appcache/appcache_entry.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_host.h"
-#include "webkit/browser/appcache/appcache_request_handler.h"
-#include "webkit/browser/appcache/appcache_service_impl.h"
-#include "webkit/browser/appcache/appcache_storage_impl.h"
-#include "webkit/browser/quota/quota_manager.h"
-
-using appcache::APPCACHE_FALLBACK_NAMESPACE;
-using appcache::APPCACHE_NETWORK_NAMESPACE;
-using appcache::AppCacheBackendImpl;
-using appcache::AppCacheDatabase;
-using appcache::AppCacheEntry;
-using appcache::AppCacheFrontend;
-using appcache::AppCacheHost;
-using appcache::AppCacheInfo;
-using appcache::AppCacheGroup;
-using appcache::AppCacheServiceImpl;
-using appcache::AppCacheStorage;
-using appcache::AppCacheStorageImpl;
-using appcache::AppCacheStorageReference;
-using appcache::AppCache;
-using appcache::AppCacheErrorDetails;
-using appcache::AppCacheEventID;
-using appcache::kAppCacheNoCacheId;
-using appcache::kAppCacheNoResponseId;
-using appcache::APPCACHE_INTERCEPT_NAMESPACE;
-using appcache::AppCacheLogLevel;
-using appcache::Namespace;
-using appcache::AppCacheStatus;
namespace content {
@@ -149,11 +126,23 @@ class MockHttpServer {
class MockHttpServerJobFactory
: public net::URLRequestJobFactory::ProtocolHandler {
public:
- virtual net::URLRequestJob* MaybeCreateJob(
+ MockHttpServerJobFactory(
+ scoped_ptr<net::URLRequestInterceptor> appcache_start_interceptor)
+ : appcache_start_interceptor_(appcache_start_interceptor.Pass()) {
+ }
+
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
+ net::URLRequestJob* appcache_job =
+ appcache_start_interceptor_->MaybeInterceptRequest(
+ request, network_delegate);
+ if (appcache_job)
+ return appcache_job;
return MockHttpServer::CreateJob(request, network_delegate);
}
+ private:
+ scoped_ptr<net::URLRequestInterceptor> appcache_start_interceptor_;
};
class IOThread : public base::Thread {
@@ -162,25 +151,26 @@ class IOThread : public base::Thread {
: base::Thread(name) {
}
- virtual ~IOThread() {
- Stop();
- }
+ ~IOThread() override { Stop(); }
net::URLRequestContext* request_context() {
return request_context_.get();
}
- virtual void Init() OVERRIDE {
+ void Init() override {
scoped_ptr<net::URLRequestJobFactoryImpl> factory(
new net::URLRequestJobFactoryImpl());
- factory->SetProtocolHandler("http", new MockHttpServerJobFactory);
+ factory->SetProtocolHandler(
+ "http",
+ new MockHttpServerJobFactory(
+ AppCacheInterceptor::CreateStartInterceptor()));
job_factory_ = factory.Pass();
request_context_.reset(new net::TestURLRequestContext());
request_context_->set_job_factory(job_factory_.get());
AppCacheInterceptor::EnsureRegistered();
}
- virtual void CleanUp() OVERRIDE {
+ void CleanUp() override {
request_context_.reset();
job_factory_.reset();
}
@@ -205,14 +195,14 @@ class AppCacheStorageImplTest : public testing::Test {
found_cache_id_(kAppCacheNoCacheId), test_(test) {
}
- virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE {
+ void OnCacheLoaded(AppCache* cache, int64 cache_id) override {
loaded_cache_ = cache;
loaded_cache_id_ = cache_id;
test_->ScheduleNextTask();
}
- virtual void OnGroupLoaded(AppCacheGroup* group,
- const GURL& manifest_url) OVERRIDE {
+ void OnGroupLoaded(AppCacheGroup* group,
+ const GURL& manifest_url) override {
loaded_group_ = group;
loaded_manifest_url_ = manifest_url;
loaded_groups_newest_cache_ = group ? group->newest_complete_cache()
@@ -220,30 +210,31 @@ class AppCacheStorageImplTest : public testing::Test {
test_->ScheduleNextTask();
}
- virtual void OnGroupAndNewestCacheStored(
- AppCacheGroup* group, AppCache* newest_cache, bool success,
- bool would_exceed_quota) OVERRIDE {
+ void OnGroupAndNewestCacheStored(AppCacheGroup* group,
+ AppCache* newest_cache,
+ bool success,
+ bool would_exceed_quota) override {
stored_group_ = group;
stored_group_success_ = success;
would_exceed_quota_ = would_exceed_quota;
test_->ScheduleNextTask();
}
- virtual void OnGroupMadeObsolete(AppCacheGroup* group,
- bool success,
- int response_code) OVERRIDE {
+ void OnGroupMadeObsolete(AppCacheGroup* group,
+ bool success,
+ int response_code) override {
obsoleted_group_ = group;
obsoleted_success_ = success;
test_->ScheduleNextTask();
}
- virtual void OnMainResponseFound(const GURL& url,
- const AppCacheEntry& entry,
- const GURL& namespace_entry_url,
- const AppCacheEntry& fallback_entry,
- int64 cache_id,
- int64 group_id,
- const GURL& manifest_url) OVERRIDE {
+ void OnMainResponseFound(const GURL& url,
+ const AppCacheEntry& entry,
+ const GURL& namespace_entry_url,
+ const AppCacheEntry& fallback_entry,
+ int64 cache_id,
+ int64 group_id,
+ const GURL& manifest_url) override {
found_url_ = url;
found_entry_ = entry;
found_namespace_entry_url_ = namespace_entry_url;
@@ -274,7 +265,7 @@ class AppCacheStorageImplTest : public testing::Test {
AppCacheStorageImplTest* test_;
};
- class MockQuotaManager : public quota::QuotaManager {
+ class MockQuotaManager : public storage::QuotaManager {
public:
MockQuotaManager()
: QuotaManager(true /* is_incognito */,
@@ -284,11 +275,10 @@ class AppCacheStorageImplTest : public testing::Test {
NULL),
async_(false) {}
- virtual void GetUsageAndQuota(
- const GURL& origin,
- quota::StorageType type,
- const GetUsageAndQuotaCallback& callback) OVERRIDE {
- EXPECT_EQ(quota::kStorageTypeTemporary, type);
+ void GetUsageAndQuota(const GURL& origin,
+ storage::StorageType type,
+ const GetUsageAndQuotaCallback& callback) override {
+ EXPECT_EQ(storage::kStorageTypeTemporary, type);
if (async_) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
@@ -301,16 +291,16 @@ class AppCacheStorageImplTest : public testing::Test {
}
void CallCallback(const GetUsageAndQuotaCallback& callback) {
- callback.Run(quota::kQuotaStatusOk, 0, kMockQuota);
+ callback.Run(storage::kQuotaStatusOk, 0, kMockQuota);
}
bool async_;
protected:
- virtual ~MockQuotaManager() {}
+ ~MockQuotaManager() override {}
};
- class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
+ class MockQuotaManagerProxy : public storage::QuotaManagerProxy {
public:
MockQuotaManagerProxy()
: QuotaManagerProxy(NULL, NULL),
@@ -321,39 +311,38 @@ class AppCacheStorageImplTest : public testing::Test {
manager_ = mock_manager_.get();
}
- virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type) OVERRIDE {
- EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
- EXPECT_EQ(quota::kStorageTypeTemporary, type);
+ void NotifyStorageAccessed(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type) override {
+ EXPECT_EQ(storage::QuotaClient::kAppcache, client_id);
+ EXPECT_EQ(storage::kStorageTypeTemporary, type);
++notify_storage_accessed_count_;
last_origin_ = origin;
}
- virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type,
- int64 delta) OVERRIDE {
- EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
- EXPECT_EQ(quota::kStorageTypeTemporary, type);
+ void NotifyStorageModified(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type,
+ int64 delta) override {
+ EXPECT_EQ(storage::QuotaClient::kAppcache, client_id);
+ EXPECT_EQ(storage::kStorageTypeTemporary, type);
++notify_storage_modified_count_;
last_origin_ = origin;
last_delta_ = delta;
}
// Not needed for our tests.
- virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {}
- virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
- virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
- virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type,
- bool enabled) OVERRIDE {}
- virtual void GetUsageAndQuota(
- base::SequencedTaskRunner* original_task_runner,
- const GURL& origin,
- quota::StorageType type,
- const GetUsageAndQuotaCallback& callback) OVERRIDE {}
+ void RegisterClient(storage::QuotaClient* client) override {}
+ void NotifyOriginInUse(const GURL& origin) override {}
+ void NotifyOriginNoLongerInUse(const GURL& origin) override {}
+ void SetUsageCacheEnabled(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type,
+ bool enabled) override {}
+ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
+ const GURL& origin,
+ storage::StorageType type,
+ const GetUsageAndQuotaCallback& callback) override {}
int notify_storage_accessed_count_;
int notify_storage_modified_count_;
@@ -362,7 +351,7 @@ class AppCacheStorageImplTest : public testing::Test {
scoped_refptr<MockQuotaManager> mock_manager_;
protected:
- virtual ~MockQuotaManagerProxy() {}
+ ~MockQuotaManagerProxy() override {}
};
template <class Method>
@@ -421,8 +410,7 @@ class AppCacheStorageImplTest : public testing::Test {
void SetUpTest() {
DCHECK(base::MessageLoop::current() == io_thread->message_loop());
service_.reset(new AppCacheServiceImpl(NULL));
- service_->Initialize(
- base::FilePath(), db_thread->message_loop_proxy().get(), NULL);
+ service_->Initialize(base::FilePath(), db_thread->task_runner(), NULL);
mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
delegate_.reset(new MockStorageDelegate(this));
@@ -734,7 +722,7 @@ class AppCacheStorageImplTest : public testing::Test {
base::Unretained(this), now));
// Conduct the test.
- EXPECT_EQ(cache_, group_->newest_complete_cache());
+ EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
EXPECT_FALSE(delegate()->stored_group_success_);
}
@@ -742,7 +730,7 @@ class AppCacheStorageImplTest : public testing::Test {
void Verify_StoreExistingGroupExistingCache(
base::Time expected_update_time) {
EXPECT_TRUE(delegate()->stored_group_success_);
- EXPECT_EQ(cache_, group_->newest_complete_cache());
+ EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
AppCacheDatabase::CacheRecord cache_record;
EXPECT_TRUE(database()->FindCache(1, &cache_record));
@@ -1054,12 +1042,12 @@ class AppCacheStorageImplTest : public testing::Test {
cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
cache_->fallback_namespaces_.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE,
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
kFallbackNamespace2,
kEntryUrl2,
false));
cache_->fallback_namespaces_.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE,
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
kFallbackNamespace,
kEntryUrl,
false));
@@ -1132,10 +1120,10 @@ class AppCacheStorageImplTest : public testing::Test {
cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2));
cache_->intercept_namespaces_.push_back(
- Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace2,
+ AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace2,
kEntryUrl2, false));
cache_->intercept_namespaces_.push_back(
- Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace,
+ AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace,
kEntryUrl, false));
AppCacheDatabase::CacheRecord cache_record;
std::vector<AppCacheDatabase::EntryRecord> entries;
@@ -1202,8 +1190,8 @@ class AppCacheStorageImplTest : public testing::Test {
MakeCacheAndGroup(kManifestUrl, 2, 1, true);
cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
cache_->intercept_namespaces_.push_back(
- Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptPatternNamespace,
- kEntryUrl, true));
+ AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE,
+ kInterceptPatternNamespace, kEntryUrl, true));
AppCacheDatabase::CacheRecord cache_record;
std::vector<AppCacheDatabase::EntryRecord> entries;
std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
@@ -1289,8 +1277,8 @@ class AppCacheStorageImplTest : public testing::Test {
MakeCacheAndGroup(kManifestUrl, 2, 1, true);
cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
cache_->fallback_namespaces_.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackPatternNamespace,
- kEntryUrl, true));
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
+ kFallbackPatternNamespace, kEntryUrl, true));
AppCacheDatabase::CacheRecord cache_record;
std::vector<AppCacheDatabase::EntryRecord> entries;
std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
@@ -1420,7 +1408,7 @@ class AppCacheStorageImplTest : public testing::Test {
fallback_namespace_record.origin = manifest_url.GetOrigin();
EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
cache_->fallback_namespaces_.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE,
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
kFallbackNamespace,
kEntryUrl2,
false));
@@ -1435,7 +1423,7 @@ class AppCacheStorageImplTest : public testing::Test {
EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
- // Conduct another test perferring kManifestUrl
+ // Conduct another test preferring kManifestUrl
delegate_.reset(new MockStorageDelegate(this));
PushNextTask(base::Bind(
&AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2,
@@ -1453,7 +1441,7 @@ class AppCacheStorageImplTest : public testing::Test {
EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
- // Conduct the another test perferring kManifestUrl2
+ // Conduct the another test preferring kManifestUrl2
delegate_.reset(new MockStorageDelegate(this));
PushNextTask(base::Bind(
&AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3,
@@ -1535,16 +1523,16 @@ class AppCacheStorageImplTest : public testing::Test {
AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1));
cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
cache_->fallback_namespaces_.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE,
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
kFallbackNamespace,
kEntryUrl2,
false));
cache_->online_whitelist_namespaces_.push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespace,
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespace,
GURL(), false));
cache_->online_whitelist_namespaces_.push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespaceWithinFallback,
- GURL(), false));
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE,
+ kOnlineNamespaceWithinFallback, GURL(), false));
AppCacheDatabase::EntryRecord entry_record;
entry_record.cache_id = 1;
@@ -1622,8 +1610,8 @@ class AppCacheStorageImplTest : public testing::Test {
explicit MockServiceObserver(AppCacheStorageImplTest* test)
: test_(test) {}
- virtual void OnServiceReinitialized(
- AppCacheStorageReference* old_storage_ref) OVERRIDE {
+ void OnServiceReinitialized(
+ AppCacheStorageReference* old_storage_ref) override {
observed_old_storage_ = old_storage_ref;
test_->ScheduleNextTask();
}
@@ -1636,25 +1624,23 @@ class AppCacheStorageImplTest : public testing::Test {
public:
MockAppCacheFrontend() : error_event_was_raised_(false) {}
- virtual void OnCacheSelected(
- int host_id, const AppCacheInfo& info) OVERRIDE {}
- virtual void OnStatusChanged(const std::vector<int>& host_ids,
- AppCacheStatus status) OVERRIDE {}
- virtual void OnEventRaised(const std::vector<int>& host_ids,
- AppCacheEventID event_id) OVERRIDE {}
- virtual void OnProgressEventRaised(
- const std::vector<int>& host_ids,
- const GURL& url,
- int num_total, int num_complete) OVERRIDE {}
- virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
- const AppCacheErrorDetails& details)
- OVERRIDE {
+ void OnCacheSelected(int host_id, const AppCacheInfo& info) override {}
+ void OnStatusChanged(const std::vector<int>& host_ids,
+ AppCacheStatus status) override {}
+ void OnEventRaised(const std::vector<int>& host_ids,
+ AppCacheEventID event_id) override {}
+ void OnProgressEventRaised(const std::vector<int>& host_ids,
+ const GURL& url,
+ int num_total,
+ int num_complete) override {}
+ void OnErrorEventRaised(const std::vector<int>& host_ids,
+ const AppCacheErrorDetails& details) override {
error_event_was_raised_ = true;
}
- virtual void OnLogMessage(int host_id, AppCacheLogLevel log_level,
- const std::string& message) OVERRIDE {}
- virtual void OnContentBlocked(
- int host_id, const GURL& manifest_url) OVERRIDE {}
+ void OnLogMessage(int host_id,
+ AppCacheLogLevel log_level,
+ const std::string& message) override {}
+ void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
bool error_event_was_raised_;
};
@@ -1733,10 +1719,9 @@ class AppCacheStorageImplTest : public testing::Test {
// Recreate the service to point at the db and corruption on disk.
service_.reset(new AppCacheServiceImpl(NULL));
service_->set_request_context(io_thread->request_context());
- service_->Initialize(
- temp_directory_.path(),
- db_thread->message_loop_proxy().get(),
- db_thread->message_loop_proxy().get());
+ service_->Initialize(temp_directory_.path(),
+ db_thread->task_runner(),
+ db_thread->task_runner());
mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
delegate_.reset(new MockStorageDelegate(this));
@@ -1791,7 +1776,7 @@ class AppCacheStorageImplTest : public testing::Test {
AppCacheInterceptor::SetExtraRequestInfo(
request_.get(), service_.get(),
backend_->process_id(), host2->host_id(),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
request_->Start();
}
@@ -1823,7 +1808,7 @@ class AppCacheStorageImplTest : public testing::Test {
EXPECT_TRUE(frontend_.error_event_was_raised_);
AppCacheHost* host1 = backend_->GetHost(1);
EXPECT_FALSE(host1->associated_cache());
- EXPECT_FALSE(host1->group_being_updated_);
+ EXPECT_FALSE(host1->group_being_updated_.get());
EXPECT_TRUE(host1->disabled_storage_reference_.get());
} else {
ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
diff --git a/chromium/content/browser/appcache/appcache_storage_unittest.cc b/chromium/content/browser/appcache/appcache_storage_unittest.cc
index fa696968e72..c6b50bf043a 100644
--- a/chromium/content/browser/appcache/appcache_storage_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_storage_unittest.cc
@@ -3,24 +3,18 @@
// found in the LICENSE file.
#include "base/message_loop/message_loop.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_storage.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "content/browser/quota/mock_quota_manager_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_storage.h"
-
-using appcache::AppCache;
-using appcache::AppCacheGroup;
-using appcache::AppCacheResponseInfo;
-using appcache::AppCacheStorage;
-using appcache::kUnkownResponseDataSize;
namespace content {
namespace {
-const quota::StorageType kTemp = quota::kStorageTypeTemporary;
+const storage::StorageType kTemp = storage::kStorageTypeTemporary;
}
class AppCacheStorageTest : public testing::Test {
diff --git a/chromium/content/browser/appcache/appcache_unittest.cc b/chromium/content/browser/appcache/appcache_unittest.cc
index 32c4e89dee0..4062498e95e 100644
--- a/chromium/content/browser/appcache/appcache_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_unittest.cc
@@ -2,30 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_host.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_host.h"
-
-using appcache::AppCache;
-using appcache::AppCacheDatabase;
-using appcache::AppCacheEntry;
-using appcache::AppCacheFrontend;
-using appcache::AppCacheGroup;
-using appcache::AppCacheHost;
-using appcache::AppCacheInfo;
-using appcache::AppCacheErrorDetails;
-using appcache::AppCacheEventID;
-using appcache::APPCACHE_FALLBACK_NAMESPACE;
-using appcache::APPCACHE_INTERCEPT_NAMESPACE;
-using appcache::AppCacheLogLevel;
-using appcache::Manifest;
-using appcache::Namespace;
-using appcache::NamespaceVector;
-using appcache::APPCACHE_NETWORK_NAMESPACE;
-using appcache::PARSE_MANIFEST_ALLOWING_INTERCEPTS;
-using appcache::PARSE_MANIFEST_PER_STANDARD;
-using appcache::AppCacheStatus;
namespace content {
@@ -33,23 +13,21 @@ namespace {
class MockAppCacheFrontend : public AppCacheFrontend {
public:
- virtual void OnCacheSelected(int host_id, const AppCacheInfo& info) OVERRIDE {
- }
- virtual void OnStatusChanged(const std::vector<int>& host_ids,
- AppCacheStatus status) OVERRIDE {}
- virtual void OnEventRaised(const std::vector<int>& host_ids,
- AppCacheEventID event_id) OVERRIDE {}
- virtual void OnProgressEventRaised(
- const std::vector<int>& host_ids,
- const GURL& url,
- int num_total, int num_complete) OVERRIDE {}
- virtual void OnErrorEventRaised(
- const std::vector<int>& host_ids,
- const AppCacheErrorDetails& details) OVERRIDE {}
- virtual void OnLogMessage(int host_id, AppCacheLogLevel log_level,
- const std::string& message) OVERRIDE {}
- virtual void OnContentBlocked(
- int host_id, const GURL& manifest_url) OVERRIDE {}
+ void OnCacheSelected(int host_id, const AppCacheInfo& info) override {}
+ void OnStatusChanged(const std::vector<int>& host_ids,
+ AppCacheStatus status) override {}
+ void OnEventRaised(const std::vector<int>& host_ids,
+ AppCacheEventID event_id) override {}
+ void OnProgressEventRaised(const std::vector<int>& host_ids,
+ const GURL& url,
+ int num_total,
+ int num_complete) override {}
+ void OnErrorEventRaised(const std::vector<int>& host_ids,
+ const AppCacheErrorDetails& details) override {}
+ void OnLogMessage(int host_id,
+ AppCacheLogLevel log_level,
+ const std::string& message) override {}
+ void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
};
} // namespace
@@ -128,27 +106,30 @@ TEST(AppCacheTest, InitializeWithManifest) {
EXPECT_TRUE(cache->online_whitelist_namespaces_.empty());
EXPECT_FALSE(cache->online_whitelist_all_);
- Manifest manifest;
+ AppCacheManifest manifest;
manifest.explicit_urls.insert("http://one.com");
manifest.explicit_urls.insert("http://two.com");
manifest.fallback_namespaces.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE, GURL("http://fb1.com"),
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, GURL("http://fb1.com"),
GURL("http://fbone.com"), true));
manifest.online_whitelist_namespaces.push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE, GURL("http://w1.com"), GURL(), false));
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, GURL("http://w1.com"),
+ GURL(), false));
manifest.online_whitelist_namespaces.push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE, GURL("http://w2.com"), GURL(), false));
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, GURL("http://w2.com"),
+ GURL(), false));
manifest.online_whitelist_all = true;
cache->InitializeWithManifest(&manifest);
- const std::vector<Namespace>& fallbacks =
+ const std::vector<AppCacheNamespace>& fallbacks =
cache->fallback_namespaces_;
size_t expected = 1;
EXPECT_EQ(expected, fallbacks.size());
EXPECT_EQ(GURL("http://fb1.com"), fallbacks[0].namespace_url);
EXPECT_EQ(GURL("http://fbone.com"), fallbacks[0].target_url);
EXPECT_TRUE(fallbacks[0].is_pattern);
- const NamespaceVector& whitelist = cache->online_whitelist_namespaces_;
+ const AppCacheNamespaceVector& whitelist =
+ cache->online_whitelist_namespaces_;
expected = 2;
EXPECT_EQ(expected, whitelist.size());
EXPECT_EQ(GURL("http://w1.com"), whitelist[0].namespace_url);
@@ -191,26 +172,25 @@ TEST(AppCacheTest, FindResponseForRequest) {
const int64 kExplicitInOnlineNamespaceResponseId = 5;
const int64 kInterceptResponseId = 6;
- Manifest manifest;
+ AppCacheManifest manifest;
manifest.online_whitelist_namespaces.push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespaceUrl,
- GURL(), false));
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespaceUrl,
+ GURL(), false));
manifest.online_whitelist_namespaces.push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE,
- kOnlineNamespaceWithinOtherNamespaces,
- GURL(), false));
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE,
+ kOnlineNamespaceWithinOtherNamespaces, GURL(), false));
manifest.fallback_namespaces.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl1,
- kFallbackEntryUrl1, false));
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl1,
+ kFallbackEntryUrl1, false));
manifest.fallback_namespaces.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl2,
- kFallbackEntryUrl2, false));
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl2,
+ kFallbackEntryUrl2, false));
manifest.intercept_namespaces.push_back(
- Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace,
- kInterceptNamespaceEntry, false));
+ AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace,
+ kInterceptNamespaceEntry, false));
manifest.intercept_namespaces.push_back(
- Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespaceWithinFallback,
- kInterceptNamespaceEntry, false));
+ AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE,
+ kInterceptNamespaceWithinFallback, kInterceptNamespaceEntry, false));
// Create a cache with some namespaces and entries.
scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
@@ -383,10 +363,10 @@ TEST(AppCacheTest, FindInterceptPatternResponseForRequest) {
kInterceptNamespaceBase.Resolve("*.hit*"));
const GURL kInterceptNamespaceEntry("http://blah/intercept_resource");
const int64 kInterceptResponseId = 1;
- Manifest manifest;
+ AppCacheManifest manifest;
manifest.intercept_namespaces.push_back(
- Namespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptPatternNamespace,
- kInterceptNamespaceEntry, true));
+ AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE,
+ kInterceptPatternNamespace, kInterceptNamespaceEntry, true));
scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
cache->InitializeWithManifest(&manifest);
cache->AddEntry(
@@ -454,9 +434,9 @@ TEST(AppCacheTest, FindFallbackPatternResponseForRequest) {
kFallbackNamespaceBase.Resolve("*.hit*"));
const GURL kFallbackNamespaceEntry("http://blah/fallback_resource");
const int64 kFallbackResponseId = 1;
- Manifest manifest;
+ AppCacheManifest manifest;
manifest.fallback_namespaces.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackPatternNamespace,
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackPatternNamespace,
kFallbackNamespaceEntry, true));
scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
cache->InitializeWithManifest(&manifest);
@@ -524,9 +504,9 @@ TEST(AppCacheTest, FindNetworkNamespacePatternResponseForRequest) {
const GURL kNetworkNamespaceBase("http://blah/network_namespace/");
const GURL kNetworkPatternNamespace(
kNetworkNamespaceBase.Resolve("*.hit*"));
- Manifest manifest;
+ AppCacheManifest manifest;
manifest.online_whitelist_namespaces.push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE, kNetworkPatternNamespace,
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kNetworkPatternNamespace,
GURL(), true));
manifest.online_whitelist_all = false;
scoped_refptr<AppCache> cache(new AppCache(service.storage(), 1234));
@@ -580,7 +560,7 @@ TEST(AppCacheTest, ToFromDatabaseRecords) {
scoped_refptr<AppCacheGroup> group =
new AppCacheGroup(service.storage(), kManifestUrl, kGroupId);
scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
- Manifest manifest;
+ AppCacheManifest manifest;
EXPECT_TRUE(ParseManifest(kManifestUrl, kData.c_str(), kData.length(),
PARSE_MANIFEST_ALLOWING_INTERCEPTS, manifest));
cache->InitializeWithManifest(&manifest);
@@ -644,7 +624,7 @@ TEST(AppCacheTest, ToFromDatabaseRecords) {
}
TEST(AppCacheTest, IsNamespaceMatch) {
- Namespace prefix;
+ AppCacheNamespace prefix;
prefix.namespace_url = GURL("http://foo.com/prefix");
prefix.is_pattern = false;
EXPECT_TRUE(prefix.IsMatch(
@@ -652,7 +632,7 @@ TEST(AppCacheTest, IsNamespaceMatch) {
EXPECT_FALSE(prefix.IsMatch(
GURL("http://foo.com/nope")));
- Namespace bar_no_star;
+ AppCacheNamespace bar_no_star;
bar_no_star.namespace_url = GURL("http://foo.com/bar");
bar_no_star.is_pattern = true;
EXPECT_TRUE(bar_no_star.IsMatch(
@@ -660,7 +640,7 @@ TEST(AppCacheTest, IsNamespaceMatch) {
EXPECT_FALSE(bar_no_star.IsMatch(
GURL("http://foo.com/bar/nope")));
- Namespace bar_star;
+ AppCacheNamespace bar_star;
bar_star.namespace_url = GURL("http://foo.com/bar/*");
bar_star.is_pattern = true;
EXPECT_TRUE(bar_star.IsMatch(
@@ -670,7 +650,7 @@ TEST(AppCacheTest, IsNamespaceMatch) {
EXPECT_FALSE(bar_star.IsMatch(
GURL("http://foo.com/not_bar/should_not_match")));
- Namespace star_bar_star;
+ AppCacheNamespace star_bar_star;
star_bar_star.namespace_url = GURL("http://foo.com/*/bar/*");
star_bar_star.is_pattern = true;
EXPECT_TRUE(star_bar_star.IsMatch(
@@ -680,7 +660,7 @@ TEST(AppCacheTest, IsNamespaceMatch) {
EXPECT_FALSE(star_bar_star.IsMatch(
GURL("http://foo.com/any/not_bar/no_match")));
- Namespace query_star_edit;
+ AppCacheNamespace query_star_edit;
query_star_edit.namespace_url = GURL("http://foo.com/query?id=*&verb=edit*");
query_star_edit.is_pattern = true;
EXPECT_TRUE(query_star_edit.IsMatch(
@@ -692,7 +672,7 @@ TEST(AppCacheTest, IsNamespaceMatch) {
EXPECT_TRUE(query_star_edit.IsMatch(
GURL("http://foo.com/query?id=123&verb=print&verb=edit")));
- Namespace star_greediness;
+ AppCacheNamespace star_greediness;
star_greediness.namespace_url = GURL("http://foo.com/*/b");
star_greediness.is_pattern = true;
EXPECT_TRUE(star_greediness.IsMatch(
diff --git a/chromium/content/browser/appcache/appcache_update_job.cc b/chromium/content/browser/appcache/appcache_update_job.cc
new file mode 100644
index 00000000000..af47342e97c
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_update_job.cc
@@ -0,0 +1,1636 @@
+// 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/appcache/appcache_update_job.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_histograms.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/io_buffer.h"
+#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_context.h"
+
+namespace {
+bool IsDataReductionProxy(const net::HostPortPair& proxy_server) {
+ return (
+ proxy_server.Equals(net::HostPortPair("proxy.googlezip.net", 443)) ||
+ proxy_server.Equals(net::HostPortPair("compress.googlezip.net", 80)) ||
+ proxy_server.Equals(net::HostPortPair("proxy-dev.googlezip.net", 80)));
+}
+} // namspace
+
+namespace content {
+
+static const int kBufferSize = 32768;
+static const size_t kMaxConcurrentUrlFetches = 2;
+static const int kMax503Retries = 3;
+
+static std::string FormatUrlErrorMessage(
+ const char* format, const GURL& url,
+ AppCacheUpdateJob::ResultType error,
+ int response_code) {
+ // Show the net response code if we have one.
+ int code = response_code;
+ if (error != AppCacheUpdateJob::SERVER_ERROR)
+ code = static_cast<int>(error);
+ return base::StringPrintf(format, code, url.spec().c_str());
+}
+
+// Helper class for collecting hosts per frontend when sending notifications
+// so that only one notification is sent for all hosts using the same frontend.
+class HostNotifier {
+ public:
+ typedef std::vector<int> HostIds;
+ typedef std::map<AppCacheFrontend*, HostIds> NotifyHostMap;
+
+ // Caller is responsible for ensuring there will be no duplicate hosts.
+ void AddHost(AppCacheHost* host) {
+ std::pair<NotifyHostMap::iterator , bool> ret = hosts_to_notify.insert(
+ NotifyHostMap::value_type(host->frontend(), HostIds()));
+ ret.first->second.push_back(host->host_id());
+ }
+
+ void AddHosts(const std::set<AppCacheHost*>& hosts) {
+ for (std::set<AppCacheHost*>::const_iterator it = hosts.begin();
+ it != hosts.end(); ++it) {
+ AddHost(*it);
+ }
+ }
+
+ void SendNotifications(AppCacheEventID event_id) {
+ for (NotifyHostMap::iterator it = hosts_to_notify.begin();
+ it != hosts_to_notify.end(); ++it) {
+ AppCacheFrontend* frontend = it->first;
+ frontend->OnEventRaised(it->second, event_id);
+ }
+ }
+
+ void SendProgressNotifications(
+ const GURL& url, int num_total, int num_complete) {
+ for (NotifyHostMap::iterator it = hosts_to_notify.begin();
+ it != hosts_to_notify.end(); ++it) {
+ AppCacheFrontend* frontend = it->first;
+ frontend->OnProgressEventRaised(it->second, url,
+ num_total, num_complete);
+ }
+ }
+
+ void SendErrorNotifications(const AppCacheErrorDetails& details) {
+ DCHECK(!details.message.empty());
+ for (NotifyHostMap::iterator it = hosts_to_notify.begin();
+ it != hosts_to_notify.end(); ++it) {
+ AppCacheFrontend* frontend = it->first;
+ frontend->OnErrorEventRaised(it->second, details);
+ }
+ }
+
+ void SendLogMessage(const std::string& message) {
+ for (NotifyHostMap::iterator it = hosts_to_notify.begin();
+ it != hosts_to_notify.end(); ++it) {
+ AppCacheFrontend* frontend = it->first;
+ for (HostIds::iterator id = it->second.begin();
+ id != it->second.end(); ++id) {
+ frontend->OnLogMessage(*id, APPCACHE_LOG_WARNING, message);
+ }
+ }
+ }
+
+ private:
+ NotifyHostMap hosts_to_notify;
+};
+
+AppCacheUpdateJob::UrlToFetch::UrlToFetch(const GURL& url,
+ bool checked,
+ AppCacheResponseInfo* info)
+ : url(url),
+ storage_checked(checked),
+ existing_response_info(info) {
+}
+
+AppCacheUpdateJob::UrlToFetch::~UrlToFetch() {
+}
+
+// Helper class to fetch resources. Depending on the fetch type,
+// can either fetch to an in-memory string or write the response
+// data out to the disk cache.
+AppCacheUpdateJob::URLFetcher::URLFetcher(const GURL& url,
+ FetchType fetch_type,
+ AppCacheUpdateJob* job)
+ : url_(url),
+ job_(job),
+ fetch_type_(fetch_type),
+ retry_503_attempts_(0),
+ buffer_(new net::IOBuffer(kBufferSize)),
+ request_(job->service_->request_context()
+ ->CreateRequest(url, net::DEFAULT_PRIORITY, this, NULL)),
+ result_(UPDATE_OK),
+ redirect_response_code_(-1) {}
+
+AppCacheUpdateJob::URLFetcher::~URLFetcher() {
+}
+
+void AppCacheUpdateJob::URLFetcher::Start() {
+ request_->set_first_party_for_cookies(job_->manifest_url_);
+ request_->SetLoadFlags(request_->load_flags() |
+ net::LOAD_DISABLE_INTERCEPT);
+ if (existing_response_headers_.get())
+ AddConditionalHeaders(existing_response_headers_.get());
+ request_->Start();
+}
+
+void AppCacheUpdateJob::URLFetcher::OnReceivedRedirect(
+ net::URLRequest* request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) {
+ DCHECK(request_ == request);
+ // TODO(bengr): Remove this special case logic when crbug.com/429505 is
+ // resolved. Until then, the data reduction proxy client logic uses the
+ // redirect mechanism to resend requests over a direct connection when
+ // the proxy instructs it to do so. The redirect is to the same location
+ // as the original URL.
+ if ((request->load_flags() & net::LOAD_BYPASS_PROXY) &&
+ IsDataReductionProxy(request->proxy_server())) {
+ DCHECK_EQ(request->original_url(), request->url());
+ return;
+ }
+ // Redirect is not allowed by the update process.
+ job_->MadeProgress();
+ redirect_response_code_ = request->GetResponseCode();
+ request->Cancel();
+ result_ = REDIRECT_ERROR;
+ OnResponseCompleted();
+}
+
+void AppCacheUpdateJob::URLFetcher::OnResponseStarted(
+ net::URLRequest *request) {
+ DCHECK(request == request_);
+ int response_code = -1;
+ if (request->status().is_success()) {
+ response_code = request->GetResponseCode();
+ job_->MadeProgress();
+ }
+
+ if ((response_code / 100) != 2) {
+ if (response_code > 0)
+ result_ = SERVER_ERROR;
+ else
+ result_ = NETWORK_ERROR;
+ OnResponseCompleted();
+ return;
+ }
+
+ if (url_.SchemeIsSecure()) {
+ // Do not cache content with cert errors.
+ // Also, we willfully violate the HTML5 spec at this point in order
+ // to support the appcaching of cross-origin HTTPS resources.
+ // We've opted for a milder constraint and allow caching unless
+ // the resource has a "no-store" header. A spec change has been
+ // requested on the whatwg list.
+ // See http://code.google.com/p/chromium/issues/detail?id=69594
+ // TODO(michaeln): Consider doing this for cross-origin HTTP too.
+ if (net::IsCertStatusError(request->ssl_info().cert_status) ||
+ (url_.GetOrigin() != job_->manifest_url_.GetOrigin() &&
+ request->response_headers()->
+ HasHeaderValue("cache-control", "no-store"))) {
+ DCHECK_EQ(-1, redirect_response_code_);
+ request->Cancel();
+ result_ = SECURITY_ERROR;
+ OnResponseCompleted();
+ return;
+ }
+ }
+
+ // Write response info to storage for URL fetches. Wait for async write
+ // completion before reading any response data.
+ if (fetch_type_ == URL_FETCH || fetch_type_ == MASTER_ENTRY_FETCH) {
+ response_writer_.reset(job_->CreateResponseWriter());
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
+ new HttpResponseInfoIOBuffer(
+ new net::HttpResponseInfo(request->response_info())));
+ response_writer_->WriteInfo(
+ io_buffer.get(),
+ base::Bind(&URLFetcher::OnWriteComplete, base::Unretained(this)));
+ } else {
+ ReadResponseData();
+ }
+}
+
+void AppCacheUpdateJob::URLFetcher::OnReadCompleted(
+ net::URLRequest* request, int bytes_read) {
+ DCHECK(request_ == request);
+ bool data_consumed = true;
+ if (request->status().is_success() && bytes_read > 0) {
+ job_->MadeProgress();
+ data_consumed = ConsumeResponseData(bytes_read);
+ if (data_consumed) {
+ bytes_read = 0;
+ while (request->Read(buffer_.get(), kBufferSize, &bytes_read)) {
+ if (bytes_read > 0) {
+ data_consumed = ConsumeResponseData(bytes_read);
+ if (!data_consumed)
+ break; // wait for async data processing, then read more
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ if (data_consumed && !request->status().is_io_pending()) {
+ DCHECK_EQ(UPDATE_OK, result_);
+ OnResponseCompleted();
+ }
+}
+
+void AppCacheUpdateJob::URLFetcher::AddConditionalHeaders(
+ const net::HttpResponseHeaders* headers) {
+ DCHECK(request_.get() && headers);
+ net::HttpRequestHeaders extra_headers;
+
+ // 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);
+ if (!last_modified_value.empty()) {
+ extra_headers.SetHeader(net::HttpRequestHeaders::kIfModifiedSince,
+ last_modified_value);
+ }
+
+ // 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);
+ if (!etag_value.empty()) {
+ extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch,
+ etag_value);
+ }
+ if (!extra_headers.IsEmpty())
+ request_->SetExtraRequestHeaders(extra_headers);
+}
+
+void AppCacheUpdateJob::URLFetcher::OnWriteComplete(int result) {
+ if (result < 0) {
+ request_->Cancel();
+ result_ = DISKCACHE_ERROR;
+ OnResponseCompleted();
+ return;
+ }
+ ReadResponseData();
+}
+
+void AppCacheUpdateJob::URLFetcher::ReadResponseData() {
+ InternalUpdateState state = job_->internal_state_;
+ if (state == CACHE_FAILURE || state == CANCELLED || state == COMPLETED)
+ return;
+ int bytes_read = 0;
+ request_->Read(buffer_.get(), kBufferSize, &bytes_read);
+ OnReadCompleted(request_.get(), bytes_read);
+}
+
+// Returns false if response data is processed asynchronously, in which
+// case ReadResponseData will be invoked when it is safe to continue
+// reading more response data from the request.
+bool AppCacheUpdateJob::URLFetcher::ConsumeResponseData(int bytes_read) {
+ DCHECK_GT(bytes_read, 0);
+ switch (fetch_type_) {
+ case MANIFEST_FETCH:
+ case MANIFEST_REFETCH:
+ manifest_data_.append(buffer_->data(), bytes_read);
+ break;
+ case URL_FETCH:
+ case MASTER_ENTRY_FETCH:
+ DCHECK(response_writer_.get());
+ response_writer_->WriteData(
+ buffer_.get(),
+ bytes_read,
+ base::Bind(&URLFetcher::OnWriteComplete, base::Unretained(this)));
+ return false; // wait for async write completion to continue reading
+ default:
+ NOTREACHED();
+ }
+ return true;
+}
+
+void AppCacheUpdateJob::URLFetcher::OnResponseCompleted() {
+ if (request_->status().is_success())
+ job_->MadeProgress();
+
+ // Retry for 503s where retry-after is 0.
+ if (request_->status().is_success() &&
+ request_->GetResponseCode() == 503 &&
+ MaybeRetryRequest()) {
+ return;
+ }
+
+ switch (fetch_type_) {
+ case MANIFEST_FETCH:
+ job_->HandleManifestFetchCompleted(this);
+ break;
+ case URL_FETCH:
+ job_->HandleUrlFetchCompleted(this);
+ break;
+ case MASTER_ENTRY_FETCH:
+ job_->HandleMasterEntryFetchCompleted(this);
+ break;
+ case MANIFEST_REFETCH:
+ job_->HandleManifestRefetchCompleted(this);
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ delete this;
+}
+
+bool AppCacheUpdateJob::URLFetcher::MaybeRetryRequest() {
+ if (retry_503_attempts_ >= kMax503Retries ||
+ !request_->response_headers()->HasHeaderValue("retry-after", "0")) {
+ return false;
+ }
+ ++retry_503_attempts_;
+ result_ = UPDATE_OK;
+ request_ = job_->service_->request_context()->CreateRequest(
+ url_, net::DEFAULT_PRIORITY, this, NULL);
+ Start();
+ return true;
+}
+
+AppCacheUpdateJob::AppCacheUpdateJob(AppCacheServiceImpl* service,
+ AppCacheGroup* group)
+ : service_(service),
+ manifest_url_(group->manifest_url()),
+ group_(group),
+ update_type_(UNKNOWN_TYPE),
+ internal_state_(FETCH_MANIFEST),
+ master_entries_completed_(0),
+ url_fetches_completed_(0),
+ manifest_fetcher_(NULL),
+ manifest_has_valid_mime_type_(false),
+ stored_state_(UNSTORED),
+ storage_(service->storage()) {
+ service_->AddObserver(this);
+}
+
+AppCacheUpdateJob::~AppCacheUpdateJob() {
+ if (service_)
+ service_->RemoveObserver(this);
+ if (internal_state_ != COMPLETED)
+ Cancel();
+
+ DCHECK(!manifest_fetcher_);
+ DCHECK(pending_url_fetches_.empty());
+ DCHECK(!inprogress_cache_.get());
+ DCHECK(pending_master_entries_.empty());
+ DCHECK(master_entry_fetches_.empty());
+
+ if (group_)
+ group_->SetUpdateAppCacheStatus(AppCacheGroup::IDLE);
+}
+
+void AppCacheUpdateJob::StartUpdate(AppCacheHost* host,
+ const GURL& new_master_resource) {
+ DCHECK(group_->update_job() == this);
+ DCHECK(!group_->is_obsolete());
+
+ bool is_new_pending_master_entry = false;
+ if (!new_master_resource.is_empty()) {
+ DCHECK(new_master_resource == host->pending_master_entry_url());
+ DCHECK(!new_master_resource.has_ref());
+ DCHECK(new_master_resource.GetOrigin() == manifest_url_.GetOrigin());
+
+ // Cannot add more to this update if already terminating.
+ if (IsTerminating()) {
+ group_->QueueUpdate(host, new_master_resource);
+ return;
+ }
+
+ std::pair<PendingMasters::iterator, bool> ret =
+ pending_master_entries_.insert(
+ PendingMasters::value_type(new_master_resource, PendingHosts()));
+ is_new_pending_master_entry = ret.second;
+ ret.first->second.push_back(host);
+ host->AddObserver(this);
+ }
+
+ // Notify host (if any) if already checking or downloading.
+ AppCacheGroup::UpdateAppCacheStatus update_status = group_->update_status();
+ if (update_status == AppCacheGroup::CHECKING ||
+ update_status == AppCacheGroup::DOWNLOADING) {
+ if (host) {
+ NotifySingleHost(host, APPCACHE_CHECKING_EVENT);
+ if (update_status == AppCacheGroup::DOWNLOADING)
+ NotifySingleHost(host, APPCACHE_DOWNLOADING_EVENT);
+
+ // Add to fetch list or an existing entry if already fetched.
+ if (!new_master_resource.is_empty()) {
+ AddMasterEntryToFetchList(host, new_master_resource,
+ is_new_pending_master_entry);
+ }
+ }
+ return;
+ }
+
+ // Begin update process for the group.
+ MadeProgress();
+ group_->SetUpdateAppCacheStatus(AppCacheGroup::CHECKING);
+ if (group_->HasCache()) {
+ update_type_ = UPGRADE_ATTEMPT;
+ NotifyAllAssociatedHosts(APPCACHE_CHECKING_EVENT);
+ } else {
+ update_type_ = CACHE_ATTEMPT;
+ DCHECK(host);
+ NotifySingleHost(host, APPCACHE_CHECKING_EVENT);
+ }
+
+ if (!new_master_resource.is_empty()) {
+ AddMasterEntryToFetchList(host, new_master_resource,
+ is_new_pending_master_entry);
+ }
+
+ FetchManifest(true);
+}
+
+AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() {
+ AppCacheResponseWriter* writer =
+ storage_->CreateResponseWriter(manifest_url_,
+ group_->group_id());
+ stored_response_ids_.push_back(writer->response_id());
+ return writer;
+}
+
+void AppCacheUpdateJob::HandleCacheFailure(
+ const AppCacheErrorDetails& error_details,
+ ResultType result,
+ const GURL& failed_resource_url) {
+ // 6.9.4 cache failure steps 2-8.
+ DCHECK(internal_state_ != CACHE_FAILURE);
+ DCHECK(!error_details.message.empty());
+ DCHECK(result != UPDATE_OK);
+ internal_state_ = CACHE_FAILURE;
+ LogHistogramStats(result, failed_resource_url);
+ CancelAllUrlFetches();
+ CancelAllMasterEntryFetches(error_details);
+ NotifyAllError(error_details);
+ DiscardInprogressCache();
+ internal_state_ = COMPLETED;
+ DeleteSoon(); // To unwind the stack prior to deletion.
+}
+
+void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) {
+ DCHECK(!manifest_fetcher_);
+ manifest_fetcher_ = new URLFetcher(
+ manifest_url_,
+ is_first_fetch ? URLFetcher::MANIFEST_FETCH :
+ URLFetcher::MANIFEST_REFETCH,
+ this);
+
+ // Add any necessary Http headers before sending fetch request.
+ if (is_first_fetch) {
+ AppCacheEntry* entry = (update_type_ == UPGRADE_ATTEMPT) ?
+ group_->newest_complete_cache()->GetEntry(manifest_url_) : NULL;
+ if (entry) {
+ // Asynchronously load response info for manifest from newest cache.
+ storage_->LoadResponseInfo(manifest_url_, group_->group_id(),
+ entry->response_id(), this);
+ } else {
+ manifest_fetcher_->Start();
+ }
+ } else {
+ DCHECK(internal_state_ == REFETCH_MANIFEST);
+ DCHECK(manifest_response_info_.get());
+ manifest_fetcher_->set_existing_response_headers(
+ manifest_response_info_->headers.get());
+ manifest_fetcher_->Start();
+ }
+}
+
+
+void AppCacheUpdateJob::HandleManifestFetchCompleted(
+ URLFetcher* fetcher) {
+ DCHECK_EQ(internal_state_, FETCH_MANIFEST);
+ DCHECK_EQ(manifest_fetcher_, fetcher);
+ manifest_fetcher_ = NULL;
+
+ net::URLRequest* request = fetcher->request();
+ int response_code = -1;
+ bool is_valid_response_code = false;
+ if (request->status().is_success()) {
+ response_code = request->GetResponseCode();
+ is_valid_response_code = (response_code / 100 == 2);
+
+ std::string mime_type;
+ request->GetMimeType(&mime_type);
+ manifest_has_valid_mime_type_ = (mime_type == "text/cache-manifest");
+ }
+
+ if (is_valid_response_code) {
+ manifest_data_ = fetcher->manifest_data();
+ manifest_response_info_.reset(
+ new net::HttpResponseInfo(request->response_info()));
+ if (update_type_ == UPGRADE_ATTEMPT)
+ CheckIfManifestChanged(); // continues asynchronously
+ else
+ ContinueHandleManifestFetchCompleted(true);
+ } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) {
+ ContinueHandleManifestFetchCompleted(false);
+ } else if ((response_code == 404 || response_code == 410) &&
+ update_type_ == UPGRADE_ATTEMPT) {
+ storage_->MakeGroupObsolete(group_, this, response_code); // async
+ } else {
+ const char* kFormatString = "Manifest fetch failed (%d) %s";
+ std::string message = FormatUrlErrorMessage(
+ kFormatString, manifest_url_, fetcher->result(), response_code);
+ HandleCacheFailure(AppCacheErrorDetails(message,
+ APPCACHE_MANIFEST_ERROR,
+ manifest_url_,
+ response_code,
+ false /*is_cross_origin*/),
+ fetcher->result(),
+ GURL());
+ }
+}
+
+void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group,
+ bool success,
+ int response_code) {
+ DCHECK(master_entry_fetches_.empty());
+ CancelAllMasterEntryFetches(AppCacheErrorDetails(
+ "The cache has been made obsolete, "
+ "the manifest file returned 404 or 410",
+ APPCACHE_MANIFEST_ERROR,
+ GURL(),
+ response_code,
+ false /*is_cross_origin*/));
+ if (success) {
+ DCHECK(group->is_obsolete());
+ NotifyAllAssociatedHosts(APPCACHE_OBSOLETE_EVENT);
+ internal_state_ = COMPLETED;
+ MaybeCompleteUpdate();
+ } else {
+ // Treat failure to mark group obsolete as a cache failure.
+ HandleCacheFailure(AppCacheErrorDetails(
+ "Failed to mark the cache as obsolete",
+ APPCACHE_UNKNOWN_ERROR,
+ GURL(),
+ 0,
+ false /*is_cross_origin*/),
+ DB_ERROR,
+ GURL());
+ }
+}
+
+void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) {
+ DCHECK(internal_state_ == FETCH_MANIFEST);
+
+ if (!changed) {
+ DCHECK(update_type_ == UPGRADE_ATTEMPT);
+ internal_state_ = NO_UPDATE;
+
+ // Wait for pending master entries to download.
+ FetchMasterEntries();
+ MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps
+ return;
+ }
+
+ AppCacheManifest manifest;
+ if (!ParseManifest(manifest_url_, manifest_data_.data(),
+ manifest_data_.length(),
+ manifest_has_valid_mime_type_ ?
+ PARSE_MANIFEST_ALLOWING_INTERCEPTS :
+ PARSE_MANIFEST_PER_STANDARD,
+ manifest)) {
+ const char* kFormatString = "Failed to parse manifest %s";
+ const std::string message = base::StringPrintf(kFormatString,
+ manifest_url_.spec().c_str());
+ HandleCacheFailure(
+ AppCacheErrorDetails(
+ message, APPCACHE_SIGNATURE_ERROR, GURL(), 0,
+ false /*is_cross_origin*/),
+ MANIFEST_ERROR,
+ GURL());
+ VLOG(1) << message;
+ return;
+ }
+
+ // Proceed with update process. Section 6.9.4 steps 8-20.
+ internal_state_ = DOWNLOADING;
+ inprogress_cache_ = new AppCache(storage_, storage_->NewCacheId());
+ BuildUrlFileList(manifest);
+ inprogress_cache_->InitializeWithManifest(&manifest);
+
+ // Associate all pending master hosts with the newly created cache.
+ for (PendingMasters::iterator it = pending_master_entries_.begin();
+ it != pending_master_entries_.end(); ++it) {
+ PendingHosts& hosts = it->second;
+ for (PendingHosts::iterator host_it = hosts.begin();
+ host_it != hosts.end(); ++host_it) {
+ (*host_it)
+ ->AssociateIncompleteCache(inprogress_cache_.get(), manifest_url_);
+ }
+ }
+
+ if (manifest.did_ignore_intercept_namespaces) {
+ // Must be done after associating all pending master hosts.
+ std::string message(
+ "Ignoring the INTERCEPT section of the application cache manifest "
+ "because the content type is not text/cache-manifest");
+ LogConsoleMessageToAll(message);
+ }
+
+ group_->SetUpdateAppCacheStatus(AppCacheGroup::DOWNLOADING);
+ NotifyAllAssociatedHosts(APPCACHE_DOWNLOADING_EVENT);
+ FetchUrls();
+ FetchMasterEntries();
+ MaybeCompleteUpdate(); // if not done, continues when async fetches complete
+}
+
+void AppCacheUpdateJob::HandleUrlFetchCompleted(URLFetcher* fetcher) {
+ DCHECK(internal_state_ == DOWNLOADING);
+
+ net::URLRequest* request = fetcher->request();
+ const GURL& url = request->original_url();
+ pending_url_fetches_.erase(url);
+ NotifyAllProgress(url);
+ ++url_fetches_completed_;
+
+ int response_code = request->status().is_success()
+ ? request->GetResponseCode()
+ : fetcher->redirect_response_code();
+
+ AppCacheEntry& entry = url_file_list_.find(url)->second;
+
+ if (response_code / 100 == 2) {
+ // Associate storage with the new entry.
+ DCHECK(fetcher->response_writer());
+ entry.set_response_id(fetcher->response_writer()->response_id());
+ entry.set_response_size(fetcher->response_writer()->amount_written());
+ if (!inprogress_cache_->AddOrModifyEntry(url, entry))
+ duplicate_response_ids_.push_back(entry.response_id());
+
+ // TODO(michaeln): Check for <html manifest=xxx>
+ // See http://code.google.com/p/chromium/issues/detail?id=97930
+ // if (entry.IsMaster() && !(entry.IsExplicit() || fallback || intercept))
+ // if (!manifestAttribute) skip it
+
+ // Foreign entries will be detected during cache selection.
+ // Note: 6.9.4, step 17.9 possible optimization: if resource is HTML or XML
+ // file whose root element is an html element with a manifest attribute
+ // whose value doesn't match the manifest url of the application cache
+ // being processed, mark the entry as being foreign.
+ } else {
+ VLOG(1) << "Request status: " << request->status().status()
+ << " error: " << request->status().error()
+ << " response code: " << response_code;
+ if (entry.IsExplicit() || entry.IsFallback() || entry.IsIntercept()) {
+ if (response_code == 304 && fetcher->existing_entry().has_response_id()) {
+ // Keep the existing response.
+ entry.set_response_id(fetcher->existing_entry().response_id());
+ entry.set_response_size(fetcher->existing_entry().response_size());
+ inprogress_cache_->AddOrModifyEntry(url, entry);
+ } else {
+ const char* kFormatString = "Resource fetch failed (%d) %s";
+ std::string message = FormatUrlErrorMessage(
+ kFormatString, url, fetcher->result(), response_code);
+ ResultType result = fetcher->result();
+ bool is_cross_origin = url.GetOrigin() != manifest_url_.GetOrigin();
+ switch (result) {
+ case DISKCACHE_ERROR:
+ HandleCacheFailure(
+ AppCacheErrorDetails(
+ message, APPCACHE_UNKNOWN_ERROR, GURL(), 0,
+ is_cross_origin),
+ result,
+ url);
+ break;
+ case NETWORK_ERROR:
+ HandleCacheFailure(
+ AppCacheErrorDetails(message, APPCACHE_RESOURCE_ERROR, url, 0,
+ is_cross_origin),
+ result,
+ url);
+ break;
+ default:
+ HandleCacheFailure(AppCacheErrorDetails(message,
+ APPCACHE_RESOURCE_ERROR,
+ url,
+ response_code,
+ is_cross_origin),
+ result,
+ url);
+ break;
+ }
+ return;
+ }
+ } else if (response_code == 404 || response_code == 410) {
+ // Entry is skipped. They are dropped from the cache.
+ } else if (update_type_ == UPGRADE_ATTEMPT &&
+ fetcher->existing_entry().has_response_id()) {
+ // Keep the existing response.
+ // TODO(michaeln): Not sure this is a good idea. This is spec compliant
+ // but the old resource may or may not be compatible with the new contents
+ // of the cache. Impossible to know one way or the other.
+ entry.set_response_id(fetcher->existing_entry().response_id());
+ entry.set_response_size(fetcher->existing_entry().response_size());
+ inprogress_cache_->AddOrModifyEntry(url, entry);
+ }
+ }
+
+ // Fetch another URL now that one request has completed.
+ DCHECK(internal_state_ != CACHE_FAILURE);
+ FetchUrls();
+ MaybeCompleteUpdate();
+}
+
+void AppCacheUpdateJob::HandleMasterEntryFetchCompleted(
+ URLFetcher* fetcher) {
+ DCHECK(internal_state_ == NO_UPDATE || internal_state_ == DOWNLOADING);
+
+ // TODO(jennb): Handle downloads completing during cache failure when update
+ // no longer fetches master entries directly. For now, we cancel all pending
+ // master entry fetches when entering cache failure state so this will never
+ // be called in CACHE_FAILURE state.
+
+ net::URLRequest* request = fetcher->request();
+ const GURL& url = request->original_url();
+ master_entry_fetches_.erase(url);
+ ++master_entries_completed_;
+
+ int response_code = request->status().is_success()
+ ? request->GetResponseCode() : -1;
+
+ PendingMasters::iterator found = pending_master_entries_.find(url);
+ DCHECK(found != pending_master_entries_.end());
+ PendingHosts& hosts = found->second;
+
+ // Section 6.9.4. No update case: step 7.3, else step 22.
+ if (response_code / 100 == 2) {
+ // Add fetched master entry to the appropriate cache.
+ AppCache* cache = inprogress_cache_.get() ? inprogress_cache_.get()
+ : group_->newest_complete_cache();
+ DCHECK(fetcher->response_writer());
+ AppCacheEntry master_entry(AppCacheEntry::MASTER,
+ fetcher->response_writer()->response_id(),
+ fetcher->response_writer()->amount_written());
+ if (cache->AddOrModifyEntry(url, master_entry))
+ added_master_entries_.push_back(url);
+ else
+ duplicate_response_ids_.push_back(master_entry.response_id());
+
+ // In no-update case, associate host with the newest cache.
+ if (!inprogress_cache_.get()) {
+ // TODO(michaeln): defer until the updated cache has been stored
+ DCHECK(cache == group_->newest_complete_cache());
+ for (PendingHosts::iterator host_it = hosts.begin();
+ host_it != hosts.end(); ++host_it) {
+ (*host_it)->AssociateCompleteCache(cache);
+ }
+ }
+ } else {
+ HostNotifier host_notifier;
+ for (PendingHosts::iterator host_it = hosts.begin();
+ host_it != hosts.end(); ++host_it) {
+ AppCacheHost* host = *host_it;
+ host_notifier.AddHost(host);
+
+ // In downloading case, disassociate host from inprogress cache.
+ if (inprogress_cache_.get())
+ host->AssociateNoCache(GURL());
+
+ host->RemoveObserver(this);
+ }
+ hosts.clear();
+
+ const char* kFormatString = "Manifest fetch failed (%d) %s";
+ std::string message = FormatUrlErrorMessage(
+ kFormatString, request->url(), fetcher->result(), response_code);
+ host_notifier.SendErrorNotifications(
+ AppCacheErrorDetails(message,
+ APPCACHE_MANIFEST_ERROR,
+ request->url(),
+ response_code,
+ false /*is_cross_origin*/));
+
+ // In downloading case, update result is different if all master entries
+ // failed vs. only some failing.
+ if (inprogress_cache_.get()) {
+ // Only count successful downloads to know if all master entries failed.
+ pending_master_entries_.erase(found);
+ --master_entries_completed_;
+
+ // Section 6.9.4, step 22.3.
+ if (update_type_ == CACHE_ATTEMPT && pending_master_entries_.empty()) {
+ HandleCacheFailure(AppCacheErrorDetails(message,
+ APPCACHE_MANIFEST_ERROR,
+ request->url(),
+ response_code,
+ false /*is_cross_origin*/),
+ fetcher->result(),
+ GURL());
+ return;
+ }
+ }
+ }
+
+ DCHECK(internal_state_ != CACHE_FAILURE);
+ FetchMasterEntries();
+ MaybeCompleteUpdate();
+}
+
+void AppCacheUpdateJob::HandleManifestRefetchCompleted(
+ URLFetcher* fetcher) {
+ DCHECK(internal_state_ == REFETCH_MANIFEST);
+ DCHECK(manifest_fetcher_ == fetcher);
+ manifest_fetcher_ = NULL;
+
+ net::URLRequest* request = fetcher->request();
+ int response_code = request->status().is_success()
+ ? request->GetResponseCode() : -1;
+ if (response_code == 304 || manifest_data_ == fetcher->manifest_data()) {
+ // Only need to store response in storage if manifest is not already
+ // an entry in the cache.
+ AppCacheEntry* entry = inprogress_cache_->GetEntry(manifest_url_);
+ if (entry) {
+ entry->add_types(AppCacheEntry::MANIFEST);
+ StoreGroupAndCache();
+ } else {
+ manifest_response_writer_.reset(CreateResponseWriter());
+ scoped_refptr<HttpResponseInfoIOBuffer> io_buffer(
+ new HttpResponseInfoIOBuffer(manifest_response_info_.release()));
+ manifest_response_writer_->WriteInfo(
+ io_buffer.get(),
+ base::Bind(&AppCacheUpdateJob::OnManifestInfoWriteComplete,
+ base::Unretained(this)));
+ }
+ } else {
+ VLOG(1) << "Request status: " << request->status().status()
+ << " error: " << request->status().error()
+ << " response code: " << response_code;
+ ScheduleUpdateRetry(kRerunDelayMs);
+ if (response_code == 200) {
+ HandleCacheFailure(AppCacheErrorDetails("Manifest changed during update",
+ APPCACHE_CHANGED_ERROR,
+ GURL(),
+ 0,
+ false /*is_cross_origin*/),
+ MANIFEST_ERROR,
+ GURL());
+ } else {
+ const char* kFormatString = "Manifest re-fetch failed (%d) %s";
+ std::string message = FormatUrlErrorMessage(
+ kFormatString, manifest_url_, fetcher->result(), response_code);
+ HandleCacheFailure(AppCacheErrorDetails(message,
+ APPCACHE_MANIFEST_ERROR,
+ GURL(),
+ response_code,
+ false /*is_cross_origin*/),
+ fetcher->result(),
+ GURL());
+ }
+ }
+}
+
+void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) {
+ if (result > 0) {
+ scoped_refptr<net::StringIOBuffer> io_buffer(
+ new net::StringIOBuffer(manifest_data_));
+ manifest_response_writer_->WriteData(
+ io_buffer.get(),
+ manifest_data_.length(),
+ base::Bind(&AppCacheUpdateJob::OnManifestDataWriteComplete,
+ base::Unretained(this)));
+ } else {
+ HandleCacheFailure(
+ AppCacheErrorDetails("Failed to write the manifest headers to storage",
+ APPCACHE_UNKNOWN_ERROR,
+ GURL(),
+ 0,
+ false /*is_cross_origin*/),
+ DISKCACHE_ERROR,
+ GURL());
+ }
+}
+
+void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) {
+ if (result > 0) {
+ AppCacheEntry entry(AppCacheEntry::MANIFEST,
+ manifest_response_writer_->response_id(),
+ manifest_response_writer_->amount_written());
+ if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry))
+ duplicate_response_ids_.push_back(entry.response_id());
+ StoreGroupAndCache();
+ } else {
+ HandleCacheFailure(
+ AppCacheErrorDetails("Failed to write the manifest data to storage",
+ APPCACHE_UNKNOWN_ERROR,
+ GURL(),
+ 0,
+ false /*is_cross_origin*/),
+ DISKCACHE_ERROR,
+ GURL());
+ }
+}
+
+void AppCacheUpdateJob::StoreGroupAndCache() {
+ DCHECK(stored_state_ == UNSTORED);
+ stored_state_ = STORING;
+ scoped_refptr<AppCache> newest_cache;
+ if (inprogress_cache_.get())
+ newest_cache.swap(inprogress_cache_);
+ else
+ newest_cache = group_->newest_complete_cache();
+ newest_cache->set_update_time(base::Time::Now());
+
+ // TODO(michaeln): dcheck is fishing for clues to crbug/95101
+ DCHECK_EQ(manifest_url_, group_->manifest_url());
+ storage_->StoreGroupAndNewestCache(group_, newest_cache.get(), this);
+}
+
+void AppCacheUpdateJob::OnGroupAndNewestCacheStored(AppCacheGroup* group,
+ AppCache* newest_cache,
+ bool success,
+ bool would_exceed_quota) {
+ DCHECK(stored_state_ == STORING);
+ if (success) {
+ stored_state_ = STORED;
+ MaybeCompleteUpdate(); // will definitely complete
+ } else {
+ stored_state_ = UNSTORED;
+
+ // Restore inprogress_cache_ to get the proper events delivered
+ // and the proper cleanup to occur.
+ if (newest_cache != group->newest_complete_cache())
+ inprogress_cache_ = newest_cache;
+
+ ResultType result = DB_ERROR;
+ AppCacheErrorReason reason = APPCACHE_UNKNOWN_ERROR;
+ std::string message("Failed to commit new cache to storage");
+ if (would_exceed_quota) {
+ message.append(", would exceed quota");
+ result = QUOTA_ERROR;
+ reason = APPCACHE_QUOTA_ERROR;
+ }
+ HandleCacheFailure(
+ AppCacheErrorDetails(message, reason, GURL(), 0,
+ false /*is_cross_origin*/),
+ result,
+ GURL());
+ }
+}
+
+void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host,
+ AppCacheEventID event_id) {
+ std::vector<int> ids(1, host->host_id());
+ host->frontend()->OnEventRaised(ids, event_id);
+}
+
+void AppCacheUpdateJob::NotifyAllAssociatedHosts(AppCacheEventID event_id) {
+ HostNotifier host_notifier;
+ AddAllAssociatedHostsToNotifier(&host_notifier);
+ host_notifier.SendNotifications(event_id);
+}
+
+void AppCacheUpdateJob::NotifyAllProgress(const GURL& url) {
+ HostNotifier host_notifier;
+ AddAllAssociatedHostsToNotifier(&host_notifier);
+ host_notifier.SendProgressNotifications(
+ url, url_file_list_.size(), url_fetches_completed_);
+}
+
+void AppCacheUpdateJob::NotifyAllFinalProgress() {
+ DCHECK(url_file_list_.size() == url_fetches_completed_);
+ NotifyAllProgress(GURL());
+}
+
+void AppCacheUpdateJob::NotifyAllError(const AppCacheErrorDetails& details) {
+ HostNotifier host_notifier;
+ AddAllAssociatedHostsToNotifier(&host_notifier);
+ host_notifier.SendErrorNotifications(details);
+}
+
+void AppCacheUpdateJob::LogConsoleMessageToAll(const std::string& message) {
+ HostNotifier host_notifier;
+ AddAllAssociatedHostsToNotifier(&host_notifier);
+ host_notifier.SendLogMessage(message);
+}
+
+void AppCacheUpdateJob::AddAllAssociatedHostsToNotifier(
+ HostNotifier* host_notifier) {
+ // Collect hosts so we only send one notification per frontend.
+ // A host can only be associated with a single cache so no need to worry
+ // about duplicate hosts being added to the notifier.
+ if (inprogress_cache_.get()) {
+ DCHECK(internal_state_ == DOWNLOADING || internal_state_ == CACHE_FAILURE);
+ host_notifier->AddHosts(inprogress_cache_->associated_hosts());
+ }
+
+ AppCacheGroup::Caches old_caches = group_->old_caches();
+ for (AppCacheGroup::Caches::const_iterator it = old_caches.begin();
+ it != old_caches.end(); ++it) {
+ host_notifier->AddHosts((*it)->associated_hosts());
+ }
+
+ AppCache* newest_cache = group_->newest_complete_cache();
+ if (newest_cache)
+ host_notifier->AddHosts(newest_cache->associated_hosts());
+}
+
+void AppCacheUpdateJob::OnDestructionImminent(AppCacheHost* host) {
+ // The host is about to be deleted; remove from our collection.
+ PendingMasters::iterator found =
+ pending_master_entries_.find(host->pending_master_entry_url());
+ DCHECK(found != pending_master_entries_.end());
+ PendingHosts& hosts = found->second;
+ PendingHosts::iterator it = std::find(hosts.begin(), hosts.end(), host);
+ DCHECK(it != hosts.end());
+ hosts.erase(it);
+}
+
+void AppCacheUpdateJob::OnServiceReinitialized(
+ AppCacheStorageReference* old_storage_ref) {
+ // We continue to use the disabled instance, but arrange for its
+ // deletion when its no longer needed.
+ if (old_storage_ref->storage() == storage_)
+ disabled_storage_reference_ = old_storage_ref;
+}
+
+void AppCacheUpdateJob::CheckIfManifestChanged() {
+ DCHECK(update_type_ == UPGRADE_ATTEMPT);
+ AppCacheEntry* entry = NULL;
+ if (group_->newest_complete_cache())
+ entry = group_->newest_complete_cache()->GetEntry(manifest_url_);
+ if (!entry) {
+ // TODO(michaeln): This is just a bandaid to avoid a crash.
+ // http://code.google.com/p/chromium/issues/detail?id=95101
+ if (service_->storage() == storage_) {
+ // Use a local variable because service_ is reset in HandleCacheFailure.
+ AppCacheServiceImpl* service = service_;
+ HandleCacheFailure(
+ AppCacheErrorDetails("Manifest entry not found in existing cache",
+ APPCACHE_UNKNOWN_ERROR,
+ GURL(),
+ 0,
+ false /*is_cross_origin*/),
+ DB_ERROR,
+ GURL());
+ AppCacheHistograms::AddMissingManifestEntrySample();
+ service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback());
+ }
+ return;
+ }
+
+ // Load manifest data from storage to compare against fetched manifest.
+ manifest_response_reader_.reset(
+ storage_->CreateResponseReader(manifest_url_,
+ group_->group_id(),
+ entry->response_id()));
+ read_manifest_buffer_ = new net::IOBuffer(kBufferSize);
+ manifest_response_reader_->ReadData(
+ read_manifest_buffer_.get(),
+ kBufferSize,
+ base::Bind(&AppCacheUpdateJob::OnManifestDataReadComplete,
+ base::Unretained(this))); // async read
+}
+
+void AppCacheUpdateJob::OnManifestDataReadComplete(int result) {
+ if (result > 0) {
+ loaded_manifest_data_.append(read_manifest_buffer_->data(), result);
+ manifest_response_reader_->ReadData(
+ read_manifest_buffer_.get(),
+ kBufferSize,
+ base::Bind(&AppCacheUpdateJob::OnManifestDataReadComplete,
+ base::Unretained(this))); // read more
+ } else {
+ read_manifest_buffer_ = NULL;
+ manifest_response_reader_.reset();
+ ContinueHandleManifestFetchCompleted(
+ result < 0 || manifest_data_ != loaded_manifest_data_);
+ }
+}
+
+void AppCacheUpdateJob::BuildUrlFileList(const AppCacheManifest& manifest) {
+ for (base::hash_set<std::string>::const_iterator it =
+ manifest.explicit_urls.begin();
+ it != manifest.explicit_urls.end(); ++it) {
+ AddUrlToFileList(GURL(*it), AppCacheEntry::EXPLICIT);
+ }
+
+ const std::vector<AppCacheNamespace>& intercepts =
+ manifest.intercept_namespaces;
+ for (std::vector<AppCacheNamespace>::const_iterator it = intercepts.begin();
+ it != intercepts.end(); ++it) {
+ int flags = AppCacheEntry::INTERCEPT;
+ if (it->is_executable)
+ flags |= AppCacheEntry::EXECUTABLE;
+ AddUrlToFileList(it->target_url, flags);
+ }
+
+ const std::vector<AppCacheNamespace>& fallbacks =
+ manifest.fallback_namespaces;
+ for (std::vector<AppCacheNamespace>::const_iterator it = fallbacks.begin();
+ it != fallbacks.end(); ++it) {
+ AddUrlToFileList(it->target_url, AppCacheEntry::FALLBACK);
+ }
+
+ // Add all master entries from newest complete cache.
+ if (update_type_ == UPGRADE_ATTEMPT) {
+ const AppCache::EntryMap& entries =
+ group_->newest_complete_cache()->entries();
+ for (AppCache::EntryMap::const_iterator it = entries.begin();
+ it != entries.end(); ++it) {
+ const AppCacheEntry& entry = it->second;
+ if (entry.IsMaster())
+ AddUrlToFileList(it->first, AppCacheEntry::MASTER);
+ }
+ }
+}
+
+void AppCacheUpdateJob::AddUrlToFileList(const GURL& url, int type) {
+ std::pair<AppCache::EntryMap::iterator, bool> ret = url_file_list_.insert(
+ AppCache::EntryMap::value_type(url, AppCacheEntry(type)));
+
+ if (ret.second)
+ urls_to_fetch_.push_back(UrlToFetch(url, false, NULL));
+ else
+ ret.first->second.add_types(type); // URL already exists. Merge types.
+}
+
+void AppCacheUpdateJob::FetchUrls() {
+ DCHECK(internal_state_ == DOWNLOADING);
+
+ // Fetch each URL in the list according to section 6.9.4 step 17.1-17.3.
+ // Fetch up to the concurrent limit. Other fetches will be triggered as each
+ // each fetch completes.
+ while (pending_url_fetches_.size() < kMaxConcurrentUrlFetches &&
+ !urls_to_fetch_.empty()) {
+ UrlToFetch url_to_fetch = urls_to_fetch_.front();
+ urls_to_fetch_.pop_front();
+
+ AppCache::EntryMap::iterator it = url_file_list_.find(url_to_fetch.url);
+ DCHECK(it != url_file_list_.end());
+ AppCacheEntry& entry = it->second;
+ if (ShouldSkipUrlFetch(entry)) {
+ NotifyAllProgress(url_to_fetch.url);
+ ++url_fetches_completed_;
+ } else if (AlreadyFetchedEntry(url_to_fetch.url, entry.types())) {
+ NotifyAllProgress(url_to_fetch.url);
+ ++url_fetches_completed_; // saved a URL request
+ } else if (!url_to_fetch.storage_checked &&
+ MaybeLoadFromNewestCache(url_to_fetch.url, entry)) {
+ // Continues asynchronously after data is loaded from newest cache.
+ } else {
+ URLFetcher* fetcher = new URLFetcher(
+ url_to_fetch.url, URLFetcher::URL_FETCH, this);
+ if (url_to_fetch.existing_response_info.get()) {
+ DCHECK(group_->newest_complete_cache());
+ AppCacheEntry* existing_entry =
+ group_->newest_complete_cache()->GetEntry(url_to_fetch.url);
+ DCHECK(existing_entry);
+ DCHECK(existing_entry->response_id() ==
+ url_to_fetch.existing_response_info->response_id());
+ fetcher->set_existing_response_headers(
+ url_to_fetch.existing_response_info->http_response_info()->headers
+ .get());
+ fetcher->set_existing_entry(*existing_entry);
+ }
+ fetcher->Start();
+ pending_url_fetches_.insert(
+ PendingUrlFetches::value_type(url_to_fetch.url, fetcher));
+ }
+ }
+}
+
+void AppCacheUpdateJob::CancelAllUrlFetches() {
+ // Cancel any pending URL requests.
+ for (PendingUrlFetches::iterator it = pending_url_fetches_.begin();
+ it != pending_url_fetches_.end(); ++it) {
+ delete it->second;
+ }
+
+ url_fetches_completed_ +=
+ pending_url_fetches_.size() + urls_to_fetch_.size();
+ pending_url_fetches_.clear();
+ urls_to_fetch_.clear();
+}
+
+bool AppCacheUpdateJob::ShouldSkipUrlFetch(const AppCacheEntry& entry) {
+ // 6.6.4 Step 17
+ // If the resource URL being processed was flagged as neither an
+ // "explicit entry" nor or a "fallback entry", then the user agent
+ // may skip this URL.
+ if (entry.IsExplicit() || entry.IsFallback() || entry.IsIntercept())
+ return false;
+
+ // TODO(jennb): decide if entry should be skipped to expire it from cache
+ return false;
+}
+
+bool AppCacheUpdateJob::AlreadyFetchedEntry(const GURL& url,
+ int entry_type) {
+ DCHECK(internal_state_ == DOWNLOADING || internal_state_ == NO_UPDATE);
+ AppCacheEntry* existing =
+ inprogress_cache_.get() ? inprogress_cache_->GetEntry(url)
+ : group_->newest_complete_cache()->GetEntry(url);
+ if (existing) {
+ existing->add_types(entry_type);
+ return true;
+ }
+ return false;
+}
+
+void AppCacheUpdateJob::AddMasterEntryToFetchList(AppCacheHost* host,
+ const GURL& url,
+ bool is_new) {
+ DCHECK(!IsTerminating());
+
+ if (internal_state_ == DOWNLOADING || internal_state_ == NO_UPDATE) {
+ AppCache* cache;
+ if (inprogress_cache_.get()) {
+ // always associate
+ host->AssociateIncompleteCache(inprogress_cache_.get(), manifest_url_);
+ cache = inprogress_cache_.get();
+ } else {
+ cache = group_->newest_complete_cache();
+ }
+
+ // Update existing entry if it has already been fetched.
+ AppCacheEntry* entry = cache->GetEntry(url);
+ if (entry) {
+ entry->add_types(AppCacheEntry::MASTER);
+ if (internal_state_ == NO_UPDATE && !inprogress_cache_.get()) {
+ // only associate if have entry
+ host->AssociateCompleteCache(cache);
+ }
+ if (is_new)
+ ++master_entries_completed_; // pretend fetching completed
+ return;
+ }
+ }
+
+ // Add to fetch list if not already fetching.
+ if (master_entry_fetches_.find(url) == master_entry_fetches_.end()) {
+ master_entries_to_fetch_.insert(url);
+ if (internal_state_ == DOWNLOADING || internal_state_ == NO_UPDATE)
+ FetchMasterEntries();
+ }
+}
+
+void AppCacheUpdateJob::FetchMasterEntries() {
+ DCHECK(internal_state_ == NO_UPDATE || internal_state_ == DOWNLOADING);
+
+ // Fetch each master entry in the list, up to the concurrent limit.
+ // Additional fetches will be triggered as each fetch completes.
+ while (master_entry_fetches_.size() < kMaxConcurrentUrlFetches &&
+ !master_entries_to_fetch_.empty()) {
+ const GURL& url = *master_entries_to_fetch_.begin();
+
+ if (AlreadyFetchedEntry(url, AppCacheEntry::MASTER)) {
+ ++master_entries_completed_; // saved a URL request
+
+ // In no update case, associate hosts to newest cache in group
+ // now that master entry has been "successfully downloaded".
+ if (internal_state_ == NO_UPDATE) {
+ // TODO(michaeln): defer until the updated cache has been stored.
+ DCHECK(!inprogress_cache_.get());
+ AppCache* cache = group_->newest_complete_cache();
+ PendingMasters::iterator found = pending_master_entries_.find(url);
+ DCHECK(found != pending_master_entries_.end());
+ PendingHosts& hosts = found->second;
+ for (PendingHosts::iterator host_it = hosts.begin();
+ host_it != hosts.end(); ++host_it) {
+ (*host_it)->AssociateCompleteCache(cache);
+ }
+ }
+ } else {
+ URLFetcher* fetcher = new URLFetcher(
+ url, URLFetcher::MASTER_ENTRY_FETCH, this);
+ fetcher->Start();
+ master_entry_fetches_.insert(PendingUrlFetches::value_type(url, fetcher));
+ }
+
+ master_entries_to_fetch_.erase(master_entries_to_fetch_.begin());
+ }
+}
+
+void AppCacheUpdateJob::CancelAllMasterEntryFetches(
+ const AppCacheErrorDetails& error_details) {
+ // For now, cancel all in-progress fetches for master entries and pretend
+ // all master entries fetches have completed.
+ // TODO(jennb): Delete this when update no longer fetches master entries
+ // directly.
+
+ // Cancel all in-progress fetches.
+ for (PendingUrlFetches::iterator it = master_entry_fetches_.begin();
+ it != master_entry_fetches_.end(); ++it) {
+ delete it->second;
+ master_entries_to_fetch_.insert(it->first); // back in unfetched list
+ }
+ master_entry_fetches_.clear();
+
+ master_entries_completed_ += master_entries_to_fetch_.size();
+
+ // Cache failure steps, step 2.
+ // Pretend all master entries that have not yet been fetched have completed
+ // downloading. Unassociate hosts from any appcache and send ERROR event.
+ HostNotifier host_notifier;
+ while (!master_entries_to_fetch_.empty()) {
+ const GURL& url = *master_entries_to_fetch_.begin();
+ PendingMasters::iterator found = pending_master_entries_.find(url);
+ DCHECK(found != pending_master_entries_.end());
+ PendingHosts& hosts = found->second;
+ for (PendingHosts::iterator host_it = hosts.begin();
+ host_it != hosts.end(); ++host_it) {
+ AppCacheHost* host = *host_it;
+ host->AssociateNoCache(GURL());
+ host_notifier.AddHost(host);
+ host->RemoveObserver(this);
+ }
+ hosts.clear();
+
+ master_entries_to_fetch_.erase(master_entries_to_fetch_.begin());
+ }
+ host_notifier.SendErrorNotifications(error_details);
+}
+
+bool AppCacheUpdateJob::MaybeLoadFromNewestCache(const GURL& url,
+ AppCacheEntry& entry) {
+ if (update_type_ != UPGRADE_ATTEMPT)
+ return false;
+
+ AppCache* newest = group_->newest_complete_cache();
+ AppCacheEntry* copy_me = newest->GetEntry(url);
+ if (!copy_me || !copy_me->has_response_id())
+ return false;
+
+ // Load HTTP headers for entry from newest cache.
+ loading_responses_.insert(
+ LoadingResponses::value_type(copy_me->response_id(), url));
+ storage_->LoadResponseInfo(manifest_url_, group_->group_id(),
+ copy_me->response_id(),
+ this);
+ // Async: wait for OnResponseInfoLoaded to complete.
+ return true;
+}
+
+void AppCacheUpdateJob::OnResponseInfoLoaded(
+ AppCacheResponseInfo* response_info, int64 response_id) {
+ const net::HttpResponseInfo* http_info = response_info ?
+ response_info->http_response_info() : NULL;
+
+ // Needed response info for a manifest fetch request.
+ if (internal_state_ == FETCH_MANIFEST) {
+ if (http_info)
+ manifest_fetcher_->set_existing_response_headers(
+ http_info->headers.get());
+ manifest_fetcher_->Start();
+ return;
+ }
+
+ LoadingResponses::iterator found = loading_responses_.find(response_id);
+ DCHECK(found != loading_responses_.end());
+ const GURL& url = found->second;
+
+ if (!http_info) {
+ LoadFromNewestCacheFailed(url, NULL); // no response found
+ } else {
+ // Check if response can be re-used according to HTTP caching semantics.
+ // Responses with a "vary" header get treated as expired.
+ const std::string name = "vary";
+ std::string value;
+ void* iter = NULL;
+ if (!http_info->headers.get() ||
+ http_info->headers->RequiresValidation(http_info->request_time,
+ http_info->response_time,
+ base::Time::Now()) ||
+ http_info->headers->EnumerateHeader(&iter, name, &value)) {
+ LoadFromNewestCacheFailed(url, response_info);
+ } else {
+ DCHECK(group_->newest_complete_cache());
+ AppCacheEntry* copy_me = group_->newest_complete_cache()->GetEntry(url);
+ DCHECK(copy_me);
+ DCHECK(copy_me->response_id() == response_id);
+
+ AppCache::EntryMap::iterator it = url_file_list_.find(url);
+ DCHECK(it != url_file_list_.end());
+ AppCacheEntry& entry = it->second;
+ entry.set_response_id(response_id);
+ entry.set_response_size(copy_me->response_size());
+ inprogress_cache_->AddOrModifyEntry(url, entry);
+ NotifyAllProgress(url);
+ ++url_fetches_completed_;
+ }
+ }
+ loading_responses_.erase(found);
+
+ MaybeCompleteUpdate();
+}
+
+void AppCacheUpdateJob::LoadFromNewestCacheFailed(
+ const GURL& url, AppCacheResponseInfo* response_info) {
+ if (internal_state_ == CACHE_FAILURE)
+ return;
+
+ // Re-insert url at front of fetch list. Indicate storage has been checked.
+ urls_to_fetch_.push_front(UrlToFetch(url, true, response_info));
+ FetchUrls();
+}
+
+void AppCacheUpdateJob::MaybeCompleteUpdate() {
+ DCHECK(internal_state_ != CACHE_FAILURE);
+
+ // Must wait for any pending master entries or url fetches to complete.
+ if (master_entries_completed_ != pending_master_entries_.size() ||
+ url_fetches_completed_ != url_file_list_.size()) {
+ DCHECK(internal_state_ != COMPLETED);
+ return;
+ }
+
+ switch (internal_state_) {
+ case NO_UPDATE:
+ if (master_entries_completed_ > 0) {
+ switch (stored_state_) {
+ case UNSTORED:
+ StoreGroupAndCache();
+ return;
+ case STORING:
+ return;
+ case STORED:
+ break;
+ }
+ }
+ // 6.9.4 steps 7.3-7.7.
+ NotifyAllAssociatedHosts(APPCACHE_NO_UPDATE_EVENT);
+ DiscardDuplicateResponses();
+ internal_state_ = COMPLETED;
+ break;
+ case DOWNLOADING:
+ internal_state_ = REFETCH_MANIFEST;
+ FetchManifest(false);
+ break;
+ case REFETCH_MANIFEST:
+ DCHECK(stored_state_ == STORED);
+ NotifyAllFinalProgress();
+ if (update_type_ == CACHE_ATTEMPT)
+ NotifyAllAssociatedHosts(APPCACHE_CACHED_EVENT);
+ else
+ NotifyAllAssociatedHosts(APPCACHE_UPDATE_READY_EVENT);
+ DiscardDuplicateResponses();
+ internal_state_ = COMPLETED;
+ LogHistogramStats(UPDATE_OK, GURL());
+ break;
+ case CACHE_FAILURE:
+ NOTREACHED(); // See HandleCacheFailure
+ break;
+ default:
+ break;
+ }
+
+ // Let the stack unwind before deletion to make it less risky as this
+ // method is called from multiple places in this file.
+ if (internal_state_ == COMPLETED)
+ DeleteSoon();
+}
+
+void AppCacheUpdateJob::ScheduleUpdateRetry(int delay_ms) {
+ // TODO(jennb): post a delayed task with the "same parameters" as this job
+ // to retry the update at a later time. Need group, URLs of pending master
+ // entries and their hosts.
+}
+
+void AppCacheUpdateJob::Cancel() {
+ internal_state_ = CANCELLED;
+
+ LogHistogramStats(CANCELLED_ERROR, GURL());
+
+ if (manifest_fetcher_) {
+ delete manifest_fetcher_;
+ manifest_fetcher_ = NULL;
+ }
+
+ for (PendingUrlFetches::iterator it = pending_url_fetches_.begin();
+ it != pending_url_fetches_.end(); ++it) {
+ delete it->second;
+ }
+ pending_url_fetches_.clear();
+
+ for (PendingUrlFetches::iterator it = master_entry_fetches_.begin();
+ it != master_entry_fetches_.end(); ++it) {
+ delete it->second;
+ }
+ master_entry_fetches_.clear();
+
+ ClearPendingMasterEntries();
+ DiscardInprogressCache();
+
+ // Delete response writer to avoid any callbacks.
+ if (manifest_response_writer_)
+ manifest_response_writer_.reset();
+
+ storage_->CancelDelegateCallbacks(this);
+}
+
+void AppCacheUpdateJob::ClearPendingMasterEntries() {
+ for (PendingMasters::iterator it = pending_master_entries_.begin();
+ it != pending_master_entries_.end(); ++it) {
+ PendingHosts& hosts = it->second;
+ for (PendingHosts::iterator host_it = hosts.begin();
+ host_it != hosts.end(); ++host_it) {
+ (*host_it)->RemoveObserver(this);
+ }
+ }
+
+ pending_master_entries_.clear();
+}
+
+void AppCacheUpdateJob::DiscardInprogressCache() {
+ if (stored_state_ == STORING) {
+ // We can make no assumptions about whether the StoreGroupAndCacheTask
+ // actually completed or not. This condition should only be reachable
+ // during shutdown. Free things up and return to do no harm.
+ inprogress_cache_ = NULL;
+ added_master_entries_.clear();
+ return;
+ }
+
+ storage_->DoomResponses(manifest_url_, stored_response_ids_);
+
+ if (!inprogress_cache_.get()) {
+ // We have to undo the changes we made, if any, to the existing cache.
+ if (group_ && group_->newest_complete_cache()) {
+ for (std::vector<GURL>::iterator iter = added_master_entries_.begin();
+ iter != added_master_entries_.end(); ++iter) {
+ group_->newest_complete_cache()->RemoveEntry(*iter);
+ }
+ }
+ added_master_entries_.clear();
+ return;
+ }
+
+ AppCache::AppCacheHosts& hosts = inprogress_cache_->associated_hosts();
+ while (!hosts.empty())
+ (*hosts.begin())->AssociateNoCache(GURL());
+
+ inprogress_cache_ = NULL;
+ added_master_entries_.clear();
+}
+
+void AppCacheUpdateJob::DiscardDuplicateResponses() {
+ storage_->DoomResponses(manifest_url_, duplicate_response_ids_);
+}
+
+void AppCacheUpdateJob::LogHistogramStats(
+ ResultType result, const GURL& failed_resource_url) {
+ AppCacheHistograms::CountUpdateJobResult(result, manifest_url_.GetOrigin());
+ if (result == UPDATE_OK)
+ return;
+
+ int percent_complete = 0;
+ if (url_file_list_.size() > 0) {
+ size_t actual_fetches_completed = url_fetches_completed_;
+ if (!failed_resource_url.is_empty() && actual_fetches_completed)
+ --actual_fetches_completed;
+ percent_complete = (static_cast<double>(actual_fetches_completed) /
+ static_cast<double>(url_file_list_.size())) * 100.0;
+ percent_complete = std::min(percent_complete, 99);
+ }
+
+ bool was_making_progress =
+ base::Time::Now() - last_progress_time_ <
+ base::TimeDelta::FromMinutes(5);
+
+ bool off_origin_resource_failure =
+ !failed_resource_url.is_empty() &&
+ (failed_resource_url.GetOrigin() != manifest_url_.GetOrigin());
+
+ AppCacheHistograms::LogUpdateFailureStats(
+ manifest_url_.GetOrigin(),
+ percent_complete,
+ was_making_progress,
+ off_origin_resource_failure);
+}
+
+void AppCacheUpdateJob::DeleteSoon() {
+ ClearPendingMasterEntries();
+ manifest_response_writer_.reset();
+ storage_->CancelDelegateCallbacks(this);
+ service_->RemoveObserver(this);
+ service_ = NULL;
+
+ // Break the connection with the group so the group cannot call delete
+ // on this object after we've posted a task to delete ourselves.
+ group_->SetUpdateAppCacheStatus(AppCacheGroup::IDLE);
+ group_ = NULL;
+
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_update_job.h b/chromium/content/browser/appcache/appcache_update_job.h
new file mode 100644
index 00000000000..4d2d896ea74
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_update_job.h
@@ -0,0 +1,346 @@
+// 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_APPCACHE_APPCACHE_UPDATE_JOB_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_
+
+#include <deque>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "content/browser/appcache/appcache_storage.h"
+#include "content/common/appcache_interfaces.h"
+#include "content/common/content_export.h"
+#include "net/base/completion_callback.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request.h"
+#include "url/gurl.h"
+
+namespace content {
+FORWARD_DECLARE_TEST(AppCacheGroupTest, QueueUpdate);
+class AppCacheGroupTest;
+class AppCacheUpdateJobTest;
+class HostNotifier;
+
+// Application cache Update algorithm and state.
+class CONTENT_EXPORT AppCacheUpdateJob
+ : public AppCacheStorage::Delegate,
+ public AppCacheHost::Observer,
+ public AppCacheServiceImpl::Observer {
+ public:
+ // Used for uma stats only for now, so new values are append only.
+ enum ResultType {
+ UPDATE_OK, DB_ERROR, DISKCACHE_ERROR, QUOTA_ERROR, REDIRECT_ERROR,
+ MANIFEST_ERROR, NETWORK_ERROR, SERVER_ERROR, CANCELLED_ERROR,
+ SECURITY_ERROR, NUM_UPDATE_JOB_RESULT_TYPES
+ };
+
+ AppCacheUpdateJob(AppCacheServiceImpl* service, AppCacheGroup* group);
+ ~AppCacheUpdateJob() override;
+
+ // Triggers the update process or adds more info if this update is already
+ // in progress.
+ void StartUpdate(AppCacheHost* host, const GURL& new_master_resource);
+
+ private:
+ friend class content::AppCacheGroupTest;
+ friend class content::AppCacheUpdateJobTest;
+ class URLFetcher;
+
+ // Master entries have multiple hosts, for example, the same page is opened
+ // in different tabs.
+ typedef std::vector<AppCacheHost*> PendingHosts;
+ typedef std::map<GURL, PendingHosts> PendingMasters;
+ typedef std::map<GURL, URLFetcher*> PendingUrlFetches;
+ typedef std::map<int64, GURL> LoadingResponses;
+
+ static const int kRerunDelayMs = 1000;
+
+ // TODO(michaeln): Rework the set of states vs update types vs stored states.
+ // The NO_UPDATE state is really more of an update type. For all update types
+ // storing the results is relevant.
+
+ enum UpdateType {
+ UNKNOWN_TYPE,
+ UPGRADE_ATTEMPT,
+ CACHE_ATTEMPT,
+ };
+
+ enum InternalUpdateState {
+ FETCH_MANIFEST,
+ NO_UPDATE,
+ DOWNLOADING,
+
+ // Every state after this comment indicates the update is terminating.
+ REFETCH_MANIFEST,
+ CACHE_FAILURE,
+ CANCELLED,
+ COMPLETED,
+ };
+
+ enum StoredState {
+ UNSTORED,
+ STORING,
+ STORED,
+ };
+
+ struct UrlToFetch {
+ UrlToFetch(const GURL& url, bool checked, AppCacheResponseInfo* info);
+ ~UrlToFetch();
+
+ GURL url;
+ bool storage_checked;
+ scoped_refptr<AppCacheResponseInfo> existing_response_info;
+ };
+
+ class URLFetcher : public net::URLRequest::Delegate {
+ public:
+ enum FetchType {
+ MANIFEST_FETCH,
+ URL_FETCH,
+ MASTER_ENTRY_FETCH,
+ MANIFEST_REFETCH,
+ };
+ URLFetcher(const GURL& url,
+ FetchType fetch_type,
+ AppCacheUpdateJob* job);
+ ~URLFetcher() override;
+ void Start();
+ FetchType fetch_type() const { return fetch_type_; }
+ net::URLRequest* request() const { return request_.get(); }
+ const AppCacheEntry& existing_entry() const { return existing_entry_; }
+ const std::string& manifest_data() const { return manifest_data_; }
+ AppCacheResponseWriter* response_writer() const {
+ return response_writer_.get();
+ }
+ void set_existing_response_headers(net::HttpResponseHeaders* headers) {
+ existing_response_headers_ = headers;
+ }
+ void set_existing_entry(const AppCacheEntry& entry) {
+ existing_entry_ = entry;
+ }
+ ResultType result() const { return result_; }
+ int redirect_response_code() const { return redirect_response_code_; }
+
+ private:
+ // URLRequest::Delegate overrides
+ void OnReceivedRedirect(net::URLRequest* request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) override;
+ void OnResponseStarted(net::URLRequest* request) override;
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
+
+ void AddConditionalHeaders(const net::HttpResponseHeaders* headers);
+ void OnWriteComplete(int result);
+ void ReadResponseData();
+ bool ConsumeResponseData(int bytes_read);
+ void OnResponseCompleted();
+ bool MaybeRetryRequest();
+
+ GURL url_;
+ AppCacheUpdateJob* job_;
+ FetchType fetch_type_;
+ int retry_503_attempts_;
+ scoped_refptr<net::IOBuffer> buffer_;
+ scoped_ptr<net::URLRequest> request_;
+ AppCacheEntry existing_entry_;
+ scoped_refptr<net::HttpResponseHeaders> existing_response_headers_;
+ std::string manifest_data_;
+ ResultType result_;
+ int redirect_response_code_;
+ scoped_ptr<AppCacheResponseWriter> response_writer_;
+ }; // class URLFetcher
+
+ AppCacheResponseWriter* CreateResponseWriter();
+
+ // Methods for AppCacheStorage::Delegate.
+ void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
+ int64 response_id) override;
+ void OnGroupAndNewestCacheStored(AppCacheGroup* group,
+ AppCache* newest_cache,
+ bool success,
+ bool would_exceed_quota) override;
+ void OnGroupMadeObsolete(AppCacheGroup* group,
+ bool success,
+ int response_code) override;
+
+ // Methods for AppCacheHost::Observer.
+ void OnCacheSelectionComplete(AppCacheHost* host) override {} // N/A
+ void OnDestructionImminent(AppCacheHost* host) override;
+
+ // Methods for AppCacheServiceImpl::Observer.
+ void OnServiceReinitialized(AppCacheStorageReference* old_storage) override;
+
+ void HandleCacheFailure(const AppCacheErrorDetails& details,
+ ResultType result,
+ const GURL& failed_resource_url);
+
+ void FetchManifest(bool is_first_fetch);
+ void HandleManifestFetchCompleted(URLFetcher* fetcher);
+ void ContinueHandleManifestFetchCompleted(bool changed);
+
+ void HandleUrlFetchCompleted(URLFetcher* fetcher);
+ void HandleMasterEntryFetchCompleted(URLFetcher* fetcher);
+
+ void HandleManifestRefetchCompleted(URLFetcher* fetcher);
+ void OnManifestInfoWriteComplete(int result);
+ void OnManifestDataWriteComplete(int result);
+
+ void StoreGroupAndCache();
+
+ void NotifySingleHost(AppCacheHost* host, AppCacheEventID event_id);
+ void NotifyAllAssociatedHosts(AppCacheEventID event_id);
+ void NotifyAllProgress(const GURL& url);
+ void NotifyAllFinalProgress();
+ void NotifyAllError(const AppCacheErrorDetails& detals);
+ void LogConsoleMessageToAll(const std::string& message);
+ void AddAllAssociatedHostsToNotifier(HostNotifier* notifier);
+
+ // Checks if manifest is byte for byte identical with the manifest
+ // in the newest application cache.
+ void CheckIfManifestChanged();
+ void OnManifestDataReadComplete(int result);
+
+ // Creates the list of files that may need to be fetched and initiates
+ // fetches. Section 6.9.4 steps 12-17
+ void BuildUrlFileList(const AppCacheManifest& manifest);
+ void AddUrlToFileList(const GURL& url, int type);
+ void FetchUrls();
+ void CancelAllUrlFetches();
+ bool ShouldSkipUrlFetch(const AppCacheEntry& entry);
+
+ // If entry already exists in the cache currently being updated, merge
+ // the entry type information with the existing entry.
+ // Returns true if entry exists in cache currently being updated.
+ bool AlreadyFetchedEntry(const GURL& url, int entry_type);
+
+ // TODO(jennb): Delete when update no longer fetches master entries directly.
+ // Creates the list of master entries that need to be fetched and initiates
+ // fetches.
+ void AddMasterEntryToFetchList(AppCacheHost* host, const GURL& url,
+ bool is_new);
+ void FetchMasterEntries();
+ void CancelAllMasterEntryFetches(const AppCacheErrorDetails& details);
+
+ // Asynchronously loads the entry from the newest complete cache if the
+ // HTTP caching semantics allow.
+ // Returns false if immediately obvious that data cannot be loaded from
+ // newest complete cache.
+ bool MaybeLoadFromNewestCache(const GURL& url, AppCacheEntry& entry);
+ void LoadFromNewestCacheFailed(const GURL& url,
+ AppCacheResponseInfo* newest_response_info);
+
+ // Does nothing if update process is still waiting for pending master
+ // entries or URL fetches to complete downloading. Otherwise, completes
+ // the update process.
+ void MaybeCompleteUpdate();
+
+ // Schedules a rerun of the entire update with the same parameters as
+ // this update job after a short delay.
+ void ScheduleUpdateRetry(int delay_ms);
+
+ void Cancel();
+ void ClearPendingMasterEntries();
+ void DiscardInprogressCache();
+ void DiscardDuplicateResponses();
+
+ void LogHistogramStats(ResultType result, const GURL& failed_resource_url);
+ void MadeProgress() { last_progress_time_ = base::Time::Now(); }
+
+ // Deletes this object after letting the stack unwind.
+ void DeleteSoon();
+
+ bool IsTerminating() { return internal_state_ >= REFETCH_MANIFEST ||
+ stored_state_ != UNSTORED; }
+
+ AppCacheServiceImpl* service_;
+ const GURL manifest_url_; // here for easier access
+
+ // Defined prior to refs to AppCaches and Groups because destruction
+ // order matters, the disabled_storage_reference_ must outlive those
+ // objects.
+ scoped_refptr<AppCacheStorageReference> disabled_storage_reference_;
+
+ scoped_refptr<AppCache> inprogress_cache_;
+
+ AppCacheGroup* group_;
+
+ UpdateType update_type_;
+ InternalUpdateState internal_state_;
+ base::Time last_progress_time_;
+
+ PendingMasters pending_master_entries_;
+ size_t master_entries_completed_;
+
+ // TODO(jennb): Delete when update no longer fetches master entries directly.
+ // Helper containers to track which pending master entries have yet to be
+ // fetched and which are currently being fetched. Master entries that
+ // are listed in the manifest may be fetched as a regular URL instead of
+ // as a separate master entry fetch to optimize against duplicate fetches.
+ std::set<GURL> master_entries_to_fetch_;
+ PendingUrlFetches master_entry_fetches_;
+
+ // URLs of files to fetch along with their flags.
+ AppCache::EntryMap url_file_list_;
+ size_t url_fetches_completed_;
+
+ // Helper container to track which urls have not been fetched yet. URLs are
+ // removed when the fetch is initiated. Flag indicates whether an attempt
+ // to load the URL from storage has already been tried and failed.
+ std::deque<UrlToFetch> urls_to_fetch_;
+
+ // Helper container to track which urls are being loaded from response
+ // storage.
+ LoadingResponses loading_responses_;
+
+ // Keep track of pending URL requests so we can cancel them if necessary.
+ URLFetcher* manifest_fetcher_;
+ PendingUrlFetches pending_url_fetches_;
+
+ // Temporary storage of manifest response data for parsing and comparison.
+ std::string manifest_data_;
+ scoped_ptr<net::HttpResponseInfo> manifest_response_info_;
+ scoped_ptr<AppCacheResponseWriter> manifest_response_writer_;
+ scoped_refptr<net::IOBuffer> read_manifest_buffer_;
+ std::string loaded_manifest_data_;
+ scoped_ptr<AppCacheResponseReader> manifest_response_reader_;
+ bool manifest_has_valid_mime_type_;
+
+ // New master entries added to the cache by this job, used to cleanup
+ // in error conditions.
+ std::vector<GURL> added_master_entries_;
+
+ // Response ids stored by this update job, used to cleanup in
+ // error conditions.
+ std::vector<int64> stored_response_ids_;
+
+ // In some cases we fetch the same resource multiple times, and then
+ // have to delete the duplicates upon successful update. These ids
+ // are also in the stored_response_ids_ collection so we only schedule
+ // these for deletion on success.
+ // TODO(michaeln): Rework when we no longer fetches master entries directly.
+ std::vector<int64> duplicate_response_ids_;
+
+ // Whether we've stored the resulting group/cache yet.
+ StoredState stored_state_;
+
+ AppCacheStorage* storage_;
+
+ FRIEND_TEST_ALL_PREFIXES(content::AppCacheGroupTest, QueueUpdate);
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheUpdateJob);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_UPDATE_JOB_H_
diff --git a/chromium/content/browser/appcache/appcache_update_job_unittest.cc b/chromium/content/browser/appcache/appcache_update_job_unittest.cc
index bc3957e6bea..4955a71d780 100644
--- a/chromium/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_update_job_unittest.cc
@@ -7,6 +7,10 @@
#include "base/stl_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_update_job.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
@@ -15,35 +19,6 @@
#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"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_host.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_update_job.h"
-
-using appcache::AppCache;
-using appcache::AppCacheEntry;
-using appcache::AppCacheFrontend;
-using appcache::AppCacheHost;
-using appcache::AppCacheGroup;
-using appcache::AppCacheResponseInfo;
-using appcache::AppCacheUpdateJob;
-using appcache::AppCacheResponseWriter;
-using appcache::APPCACHE_CACHED_EVENT;
-using appcache::APPCACHE_CHECKING_EVENT;
-using appcache::APPCACHE_DOWNLOADING_EVENT;
-using appcache::APPCACHE_ERROR_EVENT;
-using appcache::AppCacheEventID;
-using appcache::APPCACHE_FALLBACK_NAMESPACE;
-using appcache::HttpResponseInfoIOBuffer;
-using appcache::kAppCacheNoCacheId;
-using appcache::kAppCacheNoResponseId;
-using appcache::Namespace;
-using appcache::APPCACHE_NETWORK_NAMESPACE;
-using appcache::APPCACHE_NO_UPDATE_EVENT;
-using appcache::APPCACHE_OBSOLETE_EVENT;
-using appcache::APPCACHE_PROGRESS_EVENT;
-using appcache::APPCACHE_UPDATE_READY_EVENT;
-using appcache::AppCacheStatus;
namespace content {
class AppCacheUpdateJobTest;
@@ -220,14 +195,15 @@ class MockHttpServer {
class MockHttpServerJobFactory
: public net::URLRequestJobFactory::ProtocolHandler {
public:
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
return MockHttpServer::JobFactory(request, network_delegate);
}
};
-inline bool operator==(const Namespace& lhs, const Namespace& rhs) {
+inline bool operator==(const AppCacheNamespace& lhs,
+ const AppCacheNamespace& rhs) {
return lhs.type == rhs.type &&
lhs.namespace_url == rhs.namespace_url &&
lhs.target_url == rhs.target_url;
@@ -243,16 +219,13 @@ class MockFrontend : public AppCacheFrontend {
start_update_trigger_(APPCACHE_CHECKING_EVENT), update_(NULL) {
}
- virtual void OnCacheSelected(
- int host_id, const appcache::AppCacheInfo& info) OVERRIDE {
- }
+ void OnCacheSelected(int host_id, const AppCacheInfo& info) override {}
- virtual void OnStatusChanged(const std::vector<int>& host_ids,
- AppCacheStatus status) OVERRIDE {
- }
+ void OnStatusChanged(const std::vector<int>& host_ids,
+ AppCacheStatus status) override {}
- virtual void OnEventRaised(const std::vector<int>& host_ids,
- AppCacheEventID event_id) OVERRIDE {
+ void OnEventRaised(const std::vector<int>& host_ids,
+ AppCacheEventID event_id) override {
raised_events_.push_back(RaisedEvent(host_ids, event_id));
// Trigger additional updates if requested.
@@ -267,17 +240,16 @@ class MockFrontend : public AppCacheFrontend {
}
}
- virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
- const appcache::AppCacheErrorDetails& details)
- OVERRIDE {
+ void OnErrorEventRaised(const std::vector<int>& host_ids,
+ const AppCacheErrorDetails& details) override {
error_message_ = details.message;
OnEventRaised(host_ids, APPCACHE_ERROR_EVENT);
}
- virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
- const GURL& url,
- int num_total,
- int num_complete) OVERRIDE {
+ void OnProgressEventRaised(const std::vector<int>& host_ids,
+ const GURL& url,
+ int num_total,
+ int num_complete) override {
if (!ignore_progress_events_)
OnEventRaised(host_ids, APPCACHE_PROGRESS_EVENT);
@@ -305,14 +277,11 @@ class MockFrontend : public AppCacheFrontend {
}
}
- virtual void OnLogMessage(int host_id,
- appcache::AppCacheLogLevel log_level,
- const std::string& message) OVERRIDE {
- }
+ void OnLogMessage(int host_id,
+ AppCacheLogLevel log_level,
+ const std::string& message) override {}
- virtual void OnContentBlocked(int host_id,
- const GURL& manifest_url) OVERRIDE {
- }
+ void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
void AddExpectedEvent(const std::vector<int>& host_ids,
AppCacheEventID event_id) {
@@ -369,9 +338,9 @@ class MockFrontend : public AppCacheFrontend {
// Helper factories to simulate redirected URL responses for tests.
class RedirectFactory : public net::URLRequestJobFactory::ProtocolHandler {
public:
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
return new net::URLRequestTestJob(
request,
network_delegate,
@@ -423,10 +392,10 @@ class RetryRequestTestJob : public net::URLRequestTestJob {
}
}
- virtual int GetResponseCode() const OVERRIDE { return response_code_; }
+ int GetResponseCode() const override { return response_code_; }
private:
- virtual ~RetryRequestTestJob() {}
+ ~RetryRequestTestJob() override {}
static std::string retry_headers() {
const char no_retry_after[] =
@@ -485,9 +454,9 @@ class RetryRequestTestJob : public net::URLRequestTestJob {
class RetryRequestTestJobFactory
: public net::URLRequestJobFactory::ProtocolHandler {
public:
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
return RetryRequestTestJob::RetryFactory(request, network_delegate);
}
};
@@ -545,7 +514,7 @@ class HttpHeadersRequestTestJob : public net::URLRequestTestJob {
}
protected:
- virtual ~HttpHeadersRequestTestJob() {}
+ ~HttpHeadersRequestTestJob() override {}
private:
static std::string expect_if_modified_since_;
@@ -565,9 +534,9 @@ bool HttpHeadersRequestTestJob::already_checked_ = false;
class IfModifiedSinceJobFactory
: public net::URLRequestJobFactory::ProtocolHandler {
public:
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
return HttpHeadersRequestTestJob::IfModifiedSinceFactory(
request, network_delegate);
}
@@ -579,9 +548,7 @@ class IOThread : public base::Thread {
: base::Thread(name) {
}
- virtual ~IOThread() {
- Stop();
- }
+ ~IOThread() override { Stop(); }
net::URLRequestContext* request_context() {
return request_context_.get();
@@ -593,7 +560,7 @@ class IOThread : public base::Thread {
request_context_->set_job_factory(job_factory_.get());
}
- virtual void Init() OVERRIDE {
+ void Init() override {
scoped_ptr<net::URLRequestJobFactoryImpl> factory(
new net::URLRequestJobFactoryImpl());
factory->SetProtocolHandler("http", new MockHttpServerJobFactory);
@@ -603,7 +570,7 @@ class IOThread : public base::Thread {
request_context_->set_job_factory(job_factory_.get());
}
- virtual void CleanUp() OVERRIDE {
+ void CleanUp() override {
request_context_.reset();
job_factory_.reset();
}
@@ -3041,8 +3008,8 @@ class AppCacheUpdateJobTest : public testing::Test,
group_->AddUpdateObserver(this);
}
- virtual void OnUpdateComplete(AppCacheGroup* group) OVERRIDE {
- ASSERT_EQ(group_, group);
+ void OnUpdateComplete(AppCacheGroup* group) override {
+ ASSERT_EQ(group_.get(), group);
protect_newest_cache_ = group->newest_complete_cache();
UpdateFinished();
}
@@ -3216,7 +3183,7 @@ class AppCacheUpdateJobTest : public testing::Test,
if (tested_manifest_) {
AppCache* cache = group_->newest_complete_cache();
ASSERT_TRUE(cache != NULL);
- EXPECT_EQ(group_, cache->owning_group());
+ EXPECT_EQ(group_.get(), cache->owning_group());
EXPECT_TRUE(cache->is_complete());
switch (tested_manifest_) {
@@ -3273,7 +3240,7 @@ class AppCacheUpdateJobTest : public testing::Test,
expected = 1;
ASSERT_EQ(expected, cache->fallback_namespaces_.size());
EXPECT_TRUE(cache->fallback_namespaces_[0] ==
- Namespace(
+ AppCacheNamespace(
APPCACHE_FALLBACK_NAMESPACE,
MockHttpServer::GetMockUrl("files/fallback1"),
MockHttpServer::GetMockUrl("files/fallback1a"),
@@ -3301,7 +3268,7 @@ class AppCacheUpdateJobTest : public testing::Test,
expected = 1;
ASSERT_EQ(expected, cache->fallback_namespaces_.size());
EXPECT_TRUE(cache->fallback_namespaces_[0] ==
- Namespace(
+ AppCacheNamespace(
APPCACHE_FALLBACK_NAMESPACE,
MockHttpServer::GetMockUrl("files/fallback1"),
MockHttpServer::GetMockUrl("files/explicit1"),
@@ -3309,7 +3276,7 @@ class AppCacheUpdateJobTest : public testing::Test,
EXPECT_EQ(expected, cache->online_whitelist_namespaces_.size());
EXPECT_TRUE(cache->online_whitelist_namespaces_[0] ==
- Namespace(
+ AppCacheNamespace(
APPCACHE_NETWORK_NAMESPACE,
MockHttpServer::GetMockUrl("files/online1"),
GURL(), false));
@@ -3498,7 +3465,7 @@ TEST_F(AppCacheUpdateJobTest, AlreadyDownloading) {
EXPECT_EQ(expected, events[1].first.size());
EXPECT_EQ(host.host_id(), events[1].first[0]);
- EXPECT_EQ(appcache::APPCACHE_DOWNLOADING_EVENT, events[1].second);
+ EXPECT_EQ(APPCACHE_DOWNLOADING_EVENT, events[1].second);
EXPECT_EQ(AppCacheGroup::DOWNLOADING, group->update_status());
}
diff --git a/chromium/content/browser/appcache/appcache_url_request_job.cc b/chromium/content/browser/appcache/appcache_url_request_job.cc
new file mode 100644
index 00000000000..b12a5b6db5f
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_url_request_job.cc
@@ -0,0 +1,449 @@
+// 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/appcache/appcache_url_request_job.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_histograms.h"
+#include "content/browser/appcache/appcache_host.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_status.h"
+
+namespace content {
+
+AppCacheURLRequestJob::AppCacheURLRequestJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ AppCacheStorage* storage,
+ AppCacheHost* host,
+ bool is_main_resource)
+ : net::URLRequestJob(request, network_delegate),
+ host_(host),
+ storage_(storage),
+ has_been_started_(false), has_been_killed_(false),
+ delivery_type_(AWAITING_DELIVERY_ORDERS),
+ group_id_(0), cache_id_(kAppCacheNoCacheId), is_fallback_(false),
+ is_main_resource_(is_main_resource),
+ cache_entry_not_found_(false),
+ weak_factory_(this) {
+ DCHECK(storage_);
+}
+
+void AppCacheURLRequestJob::DeliverAppCachedResponse(
+ const GURL& manifest_url, int64 group_id, int64 cache_id,
+ const AppCacheEntry& entry, bool is_fallback) {
+ DCHECK(!has_delivery_orders());
+ DCHECK(entry.has_response_id());
+ delivery_type_ = APPCACHED_DELIVERY;
+ manifest_url_ = manifest_url;
+ group_id_ = group_id;
+ cache_id_ = cache_id;
+ entry_ = entry;
+ is_fallback_ = is_fallback;
+ MaybeBeginDelivery();
+}
+
+void AppCacheURLRequestJob::DeliverNetworkResponse() {
+ DCHECK(!has_delivery_orders());
+ delivery_type_ = NETWORK_DELIVERY;
+ storage_ = NULL; // not needed
+ MaybeBeginDelivery();
+}
+
+void AppCacheURLRequestJob::DeliverErrorResponse() {
+ DCHECK(!has_delivery_orders());
+ delivery_type_ = ERROR_DELIVERY;
+ storage_ = NULL; // not needed
+ MaybeBeginDelivery();
+}
+
+void AppCacheURLRequestJob::MaybeBeginDelivery() {
+ if (has_been_started() && has_delivery_orders()) {
+ // Start asynchronously so that all error reporting and data
+ // callbacks happen as they would for network requests.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&AppCacheURLRequestJob::BeginDelivery,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void AppCacheURLRequestJob::BeginDelivery() {
+ DCHECK(has_delivery_orders() && has_been_started());
+
+ if (has_been_killed())
+ return;
+
+ switch (delivery_type_) {
+ case NETWORK_DELIVERY:
+ AppCacheHistograms::AddNetworkJobStartDelaySample(
+ base::TimeTicks::Now() - start_time_tick_);
+ // To fallthru to the network, we restart the request which will
+ // cause a new job to be created to retrieve the resource from the
+ // network. Our caller is responsible for arranging to not re-intercept
+ // the same request.
+ NotifyRestartRequired();
+ break;
+
+ case ERROR_DELIVERY:
+ AppCacheHistograms::AddErrorJobStartDelaySample(
+ base::TimeTicks::Now() - start_time_tick_);
+ request()->net_log().AddEvent(
+ net::NetLog::TYPE_APPCACHE_DELIVERING_ERROR_RESPONSE);
+ NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_FAILED));
+ break;
+
+ case APPCACHED_DELIVERY:
+ if (entry_.IsExecutable()) {
+ BeginExecutableHandlerDelivery();
+ return;
+ }
+ AppCacheHistograms::AddAppCacheJobStartDelaySample(
+ base::TimeTicks::Now() - start_time_tick_);
+ request()->net_log().AddEvent(
+ is_fallback_ ?
+ net::NetLog::TYPE_APPCACHE_DELIVERING_FALLBACK_RESPONSE :
+ net::NetLog::TYPE_APPCACHE_DELIVERING_CACHED_RESPONSE);
+ storage_->LoadResponseInfo(
+ manifest_url_, group_id_, entry_.response_id(), this);
+ break;
+
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void AppCacheURLRequestJob::BeginExecutableHandlerDelivery() {
+ DCHECK(CommandLine::ForCurrentProcess()->
+ HasSwitch(kEnableExecutableHandlers));
+ if (!storage_->service()->handler_factory()) {
+ BeginErrorDelivery("missing handler factory");
+ return;
+ }
+
+ request()->net_log().AddEvent(
+ net::NetLog::TYPE_APPCACHE_DELIVERING_EXECUTABLE_RESPONSE);
+
+ // We defer job delivery until the executable handler is spun up and
+ // provides a response. The sequence goes like this...
+ //
+ // 1. First we load the cache.
+ // 2. Then if the handler is not spun up, we load the script resource which
+ // is needed to spin it up.
+ // 3. Then we ask then we ask the handler to compute a response.
+ // 4. Finally we deilver that response to the caller.
+ storage_->LoadCache(cache_id_, this);
+}
+
+void AppCacheURLRequestJob::OnCacheLoaded(AppCache* cache, int64 cache_id) {
+ DCHECK_EQ(cache_id_, cache_id);
+ DCHECK(!has_been_killed());
+
+ if (!cache) {
+ BeginErrorDelivery("cache load failed");
+ return;
+ }
+
+ // Keep references to ensure they don't go out of scope until job completion.
+ cache_ = cache;
+ group_ = cache->owning_group();
+
+ // If the handler is spun up, ask it to compute a response.
+ AppCacheExecutableHandler* handler =
+ cache->GetExecutableHandler(entry_.response_id());
+ if (handler) {
+ InvokeExecutableHandler(handler);
+ return;
+ }
+
+ // Handler is not spun up yet, load the script resource to do that.
+ // NOTE: This is not ideal since multiple jobs may be doing this,
+ // concurrently but close enough for now, the first to load the script
+ // will win.
+
+ // Read the script data, truncating if its too large.
+ // NOTE: we just issue one read and don't bother chaining if the resource
+ // is very (very) large, close enough for now.
+ const int64 kLimit = 500 * 1000;
+ handler_source_buffer_ = new net::GrowableIOBuffer();
+ handler_source_buffer_->SetCapacity(kLimit);
+ handler_source_reader_.reset(storage_->CreateResponseReader(
+ manifest_url_, group_id_, entry_.response_id()));
+ handler_source_reader_->ReadData(
+ handler_source_buffer_.get(),
+ kLimit,
+ base::Bind(&AppCacheURLRequestJob::OnExecutableSourceLoaded,
+ base::Unretained(this)));
+}
+
+void AppCacheURLRequestJob::OnExecutableSourceLoaded(int result) {
+ DCHECK(!has_been_killed());
+ handler_source_reader_.reset();
+ if (result < 0) {
+ BeginErrorDelivery("script source load failed");
+ return;
+ }
+
+ handler_source_buffer_->SetCapacity(result); // Free up some memory.
+
+ AppCacheExecutableHandler* handler = cache_->GetOrCreateExecutableHandler(
+ entry_.response_id(), handler_source_buffer_.get());
+ handler_source_buffer_ = NULL; // not needed anymore
+ if (handler) {
+ InvokeExecutableHandler(handler);
+ return;
+ }
+
+ BeginErrorDelivery("factory failed to produce a handler");
+}
+
+void AppCacheURLRequestJob::InvokeExecutableHandler(
+ AppCacheExecutableHandler* handler) {
+ handler->HandleRequest(
+ request(),
+ base::Bind(&AppCacheURLRequestJob::OnExecutableResponseCallback,
+ weak_factory_.GetWeakPtr()));
+}
+
+void AppCacheURLRequestJob::OnExecutableResponseCallback(
+ const AppCacheExecutableHandler::Response& response) {
+ DCHECK(!has_been_killed());
+ if (response.use_network) {
+ delivery_type_ = NETWORK_DELIVERY;
+ storage_ = NULL;
+ BeginDelivery();
+ return;
+ }
+
+ if (!response.cached_resource_url.is_empty()) {
+ AppCacheEntry* entry_ptr = cache_->GetEntry(response.cached_resource_url);
+ if (entry_ptr && !entry_ptr->IsExecutable()) {
+ entry_ = *entry_ptr;
+ BeginDelivery();
+ return;
+ }
+ }
+
+ if (!response.redirect_url.is_empty()) {
+ // TODO(michaeln): playback a redirect
+ // response_headers_(new HttpResponseHeaders(response_headers)),
+ // fallthru for now to deliver an error
+ }
+
+ // Otherwise, return an error.
+ BeginErrorDelivery("handler returned an invalid response");
+}
+
+void AppCacheURLRequestJob::BeginErrorDelivery(const char* message) {
+ if (host_)
+ host_->frontend()->OnLogMessage(host_->host_id(), APPCACHE_LOG_ERROR,
+ message);
+ delivery_type_ = ERROR_DELIVERY;
+ storage_ = NULL;
+ BeginDelivery();
+}
+
+AppCacheURLRequestJob::~AppCacheURLRequestJob() {
+ if (storage_)
+ storage_->CancelDelegateCallbacks(this);
+}
+
+void AppCacheURLRequestJob::OnResponseInfoLoaded(
+ AppCacheResponseInfo* response_info, int64 response_id) {
+ DCHECK(is_delivering_appcache_response());
+ scoped_refptr<AppCacheURLRequestJob> protect(this);
+ if (response_info) {
+ info_ = response_info;
+ reader_.reset(storage_->CreateResponseReader(
+ manifest_url_, group_id_, entry_.response_id()));
+
+ if (is_range_request())
+ SetupRangeResponse();
+
+ NotifyHeadersComplete();
+ } else {
+ if (storage_->service()->storage() == storage_) {
+ // A resource that is expected to be in the appcache is missing.
+ // See http://code.google.com/p/chromium/issues/detail?id=50657
+ // Instead of failing the request, we restart the request. The retry
+ // attempt will fallthru to the network instead of trying to load
+ // from the appcache.
+ storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
+ entry_.response_id());
+ AppCacheHistograms::CountResponseRetrieval(
+ false, is_main_resource_, manifest_url_.GetOrigin());
+ }
+ cache_entry_not_found_ = true;
+ NotifyRestartRequired();
+ }
+}
+
+const net::HttpResponseInfo* AppCacheURLRequestJob::http_info() const {
+ if (!info_.get())
+ return NULL;
+ if (range_response_info_)
+ return range_response_info_.get();
+ return info_->http_response_info();
+}
+
+void AppCacheURLRequestJob::SetupRangeResponse() {
+ DCHECK(is_range_request() && info_.get() && reader_.get() &&
+ is_delivering_appcache_response());
+ int resource_size = static_cast<int>(info_->response_data_size());
+ if (resource_size < 0 || !range_requested_.ComputeBounds(resource_size)) {
+ range_requested_ = net::HttpByteRange();
+ return;
+ }
+
+ DCHECK(range_requested_.IsValid());
+ int offset = static_cast<int>(range_requested_.first_byte_position());
+ int length = static_cast<int>(range_requested_.last_byte_position() -
+ range_requested_.first_byte_position() + 1);
+
+ // Tell the reader about the range to read.
+ reader_->SetReadRange(offset, length);
+
+ // Make a copy of the full response headers and fix them up
+ // for the range we'll be returning.
+ range_response_info_.reset(
+ new net::HttpResponseInfo(*info_->http_response_info()));
+ net::HttpResponseHeaders* headers = range_response_info_->headers.get();
+ headers->UpdateWithNewRange(
+ range_requested_, resource_size, true /* replace status line */);
+}
+
+void AppCacheURLRequestJob::OnReadComplete(int result) {
+ DCHECK(is_delivering_appcache_response());
+ if (result == 0) {
+ NotifyDone(net::URLRequestStatus());
+ AppCacheHistograms::CountResponseRetrieval(
+ true, is_main_resource_, manifest_url_.GetOrigin());
+ } else if (result < 0) {
+ if (storage_->service()->storage() == storage_) {
+ storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
+ entry_.response_id());
+ }
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
+ AppCacheHistograms::CountResponseRetrieval(
+ false, is_main_resource_, manifest_url_.GetOrigin());
+ } else {
+ SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
+ }
+ NotifyReadComplete(result);
+}
+
+// net::URLRequestJob overrides ------------------------------------------------
+
+void AppCacheURLRequestJob::Start() {
+ DCHECK(!has_been_started());
+ has_been_started_ = true;
+ start_time_tick_ = base::TimeTicks::Now();
+ MaybeBeginDelivery();
+}
+
+void AppCacheURLRequestJob::Kill() {
+ if (!has_been_killed_) {
+ has_been_killed_ = true;
+ reader_.reset();
+ handler_source_reader_.reset();
+ if (storage_) {
+ storage_->CancelDelegateCallbacks(this);
+ storage_ = NULL;
+ }
+ host_ = NULL;
+ info_ = NULL;
+ cache_ = NULL;
+ group_ = NULL;
+ range_response_info_.reset();
+ net::URLRequestJob::Kill();
+ weak_factory_.InvalidateWeakPtrs();
+ }
+}
+
+net::LoadState AppCacheURLRequestJob::GetLoadState() const {
+ if (!has_been_started())
+ return net::LOAD_STATE_IDLE;
+ if (!has_delivery_orders())
+ return net::LOAD_STATE_WAITING_FOR_APPCACHE;
+ if (delivery_type_ != APPCACHED_DELIVERY)
+ return net::LOAD_STATE_IDLE;
+ if (!info_.get())
+ return net::LOAD_STATE_WAITING_FOR_APPCACHE;
+ if (reader_.get() && reader_->IsReadPending())
+ return net::LOAD_STATE_READING_RESPONSE;
+ return net::LOAD_STATE_IDLE;
+}
+
+bool AppCacheURLRequestJob::GetMimeType(std::string* mime_type) const {
+ if (!http_info())
+ return false;
+ return http_info()->headers->GetMimeType(mime_type);
+}
+
+bool AppCacheURLRequestJob::GetCharset(std::string* charset) {
+ if (!http_info())
+ return false;
+ return http_info()->headers->GetCharset(charset);
+}
+
+void AppCacheURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
+ if (!http_info())
+ return;
+ *info = *http_info();
+}
+
+int AppCacheURLRequestJob::GetResponseCode() const {
+ if (!http_info())
+ return -1;
+ return http_info()->headers->response_code();
+}
+
+bool AppCacheURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size,
+ int *bytes_read) {
+ DCHECK(is_delivering_appcache_response());
+ DCHECK_NE(buf_size, 0);
+ DCHECK(bytes_read);
+ DCHECK(!reader_->IsReadPending());
+ reader_->ReadData(
+ buf, buf_size, base::Bind(&AppCacheURLRequestJob::OnReadComplete,
+ base::Unretained(this)));
+ SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+ return false;
+}
+
+void AppCacheURLRequestJob::SetExtraRequestHeaders(
+ const net::HttpRequestHeaders& headers) {
+ std::string value;
+ std::vector<net::HttpByteRange> ranges;
+ if (!headers.GetHeader(net::HttpRequestHeaders::kRange, &value) ||
+ !net::HttpUtil::ParseRangeHeader(value, &ranges)) {
+ return;
+ }
+
+ // If multiple ranges are requested, we play dumb and
+ // return the entire response with 200 OK.
+ if (ranges.size() == 1U)
+ range_requested_ = ranges[0];
+}
+
+} // namespace content
diff --git a/chromium/content/browser/appcache/appcache_url_request_job.h b/chromium/content/browser/appcache/appcache_url_request_job.h
new file mode 100644
index 00000000000..580b86a58a2
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_url_request_job.h
@@ -0,0 +1,175 @@
+// 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_APPCACHE_APPCACHE_URL_REQUEST_JOB_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_URL_REQUEST_JOB_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "content/browser/appcache/appcache_entry.h"
+#include "content/browser/appcache/appcache_executable_handler.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_storage.h"
+#include "content/common/content_export.h"
+#include "net/http/http_byte_range.h"
+#include "net/url_request/url_request_job.h"
+
+namespace net {
+class GrowableIOBuffer;
+};
+
+namespace content {
+class AppCacheHost;
+class AppCacheRequestHandlerTest;
+class AppCacheURLRequestJobTest;
+
+// A net::URLRequestJob derivative that knows how to return a response stored
+// in the appcache.
+class CONTENT_EXPORT AppCacheURLRequestJob
+ : public net::URLRequestJob,
+ public AppCacheStorage::Delegate {
+ public:
+ AppCacheURLRequestJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ AppCacheStorage* storage,
+ AppCacheHost* host,
+ bool is_main_resource);
+
+ // Informs the job of what response it should deliver. Only one of these
+ // methods should be called, and only once per job. A job will sit idle and
+ // wait indefinitely until one of the deliver methods is called.
+ void DeliverAppCachedResponse(const GURL& manifest_url, int64 group_id,
+ int64 cache_id, const AppCacheEntry& entry,
+ bool is_fallback);
+ void DeliverNetworkResponse();
+ void DeliverErrorResponse();
+
+ bool is_waiting() const {
+ return delivery_type_ == AWAITING_DELIVERY_ORDERS;
+ }
+
+ bool is_delivering_appcache_response() const {
+ return delivery_type_ == APPCACHED_DELIVERY;
+ }
+
+ bool is_delivering_network_response() const {
+ return delivery_type_ == NETWORK_DELIVERY;
+ }
+
+ bool is_delivering_error_response() const {
+ return delivery_type_ == ERROR_DELIVERY;
+ }
+
+ // Accessors for the info about the appcached response, if any,
+ // that this job has been instructed to deliver. These are only
+ // valid to call if is_delivering_appcache_response.
+ const GURL& manifest_url() const { return manifest_url_; }
+ int64 group_id() const { return group_id_; }
+ int64 cache_id() const { return cache_id_; }
+ const AppCacheEntry& entry() const { return entry_; }
+
+ // net::URLRequestJob's Kill method is made public so the users of this
+ // class in the appcache namespace can call it.
+ void Kill() override;
+
+ // Returns true if the job has been started by the net library.
+ bool has_been_started() const {
+ return has_been_started_;
+ }
+
+ // Returns true if the job has been killed.
+ bool has_been_killed() const {
+ return has_been_killed_;
+ }
+
+ // Returns true if the cache entry was not found in the disk cache.
+ bool cache_entry_not_found() const {
+ return cache_entry_not_found_;
+ }
+
+ protected:
+ ~AppCacheURLRequestJob() override;
+
+ private:
+ friend class content::AppCacheRequestHandlerTest;
+ friend class content::AppCacheURLRequestJobTest;
+
+ enum DeliveryType {
+ AWAITING_DELIVERY_ORDERS,
+ APPCACHED_DELIVERY,
+ NETWORK_DELIVERY,
+ ERROR_DELIVERY
+ };
+
+ // Returns true if one of the Deliver methods has been called.
+ bool has_delivery_orders() const {
+ return !is_waiting();
+ }
+
+ void MaybeBeginDelivery();
+ void BeginDelivery();
+
+ // For executable response handling.
+ void BeginExecutableHandlerDelivery();
+ void OnExecutableSourceLoaded(int result);
+ void InvokeExecutableHandler(AppCacheExecutableHandler* handler);
+ void OnExecutableResponseCallback(
+ const AppCacheExecutableHandler::Response& response);
+ void BeginErrorDelivery(const char* message);
+
+ // AppCacheStorage::Delegate methods
+ void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
+ int64 response_id) override;
+ void OnCacheLoaded(AppCache* cache, int64 cache_id) override;
+
+ const net::HttpResponseInfo* http_info() const;
+ bool is_range_request() const { return range_requested_.IsValid(); }
+ void SetupRangeResponse();
+
+ // AppCacheResponseReader completion callback
+ void OnReadComplete(int result);
+
+ // net::URLRequestJob methods, see url_request_job.h for doc comments
+ void Start() override;
+ net::LoadState GetLoadState() const override;
+ bool GetCharset(std::string* charset) override;
+ void GetResponseInfo(net::HttpResponseInfo* info) override;
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+
+ // Sets extra request headers for Job types that support request headers.
+ // This is how we get informed of range-requests.
+ void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
+
+ // FilterContext methods
+ bool GetMimeType(std::string* mime_type) const override;
+ int GetResponseCode() const override;
+
+ AppCacheHost* host_;
+ AppCacheStorage* storage_;
+ base::TimeTicks start_time_tick_;
+ bool has_been_started_;
+ bool has_been_killed_;
+ DeliveryType delivery_type_;
+ GURL manifest_url_;
+ int64 group_id_;
+ int64 cache_id_;
+ AppCacheEntry entry_;
+ bool is_fallback_;
+ bool is_main_resource_; // Used for histogram logging.
+ bool cache_entry_not_found_;
+ scoped_refptr<AppCacheResponseInfo> info_;
+ scoped_refptr<net::GrowableIOBuffer> handler_source_buffer_;
+ scoped_ptr<AppCacheResponseReader> handler_source_reader_;
+ net::HttpByteRange range_requested_;
+ scoped_ptr<net::HttpResponseInfo> range_response_info_;
+ scoped_ptr<AppCacheResponseReader> reader_;
+ scoped_refptr<AppCache> cache_;
+ scoped_refptr<AppCacheGroup> group_;
+ base::WeakPtrFactory<AppCacheURLRequestJob> weak_factory_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_REQUEST_HANDLER_H_
diff --git a/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc b/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc
index edaa07e8e38..8acc71c7c9c 100644
--- a/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc
+++ b/chromium/content/browser/appcache/appcache_url_request_job_unittest.cc
@@ -9,9 +9,13 @@
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/pickle.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_url_request_job.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -22,17 +26,8 @@
#include "net/url_request/url_request_error_job.h"
#include "net/url_request/url_request_job_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_url_request_job.h"
-
-using appcache::AppCacheEntry;
-using appcache::AppCacheStorage;
-using appcache::AppCacheResponseInfo;
-using appcache::AppCacheResponseReader;
-using appcache::AppCacheResponseWriter;
-using appcache::AppCacheURLRequestJob;
-using appcache::HttpResponseInfoIOBuffer;
-using appcache::kAppCacheNoCacheId;
+#include "url/gurl.h"
+
using net::IOBuffer;
using net::WrappedIOBuffer;
@@ -51,9 +46,7 @@ class MockURLRequestJobFactory : public net::URLRequestJobFactory {
MockURLRequestJobFactory() : job_(NULL) {
}
- virtual ~MockURLRequestJobFactory() {
- DCHECK(!job_);
- }
+ ~MockURLRequestJobFactory() override { DCHECK(!job_); }
void SetJob(net::URLRequestJob* job) {
job_ = job;
@@ -64,10 +57,10 @@ class MockURLRequestJobFactory : public net::URLRequestJobFactory {
}
// net::URLRequestJobFactory implementation.
- virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+ net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
if (job_) {
net::URLRequestJob* temp = job_;
job_ = NULL;
@@ -79,20 +72,33 @@ class MockURLRequestJobFactory : public net::URLRequestJobFactory {
}
}
- virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
+ net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const override {
+ return nullptr;
+ }
+
+ net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return nullptr;
+ }
+
+ bool IsHandledProtocol(const std::string& scheme) const override {
return scheme == "http";
};
- virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
+ bool IsHandledURL(const GURL& url) const override {
return url.SchemeIs("http");
}
- virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
+ bool IsSafeRedirectTarget(const GURL& location) const override {
return false;
}
- private:
- mutable net::URLRequestJob* job_;
+ private:
+ mutable net::URLRequestJob* job_;
};
class AppCacheURLRequestJobTest : public testing::Test {
@@ -107,8 +113,8 @@ class AppCacheURLRequestJobTest : public testing::Test {
: loaded_info_id_(0), test_(test) {
}
- virtual void OnResponseInfoLoaded(AppCacheResponseInfo* info,
- int64 response_id) OVERRIDE {
+ void OnResponseInfoLoaded(AppCacheResponseInfo* info,
+ int64 response_id) override {
loaded_info_ = info;
loaded_info_id_ = response_id;
test_->ScheduleNextTask();
@@ -128,7 +134,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
kill_after_amount_received_(0), kill_with_io_pending_(false) {
}
- virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {
+ void OnResponseStarted(net::URLRequest* request) override {
amount_received_ = 0;
did_receive_headers_ = false;
if (request->status().is_success()) {
@@ -141,8 +147,7 @@ class AppCacheURLRequestJobTest : public testing::Test {
}
}
- virtual void OnReadCompleted(net::URLRequest* request,
- int bytes_read) OVERRIDE {
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
if (bytes_read > 0) {
amount_received_ += bytes_read;
@@ -424,14 +429,13 @@ class AppCacheURLRequestJobTest : public testing::Test {
// Basic -------------------------------------------------------------------
void Basic() {
AppCacheStorage* storage = service_->storage();
- net::URLRequest request(GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL,
- empty_context_.get());
+ scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL, NULL));
scoped_refptr<AppCacheURLRequestJob> job;
// Create an instance and see that it looks as expected.
- job = new AppCacheURLRequestJob(
- &request, NULL, storage, NULL, false);
+ job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
EXPECT_TRUE(job->is_waiting());
EXPECT_FALSE(job->is_delivering_appcache_response());
EXPECT_FALSE(job->is_delivering_network_response());
@@ -448,24 +452,24 @@ class AppCacheURLRequestJobTest : public testing::Test {
// DeliveryOrders -----------------------------------------------------
void DeliveryOrders() {
AppCacheStorage* storage = service_->storage();
- net::URLRequest request(GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL,
- empty_context_.get());
+ scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
+ GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL, NULL));
scoped_refptr<AppCacheURLRequestJob> job;
// Create an instance, give it a delivery order and see that
// it looks as expected.
- job = new AppCacheURLRequestJob(&request, NULL, storage, NULL, false);
+ job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
job->DeliverErrorResponse();
EXPECT_TRUE(job->is_delivering_error_response());
EXPECT_FALSE(job->has_been_started());
- job = new AppCacheURLRequestJob(&request, NULL, storage, NULL, false);
+ job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
job->DeliverNetworkResponse();
EXPECT_TRUE(job->is_delivering_network_response());
EXPECT_FALSE(job->has_been_started());
- job = new AppCacheURLRequestJob(&request, NULL, storage, NULL, false);
+ job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
const GURL kManifestUrl("http://blah/");
const int64 kCacheId(1);
const int64 kGroupId(1);
diff --git a/chromium/content/browser/appcache/appcache_working_set.cc b/chromium/content/browser/appcache/appcache_working_set.cc
new file mode 100644
index 00000000000..4394097aee0
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_working_set.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2009 The Chromium Authors. 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/appcache/appcache_working_set.h"
+
+#include "base/logging.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_response.h"
+
+namespace content {
+
+AppCacheWorkingSet::AppCacheWorkingSet() : is_disabled_(false) {}
+
+AppCacheWorkingSet::~AppCacheWorkingSet() {
+ DCHECK(caches_.empty());
+ DCHECK(groups_.empty());
+ DCHECK(groups_by_origin_.empty());
+}
+
+void AppCacheWorkingSet::Disable() {
+ if (is_disabled_)
+ return;
+ is_disabled_ = true;
+ caches_.clear();
+ groups_.clear();
+ groups_by_origin_.clear();
+ response_infos_.clear();
+}
+
+void AppCacheWorkingSet::AddCache(AppCache* cache) {
+ if (is_disabled_)
+ return;
+ DCHECK(cache->cache_id() != kAppCacheNoCacheId);
+ int64 cache_id = cache->cache_id();
+ DCHECK(caches_.find(cache_id) == caches_.end());
+ caches_.insert(CacheMap::value_type(cache_id, cache));
+}
+
+void AppCacheWorkingSet::RemoveCache(AppCache* cache) {
+ caches_.erase(cache->cache_id());
+}
+
+void AppCacheWorkingSet::AddGroup(AppCacheGroup* group) {
+ if (is_disabled_)
+ return;
+ const GURL& url = group->manifest_url();
+ DCHECK(groups_.find(url) == groups_.end());
+ groups_.insert(GroupMap::value_type(url, group));
+ groups_by_origin_[url.GetOrigin()].insert(GroupMap::value_type(url, group));
+}
+
+void AppCacheWorkingSet::RemoveGroup(AppCacheGroup* group) {
+ const GURL& url = group->manifest_url();
+ groups_.erase(url);
+
+ GURL origin_url = url.GetOrigin();
+ GroupMap* groups_in_origin = GetMutableGroupsInOrigin(origin_url);
+ if (groups_in_origin) {
+ groups_in_origin->erase(url);
+ if (groups_in_origin->empty())
+ groups_by_origin_.erase(origin_url);
+ }
+}
+
+void AppCacheWorkingSet::AddResponseInfo(AppCacheResponseInfo* info) {
+ if (is_disabled_)
+ return;
+ DCHECK(info->response_id() != kAppCacheNoResponseId);
+ int64 response_id = info->response_id();
+ DCHECK(response_infos_.find(response_id) == response_infos_.end());
+ response_infos_.insert(ResponseInfoMap::value_type(response_id, info));
+}
+
+void AppCacheWorkingSet::RemoveResponseInfo(AppCacheResponseInfo* info) {
+ response_infos_.erase(info->response_id());
+}
+
+} // namespace
diff --git a/chromium/content/browser/appcache/appcache_working_set.h b/chromium/content/browser/appcache/appcache_working_set.h
new file mode 100644
index 00000000000..5b9d00a1e1c
--- /dev/null
+++ b/chromium/content/browser/appcache/appcache_working_set.h
@@ -0,0 +1,76 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_WORKING_SET_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_WORKING_SET_H_
+
+#include <map>
+
+#include "base/containers/hash_tables.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class AppCache;
+class AppCacheGroup;
+class AppCacheResponseInfo;
+
+// Represents the working set of appcache object instances
+// currently in memory.
+class CONTENT_EXPORT AppCacheWorkingSet {
+ public:
+ typedef std::map<GURL, AppCacheGroup*> GroupMap;
+
+ AppCacheWorkingSet();
+ ~AppCacheWorkingSet();
+
+ void Disable();
+ bool is_disabled() const { return is_disabled_; }
+
+ void AddCache(AppCache* cache);
+ void RemoveCache(AppCache* cache);
+ AppCache* GetCache(int64 id) {
+ CacheMap::iterator it = caches_.find(id);
+ return (it != caches_.end()) ? it->second : NULL;
+ }
+
+ void AddGroup(AppCacheGroup* group);
+ void RemoveGroup(AppCacheGroup* group);
+ AppCacheGroup* GetGroup(const GURL& manifest_url) {
+ GroupMap::iterator it = groups_.find(manifest_url);
+ return (it != groups_.end()) ? it->second : NULL;
+ }
+
+ const GroupMap* GetGroupsInOrigin(const GURL& origin_url) {
+ return GetMutableGroupsInOrigin(origin_url);
+ }
+
+ void AddResponseInfo(AppCacheResponseInfo* response_info);
+ void RemoveResponseInfo(AppCacheResponseInfo* response_info);
+ AppCacheResponseInfo* GetResponseInfo(int64 id) {
+ ResponseInfoMap::iterator it = response_infos_.find(id);
+ return (it != response_infos_.end()) ? it->second : NULL;
+ }
+
+ private:
+ typedef base::hash_map<int64, AppCache*> CacheMap;
+ typedef std::map<GURL, GroupMap> GroupsByOriginMap;
+ typedef base::hash_map<int64, AppCacheResponseInfo*> ResponseInfoMap;
+
+ GroupMap* GetMutableGroupsInOrigin(const GURL& origin_url) {
+ GroupsByOriginMap::iterator it = groups_by_origin_.find(origin_url);
+ return (it != groups_by_origin_.end()) ? &it->second : NULL;
+ }
+
+ CacheMap caches_;
+ GroupMap groups_;
+ GroupsByOriginMap groups_by_origin_; // origin -> (manifest -> group)
+ ResponseInfoMap response_infos_;
+ bool is_disabled_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_WORKING_SET_H_
diff --git a/chromium/content/browser/appcache/chrome_appcache_service.cc b/chromium/content/browser/appcache/chrome_appcache_service.cc
index c72c21812ac..e4dbf7e00a1 100644
--- a/chromium/content/browser/appcache/chrome_appcache_service.cc
+++ b/chromium/content/browser/appcache/chrome_appcache_service.cc
@@ -5,27 +5,26 @@
#include "content/browser/appcache/chrome_appcache_service.h"
#include "base/files/file_path.h"
+#include "content/browser/appcache/appcache_storage_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/resource_context.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_context_getter.h"
-#include "webkit/browser/appcache/appcache_storage_impl.h"
-#include "webkit/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_manager.h"
namespace content {
ChromeAppCacheService::ChromeAppCacheService(
- quota::QuotaManagerProxy* quota_manager_proxy)
- : AppCacheServiceImpl(quota_manager_proxy),
- resource_context_(NULL) {
+ storage::QuotaManagerProxy* quota_manager_proxy)
+ : AppCacheServiceImpl(quota_manager_proxy), resource_context_(NULL) {
}
void ChromeAppCacheService::InitializeOnIOThread(
const base::FilePath& cache_path,
ResourceContext* resource_context,
net::URLRequestContextGetter* request_context_getter,
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy) {
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
cache_path_ = cache_path;
diff --git a/chromium/content/browser/appcache/chrome_appcache_service.h b/chromium/content/browser/appcache/chrome_appcache_service.h
index 2f33d9b0f24..6976d873007 100644
--- a/chromium/content/browser/appcache/chrome_appcache_service.h
+++ b/chromium/content/browser/appcache/chrome_appcache_service.h
@@ -8,10 +8,10 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner_helpers.h"
+#include "content/browser/appcache/appcache_policy.h"
+#include "content/browser/appcache/appcache_service_impl.h"
#include "content/common/content_export.h"
-#include "webkit/browser/appcache/appcache_policy.h"
-#include "webkit/browser/appcache/appcache_service_impl.h"
-#include "webkit/browser/quota/special_storage_policy.h"
+#include "storage/browser/quota/special_storage_policy.h"
namespace base {
class FilePath;
@@ -40,26 +40,26 @@ struct ChromeAppCacheServiceDeleter;
class CONTENT_EXPORT ChromeAppCacheService
: public base::RefCountedThreadSafe<ChromeAppCacheService,
ChromeAppCacheServiceDeleter>,
- NON_EXPORTED_BASE(public appcache::AppCacheServiceImpl),
- NON_EXPORTED_BASE(public appcache::AppCachePolicy) {
+ NON_EXPORTED_BASE(public AppCacheServiceImpl),
+ NON_EXPORTED_BASE(public AppCachePolicy) {
public:
- explicit ChromeAppCacheService(quota::QuotaManagerProxy* proxy);
+ explicit ChromeAppCacheService(storage::QuotaManagerProxy* proxy);
// If |cache_path| is empty we will use in-memory structs.
void InitializeOnIOThread(
const base::FilePath& cache_path,
ResourceContext* resource_context,
net::URLRequestContextGetter* request_context_getter,
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy);
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy);
// AppCachePolicy overrides
- virtual bool CanLoadAppCache(const GURL& manifest_url,
- const GURL& first_party) OVERRIDE;
- virtual bool CanCreateAppCache(const GURL& manifest_url,
- const GURL& first_party) OVERRIDE;
+ bool CanLoadAppCache(const GURL& manifest_url,
+ const GURL& first_party) override;
+ bool CanCreateAppCache(const GURL& manifest_url,
+ const GURL& first_party) override;
protected:
- virtual ~ChromeAppCacheService();
+ ~ChromeAppCacheService() override;
private:
friend class base::DeleteHelper<ChromeAppCacheService>;
diff --git a/chromium/content/browser/appcache/chrome_appcache_service_unittest.cc b/chromium/content/browser/appcache/chrome_appcache_service_unittest.cc
index 1800d0bf328..450bfe2c49e 100644
--- a/chromium/content/browser/appcache/chrome_appcache_service_unittest.cc
+++ b/chromium/content/browser/appcache/chrome_appcache_service_unittest.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
+#include "content/browser/appcache/appcache_database.h"
+#include "content/browser/appcache/appcache_storage_impl.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/browser_thread_impl.h"
#include "content/public/browser/resource_context.h"
@@ -15,8 +17,6 @@
#include "content/test/appcache_test_helper.h"
#include "net/url_request/url_request_context_getter.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache_database.h"
-#include "webkit/browser/appcache/appcache_storage_impl.h"
#include <set>
@@ -39,17 +39,15 @@ class MockURLRequestContextGetter : public net::URLRequestContextGetter {
: context_(context), message_loop_proxy_(message_loop_proxy) {
}
- virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
- return context_;
- }
+ net::URLRequestContext* GetURLRequestContext() override { return context_; }
- virtual scoped_refptr<base::SingleThreadTaskRunner>
- GetNetworkTaskRunner() const OVERRIDE {
+ scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
+ const override {
return message_loop_proxy_;
}
protected:
- virtual ~MockURLRequestContextGetter() {}
+ ~MockURLRequestContextGetter() override {}
private:
net::URLRequestContext* context_;
@@ -116,8 +114,8 @@ ChromeAppCacheServiceTest::CreateAppCacheServiceImpl(
// Steps needed to initialize the storage of AppCache data.
message_loop_.RunUntilIdle();
if (init_storage) {
- appcache::AppCacheStorageImpl* storage =
- static_cast<appcache::AppCacheStorageImpl*>(
+ AppCacheStorageImpl* storage =
+ static_cast<AppCacheStorageImpl*>(
appcache_service->storage());
storage->database_->db_connection();
storage->disk_cache();
diff --git a/chromium/content/browser/appcache/mock_appcache_policy.h b/chromium/content/browser/appcache/mock_appcache_policy.h
index bc7576412b9..a571e25efb6 100644
--- a/chromium/content/browser/appcache/mock_appcache_policy.h
+++ b/chromium/content/browser/appcache/mock_appcache_policy.h
@@ -6,20 +6,20 @@
#define CONTENT_BROWSER_APPCACHE_MOCK_APPCACHE_POLICY_H_
#include "base/compiler_specific.h"
+#include "content/browser/appcache/appcache_policy.h"
#include "url/gurl.h"
-#include "webkit/browser/appcache/appcache_policy.h"
namespace content {
-class MockAppCachePolicy : public appcache::AppCachePolicy {
+class MockAppCachePolicy : public AppCachePolicy {
public:
MockAppCachePolicy();
virtual ~MockAppCachePolicy();
- virtual bool CanLoadAppCache(const GURL& manifest_url,
- const GURL& first_party) OVERRIDE;
- virtual bool CanCreateAppCache(const GURL& manifest_url,
- const GURL& first_party) OVERRIDE;
+ bool CanLoadAppCache(const GURL& manifest_url,
+ const GURL& first_party) override;
+ bool CanCreateAppCache(const GURL& manifest_url,
+ const GURL& first_party) override;
bool can_load_return_value_;
bool can_create_return_value_;
diff --git a/chromium/content/browser/appcache/mock_appcache_service.h b/chromium/content/browser/appcache/mock_appcache_service.h
index 691736baa60..5e384201e4c 100644
--- a/chromium/content/browser/appcache/mock_appcache_service.h
+++ b/chromium/content/browser/appcache/mock_appcache_service.h
@@ -6,11 +6,9 @@
#define CONTENT_BROWSER_APPCACHE_MOCK_APPCACHE_SERVICE_H_
#include "base/compiler_specific.h"
+#include "content/browser/appcache/appcache_service_impl.h"
#include "content/browser/appcache/mock_appcache_storage.h"
-#include "webkit/browser/appcache/appcache_service_impl.h"
-#include "webkit/browser/quota/quota_manager.h"
-
-using appcache::AppCacheServiceImpl;
+#include "storage/browser/quota/quota_manager.h"
namespace content {
@@ -26,11 +24,11 @@ class MockAppCacheService : public AppCacheServiceImpl {
// Just returns a canned completion code without actually
// removing groups and caches in our mock storage instance.
- virtual void DeleteAppCachesForOrigin(
+ void DeleteAppCachesForOrigin(
const GURL& origin,
- const net::CompletionCallback& callback) OVERRIDE;
+ const net::CompletionCallback& callback) override;
- void set_quota_manager_proxy(quota::QuotaManagerProxy* proxy) {
+ void set_quota_manager_proxy(storage::QuotaManagerProxy* proxy) {
quota_manager_proxy_ = proxy;
}
diff --git a/chromium/content/browser/appcache/mock_appcache_storage.cc b/chromium/content/browser/appcache/mock_appcache_storage.cc
index ea9673df497..91630f7d351 100644
--- a/chromium/content/browser/appcache/mock_appcache_storage.cc
+++ b/chromium/content/browser/appcache/mock_appcache_storage.cc
@@ -9,11 +9,11 @@
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_entry.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_service_impl.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_entry.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_service_impl.h"
// This is a quick and easy 'mock' implementation of the storage interface
// that doesn't put anything to disk.
@@ -25,13 +25,6 @@
// happen with a real disk-backed storage impl that involves IO on a
// background thread.
-using appcache::AppCacheResponseWriter;
-using appcache::AppCacheServiceImpl;
-using appcache::APPCACHE_FALLBACK_NAMESPACE;
-using appcache::APPCACHE_INTERCEPT_NAMESPACE;
-using appcache::kAppCacheNoCacheId;
-using appcache::AppCacheNamespaceType;
-
namespace content {
MockAppCacheStorage::MockAppCacheStorage(AppCacheServiceImpl* service)
diff --git a/chromium/content/browser/appcache/mock_appcache_storage.h b/chromium/content/browser/appcache/mock_appcache_storage.h
index 5d31748da43..a6ece438ef1 100644
--- a/chromium/content/browser/appcache/mock_appcache_storage.h
+++ b/chromium/content/browser/appcache/mock_appcache_storage.h
@@ -14,22 +14,11 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_disk_cache.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_storage.h"
-
-using appcache::AppCache;
-using appcache::AppCacheDiskCache;
-using appcache::AppCacheEntry;
-using appcache::AppCacheGroup;
-using appcache::AppCacheInfoCollection;
-using appcache::AppCacheResponseReader;
-using appcache::AppCacheResponseWriter;
-using appcache::AppCacheServiceImpl;
-using appcache::AppCacheStorage;
-using appcache::kAppCacheNoCacheId;
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_disk_cache.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_storage.h"
namespace content {
FORWARD_DECLARE_TEST(AppCacheServiceImplTest, DeleteAppCachesForOrigin);
@@ -58,37 +47,35 @@ class MockAppCacheStorageTest;
class MockAppCacheStorage : public AppCacheStorage {
public:
explicit MockAppCacheStorage(AppCacheServiceImpl* service);
- virtual ~MockAppCacheStorage();
-
- virtual void GetAllInfo(Delegate* delegate) OVERRIDE;
- virtual void LoadCache(int64 id, Delegate* delegate) OVERRIDE;
- virtual void LoadOrCreateGroup(const GURL& manifest_url,
- Delegate* delegate) OVERRIDE;
- virtual void StoreGroupAndNewestCache(AppCacheGroup* group,
- AppCache* newest_cache,
- Delegate* delegate) OVERRIDE;
- virtual void FindResponseForMainRequest(const GURL& url,
- const GURL& preferred_manifest_url,
- Delegate* delegate) OVERRIDE;
- virtual void FindResponseForSubRequest(
- AppCache* cache, const GURL& url,
- AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
- bool * found_network_namespace) OVERRIDE;
- virtual void MarkEntryAsForeign(const GURL& entry_url,
- int64 cache_id) OVERRIDE;
- virtual void MakeGroupObsolete(AppCacheGroup* group,
- Delegate* delegate,
- int response_code) OVERRIDE;
- virtual AppCacheResponseReader* CreateResponseReader(
- const GURL& manifest_url, int64 group_id, int64 response_id) OVERRIDE;
- virtual AppCacheResponseWriter* CreateResponseWriter(
- const GURL& manifest_url, int64 group_id) OVERRIDE;
- virtual void DoomResponses(
- const GURL& manifest_url,
- const std::vector<int64>& response_ids) OVERRIDE;
- virtual void DeleteResponses(
- const GURL& manifest_url,
- const std::vector<int64>& response_ids) OVERRIDE;
+ ~MockAppCacheStorage() override;
+
+ void GetAllInfo(Delegate* delegate) override;
+ void LoadCache(int64 id, Delegate* delegate) override;
+ void LoadOrCreateGroup(const GURL& manifest_url, Delegate* delegate) override;
+ void StoreGroupAndNewestCache(AppCacheGroup* group,
+ AppCache* newest_cache,
+ Delegate* delegate) override;
+ void FindResponseForMainRequest(const GURL& url,
+ const GURL& preferred_manifest_url,
+ Delegate* delegate) override;
+ void FindResponseForSubRequest(AppCache* cache,
+ const GURL& url,
+ AppCacheEntry* found_entry,
+ AppCacheEntry* found_fallback_entry,
+ bool* found_network_namespace) override;
+ void MarkEntryAsForeign(const GURL& entry_url, int64 cache_id) override;
+ void MakeGroupObsolete(AppCacheGroup* group,
+ Delegate* delegate,
+ int response_code) override;
+ AppCacheResponseReader* CreateResponseReader(const GURL& manifest_url,
+ int64 group_id,
+ int64 response_id) override;
+ AppCacheResponseWriter* CreateResponseWriter(const GURL& manifest_url,
+ int64 group_id) override;
+ void DoomResponses(const GURL& manifest_url,
+ const std::vector<int64>& response_ids) override;
+ void DeleteResponses(const GURL& manifest_url,
+ const std::vector<int64>& response_ids) override;
private:
friend class AppCacheRequestHandlerTest;
diff --git a/chromium/content/browser/appcache/mock_appcache_storage_unittest.cc b/chromium/content/browser/appcache/mock_appcache_storage_unittest.cc
index f1c9149102c..8f52912d39f 100644
--- a/chromium/content/browser/appcache/mock_appcache_storage_unittest.cc
+++ b/chromium/content/browser/appcache/mock_appcache_storage_unittest.cc
@@ -3,24 +3,12 @@
// found in the LICENSE file.
#include "base/run_loop.h"
+#include "content/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_storage.h"
#include "content/browser/appcache/mock_appcache_service.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_storage.h"
-
-using appcache::AppCache;
-using appcache::AppCacheEntry;
-using appcache::AppCacheGroup;
-using appcache::AppCacheStorage;
-using appcache::APPCACHE_FALLBACK_NAMESPACE;
-using appcache::APPCACHE_INTERCEPT_NAMESPACE;
-using appcache::kAppCacheNoCacheId;
-using appcache::kAppCacheNoResponseId;
-using appcache::Manifest;
-using appcache::Namespace;
-using appcache::APPCACHE_NETWORK_NAMESPACE;
namespace content {
@@ -33,38 +21,39 @@ class MockAppCacheStorageTest : public testing::Test {
obsoleted_success_(false), found_cache_id_(kAppCacheNoCacheId) {
}
- virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE {
+ void OnCacheLoaded(AppCache* cache, int64 cache_id) override {
loaded_cache_ = cache;
loaded_cache_id_ = cache_id;
}
- virtual void OnGroupLoaded(AppCacheGroup* group,
- const GURL& manifest_url) OVERRIDE {
+ void OnGroupLoaded(AppCacheGroup* group,
+ const GURL& manifest_url) override {
loaded_group_ = group;
loaded_manifest_url_ = manifest_url;
}
- virtual void OnGroupAndNewestCacheStored(
- AppCacheGroup* group, AppCache* newest_cache, bool success,
- bool would_exceed_quota) OVERRIDE {
+ void OnGroupAndNewestCacheStored(AppCacheGroup* group,
+ AppCache* newest_cache,
+ bool success,
+ bool would_exceed_quota) override {
stored_group_ = group;
stored_group_success_ = success;
}
- virtual void OnGroupMadeObsolete(AppCacheGroup* group,
- bool success,
- int response_code) OVERRIDE {
+ void OnGroupMadeObsolete(AppCacheGroup* group,
+ bool success,
+ int response_code) override {
obsoleted_group_ = group;
obsoleted_success_ = success;
}
- virtual void OnMainResponseFound(const GURL& url,
- const AppCacheEntry& entry,
- const GURL& fallback_url,
- const AppCacheEntry& fallback_entry,
- int64 cache_id,
- int64 group_id,
- const GURL& manifest_url) OVERRIDE {
+ void OnMainResponseFound(const GURL& url,
+ const AppCacheEntry& entry,
+ const GURL& fallback_url,
+ const AppCacheEntry& fallback_entry,
+ int64 cache_id,
+ int64 group_id,
+ const GURL& manifest_url) override {
found_url_ = url;
found_entry_ = entry;
found_fallback_url_ = fallback_url;
@@ -249,7 +238,7 @@ TEST_F(MockAppCacheStorageTest, StoreNewGroup) {
EXPECT_TRUE(delegate.stored_group_success_);
EXPECT_FALSE(storage->stored_caches_.empty());
EXPECT_FALSE(storage->stored_groups_.empty());
- EXPECT_EQ(cache, group->newest_complete_cache());
+ EXPECT_EQ(cache.get(), group->newest_complete_cache());
EXPECT_TRUE(cache->is_complete());
}
@@ -318,7 +307,7 @@ TEST_F(MockAppCacheStorageTest, StoreExistingGroupExistingCache) {
// Hold our refs to simulate the UpdateJob holding these refs.
// Change the group's newest cache.
- EXPECT_EQ(cache, group->newest_complete_cache());
+ EXPECT_EQ(cache.get(), group->newest_complete_cache());
GURL entry_url("http://blah/blah");
cache->AddEntry(entry_url, AppCacheEntry(AppCacheEntry::MASTER));
@@ -336,7 +325,7 @@ TEST_F(MockAppCacheStorageTest, StoreExistingGroupExistingCache) {
EXPECT_EQ(size_t(1), storage->stored_caches_.size());
EXPECT_EQ(size_t(1), storage->stored_groups_.size());
EXPECT_TRUE(storage->IsCacheStored(cache.get()));
- EXPECT_EQ(cache, group->newest_complete_cache());
+ EXPECT_EQ(cache.get(), group->newest_complete_cache());
EXPECT_TRUE(cache->GetEntry(entry_url));
}
@@ -481,12 +470,12 @@ TEST_F(MockAppCacheStorageTest, BasicFindMainFallbackResponse) {
const int64 kResponseId1 = 1;
const int64 kResponseId2 = 2;
- Manifest manifest;
+ AppCacheManifest manifest;
manifest.fallback_namespaces.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl1,
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl1,
kFallbackEntryUrl1, false));
manifest.fallback_namespaces.push_back(
- Namespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl2,
+ AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE, kFallbackNamespaceUrl2,
kFallbackEntryUrl2, false));
scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
@@ -593,9 +582,9 @@ TEST_F(MockAppCacheStorageTest, FindMainResponseExclusions) {
const GURL kOnlineNamespaceUrl("http://blah/online_namespace");
const int64 kResponseId = 1;
- Manifest manifest;
+ AppCacheManifest manifest;
manifest.online_whitelist_namespaces.push_back(
- Namespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespaceUrl,
+ AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespaceUrl,
GURL(), false));
scoped_refptr<AppCache> cache(new AppCache(service.storage(), kCacheId));
cache->InitializeWithManifest(&manifest);
diff --git a/chromium/content/browser/appcache/view_appcache_internals_job.cc b/chromium/content/browser/appcache/view_appcache_internals_job.cc
index 0cc64c361f0..5e793bbb760 100644
--- a/chromium/content/browser/appcache/view_appcache_internals_job.cc
+++ b/chromium/content/browser/appcache/view_appcache_internals_job.cc
@@ -13,10 +13,17 @@
#include "base/i18n/time_formatting.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
+#include "base/profiler/scoped_tracker.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/browser/appcache/appcache.h"
+#include "content/browser/appcache/appcache_group.h"
+#include "content/browser/appcache/appcache_policy.h"
+#include "content/browser/appcache/appcache_response.h"
+#include "content/browser/appcache/appcache_service_impl.h"
+#include "content/browser/appcache/appcache_storage.h"
#include "net/base/escape.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -24,24 +31,6 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_simple_job.h"
#include "net/url_request/view_cache_helper.h"
-#include "webkit/browser/appcache/appcache.h"
-#include "webkit/browser/appcache/appcache_group.h"
-#include "webkit/browser/appcache/appcache_policy.h"
-#include "webkit/browser/appcache/appcache_response.h"
-#include "webkit/browser/appcache/appcache_service_impl.h"
-#include "webkit/browser/appcache/appcache_storage.h"
-
-using appcache::AppCacheGroup;
-using appcache::AppCacheInfo;
-using appcache::AppCacheInfoCollection;
-using appcache::AppCacheInfoVector;
-using appcache::AppCacheServiceImpl;
-using appcache::AppCacheStorage;
-using appcache::AppCacheStorageReference;
-using appcache::AppCacheResourceInfo;
-using appcache::AppCacheResourceInfoVector;
-using appcache::AppCacheResponseInfo;
-using appcache::AppCacheResponseReader;
namespace content {
namespace {
@@ -332,12 +321,10 @@ class BaseInternalsJob : public net::URLRequestSimpleJob,
appcache_service_->AddObserver(this);
}
- virtual ~BaseInternalsJob() {
- appcache_service_->RemoveObserver(this);
- }
+ ~BaseInternalsJob() override { appcache_service_->RemoveObserver(this); }
- virtual void OnServiceReinitialized(
- AppCacheStorageReference* old_storage_ref) OVERRIDE {
+ void OnServiceReinitialized(
+ AppCacheStorageReference* old_storage_ref) override {
if (old_storage_ref->storage() == appcache_storage_)
disabled_storage_reference_ = old_storage_ref;
}
@@ -357,7 +344,7 @@ class MainPageJob : public BaseInternalsJob {
weak_factory_(this) {
}
- virtual void Start() OVERRIDE {
+ void Start() override {
DCHECK(request_);
info_collection_ = new AppCacheInfoCollection;
appcache_service_->GetAllAppCacheInfo(
@@ -367,10 +354,14 @@ class MainPageJob : public BaseInternalsJob {
}
// Produces a page containing the listing
- virtual int GetData(std::string* mime_type,
- std::string* charset,
- std::string* out,
- const net::CompletionCallback& callback) const OVERRIDE {
+ int GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* out,
+ const net::CompletionCallback& callback) const override {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("422489 MainPageJob::GetData"));
+
mime_type->assign("text/html");
charset->assign("UTF-8");
@@ -399,7 +390,7 @@ class MainPageJob : public BaseInternalsJob {
}
private:
- virtual ~MainPageJob() {}
+ ~MainPageJob() override {}
void OnGotInfoComplete(int rv) {
if (rv != net::OK)
@@ -420,22 +411,21 @@ class RedirectToMainPageJob : public BaseInternalsJob {
AppCacheServiceImpl* service)
: BaseInternalsJob(request, network_delegate, service) {}
- virtual int GetData(std::string* mime_type,
- std::string* charset,
- std::string* data,
- const net::CompletionCallback& callback) const OVERRIDE {
+ int GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* data,
+ const net::CompletionCallback& callback) const override {
return net::OK; // IsRedirectResponse induces a redirect.
}
- virtual bool IsRedirectResponse(GURL* location,
- int* http_status_code) OVERRIDE {
+ bool IsRedirectResponse(GURL* location, int* http_status_code) override {
*location = ClearQuery(request_->url());
*http_status_code = 307;
return true;
}
protected:
- virtual ~RedirectToMainPageJob() {}
+ ~RedirectToMainPageJob() override {}
};
// Job that removes an appcache and then redirects back to the main page.
@@ -451,7 +441,7 @@ class RemoveAppCacheJob : public RedirectToMainPageJob {
weak_factory_(this) {
}
- virtual void Start() OVERRIDE {
+ void Start() override {
DCHECK(request_);
appcache_service_->DeleteAppCacheGroup(
@@ -460,7 +450,7 @@ class RemoveAppCacheJob : public RedirectToMainPageJob {
}
private:
- virtual ~RemoveAppCacheJob() {}
+ ~RemoveAppCacheJob() override {}
void OnDeleteAppCacheComplete(int rv) {
StartAsync(); // Causes the base class to redirect.
@@ -483,16 +473,20 @@ class ViewAppCacheJob : public BaseInternalsJob,
: BaseInternalsJob(request, network_delegate, service),
manifest_url_(manifest_url) {}
- virtual void Start() OVERRIDE {
+ void Start() override {
DCHECK(request_);
appcache_storage_->LoadOrCreateGroup(manifest_url_, this);
}
// Produces a page containing the entries listing.
- virtual int GetData(std::string* mime_type,
- std::string* charset,
- std::string* out,
- const net::CompletionCallback& callback) const OVERRIDE {
+ int GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* out,
+ const net::CompletionCallback& callback) const override {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("422489 ViewAppCacheJob::GetData"));
+
mime_type->assign("text/html");
charset->assign("UTF-8");
out->clear();
@@ -513,13 +507,12 @@ class ViewAppCacheJob : public BaseInternalsJob,
}
private:
- virtual ~ViewAppCacheJob() {
+ ~ViewAppCacheJob() override {
appcache_storage_->CancelDelegateCallbacks(this);
}
// AppCacheStorage::Delegate override
- virtual void OnGroupLoaded(
- AppCacheGroup* group, const GURL& manifest_url) OVERRIDE {
+ void OnGroupLoaded(AppCacheGroup* group, const GURL& manifest_url) override {
DCHECK_EQ(manifest_url_, manifest_url);
if (group && group->newest_complete_cache()) {
appcache_info_.manifest_url = manifest_url;
@@ -558,17 +551,21 @@ class ViewEntryJob : public BaseInternalsJob,
response_id_(response_id), group_id_(group_id), amount_read_(0) {
}
- virtual void Start() OVERRIDE {
+ void Start() override {
DCHECK(request_);
appcache_storage_->LoadResponseInfo(
manifest_url_, group_id_, response_id_, this);
}
// Produces a page containing the response headers and data.
- virtual int GetData(std::string* mime_type,
- std::string* charset,
- std::string* out,
- const net::CompletionCallback& callback) const OVERRIDE {
+ int GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* out,
+ const net::CompletionCallback& callback) const override {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("422489 ViewEntryJob::GetData"));
+
mime_type->assign("text/html");
charset->assign("UTF-8");
out->clear();
@@ -598,12 +595,10 @@ class ViewEntryJob : public BaseInternalsJob,
}
private:
- virtual ~ViewEntryJob() {
- appcache_storage_->CancelDelegateCallbacks(this);
- }
+ ~ViewEntryJob() override { appcache_storage_->CancelDelegateCallbacks(this); }
- virtual void OnResponseInfoLoaded(
- AppCacheResponseInfo* response_info, int64 response_id) OVERRIDE {
+ void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
+ int64 response_id) override {
if (!response_info) {
StartAsync();
return;
@@ -664,8 +659,8 @@ net::URLRequestJob* ViewAppCacheInternalsJobFactory::CreateJobForRequest(
DecodeBase64URL(param));
std::vector<std::string> tokens;
- int64 response_id;
- int64 group_id;
+ int64 response_id = 0;
+ int64 group_id = 0;
if (command == kViewEntryCommand && Tokenize(param, "|", &tokens) == 4u &&
base::StringToInt64(tokens[2], &response_id) &&
base::StringToInt64(tokens[3], &group_id)) {
diff --git a/chromium/content/browser/appcache/view_appcache_internals_job.h b/chromium/content/browser/appcache/view_appcache_internals_job.h
index f11b68e5875..5118212cd51 100644
--- a/chromium/content/browser/appcache/view_appcache_internals_job.h
+++ b/chromium/content/browser/appcache/view_appcache_internals_job.h
@@ -13,23 +13,20 @@ class URLRequest;
class URLRequestJob;
}
-namespace appcache {
-class AppCacheServiceImpl;
-}
-
namespace content {
+class AppCacheServiceImpl;
class ViewAppCacheInternalsJobFactory {
public:
static net::URLRequestJob* CreateJobForRequest(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
- appcache::AppCacheServiceImpl* service);
+ AppCacheServiceImpl* service);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ViewAppCacheInternalsJobFactory);
};
-} // namespace appcache
+} // namespace content
#endif // CONTENT_BROWSER_APPCACHE_VIEW_APPCACHE_INTERNALS_JOB_H_
diff --git a/chromium/content/browser/battery_status/OWNERS b/chromium/content/browser/battery_status/OWNERS
deleted file mode 100644
index 1fd89e0e2eb..00000000000
--- a/chromium/content/browser/battery_status/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-timvolodine@chromium.org
diff --git a/chromium/content/browser/battery_status/battery_status_browsertest.cc b/chromium/content/browser/battery_status/battery_status_browsertest.cc
index 76878315054..7da7f86d082 100644
--- a/chromium/content/browser/battery_status/battery_status_browsertest.cc
+++ b/chromium/content/browser/battery_status/battery_status_browsertest.cc
@@ -4,8 +4,7 @@
#include "base/command_line.h"
#include "base/synchronization/waitable_event.h"
-#include "content/browser/battery_status/battery_status_manager.h"
-#include "content/browser/battery_status/battery_status_service.h"
+#include "base/thread_task_runner_handle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/content_browser_test.h"
@@ -13,36 +12,38 @@
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
+#include "device/battery/battery_status_manager.h"
+#include "device/battery/battery_status_service.h"
namespace content {
namespace {
-class FakeBatteryManager : public BatteryStatusManager {
+class FakeBatteryManager : public device::BatteryStatusManager {
public:
explicit FakeBatteryManager(
- const BatteryStatusService::BatteryUpdateCallback& callback)
- : battery_status_available_(true),
- started_(false) {
- callback_ = callback;
- }
- virtual ~FakeBatteryManager() { }
+ const device::BatteryStatusService::BatteryUpdateCallback& callback)
+ : callback_(callback), battery_status_available_(true), started_(false) {}
+ ~FakeBatteryManager() override {}
// Methods from BatteryStatusManager.
- virtual bool StartListeningBatteryChange() OVERRIDE {
+ bool StartListeningBatteryChange() override {
started_ = true;
if (battery_status_available_)
InvokeUpdateCallback();
return battery_status_available_;
}
- virtual void StopListeningBatteryChange() OVERRIDE { }
+ void StopListeningBatteryChange() override {}
void InvokeUpdateCallback() {
- callback_.Run(status_);
+ // Invoke asynchronously to mimic the OS-specific battery managers.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(callback_, status_));
}
- void set_battery_status(const blink::WebBatteryStatus& status) {
+ void set_battery_status(const device::BatteryStatus& status) {
status_ = status;
}
@@ -55,9 +56,10 @@ class FakeBatteryManager : public BatteryStatusManager {
}
private:
+ device::BatteryStatusService::BatteryUpdateCallback callback_;
bool battery_status_available_;
bool started_;
- blink::WebBatteryStatus status_;
+ device::BatteryStatus status_;
DISALLOW_COPY_AND_ASSIGN(FakeBatteryManager);
};
@@ -65,33 +67,32 @@ class FakeBatteryManager : public BatteryStatusManager {
class BatteryStatusBrowserTest : public ContentBrowserTest {
public:
BatteryStatusBrowserTest()
- : battery_manager_(0),
- battery_service_(0),
- io_loop_finished_event_(false, false) {
+ : battery_manager_(NULL),
+ battery_service_(NULL) {
}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
}
- virtual void SetUpOnMainThread() OVERRIDE {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&BatteryStatusBrowserTest::SetUpOnIOThread, this));
- io_loop_finished_event_.Wait();
- }
+ void SetUpOnMainThread() override {
+ battery_service_ = device::BatteryStatusService::GetInstance();
+
+ // We keep a raw pointer to the FakeBatteryManager, which we expect to
+ // remain valid for the lifetime of the BatteryStatusService.
+ scoped_ptr<FakeBatteryManager> battery_manager(new FakeBatteryManager(
+ battery_service_->GetUpdateCallbackForTesting()));
+ battery_manager_ = battery_manager.get();
- void SetUpOnIOThread() {
- battery_service_ = BatteryStatusService::GetInstance();
- battery_manager_ = new FakeBatteryManager(
- battery_service_->GetUpdateCallbackForTesting());
- battery_service_->SetBatteryManagerForTesting(battery_manager_);
- io_loop_finished_event_.Signal();
+ battery_service_->SetBatteryManagerForTesting(
+ battery_manager.Pass());
}
- virtual void TearDown() OVERRIDE {
- battery_service_->SetBatteryManagerForTesting(0);
+ void TearDown() override {
+ battery_service_->SetBatteryManagerForTesting(
+ scoped_ptr<device::BatteryStatusManager>());
+ battery_manager_ = NULL;
}
FakeBatteryManager* battery_manager() {
@@ -100,8 +101,7 @@ class BatteryStatusBrowserTest : public ContentBrowserTest {
private:
FakeBatteryManager* battery_manager_;
- BatteryStatusService* battery_service_;
- base::WaitableEvent io_loop_finished_event_;
+ device::BatteryStatusService* battery_service_;
DISALLOW_COPY_AND_ASSIGN(BatteryStatusBrowserTest);
};
@@ -122,10 +122,10 @@ IN_PROC_BROWSER_TEST_F(BatteryStatusBrowserTest, BatteryManagerResolvePromise) {
// Set the fake battery manager to return predefined battery status values.
// From JavaScript request a promise for the battery status information and
// once it resolves check the values and navigate to #pass.
- blink::WebBatteryStatus status;
+ device::BatteryStatus status;
status.charging = true;
- status.chargingTime = 100;
- status.dischargingTime = std::numeric_limits<double>::infinity();
+ status.charging_time = 100;
+ status.discharging_time = std::numeric_limits<double>::infinity();
status.level = 0.5;
battery_manager()->set_battery_status(status);
@@ -143,7 +143,7 @@ IN_PROC_BROWSER_TEST_F(BatteryStatusBrowserTest,
// Once it resolves add an event listener for battery level change. Set
// battery level to 0.6 and invoke update. Check that the event listener
// is invoked with the correct value for level and navigate to #pass.
- blink::WebBatteryStatus status;
+ device::BatteryStatus status;
battery_manager()->set_battery_status(status);
TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
diff --git a/chromium/content/browser/battery_status/battery_status_manager.h b/chromium/content/browser/battery_status/battery_status_manager.h
deleted file mode 100644
index 20e71edfbb1..00000000000
--- a/chromium/content/browser/battery_status/battery_status_manager.h
+++ /dev/null
@@ -1,57 +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 CHROME_BROWSER_BATTERY_STATUS_BATTERY_STATUS_MANAGER_H_
-#define CHROME_BROWSER_BATTERY_STATUS_BATTERY_STATUS_MANAGER_H_
-
-#include "build/build_config.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/scoped_java_ref.h"
-#endif
-
-#include "content/browser/battery_status/battery_status_service.h"
-
-namespace content {
-
-// Platform specific manager class for fetching battery status data.
-class CONTENT_EXPORT BatteryStatusManager {
- public:
- explicit BatteryStatusManager(
- const BatteryStatusService::BatteryUpdateCallback& callback);
- virtual ~BatteryStatusManager();
-
- // Start listening for battery status changes. New updates are signalled
- // by invoking the callback provided at construction time.
- virtual bool StartListeningBatteryChange();
-
- // Stop listening for battery status changes.
- virtual void StopListeningBatteryChange();
-
-#if defined(OS_ANDROID)
- // Must be called at startup.
- static bool Register(JNIEnv* env);
-
- // Called from Java via JNI.
- void GotBatteryStatus(JNIEnv*, jobject, jboolean charging,
- jdouble charging_time, jdouble discharging_time,
- jdouble level);
-#endif
-
- protected:
- BatteryStatusManager();
- BatteryStatusService::BatteryUpdateCallback callback_;
-
- private:
-#if defined(OS_ANDROID)
- // Java provider of battery status info.
- base::android::ScopedJavaGlobalRef<jobject> j_manager_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(BatteryStatusManager);
-};
-
-} // namespace content
-
-#endif // CHROME_BROWSER_BATTERY_STATUS_BATTERY_STATUS_MANAGER_H_
diff --git a/chromium/content/browser/battery_status/battery_status_manager_android.cc b/chromium/content/browser/battery_status/battery_status_manager_android.cc
deleted file mode 100644
index a8438b85572..00000000000
--- a/chromium/content/browser/battery_status/battery_status_manager_android.cc
+++ /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.
-
-#include "content/browser/battery_status/battery_status_manager.h"
-
-#include "base/android/jni_android.h"
-#include "base/metrics/histogram.h"
-#include "jni/BatteryStatusManager_jni.h"
-
-using base::android::AttachCurrentThread;
-
-namespace content {
-
-BatteryStatusManager::BatteryStatusManager(
- const BatteryStatusService::BatteryUpdateCallback& callback)
- : callback_(callback) {
- j_manager_.Reset(
- Java_BatteryStatusManager_getInstance(
- AttachCurrentThread(), base::android::GetApplicationContext()));
-}
-
-BatteryStatusManager::BatteryStatusManager() {
-}
-
-BatteryStatusManager::~BatteryStatusManager() {
-}
-
-bool BatteryStatusManager::Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-void BatteryStatusManager::GotBatteryStatus(JNIEnv*, jobject,
- jboolean charging, jdouble charging_time, jdouble discharging_time,
- jdouble level) {
- blink::WebBatteryStatus status;
- status.charging = charging;
- status.chargingTime = charging_time;
- status.dischargingTime = discharging_time;
- status.level = level;
- callback_.Run(status);
-}
-
-bool BatteryStatusManager::StartListeningBatteryChange() {
- bool result = Java_BatteryStatusManager_start(AttachCurrentThread(),
- j_manager_.obj(), reinterpret_cast<intptr_t>(this));
- UMA_HISTOGRAM_BOOLEAN("BatteryStatus.StartAndroid", result);
- return result;
-}
-
-void BatteryStatusManager::StopListeningBatteryChange() {
- Java_BatteryStatusManager_stop(
- AttachCurrentThread(), j_manager_.obj());
-}
-
-} // namespace content
diff --git a/chromium/content/browser/battery_status/battery_status_manager_default.cc b/chromium/content/browser/battery_status/battery_status_manager_default.cc
deleted file mode 100644
index a8d066bdefd..00000000000
--- a/chromium/content/browser/battery_status/battery_status_manager_default.cc
+++ /dev/null
@@ -1,31 +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/battery_status/battery_status_manager.h"
-
-#include "base/logging.h"
-
-namespace content {
-
-BatteryStatusManager::BatteryStatusManager(
- const BatteryStatusService::BatteryUpdateCallback& callback)
- : callback_(callback) {
-}
-
-BatteryStatusManager::BatteryStatusManager() {
-}
-
-BatteryStatusManager::~BatteryStatusManager() {
-}
-
-bool BatteryStatusManager::StartListeningBatteryChange() {
- NOTIMPLEMENTED();
- return false;
-}
-
-void BatteryStatusManager::StopListeningBatteryChange() {
- NOTIMPLEMENTED();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/battery_status/battery_status_message_filter.cc b/chromium/content/browser/battery_status/battery_status_message_filter.cc
deleted file mode 100644
index 19a21b80787..00000000000
--- a/chromium/content/browser/battery_status/battery_status_message_filter.cc
+++ /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.
-
-#include "content/browser/battery_status/battery_status_message_filter.h"
-
-#include "content/common/battery_status_messages.h"
-
-namespace content {
-
-BatteryStatusMessageFilter::BatteryStatusMessageFilter()
- : BrowserMessageFilter(BatteryStatusMsgStart),
- is_started_(false) {
- callback_ = base::Bind(&BatteryStatusMessageFilter::SendBatteryChange,
- base::Unretained(this));
-}
-
-BatteryStatusMessageFilter::~BatteryStatusMessageFilter() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (is_started_)
- subscription_.reset();
-}
-
-bool BatteryStatusMessageFilter::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(BatteryStatusMessageFilter, message)
- IPC_MESSAGE_HANDLER(BatteryStatusHostMsg_Start, OnBatteryStatusStart)
- IPC_MESSAGE_HANDLER(BatteryStatusHostMsg_Stop, OnBatteryStatusStop)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void BatteryStatusMessageFilter::OnBatteryStatusStart() {
- DCHECK(!is_started_);
- if (is_started_)
- return;
- is_started_ = true;
- subscription_ = BatteryStatusService::GetInstance()->AddCallback(callback_);
-}
-
-void BatteryStatusMessageFilter::OnBatteryStatusStop() {
- DCHECK(is_started_);
- if (!is_started_)
- return;
- is_started_ = false;
- subscription_.reset();
-}
-
-void BatteryStatusMessageFilter::SendBatteryChange(
- const blink::WebBatteryStatus& status) {
- Send(new BatteryStatusMsg_DidChange(status));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/battery_status/battery_status_message_filter.h b/chromium/content/browser/battery_status/battery_status_message_filter.h
index 9484114c576..efe94303c4e 100644
--- a/chromium/content/browser/battery_status/battery_status_message_filter.h
+++ b/chromium/content/browser/battery_status/battery_status_message_filter.h
@@ -15,10 +15,10 @@ class BatteryStatusMessageFilter : public BrowserMessageFilter {
BatteryStatusMessageFilter();
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
- virtual ~BatteryStatusMessageFilter();
+ ~BatteryStatusMessageFilter() override;
void OnBatteryStatusStart();
void OnBatteryStatusStop();
diff --git a/chromium/content/browser/battery_status/battery_status_service.cc b/chromium/content/browser/battery_status/battery_status_service.cc
deleted file mode 100644
index 21d59d3780d..00000000000
--- a/chromium/content/browser/battery_status/battery_status_service.cc
+++ /dev/null
@@ -1,106 +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/battery_status/battery_status_service.h"
-
-#include "base/bind.h"
-#include "content/browser/battery_status/battery_status_manager.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace content {
-
-BatteryStatusService::BatteryStatusService()
- : update_callback_(base::Bind(&BatteryStatusService::UpdateBatteryStatus,
- base::Unretained(this))),
- status_updated_(false),
- is_shutdown_(false) {
- callback_list_.set_removal_callback(
- base::Bind(&BatteryStatusService::ConsumersChanged,
- base::Unretained(this)));
-}
-
-BatteryStatusService::~BatteryStatusService() {
-}
-
-BatteryStatusService* BatteryStatusService::GetInstance() {
- return Singleton<BatteryStatusService,
- LeakySingletonTraits<BatteryStatusService> >::get();
-}
-
-scoped_ptr<BatteryStatusService::BatteryUpdateSubscription>
-BatteryStatusService::AddCallback(const BatteryUpdateCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!is_shutdown_);
-
- if (!battery_fetcher_)
- battery_fetcher_.reset(new BatteryStatusManager(update_callback_));
-
- if (callback_list_.empty()) {
- bool success = battery_fetcher_->StartListeningBatteryChange();
- if (!success) {
- // Make sure the promise resolves with the default values in Blink.
- callback.Run(blink::WebBatteryStatus());
- }
- }
-
- if (status_updated_) {
- // Send recent status to the new callback if already available.
- callback.Run(status_);
- }
-
- return callback_list_.Add(callback);
-}
-
-void BatteryStatusService::ConsumersChanged() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(!is_shutdown_);
-
- if (callback_list_.empty()) {
- battery_fetcher_->StopListeningBatteryChange();
- status_updated_ = false;
- }
-}
-
-void BatteryStatusService::UpdateBatteryStatus(
- const blink::WebBatteryStatus& status) {
- DCHECK(!is_shutdown_);
- BrowserThread::PostTask(BrowserThread::IO,
- FROM_HERE,
- base::Bind(&BatteryStatusService::NotifyConsumers,
- base::Unretained(this), status));
-}
-
-void BatteryStatusService::NotifyConsumers(
- const blink::WebBatteryStatus& status) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- if (callback_list_.empty())
- return;
-
- status_ = status;
- status_updated_ = true;
- callback_list_.Notify(status);
-}
-
-void BatteryStatusService::Shutdown() {
- if (!callback_list_.empty())
- battery_fetcher_->StopListeningBatteryChange();
- battery_fetcher_.reset();
- is_shutdown_ = true;
-}
-
-const BatteryStatusService::BatteryUpdateCallback&
-BatteryStatusService::GetUpdateCallbackForTesting() const {
- return update_callback_;
-}
-
-void BatteryStatusService::SetBatteryManagerForTesting(
- BatteryStatusManager* test_battery_manager) {
- battery_fetcher_.reset(test_battery_manager);
- blink::WebBatteryStatus status;
- status_ = status;
- status_updated_ = false;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/battery_status/battery_status_service.h b/chromium/content/browser/battery_status/battery_status_service.h
deleted file mode 100644
index 1c1e3648363..00000000000
--- a/chromium/content/browser/battery_status/battery_status_service.h
+++ /dev/null
@@ -1,66 +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_BATTERY_STATUS_BATTERY_STATUS_SERVICE_H_
-#define CONTENT_BROWSER_BATTERY_STATUS_BATTERY_STATUS_SERVICE_H_
-
-#include "base/callback_list.h"
-#include "base/memory/singleton.h"
-#include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebBatteryStatus.h"
-
-namespace content {
-class BatteryStatusManager;
-
-class CONTENT_EXPORT BatteryStatusService {
- public:
- typedef base::Callback<void(const blink::WebBatteryStatus&)>
- BatteryUpdateCallback;
- typedef base::CallbackList<void(const blink::WebBatteryStatus&)>
- BatteryUpdateCallbackList;
- typedef BatteryUpdateCallbackList::Subscription BatteryUpdateSubscription;
-
- // Returns the BatteryStatusService singleton.
- static BatteryStatusService* GetInstance();
-
- // Adds a callback to receive battery status updates.
- // Must be called on the I/O thread.
- scoped_ptr<BatteryUpdateSubscription> AddCallback(
- const BatteryUpdateCallback& callback);
-
- // Gracefully clean-up.
- void Shutdown();
-
- // Injects a custom battery status manager for testing purposes.
- // This class takes ownership of the injected object.
- void SetBatteryManagerForTesting(BatteryStatusManager* test_battery_manager);
-
- // Returns callback to invoke when battery is changed. Used for testing.
- const BatteryUpdateCallback& GetUpdateCallbackForTesting() const;
-
- private:
- friend struct DefaultSingletonTraits<BatteryStatusService>;
-
- BatteryStatusService();
- virtual ~BatteryStatusService();
-
- // Updates current battery status and sends new status to interested
- // render processes. Can be called on any thread via a callback.
- void UpdateBatteryStatus(const blink::WebBatteryStatus& status);
- void NotifyConsumers(const blink::WebBatteryStatus& status);
- void ConsumersChanged();
-
- scoped_ptr<BatteryStatusManager> battery_fetcher_;
- BatteryUpdateCallbackList callback_list_;
- BatteryUpdateCallback update_callback_;
- blink::WebBatteryStatus status_;
- bool status_updated_;
- bool is_shutdown_;
-
- DISALLOW_COPY_AND_ASSIGN(BatteryStatusService);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_BATTERY_STATUS_BATTERY_STATUS_SERVICE_H_
diff --git a/chromium/content/browser/battery_status/battery_status_service_unittest.cc b/chromium/content/browser/battery_status/battery_status_service_unittest.cc
deleted file mode 100644
index f92c8766fc8..00000000000
--- a/chromium/content/browser/battery_status/battery_status_service_unittest.cc
+++ /dev/null
@@ -1,193 +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/battery_status/battery_status_service.h"
-
-#include "base/bind.h"
-#include "base/run_loop.h"
-#include "content/browser/battery_status/battery_status_manager.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-
-namespace content {
-
-namespace {
-
-class FakeBatteryManager : public BatteryStatusManager {
- public:
- explicit FakeBatteryManager(
- const BatteryStatusService::BatteryUpdateCallback& callback)
- : start_invoked_count_(0),
- stop_invoked_count_(0) {
- callback_ = callback;
- }
- virtual ~FakeBatteryManager() { }
-
- // Methods from Battery Status Manager
- virtual bool StartListeningBatteryChange() OVERRIDE {
- start_invoked_count_++;
- return true;
- }
-
- virtual void StopListeningBatteryChange() OVERRIDE {
- stop_invoked_count_++;
- }
-
- void InvokeUpdateCallback(const blink::WebBatteryStatus& status) {
- callback_.Run(status);
- }
-
- int start_invoked_count() const { return start_invoked_count_; }
- int stop_invoked_count() const { return stop_invoked_count_; }
-
- private:
- int start_invoked_count_;
- int stop_invoked_count_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeBatteryManager);
-};
-
-class BatteryStatusServiceTest : public testing::Test {
- public:
- BatteryStatusServiceTest()
- : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
- battery_service_(0),
- battery_manager_(0),
- callback1_invoked_count_(0),
- callback2_invoked_count_(0) {
- }
- virtual ~BatteryStatusServiceTest() { }
-
- protected:
- typedef BatteryStatusService::BatteryUpdateSubscription BatterySubscription;
-
- virtual void SetUp() OVERRIDE {
- callback1_ = base::Bind(&BatteryStatusServiceTest::Callback1,
- base::Unretained(this));
- callback2_ = base::Bind(&BatteryStatusServiceTest::Callback2,
- base::Unretained(this));
- battery_service_ = BatteryStatusService::GetInstance();
- battery_manager_ = new FakeBatteryManager(
- battery_service_->GetUpdateCallbackForTesting());
- battery_service_->SetBatteryManagerForTesting(battery_manager_);
- }
-
- virtual void TearDown() OVERRIDE {
- base::RunLoop().RunUntilIdle();
- battery_service_->SetBatteryManagerForTesting(0);
- }
-
- FakeBatteryManager* battery_manager() {
- return battery_manager_;
- }
-
- scoped_ptr<BatterySubscription> AddCallback(
- const BatteryStatusService::BatteryUpdateCallback& callback) {
- return battery_service_->AddCallback(callback);
- }
-
- int callback1_invoked_count() const {
- return callback1_invoked_count_;
- }
-
- int callback2_invoked_count() const {
- return callback2_invoked_count_;
- }
-
- const blink::WebBatteryStatus& battery_status() const {
- return battery_status_;
- }
-
- const BatteryStatusService::BatteryUpdateCallback& callback1() const {
- return callback1_;
- }
-
- const BatteryStatusService::BatteryUpdateCallback& callback2() const {
- return callback2_;
- }
-
- private:
- void Callback1(const blink::WebBatteryStatus& status) {
- callback1_invoked_count_++;
- battery_status_ = status;
- }
-
- void Callback2(const blink::WebBatteryStatus& status) {
- callback2_invoked_count_++;
- battery_status_ = status;
- }
-
- content::TestBrowserThreadBundle thread_bundle_;
- BatteryStatusService* battery_service_;
- FakeBatteryManager* battery_manager_;
- BatteryStatusService::BatteryUpdateCallback callback1_;
- BatteryStatusService::BatteryUpdateCallback callback2_;
- int callback1_invoked_count_;
- int callback2_invoked_count_;
- blink::WebBatteryStatus battery_status_;
-
- DISALLOW_COPY_AND_ASSIGN(BatteryStatusServiceTest);
-};
-
-TEST_F(BatteryStatusServiceTest, AddFirstCallback) {
- scoped_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
- EXPECT_EQ(1, battery_manager()->start_invoked_count());
- EXPECT_EQ(0, battery_manager()->stop_invoked_count());
- subscription1.reset();
- EXPECT_EQ(1, battery_manager()->start_invoked_count());
- EXPECT_EQ(1, battery_manager()->stop_invoked_count());
-}
-
-TEST_F(BatteryStatusServiceTest, AddCallbackAfterUpdate) {
- scoped_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
- blink::WebBatteryStatus status;
- battery_manager()->InvokeUpdateCallback(status);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, callback1_invoked_count());
- EXPECT_EQ(0, callback2_invoked_count());
-
- scoped_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
- EXPECT_EQ(1, callback1_invoked_count());
- EXPECT_EQ(1, callback2_invoked_count());
-}
-
-TEST_F(BatteryStatusServiceTest, TwoCallbacksUpdate) {
- scoped_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
- scoped_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
-
- blink::WebBatteryStatus status;
- status.charging = true;
- status.chargingTime = 100;
- status.dischargingTime = 200;
- status.level = 0.5;
- battery_manager()->InvokeUpdateCallback(status);
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(1, callback1_invoked_count());
- EXPECT_EQ(1, callback2_invoked_count());
- EXPECT_EQ(status.charging, battery_status().charging);
- EXPECT_EQ(status.chargingTime, battery_status().chargingTime);
- EXPECT_EQ(status.dischargingTime, battery_status().dischargingTime);
- EXPECT_EQ(status.level, battery_status().level);
-}
-
-TEST_F(BatteryStatusServiceTest, RemoveOneCallback) {
- scoped_ptr<BatterySubscription> subscription1 = AddCallback(callback1());
- scoped_ptr<BatterySubscription> subscription2 = AddCallback(callback2());
-
- blink::WebBatteryStatus status;
- battery_manager()->InvokeUpdateCallback(status);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, callback1_invoked_count());
- EXPECT_EQ(1, callback2_invoked_count());
-
- subscription1.reset();
- battery_manager()->InvokeUpdateCallback(status);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, callback1_invoked_count());
- EXPECT_EQ(2, callback2_invoked_count());
-}
-
-} // namespace
-
-} // namespace content
diff --git a/chromium/content/browser/bootstrap_sandbox_mac.cc b/chromium/content/browser/bootstrap_sandbox_mac.cc
index 040a23783ea..2361563b197 100644
--- a/chromium/content/browser/bootstrap_sandbox_mac.cc
+++ b/chromium/content/browser/bootstrap_sandbox_mac.cc
@@ -8,16 +8,9 @@
#include "base/mac/mac_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
-#include "content/browser/mach_broker_mac.h"
#include "content/common/sandbox_init_mac.h"
#include "content/public/browser/browser_child_process_observer.h"
#include "content/public/browser/child_process_data.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_process_host.h"
#include "content/public/common/sandbox_type_mac.h"
#include "sandbox/mac/bootstrap_sandbox.h"
@@ -27,8 +20,7 @@ namespace {
// This class is responsible for creating the BootstrapSandbox global
// singleton, as well as registering all associated policies with it.
-class BootstrapSandboxPolicy : public BrowserChildProcessObserver,
- public NotificationObserver {
+class BootstrapSandboxPolicy : public BrowserChildProcessObserver {
public:
static BootstrapSandboxPolicy* GetInstance();
@@ -37,27 +29,16 @@ class BootstrapSandboxPolicy : public BrowserChildProcessObserver,
}
// BrowserChildProcessObserver:
- virtual void BrowserChildProcessHostDisconnected(
- const ChildProcessData& data) OVERRIDE;
- virtual void BrowserChildProcessCrashed(
- const ChildProcessData& data) OVERRIDE;
-
- // NotificationObserver:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void BrowserChildProcessHostDisconnected(
+ const ChildProcessData& data) override;
+ void BrowserChildProcessCrashed(const ChildProcessData& data) override;
private:
friend struct DefaultSingletonTraits<BootstrapSandboxPolicy>;
BootstrapSandboxPolicy();
- virtual ~BootstrapSandboxPolicy();
+ ~BootstrapSandboxPolicy() override;
void RegisterSandboxPolicies();
- void RegisterRendererPolicy();
-
- void AddBaselinePolicy(sandbox::BootstrapSandboxPolicy* policy);
-
- NotificationRegistrar notification_registrar_;
scoped_ptr<sandbox::BootstrapSandbox> sandbox_;
};
@@ -76,26 +57,10 @@ void BootstrapSandboxPolicy::BrowserChildProcessCrashed(
sandbox()->ChildDied(data.handle);
}
-void BootstrapSandboxPolicy::Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type) {
- case NOTIFICATION_RENDERER_PROCESS_CLOSED:
- sandbox()->ChildDied(
- Details<RenderProcessHost::RendererClosedDetails>(details)->handle);
- break;
- default:
- NOTREACHED() << "Unexpected notification " << type;
- break;
- }
-}
-
BootstrapSandboxPolicy::BootstrapSandboxPolicy()
: sandbox_(sandbox::BootstrapSandbox::Create()) {
CHECK(sandbox_.get());
BrowserChildProcessObserver::Add(this);
- notification_registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
- NotificationService::AllBrowserContextsAndSources());
RegisterSandboxPolicies();
}
@@ -104,42 +69,13 @@ BootstrapSandboxPolicy::~BootstrapSandboxPolicy() {
}
void BootstrapSandboxPolicy::RegisterSandboxPolicies() {
- RegisterRendererPolicy();
-}
-
-void BootstrapSandboxPolicy::RegisterRendererPolicy() {
- sandbox::BootstrapSandboxPolicy policy;
- AddBaselinePolicy(&policy);
-
- // Permit font queries.
- policy.rules["com.apple.FontServer"] = sandbox::Rule(sandbox::POLICY_ALLOW);
- policy.rules["com.apple.FontObjectsServer"] =
- sandbox::Rule(sandbox::POLICY_ALLOW);
-
- // Allow access to the windowserver. This is needed to get the colorspace
- // during sandbox warmup. Since NSColorSpace conforms to NSCoding, this
- // should be plumbed over IPC instead <http://crbug.com/265709>.
- policy.rules["com.apple.windowserver.active"] =
- sandbox::Rule(sandbox::POLICY_ALLOW);
-
- sandbox_->RegisterSandboxPolicy(SANDBOX_TYPE_RENDERER, policy);
-}
-
-void BootstrapSandboxPolicy::AddBaselinePolicy(
- sandbox::BootstrapSandboxPolicy* policy) {
- auto& rules = policy->rules;
-
- // Allow the child to send its task port to the MachBroker.
- rules[MachBroker::GetMachPortName()] = sandbox::Rule(sandbox::POLICY_ALLOW);
-
- // Allow logging to the syslog.
- rules["com.apple.system.logger"] = sandbox::Rule(sandbox::POLICY_ALLOW);
}
} // namespace
bool ShouldEnableBootstrapSandbox() {
- return false;
+ return base::mac::IsOSMountainLionOrEarlier() ||
+ base::mac::IsOSMavericks();
}
sandbox::BootstrapSandbox* GetBootstrapSandbox() {
diff --git a/chromium/content/browser/browser_child_process_host_impl.cc b/chromium/content/browser/browser_child_process_host_impl.cc
index c2d31b8a697..b22ee21aae6 100644
--- a/chromium/content/browser/browser_child_process_host_impl.cc
+++ b/chromium/content/browser/browser_child_process_host_impl.cc
@@ -11,7 +11,6 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
-#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/synchronization/waitable_event.h"
@@ -106,14 +105,12 @@ BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
g_child_process_list.Get().push_back(this);
GetContentClient()->browser()->BrowserChildProcessHostCreated(this);
+
+ power_monitor_message_broadcaster_.Init();
}
BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() {
g_child_process_list.Get().remove(this);
-
-#if defined(OS_WIN)
- DeleteProcessWaitableEvent(early_exit_watcher_.GetWatchedEvent());
-#endif
}
// static
@@ -130,13 +127,14 @@ void BrowserChildProcessHostImpl::TerminateAll() {
void BrowserChildProcessHostImpl::Launch(
SandboxedProcessLauncherDelegate* delegate,
- CommandLine* cmd_line) {
+ base::CommandLine* cmd_line) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
GetContentClient()->browser()->AppendExtraCommandLineSwitches(
cmd_line, data_.id);
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
static const char* kForwardSwitches[] = {
switches::kDisableLogging,
switches::kEnableLogging,
@@ -145,9 +143,6 @@ void BrowserChildProcessHostImpl::Launch(
switches::kTraceToConsole,
switches::kV,
switches::kVModule,
-#if defined(OS_WIN)
- switches::kEnableHighResolutionTime,
-#endif
};
cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
arraysize(kForwardSwitches));
@@ -173,9 +168,9 @@ base::ProcessHandle BrowserChildProcessHostImpl::GetHandle() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(child_process_.get())
<< "Requesting a child process handle before launching.";
- DCHECK(child_process_->GetHandle())
+ DCHECK(child_process_->GetProcess().IsValid())
<< "Requesting a child process handle before launch has completed OK.";
- return child_process_->GetHandle();
+ return child_process_->GetProcess().Handle();
}
void BrowserChildProcessHostImpl::SetName(const base::string16& name) {
@@ -239,7 +234,6 @@ void BrowserChildProcessHostImpl::OnChannelConnected(int32 peer_pid) {
#if defined(OS_WIN)
// From this point onward, the exit of the child process is detected by an
// error on the IPC channel.
- DeleteProcessWaitableEvent(early_exit_watcher_.GetWatchedEvent());
early_exit_watcher_.StopWatching();
#endif
@@ -270,8 +264,12 @@ bool BrowserChildProcessHostImpl::CanShutdown() {
void BrowserChildProcessHostImpl::OnChildDisconnected() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+#if defined(OS_WIN)
+ // OnChildDisconnected may be called without OnChannelConnected, so stop the
+ // early exit watcher so GetTerminationStatus can close the process handle.
+ early_exit_watcher_.StopWatching();
+#endif
if (child_process_.get() || data_.handle) {
- DCHECK(data_.handle != base::kNullProcessHandle);
int exit_code;
base::TerminationStatus status = GetTerminationStatus(
true /* known_dead */, &exit_code);
@@ -321,45 +319,26 @@ void BrowserChildProcessHostImpl::OnProcessLaunchFailed() {
}
void BrowserChildProcessHostImpl::OnProcessLaunched() {
- base::ProcessHandle handle = child_process_->GetHandle();
- if (!handle) {
- delete delegate_; // Will delete us
- return;
- }
+ const base::Process& process = child_process_->GetProcess();
+ DCHECK(process.IsValid());
#if defined(OS_WIN)
// Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
// child process exits. This watcher is stopped once the IPC channel is
// connected and the exit of the child process is detecter by an error on the
// IPC channel thereafter.
- DCHECK(!early_exit_watcher_.GetWatchedEvent());
- early_exit_watcher_.StartWatching(
- new base::WaitableEvent(handle),
- base::Bind(&BrowserChildProcessHostImpl::OnProcessExitedEarly,
- base::Unretained(this)));
+ DCHECK(!early_exit_watcher_.GetWatchedObject());
+ early_exit_watcher_.StartWatching(process.Handle(), this);
#endif
- data_.handle = handle;
+ // TODO(rvargas) crbug.com/417532: Don't store a handle.
+ data_.handle = process.Handle();
delegate_->OnProcessLaunched();
}
#if defined(OS_WIN)
-void BrowserChildProcessHostImpl::DeleteProcessWaitableEvent(
- base::WaitableEvent* event) {
- if (!event)
- return;
-
- // The WaitableEvent does not own the process handle so ensure it does not
- // close it.
- event->Release();
-
- delete event;
-}
-
-void BrowserChildProcessHostImpl::OnProcessExitedEarly(
- base::WaitableEvent* event) {
- DeleteProcessWaitableEvent(event);
+void BrowserChildProcessHostImpl::OnObjectSignaled(HANDLE object) {
OnChildDisconnected();
}
diff --git a/chromium/content/browser/browser_child_process_host_impl.h b/chromium/content/browser/browser_child_process_host_impl.h
index b196551532e..4490b99e142 100644
--- a/chromium/content/browser/browser_child_process_host_impl.h
+++ b/chromium/content/browser/browser_child_process_host_impl.h
@@ -17,6 +17,10 @@
#include "content/public/browser/child_process_data.h"
#include "content/public/common/child_process_host_delegate.h"
+#if defined(OS_WIN)
+#include "base/win/object_watcher.h"
+#endif
+
namespace base {
class CommandLine;
}
@@ -33,37 +37,39 @@ class BrowserMessageFilter;
class CONTENT_EXPORT BrowserChildProcessHostImpl
: public BrowserChildProcessHost,
public NON_EXPORTED_BASE(ChildProcessHostDelegate),
+#if defined(OS_WIN)
+ public base::win::ObjectWatcher::Delegate,
+#endif
public ChildProcessLauncher::Client {
public:
BrowserChildProcessHostImpl(
int process_type,
BrowserChildProcessHostDelegate* delegate);
- virtual ~BrowserChildProcessHostImpl();
+ ~BrowserChildProcessHostImpl() override;
// Terminates all child processes and deletes each BrowserChildProcessHost
// instance.
static void TerminateAll();
// BrowserChildProcessHost implementation:
- virtual bool Send(IPC::Message* message) OVERRIDE;
- virtual void Launch(
- SandboxedProcessLauncherDelegate* delegate,
- base::CommandLine* cmd_line) OVERRIDE;
- virtual const ChildProcessData& GetData() const OVERRIDE;
- virtual ChildProcessHost* GetHost() const OVERRIDE;
- virtual base::TerminationStatus GetTerminationStatus(
- bool known_dead, int* exit_code) OVERRIDE;
- virtual void SetName(const base::string16& name) OVERRIDE;
- virtual void SetHandle(base::ProcessHandle handle) OVERRIDE;
+ bool Send(IPC::Message* message) override;
+ void Launch(SandboxedProcessLauncherDelegate* delegate,
+ base::CommandLine* cmd_line) override;
+ const ChildProcessData& GetData() const override;
+ ChildProcessHost* GetHost() const override;
+ base::TerminationStatus GetTerminationStatus(bool known_dead,
+ int* exit_code) override;
+ void SetName(const base::string16& name) override;
+ void SetHandle(base::ProcessHandle handle) override;
// ChildProcessHostDelegate implementation:
- virtual bool CanShutdown() OVERRIDE;
- virtual void OnChildDisconnected() OVERRIDE;
- virtual base::ProcessHandle GetHandle() const OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
- virtual void OnChannelError() OVERRIDE;
- virtual void OnBadMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool CanShutdown() override;
+ void OnChildDisconnected() override;
+ base::ProcessHandle GetHandle() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnChannelConnected(int32 peer_pid) override;
+ void OnChannelError() override;
+ void OnBadMessageReceived(const IPC::Message& message) override;
// Removes this host from the host list. Calls ChildProcessHost::ForceShutdown
void ForceShutdown();
@@ -96,12 +102,12 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
static void RemoveObserver(BrowserChildProcessObserver* observer);
// ChildProcessLauncher::Client implementation.
- virtual void OnProcessLaunched() OVERRIDE;
- virtual void OnProcessLaunchFailed() OVERRIDE;
+ void OnProcessLaunched() override;
+ void OnProcessLaunchFailed() override;
#if defined(OS_WIN)
- void DeleteProcessWaitableEvent(base::WaitableEvent* event);
- void OnProcessExitedEarly(base::WaitableEvent* event);
+ // ObjectWatcher::Delegate implementation.
+ void OnObjectSignaled(HANDLE object) override;
#endif
ChildProcessData data_;
@@ -116,7 +122,7 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl
// Watches to see if the child process exits before the IPC channel has
// been connected. Thereafter, its exit is determined by an error on the
// IPC channel.
- base::WaitableEventWatcher early_exit_watcher_;
+ base::win::ObjectWatcher early_exit_watcher_;
#endif
};
diff --git a/chromium/content/browser/browser_context.cc b/chromium/content/browser/browser_context.cc
index dbc5949317a..76188331198 100644
--- a/chromium/content/browser/browser_context.cc
+++ b/chromium/content/browser/browser_context.cc
@@ -9,6 +9,7 @@
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/push_messaging/push_messaging_router.h"
#include "content/browser/storage_partition_impl_map.h"
#include "content/common/child_process_host_impl.h"
#include "content/public/browser/blob_handle.h"
@@ -17,12 +18,12 @@
#include "content/public/browser/site_instance.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
-#include "net/ssl/server_bound_cert_service.h"
-#include "net/ssl/server_bound_cert_store.h"
+#include "net/ssl/channel_id_service.h"
+#include "net/ssl/channel_id_store.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
-#include "webkit/browser/database/database_tracker.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
+#include "storage/browser/database/database_tracker.h"
+#include "storage/browser/fileapi/external_mount_points.h"
#endif // !OS_IOS
using base::UserDataAdapter;
@@ -69,11 +70,11 @@ StoragePartition* GetStoragePartitionFromConfig(
void SaveSessionStateOnIOThread(
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
- appcache::AppCacheServiceImpl* appcache_service) {
+ AppCacheServiceImpl* appcache_service) {
net::URLRequestContext* context = context_getter->GetURLRequestContext();
context->cookie_store()->GetCookieMonster()->
SetForceKeepSessionState();
- context->server_bound_cert_service()->GetCertStore()->
+ context->channel_id_service()->GetChannelIDStore()->
SetForceKeepSessionState();
appcache_service->set_force_keep_session_state();
}
@@ -83,6 +84,13 @@ void SaveSessionStateOnIndexedDBThread(
indexed_db_context->SetForceKeepSessionState();
}
+void ShutdownServiceWorkerContext(StoragePartition* partition) {
+ ServiceWorkerContextWrapper* wrapper =
+ static_cast<ServiceWorkerContextWrapper*>(
+ partition->GetServiceWorkerContext());
+ wrapper->process_manager()->Shutdown();
+}
+
} // namespace
// static
@@ -124,7 +132,7 @@ DownloadManager* BrowserContext::GetDownloadManager(
}
// static
-fileapi::ExternalMountPoints* BrowserContext::GetMountPoints(
+storage::ExternalMountPoints* BrowserContext::GetMountPoints(
BrowserContext* context) {
// Ensure that these methods are called on the UI thread, except for
// unittests where a UI thread might not have been created.
@@ -133,15 +141,15 @@ fileapi::ExternalMountPoints* BrowserContext::GetMountPoints(
#if defined(OS_CHROMEOS)
if (!context->GetUserData(kMountPointsKey)) {
- scoped_refptr<fileapi::ExternalMountPoints> mount_points =
- fileapi::ExternalMountPoints::CreateRefCounted();
+ scoped_refptr<storage::ExternalMountPoints> mount_points =
+ storage::ExternalMountPoints::CreateRefCounted();
context->SetUserData(
kMountPointsKey,
- new UserDataAdapter<fileapi::ExternalMountPoints>(mount_points.get()));
+ new UserDataAdapter<storage::ExternalMountPoints>(mount_points.get()));
}
- return UserDataAdapter<fileapi::ExternalMountPoints>::Get(
- context, kMountPointsKey);
+ return UserDataAdapter<storage::ExternalMountPoints>::Get(context,
+ kMountPointsKey);
#else
return NULL;
#endif
@@ -212,6 +220,27 @@ void BrowserContext::CreateMemoryBackedBlob(BrowserContext* browser_context,
callback);
}
+// static
+void BrowserContext::DeliverPushMessage(
+ BrowserContext* browser_context,
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const std::string& data,
+ const base::Callback<void(PushDeliveryStatus)>& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ PushMessagingRouter::DeliverMessage(
+ browser_context, origin, service_worker_registration_id, data, callback);
+}
+
+// static
+void BrowserContext::NotifyWillBeDestroyed(BrowserContext* browser_context) {
+ // Service Workers must shutdown before the browser context is destroyed,
+ // since they keep render process hosts alive and the codebase assumes that
+ // render process hosts die before their profile (browser context) dies.
+ ForEachStoragePartition(browser_context,
+ base::Bind(ShutdownServiceWorkerContext));
+}
+
void BrowserContext::EnsureResourceContextInitialized(BrowserContext* context) {
// This will be enough to tickle initialization of BrowserContext if
// necessary, which initializes ResourceContext. The reason we don't call
@@ -236,7 +265,7 @@ void BrowserContext::SaveSessionState(BrowserContext* browser_context) {
base::Bind(
&SaveSessionStateOnIOThread,
make_scoped_refptr(browser_context->GetRequestContext()),
- static_cast<appcache::AppCacheServiceImpl*>(
+ static_cast<AppCacheServiceImpl*>(
storage_partition->GetAppCacheService())));
}
diff --git a/chromium/content/browser/browser_main_loop.cc b/chromium/content/browser/browser_main_loop.cc
index 8bcc3d33b9d..c7dd81bcf36 100644
--- a/chromium/content/browser/browser_main_loop.cc
+++ b/chromium/content/browser/browser_main_loop.cc
@@ -7,12 +7,10 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
-#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
-#include "base/path_service.h"
#include "base/pending_task.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
@@ -23,7 +21,6 @@
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread_restrictions.h"
#include "base/timer/hi_res_timer_manager.h"
-#include "content/browser/battery_status/battery_status_service.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/device_sensors/device_inertial_sensor_service.h"
#include "content/browser/download/save_file_manager.h"
@@ -35,10 +32,8 @@
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/browser/histogram_synchronizer.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
-#include "content/browser/media/capture/audio_mirroring_manager.h"
#include "content/browser/media/media_internals.h"
#include "content/browser/net/browser_online_state_observer.h"
-#include "content/browser/plugin_service_impl.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/speech/speech_recognition_manager_impl.h"
#include "content/browser/startup_task_runner.h"
@@ -54,6 +49,7 @@
#include "content/public/common/main_function_params.h"
#include "content/public/common/result_codes.h"
#include "crypto/nss_util.h"
+#include "device/battery/battery_status_service.h"
#include "media/audio/audio_manager.h"
#include "media/base/media.h"
#include "media/base/user_input_monitor.h"
@@ -79,13 +75,16 @@
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
#include "content/browser/android/browser_startup_controller.h"
-#include "content/browser/android/surface_texture_peer_browser_impl.h"
+#include "content/browser/android/browser_surface_texture_manager.h"
#include "content/browser/android/tracing_controller_android.h"
+#include "content/browser/screen_orientation/screen_orientation_delegate_android.h"
+#include "content/public/browser/screen_orientation_provider.h"
#include "ui/gl/gl_surface.h"
#endif
#if defined(OS_MACOSX) && !defined(OS_IOS)
#include "content/browser/bootstrap_sandbox_mac.h"
+#include "content/browser/cocoa/system_hotkey_helper_mac.h"
#include "content/browser/theme_helper_mac.h"
#endif
@@ -116,6 +115,10 @@
#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
#endif
+#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
@@ -134,7 +137,7 @@ namespace content {
namespace {
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
-void SetupSandbox(const CommandLine& parsed_command_line) {
+void SetupSandbox(const base::CommandLine& parsed_command_line) {
TRACE_EVENT0("startup", "SetupSandbox");
base::FilePath sandbox_binary;
@@ -238,6 +241,47 @@ bool ShouldInitializeBrowserGpuChannelAndTransportSurface() {
}
#endif
+// Disable optimizations for this block of functions so the compiler doesn't
+// merge them all together. This makes it possible to tell what thread was
+// unresponsive by inspecting the callstack.
+MSVC_DISABLE_OPTIMIZE()
+MSVC_PUSH_DISABLE_WARNING(4748)
+
+NOINLINE void ResetThread_DB(scoped_ptr<BrowserProcessSubThread> thread) {
+ thread.reset();
+}
+
+NOINLINE void ResetThread_FILE(scoped_ptr<BrowserProcessSubThread> thread) {
+ thread.reset();
+}
+
+NOINLINE void ResetThread_FILE_USER_BLOCKING(
+ scoped_ptr<BrowserProcessSubThread> thread) {
+ thread.reset();
+}
+
+NOINLINE void ResetThread_PROCESS_LAUNCHER(
+ scoped_ptr<BrowserProcessSubThread> thread) {
+ thread.reset();
+}
+
+NOINLINE void ResetThread_CACHE(scoped_ptr<BrowserProcessSubThread> thread) {
+ thread.reset();
+}
+
+NOINLINE void ResetThread_IO(scoped_ptr<BrowserProcessSubThread> thread) {
+ thread.reset();
+}
+
+#if !defined(OS_IOS)
+NOINLINE void ResetThread_IndexedDb(scoped_ptr<base::Thread> thread) {
+ thread.reset();
+}
+#endif
+
+MSVC_POP_WARNING()
+MSVC_ENABLE_OPTIMIZE();
+
} // namespace
// The currently-running BrowserMainLoop. There can be one or zero.
@@ -271,12 +315,11 @@ void ImmediateShutdownAndExitProcess() {
class BrowserMainLoop::MemoryObserver : public base::MessageLoop::TaskObserver {
public:
MemoryObserver() {}
- virtual ~MemoryObserver() {}
+ ~MemoryObserver() override {}
- virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE {
- }
+ void WillProcessTask(const base::PendingTask& pending_task) override {}
- virtual void DidProcessTask(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::CreateProcessMetrics(
@@ -287,7 +330,7 @@ class BrowserMainLoop::MemoryObserver : public base::MessageLoop::TaskObserver {
#endif
size_t private_bytes;
process_metrics->GetMemoryBytes(&private_bytes, NULL);
- HISTOGRAM_MEMORY_KB("Memory.BrowserUsed", private_bytes >> 10);
+ LOCAL_HISTOGRAM_MEMORY_KB("Memory.BrowserUsed", private_bytes >> 10);
#endif
}
private:
@@ -465,10 +508,6 @@ void BrowserMainLoop::MainMessageLoopStart() {
}
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:AudioMirroringManager");
- audio_mirroring_manager_.reset(new AudioMirroringManager());
- }
- {
TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:OnlineStateObserver");
online_state_observer_.reset(new BrowserOnlineStateObserver);
}
@@ -498,8 +537,16 @@ void BrowserMainLoop::MainMessageLoopStart() {
#if defined(OS_ANDROID)
{
- TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SurfaceTexturePeer");
- SurfaceTexturePeer::InitInstance(new SurfaceTexturePeerBrowserImpl());
+ TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SurfaceTextureManager");
+ SurfaceTextureManager::InitInstance(new BrowserSurfaceTextureManager);
+ }
+
+ {
+ TRACE_EVENT0("startup",
+ "BrowserMainLoop::Subsystem:ScreenOrientationProvider");
+ screen_orientation_delegate_.reset(
+ new ScreenOrientationDelegateAndroid());
+ ScreenOrientationProvider::SetDelegate(screen_orientation_delegate_.get());
}
#endif
@@ -598,7 +645,6 @@ void BrowserMainLoop::CreateStartupTasks() {
int BrowserMainLoop::CreateThreads() {
TRACE_EVENT0("startup", "BrowserMainLoop::CreateThreads");
- base::Thread::Options default_options;
base::Thread::Options io_message_loop_options;
io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO;
base::Thread::Options ui_message_loop_options;
@@ -613,7 +659,7 @@ int BrowserMainLoop::CreateThreads() {
thread_id < BrowserThread::ID_COUNT;
++thread_id) {
scoped_ptr<BrowserProcessSubThread>* thread_to_start = NULL;
- base::Thread::Options* options = &default_options;
+ base::Thread::Options options;
switch (thread_id) {
case BrowserThread::DB:
@@ -621,6 +667,7 @@ int BrowserMainLoop::CreateThreads() {
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::DB");
thread_to_start = &db_thread_;
+ options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::FILE_USER_BLOCKING:
TRACE_EVENT_BEGIN1("startup",
@@ -637,30 +684,33 @@ int BrowserMainLoop::CreateThreads() {
// On Windows, the FILE thread needs to be have a UI message loop
// which pumps messages in such a way that Google Update can
// communicate back to us.
- options = &ui_message_loop_options;
+ options = ui_message_loop_options;
#else
- options = &io_message_loop_options;
+ options = io_message_loop_options;
#endif
+ options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::PROCESS_LAUNCHER:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::PROCESS_LAUNCHER");
thread_to_start = &process_launcher_thread_;
+ options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::CACHE:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::CACHE");
thread_to_start = &cache_thread_;
- options = &io_message_loop_options;
+ options = io_message_loop_options;
+ options.timer_slack = base::TIMER_SLACK_MAXIMUM;
break;
case BrowserThread::IO:
TRACE_EVENT_BEGIN1("startup",
"BrowserMainLoop::CreateThreads:start",
"Thread", "BrowserThread::IO");
thread_to_start = &io_thread_;
- options = &io_message_loop_options;
+ options = io_message_loop_options;
break;
case BrowserThread::UI:
case BrowserThread::ID_COUNT:
@@ -673,7 +723,9 @@ int BrowserMainLoop::CreateThreads() {
if (thread_to_start) {
(*thread_to_start).reset(new BrowserProcessSubThread(id));
- (*thread_to_start)->StartWithOptions(*options);
+ if (!(*thread_to_start)->StartWithOptions(options)) {
+ LOG(FATAL) << "Failed to start the browser thread: id == " << id;
+ }
} else {
NOTREACHED();
}
@@ -803,42 +855,42 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
// - (Not sure why DB stops last.)
switch (thread_id) {
case BrowserThread::DB: {
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:DBThread");
- db_thread_.reset();
- }
- break;
- case BrowserThread::FILE_USER_BLOCKING: {
- TRACE_EVENT0("shutdown",
- "BrowserMainLoop::Subsystem:FileUserBlockingThread");
- file_user_blocking_thread_.reset();
- }
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:DBThread");
+ ResetThread_DB(db_thread_.Pass());
break;
+ }
case BrowserThread::FILE: {
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:FileThread");
+ 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();
+ // 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)
- file_thread_.reset();
- }
+ ResetThread_FILE(file_thread_.Pass());
+ break;
+ }
+ case BrowserThread::FILE_USER_BLOCKING: {
+ TRACE_EVENT0("shutdown",
+ "BrowserMainLoop::Subsystem:FileUserBlockingThread");
+ ResetThread_FILE_USER_BLOCKING(file_user_blocking_thread_.Pass());
break;
+ }
case BrowserThread::PROCESS_LAUNCHER: {
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:LauncherThread");
- process_launcher_thread_.reset();
- }
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:LauncherThread");
+ ResetThread_PROCESS_LAUNCHER(process_launcher_thread_.Pass());
break;
+ }
case BrowserThread::CACHE: {
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:CacheThread");
- cache_thread_.reset();
- }
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:CacheThread");
+ ResetThread_CACHE(cache_thread_.Pass());
break;
+ }
case BrowserThread::IO: {
- TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread");
- io_thread_.reset();
- }
+ TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread");
+ ResetThread_IO(io_thread_.Pass());
break;
+ }
case BrowserThread::UI:
case BrowserThread::ID_COUNT:
default:
@@ -850,7 +902,7 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
#if !defined(OS_IOS)
{
TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IndexedDBThread");
- indexed_db_thread_.reset();
+ ResetThread_IndexedDb(indexed_db_thread_.Pass());
}
#endif
@@ -886,7 +938,7 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
}
{
TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:BatteryStatusService");
- BatteryStatusService::GetInstance()->Shutdown();
+ device::BatteryStatusService::GetInstance()->Shutdown();
}
{
TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:DeleteDataSources");
@@ -900,6 +952,10 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
}
}
+void BrowserMainLoop::StopStartupTracingTimer() {
+ startup_trace_timer_.Stop();
+}
+
void BrowserMainLoop::InitializeMainThread() {
TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread");
const char* kThreadName = "CrBrowserMain";
@@ -959,8 +1015,7 @@ int BrowserMainLoop::BrowserThreadsStarted() {
ImageTransportFactory::Initialize();
#if defined(USE_AURA)
if (aura::Env::GetInstance()) {
- aura::Env::GetInstance()->set_context_factory(
- content::GetContextFactory());
+ aura::Env::GetInstance()->set_context_factory(GetContextFactory());
}
#endif
}
@@ -1041,6 +1096,7 @@ int BrowserMainLoop::BrowserThreadsStarted() {
#if defined(OS_MACOSX)
ThemeHelperMac::GetInstance();
+ SystemHotkeyHelperMac::GetInstance()->DeferredLoadSystemHotkeys();
if (ShouldEnableBootstrapSandbox()) {
TRACE_EVENT0("startup",
"BrowserMainLoop::BrowserThreadsStarted:BootstrapSandbox");
@@ -1104,16 +1160,15 @@ void BrowserMainLoop::MainMessageLoopRun() {
#endif
}
-void BrowserMainLoop::InitStartupTracing(const CommandLine& command_line) {
- DCHECK(is_tracing_startup_);
-
+base::FilePath BrowserMainLoop::GetStartupTraceFileName(
+ const base::CommandLine& command_line) const {
base::FilePath trace_file = command_line.GetSwitchValuePath(
switches::kTraceStartupFile);
// trace_file = "none" means that startup events will show up for the next
// begin/end tracing (via about:tracing or AutomationProxy::BeginTracing/
// EndTracing, for example).
if (trace_file == base::FilePath().AppendASCII("none"))
- return;
+ return trace_file;
if (trace_file.empty()) {
#if defined(OS_ANDROID)
@@ -1124,6 +1179,15 @@ void BrowserMainLoop::InitStartupTracing(const CommandLine& command_line) {
#endif
}
+ return trace_file;
+}
+
+void BrowserMainLoop::InitStartupTracing(
+ const base::CommandLine& command_line) {
+ DCHECK(is_tracing_startup_);
+
+ startup_trace_file_ = GetStartupTraceFileName(parsed_command_line_);
+
std::string delay_str = command_line.GetSwitchValueASCII(
switches::kTraceStartupDuration);
int delay_secs = 5;
@@ -1133,17 +1197,18 @@ void BrowserMainLoop::InitStartupTracing(const CommandLine& command_line) {
delay_secs = 5;
}
- BrowserThread::PostDelayedTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&BrowserMainLoop::EndStartupTracing,
- base::Unretained(this), trace_file),
- base::TimeDelta::FromSeconds(delay_secs));
+ startup_trace_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromSeconds(delay_secs),
+ this,
+ &BrowserMainLoop::EndStartupTracing);
}
-void BrowserMainLoop::EndStartupTracing(const base::FilePath& trace_file) {
+void BrowserMainLoop::EndStartupTracing() {
is_tracing_startup_ = false;
TracingController::GetInstance()->DisableRecording(
- trace_file, base::Bind(&OnStoppedStartupTracing));
+ TracingController::CreateFileSink(
+ startup_trace_file_,
+ base::Bind(OnStoppedStartupTracing, startup_trace_file_)));
}
} // namespace content
diff --git a/chromium/content/browser/browser_main_loop.h b/chromium/content/browser/browser_main_loop.h
index f38ac4234ab..188aa3209d3 100644
--- a/chromium/content/browser/browser_main_loop.h
+++ b/chromium/content/browser/browser_main_loop.h
@@ -6,8 +6,10 @@
#define CONTENT_BROWSER_BROWSER_MAIN_LOOP_H_
#include "base/basictypes.h"
+#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/timer/timer.h"
#include "content/browser/browser_process_sub_thread.h"
#include "content/public/browser/browser_main_runner.h"
@@ -35,7 +37,6 @@ class NetworkChangeNotifier;
} // namespace net
namespace content {
-class AudioMirroringManager;
class BrowserMainParts;
class BrowserOnlineStateObserver;
class BrowserShutdownImpl;
@@ -47,7 +48,9 @@ class StartupTaskRunner;
class TimeZoneMonitor;
struct MainFunctionParams;
-#if defined(OS_LINUX)
+#if defined(OS_ANDROID)
+class ScreenOrientationDelegate;
+#elif defined(OS_LINUX)
class DeviceMonitorLinux;
#elif defined(OS_MACOSX)
class DeviceMonitorMac;
@@ -90,9 +93,6 @@ class CONTENT_EXPORT BrowserMainLoop {
int GetResultCode() const { return result_code_; }
media::AudioManager* audio_manager() const { return audio_manager_.get(); }
- AudioMirroringManager* audio_mirroring_manager() const {
- return audio_mirroring_manager_.get();
- }
MediaStreamManager* media_stream_manager() const {
return media_stream_manager_.get();
}
@@ -104,6 +104,12 @@ class CONTENT_EXPORT BrowserMainLoop {
bool is_tracing_startup() const { return is_tracing_startup_; }
+ const base::FilePath& startup_trace_file() const {
+ return startup_trace_file_;
+ }
+
+ void StopStartupTracingTimer();
+
#if defined(OS_MACOSX) && !defined(OS_IOS)
DeviceMonitorMac* device_monitor_mac() const {
return device_monitor_mac_.get();
@@ -130,8 +136,10 @@ class CONTENT_EXPORT BrowserMainLoop {
void MainMessageLoopRun();
+ base::FilePath GetStartupTraceFileName(
+ const base::CommandLine& command_line) const;
void InitStartupTracing(const base::CommandLine& command_line);
- void EndStartupTracing(const base::FilePath& trace_file);
+ void EndStartupTracing();
// Members initialized on construction ---------------------------------------
const MainFunctionParams& parameters_;
@@ -150,7 +158,6 @@ class CONTENT_EXPORT BrowserMainLoop {
scoped_ptr<media::UserInputMonitor> user_input_monitor_;
scoped_ptr<media::AudioManager> audio_manager_;
scoped_ptr<media::MidiManager> midi_manager_;
- scoped_ptr<AudioMirroringManager> audio_mirroring_manager_;
scoped_ptr<MediaStreamManager> media_stream_manager_;
// Per-process listener for online state changes.
scoped_ptr<BrowserOnlineStateObserver> online_state_observer_;
@@ -161,6 +168,10 @@ class CONTENT_EXPORT BrowserMainLoop {
#elif defined(OS_MACOSX) && !defined(OS_IOS)
scoped_ptr<DeviceMonitorMac> device_monitor_mac_;
#endif
+#if defined(OS_ANDROID)
+ // Android implementation of ScreenOrientationDelegate
+ scoped_ptr<ScreenOrientationDelegate> screen_orientation_delegate_;
+#endif
// The startup task runner is created by CreateStartupTasks()
scoped_ptr<StartupTaskRunner> startup_task_runner_;
@@ -190,6 +201,10 @@ class CONTENT_EXPORT BrowserMainLoop {
scoped_ptr<base::debug::TraceEventSystemStatsMonitor> system_stats_monitor_;
bool is_tracing_startup_;
+ base::FilePath startup_trace_file_;
+
+ // This timer initiates trace file saving.
+ base::OneShotTimer<BrowserMainLoop> startup_trace_timer_;
DISALLOW_COPY_AND_ASSIGN(BrowserMainLoop);
};
diff --git a/chromium/content/browser/browser_main_runner.cc b/chromium/content/browser/browser_main_runner.cc
index c41fc9541c9..4a74b6eb5f8 100644
--- a/chromium/content/browser/browser_main_runner.cc
+++ b/chromium/content/browser/browser_main_runner.cc
@@ -20,25 +20,146 @@
#include "ui/base/ime/input_method_initializer.h"
#if defined(OS_WIN)
+#include <dwrite.h>
+#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 "skia/ext/fontmgr_default_win.h"
+#include "third_party/skia/include/ports/SkFontMgr.h"
+#include "third_party/skia/include/ports/SkTypeface_win.h"
#include "ui/base/win/scoped_ole_initializer.h"
+#include "ui/gfx/platform_font_win.h"
+#include "ui/gfx/switches.h"
+#include "ui/gfx/win/direct_write.h"
#endif
bool g_exited_main_message_loop = false;
namespace content {
+#if defined(OS_WIN)
+namespace {
+
+// 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);
+}
+
+// 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
+}
+
+void MaybeEnableDirectWriteFontRendering() {
+ if (gfx::win::ShouldUseDirectWrite() &&
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableDirectWriteForUI) &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableHarfBuzzRenderText)) {
+ typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc;
+ HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll");
+ if (!dwrite_dll)
+ return;
+
+ DWriteCreateFactoryProc dwrite_create_factory_proc =
+ reinterpret_cast<DWriteCreateFactoryProc>(
+ GetProcAddress(dwrite_dll, "DWriteCreateFactory"));
+ // Not finding the DWriteCreateFactory function indicates a corrupt dll.
+ CHECK(dwrite_create_factory_proc);
+
+ IDWriteFactory* factory = NULL;
+
+ CHECK(SUCCEEDED(
+ dwrite_create_factory_proc(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(&factory))));
+ SetDefaultSkiaFactory(SkFontMgr_New_DirectWrite(factory));
+ gfx::PlatformFontWin::set_use_skia_for_font_metrics(true);
+ }
+}
+
+} // namespace
+
+#endif // OS_WIN
+
class BrowserMainRunnerImpl : public BrowserMainRunner {
public:
BrowserMainRunnerImpl()
: initialization_started_(false), is_shutdown_(false) {}
- virtual ~BrowserMainRunnerImpl() {
+ ~BrowserMainRunnerImpl() override {
if (initialization_started_ && !is_shutdown_)
Shutdown();
}
- virtual int Initialize(const MainFunctionParams& parameters) OVERRIDE {
+ int Initialize(const MainFunctionParams& parameters) override {
TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize");
// On Android we normally initialize the browser in a series of UI thread
// tasks. While this is happening a second request can come from the OS or
@@ -64,6 +185,7 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
// Win32 API here directly.
ImmDisableTextFrameService(static_cast<DWORD>(-1));
}
+ InstallSha256LegacyHooks();
#endif // OS_WIN
base::StatisticsRecorder::Initialize();
@@ -75,6 +197,8 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
// (Text Services Framework) module can interact with the message pump
// on Windows 8 Metro mode.
ole_initializer_.reset(new ui::ScopedOleInitializer);
+ // Enable DirectWrite font rendering if needed.
+ MaybeEnableDirectWriteFontRendering();
#endif // OS_WIN
main_loop_.reset(new BrowserMainLoop(parameters));
@@ -112,14 +236,14 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
return -1;
}
- virtual int Run() OVERRIDE {
+ int Run() override {
DCHECK(initialization_started_);
DCHECK(!is_shutdown_);
main_loop_->RunMainMessageLoopParts();
return main_loop_->GetResultCode();
}
- virtual void Shutdown() OVERRIDE {
+ void Shutdown() override {
DCHECK(initialization_started_);
DCHECK(!is_shutdown_);
#ifdef LEAK_SANITIZER
@@ -130,13 +254,29 @@ class BrowserMainRunnerImpl : public BrowserMainRunner {
// If leaks are found, the process will exit here.
__lsan_do_leak_check();
#endif
+ // If startup tracing has not been finished yet, replace it's dumper
+ // with special version, which would save trace file on exit (i.e.
+ // startup tracing becomes a version of shutdown tracing).
+ scoped_ptr<BrowserShutdownProfileDumper> startup_profiler;
+ if (main_loop_->is_tracing_startup()) {
+ main_loop_->StopStartupTracingTimer();
+ if (main_loop_->startup_trace_file() !=
+ base::FilePath().AppendASCII("none")) {
+ startup_profiler.reset(
+ new BrowserShutdownProfileDumper(main_loop_->startup_trace_file()));
+ }
+ }
+
// The shutdown tracing got enabled in AttemptUserExit earlier, but someone
// needs to write the result to disc. For that a dumper needs to get created
// which will dump the traces to disc when it gets destroyed.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- scoped_ptr<BrowserShutdownProfileDumper> profiler;
- if (command_line.HasSwitch(switches::kTraceShutdown))
- profiler.reset(new BrowserShutdownProfileDumper());
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ scoped_ptr<BrowserShutdownProfileDumper> shutdown_profiler;
+ if (command_line.HasSwitch(switches::kTraceShutdown)) {
+ shutdown_profiler.reset(new BrowserShutdownProfileDumper(
+ BrowserShutdownProfileDumper::GetShutdownProfileFileName()));
+ }
{
// The trace event has to stay between profiler creation and destruction.
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc b/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
index 30b47890802..cb471594ac8 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_embedder.cc
@@ -22,12 +22,14 @@
#include "content/public/common/result_codes.h"
#include "content/public/common/url_constants.h"
#include "net/base/escape.h"
+#include "third_party/WebKit/public/web/WebFindOptions.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace content {
BrowserPluginEmbedder::BrowserPluginEmbedder(WebContentsImpl* web_contents)
: WebContentsObserver(web_contents),
+ guest_drag_ending_(false),
weak_ptr_factory_(this) {
}
@@ -54,6 +56,7 @@ void BrowserPluginEmbedder::DragLeftGuest(BrowserPluginGuest* guest) {
void BrowserPluginEmbedder::StartDrag(BrowserPluginGuest* guest) {
guest_started_drag_ = guest->AsWeakPtr();
+ guest_drag_ending_ = false;
}
WebContentsImpl* BrowserPluginEmbedder::GetWebContents() const {
@@ -65,6 +68,20 @@ BrowserPluginEmbedder::GetBrowserPluginGuestManager() const {
return GetWebContents()->GetBrowserContext()->GetGuestManager();
}
+void BrowserPluginEmbedder::ClearGuestDragStateIfApplicable() {
+ // The order at which we observe SystemDragEnded() and DragSourceEndedAt() is
+ // platform dependent.
+ // In OSX, we see SystemDragEnded() first, where in aura, we see
+ // DragSourceEndedAt() first. For this reason, we check if both methods were
+ // called before resetting |guest_started_drag_|.
+ if (guest_drag_ending_) {
+ if (guest_started_drag_)
+ guest_started_drag_.reset();
+ } else {
+ guest_drag_ending_ = true;
+ }
+}
+
bool BrowserPluginEmbedder::DidSendScreenRectsCallback(
WebContents* guest_web_contents) {
static_cast<RenderViewHostImpl*>(
@@ -93,64 +110,93 @@ bool BrowserPluginEmbedder::OnMessageReceived(const IPC::Message& message) {
void BrowserPluginEmbedder::DragSourceEndedAt(int client_x, int client_y,
int screen_x, int screen_y, blink::WebDragOperation operation) {
- if (guest_started_drag_.get()) {
+ if (guest_started_drag_) {
gfx::Point guest_offset =
guest_started_drag_->GetScreenCoordinates(gfx::Point());
guest_started_drag_->DragSourceEndedAt(client_x - guest_offset.x(),
client_y - guest_offset.y(), screen_x, screen_y, operation);
}
+ ClearGuestDragStateIfApplicable();
}
void BrowserPluginEmbedder::SystemDragEnded() {
// When the embedder's drag/drop operation ends, we need to pass the message
// to the guest that initiated the drag/drop operation. This will ensure that
// the guest's RVH state is reset properly.
- if (guest_started_drag_.get())
+ if (guest_started_drag_)
guest_started_drag_->EndSystemDrag();
- guest_started_drag_.reset();
guest_dragging_over_.reset();
+ ClearGuestDragStateIfApplicable();
}
void BrowserPluginEmbedder::OnUpdateDragCursor(bool* handled) {
*handled = (guest_dragging_over_.get() != NULL);
}
-void BrowserPluginEmbedder::OnGuestCallback(
- int instance_id,
- const BrowserPluginHostMsg_Attach_Params& params,
- const base::DictionaryValue* extra_params,
- WebContents* guest_web_contents) {
- BrowserPluginGuest* guest = guest_web_contents ?
- static_cast<WebContentsImpl*>(guest_web_contents)->
- GetBrowserPluginGuest() : NULL;
- if (!guest) {
- scoped_ptr<base::DictionaryValue> copy_extra_params(
- extra_params->DeepCopy());
- guest_web_contents = GetBrowserPluginGuestManager()->CreateGuest(
- GetWebContents()->GetSiteInstance(),
- instance_id,
- copy_extra_params.Pass());
- guest = guest_web_contents
- ? static_cast<WebContentsImpl*>(guest_web_contents)
- ->GetBrowserPluginGuest()
- : NULL;
+void BrowserPluginEmbedder::OnAttach(
+ int browser_plugin_instance_id,
+ const BrowserPluginHostMsg_Attach_Params& params) {
+ WebContents* guest_web_contents =
+ GetBrowserPluginGuestManager()->GetGuestByInstanceID(
+ GetWebContents(), browser_plugin_instance_id);
+ if (!guest_web_contents)
+ return;
+ BrowserPluginGuest* guest = static_cast<WebContentsImpl*>(guest_web_contents)
+ ->GetBrowserPluginGuest();
+ guest->Attach(browser_plugin_instance_id, GetWebContents(), params);
+}
+
+bool BrowserPluginEmbedder::HandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event) {
+ if ((event.windowsKeyCode != ui::VKEY_ESCAPE) ||
+ (event.modifiers & blink::WebInputEvent::InputModifiers)) {
+ return false;
}
- if (guest)
- guest->Attach(GetWebContents(), params, *extra_params);
+ bool event_consumed = false;
+ GetBrowserPluginGuestManager()->ForEachGuest(
+ GetWebContents(),
+ base::Bind(&BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback,
+ base::Unretained(this),
+ &event_consumed));
+
+ return event_consumed;
}
-void BrowserPluginEmbedder::OnAttach(
- int instance_id,
- const BrowserPluginHostMsg_Attach_Params& params,
- const base::DictionaryValue& extra_params) {
- GetBrowserPluginGuestManager()->MaybeGetGuestByInstanceIDOrKill(
- instance_id, GetWebContents()->GetRenderProcessHost()->GetID(),
- base::Bind(&BrowserPluginEmbedder::OnGuestCallback,
+bool BrowserPluginEmbedder::Find(int request_id,
+ const base::string16& search_text,
+ const blink::WebFindOptions& options) {
+ return GetBrowserPluginGuestManager()->ForEachGuest(
+ GetWebContents(),
+ base::Bind(&BrowserPluginEmbedder::FindInGuest,
base::Unretained(this),
- instance_id,
- params,
- &extra_params));
+ request_id,
+ search_text,
+ options));
+}
+
+bool BrowserPluginEmbedder::UnlockMouseIfNecessaryCallback(bool* mouse_unlocked,
+ WebContents* guest) {
+ *mouse_unlocked |= static_cast<WebContentsImpl*>(guest)
+ ->GetBrowserPluginGuest()
+ ->mouse_locked();
+ guest->GotResponseToLockMouseRequest(false);
+
+ // Returns false to iterate over all guests.
+ return false;
+}
+
+bool BrowserPluginEmbedder::FindInGuest(int request_id,
+ const base::string16& search_text,
+ const blink::WebFindOptions& options,
+ WebContents* guest) {
+ if (static_cast<WebContentsImpl*>(guest)->GetBrowserPluginGuest()->Find(
+ request_id, search_text, options)) {
+ // There can only ever currently be one browser plugin that handles find so
+ // we can break the iteration at this point.
+ return true;
+ }
+ return false;
}
} // namespace content
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_embedder.h b/chromium/content/browser/browser_plugin/browser_plugin_embedder.h
index 3c35bef17a7..7ea98f7773a 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_embedder.h
+++ b/chromium/content/browser/browser_plugin/browser_plugin_embedder.h
@@ -39,7 +39,7 @@ struct NativeWebKeyboardEvent;
class CONTENT_EXPORT BrowserPluginEmbedder : public WebContentsObserver {
public:
- virtual ~BrowserPluginEmbedder();
+ ~BrowserPluginEmbedder() override;
static BrowserPluginEmbedder* Create(WebContentsImpl* web_contents);
@@ -50,7 +50,7 @@ class CONTENT_EXPORT BrowserPluginEmbedder : public WebContentsObserver {
void DidSendScreenRects();
// WebContentsObserver implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
void DragSourceEndedAt(int client_x, int client_y, int screen_x,
int screen_y, blink::WebDragOperation operation);
@@ -67,30 +67,34 @@ class CONTENT_EXPORT BrowserPluginEmbedder : public WebContentsObserver {
// operation, if there's any.
void SystemDragEnded();
+ // Used to handle special keyboard events.
+ bool HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
+
+ // Find the given |search_text| in the page. Returns true if the find request
+ // is handled by this browser plugin embedder.
+ bool Find(int request_id,
+ const base::string16& search_text,
+ const blink::WebFindOptions& options);
+
private:
explicit BrowserPluginEmbedder(WebContentsImpl* web_contents);
BrowserPluginGuestManager* GetBrowserPluginGuestManager() const;
- bool DidSendScreenRectsCallback(WebContents* guest_web_contents);
+ void ClearGuestDragStateIfApplicable();
- bool SetZoomLevelCallback(double level, WebContents* guest_web_contents);
+ bool DidSendScreenRectsCallback(WebContents* guest_web_contents);
- bool UnlockMouseIfNecessaryCallback(const NativeWebKeyboardEvent& event,
- WebContents* guest);
+ bool UnlockMouseIfNecessaryCallback(bool* mouse_unlocked, WebContents* guest);
- // Called by the content embedder when a guest exists with the provided
- // |instance_id|.
- void OnGuestCallback(int instance_id,
- const BrowserPluginHostMsg_Attach_Params& params,
- const base::DictionaryValue* extra_params,
- WebContents* guest_web_contents);
+ bool FindInGuest(int request_id,
+ const base::string16& search_text,
+ const blink::WebFindOptions& options,
+ WebContents* guest);
// Message handlers.
-
void OnAttach(int instance_id,
- const BrowserPluginHostMsg_Attach_Params& params,
- const base::DictionaryValue& extra_params);
+ const BrowserPluginHostMsg_Attach_Params& params);
void OnPluginAtPositionResponse(int instance_id,
int request_id,
const gfx::Point& position);
@@ -106,6 +110,9 @@ class CONTENT_EXPORT BrowserPluginEmbedder : public WebContentsObserver {
// status messages to the correct guest.
base::WeakPtr<BrowserPluginGuest> guest_started_drag_;
+ // Keeps track of "dragend" state.
+ bool guest_drag_ending_;
+
base::WeakPtrFactory<BrowserPluginEmbedder> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BrowserPluginEmbedder);
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_guest.cc b/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
index b3bd05a6b21..c2db313eedd 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/message_loop/message_loop.h"
+#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/browser_plugin/browser_plugin_embedder.h"
#include "content/browser/browser_thread_impl.h"
@@ -19,9 +20,12 @@
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/browser/web_contents/web_contents_view_guest.h"
+#include "content/common/browser_plugin/browser_plugin_constants.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
#include "content/common/content_constants_internal.h"
#include "content/common/drag_messages.h"
+#include "content/common/frame_messages.h"
+#include "content/common/host_shared_bitmap_manager.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
@@ -31,7 +35,7 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/drop_data.h"
-#include "third_party/WebKit/public/platform/WebCursorInfo.h"
+#include "ui/gfx/geometry/size_conversions.h"
#if defined(OS_MACOSX)
#include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
@@ -47,15 +51,14 @@ class BrowserPluginGuest::EmbedderWebContentsObserver
browser_plugin_guest_(guest) {
}
- virtual ~EmbedderWebContentsObserver() {
- }
+ ~EmbedderWebContentsObserver() override {}
// WebContentsObserver implementation.
- virtual void WasShown() OVERRIDE {
+ void WasShown() override {
browser_plugin_guest_->EmbedderVisibilityChanged(true);
}
- virtual void WasHidden() OVERRIDE {
+ void WasHidden() override {
browser_plugin_guest_->EmbedderVisibilityChanged(false);
}
@@ -65,43 +68,72 @@ class BrowserPluginGuest::EmbedderWebContentsObserver
DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
};
-BrowserPluginGuest::BrowserPluginGuest(
- int instance_id,
- bool has_render_view,
- WebContentsImpl* web_contents)
+BrowserPluginGuest::BrowserPluginGuest(bool has_render_view,
+ WebContentsImpl* web_contents,
+ BrowserPluginGuestDelegate* delegate)
: WebContentsObserver(web_contents),
embedder_web_contents_(NULL),
- instance_id_(instance_id),
+ browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
guest_device_scale_factor_(1.0f),
focused_(false),
mouse_locked_(false),
pending_lock_request_(false),
guest_visible_(false),
- guest_opaque_(true),
embedder_visible_(true),
- auto_size_enabled_(false),
- copy_request_id_(0),
+ is_full_page_plugin_(false),
has_render_view_(has_render_view),
- last_seen_auto_size_enabled_(false),
is_in_destruction_(false),
last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
+ last_input_flags_(0),
last_can_compose_inline_(true),
- delegate_(NULL),
+ guest_proxy_routing_id_(MSG_ROUTING_NONE),
+ delegate_(delegate),
weak_ptr_factory_(this) {
DCHECK(web_contents);
+ DCHECK(delegate);
+ RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
+ web_contents->SetBrowserPluginGuest(this);
+ delegate->RegisterDestructionCallback(
+ base::Bind(&BrowserPluginGuest::WillDestroy, AsWeakPtr()));
}
void BrowserPluginGuest::WillDestroy() {
is_in_destruction_ = true;
embedder_web_contents_ = NULL;
- delegate_ = NULL;
}
base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
+void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh, bool focused) {
+ focused_ = focused;
+ if (!rwh)
+ return;
+
+ rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused));
+ if (!focused && mouse_locked_)
+ OnUnlockMouse();
+
+ // Restore the last seen state of text input to the view.
+ RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
+ rwh->GetView());
+ if (rwhv) {
+ rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_,
+ last_can_compose_inline_, last_input_flags_);
+ }
+}
+
+void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) {
+ if (tooltip_text == current_tooltip_text_)
+ return;
+ current_tooltip_text_ = tooltip_text;
+
+ SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
+ browser_plugin_instance_id_, tooltip_text));
+}
+
bool BrowserPluginGuest::LockMouse(bool allowed) {
if (!attached() || (mouse_locked_ == allowed))
return false;
@@ -109,43 +141,47 @@ bool BrowserPluginGuest::LockMouse(bool allowed) {
return embedder_web_contents()->GotResponseToLockMouseRequest(allowed);
}
-void BrowserPluginGuest::Destroy() {
- if (!delegate_)
- return;
- delegate_->Destroy();
+WebContentsImpl* BrowserPluginGuest::CreateNewGuestWindow(
+ const WebContents::CreateParams& params) {
+ WebContentsImpl* new_contents =
+ static_cast<WebContentsImpl*>(delegate_->CreateNewGuestWindow(params));
+ DCHECK(new_contents);
+ return new_contents;
}
bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
const IPC::Message& message) {
+ RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
+ web_contents()->GetRenderWidgetHostView());
+ if (rwhv &&
+ rwhv->OnMessageReceivedFromEmbedder(
+ message,
+ static_cast<RenderViewHostImpl*>(
+ embedder_web_contents()->GetRenderViewHost()))) {
+ return true;
+ }
+
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
OnCompositorFrameSwappedACK)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CopyFromCompositingSurfaceAck,
- OnCopyFromCompositingSurfaceAck)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
OnDragStatusUpdate)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
OnExecuteEditCommand)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
OnExtendSelectionAndDelete)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
- OnHandleInputEvent)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
OnImeConfirmComposition)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
OnImeSetComposition)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
OnReclaimCompositorResources)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetAutoSize)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
OnSetEditCommandsForNextKeyEvent)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetContentsOpaque,
- OnSetContentsOpaque)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
@@ -155,26 +191,25 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
}
void BrowserPluginGuest::Initialize(
+ int browser_plugin_instance_id,
const BrowserPluginHostMsg_Attach_Params& params,
- WebContentsImpl* embedder_web_contents,
- const base::DictionaryValue& extra_params) {
+ WebContentsImpl* embedder_web_contents) {
+ browser_plugin_instance_id_ = browser_plugin_instance_id;
focused_ = params.focused;
guest_visible_ = params.visible;
- guest_opaque_ = params.opaque;
+ is_full_page_plugin_ = params.is_full_page_plugin;
guest_window_rect_ = gfx::Rect(params.origin,
params.resize_guest_params.view_size);
- auto_size_enabled_ = params.auto_size_params.enable;
- max_auto_size_ = params.auto_size_params.max_size;
- min_auto_size_ = params.auto_size_params.min_size;
+ WebContentsViewGuest* new_view =
+ static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
+ if (attached())
+ new_view->OnGuestDetached(embedder_web_contents_->GetView());
// Once a BrowserPluginGuest has an embedder WebContents, it's considered to
// be attached.
embedder_web_contents_ = embedder_web_contents;
-
- WebContentsViewGuest* new_view =
- static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
- new_view->OnGuestInitialized(embedder_web_contents->GetView());
+ new_view->OnGuestAttached(embedder_web_contents->GetView());
RendererPreferences* renderer_prefs =
GetWebContents()->GetMutableRendererPrefs();
@@ -200,19 +235,12 @@ void BrowserPluginGuest::Initialize(
embedder_web_contents_observer_.reset(new EmbedderWebContentsObserver(this));
- OnSetAutoSize(
- instance_id_, params.auto_size_params, params.resize_guest_params);
-
- // Create a swapped out RenderView for the guest in the embedder render
- // process, so that the embedder can access the guest's window object.
- int guest_routing_id =
- GetWebContents()->CreateSwappedOutRenderView(
- embedder_web_contents_->GetSiteInstance());
- SendMessageToEmbedder(
- new BrowserPluginMsg_GuestContentWindowReady(instance_id_,
- guest_routing_id));
+ OnResizeGuest(browser_plugin_instance_id_, params.resize_guest_params);
- WebPreferences prefs = GetWebContents()->GetWebkitPrefs();
+ // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
+ // be reset again the next time preferences are updated.
+ WebPreferences prefs =
+ GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
prefs.navigate_on_drag_drop = false;
GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
@@ -225,7 +253,8 @@ void BrowserPluginGuest::Initialize(
}
// Inform the embedder of the guest's attachment.
- SendMessageToEmbedder(new BrowserPluginMsg_Attach_ACK(instance_id_));
+ SendMessageToEmbedder(
+ new BrowserPluginMsg_Attach_ACK(browser_plugin_instance_id_));
}
BrowserPluginGuest::~BrowserPluginGuest() {
@@ -233,35 +262,10 @@ BrowserPluginGuest::~BrowserPluginGuest() {
// static
BrowserPluginGuest* BrowserPluginGuest::Create(
- int instance_id,
- SiteInstance* guest_site_instance,
WebContentsImpl* web_contents,
- scoped_ptr<base::DictionaryValue> extra_params,
- BrowserPluginGuest* opener) {
- RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
- BrowserPluginGuest* guest = new BrowserPluginGuest(
- instance_id, web_contents->opener() != NULL, web_contents);
- web_contents->SetBrowserPluginGuest(guest);
- WebContents* opener_web_contents = NULL;
- if (opener) {
- opener_web_contents = opener->GetWebContents();
- guest_site_instance = opener_web_contents->GetSiteInstance();
- }
- BrowserPluginGuestDelegate* delegate = NULL;
- GetContentClient()->browser()->GuestWebContentsCreated(
- instance_id,
- guest_site_instance,
- web_contents,
- opener_web_contents,
- &delegate,
- extra_params.Pass());
- if (delegate) {
- delegate->RegisterDestructionCallback(
- base::Bind(&BrowserPluginGuest::WillDestroy,
- base::Unretained(guest)));
- guest->set_delegate(delegate);
- }
- return guest;
+ BrowserPluginGuestDelegate* delegate) {
+ return new BrowserPluginGuest(
+ web_contents->opener() != NULL, web_contents, delegate);
}
// static
@@ -283,17 +287,7 @@ RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
}
void BrowserPluginGuest::UpdateVisibility() {
- OnSetVisibility(instance_id_, visible());
-}
-
-void BrowserPluginGuest::CopyFromCompositingSurface(
- gfx::Rect src_subrect,
- gfx::Size dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback) {
- copy_request_callbacks_.insert(std::make_pair(++copy_request_id_, callback));
- SendMessageToEmbedder(
- new BrowserPluginMsg_CopyFromCompositingSurface(instance_id(),
- copy_request_id_, src_subrect, dst_size));
+ OnSetVisibility(browser_plugin_instance_id(), visible());
}
BrowserPluginGuestManager*
@@ -301,13 +295,6 @@ BrowserPluginGuest::GetBrowserPluginGuestManager() const {
return GetWebContents()->GetBrowserContext()->GetGuestManager();
}
-// screen.
-gfx::Rect BrowserPluginGuest::ToGuestRect(const gfx::Rect& bounds) {
- gfx::Rect guest_rect(bounds);
- guest_rect.Offset(guest_window_rect_.OffsetFromOrigin());
- return guest_rect;
-}
-
void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
embedder_visible_ = visible;
UpdateVisibility();
@@ -315,7 +302,46 @@ void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
SendMessageToEmbedder(
- new BrowserPluginMsg_SetMouseLock(instance_id(), allow));
+ new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
+}
+
+void BrowserPluginGuest::SwapCompositorFrame(
+ uint32 output_surface_id,
+ int host_process_id,
+ int host_routing_id,
+ scoped_ptr<cc::CompositorFrame> frame) {
+ cc::RenderPass* root_pass =
+ frame->delegated_frame_data->render_pass_list.back();
+ gfx::Size view_size(gfx::ToFlooredSize(gfx::ScaleSize(
+ root_pass->output_rect.size(),
+ 1.0f / frame->metadata.device_scale_factor)));
+
+ if (last_seen_view_size_ != view_size) {
+ delegate_->GuestSizeChanged(last_seen_view_size_, view_size);
+ last_seen_view_size_ = view_size;
+ }
+
+ FrameMsg_CompositorFrameSwapped_Params guest_params;
+ frame->AssignTo(&guest_params.frame);
+ guest_params.output_surface_id = output_surface_id;
+ guest_params.producing_route_id = host_routing_id;
+ guest_params.producing_host_id = host_process_id;
+ SendMessageToEmbedder(
+ new BrowserPluginMsg_CompositorFrameSwapped(
+ browser_plugin_instance_id(), guest_params));
+}
+
+void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
+ SendMessageToEmbedder(
+ new BrowserPluginMsg_SetContentsOpaque(
+ browser_plugin_instance_id(), opaque));
+}
+
+bool BrowserPluginGuest::Find(int request_id,
+ const base::string16& search_text,
+ const blink::WebFindOptions& options) {
+ return delegate_->Find(request_id, search_text, options,
+ is_full_page_plugin_);
}
WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
@@ -324,16 +350,19 @@ WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
gfx::Point BrowserPluginGuest::GetScreenCoordinates(
const gfx::Point& relative_position) const {
+ if (!attached())
+ return relative_position;
+
gfx::Point screen_pos(relative_position);
screen_pos += guest_window_rect_.OffsetFromOrigin();
+ if (embedder_web_contents()->GetBrowserPluginGuest()) {
+ BrowserPluginGuest* embedder_guest =
+ embedder_web_contents()->GetBrowserPluginGuest();
+ screen_pos += embedder_guest->guest_window_rect_.OffsetFromOrigin();
+ }
return screen_pos;
}
-bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size& size) const {
- return size.width() <= max_auto_size_.width() &&
- size.height() <= max_auto_size_.height();
-}
-
void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
if (!attached()) {
// Some pages such as data URLs, javascript URLs, and about:blank
@@ -372,12 +401,9 @@ void BrowserPluginGuest::SendQueuedMessages() {
}
void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
- int64 frame_id,
- const base::string16& frame_unique_name,
- bool is_main_frame,
+ RenderFrameHost* render_frame_host,
const GURL& url,
- PageTransition transition_type,
- RenderViewHost* render_view_host) {
+ ui::PageTransition transition_type) {
RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
}
@@ -387,19 +413,14 @@ void BrowserPluginGuest::RenderViewReady() {
// here (see http://crbug.com/158151).
Send(new InputMsg_SetFocus(routing_id(), focused_));
UpdateVisibility();
- if (auto_size_enabled_)
- rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
- else
- rvh->DisableAutoResize(full_size_);
-
- OnSetContentsOpaque(instance_id_, guest_opaque_);
RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay_ms(
base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
}
void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
- SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id()));
+ SendMessageToEmbedder(
+ new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
switch (status) {
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
@@ -421,7 +442,6 @@ bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
const IPC::Message& message) {
switch (message.type()) {
case BrowserPluginHostMsg_CompositorFrameSwappedACK::ID:
- case BrowserPluginHostMsg_CopyFromCompositingSurfaceAck::ID:
case BrowserPluginHostMsg_DragStatusUpdate::ID:
case BrowserPluginHostMsg_ExecuteEditCommand::ID:
case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID:
@@ -429,13 +449,10 @@ bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
case BrowserPluginHostMsg_ImeConfirmComposition::ID:
case BrowserPluginHostMsg_ImeSetComposition::ID:
case BrowserPluginHostMsg_LockMouse_ACK::ID:
- case BrowserPluginHostMsg_PluginDestroyed::ID:
case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
case BrowserPluginHostMsg_ResizeGuest::ID:
- case BrowserPluginHostMsg_SetAutoSize::ID:
case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
case BrowserPluginHostMsg_SetFocus::ID:
- case BrowserPluginHostMsg_SetContentsOpaque::ID:
case BrowserPluginHostMsg_SetVisibility::ID:
case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
case BrowserPluginHostMsg_UpdateGeometry::ID:
@@ -448,66 +465,96 @@ bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
+ IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
+ OnImeCancelComposition)
+#if defined(OS_MACOSX) || defined(USE_AURA)
+ IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
+ OnImeCompositionRangeChanged)
+#endif
IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
OnHasTouchEventHandlers)
IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor)
- #if defined(OS_MACOSX)
- // MacOSX creates and populates platform-specific select drop-down menus
- // whereas other platforms merely create a popup window that the guest
- // renderer process paints inside.
- IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnShowPopup)
- #endif
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
- IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
- OnTextInputStateChanged)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition,
- OnImeCancelComposition)
-#if defined(OS_MACOSX) || defined(USE_AURA)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged,
- OnImeCompositionRangeChanged)
-#endif
+ IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
+ OnTextInputTypeChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
- IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
+bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) {
+ // This will eventually be the home for more IPC handlers that depend on
+ // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
+ // compile if there are no handlers for a platform. So we have both #if guards
+ // around the whole thing (unfortunate but temporary), and #if guards where
+ // they belong, only around the one IPC handler. TODO(avi): Move more of the
+ // frame-based handlers to this function and remove the outer #if layer.
+#if defined(OS_MACOSX)
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest, message,
+ render_frame_host)
+#if defined(OS_MACOSX)
+ // MacOS X creates and populates platform-specific select drop-down menus
+ // whereas other platforms merely create a popup window that the guest
+ // renderer process paints inside.
+ IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
+#endif
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+#else
+ return false;
+#endif
+}
+
void BrowserPluginGuest::Attach(
+ int browser_plugin_instance_id,
WebContentsImpl* embedder_web_contents,
- const BrowserPluginHostMsg_Attach_Params& params,
- const base::DictionaryValue& extra_params) {
- if (attached())
- return;
-
- if (delegate_)
- delegate_->WillAttach(embedder_web_contents, extra_params);
+ const BrowserPluginHostMsg_Attach_Params& params) {
+ delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id);
// 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 (has_render_view_) {
+ // This will trigger a callback to RenderViewReady after a round-trip IPC.
static_cast<RenderViewHostImpl*>(
GetWebContents()->GetRenderViewHost())->Init();
- WebContentsViewGuest* new_view =
+ WebContentsViewGuest* web_contents_view =
static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
- new_view->CreateViewForWidget(web_contents()->GetRenderViewHost());
+ if (!web_contents()->GetRenderViewHost()->GetView()) {
+ web_contents_view->CreateViewForWidget(
+ web_contents()->GetRenderViewHost(), true);
+ }
}
- Initialize(params, embedder_web_contents, extra_params);
+ Initialize(browser_plugin_instance_id, params, embedder_web_contents);
SendQueuedMessages();
- if (delegate_)
- delegate_->DidAttach();
+ // Create a swapped out RenderView for the guest in the embedder render
+ // process, so that the embedder can access the guest's window object.
+ // On reattachment, we can reuse the same swapped out RenderView because
+ // the embedder process will always be the same even if the embedder
+ // WebContents changes.
+ if (guest_proxy_routing_id_ == MSG_ROUTING_NONE) {
+ guest_proxy_routing_id_ =
+ GetWebContents()->CreateSwappedOutRenderView(
+ embedder_web_contents_->GetSiteInstance());
+ }
+
+ delegate_->DidAttach(guest_proxy_routing_id_);
+
+ has_render_view_ = true;
RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
}
void BrowserPluginGuest::OnCompositorFrameSwappedACK(
- int instance_id,
+ int browser_plugin_instance_id,
const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
params.output_surface_id,
@@ -515,7 +562,7 @@ void BrowserPluginGuest::OnCompositorFrameSwappedACK(
params.ack);
}
-void BrowserPluginGuest::OnDragStatusUpdate(int instance_id,
+void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
blink::WebDragStatus drag_status,
const DropData& drop_data,
blink::WebDragOperationsMask mask,
@@ -543,34 +590,34 @@ void BrowserPluginGuest::OnDragStatusUpdate(int instance_id,
}
}
-void BrowserPluginGuest::OnExecuteEditCommand(int instance_id,
+void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
const std::string& name) {
Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
}
void BrowserPluginGuest::OnImeSetComposition(
- int instance_id,
+ int browser_plugin_instance_id,
const std::string& text,
const std::vector<blink::WebCompositionUnderline>& underlines,
int selection_start,
int selection_end) {
- Send(new ViewMsg_ImeSetComposition(routing_id(),
- base::UTF8ToUTF16(text), underlines,
- selection_start, selection_end));
+ Send(new InputMsg_ImeSetComposition(routing_id(),
+ base::UTF8ToUTF16(text), underlines,
+ selection_start, selection_end));
}
void BrowserPluginGuest::OnImeConfirmComposition(
- int instance_id,
+ int browser_plugin_instance_id,
const std::string& text,
bool keep_selection) {
- Send(new ViewMsg_ImeConfirmComposition(routing_id(),
- base::UTF8ToUTF16(text),
- gfx::Range::InvalidRange(),
- keep_selection));
+ Send(new InputMsg_ImeConfirmComposition(routing_id(),
+ base::UTF8ToUTF16(text),
+ gfx::Range::InvalidRange(),
+ keep_selection));
}
void BrowserPluginGuest::OnExtendSelectionAndDelete(
- int instance_id,
+ int browser_plugin_instance_id,
int before,
int after) {
RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
@@ -580,7 +627,7 @@ void BrowserPluginGuest::OnExtendSelectionAndDelete(
}
void BrowserPluginGuest::OnReclaimCompositorResources(
- int instance_id,
+ int browser_plugin_instance_id,
const FrameHostMsg_ReclaimCompositorResources_Params& params) {
RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
params.output_surface_id,
@@ -588,61 +635,6 @@ void BrowserPluginGuest::OnReclaimCompositorResources(
params.ack);
}
-void BrowserPluginGuest::OnHandleInputEvent(
- int instance_id,
- const gfx::Rect& guest_window_rect,
- const blink::WebInputEvent* event) {
- guest_window_rect_ = guest_window_rect;
- // If the embedder's RWHV is destroyed then that means that the embedder's
- // window has been closed but the embedder's WebContents has not yet been
- // destroyed. Computing screen coordinates of a BrowserPlugin only makes sense
- // if there is a visible embedder.
- if (embedder_web_contents_->GetRenderWidgetHostView()) {
- guest_screen_rect_ = guest_window_rect;
- guest_screen_rect_.Offset(
- embedder_web_contents_->GetRenderWidgetHostView()->
- GetViewBounds().OffsetFromOrigin());
- }
- RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
- GetWebContents()->GetRenderViewHost());
-
- if (blink::WebInputEvent::isMouseEventType(event->type)) {
- guest_rvh->ForwardMouseEvent(
- *static_cast<const blink::WebMouseEvent*>(event));
- return;
- }
-
- if (event->type == blink::WebInputEvent::MouseWheel) {
- guest_rvh->ForwardWheelEvent(
- *static_cast<const blink::WebMouseWheelEvent*>(event));
- return;
- }
-
- if (blink::WebInputEvent::isKeyboardEventType(event->type)) {
- RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>(
- embedder_web_contents_->GetRenderViewHost());
- if (!embedder_rvh->GetLastKeyboardEvent())
- return;
- NativeWebKeyboardEvent keyboard_event(
- *embedder_rvh->GetLastKeyboardEvent());
- guest_rvh->ForwardKeyboardEvent(keyboard_event);
- return;
- }
-
- if (blink::WebInputEvent::isTouchEventType(event->type)) {
- guest_rvh->ForwardTouchEventWithLatencyInfo(
- *static_cast<const blink::WebTouchEvent*>(event),
- ui::LatencyInfo());
- return;
- }
-
- if (blink::WebInputEvent::isGestureEventType(event->type)) {
- guest_rvh->ForwardGestureEvent(
- *static_cast<const blink::WebGestureEvent*>(event));
- return;
- }
-}
-
void BrowserPluginGuest::OnLockMouse(bool user_gesture,
bool last_unlocked_by_target,
bool privileged) {
@@ -653,9 +645,6 @@ void BrowserPluginGuest::OnLockMouse(bool user_gesture,
return;
}
- if (!delegate_)
- return;
-
pending_lock_request_ = true;
delegate_->RequestPointerLockPermission(
@@ -665,113 +654,56 @@ void BrowserPluginGuest::OnLockMouse(bool user_gesture,
weak_ptr_factory_.GetWeakPtr()));
}
-void BrowserPluginGuest::OnLockMouseAck(int instance_id, bool succeeded) {
+void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
+ bool succeeded) {
Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
pending_lock_request_ = false;
if (succeeded)
mouse_locked_ = true;
}
-void BrowserPluginGuest::OnPluginDestroyed(int instance_id) {
- Destroy();
-}
-
void BrowserPluginGuest::OnResizeGuest(
- int instance_id,
+ int browser_plugin_instance_id,
const BrowserPluginHostMsg_ResizeGuest_Params& params) {
- if (!params.size_changed)
- return;
- // BrowserPlugin manages resize flow control itself and does not depend
- // on RenderWidgetHost's mechanisms for flow control, so we reset those flags
- // here. If we are setting the size for the first time before navigating then
+ // If we are setting the size for the first time before navigating then
// BrowserPluginGuest does not yet have a RenderViewHost.
- if (GetWebContents()->GetRenderViewHost()) {
+ if (guest_device_scale_factor_ != params.scale_factor &&
+ GetWebContents()->GetRenderViewHost()) {
RenderWidgetHostImpl* render_widget_host =
RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
- render_widget_host->ResetSizeAndRepaintPendingFlags();
-
- if (guest_device_scale_factor_ != params.scale_factor) {
- guest_device_scale_factor_ = params.scale_factor;
- render_widget_host->NotifyScreenInfoChanged();
- }
+ guest_device_scale_factor_ = params.scale_factor;
+ render_widget_host->NotifyScreenInfoChanged();
}
- // When autosize is turned off and as a result there is a layout change, we
- // send a sizechanged event.
- if (!auto_size_enabled_ && last_seen_auto_size_enabled_ &&
- !params.view_size.IsEmpty() && delegate_) {
- delegate_->SizeChanged(last_seen_view_size_, params.view_size);
- last_seen_auto_size_enabled_ = false;
+
+ if (last_seen_browser_plugin_size_ != params.view_size) {
+ delegate_->ElementSizeChanged(last_seen_browser_plugin_size_,
+ params.view_size);
+ last_seen_browser_plugin_size_ = params.view_size;
}
+
// Just resize the WebContents and repaint if needed.
- full_size_ = params.view_size;
if (!params.view_size.IsEmpty())
GetWebContents()->GetView()->SizeContents(params.view_size);
if (params.repaint)
Send(new ViewMsg_Repaint(routing_id(), params.view_size));
}
-void BrowserPluginGuest::OnSetFocus(int instance_id, bool focused) {
- focused_ = focused;
- Send(new InputMsg_SetFocus(routing_id(), focused));
- if (!focused && mouse_locked_)
- OnUnlockMouse();
-
- // Restore the last seen state of text input to the view.
- RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
- web_contents()->GetRenderWidgetHostView());
- if (rwhv) {
- ViewHostMsg_TextInputState_Params params;
- params.type = last_text_input_type_;
- params.mode = last_input_mode_;
- params.can_compose_inline = last_can_compose_inline_;
- rwhv->TextInputStateChanged(params);
- }
-}
-
-void BrowserPluginGuest::OnSetAutoSize(
- int instance_id,
- const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
- const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
- bool old_auto_size_enabled = auto_size_enabled_;
- gfx::Size old_max_size = max_auto_size_;
- gfx::Size old_min_size = min_auto_size_;
- auto_size_enabled_ = auto_size_params.enable;
- max_auto_size_ = auto_size_params.max_size;
- min_auto_size_ = auto_size_params.min_size;
- if (auto_size_enabled_ && (!old_auto_size_enabled ||
- (old_max_size != max_auto_size_) ||
- (old_min_size != min_auto_size_))) {
- RecordAction(
- base::UserMetricsAction("BrowserPlugin.Guest.EnableAutoResize"));
- GetWebContents()->GetRenderViewHost()->EnableAutoResize(
- min_auto_size_, max_auto_size_);
- // TODO(fsamuel): If we're changing autosize parameters, then we force
- // the guest to completely repaint itself.
- // Ideally, we shouldn't need to do this unless |max_auto_size_| has
- // changed.
- // However, even in that case, layout may not change and so we may
- // not get a full frame worth of pixels.
- Send(new ViewMsg_Repaint(routing_id(), max_auto_size_));
- } else if (!auto_size_enabled_ && old_auto_size_enabled) {
- GetWebContents()->GetRenderViewHost()->DisableAutoResize(
- resize_guest_params.view_size);
- }
- OnResizeGuest(instance_id_, resize_guest_params);
+void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id,
+ bool focused) {
+ RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
+ RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : NULL;
+ SetFocus(rwh, focused);
}
void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
- int instance_id,
+ int browser_plugin_instance_id,
const std::vector<EditCommand>& edit_commands) {
Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
edit_commands));
}
-void BrowserPluginGuest::OnSetContentsOpaque(int instance_id, bool opaque) {
- guest_opaque_ = opaque;
- Send(new ViewMsg_SetBackgroundOpaque(routing_id(), guest_opaque_));
-}
-
-void BrowserPluginGuest::OnSetVisibility(int instance_id, bool visible) {
+void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id,
+ bool visible) {
guest_visible_ = visible;
if (embedder_visible_ && guest_visible_)
GetWebContents()->WasShown();
@@ -781,10 +713,10 @@ void BrowserPluginGuest::OnSetVisibility(int instance_id, bool visible) {
void BrowserPluginGuest::OnUnlockMouse() {
SendMessageToEmbedder(
- new BrowserPluginMsg_SetMouseLock(instance_id(), false));
+ new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
}
-void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) {
+void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
// mouse_locked_ could be false here if the lock attempt was cancelled due
// to window focus, or for various other reasons before the guest was informed
// of the lock's success.
@@ -793,19 +725,7 @@ void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) {
mouse_locked_ = false;
}
-void BrowserPluginGuest::OnCopyFromCompositingSurfaceAck(
- int instance_id,
- int request_id,
- const SkBitmap& bitmap) {
- CHECK(copy_request_callbacks_.count(request_id));
- if (!copy_request_callbacks_.count(request_id))
- return;
- const CopyRequestCallback& callback = copy_request_callbacks_[request_id];
- callback.Run(!bitmap.empty() && !bitmap.isNull(), bitmap);
- copy_request_callbacks_.erase(request_id);
-}
-
-void BrowserPluginGuest::OnUpdateGeometry(int instance_id,
+void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id,
const gfx::Rect& view_rect) {
// The plugin has moved within the embedder without resizing or the
// embedder/container's view rect changing.
@@ -818,21 +738,18 @@ void BrowserPluginGuest::OnUpdateGeometry(int instance_id,
void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
SendMessageToEmbedder(
- new BrowserPluginMsg_ShouldAcceptTouchEvents(instance_id(), accept));
-}
-
-void BrowserPluginGuest::OnSetCursor(const WebCursor& cursor) {
- SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(instance_id(), cursor));
+ new BrowserPluginMsg_ShouldAcceptTouchEvents(
+ browser_plugin_instance_id(), accept));
}
#if defined(OS_MACOSX)
void BrowserPluginGuest::OnShowPopup(
- const ViewHostMsg_ShowPopup_Params& params) {
+ RenderFrameHost* render_frame_host,
+ const FrameHostMsg_ShowPopup_Params& params) {
gfx::Rect translated_bounds(params.bounds);
translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
BrowserPluginPopupMenuHelper popup_menu_helper(
- embedder_web_contents_->GetRenderViewHost(),
- GetWebContents()->GetRenderViewHost());
+ embedder_web_contents_->GetRenderViewHost(), render_frame_host);
popup_menu_helper.ShowPopupMenu(translated_bounds,
params.item_height,
params.item_font_size,
@@ -850,40 +767,22 @@ void BrowserPluginGuest::OnShowWidget(int route_id,
void BrowserPluginGuest::OnTakeFocus(bool reverse) {
SendMessageToEmbedder(
- new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse));
-}
-
-void BrowserPluginGuest::OnUpdateRect(
- const ViewHostMsg_UpdateRect_Params& params) {
- BrowserPluginMsg_UpdateRect_Params relay_params;
- relay_params.view_size = params.view_size;
- relay_params.scale_factor = params.scale_factor;
- relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack(
- params.flags);
-
- bool size_changed = last_seen_view_size_ != params.view_size;
- gfx::Size old_size = last_seen_view_size_;
- last_seen_view_size_ = params.view_size;
-
- if ((auto_size_enabled_ || last_seen_auto_size_enabled_) &&
- size_changed && delegate_) {
- delegate_->SizeChanged(old_size, last_seen_view_size_);
- }
- last_seen_auto_size_enabled_ = auto_size_enabled_;
-
- SendMessageToEmbedder(
- new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
+ new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
}
-void BrowserPluginGuest::OnTextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) {
+void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) {
// Save the state of text input so we can restore it on focus.
- last_text_input_type_ = params.type;
- last_input_mode_ = params.mode;
- last_can_compose_inline_ = params.can_compose_inline;
+ last_text_input_type_ = type;
+ last_input_mode_ = input_mode;
+ last_input_flags_ = flags;
+ last_can_compose_inline_ = can_compose_inline;
static_cast<RenderWidgetHostViewBase*>(
- web_contents()->GetRenderWidgetHostView())->TextInputStateChanged(params);
+ web_contents()->GetRenderWidgetHostView())->TextInputTypeChanged(
+ type, input_mode, can_compose_inline, flags);
}
void BrowserPluginGuest::OnImeCancelComposition() {
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_guest.h b/chromium/content/browser/browser_plugin/browser_plugin_guest.h
index d1bd4ba36c7..cb1ba7eef8e 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/chromium/content/browser/browser_plugin/browser_plugin_guest.h
@@ -38,32 +38,33 @@
#include "ui/gfx/rect.h"
class SkBitmap;
-struct BrowserPluginHostMsg_AutoSize_Params;
struct BrowserPluginHostMsg_Attach_Params;
struct BrowserPluginHostMsg_ResizeGuest_Params;
struct FrameHostMsg_CompositorFrameSwappedACK_Params;
struct FrameHostMsg_ReclaimCompositorResources_Params;
#if defined(OS_MACOSX)
-struct ViewHostMsg_ShowPopup_Params;
+struct FrameHostMsg_ShowPopup_Params;
#endif
-struct ViewHostMsg_TextInputState_Params;
-struct ViewHostMsg_UpdateRect_Params;
namespace blink {
class WebInputEvent;
-}
+} // namespace blink
+
+namespace cc {
+class CompositorFrame;
+} // namespace cc
namespace gfx {
class Range;
-}
+} // namespace gfx
namespace content {
class BrowserPluginGuestManager;
class RenderViewHostImpl;
+class RenderWidgetHost;
class RenderWidgetHostView;
class SiteInstance;
-class WebCursor;
struct DropData;
// A browser plugin guest provides functionality for WebContents to operate in
@@ -78,7 +79,7 @@ struct DropData;
// which means it can share storage and can script this guest.
class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
public:
- virtual ~BrowserPluginGuest();
+ ~BrowserPluginGuest() override;
// The WebContents passed into the factory method here has not been
// initialized yet and so it does not yet hold a SiteInstance.
@@ -87,12 +88,8 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// type of WebContentsView to construct on initialization. The content
// embedder needs to be aware of |guest_site_instance| on the guest's
// construction and so we pass it in here.
- static BrowserPluginGuest* Create(
- int instance_id,
- SiteInstance* guest_site_instance,
- WebContentsImpl* web_contents,
- scoped_ptr<base::DictionaryValue> extra_params,
- BrowserPluginGuest* opener);
+ static BrowserPluginGuest* Create(WebContentsImpl* web_contents,
+ BrowserPluginGuestDelegate* delegate);
// Returns whether the given WebContents is a BrowserPlugin guest.
static bool IsGuest(WebContentsImpl* web_contents);
@@ -103,20 +100,30 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// Returns a WeakPtr to this BrowserPluginGuest.
base::WeakPtr<BrowserPluginGuest> AsWeakPtr();
+ // Sets the focus state of the current RenderWidgetHostView.
+ void SetFocus(RenderWidgetHost* rwh, bool focused);
+
+ // Sets the tooltip text.
+ void SetTooltipText(const base::string16& tooltip_text);
+
// Sets the lock state of the pointer. Returns true if |allowed| is true and
// the mouse has been successfully locked.
bool LockMouse(bool allowed);
+ // Return true if the mouse is locked.
+ bool mouse_locked() const { return mouse_locked_; }
+
// Called when the embedder WebContents changes visibility.
void EmbedderVisibilityChanged(bool visible);
- // Destroys the guest WebContents and all its associated state, including
- // this BrowserPluginGuest, and its new unattached windows.
- void Destroy();
+ // Creates a new guest WebContentsImpl with the provided |params| with |this|
+ // as the |opener|.
+ WebContentsImpl* CreateNewGuestWindow(
+ const WebContents::CreateParams& params);
// Returns the identifier that uniquely identifies a browser plugin guest
// within an embedder.
- int instance_id() const { return instance_id_; }
+ int browser_plugin_instance_id() const { return browser_plugin_instance_id_; }
bool OnMessageReceivedFromEmbedder(const IPC::Message& message);
@@ -132,30 +139,21 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
bool visible() const { return guest_visible_; }
bool is_in_destruction() { return is_in_destruction_; }
- // Returns the BrowserPluginGuest that created this guest, if any.
- BrowserPluginGuest* GetOpener() const;
-
void UpdateVisibility();
- void CopyFromCompositingSurface(
- gfx::Rect src_subrect,
- gfx::Size dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback);
-
BrowserPluginGuestManager* GetBrowserPluginGuestManager() const;
// WebContentsObserver implementation.
- virtual void DidCommitProvisionalLoadForFrame(
- int64 frame_id,
- const base::string16& frame_unique_name,
- bool is_main_frame,
+ void DidCommitProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
const GURL& url,
- PageTransition transition_type,
- RenderViewHost* render_view_host) OVERRIDE;
+ ui::PageTransition transition_type) override;
- virtual void RenderViewReady() OVERRIDE;
- virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void RenderViewReady() override;
+ void RenderProcessGone(base::TerminationStatus status) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) override;
// Exposes the protected web_contents() from WebContentsObserver.
WebContentsImpl* GetWebContents() const;
@@ -172,17 +170,14 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// Attaches this BrowserPluginGuest to the provided |embedder_web_contents|
// and initializes the guest with the provided |params|. Attaching a guest
// to an embedder implies that this guest's lifetime is no longer managed
- // by its opener, and it can begin loading resources. |extra_params| are
- // parameters passed into BrowserPlugin from JavaScript to be forwarded to
- // the content embedder.
- void Attach(WebContentsImpl* embedder_web_contents,
- const BrowserPluginHostMsg_Attach_Params& params,
- const base::DictionaryValue& extra_params);
+ // by its opener, and it can begin loading resources.
+ void Attach(int browser_plugin_instance_id,
+ WebContentsImpl* embedder_web_contents,
+ const BrowserPluginHostMsg_Attach_Params& params);
// Returns whether BrowserPluginGuest is interested in receiving the given
// |message|.
static bool ShouldForwardToBrowserPluginGuest(const IPC::Message& message);
- gfx::Rect ToGuestRect(const gfx::Rect& rect);
void DragSourceEndedAt(int client_x, int client_y, int screen_x,
int screen_y, blink::WebDragOperation operation);
@@ -190,42 +185,47 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// Called when the drag started by this guest ends at an OS-level.
void EndSystemDrag();
- void set_delegate(BrowserPluginGuestDelegate* delegate) {
- DCHECK(!delegate_);
- delegate_ = delegate;
- }
-
void RespondToPermissionRequest(int request_id,
bool should_allow,
const std::string& user_input);
void PointerLockPermissionResponse(bool allow);
+ void SwapCompositorFrame(uint32 output_surface_id,
+ int host_process_id,
+ int host_routing_id,
+ scoped_ptr<cc::CompositorFrame> frame);
+
+ void SetContentsOpaque(bool opaque);
+
+ // Find the given |search_text| in the page. Returns true if the find request
+ // is handled by this browser plugin guest.
+ bool Find(int request_id,
+ const base::string16& search_text,
+ const blink::WebFindOptions& options);
+
private:
class EmbedderWebContentsObserver;
// BrowserPluginGuest is a WebContentsObserver of |web_contents| and
// |web_contents| has to stay valid for the lifetime of BrowserPluginGuest.
- BrowserPluginGuest(int instance_id,
- bool has_render_view,
- WebContentsImpl* web_contents);
+ BrowserPluginGuest(bool has_render_view,
+ WebContentsImpl* web_contents,
+ BrowserPluginGuestDelegate* delegate);
void WillDestroy();
- void Initialize(const BrowserPluginHostMsg_Attach_Params& params,
- WebContentsImpl* embedder_web_contents,
- const base::DictionaryValue& extra_params);
+ void Initialize(int browser_plugin_instance_id,
+ const BrowserPluginHostMsg_Attach_Params& params,
+ WebContentsImpl* embedder_web_contents);
bool InAutoSizeBounds(const gfx::Size& size) const;
// Message handlers for messages from embedder.
-
void OnCompositorFrameSwappedACK(
int instance_id,
const FrameHostMsg_CompositorFrameSwappedACK_Params& params);
- void OnCopyFromCompositingSurfaceAck(int instance_id,
- int request_id,
- const SkBitmap& bitmap);
+
// Handles drag events from the embedder.
// When dragging, the drag events go to the embedder first, and if the drag
// happens on the browser plugin, then the plugin sends a corresponding
@@ -245,14 +245,10 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
int instance_id,
const FrameHostMsg_ReclaimCompositorResources_Params& params);
- void OnHandleInputEvent(int instance_id,
- const gfx::Rect& guest_window_rect,
- const blink::WebInputEvent* event);
void OnLockMouse(bool user_gesture,
bool last_unlocked_by_target,
bool privileged);
void OnLockMouseAck(int instance_id, bool succeeded);
- void OnPluginDestroyed(int instance_id);
// Resizes the guest's web contents.
void OnResizeGuest(
int instance_id, const BrowserPluginHostMsg_ResizeGuest_Params& params);
@@ -261,14 +257,9 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// access it.
void OnSetName(int instance_id, const std::string& name);
// Updates the size state of the guest.
- void OnSetAutoSize(
- int instance_id,
- const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
- const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params);
void OnSetEditCommandsForNextKeyEvent(
int instance_id,
const std::vector<EditCommand>& edit_commands);
- void OnSetContentsOpaque(int instance_id, bool opaque);
// The guest WebContents is visible if both its embedder is visible and
// the browser plugin element is visible. If either one is not then the
// WebContents is marked as hidden. A hidden WebContents will consume
@@ -289,9 +280,10 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
void OnUnlockMouseAck(int instance_id);
void OnUpdateGeometry(int instance_id, const gfx::Rect& view_rect);
- void OnTextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params);
-
+ void OnTextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags);
void OnImeSetComposition(
int instance_id,
const std::string& text,
@@ -311,55 +303,42 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
#endif
// Message handlers for messages from guest.
-
- void OnDragStopped();
void OnHandleInputEventAck(
blink::WebInputEvent::Type event_type,
InputEventAckState ack_result);
void OnHasTouchEventHandlers(bool accept);
- void OnSetCursor(const WebCursor& cursor);
- // On MacOSX popups are painted by the browser process. We handle them here
- // so that they are positioned correctly.
#if defined(OS_MACOSX)
- void OnShowPopup(const ViewHostMsg_ShowPopup_Params& params);
+ // On MacOS X popups are painted by the browser process. We handle them here
+ // so that they are positioned correctly.
+ void OnShowPopup(RenderFrameHost* render_frame_host,
+ const FrameHostMsg_ShowPopup_Params& params);
#endif
void OnShowWidget(int route_id, const gfx::Rect& initial_pos);
void OnTakeFocus(bool reverse);
void OnUpdateFrameName(int frame_id,
bool is_top_level,
const std::string& name);
- void OnUpdateRect(const ViewHostMsg_UpdateRect_Params& params);
// Forwards all messages from the |pending_messages_| queue to the embedder.
void SendQueuedMessages();
+ // The last tooltip that was set with SetTooltipText().
+ base::string16 current_tooltip_text_;
+
scoped_ptr<EmbedderWebContentsObserver> embedder_web_contents_observer_;
WebContentsImpl* embedder_web_contents_;
- // An identifier that uniquely identifies a browser plugin guest within an
- // embedder.
- int instance_id_;
+ // An identifier that uniquely identifies a browser plugin within an embedder.
+ int browser_plugin_instance_id_;
float guest_device_scale_factor_;
gfx::Rect guest_window_rect_;
- gfx::Rect guest_screen_rect_;
bool focused_;
bool mouse_locked_;
bool pending_lock_request_;
bool guest_visible_;
- bool guest_opaque_;
bool embedder_visible_;
- std::string name_;
- bool auto_size_enabled_;
- gfx::Size max_auto_size_;
- gfx::Size min_auto_size_;
- gfx::Size full_size_;
-
- // Each copy-request is identified by a unique number. The unique number is
- // used to keep track of the right callback.
- int copy_request_id_;
- typedef base::Callback<void(bool, const SkBitmap&)> CopyRequestCallback;
- typedef std::map<int, const CopyRequestCallback> CopyRequestMap;
- CopyRequestMap copy_request_callbacks_;
+ // Whether the browser plugin is inside a plugin document.
+ bool is_full_page_plugin_;
// Indicates that this BrowserPluginGuest has associated renderer-side state.
// This is used to determine whether or not to create a new RenderView when
@@ -368,23 +347,28 @@ class CONTENT_EXPORT BrowserPluginGuest : public WebContentsObserver {
// maintains a JavaScript reference to its opener.
bool has_render_view_;
- // Last seen size of guest contents (by OnUpdateRect).
+ // Last seen size of guest contents (by SwapCompositorFrame).
gfx::Size last_seen_view_size_;
- // Last seen autosize attribute state (by OnUpdateRect).
- bool last_seen_auto_size_enabled_;
+ // Last seen size of BrowserPlugin (by OnResizeGuest).
+ gfx::Size last_seen_browser_plugin_size_;
bool is_in_destruction_;
// Text input type states.
ui::TextInputType last_text_input_type_;
ui::TextInputMode last_input_mode_;
+ int last_input_flags_;
bool last_can_compose_inline_;
+ // The is the routing ID for a swapped out RenderView for the guest
+ // WebContents in the embedder's process.
+ int guest_proxy_routing_id_;
+
// 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_;
- BrowserPluginGuestDelegate* delegate_;
+ BrowserPluginGuestDelegate* const delegate_;
// Weak pointer used to ask GeolocationPermissionContext about geolocation
// permission.
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_message_filter.cc b/chromium/content/browser/browser_plugin/browser_plugin_message_filter.cc
index e82fb7a031a..c39476d2fbc 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_message_filter.cc
+++ b/chromium/content/browser/browser_plugin/browser_plugin_message_filter.cc
@@ -10,7 +10,6 @@
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/browser_plugin/browser_plugin_constants.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
-#include "content/common/gpu/gpu_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
@@ -39,14 +38,7 @@ bool BrowserPluginMessageFilter::OnMessageReceived(
// thread.
return true;
}
- bool handled = true;
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- IPC_BEGIN_MESSAGE_MAP(BrowserPluginMessageFilter, message)
- IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_BuffersSwappedACK,
- OnSwapBuffersACK)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
+ return false;
}
void BrowserPluginMessageFilter::OnDestruct() const {
@@ -59,45 +51,32 @@ void BrowserPluginMessageFilter::OverrideThreadForMessage(
*thread = BrowserThread::UI;
}
-static void BrowserPluginGuestMessageCallback(const IPC::Message& message,
- WebContents* guest_web_contents) {
- if (!guest_web_contents)
- return;
- static_cast<WebContentsImpl*>(guest_web_contents)->GetBrowserPluginGuest()->
- OnMessageReceivedFromEmbedder(message);
-}
-
void BrowserPluginMessageFilter::ForwardMessageToGuest(
const IPC::Message& message) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
- RenderProcessHost::FromID(render_process_id_));
- if (!host)
+ RenderViewHost* rvh = RenderViewHost::FromID(render_process_id_,
+ message.routing_id());
+ if (!rvh)
return;
- int instance_id = 0;
+ WebContents* embedder_web_contents = WebContents::FromRenderViewHost(rvh);
+
+ int browser_plugin_instance_id = 0;
// All allowed messages must have instance_id as their first parameter.
PickleIterator iter(message);
- bool success = iter.ReadInt(&instance_id);
+ bool success = iter.ReadInt(&browser_plugin_instance_id);
DCHECK(success);
- host->GetBrowserContext()->GetGuestManager()->
- MaybeGetGuestByInstanceIDOrKill(
- instance_id,
- render_process_id_,
- base::Bind(&BrowserPluginGuestMessageCallback,
- message));
-}
-
-void BrowserPluginMessageFilter::OnSwapBuffersACK(
- const FrameHostMsg_BuffersSwappedACK_Params& params) {
- GpuProcessHost* gpu_host = GpuProcessHost::FromID(params.gpu_host_id);
- if (!gpu_host)
+ WebContents* guest_web_contents =
+ embedder_web_contents->GetBrowserContext()
+ ->GetGuestManager()
+ ->GetGuestByInstanceID(embedder_web_contents,
+ browser_plugin_instance_id);
+ if (!guest_web_contents)
return;
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.mailbox = params.mailbox;
- ack_params.sync_point = params.sync_point;
- gpu_host->Send(new AcceleratedSurfaceMsg_BufferPresented(params.gpu_route_id,
- ack_params));
+
+ static_cast<WebContentsImpl*>(guest_web_contents)
+ ->GetBrowserPluginGuest()
+ ->OnMessageReceivedFromEmbedder(message);
}
} // namespace content
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_message_filter.h b/chromium/content/browser/browser_plugin/browser_plugin_message_filter.h
index 136c6cc58e6..672f6de51b6 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_message_filter.h
+++ b/chromium/content/browser/browser_plugin/browser_plugin_message_filter.h
@@ -20,22 +20,19 @@ class BrowserPluginMessageFilter : public BrowserMessageFilter {
BrowserPluginMessageFilter(int render_process_id);
// BrowserMessageFilter implementation.
- virtual void OverrideThreadForMessage(
- const IPC::Message& message,
- BrowserThread::ID* thread) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnDestruct() const override;
private:
friend class BrowserThread;
friend class base::DeleteHelper<BrowserPluginMessageFilter>;
- virtual ~BrowserPluginMessageFilter();
+ ~BrowserPluginMessageFilter() override;
void ForwardMessageToGuest(const IPC::Message& message);
- void OnSwapBuffersACK(const FrameHostMsg_BuffersSwappedACK_Params& params);
-
int render_process_id_;
DISALLOW_COPY_AND_ASSIGN(BrowserPluginMessageFilter);
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h b/chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h
index 2b462371001..31c198031b1 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h
+++ b/chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h
@@ -5,24 +5,27 @@
#ifndef CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_POPUP_MENU_HELPER_MAC_H_
#define CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_POPUP_MENU_HELPER_MAC_H_
-#include "content/browser/renderer_host/popup_menu_helper_mac.h"
+#include "content/browser/frame_host/popup_menu_helper_mac.h"
namespace content {
+
class RenderViewHost;
class RenderViewHostImpl;
+class RenderFrameHost;
+class RenderFrameHostImpl;
// This class is similiar to PopupMenuHelperMac but positions the popup relative
// to the embedder, and issues a reply to the guest.
class BrowserPluginPopupMenuHelper : public PopupMenuHelper {
public:
// Creates a BrowserPluginPopupMenuHelper that positions popups relative to
- // |embedder_rvh| and will notify |guest_rvh| when a user selects or cancels
+ // |embedder_rvh| and will notify |guest_rfh| when a user selects or cancels
// the popup.
BrowserPluginPopupMenuHelper(RenderViewHost* embedder_rvh,
- RenderViewHost* guest_rvh);
+ RenderFrameHost* guest_rfh);
private:
- virtual RenderWidgetHostViewMac* GetRenderWidgetHostView() const OVERRIDE;
+ RenderWidgetHostViewMac* GetRenderWidgetHostView() const override;
RenderViewHostImpl* embedder_rvh_;
diff --git a/chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.mm b/chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.mm
index e2b5da55c00..413c96fd16b 100644
--- a/chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.mm
+++ b/chromium/content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.mm
@@ -4,14 +4,15 @@
#include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
namespace content {
BrowserPluginPopupMenuHelper::BrowserPluginPopupMenuHelper(
- RenderViewHost* embedder_rvh, RenderViewHost* guest_rvh)
- : PopupMenuHelper(guest_rvh),
+ RenderViewHost* embedder_rvh, RenderFrameHost* guest_rfh)
+ : PopupMenuHelper(guest_rfh),
embedder_rvh_(static_cast<RenderViewHostImpl*>(embedder_rvh)) {
}
diff --git a/chromium/content/browser/browser_process_sub_thread.h b/chromium/content/browser/browser_process_sub_thread.h
index e006388783b..5899fa31906 100644
--- a/chromium/content/browser/browser_process_sub_thread.h
+++ b/chromium/content/browser/browser_process_sub_thread.h
@@ -35,11 +35,11 @@ namespace content {
class CONTENT_EXPORT BrowserProcessSubThread : public BrowserThreadImpl {
public:
explicit BrowserProcessSubThread(BrowserThread::ID identifier);
- virtual ~BrowserProcessSubThread();
+ ~BrowserProcessSubThread() override;
protected:
- virtual void Init() OVERRIDE;
- virtual void CleanUp() OVERRIDE;
+ void Init() override;
+ void CleanUp() override;
private:
// These methods encapsulate cleanup that needs to happen on the IO thread
diff --git a/chromium/content/browser/browser_shutdown_profile_dumper.cc b/chromium/content/browser/browser_shutdown_profile_dumper.cc
index 3e74e063b0c..c2533a09604 100644
--- a/chromium/content/browser/browser_shutdown_profile_dumper.cc
+++ b/chromium/content/browser/browser_shutdown_profile_dumper.cc
@@ -8,8 +8,8 @@
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/debug/trace_event_impl.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
@@ -18,17 +18,18 @@
namespace content {
-BrowserShutdownProfileDumper::BrowserShutdownProfileDumper()
- : blocks_(0),
+BrowserShutdownProfileDumper::BrowserShutdownProfileDumper(
+ const base::FilePath& dump_file_name)
+ : dump_file_name_(dump_file_name),
+ blocks_(0),
dump_file_(NULL) {
}
BrowserShutdownProfileDumper::~BrowserShutdownProfileDumper() {
- WriteTracesToDisc(GetFileName());
+ WriteTracesToDisc();
}
-void BrowserShutdownProfileDumper::WriteTracesToDisc(
- const base::FilePath& file_name) {
+void BrowserShutdownProfileDumper::WriteTracesToDisc() {
// Note: I have seen a usage of 0.000xx% when dumping - which fits easily.
// Since the tracer stops when the trace buffer is filled, we'd rather save
// what we have than nothing since we might see from the amount of events
@@ -37,10 +38,10 @@ void BrowserShutdownProfileDumper::WriteTracesToDisc(
base::debug::TraceLog::GetInstance()->GetBufferPercentFull() <<
" full.";
DCHECK(!dump_file_);
- dump_file_ = base::OpenFile(file_name, "w+");
+ dump_file_ = base::OpenFile(dump_file_name_, "w+");
if (!IsFileValid()) {
- LOG(ERROR) << "Failed to open performance trace file: " <<
- file_name.value();
+ LOG(ERROR) << "Failed to open performance trace file: "
+ << dump_file_name_.value();
return;
}
WriteString("{\"traceEvents\":");
@@ -72,8 +73,10 @@ void BrowserShutdownProfileDumper::EndTraceAndFlush(
base::Unretained(flush_complete_event)));
}
-base::FilePath BrowserShutdownProfileDumper::GetFileName() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+// static
+base::FilePath BrowserShutdownProfileDumper::GetShutdownProfileFileName() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
base::FilePath trace_file =
command_line.GetSwitchValuePath(switches::kTraceShutdownFile);
@@ -122,8 +125,9 @@ void BrowserShutdownProfileDumper::WriteChars(const char* chars, size_t size) {
size_t written = fwrite(chars, 1, size, dump_file_);
if (written != size) {
- LOG(ERROR) << "Error " << ferror(dump_file_) <<
- " in fwrite() to trace file";
+ LOG(ERROR) << "Error " << ferror(dump_file_)
+ << " in fwrite() to trace file '" << dump_file_name_.value()
+ << "'";
CloseFile();
}
}
diff --git a/chromium/content/browser/browser_shutdown_profile_dumper.h b/chromium/content/browser/browser_shutdown_profile_dumper.h
index f98a32cb9ca..cc8666ef69d 100644
--- a/chromium/content/browser/browser_shutdown_profile_dumper.h
+++ b/chromium/content/browser/browser_shutdown_profile_dumper.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/basictypes.h"
+#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "content/common/content_export.h"
@@ -29,19 +30,19 @@ namespace content {
// |SequencedWorkerPool| will get killed in the shutdown process.
class BrowserShutdownProfileDumper {
public:
- BrowserShutdownProfileDumper();
+ explicit BrowserShutdownProfileDumper(const base::FilePath& dump_file_name);
~BrowserShutdownProfileDumper();
+ // Returns the file name where we should save the shutdown trace dump to.
+ static base::FilePath GetShutdownProfileFileName();
+
private:
// Writes all traces which happened to disk.
- void WriteTracesToDisc(const base::FilePath& file_name);
+ void WriteTracesToDisc();
void EndTraceAndFlush(base::WaitableEvent* flush_complete_event);
- // Returns the file name where we should save the trace dump to.
- base::FilePath GetFileName();
-
// The callback for the |TraceLog::Flush| function. It saves all traces to
// disc.
void WriteTraceDataCollected(
@@ -61,6 +62,9 @@ class BrowserShutdownProfileDumper {
// Closes the dump file.
void CloseFile();
+ // The name of the dump file.
+ const base::FilePath dump_file_name_;
+
// The number of blocks we have already written.
int blocks_;
// For dumping the content to disc.
diff --git a/chromium/content/browser/browser_thread_impl.cc b/chromium/content/browser/browser_thread_impl.cc
index 641056ffb78..33bfeb951e5 100644
--- a/chromium/content/browser/browser_thread_impl.cc
+++ b/chromium/content/browser/browser_thread_impl.cc
@@ -15,6 +15,7 @@
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_thread_delegate.h"
+#include "net/disk_cache/simple/simple_backend_impl.h"
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
@@ -44,26 +45,25 @@ class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
}
// MessageLoopProxy implementation.
- virtual bool PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task, base::TimeDelta delay) OVERRIDE {
+ bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override {
return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
}
- virtual bool PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) OVERRIDE {
+ bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override {
return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
delay);
}
- virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
+ bool RunsTasksOnCurrentThread() const override {
return BrowserThread::CurrentlyOn(id_);
}
protected:
- virtual ~BrowserThreadMessageLoopProxy() {}
+ ~BrowserThreadMessageLoopProxy() override {}
private:
BrowserThread::ID id_;
@@ -141,11 +141,12 @@ void BrowserThreadImpl::ShutdownThreadPool() {
}
// static
-void BrowserThreadImpl::FlushThreadPoolHelper() {
+void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
// We don't want to create a pool if none exists.
if (g_globals == NULL)
return;
g_globals.Get().blocking_pool->FlushForTesting();
+ disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
}
void BrowserThreadImpl::Init() {
diff --git a/chromium/content/browser/browser_thread_impl.h b/chromium/content/browser/browser_thread_impl.h
index 167cc3b85a1..72915ea393f 100644
--- a/chromium/content/browser/browser_thread_impl.h
+++ b/chromium/content/browser/browser_thread_impl.h
@@ -23,14 +23,14 @@ class CONTENT_EXPORT BrowserThreadImpl : public BrowserThread,
// thread already exists.
BrowserThreadImpl(BrowserThread::ID identifier,
base::MessageLoop* message_loop);
- virtual ~BrowserThreadImpl();
+ ~BrowserThreadImpl() override;
static void ShutdownThreadPool();
protected:
- virtual void Init() OVERRIDE;
- virtual void Run(base::MessageLoop* message_loop) OVERRIDE;
- virtual void CleanUp() OVERRIDE;
+ void Init() override;
+ void Run(base::MessageLoop* message_loop) override;
+ void CleanUp() override;
private:
// We implement all the functionality of the public BrowserThread
@@ -61,7 +61,7 @@ class CONTENT_EXPORT BrowserThreadImpl : public BrowserThread,
// For testing.
friend class ContentTestSuiteBaseListener;
friend class TestBrowserThreadBundle;
- static void FlushThreadPoolHelper();
+ static void FlushThreadPoolHelperForTesting();
// The identifier of this thread. Only one thread can exist with a given
// identifier at a given time.
diff --git a/chromium/content/browser/browser_thread_unittest.cc b/chromium/content/browser/browser_thread_unittest.cc
index 4083b782caf..3f1f8cdd2ee 100644
--- a/chromium/content/browser/browser_thread_unittest.cc
+++ b/chromium/content/browser/browser_thread_unittest.cc
@@ -23,14 +23,14 @@ class BrowserThreadTest : public testing::Test {
}
protected:
- virtual void SetUp() {
+ void SetUp() override {
ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI));
file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE));
ui_thread_->Start();
file_thread_->Start();
}
- virtual void TearDown() {
+ void TearDown() override {
ui_thread_->Stop();
file_thread_->Stop();
}
diff --git a/chromium/content/browser/browser_url_handler_impl.cc b/chromium/content/browser/browser_url_handler_impl.cc
index 1b7050f8ddf..7ea7ff787b9 100644
--- a/chromium/content/browser/browser_url_handler_impl.cc
+++ b/chromium/content/browser/browser_url_handler_impl.cc
@@ -4,9 +4,7 @@
#include "content/browser/browser_url_handler_impl.h"
-#include "base/command_line.h"
#include "base/strings/string_util.h"
-#include "cc/base/switches.h"
#include "content/browser/frame_host/debug_urls.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/public/browser/content_browser_client.h"
@@ -64,27 +62,12 @@ static bool ReverseViewSource(GURL* url, BrowserContext* browser_context) {
// No action necessary if the URL is already view-source:
if (url->SchemeIs(kViewSourceScheme))
return false;
-
- url::Replacements<char> repl;
- repl.SetScheme(kViewSourceScheme,
- url::Component(0, strlen(kViewSourceScheme)));
- repl.SetPath(url->spec().c_str(), url::Component(0, url->spec().size()));
- *url = url->ReplaceComponents(repl);
+ // Recreate the url with the view-source scheme.
+ *url = GURL(kViewSourceScheme + std::string(":") + url->spec());
return true;
}
static bool DebugURLHandler(GURL* url, BrowserContext* browser_context) {
- // If running inside the Telemetry test harness, allow automated
- // navigations to access browser-side debug URLs. They must use the
- // chrome:// scheme, since the about: scheme won't be rewritten in
- // this code path.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- cc::switches::kEnableGpuBenchmarking)) {
- if (HandleDebugURL(*url, PAGE_TRANSITION_FROM_ADDRESS_BAR)) {
- return true;
- }
- }
-
// Circumvent processing URLs that the renderer process will handle.
return IsRendererDebugURL(*url);
}
diff --git a/chromium/content/browser/browser_url_handler_impl.h b/chromium/content/browser/browser_url_handler_impl.h
index d0a150452ba..240554b7681 100644
--- a/chromium/content/browser/browser_url_handler_impl.h
+++ b/chromium/content/browser/browser_url_handler_impl.h
@@ -23,12 +23,11 @@ class CONTENT_EXPORT BrowserURLHandlerImpl : public BrowserURLHandler {
static BrowserURLHandlerImpl* GetInstance();
// BrowserURLHandler implementation:
- virtual void RewriteURLIfNecessary(GURL* url,
- BrowserContext* browser_context,
- bool* reverse_on_redirect) OVERRIDE;
+ void RewriteURLIfNecessary(GURL* url,
+ BrowserContext* browser_context,
+ bool* reverse_on_redirect) override;
// Add the specified handler pair to the list of URL handlers.
- virtual void AddHandlerPair(URLHandler handler,
- URLHandler reverse_handler) OVERRIDE;
+ void AddHandlerPair(URLHandler handler, URLHandler reverse_handler) override;
// Reverses the rewriting that was done for |original| using the new |url|.
bool ReverseURLRewrite(GURL* url, const GURL& original,
@@ -37,7 +36,7 @@ class CONTENT_EXPORT BrowserURLHandlerImpl : public BrowserURLHandler {
private:
// This object is a singleton:
BrowserURLHandlerImpl();
- virtual ~BrowserURLHandlerImpl();
+ ~BrowserURLHandlerImpl() override;
friend struct DefaultSingletonTraits<BrowserURLHandlerImpl>;
// The list of known URLHandlers, optionally with reverse-rewriters.
@@ -46,6 +45,7 @@ class CONTENT_EXPORT BrowserURLHandlerImpl : public BrowserURLHandler {
FRIEND_TEST_ALL_PREFIXES(BrowserURLHandlerImplTest, BasicRewriteAndReverse);
FRIEND_TEST_ALL_PREFIXES(BrowserURLHandlerImplTest, NullHandlerReverse);
+ FRIEND_TEST_ALL_PREFIXES(BrowserURLHandlerImplTest, ViewSourceReverse);
DISALLOW_COPY_AND_ASSIGN(BrowserURLHandlerImpl);
};
diff --git a/chromium/content/browser/browser_url_handler_impl_unittest.cc b/chromium/content/browser/browser_url_handler_impl_unittest.cc
index 4e8dc2115fd..daceffcee47 100644
--- a/chromium/content/browser/browser_url_handler_impl_unittest.cc
+++ b/chromium/content/browser/browser_url_handler_impl_unittest.cc
@@ -79,4 +79,19 @@ TEST_F(BrowserURLHandlerImplTest, NullHandlerReverse) {
ASSERT_EQ("foo://foo", url.spec());
}
+// Verify that the reverse handler for view-source does not duplicate query
+// parameters.
+TEST_F(BrowserURLHandlerImplTest, ViewSourceReverse) {
+ TestBrowserContext browser_context;
+ BrowserURLHandlerImpl handler;
+
+ GURL url("http://foo/?a=1");
+ GURL original_url("view-source:http://some_url");
+ bool reversed = handler.ReverseURLRewrite(&url,
+ original_url,
+ &browser_context);
+ ASSERT_TRUE(reversed);
+ ASSERT_EQ("view-source:http://foo/?a=1", url.spec());
+}
+
} // namespace content
diff --git a/chromium/content/browser/byte_stream.cc b/chromium/content/browser/byte_stream.cc
index 0cd3cd8c1b2..5c836bd6a0a 100644
--- a/chromium/content/browser/byte_stream.cc
+++ b/chromium/content/browser/byte_stream.cc
@@ -48,7 +48,7 @@ class ByteStreamWriterImpl : public ByteStreamWriter {
ByteStreamWriterImpl(scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<LifetimeFlag> lifetime_flag,
size_t buffer_size);
- virtual ~ByteStreamWriterImpl();
+ ~ByteStreamWriterImpl() override;
// Must be called before any operations are performed.
void SetPeer(ByteStreamReaderImpl* peer,
@@ -56,12 +56,11 @@ class ByteStreamWriterImpl : public ByteStreamWriter {
scoped_refptr<LifetimeFlag> peer_lifetime_flag);
// Overridden from ByteStreamWriter.
- virtual bool Write(scoped_refptr<net::IOBuffer> buffer,
- size_t byte_count) OVERRIDE;
- virtual void Flush() OVERRIDE;
- virtual void Close(int status) OVERRIDE;
- virtual void RegisterCallback(const base::Closure& source_callback) OVERRIDE;
- virtual size_t GetTotalBufferedBytes() const OVERRIDE;
+ bool Write(scoped_refptr<net::IOBuffer> buffer, size_t byte_count) override;
+ void Flush() override;
+ void Close(int status) override;
+ void RegisterCallback(const base::Closure& source_callback) override;
+ size_t GetTotalBufferedBytes() const override;
// PostTask target from |ByteStreamReaderImpl::MaybeUpdateInput|.
static void UpdateWindow(scoped_refptr<LifetimeFlag> lifetime_flag,
@@ -108,7 +107,7 @@ class ByteStreamReaderImpl : public ByteStreamReader {
ByteStreamReaderImpl(scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<LifetimeFlag> lifetime_flag,
size_t buffer_size);
- virtual ~ByteStreamReaderImpl();
+ ~ByteStreamReaderImpl() override;
// Must be called before any operations are performed.
void SetPeer(ByteStreamWriterImpl* peer,
@@ -116,10 +115,9 @@ class ByteStreamReaderImpl : public ByteStreamReader {
scoped_refptr<LifetimeFlag> peer_lifetime_flag);
// Overridden from ByteStreamReader.
- virtual StreamState Read(scoped_refptr<net::IOBuffer>* data,
- size_t* length) OVERRIDE;
- virtual int GetStatus() const OVERRIDE;
- virtual void RegisterCallback(const base::Closure& sink_callback) OVERRIDE;
+ StreamState Read(scoped_refptr<net::IOBuffer>* data, size_t* length) override;
+ int GetStatus() const override;
+ void RegisterCallback(const base::Closure& sink_callback) override;
// PostTask target from |ByteStreamWriterImpl::Write| and
// |ByteStreamWriterImpl::Close|.
diff --git a/chromium/content/browser/cert_store_impl.h b/chromium/content/browser/cert_store_impl.h
index cba87207d27..d8b689c17b0 100644
--- a/chromium/content/browser/cert_store_impl.h
+++ b/chromium/content/browser/cert_store_impl.h
@@ -18,14 +18,14 @@ class CertStoreImpl : public CertStore {
static CertStoreImpl* GetInstance();
// CertStore implementation:
- virtual int StoreCert(net::X509Certificate* cert,
- int render_process_host_id) OVERRIDE;
- virtual bool RetrieveCert(int cert_id,
- scoped_refptr<net::X509Certificate>* cert) OVERRIDE;
+ int StoreCert(net::X509Certificate* cert,
+ int render_process_host_id) override;
+ bool RetrieveCert(int cert_id,
+ scoped_refptr<net::X509Certificate>* cert) override;
protected:
CertStoreImpl();
- virtual ~CertStoreImpl();
+ ~CertStoreImpl() override;
private:
friend struct DefaultSingletonTraits<CertStoreImpl>;
diff --git a/chromium/content/browser/child_process_launcher.cc b/chromium/content/browser/child_process_launcher.cc
index 5e65042301c..e47bebc3bdf 100644
--- a/chromium/content/browser/child_process_launcher.cc
+++ b/chromium/content/browser/child_process_launcher.cc
@@ -8,7 +8,7 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -45,6 +45,7 @@
#if defined(OS_POSIX)
#include "base/metrics/stats_table.h"
#include "base/posix/global_descriptors.h"
+#include "content/browser/file_descriptor_info_impl.h"
#endif
namespace content {
@@ -74,11 +75,10 @@ class ChildProcessLauncher::Context
{
}
- void Launch(
- SandboxedProcessLauncherDelegate* delegate,
- CommandLine* cmd_line,
- int child_process_id,
- Client* client) {
+ void Launch(SandboxedProcessLauncherDelegate* delegate,
+ base::CommandLine* cmd_line,
+ int child_process_id,
+ Client* client) {
client_ = client;
CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
@@ -87,17 +87,16 @@ class ChildProcessLauncher::Context
// We need to close the client end of the IPC channel to reliably detect
// child termination. We will close this fd after we create the child
// process which is asynchronous on Android.
- ipcfd_ = delegate->GetIpcFd();
+ ipcfd_.reset(delegate->TakeIpcFd().release());
#endif
BrowserThread::PostTask(
BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
- base::Bind(
- &Context::LaunchInternal,
- make_scoped_refptr(this),
- client_thread_id_,
- child_process_id,
- delegate,
- cmd_line));
+ base::Bind(&Context::LaunchInternal,
+ make_scoped_refptr(this),
+ client_thread_id_,
+ child_process_id,
+ delegate,
+ cmd_line));
}
#if defined(OS_ANDROID)
@@ -111,14 +110,14 @@ class ChildProcessLauncher::Context
if (BrowserThread::CurrentlyOn(client_thread_id)) {
// This is always invoked on the UI thread which is commonly the
// |client_thread_id| so we can shortcut one PostTask.
- this_object->Notify(handle);
+ this_object->Notify(base::Process(handle));
} else {
BrowserThread::PostTask(
client_thread_id, FROM_HERE,
base::Bind(
&ChildProcessLauncher::Context::Notify,
this_object,
- handle));
+ base::Passed(base::Process(handle))));
}
}
#endif
@@ -134,6 +133,19 @@ class ChildProcessLauncher::Context
terminate_child_on_shutdown_ = terminate_on_shutdown;
}
+ void GetTerminationStatus() {
+ termination_status_ =
+ base::GetTerminationStatus(process_.Handle(), &exit_code_);
+ }
+
+ void SetProcessBackgrounded(bool background) {
+ base::Process to_pass = process_.Duplicate();
+ BrowserThread::PostTask(
+ BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
+ base::Bind(&Context::SetProcessBackgroundedInternal,
+ base::Passed(&to_pass), background));
+ }
+
private:
friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>;
friend class ChildProcessLauncher;
@@ -172,21 +184,21 @@ class ChildProcessLauncher::Context
BrowserThread::ID client_thread_id,
int child_process_id,
SandboxedProcessLauncherDelegate* delegate,
- CommandLine* cmd_line) {
+ base::CommandLine* cmd_line) {
scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate);
#if defined(OS_WIN)
bool launch_elevated = delegate->ShouldLaunchElevated();
#elif defined(OS_ANDROID)
- int ipcfd = delegate->GetIpcFd();
+ // Uses |ipcfd_| instead of |ipcfd| on Android.
#elif defined(OS_MACOSX)
base::EnvironmentMap env = delegate->GetEnvironment();
- int ipcfd = delegate->GetIpcFd();
+ base::ScopedFD ipcfd = delegate->TakeIpcFd();
#elif defined(OS_POSIX)
bool use_zygote = delegate->ShouldUseZygote();
base::EnvironmentMap env = delegate->GetEnvironment();
- int ipcfd = delegate->GetIpcFd();
+ base::ScopedFD ipcfd = delegate->TakeIpcFd();
#endif
- scoped_ptr<CommandLine> cmd_line_deleter(cmd_line);
+ scoped_ptr<base::CommandLine> cmd_line_deleter(cmd_line);
base::TimeTicks begin_launch_time = base::TimeTicks::Now();
#if defined(OS_WIN)
@@ -201,17 +213,21 @@ class ChildProcessLauncher::Context
#elif defined(OS_POSIX)
std::string process_type =
cmd_line->GetSwitchValueASCII(switches::kProcessType);
- std::vector<FileDescriptorInfo> files_to_register;
- files_to_register.push_back(
- FileDescriptorInfo(kPrimaryIPCChannel,
- base::FileDescriptor(ipcfd, false)));
+ scoped_ptr<FileDescriptorInfo> files_to_register(
+ FileDescriptorInfoImpl::Create());
+
+#if defined(OS_ANDROID)
+ files_to_register->Share(kPrimaryIPCChannel, this_object->ipcfd_.get());
+#else
+ files_to_register->Transfer(kPrimaryIPCChannel, ipcfd.Pass());
+#endif
base::StatsTable* stats_table = base::StatsTable::current();
if (stats_table &&
base::SharedMemory::IsHandleValid(
stats_table->GetSharedMemoryHandle())) {
- files_to_register.push_back(
- FileDescriptorInfo(kStatsTableSharedMemFd,
- stats_table->GetSharedMemoryHandle()));
+ base::FileDescriptor fd = stats_table->GetSharedMemoryHandle();
+ DCHECK(!fd.auto_close);
+ files_to_register->Share(kStatsTableSharedMemFd, fd.fd);
}
#endif
@@ -220,40 +236,37 @@ class ChildProcessLauncher::Context
// when running in single process mode.
CHECK(!cmd_line->HasSwitch(switches::kSingleProcess));
- GetContentClient()->browser()->
- GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
- &files_to_register);
+ GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
+ *cmd_line, child_process_id, files_to_register.get());
- StartChildProcess(cmd_line->argv(), child_process_id, files_to_register,
+ StartChildProcess(
+ cmd_line->argv(),
+ child_process_id,
+ files_to_register.Pass(),
base::Bind(&ChildProcessLauncher::Context::OnChildProcessStarted,
- this_object, client_thread_id, begin_launch_time));
+ this_object,
+ client_thread_id,
+ begin_launch_time));
#elif defined(OS_POSIX)
base::ProcessHandle handle = base::kNullProcessHandle;
// We need to close the client end of the IPC channel to reliably detect
// child termination.
- base::ScopedFD ipcfd_closer(ipcfd);
#if !defined(OS_MACOSX)
- GetContentClient()->browser()->
- GetAdditionalMappedFilesForChildProcess(*cmd_line, child_process_id,
- &files_to_register);
+ GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
+ *cmd_line, child_process_id, files_to_register.get());
if (use_zygote) {
- handle = ZygoteHostImpl::GetInstance()->ForkRequest(cmd_line->argv(),
- files_to_register,
- process_type);
+ handle = ZygoteHostImpl::GetInstance()->ForkRequest(
+ cmd_line->argv(), files_to_register.Pass(), process_type);
} else
// Fall through to the normal posix case below when we're not zygoting.
#endif // !defined(OS_MACOSX)
{
// Convert FD mapping to FileHandleMappingVector
- base::FileHandleMappingVector fds_to_map;
- for (size_t i = 0; i < files_to_register.size(); ++i) {
- fds_to_map.push_back(std::make_pair(
- files_to_register[i].fd.fd,
- files_to_register[i].id +
- base::GlobalDescriptors::kBaseDescriptor));
- }
+ base::FileHandleMappingVector fds_to_map =
+ files_to_register->GetMappingWithIDAdjustment(
+ base::GlobalDescriptors::kBaseDescriptor);
#if !defined(OS_MACOSX)
if (process_type == switches::kRendererProcess) {
@@ -325,7 +338,7 @@ class ChildProcessLauncher::Context
#if defined(OS_POSIX) && !defined(OS_MACOSX)
use_zygote,
#endif
- handle));
+ base::Passed(base::Process(handle))));
#endif // !defined(OS_ANDROID)
}
@@ -333,21 +346,21 @@ class ChildProcessLauncher::Context
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
bool zygote,
#endif
- base::ProcessHandle handle) {
+ base::Process process) {
#if defined(OS_ANDROID)
// Finally close the ipcfd
- base::ScopedFD ipcfd_closer(ipcfd_);
+ base::ScopedFD ipcfd_closer = ipcfd_.Pass();
#endif
starting_ = false;
- process_.set_handle(handle);
- if (!handle)
+ process_ = process.Pass();
+ if (!process_.IsValid())
LOG(ERROR) << "Failed to launch child process";
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
zygote_ = zygote;
#endif
if (client_) {
- if (handle) {
+ if (process_.IsValid()) {
client_->OnProcessLaunched();
} else {
client_->OnProcessLaunchFailed();
@@ -358,7 +371,7 @@ class ChildProcessLauncher::Context
}
void Terminate() {
- if (!process_.handle())
+ if (!process_.IsValid())
return;
if (!terminate_child_on_shutdown_)
@@ -373,16 +386,14 @@ class ChildProcessLauncher::Context
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
zygote_,
#endif
- process_.handle()));
- process_.set_handle(base::kNullProcessHandle);
+ base::Passed(&process_)));
}
- static void SetProcessBackgrounded(base::ProcessHandle handle,
- bool background) {
- base::Process process(handle);
+ static void SetProcessBackgroundedInternal(base::Process process,
+ bool background) {
process.SetProcessBackgrounded(background);
#if defined(OS_ANDROID)
- SetChildProcessInForeground(handle, !background);
+ SetChildProcessInForeground(process.Handle(), !background);
#endif
}
@@ -390,12 +401,12 @@ class ChildProcessLauncher::Context
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
bool zygote,
#endif
- base::ProcessHandle handle) {
+ base::Process process) {
#if defined(OS_ANDROID)
- VLOG(0) << "ChromeProcess: Stopping process with handle " << handle;
- StopChildProcess(handle);
+ VLOG(1) << "ChromeProcess: Stopping process with handle "
+ << process.Handle();
+ StopChildProcess(process.Handle());
#else
- base::Process process(handle);
// Client has gone away, so just kill the process. Using exit code 0
// means that UMA won't treat this as a crash.
process.Terminate(RESULT_CODE_NORMAL_EXIT);
@@ -405,14 +416,13 @@ class ChildProcessLauncher::Context
if (zygote) {
// If the renderer was created via a zygote, we have to proxy the reaping
// through the zygote process.
- ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(handle);
+ ZygoteHostImpl::GetInstance()->EnsureProcessTerminated(process.Handle());
} else
#endif // !OS_MACOSX
{
- base::EnsureProcessTerminated(handle);
+ base::EnsureProcessTerminated(process.Handle());
}
#endif // OS_POSIX
- process.Close();
#endif // defined(OS_ANDROID)
}
@@ -427,7 +437,7 @@ class ChildProcessLauncher::Context
bool terminate_child_on_shutdown_;
#if defined(OS_ANDROID)
// The fd to close after creating the process.
- int ipcfd_;
+ base::ScopedFD ipcfd_;
#elif defined(OS_POSIX) && !defined(OS_MACOSX)
bool zygote_;
#endif
@@ -436,7 +446,7 @@ class ChildProcessLauncher::Context
ChildProcessLauncher::ChildProcessLauncher(
SandboxedProcessLauncherDelegate* delegate,
- CommandLine* cmd_line,
+ base::CommandLine* cmd_line,
int child_process_id,
Client* client) {
context_ = new Context();
@@ -455,16 +465,15 @@ bool ChildProcessLauncher::IsStarting() {
return context_->starting_;
}
-base::ProcessHandle ChildProcessLauncher::GetHandle() {
+const base::Process& ChildProcessLauncher::GetProcess() const {
DCHECK(!context_->starting_);
- return context_->process_.handle();
+ return context_->process_;
}
base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
bool known_dead,
int* exit_code) {
- base::ProcessHandle handle = context_->process_.handle();
- if (handle == base::kNullProcessHandle) {
+ if (!context_->process_.IsValid()) {
// Process is already gone, so return the cached termination status.
if (exit_code)
*exit_code = context_->exit_code_;
@@ -473,25 +482,27 @@ base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
if (context_->zygote_) {
context_->termination_status_ = ZygoteHostImpl::GetInstance()->
- GetTerminationStatus(handle, known_dead, &context_->exit_code_);
+ GetTerminationStatus(context_->process_.Handle(), known_dead,
+ &context_->exit_code_);
} else if (known_dead) {
context_->termination_status_ =
- base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_);
+ base::GetKnownDeadTerminationStatus(context_->process_.Handle(),
+ &context_->exit_code_);
} else {
#elif defined(OS_MACOSX)
if (known_dead) {
context_->termination_status_ =
- base::GetKnownDeadTerminationStatus(handle, &context_->exit_code_);
+ base::GetKnownDeadTerminationStatus(context_->process_.Handle(),
+ &context_->exit_code_);
} else {
#elif defined(OS_ANDROID)
- if (IsChildProcessOomProtected(handle)) {
- context_->termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
+ if (IsChildProcessOomProtected(context_->process_.Handle())) {
+ context_->termination_status_ = base::TERMINATION_STATUS_OOM_PROTECTED;
} else {
#else
{
#endif
- context_->termination_status_ =
- base::GetTerminationStatus(handle, &context_->exit_code_);
+ context_->GetTerminationStatus();
}
if (exit_code)
@@ -510,11 +521,7 @@ base::TerminationStatus ChildProcessLauncher::GetChildTerminationStatus(
}
void ChildProcessLauncher::SetProcessBackgrounded(bool background) {
- BrowserThread::PostTask(
- BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
- base::Bind(
- &ChildProcessLauncher::Context::SetProcessBackgrounded,
- GetHandle(), background));
+ context_->SetProcessBackgrounded(background);
}
void ChildProcessLauncher::SetTerminateChildOnShutdown(
diff --git a/chromium/content/browser/child_process_launcher.h b/chromium/content/browser/child_process_launcher.h
index cc8b3f52cef..de890a92e40 100644
--- a/chromium/content/browser/child_process_launcher.h
+++ b/chromium/content/browser/child_process_launcher.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
+#include "base/process/process.h"
#include "content/common/content_export.h"
namespace base {
@@ -50,8 +51,8 @@ class CONTENT_EXPORT ChildProcessLauncher {
// True if the process is being launched and so the handle isn't available.
bool IsStarting();
- // Getter for the process handle. Only call after the process has started.
- base::ProcessHandle GetHandle();
+ // Getter for the process. Only call after the process has started.
+ const base::Process& GetProcess() const;
// Call this when the child process exits to know what happened to it.
// |known_dead| can be true if we already know the process is dead as it can
diff --git a/chromium/content/browser/child_process_launcher_browsertest.cc b/chromium/content/browser/child_process_launcher_browsertest.cc
new file mode 100644
index 00000000000..fe3fa1da32b
--- /dev/null
+++ b/chromium/content/browser/child_process_launcher_browsertest.cc
@@ -0,0 +1,25 @@
+// 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 "base/command_line.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+
+namespace content {
+
+typedef ContentBrowserTest ChildProcessLauncherBrowserTest;
+
+class StatsTableBrowserTest : public ChildProcessLauncherBrowserTest {
+ public:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kEnableStatsTable);
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(StatsTableBrowserTest, StartWithStatTable) {
+ NavigateToURL(shell(), GURL("about:blank"));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/child_process_security_policy_browsertest.cc b/chromium/content/browser/child_process_security_policy_browsertest.cc
index 67d36e4eabf..b509a494706 100644
--- a/chromium/content/browser/child_process_security_policy_browsertest.cc
+++ b/chromium/content/browser/child_process_security_policy_browsertest.cc
@@ -20,14 +20,14 @@ namespace content {
class ChildProcessSecurityPolicyInProcessBrowserTest
: public ContentBrowserTest {
public:
- virtual void SetUp() {
+ void SetUp() override {
EXPECT_EQ(
ChildProcessSecurityPolicyImpl::GetInstance()->security_state_.size(),
0U);
ContentBrowserTest::SetUp();
}
- virtual void TearDown() {
+ void TearDown() override {
EXPECT_EQ(
ChildProcessSecurityPolicyImpl::GetInstance()->security_state_.size(),
0U);
diff --git a/chromium/content/browser/child_process_security_policy_impl.cc b/chromium/content/browser/child_process_security_policy_impl.cc
index 68f4e81fbef..34caa5a4923 100644
--- a/chromium/content/browser/child_process_security_policy_impl.cc
+++ b/chromium/content/browser/child_process_security_policy_impl.cc
@@ -20,11 +20,11 @@
#include "content/public/common/url_constants.h"
#include "net/base/filename_util.h"
#include "net/url_request/url_request.h"
+#include "storage/browser/fileapi/file_permission_policy.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_permission_policy.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/common/fileapi/file_system_util.h"
namespace content {
@@ -76,8 +76,8 @@ class ChildProcessSecurityPolicyImpl::SecurityState {
~SecurityState() {
scheme_policy_.clear();
- fileapi::IsolatedContext* isolated_context =
- fileapi::IsolatedContext::GetInstance();
+ storage::IsolatedContext* isolated_context =
+ storage::IsolatedContext::GetInstance();
for (FileSystemMap::iterator iter = filesystem_permissions_.begin();
iter != filesystem_permissions_.end();
++iter) {
@@ -121,7 +121,7 @@ class ChildProcessSecurityPolicyImpl::SecurityState {
void GrantPermissionsForFileSystem(const std::string& filesystem_id,
int permissions) {
if (!ContainsKey(filesystem_permissions_, filesystem_id))
- fileapi::IsolatedContext::GetInstance()->AddReference(filesystem_id);
+ storage::IsolatedContext::GetInstance()->AddReference(filesystem_id);
filesystem_permissions_[filesystem_id] |= permissions;
}
@@ -241,7 +241,8 @@ class ChildProcessSecurityPolicyImpl::SecurityState {
// compatibility with many sites. The similar --site-per-process flag only
// blocks JavaScript access to cross-site cookies (in
// CanAccessCookiesForOrigin).
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
return true;
@@ -580,14 +581,14 @@ void ChildProcessSecurityPolicyImpl::RevokeReadRawCookies(int child_id) {
state->second->RevokeReadRawCookies();
}
-bool ChildProcessSecurityPolicyImpl::CanLoadPage(
- int child_id,
- const GURL& url,
- ResourceType::Type resource_type) {
+bool ChildProcessSecurityPolicyImpl::CanLoadPage(int child_id,
+ const GURL& url,
+ ResourceType resource_type) {
// If --site-per-process flag is passed, we should enforce
// stronger security restrictions on page navigation.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
- ResourceType::IsFrame(resource_type)) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess) &&
+ IsResourceTypeFrame(resource_type)) {
// TODO(nasko): Do the proper check for site-per-process, once
// out-of-process iframes is ready to go.
return true;
@@ -696,7 +697,9 @@ bool ChildProcessSecurityPolicyImpl::HasPermissionsForFile(
}
bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile(
- int child_id, const fileapi::FileSystemURL& url, int permissions) {
+ int child_id,
+ const storage::FileSystemURL& url,
+ int permissions) {
if (!url.is_valid())
return false;
@@ -704,12 +707,12 @@ bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile(
return false;
// Any write access is disallowed on the root path.
- if (fileapi::VirtualPath::IsRootPath(url.path()) &&
+ if (storage::VirtualPath::IsRootPath(url.path()) &&
(permissions & ~READ_FILE_GRANT)) {
return false;
}
- if (url.mount_type() == fileapi::kFileSystemTypeIsolated) {
+ if (url.mount_type() == storage::kFileSystemTypeIsolated) {
// When Isolated filesystems is overlayed on top of another filesystem,
// its per-filesystem permission overrides the underlying filesystem
// permissions).
@@ -722,15 +725,15 @@ bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile(
if (found == file_system_policy_map_.end())
return false;
- if ((found->second & fileapi::FILE_PERMISSION_READ_ONLY) &&
+ if ((found->second & storage::FILE_PERMISSION_READ_ONLY) &&
permissions & ~READ_FILE_GRANT) {
return false;
}
- if (found->second & fileapi::FILE_PERMISSION_USE_FILE_PERMISSION)
+ if (found->second & storage::FILE_PERMISSION_USE_FILE_PERMISSION)
return HasPermissionsForFile(child_id, url.path(), permissions);
- if (found->second & fileapi::FILE_PERMISSION_SANDBOX)
+ if (found->second & storage::FILE_PERMISSION_SANDBOX)
return true;
return false;
@@ -738,38 +741,38 @@ bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystemFile(
bool ChildProcessSecurityPolicyImpl::CanReadFileSystemFile(
int child_id,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
return HasPermissionsForFileSystemFile(child_id, url, READ_FILE_GRANT);
}
bool ChildProcessSecurityPolicyImpl::CanWriteFileSystemFile(
int child_id,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
return HasPermissionsForFileSystemFile(child_id, url, WRITE_FILE_GRANT);
}
bool ChildProcessSecurityPolicyImpl::CanCreateFileSystemFile(
int child_id,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
return HasPermissionsForFileSystemFile(child_id, url, CREATE_NEW_FILE_GRANT);
}
bool ChildProcessSecurityPolicyImpl::CanCreateReadWriteFileSystemFile(
int child_id,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
return HasPermissionsForFileSystemFile(child_id, url,
CREATE_READ_WRITE_FILE_GRANT);
}
bool ChildProcessSecurityPolicyImpl::CanCopyIntoFileSystemFile(
int child_id,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
return HasPermissionsForFileSystemFile(child_id, url, COPY_INTO_FILE_GRANT);
}
bool ChildProcessSecurityPolicyImpl::CanDeleteFileSystemFile(
int child_id,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
return HasPermissionsForFileSystemFile(child_id, url, DELETE_FILE_GRANT);
}
@@ -874,7 +877,7 @@ bool ChildProcessSecurityPolicyImpl::HasPermissionsForFileSystem(
}
void ChildProcessSecurityPolicyImpl::RegisterFileSystemPermissionPolicy(
- fileapi::FileSystemType type,
+ storage::FileSystemType type,
int policy) {
base::AutoLock lock(lock_);
file_system_policy_map_[type] = policy;
diff --git a/chromium/content/browser/child_process_security_policy_impl.h b/chromium/content/browser/child_process_security_policy_impl.h
index 005292cdf2b..dcc1b887fab 100644
--- a/chromium/content/browser/child_process_security_policy_impl.h
+++ b/chromium/content/browser/child_process_security_policy_impl.h
@@ -15,8 +15,8 @@
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/child_process_security_policy.h"
-#include "webkit/common/fileapi/file_system_types.h"
-#include "webkit/common/resource_type.h"
+#include "content/public/common/resource_type.h"
+#include "storage/common/fileapi/file_system_types.h"
class GURL;
@@ -24,7 +24,7 @@ namespace base {
class FilePath;
}
-namespace fileapi {
+namespace storage {
class FileSystemURL;
}
@@ -35,51 +35,44 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
public:
// Object can only be created through GetInstance() so the constructor is
// private.
- virtual ~ChildProcessSecurityPolicyImpl();
+ ~ChildProcessSecurityPolicyImpl() override;
static ChildProcessSecurityPolicyImpl* GetInstance();
// ChildProcessSecurityPolicy implementation.
- virtual void RegisterWebSafeScheme(const std::string& scheme) OVERRIDE;
- virtual bool IsWebSafeScheme(const std::string& scheme) OVERRIDE;
- virtual void GrantReadFile(int child_id, const base::FilePath& file) OVERRIDE;
- virtual void GrantCreateReadWriteFile(int child_id,
- const base::FilePath& file) OVERRIDE;
- virtual void GrantCopyInto(int child_id, const base::FilePath& dir) OVERRIDE;
- virtual void GrantDeleteFrom(int child_id,
- const base::FilePath& dir) OVERRIDE;
- virtual void GrantReadFileSystem(
+ void RegisterWebSafeScheme(const std::string& scheme) override;
+ bool IsWebSafeScheme(const std::string& scheme) override;
+ void GrantReadFile(int child_id, const base::FilePath& file) override;
+ void GrantCreateReadWriteFile(int child_id,
+ const base::FilePath& file) override;
+ void GrantCopyInto(int child_id, const base::FilePath& dir) override;
+ void GrantDeleteFrom(int child_id, const base::FilePath& dir) override;
+ void GrantReadFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ void GrantWriteFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ void GrantCreateFileForFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ void GrantCreateReadWriteFileSystem(
int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual void GrantWriteFileSystem(
- int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual void GrantCreateFileForFileSystem(
- int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual void GrantCreateReadWriteFileSystem(
- int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual void GrantCopyIntoFileSystem(
- int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual void GrantDeleteFromFileSystem(
- int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual void GrantScheme(int child_id, const std::string& scheme) OVERRIDE;
- virtual bool CanReadFile(int child_id, const base::FilePath& file) OVERRIDE;
- virtual bool CanCreateReadWriteFile(int child_id,
- const base::FilePath& file) OVERRIDE;
- virtual bool CanReadFileSystem(int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual bool CanReadWriteFileSystem(
- int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual bool CanCopyIntoFileSystem(int child_id,
- const std::string& filesystem_id) OVERRIDE;
- virtual bool CanDeleteFromFileSystem(
- int child_id,
- const std::string& filesystem_id) OVERRIDE;
+ const std::string& filesystem_id) override;
+ void GrantCopyIntoFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ void GrantDeleteFromFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ void GrantScheme(int child_id, const std::string& scheme) override;
+ bool CanReadFile(int child_id, const base::FilePath& file) override;
+ bool CanCreateReadWriteFile(int child_id,
+ const base::FilePath& file) override;
+ bool CanReadFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ bool CanReadWriteFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ bool CanCopyIntoFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ bool CanDeleteFromFileSystem(int child_id,
+ const std::string& filesystem_id) override;
+ bool HasWebUIBindings(int child_id) override;
// Pseudo schemes are treated differently than other schemes because they
// cannot be requested like normal URLs. There is no mechanism for revoking
@@ -139,23 +132,17 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
// Only might return false if --site-per-process flag is used.
bool CanLoadPage(int child_id,
const GURL& url,
- ResourceType::Type resource_type);
+ ResourceType resource_type);
// Explicit permissions checks for FileSystemURL specified files.
- bool CanReadFileSystemFile(int child_id, const fileapi::FileSystemURL& url);
- bool CanWriteFileSystemFile(int child_id, const fileapi::FileSystemURL& url);
- bool CanCreateFileSystemFile(int child_id, const fileapi::FileSystemURL& url);
+ bool CanReadFileSystemFile(int child_id, const storage::FileSystemURL& url);
+ bool CanWriteFileSystemFile(int child_id, const storage::FileSystemURL& url);
+ bool CanCreateFileSystemFile(int child_id, const storage::FileSystemURL& url);
bool CanCreateReadWriteFileSystemFile(int child_id,
- const fileapi::FileSystemURL& url);
+ const storage::FileSystemURL& url);
bool CanCopyIntoFileSystemFile(int child_id,
- const fileapi::FileSystemURL& url);
- bool CanDeleteFileSystemFile(int child_id,
- const fileapi::FileSystemURL& url);
-
- // Returns true if the specified child_id has been granted WebUIBindings.
- // The browser should check this property before assuming the child process is
- // allowed to use WebUIBindings.
- bool HasWebUIBindings(int child_id);
+ const storage::FileSystemURL& url);
+ bool CanDeleteFileSystemFile(int child_id, const storage::FileSystemURL& url);
// Returns true if the specified child_id has been granted ReadRawCookies.
bool CanReadRawCookies(int child_id);
@@ -181,10 +168,9 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
// Register FileSystem type and permission policy which should be used
// for the type. The |policy| must be a bitwise-or'd value of
- // fileapi::FilePermissionPolicy.
- void RegisterFileSystemPermissionPolicy(
- fileapi::FileSystemType type,
- int policy);
+ // storage::FilePermissionPolicy.
+ void RegisterFileSystemPermissionPolicy(storage::FileSystemType type,
+ int policy);
// Returns true if sending system exclusive messages is allowed.
bool CanSendMidiSysExMessage(int child_id);
@@ -201,7 +187,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
typedef std::set<std::string> SchemeSet;
typedef std::map<int, SecurityState*> SecurityStateMap;
typedef std::map<int, int> WorkerToMainProcessMap;
- typedef std::map<fileapi::FileSystemType, int> FileSystemPermissionPolicyMap;
+ typedef std::map<storage::FileSystemType, int> FileSystemPermissionPolicyMap;
// Obtain an instance of ChildProcessSecurityPolicyImpl via GetInstance().
ChildProcessSecurityPolicyImpl();
@@ -241,7 +227,7 @@ class CONTENT_EXPORT ChildProcessSecurityPolicyImpl
// Determines if certain permissions were granted for a file in FileSystem
// API. |permissions| is an internally defined bit-set.
bool HasPermissionsForFileSystemFile(int child_id,
- const fileapi::FileSystemURL& url,
+ const storage::FileSystemURL& url,
int permissions);
// Determines if certain permissions were granted for a file system.
diff --git a/chromium/content/browser/child_process_security_policy_unittest.cc b/chromium/content/browser/child_process_security_policy_unittest.cc
index 97c1889b3d7..678e3d207f8 100644
--- a/chromium/content/browser/child_process_security_policy_unittest.cc
+++ b/chromium/content/browser/child_process_security_policy_unittest.cc
@@ -10,12 +10,12 @@
#include "content/browser/child_process_security_policy_impl.h"
#include "content/public/common/url_constants.h"
#include "content/test/test_content_browser_client.h"
+#include "storage/browser/fileapi/file_permission_policy.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/common/fileapi/file_system_types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_permission_policy.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/common/fileapi/file_system_types.h"
namespace content {
namespace {
@@ -34,7 +34,7 @@ class ChildProcessSecurityPolicyTestBrowserClient
public:
ChildProcessSecurityPolicyTestBrowserClient() {}
- virtual bool IsHandledURL(const GURL& url) OVERRIDE {
+ bool IsHandledURL(const GURL& url) override {
return schemes_.find(url.scheme()) != schemes_.end();
}
@@ -57,7 +57,7 @@ class ChildProcessSecurityPolicyTest : public testing::Test {
ChildProcessSecurityPolicyTest() : old_browser_client_(NULL) {
}
- virtual void SetUp() {
+ void SetUp() override {
old_browser_client_ = SetBrowserClientForTesting(&test_browser_client_);
// Claim to always handle chrome:// URLs because the CPSP's notion of
@@ -71,7 +71,7 @@ class ChildProcessSecurityPolicyTest : public testing::Test {
test_browser_client_.AddScheme(url::kFileScheme);
}
- virtual void TearDown() {
+ void TearDown() override {
test_browser_client_.ClearSchemes();
SetBrowserClientForTesting(old_browser_client_);
}
@@ -98,7 +98,7 @@ class ChildProcessSecurityPolicyTest : public testing::Test {
void CheckHasNoFileSystemFilePermission(ChildProcessSecurityPolicyImpl* p,
const base::FilePath& file,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
EXPECT_FALSE(p->CanReadFile(kRendererID, file));
EXPECT_FALSE(p->CanCreateReadWriteFile(kRendererID, file));
EXPECT_FALSE(p->CanReadFileSystemFile(kRendererID, url));
@@ -308,22 +308,24 @@ TEST_F(ChildProcessSecurityPolicyTest, FileSystemGrantsTest) {
ChildProcessSecurityPolicyImpl::GetInstance();
p->Add(kRendererID);
- std::string read_id = fileapi::IsolatedContext::GetInstance()->
- RegisterFileSystemForVirtualPath(fileapi::kFileSystemTypeTest,
- "read_filesystem",
- base::FilePath());
- std::string read_write_id = fileapi::IsolatedContext::GetInstance()->
- RegisterFileSystemForVirtualPath(fileapi::kFileSystemTypeTest,
- "read_write_filesystem",
- base::FilePath());
- std::string copy_into_id = fileapi::IsolatedContext::GetInstance()->
- RegisterFileSystemForVirtualPath(fileapi::kFileSystemTypeTest,
- "copy_into_filesystem",
- base::FilePath());
- std::string delete_from_id = fileapi::IsolatedContext::GetInstance()->
- RegisterFileSystemForVirtualPath(fileapi::kFileSystemTypeTest,
- "delete_from_filesystem",
- base::FilePath());
+ std::string read_id =
+ storage::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
+ storage::kFileSystemTypeTest, "read_filesystem", base::FilePath());
+ std::string read_write_id =
+ storage::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
+ storage::kFileSystemTypeTest,
+ "read_write_filesystem",
+ base::FilePath());
+ std::string copy_into_id =
+ storage::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
+ storage::kFileSystemTypeTest,
+ "copy_into_filesystem",
+ base::FilePath());
+ std::string delete_from_id =
+ storage::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
+ storage::kFileSystemTypeTest,
+ "delete_from_filesystem",
+ base::FilePath());
// Test initially having no permissions.
CheckHasNoFileSystemPermission(p, read_id);
@@ -373,10 +375,10 @@ TEST_F(ChildProcessSecurityPolicyTest, FileSystemGrantsTest) {
// Cleanup.
p->Remove(kRendererID);
- fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(read_id);
- fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(read_write_id);
- fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(copy_into_id);
- fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(delete_from_id);
+ storage::IsolatedContext::GetInstance()->RevokeFileSystem(read_id);
+ storage::IsolatedContext::GetInstance()->RevokeFileSystem(read_write_id);
+ storage::IsolatedContext::GetInstance()->RevokeFileSystem(copy_into_id);
+ storage::IsolatedContext::GetInstance()->RevokeFileSystem(delete_from_id);
}
TEST_F(ChildProcessSecurityPolicyTest, FilePermissionGrantingAndRevoking) {
@@ -384,14 +386,14 @@ TEST_F(ChildProcessSecurityPolicyTest, FilePermissionGrantingAndRevoking) {
ChildProcessSecurityPolicyImpl::GetInstance();
p->RegisterFileSystemPermissionPolicy(
- fileapi::kFileSystemTypeTest,
- fileapi::FILE_PERMISSION_USE_FILE_PERMISSION);
+ storage::kFileSystemTypeTest,
+ storage::FILE_PERMISSION_USE_FILE_PERMISSION);
p->Add(kRendererID);
base::FilePath file(TEST_PATH("/dir/testfile"));
file = file.NormalizePathSeparators();
- fileapi::FileSystemURL url = fileapi::FileSystemURL::CreateForTest(
- GURL("http://foo/"), fileapi::kFileSystemTypeTest, file);
+ storage::FileSystemURL url = storage::FileSystemURL::CreateForTest(
+ GURL("http://foo/"), storage::kFileSystemTypeTest, file);
// Test initially having no permissions.
CheckHasNoFileSystemFilePermission(p, file, url);
diff --git a/chromium/content/browser/cocoa/system_hotkey_helper_mac.h b/chromium/content/browser/cocoa/system_hotkey_helper_mac.h
new file mode 100644
index 00000000000..63d9e514854
--- /dev/null
+++ b/chromium/content/browser/cocoa/system_hotkey_helper_mac.h
@@ -0,0 +1,56 @@
+// 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_COCOA_SYSTEM_HOTKEY_HELPER_MAC_H_
+#define CONTENT_BROWSER_COCOA_SYSTEM_HOTKEY_HELPER_MAC_H_
+
+#include "base/memory/singleton.h"
+#include "base/memory/weak_ptr.h"
+
+#ifdef __OBJC__
+@class NSDictionary;
+#else
+class NSDictionary;
+#endif
+
+namespace content {
+
+class SystemHotkeyMap;
+
+// This singleton holds a global mapping of hotkeys reserved by OSX.
+class SystemHotkeyHelperMac {
+ public:
+ // Return pointer to the singleton instance for the current process.
+ static SystemHotkeyHelperMac* GetInstance();
+
+ // Loads the system hot keys after a brief delay, to reduce file system access
+ // immediately after launch.
+ void DeferredLoadSystemHotkeys();
+
+ // Guaranteed to not be NULL.
+ SystemHotkeyMap* map() { return map_.get(); }
+
+ private:
+ friend struct DefaultSingletonTraits<SystemHotkeyHelperMac>;
+
+ SystemHotkeyHelperMac();
+ ~SystemHotkeyHelperMac();
+
+ // Must be called from the FILE thread. Loads the file containing the system
+ // hotkeys into a NSDictionary* object, and passes the result to FileDidLoad
+ // on the UI thread.
+ void LoadSystemHotkeys();
+
+ // Must be called from the UI thread. This takes ownership of |dictionary|.
+ // Parses the system hotkeys from the plist stored in |dictionary|.
+ void FileDidLoad(NSDictionary* dictionary);
+
+ scoped_ptr<SystemHotkeyMap> map_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemHotkeyHelperMac);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COCOA_SYSTEM_HOTKEY_HELPER_MAC_H_
diff --git a/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm b/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm
new file mode 100644
index 00000000000..68c52820ef3
--- /dev/null
+++ b/chromium/content/browser/cocoa/system_hotkey_helper_mac.mm
@@ -0,0 +1,77 @@
+// 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/cocoa/system_hotkey_helper_mac.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/mac/foundation_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "content/browser/cocoa/system_hotkey_map.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace {
+
+NSString* kSystemHotkeyPlistExtension =
+ @"/Preferences/com.apple.symbolichotkeys.plist";
+
+// Amount of time to delay loading the hotkeys in seconds.
+const int kLoadHotkeysDelaySeconds = 10;
+
+} // namespace
+
+namespace content {
+
+// static
+SystemHotkeyHelperMac* SystemHotkeyHelperMac::GetInstance() {
+ return Singleton<SystemHotkeyHelperMac>::get();
+}
+
+void SystemHotkeyHelperMac::DeferredLoadSystemHotkeys() {
+ BrowserThread::PostDelayedTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&SystemHotkeyHelperMac::LoadSystemHotkeys,
+ base::Unretained(this)),
+ base::TimeDelta::FromSeconds(kLoadHotkeysDelaySeconds));
+}
+
+SystemHotkeyHelperMac::SystemHotkeyHelperMac() : map_(new SystemHotkeyMap) {
+}
+
+SystemHotkeyHelperMac::~SystemHotkeyHelperMac() {
+}
+
+void SystemHotkeyHelperMac::LoadSystemHotkeys() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ std::string library_path(base::mac::GetUserLibraryPath().value());
+ NSString* expanded_file_path =
+ [NSString stringWithFormat:@"%s%@",
+ library_path.c_str(),
+ kSystemHotkeyPlistExtension];
+
+ // Loads the file into memory.
+ NSData* data = [NSData dataWithContentsOfFile:expanded_file_path];
+ // Intentionally create the object with +1 retain count, as FileDidLoad
+ // will destroy the object.
+ NSDictionary* dictionary = [SystemHotkeyMap::DictionaryFromData(data) retain];
+
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&SystemHotkeyHelperMac::FileDidLoad,
+ base::Unretained(this),
+ dictionary));
+}
+
+void SystemHotkeyHelperMac::FileDidLoad(NSDictionary* dictionary) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ bool success = map()->ParseDictionary(dictionary);
+ UMA_HISTOGRAM_BOOLEAN("OSX.SystemHotkeyMap.LoadSuccess", success);
+ [dictionary release];
+}
+
+} // namespace content
diff --git a/chromium/content/browser/cocoa/system_hotkey_map.h b/chromium/content/browser/cocoa/system_hotkey_map.h
new file mode 100644
index 00000000000..1909aa53b88
--- /dev/null
+++ b/chromium/content/browser/cocoa/system_hotkey_map.h
@@ -0,0 +1,66 @@
+// 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_COCOA_SYSTEM_HOTKEY_MAP_H_
+#define CONTENT_BROWSER_COCOA_SYSTEM_HOTKEY_MAP_H_
+
+#import <Cocoa/Cocoa.h>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+struct SystemHotkey;
+
+// Maintains a listing of all OSX system hotkeys. e.g. (cmd + `) These hotkeys
+// should have higher priority than web content, so NSEvents that correspond to
+// a system hotkey should not be passed to the renderer.
+class CONTENT_EXPORT SystemHotkeyMap {
+ public:
+ SystemHotkeyMap();
+ ~SystemHotkeyMap();
+
+ // Converts the plist stored in |data| into an NSDictionary. Returns nil on
+ // error.
+ static NSDictionary* DictionaryFromData(NSData* data);
+
+ // Parses the property list data commonly stored at
+ // ~/Library/Preferences/com.apple.symbolichotkeys.plist
+ // Returns false on encountering an irrecoverable error.
+ // Can be called multiple times. Only the results from the most recent
+ // invocation are stored.
+ bool ParseDictionary(NSDictionary* dictionary);
+
+ // Whether the event corresponds to a hotkey that has been reserved by the
+ // system.
+ bool IsEventReserved(NSEvent* event) const;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(SystemHotkeyMapTest, Parse);
+ FRIEND_TEST_ALL_PREFIXES(SystemHotkeyMapTest, ParseCustomEntries);
+ FRIEND_TEST_ALL_PREFIXES(SystemHotkeyMapTest, ParseMouse);
+
+ // Whether the hotkey has been reserved by the user.
+ bool IsHotkeyReserved(unsigned short key_code, NSUInteger modifiers) const;
+
+ // Create at least one record of a hotkey that is reserved by the user.
+ // Certain system hotkeys automatically reserve multiple key combinations.
+ void ReserveHotkey(unsigned short key_code,
+ NSUInteger modifiers,
+ NSString* system_effect);
+
+ // Create a record of a hotkey that is reserved by the user.
+ void ReserveHotkey(unsigned short key_code, NSUInteger modifiers);
+
+ std::vector<SystemHotkey> system_hotkeys_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemHotkeyMap);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COCOA_SYSTEM_HOTKEY_MAP_H_
diff --git a/chromium/content/browser/cocoa/system_hotkey_map.mm b/chromium/content/browser/cocoa/system_hotkey_map.mm
new file mode 100644
index 00000000000..da04fa8b844
--- /dev/null
+++ b/chromium/content/browser/cocoa/system_hotkey_map.mm
@@ -0,0 +1,165 @@
+// 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.
+
+#import "content/browser/cocoa/system_hotkey_map.h"
+
+#pragma mark - NSDictionary Helper Functions
+
+namespace {
+
+// All 4 following functions return nil if the object doesn't exist, or isn't of
+// the right class.
+id ObjectForKey(NSDictionary* dict, NSString* key, Class aClass) {
+ id object = [dict objectForKey:key];
+ if (![object isKindOfClass:aClass])
+ return nil;
+ return object;
+}
+
+NSDictionary* DictionaryForKey(NSDictionary* dict, NSString* key) {
+ return ObjectForKey(dict, key, [NSDictionary class]);
+}
+
+NSArray* ArrayForKey(NSDictionary* dict, NSString* key) {
+ return ObjectForKey(dict, key, [NSArray class]);
+}
+
+NSNumber* NumberForKey(NSDictionary* dict, NSString* key) {
+ return ObjectForKey(dict, key, [NSNumber class]);
+}
+
+NSString* StringForKey(NSDictionary* dict, NSString* key) {
+ return ObjectForKey(dict, key, [NSString class]);
+}
+
+} // namespace
+
+#pragma mark - SystemHotkey
+
+namespace content {
+
+struct SystemHotkey {
+ unsigned short key_code;
+ NSUInteger modifiers;
+};
+
+#pragma mark - SystemHotkeyMap
+
+SystemHotkeyMap::SystemHotkeyMap() {
+}
+SystemHotkeyMap::~SystemHotkeyMap() {
+}
+
+NSDictionary* SystemHotkeyMap::DictionaryFromData(NSData* data) {
+ if (!data)
+ return nil;
+
+ NSError* error = nil;
+ NSPropertyListFormat format;
+ NSDictionary* dictionary =
+ [NSPropertyListSerialization propertyListWithData:data
+ options:0
+ format:&format
+ error:&error];
+
+ if (![dictionary isKindOfClass:[NSDictionary class]])
+ return nil;
+
+ return dictionary;
+}
+
+bool SystemHotkeyMap::ParseDictionary(NSDictionary* dictionary) {
+ system_hotkeys_.clear();
+
+ if (!dictionary)
+ return false;
+
+ NSDictionary* hotkey_dictionaries =
+ DictionaryForKey(dictionary, @"AppleSymbolicHotKeys");
+ if (!hotkey_dictionaries)
+ return false;
+
+ for (NSString* hotkey_system_effect in [hotkey_dictionaries allKeys]) {
+ if (![hotkey_system_effect isKindOfClass:[NSString class]])
+ continue;
+
+ NSDictionary* hotkey_dictionary =
+ [hotkey_dictionaries objectForKey:hotkey_system_effect];
+ if (![hotkey_dictionary isKindOfClass:[NSDictionary class]])
+ continue;
+
+ NSNumber* enabled = NumberForKey(hotkey_dictionary, @"enabled");
+ if (!enabled || enabled.boolValue == NO)
+ continue;
+
+ NSDictionary* value = DictionaryForKey(hotkey_dictionary, @"value");
+ if (!value)
+ continue;
+
+ NSString* type = StringForKey(value, @"type");
+ if (!type || ![type isEqualToString:@"standard"])
+ continue;
+
+ NSArray* parameters = ArrayForKey(value, @"parameters");
+ if (!parameters || [parameters count] != 3)
+ continue;
+
+ NSNumber* key_code = [parameters objectAtIndex:1];
+ if (![key_code isKindOfClass:[NSNumber class]])
+ continue;
+
+ NSNumber* modifiers = [parameters objectAtIndex:2];
+ if (![modifiers isKindOfClass:[NSNumber class]])
+ continue;
+
+ ReserveHotkey(key_code.unsignedShortValue,
+ modifiers.unsignedIntegerValue,
+ hotkey_system_effect);
+ }
+
+ return true;
+}
+
+bool SystemHotkeyMap::IsEventReserved(NSEvent* event) const {
+ return IsHotkeyReserved(event.keyCode, event.modifierFlags);
+}
+
+bool SystemHotkeyMap::IsHotkeyReserved(unsigned short key_code,
+ NSUInteger modifiers) const {
+ modifiers &= NSDeviceIndependentModifierFlagsMask;
+ std::vector<SystemHotkey>::const_iterator it;
+ for (it = system_hotkeys_.begin(); it != system_hotkeys_.end(); ++it) {
+ if (it->key_code == key_code && it->modifiers == modifiers)
+ return true;
+ }
+ return false;
+}
+
+void SystemHotkeyMap::ReserveHotkey(unsigned short key_code,
+ NSUInteger modifiers,
+ NSString* system_effect) {
+ ReserveHotkey(key_code, modifiers);
+
+ // If a hotkey exists for toggling through the windows of an application, then
+ // adding shift to that hotkey toggles through the windows backwards.
+ if ([system_effect isEqualToString:@"27"])
+ ReserveHotkey(key_code, modifiers | NSShiftKeyMask);
+}
+
+void SystemHotkeyMap::ReserveHotkey(unsigned short key_code,
+ NSUInteger modifiers) {
+ // Hotkeys require at least one of control, command, or alternate keys to be
+ // down.
+ NSUInteger required_modifiers =
+ NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask;
+ if ((modifiers & required_modifiers) == 0)
+ return;
+
+ SystemHotkey hotkey;
+ hotkey.key_code = key_code;
+ hotkey.modifiers = modifiers;
+ system_hotkeys_.push_back(hotkey);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm b/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm
new file mode 100644
index 00000000000..6b2652fb426
--- /dev/null
+++ b/chromium/content/browser/cocoa/system_hotkey_map_unittest.mm
@@ -0,0 +1,196 @@
+// 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 <gtest/gtest.h>
+
+#import <Carbon/Carbon.h>
+#import <Cocoa/Cocoa.h>
+
+#include "base/files/file_path.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/path_service.h"
+#import "content/browser/cocoa/system_hotkey_map.h"
+#include "content/public/common/content_paths.h"
+
+namespace content {
+
+class SystemHotkeyMapTest : public ::testing::Test {
+ protected:
+ SystemHotkeyMapTest() {}
+
+ NSData* DataFromTestFile(const char* file) {
+ base::FilePath test_data_dir;
+ bool result = PathService::Get(DIR_TEST_DATA, &test_data_dir);
+ if (!result)
+ return nil;
+
+ base::FilePath test_path = test_data_dir.AppendASCII(file);
+ std::string test_path_string = test_path.AsUTF8Unsafe();
+ NSString* file_path =
+ [NSString stringWithUTF8String:test_path_string.c_str()];
+ return [NSData dataWithContentsOfFile:file_path];
+ }
+
+ void AddEntryToDictionary(BOOL enabled,
+ unsigned short key_code,
+ NSUInteger modifiers) {
+ NSMutableArray* parameters = [NSMutableArray array];
+ // The first parameter is unused.
+ [parameters addObject:[NSNumber numberWithInt:65535]];
+ [parameters addObject:[NSNumber numberWithUnsignedShort:key_code]];
+ [parameters addObject:[NSNumber numberWithUnsignedInteger:modifiers]];
+
+ NSMutableDictionary* value_dictionary = [NSMutableDictionary dictionary];
+ [value_dictionary setObject:parameters forKey:@"parameters"];
+ [value_dictionary setObject:@"standard" forKey:@"type"];
+
+ NSMutableDictionary* outer_dictionary = [NSMutableDictionary dictionary];
+ [outer_dictionary setObject:value_dictionary forKey:@"value"];
+
+ NSNumber* enabled_number = [NSNumber numberWithBool:enabled];
+ [outer_dictionary setObject:enabled_number forKey:@"enabled"];
+
+ NSString* key = [NSString stringWithFormat:@"%d", count_];
+ [system_hotkey_inner_dictionary_ setObject:outer_dictionary forKey:key];
+ ++count_;
+ }
+
+ virtual void SetUp() override {
+ system_hotkey_dictionary_.reset([[NSMutableDictionary alloc] init]);
+ system_hotkey_inner_dictionary_.reset([[NSMutableDictionary alloc] init]);
+ [system_hotkey_dictionary_ setObject:system_hotkey_inner_dictionary_
+ forKey:@"AppleSymbolicHotKeys"];
+ count_ = 100;
+ }
+
+ virtual void TearDown() override {
+ system_hotkey_dictionary_.reset();
+ system_hotkey_inner_dictionary_.reset();
+ }
+
+ // A constructed dictionary that matches the format of the one that would be
+ // parsed from the system hotkeys plist.
+ base::scoped_nsobject<NSMutableDictionary> system_hotkey_dictionary_;
+
+ private:
+ // A reference to the mutable dictionary to which new entries are added.
+ base::scoped_nsobject<NSMutableDictionary> system_hotkey_inner_dictionary_;
+ // Each entry in the system_hotkey_inner_dictionary_ needs to have a unique
+ // key. This count is used to generate those unique keys.
+ int count_;
+};
+
+TEST_F(SystemHotkeyMapTest, Parse) {
+ // This plist was pulled from a real machine. It is extensively populated,
+ // and has no missing or incomplete entries.
+ NSData* data = DataFromTestFile("mac/mac_system_hotkeys.plist");
+ ASSERT_TRUE(data);
+
+ NSDictionary* dictionary = SystemHotkeyMap::DictionaryFromData(data);
+ ASSERT_TRUE(dictionary);
+
+ SystemHotkeyMap map;
+ bool result = map.ParseDictionary(dictionary);
+ EXPECT_TRUE(result);
+
+ // Command + ` is a common key binding. It should exist.
+ unsigned short key_code = kVK_ANSI_Grave;
+ NSUInteger modifiers = NSCommandKeyMask;
+ EXPECT_TRUE(map.IsHotkeyReserved(key_code, modifiers));
+
+ // Command + Shift + ` is a common key binding. It should exist.
+ modifiers = NSCommandKeyMask | NSShiftKeyMask;
+ EXPECT_TRUE(map.IsHotkeyReserved(key_code, modifiers));
+
+ // Command + Shift + Ctr + ` is not a common key binding.
+ modifiers = NSCommandKeyMask | NSShiftKeyMask | NSControlKeyMask;
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, modifiers));
+
+ // Command + L is not a common key binding.
+ key_code = kVK_ANSI_L;
+ modifiers = NSCommandKeyMask;
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, modifiers));
+}
+
+TEST_F(SystemHotkeyMapTest, ParseNil) {
+ NSDictionary* dictionary = nil;
+
+ SystemHotkeyMap map;
+ bool result = map.ParseDictionary(dictionary);
+ EXPECT_FALSE(result);
+}
+
+TEST_F(SystemHotkeyMapTest, ParseMouse) {
+ // This plist was pulled from a real machine. It has missing entries,
+ // incomplete entries, and mouse hotkeys.
+ NSData* data = DataFromTestFile("mac/mac_system_hotkeys_sparse.plist");
+ ASSERT_TRUE(data);
+
+ NSDictionary* dictionary = SystemHotkeyMap::DictionaryFromData(data);
+ ASSERT_TRUE(dictionary);
+
+ SystemHotkeyMap map;
+ 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
+ unsigned short key_code = kVK_ANSI_Grave;
+ NSUInteger modifiers = NSCommandKeyMask;
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, modifiers));
+
+ // There is a mouse keybinding for 0x08. It should not apply to keyboard
+ // hotkeys.
+ key_code = kVK_ANSI_C;
+ modifiers = 0;
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, modifiers));
+
+ // Command + Alt + = is an accessibility shortcut. Its entry in the plist is
+ // incomplete.
+ // TODO(erikchen): OSX uses the default bindings, so this hotkey should still
+ // be reserved.
+ // http://crbug.com/383558
+ key_code = kVK_ANSI_Equal;
+ modifiers = NSCommandKeyMask | NSAlternateKeyMask;
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, modifiers));
+}
+
+TEST_F(SystemHotkeyMapTest, ParseCustomEntries) {
+ unsigned short key_code = kVK_ANSI_C;
+
+ AddEntryToDictionary(YES, key_code, 0);
+ AddEntryToDictionary(YES, key_code, NSAlphaShiftKeyMask);
+ AddEntryToDictionary(YES, key_code, NSShiftKeyMask);
+ AddEntryToDictionary(YES, key_code, NSControlKeyMask);
+ AddEntryToDictionary(YES, key_code, NSFunctionKeyMask);
+ AddEntryToDictionary(YES, key_code, NSFunctionKeyMask | NSControlKeyMask);
+ AddEntryToDictionary(NO, key_code, NSAlternateKeyMask);
+
+ SystemHotkeyMap map;
+
+ bool result = map.ParseDictionary(system_hotkey_dictionary_.get());
+ EXPECT_TRUE(result);
+
+ // Entries without control, command, or alternate key mask should not be
+ // reserved.
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, 0));
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, NSAlphaShiftKeyMask));
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, NSShiftKeyMask));
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, NSFunctionKeyMask));
+
+ // Unlisted entries should not be reserved.
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, NSCommandKeyMask));
+
+ // Disabled entries should not be reserved.
+ EXPECT_FALSE(map.IsHotkeyReserved(key_code, NSAlternateKeyMask));
+
+ // Other entries should be reserved.
+ EXPECT_TRUE(map.IsHotkeyReserved(key_code, NSControlKeyMask));
+ EXPECT_TRUE(
+ map.IsHotkeyReserved(key_code, NSFunctionKeyMask | NSControlKeyMask));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/OWNERS b/chromium/content/browser/compositor/OWNERS
index 3b61cda8291..44b33c441b6 100644
--- a/chromium/content/browser/compositor/OWNERS
+++ b/chromium/content/browser/compositor/OWNERS
@@ -1,4 +1,3 @@
-piman@chromium.org
danakj@chromium.org
-sievers@chromium.org
jbauman@chromium.org
+ccameron@chromium.org
diff --git a/chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h b/chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h
new file mode 100644
index 00000000000..b342035ed5f
--- /dev/null
+++ b/chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h
@@ -0,0 +1,136 @@
+// 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_BROWSER_COMPOSITOR_CA_LAYER_TREE_MAC_H_
+#define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_CA_LAYER_TREE_MAC_H_
+
+#include <IOSurface/IOSurfaceAPI.h>
+
+#include "content/browser/compositor/browser_compositor_view_mac.h"
+
+#if defined(__OBJC__)
+#include <Cocoa/Cocoa.h>
+#include "base/mac/scoped_nsobject.h"
+#include "content/browser/compositor/io_surface_layer_mac.h"
+#include "content/browser/compositor/software_layer_mac.h"
+#include "ui/base/cocoa/remote_layer_api.h"
+#endif // __OBJC__
+
+namespace content {
+
+#if defined(__OBJC__)
+
+// BrowserCompositorCALayerTreeMac owns tree of CALayer and a ui::Compositor
+// that is used to draw the layers. The CALayer tree can be attached to the
+// NSView of a BrowserCompositorViewMac
+class BrowserCompositorCALayerTreeMac
+ : public IOSurfaceLayerClient {
+ public:
+ BrowserCompositorCALayerTreeMac();
+ virtual ~BrowserCompositorCALayerTreeMac();
+ static BrowserCompositorCALayerTreeMac* FromAcceleratedWidget(
+ gfx::AcceleratedWidget widget);
+
+ void SetView(BrowserCompositorViewMac* view);
+ void ResetView();
+
+ ui::Compositor* compositor() const { return compositor_.get(); }
+
+ // Return true if the last frame swapped has a size in DIP of |dip_size|.
+ bool HasFrameOfSize(const gfx::Size& dip_size) const;
+
+ // Return the CGL renderer ID for the surface, if one is available.
+ int GetRendererID() const;
+
+ // Return true if the renderer should not be throttled by GPU back-pressure.
+ bool IsRendererThrottlingDisabled() const;
+
+ // Mark a bracket in which new frames are being pumped in a restricted nested
+ // run loop.
+ void BeginPumpingFrames();
+ void EndPumpingFrames();
+
+ void GotAcceleratedFrame(
+ uint64 surface_handle, int output_surface_id,
+ const std::vector<ui::LatencyInfo>& latency_info,
+ gfx::Size pixel_size, float scale_factor);
+
+ void GotSoftwareFrame(
+ cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas);
+
+private:
+ // IOSurfaceLayerClient implementation:
+ bool IOSurfaceLayerShouldAckImmediately() const override;
+ void IOSurfaceLayerDidDrawFrame() override;
+ void IOSurfaceLayerHitError() override;
+
+ void GotAcceleratedCAContextFrame(
+ CAContextID ca_context_id, gfx::Size pixel_size, float scale_factor);
+
+ void GotAcceleratedIOSurfaceFrame(
+ IOSurfaceID io_surface_id, gfx::Size pixel_size, float scale_factor);
+
+ // Remove a layer from the heirarchy and destroy it. Because the accelerated
+ // layer types may be replaced by a layer of the same type, the layer to
+ // destroy is parameterized, and, if it is the current layer, the current
+ // layer is reset.
+ void DestroyCAContextLayer(
+ base::scoped_nsobject<CALayerHost> ca_context_layer);
+ void DestroyIOSurfaceLayer(
+ base::scoped_nsobject<IOSurfaceLayer> io_surface_layer);
+ void DestroySoftwareLayer();
+
+ // The BrowserCompositorViewMac that is using this as its internals.
+ BrowserCompositorViewMac* view_;
+
+ // A phony NSView handle used to identify this.
+ gfx::AcceleratedWidget native_widget_;
+
+ // The compositor drawing the contents of this view.
+ scoped_ptr<ui::Compositor> compositor_;
+
+ // A flipped layer, which acts as the parent of the compositing and software
+ // layers. This layer is flipped so that the we don't need to recompute the
+ // origin for sub-layers when their position changes (this is impossible when
+ // using remote layers, as their size change cannot be synchronized with the
+ // window). This indirection is needed because flipping hosted layers (like
+ // |background_layer_| of RenderWidgetHostViewCocoa) leads to unpredictable
+ // behavior.
+ base::scoped_nsobject<CALayer> flipped_layer_;
+
+ // The accelerated CoreAnimation layer hosted by the GPU process.
+ base::scoped_nsobject<CALayerHost> ca_context_layer_;
+
+ // The locally drawn accelerated CoreAnimation layer.
+ base::scoped_nsobject<IOSurfaceLayer> io_surface_layer_;
+
+ // The locally drawn software layer.
+ base::scoped_nsobject<SoftwareLayer> software_layer_;
+
+ // The output surface and latency info of the last accelerated surface that
+ // was swapped. Sent back to the renderer when the accelerated surface is
+ // drawn.
+ int accelerated_output_surface_id_;
+ std::vector<ui::LatencyInfo> accelerated_latency_info_;
+
+ // The size in DIP of the last swap received from |compositor_|.
+ gfx::Size last_swap_size_dip_;
+};
+
+#endif // __OBJC__
+
+void BrowserCompositorCALayerTreeMacGotAcceleratedFrame(
+ gfx::AcceleratedWidget widget,
+ uint64 surface_handle, int surface_id,
+ const std::vector<ui::LatencyInfo>& latency_info,
+ gfx::Size pixel_size, float scale_factor,
+ bool* disable_throttling, int* renderer_id);
+
+void BrowserCompositorCALayerTreeMacGotSoftwareFrame(
+ gfx::AcceleratedWidget widget,
+ cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_CA_LAYER_TREE_MAC_H_
diff --git a/chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm b/chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm
new file mode 100644
index 00000000000..3abee8cd763
--- /dev/null
+++ b/chromium/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm
@@ -0,0 +1,406 @@
+// 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/browser_compositor_ca_layer_tree_mac.h"
+
+#include <map>
+
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/message_loop/message_loop.h"
+#include "content/browser/compositor/gpu_process_transport_factory.h"
+#include "content/browser/compositor/io_surface_layer_mac.h"
+#include "content/browser/compositor/software_layer_mac.h"
+#include "content/browser/renderer_host/dip_util.h"
+#include "content/browser/renderer_host/render_widget_resize_helper.h"
+#include "content/common/gpu/surface_handle_types_mac.h"
+#include "content/public/browser/context_factory.h"
+#include "ui/base/cocoa/animation_utils.h"
+#include "ui/gl/scoped_cgl.h"
+
+namespace content {
+namespace {
+
+typedef std::map<gfx::AcceleratedWidget,BrowserCompositorCALayerTreeMac*>
+ WidgetToInternalsMap;
+base::LazyInstance<WidgetToInternalsMap> g_widget_to_internals_map;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BrowserCompositorCALayerTreeMac
+
+BrowserCompositorCALayerTreeMac::BrowserCompositorCALayerTreeMac()
+ : view_(NULL),
+ accelerated_output_surface_id_(0) {
+ // Disable the fade-in animation as the layers are added.
+ ScopedCAActionDisabler disabler;
+
+ // Add a flipped transparent layer as a child, so that we don't need to
+ // fiddle with the position of sub-layers -- they will always be at the
+ // origin.
+ flipped_layer_.reset([[CALayer alloc] init]);
+ [flipped_layer_ setGeometryFlipped:YES];
+ [flipped_layer_ setAnchorPoint:CGPointMake(0, 0)];
+ [flipped_layer_
+ setAutoresizingMask:kCALayerWidthSizable|kCALayerHeightSizable];
+
+ // Use a sequence number as the accelerated widget handle that we can use
+ // to look up the internals structure.
+ static uintptr_t last_sequence_number = 0;
+ last_sequence_number += 1;
+ native_widget_ = reinterpret_cast<gfx::AcceleratedWidget>(
+ last_sequence_number);
+ g_widget_to_internals_map.Pointer()->insert(
+ std::make_pair(native_widget_, this));
+
+ // Create a compositor to draw the contents of this view.
+ compositor_.reset(new ui::Compositor(
+ native_widget_,
+ content::GetContextFactory(),
+ RenderWidgetResizeHelper::Get()->task_runner()));
+ compositor_->SetVisible(false);
+}
+
+BrowserCompositorCALayerTreeMac::~BrowserCompositorCALayerTreeMac() {
+ DCHECK(!view_);
+ g_widget_to_internals_map.Pointer()->erase(native_widget_);
+}
+
+void BrowserCompositorCALayerTreeMac::SetView(
+ BrowserCompositorViewMac* view) {
+ // Disable the fade-in animation as the view is added.
+ ScopedCAActionDisabler disabler;
+
+ DCHECK(view && !view_);
+ view_ = view;
+ compositor_->SetRootLayer(view_->ui_root_layer());
+
+ CALayer* background_layer = [view_->native_view() layer];
+ DCHECK(background_layer);
+ [flipped_layer_ setBounds:[background_layer bounds]];
+ [background_layer addSublayer:flipped_layer_];
+ compositor_->SetVisible(true);
+}
+
+void BrowserCompositorCALayerTreeMac::ResetView() {
+ if (!view_)
+ return;
+
+ // Disable the fade-out animation as the view is removed.
+ ScopedCAActionDisabler disabler;
+
+ [flipped_layer_ removeFromSuperlayer];
+ DestroyIOSurfaceLayer(io_surface_layer_);
+ DestroyCAContextLayer(ca_context_layer_);
+ DestroySoftwareLayer();
+
+ accelerated_output_surface_id_ = 0;
+ last_swap_size_dip_ = gfx::Size();
+
+ compositor_->SetVisible(false);
+ compositor_->SetScaleAndSize(1.0, gfx::Size(0, 0));
+ compositor_->SetRootLayer(NULL);
+ view_ = NULL;
+}
+
+bool BrowserCompositorCALayerTreeMac::HasFrameOfSize(
+ const gfx::Size& dip_size) const {
+ return last_swap_size_dip_ == dip_size;
+}
+
+int BrowserCompositorCALayerTreeMac::GetRendererID() const {
+ if (io_surface_layer_)
+ return [io_surface_layer_ rendererID];
+ return 0;
+}
+
+bool BrowserCompositorCALayerTreeMac::IsRendererThrottlingDisabled() const {
+ if (view_)
+ return view_->client()->BrowserCompositorViewShouldAckImmediately();
+ return false;
+}
+
+void BrowserCompositorCALayerTreeMac::BeginPumpingFrames() {
+ [io_surface_layer_ beginPumpingFrames];
+}
+
+void BrowserCompositorCALayerTreeMac::EndPumpingFrames() {
+ [io_surface_layer_ endPumpingFrames];
+}
+
+void BrowserCompositorCALayerTreeMac::GotAcceleratedFrame(
+ uint64 surface_handle, int output_surface_id,
+ const std::vector<ui::LatencyInfo>& latency_info,
+ gfx::Size pixel_size, float scale_factor) {
+ // Record the surface and latency info to use when acknowledging this frame.
+ DCHECK(!accelerated_output_surface_id_);
+ accelerated_output_surface_id_ = output_surface_id;
+ accelerated_latency_info_.insert(accelerated_latency_info_.end(),
+ latency_info.begin(), latency_info.end());
+
+ // If there is no view and therefore no superview to draw into, early-out.
+ if (!view_) {
+ IOSurfaceLayerDidDrawFrame();
+ return;
+ }
+
+ // Disable the fade-in or fade-out effect if we create or remove layers.
+ ScopedCAActionDisabler disabler;
+
+ last_swap_size_dip_ = ConvertSizeToDIP(scale_factor, pixel_size);
+ switch (GetSurfaceHandleType(surface_handle)) {
+ case kSurfaceHandleTypeIOSurface: {
+ IOSurfaceID io_surface_id = IOSurfaceIDFromSurfaceHandle(surface_handle);
+ GotAcceleratedIOSurfaceFrame(io_surface_id, pixel_size, scale_factor);
+ break;
+ }
+ case kSurfaceHandleTypeCAContext: {
+ CAContextID ca_context_id = CAContextIDFromSurfaceHandle(surface_handle);
+ GotAcceleratedCAContextFrame(ca_context_id, pixel_size, scale_factor);
+ break;
+ }
+ default:
+ LOG(ERROR) << "Unrecognized accelerated frame type.";
+ return;
+ }
+}
+
+void BrowserCompositorCALayerTreeMac::GotAcceleratedCAContextFrame(
+ CAContextID ca_context_id,
+ gfx::Size pixel_size,
+ float scale_factor) {
+ // In the layer is replaced, keep the old one around until after the new one
+ // is installed to avoid flashes.
+ base::scoped_nsobject<CALayerHost> old_ca_context_layer =
+ ca_context_layer_;
+
+ // Create the layer to host the layer exported by the GPU process with this
+ // particular CAContext ID.
+ if ([ca_context_layer_ contextId] != ca_context_id) {
+ ca_context_layer_.reset([[CALayerHost alloc] init]);
+ [ca_context_layer_ setContextId:ca_context_id];
+ [ca_context_layer_
+ setAutoresizingMask:kCALayerMaxXMargin|kCALayerMaxYMargin];
+ [flipped_layer_ addSublayer:ca_context_layer_];
+ }
+
+ // Acknowledge the frame to unblock the compositor immediately (the GPU
+ // process will do any required throttling).
+ IOSurfaceLayerDidDrawFrame();
+
+ // If this replacing a same-type layer, remove it now that the new layer is
+ // in the hierarchy.
+ if (old_ca_context_layer != ca_context_layer_)
+ DestroyCAContextLayer(old_ca_context_layer);
+
+ // Remove any different-type layers that this is replacing.
+ DestroyIOSurfaceLayer(io_surface_layer_);
+ DestroySoftwareLayer();
+}
+
+void BrowserCompositorCALayerTreeMac::GotAcceleratedIOSurfaceFrame(
+ IOSurfaceID io_surface_id,
+ gfx::Size pixel_size,
+ float scale_factor) {
+ // In the layer is replaced, keep the old one around until after the new one
+ // is installed to avoid flashes.
+ base::scoped_nsobject<IOSurfaceLayer> old_io_surface_layer =
+ io_surface_layer_;
+
+ // Create or re-create an IOSurface layer if needed. If there already exists
+ // a layer but it has the wrong scale factor or it was poisoned, re-create the
+ // layer.
+ bool needs_new_layer =
+ !io_surface_layer_ ||
+ [io_surface_layer_ hasBeenPoisoned] ||
+ [io_surface_layer_ scaleFactor] != scale_factor;
+ if (needs_new_layer) {
+ io_surface_layer_.reset(
+ [[IOSurfaceLayer alloc] initWithClient:this
+ withScaleFactor:scale_factor]);
+ if (io_surface_layer_)
+ [flipped_layer_ addSublayer:io_surface_layer_];
+ else
+ LOG(ERROR) << "Failed to create IOSurfaceLayer";
+ }
+
+ // Open the provided IOSurface.
+ if (io_surface_layer_) {
+ bool result = [io_surface_layer_ gotFrameWithIOSurface:io_surface_id
+ withPixelSize:pixel_size
+ withScaleFactor:scale_factor];
+ if (!result) {
+ DestroyIOSurfaceLayer(io_surface_layer_);
+ LOG(ERROR) << "Failed open IOSurface in IOSurfaceLayer";
+ }
+ }
+
+ // Give a final complaint if anything with the layer's creation went wrong.
+ // This frame will appear blank, the compositor will try to create another,
+ // and maybe that will go better.
+ if (!io_surface_layer_) {
+ LOG(ERROR) << "IOSurfaceLayer is nil, tab will be blank";
+ IOSurfaceLayerHitError();
+ }
+
+ // Make the CALayer draw and set its size appropriately.
+ if (io_surface_layer_) {
+ [io_surface_layer_ gotNewFrame];
+
+ // Set the bounds of the accelerated layer to match the size of the frame.
+ // If the bounds changed, force the content to be displayed immediately.
+ CGRect new_layer_bounds = CGRectMake(
+ 0, 0, last_swap_size_dip_.width(), last_swap_size_dip_.height());
+ bool bounds_changed = !CGRectEqualToRect(
+ new_layer_bounds, [io_surface_layer_ bounds]);
+ [io_surface_layer_ setBounds:new_layer_bounds];
+ if (bounds_changed)
+ [io_surface_layer_ setNeedsDisplayAndDisplayAndAck];
+ }
+
+ // If this replacing a same-type layer, remove it now that the new layer is
+ // in the hierarchy.
+ if (old_io_surface_layer != io_surface_layer_)
+ DestroyIOSurfaceLayer(old_io_surface_layer);
+
+ // Remove any different-type layers that this is replacing.
+ DestroyCAContextLayer(ca_context_layer_);
+ DestroySoftwareLayer();
+}
+
+void BrowserCompositorCALayerTreeMac::GotSoftwareFrame(
+ cc::SoftwareFrameData* frame_data,
+ float scale_factor,
+ SkCanvas* canvas) {
+ if (!frame_data || !canvas || !view_)
+ return;
+
+ // Disable the fade-in or fade-out effect if we create or remove layers.
+ ScopedCAActionDisabler disabler;
+
+ // If there is not a layer for software frames, create one.
+ if (!software_layer_) {
+ software_layer_.reset([[SoftwareLayer alloc] init]);
+ [flipped_layer_ addSublayer:software_layer_];
+ }
+
+ // Set the software layer to draw the provided canvas.
+ SkImageInfo info;
+ size_t row_bytes;
+ const void* pixels = canvas->peekPixels(&info, &row_bytes);
+ gfx::Size pixel_size(info.fWidth, info.fHeight);
+ [software_layer_ setContentsToData:pixels
+ withRowBytes:row_bytes
+ withPixelSize:pixel_size
+ withScaleFactor:scale_factor];
+ last_swap_size_dip_ = ConvertSizeToDIP(scale_factor, pixel_size);
+
+ // Remove any different-type layers that this is replacing.
+ DestroyCAContextLayer(ca_context_layer_);
+ DestroyIOSurfaceLayer(io_surface_layer_);
+}
+
+void BrowserCompositorCALayerTreeMac::DestroyCAContextLayer(
+ base::scoped_nsobject<CALayerHost> ca_context_layer) {
+ if (!ca_context_layer)
+ return;
+ [ca_context_layer removeFromSuperlayer];
+ if (ca_context_layer == ca_context_layer_)
+ ca_context_layer_.reset();
+}
+
+void BrowserCompositorCALayerTreeMac::DestroyIOSurfaceLayer(
+ base::scoped_nsobject<IOSurfaceLayer> io_surface_layer) {
+ if (!io_surface_layer)
+ return;
+ [io_surface_layer resetClient];
+ [io_surface_layer removeFromSuperlayer];
+ if (io_surface_layer == io_surface_layer_)
+ io_surface_layer_.reset();
+}
+
+void BrowserCompositorCALayerTreeMac::DestroySoftwareLayer() {
+ if (!software_layer_)
+ return;
+ [software_layer_ removeFromSuperlayer];
+ software_layer_.reset();
+}
+
+bool BrowserCompositorCALayerTreeMac::IOSurfaceLayerShouldAckImmediately()
+ const {
+ // If there is no view then the accelerated layer is not in the hierarchy
+ // and will never draw.
+ if (!view_)
+ return true;
+ return view_->client()->BrowserCompositorViewShouldAckImmediately();
+}
+
+void BrowserCompositorCALayerTreeMac::IOSurfaceLayerDidDrawFrame() {
+ if (accelerated_output_surface_id_) {
+ content::ImageTransportFactory::GetInstance()->OnSurfaceDisplayed(
+ accelerated_output_surface_id_);
+ accelerated_output_surface_id_ = 0;
+ }
+
+ if (view_) {
+ view_->client()->BrowserCompositorViewFrameSwapped(
+ accelerated_latency_info_);
+ }
+
+ accelerated_latency_info_.clear();
+}
+
+void BrowserCompositorCALayerTreeMac::IOSurfaceLayerHitError() {
+ // Perform all acks that would have been done if the frame had succeeded, to
+ // un-block the compositor and renderer.
+ IOSurfaceLayerDidDrawFrame();
+
+ // Poison the context being used and request a mulligan.
+ [io_surface_layer_ poisonContextAndSharegroup];
+ compositor_->ScheduleFullRedraw();
+}
+
+// static
+BrowserCompositorCALayerTreeMac* BrowserCompositorCALayerTreeMac::
+ FromAcceleratedWidget(gfx::AcceleratedWidget widget) {
+ WidgetToInternalsMap::const_iterator found =
+ g_widget_to_internals_map.Pointer()->find(widget);
+ // This can end up being accessed after the underlying widget has been
+ // destroyed, but while the ui::Compositor is still being destroyed.
+ // Return NULL in these cases.
+ if (found == g_widget_to_internals_map.Pointer()->end())
+ return NULL;
+ return found->second;
+}
+
+void BrowserCompositorCALayerTreeMacGotAcceleratedFrame(
+ gfx::AcceleratedWidget widget,
+ uint64 surface_handle, int surface_id,
+ const std::vector<ui::LatencyInfo>& latency_info,
+ gfx::Size pixel_size, float scale_factor,
+ bool* disable_throttling, int* renderer_id) {
+ BrowserCompositorCALayerTreeMac* ca_layer_tree =
+ BrowserCompositorCALayerTreeMac::FromAcceleratedWidget(widget);
+ if (ca_layer_tree) {
+ ca_layer_tree->GotAcceleratedFrame(
+ surface_handle, surface_id, latency_info, pixel_size, scale_factor);
+ *disable_throttling = ca_layer_tree->IsRendererThrottlingDisabled();
+ *renderer_id = ca_layer_tree->GetRendererID();
+ } else {
+ *disable_throttling = false;
+ *renderer_id = 0;
+ }
+}
+
+void BrowserCompositorCALayerTreeMacGotSoftwareFrame(
+ gfx::AcceleratedWidget widget,
+ cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas) {
+ BrowserCompositorCALayerTreeMac* ca_layer_tree =
+ BrowserCompositorCALayerTreeMac::FromAcceleratedWidget(widget);
+ if (ca_layer_tree)
+ ca_layer_tree->GotSoftwareFrame(frame_data, scale_factor, canvas);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/browser_compositor_output_surface.cc b/chromium/content/browser/compositor/browser_compositor_output_surface.cc
index 40576b2aeaf..0c650ca9f3e 100644
--- a/chromium/content/browser/compositor/browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/browser_compositor_output_surface.cc
@@ -5,12 +5,10 @@
#include "content/browser/compositor/browser_compositor_output_surface.h"
#include "base/bind.h"
-#include "base/command_line.h"
#include "base/location.h"
#include "base/strings/string_number_conversions.h"
#include "content/browser/compositor/reflector_impl.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
-#include "ui/compositor/compositor_switches.h"
namespace content {
@@ -40,9 +38,9 @@ BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
BrowserCompositorOutputSurface::~BrowserCompositorOutputSurface() {
DCHECK(CalledOnValidThread());
- if (reflector_)
+ if (reflector_.get())
reflector_->DetachFromOutputSurface();
- DCHECK(!reflector_);
+ DCHECK(!reflector_.get());
if (!HasClient())
return;
output_surface_map_->Remove(surface_id_);
@@ -64,20 +62,12 @@ bool BrowserCompositorOutputSurface::BindToClient(
return false;
output_surface_map_->AddWithID(this, surface_id_);
- if (reflector_)
+ if (reflector_.get())
reflector_->OnSourceSurfaceReady(this);
vsync_manager_->AddObserver(this);
return true;
}
-void BrowserCompositorOutputSurface::OnSwapBuffersComplete() {
- // On Mac, delay acknowledging the swap to the output surface client until
- // it has been drawn.
-#if !defined(OS_MACOSX)
- cc::OutputSurface::OnSwapBuffersComplete();
-#endif
-}
-
void BrowserCompositorOutputSurface::OnUpdateVSyncParameters(
base::TimeTicks timebase,
base::TimeDelta interval) {
@@ -98,10 +88,4 @@ void BrowserCompositorOutputSurface::SetReflector(ReflectorImpl* reflector) {
reflector_ = reflector;
}
-#if defined(OS_MACOSX)
-void BrowserCompositorOutputSurface::OnSurfaceDisplayed() {
- cc::OutputSurface::OnSwapBuffersComplete();
-}
-#endif
-
} // namespace content
diff --git a/chromium/content/browser/compositor/browser_compositor_output_surface.h b/chromium/content/browser/compositor/browser_compositor_output_surface.h
index e622f41c497..dd538769e76 100644
--- a/chromium/content/browser/compositor/browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/browser_compositor_output_surface.h
@@ -25,15 +25,14 @@ class CONTENT_EXPORT BrowserCompositorOutputSurface
public ui::CompositorVSyncManager::Observer,
public base::NonThreadSafe {
public:
- virtual ~BrowserCompositorOutputSurface();
+ ~BrowserCompositorOutputSurface() override;
// cc::OutputSurface implementation.
- virtual bool BindToClient(cc::OutputSurfaceClient* client) OVERRIDE;
- virtual void OnSwapBuffersComplete() OVERRIDE;
+ bool BindToClient(cc::OutputSurfaceClient* client) override;
// ui::CompositorOutputSurface::Observer implementation.
- virtual void OnUpdateVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval) OVERRIDE;
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override;
void OnUpdateVSyncParametersFromGpu(base::TimeTicks tiembase,
base::TimeDelta interval);
@@ -41,7 +40,7 @@ class CONTENT_EXPORT BrowserCompositorOutputSurface
void SetReflector(ReflectorImpl* reflector);
#if defined(OS_MACOSX)
- void OnSurfaceDisplayed();
+ virtual void OnSurfaceDisplayed() = 0;
#endif
protected:
diff --git a/chromium/content/browser/compositor/browser_compositor_view_mac.h b/chromium/content/browser/compositor/browser_compositor_view_mac.h
index 5d22b873dae..619aef55edd 100644
--- a/chromium/content/browser/compositor/browser_compositor_view_mac.h
+++ b/chromium/content/browser/compositor/browser_compositor_view_mac.h
@@ -5,60 +5,87 @@
#ifndef CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_
#define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_
-#import <Cocoa/Cocoa.h>
-#include <IOSurface/IOSurfaceAPI.h>
+#include <vector>
-#include "base/mac/scoped_nsobject.h"
#include "cc/output/software_frame_data.h"
-#include "content/browser/renderer_host/compositing_iosurface_layer_mac.h"
-#include "content/browser/renderer_host/software_layer_mac.h"
#include "skia/ext/platform_canvas.h"
#include "ui/compositor/compositor.h"
+#include "ui/events/latency_info.h"
#include "ui/gfx/geometry/size.h"
namespace content {
-class BrowserCompositorViewMacHelper;
-} // namespace content
-// Additions to the NSView interface for compositor frames.
-@interface NSView (BrowserCompositorView)
-- (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
- withOutputSurfaceID:(int)surface_id
- withPixelSize:(gfx::Size)pixel_size
- withScaleFactor:(float)scale_factor;
-
-- (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
- withScaleFactor:(float)scale_factor
- withCanvas:(SkCanvas*)canvas;
-@end // NSView (BrowserCompositorView)
-
-// NSView drawn by a ui::Compositor. The superview of this view is responsible
-// for changing the ui::Compositor SizeAndScale and calling layoutLayers when
-// the size of the parent view may change. This interface is patterned after
-// the needs of RenderWidgetHostViewCocoa, and could change.
-@interface BrowserCompositorViewMac : NSView {
- scoped_ptr<ui::Compositor> compositor_;
-
- base::scoped_nsobject<CALayer> background_layer_;
- base::scoped_nsobject<CompositingIOSurfaceLayer> accelerated_layer_;
- int accelerated_layer_output_surface_id_;
- base::scoped_nsobject<SoftwareLayer> software_layer_;
-
- scoped_ptr<content::BrowserCompositorViewMacHelper> helper_;
-}
-
-// Initialize to render the content of a specific superview.
-- (id)initWithSuperview:(NSView*)view;
-
-// Re-position the layers to the correct place when this view's superview
-// changes size, or when the accelerated or software content changes.
-- (void)layoutLayers;
-
-// Disallow further access to the client.
-- (void)resetClient;
-
-// Access the underlying ui::Compositor for this view.
-- (ui::Compositor*)compositor;
-@end // BrowserCompositorViewMac
+class BrowserCompositorCALayerTreeMac;
+
+// The interface through which BrowserCompositorViewMac calls back into
+// RenderWidgetHostViewMac (or any other structure that wishes to draw a
+// NSView backed by a ui::Compositor).
+// TODO(ccameron): This interface should be in the ui namespace.
+class BrowserCompositorViewMacClient {
+ public:
+ // Drawing is usually throttled by the rate at which CoreAnimation draws
+ // frames to the screen. This can be used to disable throttling.
+ virtual bool BrowserCompositorViewShouldAckImmediately() const = 0;
+
+ // Called when a frame is drawn, and used to pass latency info back to the
+ // renderer (if any).
+ virtual void BrowserCompositorViewFrameSwapped(
+ const std::vector<ui::LatencyInfo>& latency_info) = 0;
+};
+
+// The class to hold the ui::Compositor which is used to draw a NSView.
+// TODO(ccameron): This should implement an interface in the ui namespace.
+class BrowserCompositorViewMac {
+ public:
+ // This will install the NSView which is drawn by the ui::Compositor into
+ // the NSView provided by the client. Note that |client|, |native_view|, and
+ // |ui_root_layer| outlive their BrowserCompositorViewMac object.
+ BrowserCompositorViewMac(
+ BrowserCompositorViewMacClient* client,
+ NSView* native_view,
+ ui::Layer* ui_root_layer);
+ ~BrowserCompositorViewMac();
+
+ BrowserCompositorViewMacClient* client() const { return client_; }
+ NSView* native_view() const { return native_view_; }
+ ui::Layer* ui_root_layer() const { return ui_root_layer_; }
+
+ // The ui::Compositor being used to render the NSView.
+ // TODO(ccameron): This should be in the ui namespace interface.
+ ui::Compositor* GetCompositor() const;
+
+ // Return true if the last frame swapped has a size in DIP of |dip_size|.
+ bool HasFrameOfSize(const gfx::Size& dip_size) const;
+
+ // Mark a bracket in which new frames are pumped in a restricted nested run
+ // loop because the the target window is resizing or because the view is being
+ // shown after previously being hidden.
+ void BeginPumpingFrames();
+ void EndPumpingFrames();
+
+ private:
+ BrowserCompositorViewMacClient* client_;
+ NSView* native_view_;
+ ui::Layer* ui_root_layer_;
+
+ // Because a ui::Compositor is expensive in terms of resources and
+ // re-allocating a ui::Compositor is expensive in terms of work, this class
+ // is largely used to manage recycled instances of
+ // BrowserCompositorCALayerTreeMac, which actually has a ui::Compositor
+ // instance and modifies the CALayers used to draw the NSView.
+ scoped_ptr<BrowserCompositorCALayerTreeMac> ca_layer_tree_;
+};
+
+// A class to keep around whenever a BrowserCompositorViewMac may be created.
+// While at least one instance of this class exists, a spare
+// BrowserCompositorViewCocoa will be kept around to be recycled so that the
+// next BrowserCompositorViewMac to be created will be be created quickly.
+class BrowserCompositorViewPlaceholderMac {
+ public:
+ BrowserCompositorViewPlaceholderMac();
+ ~BrowserCompositorViewPlaceholderMac();
+};
+
+} // namespace content
#endif // CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_
diff --git a/chromium/content/browser/compositor/browser_compositor_view_mac.mm b/chromium/content/browser/compositor/browser_compositor_view_mac.mm
index 0a89e691075..b38edce89ae 100644
--- a/chromium/content/browser/compositor/browser_compositor_view_mac.mm
+++ b/chromium/content/browser/compositor/browser_compositor_view_mac.mm
@@ -5,252 +5,94 @@
#include "content/browser/compositor/browser_compositor_view_mac.h"
#include "base/debug/trace_event.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "content/browser/compositor/gpu_process_transport_factory.h"
-#include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_mac.h"
-#include "content/browser/renderer_host/software_layer_mac.h"
-#include "content/public/browser/context_factory.h"
-#include "ui/base/cocoa/animation_utils.h"
-#include "ui/gl/scoped_cgl.h"
+#include "base/lazy_instance.h"
+#include "content/browser/gpu/gpu_process_host_ui_shim.h"
+#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h"
+#include "content/common/gpu/gpu_messages.h"
-@interface BrowserCompositorViewMac (Private)
-- (void)layerDidDrawFrame;
-- (void)gotAcceleratedLayerError;
-@end // BrowserCompositorViewMac (Private)
+////////////////////////////////////////////////////////////////////////////////
+// BrowserCompositorViewMac
namespace content {
-
-// The CompositingIOSurfaceLayerClient interface needs to be implemented as a
-// C++ class to operate on, rather than Objective C class. This helper class
-// provides a bridge between the two.
-class BrowserCompositorViewMacHelper : public CompositingIOSurfaceLayerClient {
- public:
- BrowserCompositorViewMacHelper(BrowserCompositorViewMac* view)
- : view_(view) {}
- virtual ~BrowserCompositorViewMacHelper() {}
-
- private:
- // CompositingIOSurfaceLayerClient implementation:
- virtual void AcceleratedLayerDidDrawFrame(bool succeeded) OVERRIDE {
- [view_ layerDidDrawFrame];
- if (!succeeded)
- [view_ gotAcceleratedLayerError];
- }
-
- BrowserCompositorViewMac* view_;
-};
-
-} // namespace content
-
-
-// The default implementation of additions to the NSView interface for browser
-// compositing should never be called. Log an error if they are.
-@implementation NSView (BrowserCompositorView)
-
-- (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
- withOutputSurfaceID:(int)surface_id
- withPixelSize:(gfx::Size)pixel_size
- withScaleFactor:(float)scale_factor {
- DLOG(ERROR) << "-[NSView gotAcceleratedIOSurfaceFrame] called on "
- << "non-overriden class.";
-}
-
-- (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
- withScaleFactor:(float)scale_factor
- withCanvas:(SkCanvas*)canvas {
- DLOG(ERROR) << "-[NSView gotSoftwareFrame] called on non-overridden class.";
-}
-
-@end // NSView (BrowserCompositorView)
-
-@implementation BrowserCompositorViewMac : NSView
-
-- (id)initWithSuperview:(NSView*)view {
- if (self = [super init]) {
- accelerated_layer_output_surface_id_ = 0;
- helper_.reset(new content::BrowserCompositorViewMacHelper(self));
-
- // Disable the fade-in animation as the layer and view are added.
- ScopedCAActionDisabler disabler;
-
- // Make this view host a transparent layer.
- background_layer_.reset([[CALayer alloc] init]);
- [background_layer_ setContentsGravity:kCAGravityTopLeft];
- [self setLayer:background_layer_];
- [self setWantsLayer:YES];
-
- compositor_.reset(new ui::Compositor(self, content::GetContextFactory()));
- [view addSubview:self];
- }
- return self;
+namespace {
+
+// The number of placeholder objects allocated. If this reaches zero, then
+// the BrowserCompositorCALayerTreeMac being held on to for recycling,
+// |g_recyclable_ca_layer_tree|, will be freed.
+uint32 g_placeholder_count = 0;
+
+// A spare BrowserCompositorCALayerTreeMac kept around for recycling.
+base::LazyInstance<scoped_ptr<BrowserCompositorCALayerTreeMac>>
+ g_recyclable_ca_layer_tree;
+
+} // namespace
+
+BrowserCompositorViewMac::BrowserCompositorViewMac(
+ BrowserCompositorViewMacClient* client,
+ NSView* native_view,
+ ui::Layer* ui_root_layer)
+ : client_(client),
+ native_view_(native_view),
+ ui_root_layer_(ui_root_layer) {
+ // Try to use the recyclable BrowserCompositorCALayerTreeMac if there is one,
+ // otherwise allocate a new one.
+ // TODO(ccameron): If there exists a frame in flight (swap has been called
+ // by the compositor, but the frame has not arrived from the GPU process
+ // yet), then that frame may inappropriately flash in the new view.
+ ca_layer_tree_ = g_recyclable_ca_layer_tree.Get().Pass();
+ if (!ca_layer_tree_)
+ ca_layer_tree_.reset(new BrowserCompositorCALayerTreeMac);
+ ca_layer_tree_->SetView(this);
}
-- (void)gotAcceleratedLayerError {
- if (!accelerated_layer_)
- return;
+BrowserCompositorViewMac::~BrowserCompositorViewMac() {
+ // Make this BrowserCompositorCALayerTreeMac recyclable for future instances.
+ ca_layer_tree_->ResetView();
+ g_recyclable_ca_layer_tree.Get() = ca_layer_tree_.Pass();
- [accelerated_layer_ context]->PoisonContextAndSharegroup();
- compositor_->ScheduleFullRedraw();
+ // If there are no placeholders allocated, destroy the recyclable
+ // BrowserCompositorCALayerTreeMac that we just populated.
+ if (!g_placeholder_count)
+ g_recyclable_ca_layer_tree.Get().reset();
}
-// This function closely mirrors RenderWidgetHostViewMac::LayoutLayers. When
-// only delegated rendering is supported, only one copy of this code will
-// need to exist.
-- (void)layoutLayers {
- // Disable animation of the layers' resizing or repositioning.
- ScopedCAActionDisabler disabler;
-
- NSSize superview_frame_size = [[self superview] frame].size;
- [self setFrame:NSMakeRect(
- 0, 0, superview_frame_size.width, superview_frame_size.height)];
-
- CGRect new_background_frame = CGRectMake(
- 0,
- 0,
- superview_frame_size.width,
- superview_frame_size.height);
- [background_layer_ setFrame:new_background_frame];
-
- // The bounds of the accelerated layer determine the size of the GL surface
- // that will be drawn to. Make sure that this is big enough to draw the
- // IOSurface.
- if (accelerated_layer_) {
- CGRect layer_bounds = CGRectMake(
- 0,
- 0,
- [accelerated_layer_ iosurface]->dip_io_surface_size().width(),
- [accelerated_layer_ iosurface]->dip_io_surface_size().height());
- CGPoint layer_position = CGPointMake(
- 0,
- CGRectGetHeight(new_background_frame) - CGRectGetHeight(layer_bounds));
- bool bounds_changed = !CGRectEqualToRect(
- layer_bounds, [accelerated_layer_ bounds]);
- [accelerated_layer_ setBounds:layer_bounds];
- [accelerated_layer_ setPosition:layer_position];
- if (bounds_changed) {
- [accelerated_layer_ setNeedsDisplay];
- [accelerated_layer_ displayIfNeeded];
- }
- }
-
- // The content area of the software layer is the size of the image provided.
- // Make the bounds of the layer match the superview's bounds, to ensure that
- // the visible contents are drawn.
- [software_layer_ setBounds:new_background_frame];
+ui::Compositor* BrowserCompositorViewMac::GetCompositor() const {
+ DCHECK(ca_layer_tree_);
+ return ca_layer_tree_->compositor();
}
-- (void)resetClient {
- [accelerated_layer_ resetClient];
+bool BrowserCompositorViewMac::HasFrameOfSize(
+ const gfx::Size& dip_size) const {
+ if (ca_layer_tree_)
+ return ca_layer_tree_->HasFrameOfSize(dip_size);
+ return false;
}
-- (ui::Compositor*)compositor {
- return compositor_.get();
+void BrowserCompositorViewMac::BeginPumpingFrames() {
+ if (ca_layer_tree_)
+ ca_layer_tree_->BeginPumpingFrames();
}
-- (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
- withOutputSurfaceID:(int)surface_id
- withPixelSize:(gfx::Size)pixel_size
- withScaleFactor:(float)scale_factor {
- DCHECK(!accelerated_layer_output_surface_id_);
- accelerated_layer_output_surface_id_ = surface_id;
-
- ScopedCAActionDisabler disabler;
-
- // If there is already an accelerated layer, but it has the wrong scale
- // factor or it was poisoned, remove the old layer and replace it.
- base::scoped_nsobject<CompositingIOSurfaceLayer> old_accelerated_layer;
- if (accelerated_layer_ && (
- [accelerated_layer_ context]->HasBeenPoisoned() ||
- [accelerated_layer_ iosurface]->scale_factor() != scale_factor)) {
- old_accelerated_layer = accelerated_layer_;
- accelerated_layer_.reset();
- }
-
- // If there is not a layer for accelerated frames, create one.
- if (!accelerated_layer_) {
- // Disable the fade-in animation as the layer is added.
- ScopedCAActionDisabler disabler;
- scoped_refptr<content::CompositingIOSurfaceMac> iosurface =
- content::CompositingIOSurfaceMac::Create();
- accelerated_layer_.reset([[CompositingIOSurfaceLayer alloc]
- initWithIOSurface:iosurface
- withScaleFactor:scale_factor
- withClient:helper_.get()]);
- [[self layer] addSublayer:accelerated_layer_];
- }
-
- {
- bool result = true;
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- [accelerated_layer_ context]->cgl_context());
- result = [accelerated_layer_ iosurface]->SetIOSurfaceWithContextCurrent(
- [accelerated_layer_ context], surface_handle, pixel_size, scale_factor);
- if (!result)
- LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
- }
- [accelerated_layer_ gotNewFrame];
- [self layoutLayers];
-
- // If there was a software layer or an old accelerated layer, remove it.
- // Disable the fade-out animation as the layer is removed.
- {
- ScopedCAActionDisabler disabler;
- [software_layer_ removeFromSuperlayer];
- software_layer_.reset();
- [old_accelerated_layer resetClient];
- [old_accelerated_layer removeFromSuperlayer];
- old_accelerated_layer.reset();
- }
+void BrowserCompositorViewMac::EndPumpingFrames() {
+ if (ca_layer_tree_)
+ ca_layer_tree_->EndPumpingFrames();
}
-- (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
- withScaleFactor:(float)scale_factor
- withCanvas:(SkCanvas*)canvas {
- if (!frame_data || !canvas)
- return;
-
- // If there is not a layer for software frames, create one.
- if (!software_layer_) {
- // Disable the fade-in animation as the layer is added.
- ScopedCAActionDisabler disabler;
- software_layer_.reset([[SoftwareLayer alloc] init]);
- [[self layer] addSublayer:software_layer_];
- }
+////////////////////////////////////////////////////////////////////////////////
+// BrowserCompositorViewPlaceholderMac
- SkImageInfo info;
- size_t row_bytes;
- const void* pixels = canvas->peekPixels(&info, &row_bytes);
- [software_layer_ setContentsToData:pixels
- withRowBytes:row_bytes
- withPixelSize:gfx::Size(info.fWidth, info.fHeight)
- withScaleFactor:scale_factor];
- [self layoutLayers];
-
- // If there was an accelerated layer, remove it.
- // Disable the fade-out animation as the layer is removed.
- {
- ScopedCAActionDisabler disabler;
- [accelerated_layer_ resetClient];
- [accelerated_layer_ removeFromSuperlayer];
- accelerated_layer_.reset();
- }
-
- // This call can be nested insider ui::Compositor commit calls, and can also
- // make additional ui::Compositor commit calls. Avoid the potential recursion
- // by acknowledging the frame asynchronously.
- [self performSelector:@selector(layerDidDrawFrame)
- withObject:nil
- afterDelay:0];
+BrowserCompositorViewPlaceholderMac::BrowserCompositorViewPlaceholderMac() {
+ g_placeholder_count += 1;
}
-- (void)layerDidDrawFrame {
- if (!accelerated_layer_output_surface_id_)
- return;
+BrowserCompositorViewPlaceholderMac::~BrowserCompositorViewPlaceholderMac() {
+ DCHECK_GT(g_placeholder_count, 0u);
+ g_placeholder_count -= 1;
- content::ImageTransportFactory::GetInstance()->OnSurfaceDisplayed(
- accelerated_layer_output_surface_id_);
- accelerated_layer_output_surface_id_ = 0;
+ // If there are no placeholders allocated, destroy the recyclable
+ // BrowserCompositorCALayerTreeMac.
+ if (!g_placeholder_count)
+ g_recyclable_ca_layer_tree.Get().reset();
}
-@end // BrowserCompositorViewMac
+} // namespace content
diff --git a/chromium/content/browser/compositor/buffer_queue.cc b/chromium/content/browser/compositor/buffer_queue.cc
new file mode 100644
index 00000000000..ebb01658ccb
--- /dev/null
+++ b/chromium/content/browser/compositor/buffer_queue.cc
@@ -0,0 +1,176 @@
+// 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/buffer_queue.h"
+
+#include "content/browser/compositor/image_transport_factory.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 "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkRegion.h"
+
+namespace content {
+
+BufferQueue::BufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
+ unsigned int internalformat,
+ GLHelper* gl_helper)
+ : context_provider_(context_provider),
+ fbo_(0),
+ allocated_count_(0),
+ internalformat_(internalformat),
+ gl_helper_(gl_helper) {
+}
+
+BufferQueue::~BufferQueue() {
+ FreeAllSurfaces();
+
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+ if (fbo_)
+ gl->DeleteFramebuffers(1, &fbo_);
+}
+
+bool BufferQueue::Initialize() {
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+ gl->GenFramebuffers(1, &fbo_);
+ return fbo_ != 0;
+}
+
+void BufferQueue::BindFramebuffer() {
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+ gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
+
+ if (!current_surface_.texture) {
+ current_surface_ = GetNextSurface();
+ gl->FramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ current_surface_.texture,
+ 0);
+ }
+}
+
+void BufferQueue::CopyBufferDamage(int texture,
+ int source_texture,
+ const gfx::Rect& new_damage,
+ const gfx::Rect& old_damage) {
+ gl_helper_->CopySubBufferDamage(
+ texture,
+ source_texture,
+ SkRegion(SkIRect::MakeXYWH(new_damage.x(),
+ new_damage.y(),
+ new_damage.width(),
+ new_damage.height())),
+ SkRegion(SkIRect::MakeXYWH(old_damage.x(),
+ old_damage.y(),
+ old_damage.width(),
+ old_damage.height())));
+}
+
+void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) {
+ for (size_t i = 0; i < available_surfaces_.size(); i++)
+ available_surfaces_[i].damage.Union(damage);
+ for (std::deque<AllocatedSurface>::iterator it =
+ in_flight_surfaces_.begin();
+ it != in_flight_surfaces_.end();
+ ++it)
+ it->damage.Union(damage);
+}
+
+void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
+ if (damage != gfx::Rect(size_)) {
+ // We must have a frame available to copy from.
+ DCHECK(!in_flight_surfaces_.empty());
+ CopyBufferDamage(current_surface_.texture,
+ in_flight_surfaces_.back().texture,
+ damage,
+ current_surface_.damage);
+ }
+ UpdateBufferDamage(damage);
+ current_surface_.damage = gfx::Rect();
+ in_flight_surfaces_.push_back(current_surface_);
+ current_surface_.texture = 0;
+ current_surface_.image = 0;
+}
+
+void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
+ DCHECK(!current_surface_.texture);
+ if (size == size_)
+ return;
+ size_ = size;
+
+ // TODO: add stencil buffer when needed.
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+ gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
+ gl->FramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
+
+ FreeAllSurfaces();
+}
+
+void BufferQueue::PageFlipComplete() {
+ if (in_flight_surfaces_.size() > 1) {
+ available_surfaces_.push_back(in_flight_surfaces_.front());
+ in_flight_surfaces_.pop_front();
+ }
+}
+
+void BufferQueue::FreeAllSurfaces() {
+ FreeSurface(&current_surface_);
+ while (!in_flight_surfaces_.empty()) {
+ FreeSurface(&in_flight_surfaces_.front());
+ in_flight_surfaces_.pop_front();
+ }
+ for (size_t i = 0; i < available_surfaces_.size(); i++)
+ FreeSurface(&available_surfaces_[i]);
+ available_surfaces_.clear();
+}
+
+void BufferQueue::FreeSurface(AllocatedSurface* surface) {
+ if (surface->texture) {
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+ gl->BindTexture(GL_TEXTURE_2D, surface->texture);
+ gl->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, surface->image);
+ gl->DeleteTextures(1, &surface->texture);
+ gl->DestroyImageCHROMIUM(surface->image);
+ surface->image = 0;
+ surface->texture = 0;
+ allocated_count_--;
+ }
+}
+
+BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() {
+ if (!available_surfaces_.empty()) {
+ AllocatedSurface surface = available_surfaces_.back();
+ available_surfaces_.pop_back();
+ return surface;
+ }
+
+ unsigned int texture = 0;
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+ gl->GenTextures(1, &texture);
+ if (!texture)
+ return AllocatedSurface();
+
+ // We don't want to allow anything more than triple buffering.
+ DCHECK_LT(allocated_count_, 4U);
+
+ unsigned int id =
+ gl->CreateGpuMemoryBufferImageCHROMIUM(size_.width(),
+ size_.height(),
+ internalformat_,
+ GL_SCANOUT_CHROMIUM);
+ if (!id) {
+ LOG(ERROR) << "Failed to allocate backing image surface";
+ gl->DeleteTextures(1, &texture);
+ return AllocatedSurface();
+ }
+ allocated_count_++;
+ gl->BindTexture(GL_TEXTURE_2D, texture);
+ gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, id);
+ return AllocatedSurface(texture, id, gfx::Rect(size_));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/buffer_queue.h b/chromium/content/browser/compositor/buffer_queue.h
new file mode 100644
index 00000000000..dca9c38c0d4
--- /dev/null
+++ b/chromium/content/browser/compositor/buffer_queue.h
@@ -0,0 +1,90 @@
+// 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_BUFFERED_OUTPUT_SURFACE_H_
+#define CONTENT_BROWSER_COMPOSITOR_BUFFERED_OUTPUT_SURFACE_H_
+
+#include <queue>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
+
+namespace cc {
+class ContextProvider;
+}
+
+namespace content {
+
+class GLHelper;
+
+// Provides a surface that manages its own buffers, backed by GpuMemoryBuffers
+// created using CHROMIUM_gpu_memory_buffer_image. Double/triple buffering is
+// implemented internally. Doublebuffering occurs if PageFlipComplete is called
+// before the next BindFramebuffer call, otherwise it creates extra buffers.
+class CONTENT_EXPORT BufferQueue {
+ public:
+ BufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
+ unsigned int internalformat,
+ GLHelper* gl_helper);
+ virtual ~BufferQueue();
+
+ bool Initialize();
+
+ void BindFramebuffer();
+ void SwapBuffers(const gfx::Rect& damage);
+ void PageFlipComplete();
+ void Reshape(const gfx::Size& size, float scale_factor);
+
+ unsigned int current_texture_id() { return current_surface_.texture; }
+
+ private:
+ friend class BufferQueueTest;
+
+ struct AllocatedSurface {
+ AllocatedSurface() : texture(0), image(0) {}
+ AllocatedSurface(unsigned int texture,
+ unsigned int image,
+ const gfx::Rect& rect)
+ : texture(texture), image(image), damage(rect) {}
+ unsigned int texture;
+ unsigned int image;
+ gfx::Rect damage; // This is the damage for this frame from the previous.
+ };
+
+ void FreeAllSurfaces();
+
+ void FreeSurface(AllocatedSurface* surface);
+
+ // Copy everything that is in |copy_rect|, except for what is in
+ // |exclude_rect| from |source_texture| to |texture|.
+ virtual void CopyBufferDamage(int texture,
+ int source_texture,
+ const gfx::Rect& new_damage,
+ const gfx::Rect& old_damage);
+
+ void UpdateBufferDamage(const gfx::Rect& damage);
+
+ // Return a surface, available to be drawn into.
+ AllocatedSurface GetNextSurface();
+
+ gfx::Size size_;
+ scoped_refptr<cc::ContextProvider> context_provider_;
+ unsigned int fbo_;
+ size_t allocated_count_;
+ unsigned int internalformat_;
+ AllocatedSurface current_surface_; // This surface is currently bound.
+ std::vector<AllocatedSurface> available_surfaces_; // These are free for use.
+ std::deque<AllocatedSurface> in_flight_surfaces_;
+ GLHelper* gl_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(BufferQueue);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_BUFFERED_OUTPUT_SURFACE_H_
diff --git a/chromium/content/browser/compositor/buffer_queue_unittest.cc b/chromium/content/browser/compositor/buffer_queue_unittest.cc
new file mode 100644
index 00000000000..1a2c4feeddc
--- /dev/null
+++ b/chromium/content/browser/compositor/buffer_queue_unittest.cc
@@ -0,0 +1,288 @@
+// 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 "cc/test/test_context_provider.h"
+#include "cc/test/test_web_graphics_context_3d.h"
+#include "content/browser/compositor/buffer_queue.h"
+#include "content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+
+using ::testing::_;
+using ::testing::Expectation;
+using ::testing::Ne;
+using ::testing::Return;
+
+namespace content {
+class MockBufferQueue : public BufferQueue {
+ public:
+ MockBufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
+ unsigned int internalformat)
+ : BufferQueue(context_provider, internalformat, nullptr) {}
+ MOCK_METHOD4(CopyBufferDamage,
+ void(int, int, const gfx::Rect&, const gfx::Rect&));
+};
+
+class BufferQueueTest : public ::testing::Test {
+ public:
+ BufferQueueTest() : doublebuffering_(true), first_frame_(true) {}
+
+ void SetUp() override {
+ scoped_refptr<cc::TestContextProvider> context_provider =
+ cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
+ context_provider->BindToCurrentThread();
+ output_surface_.reset(new MockBufferQueue(context_provider, GL_RGBA));
+ output_surface_->Initialize();
+ }
+
+ unsigned current_surface() { return output_surface_->current_surface_.image; }
+ const std::vector<BufferQueue::AllocatedSurface>& available_surfaces() {
+ return output_surface_->available_surfaces_;
+ }
+ const std::deque<BufferQueue::AllocatedSurface>& in_flight_surfaces() {
+ return output_surface_->in_flight_surfaces_;
+ }
+
+ const BufferQueue::AllocatedSurface& last_frame() {
+ return output_surface_->in_flight_surfaces_.back();
+ }
+ const BufferQueue::AllocatedSurface& next_frame() {
+ return output_surface_->available_surfaces_.back();
+ }
+ const gfx::Size size() { return output_surface_->size_; }
+
+ int CountBuffers() {
+ int n = available_surfaces().size() + in_flight_surfaces().size();
+ if (current_surface())
+ n++;
+ return n;
+ }
+
+ // Check that each buffer is unique if present.
+ void CheckUnique() {
+ std::set<unsigned> buffers;
+ EXPECT_TRUE(InsertUnique(&buffers, current_surface()));
+ for (size_t i = 0; i < available_surfaces().size(); i++)
+ EXPECT_TRUE(InsertUnique(&buffers, available_surfaces()[i].image));
+ for (std::deque<BufferQueue::AllocatedSurface>::const_iterator it =
+ in_flight_surfaces().begin();
+ it != in_flight_surfaces().end();
+ ++it)
+ EXPECT_TRUE(InsertUnique(&buffers, it->image));
+ }
+
+ void SwapBuffers() {
+ output_surface_->SwapBuffers(gfx::Rect(output_surface_->size_));
+ }
+
+ void SendDamagedFrame(const gfx::Rect& damage) {
+ // We don't care about the GL-level implementation here, just how it uses
+ // damage rects.
+ output_surface_->BindFramebuffer();
+ output_surface_->SwapBuffers(damage);
+ if (doublebuffering_ || !first_frame_)
+ output_surface_->PageFlipComplete();
+ first_frame_ = false;
+ }
+
+ void SendFullFrame() { SendDamagedFrame(gfx::Rect(output_surface_->size_)); }
+
+ protected:
+ bool InsertUnique(std::set<unsigned>* set, unsigned value) {
+ if (!value)
+ return true;
+ if (set->find(value) != set->end())
+ return false;
+ set->insert(value);
+ return true;
+ }
+
+ scoped_ptr<MockBufferQueue> output_surface_;
+ bool doublebuffering_;
+ bool first_frame_;
+};
+
+namespace {
+const gfx::Size screen_size = gfx::Size(30, 30);
+const gfx::Rect screen_rect = gfx::Rect(screen_size);
+const gfx::Rect small_damage = gfx::Rect(gfx::Size(10, 10));
+const gfx::Rect large_damage = gfx::Rect(gfx::Size(20, 20));
+const gfx::Rect overlapping_damage = gfx::Rect(gfx::Size(5, 20));
+
+class MockedContext : public cc::TestWebGraphicsContext3D {
+ public:
+ MOCK_METHOD2(bindFramebuffer, void(GLenum, GLuint));
+ MOCK_METHOD2(bindTexture, void(GLenum, GLuint));
+ MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint));
+ MOCK_METHOD4(createGpuMemoryBufferImageCHROMIUM,
+ GLuint(GLsizei, GLsizei, GLenum, GLenum));
+ MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint));
+ MOCK_METHOD5(framebufferTexture2D,
+ void(GLenum, GLenum, GLenum, GLuint, GLint));
+};
+
+scoped_ptr<BufferQueue> CreateOutputSurfaceWithMock(MockedContext** context) {
+ *context = new MockedContext();
+ scoped_refptr<cc::TestContextProvider> context_provider =
+ cc::TestContextProvider::Create(
+ scoped_ptr<cc::TestWebGraphicsContext3D>(*context));
+ context_provider->BindToCurrentThread();
+ scoped_ptr<BufferQueue> buffer_queue(
+ new BufferQueue(context_provider, GL_RGBA, nullptr));
+ buffer_queue->Initialize();
+ return buffer_queue.Pass();
+}
+
+TEST(BufferQueueStandaloneTest, FboInitialization) {
+ MockedContext* context;
+ scoped_ptr<BufferQueue> output_surface =
+ CreateOutputSurfaceWithMock(&context);
+
+ EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
+ ON_CALL(*context, framebufferTexture2D(_, _, _, _, _))
+ .WillByDefault(Return());
+
+ output_surface->Reshape(gfx::Size(10, 20), 1.0f);
+}
+
+TEST(BufferQueueStandaloneTest, FboBinding) {
+ MockedContext* context;
+ scoped_ptr<BufferQueue> output_surface =
+ CreateOutputSurfaceWithMock(&context);
+ EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, Ne(0U)));
+ EXPECT_CALL(*context, destroyImageCHROMIUM(1));
+ Expectation image =
+ EXPECT_CALL(*context,
+ createGpuMemoryBufferImageCHROMIUM(
+ 0, 0, GL_RGBA, GL_SCANOUT_CHROMIUM)).WillOnce(Return(1));
+ Expectation fb =
+ EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
+ Expectation tex = EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, Ne(0U)));
+ Expectation bind_tex =
+ EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1))
+ .After(tex, image);
+ EXPECT_CALL(
+ *context,
+ framebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Ne(0U), _))
+ .After(fb, bind_tex);
+
+ output_surface->BindFramebuffer();
+}
+
+TEST_F(BufferQueueTest, PartialSwapReuse) {
+ // Check that
+ output_surface_->Reshape(screen_size, 1.0f);
+ ASSERT_TRUE(doublebuffering_);
+ EXPECT_CALL(*output_surface_,
+ CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
+ EXPECT_CALL(*output_surface_,
+ CopyBufferDamage(_, _, small_damage, small_damage)).Times(1);
+ EXPECT_CALL(*output_surface_,
+ CopyBufferDamage(_, _, large_damage, small_damage)).Times(1);
+ SendFullFrame();
+ SendDamagedFrame(small_damage);
+ SendDamagedFrame(small_damage);
+ SendDamagedFrame(large_damage);
+ // Verify that the damage has propagated.
+ EXPECT_EQ(next_frame().damage, large_damage);
+}
+
+TEST_F(BufferQueueTest, PartialSwapFullFrame) {
+ output_surface_->Reshape(screen_size, 1.0f);
+ ASSERT_TRUE(doublebuffering_);
+ EXPECT_CALL(*output_surface_,
+ CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
+ SendFullFrame();
+ SendDamagedFrame(small_damage);
+ SendFullFrame();
+ SendFullFrame();
+ EXPECT_EQ(next_frame().damage, screen_rect);
+}
+
+TEST_F(BufferQueueTest, PartialSwapOverlapping) {
+ output_surface_->Reshape(screen_size, 1.0f);
+ ASSERT_TRUE(doublebuffering_);
+ EXPECT_CALL(*output_surface_,
+ CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
+ EXPECT_CALL(*output_surface_,
+ CopyBufferDamage(_, _, overlapping_damage, small_damage))
+ .Times(1);
+
+ SendFullFrame();
+ SendDamagedFrame(small_damage);
+ SendDamagedFrame(overlapping_damage);
+ EXPECT_EQ(next_frame().damage, overlapping_damage);
+}
+
+TEST_F(BufferQueueTest, MultipleBindCalls) {
+ // Check that multiple bind calls do not create or change surfaces.
+ output_surface_->BindFramebuffer();
+ EXPECT_EQ(1, CountBuffers());
+ unsigned int fb = current_surface();
+ output_surface_->BindFramebuffer();
+ EXPECT_EQ(1, CountBuffers());
+ EXPECT_EQ(fb, current_surface());
+}
+
+TEST_F(BufferQueueTest, CheckDoubleBuffering) {
+ // Check buffer flow through double buffering path.
+ EXPECT_EQ(0, CountBuffers());
+ output_surface_->BindFramebuffer();
+ EXPECT_EQ(1, CountBuffers());
+ EXPECT_NE(0U, current_surface());
+ SwapBuffers();
+ EXPECT_EQ(1U, in_flight_surfaces().size());
+ output_surface_->PageFlipComplete();
+ EXPECT_EQ(1U, in_flight_surfaces().size());
+ output_surface_->BindFramebuffer();
+ EXPECT_EQ(2, CountBuffers());
+ CheckUnique();
+ EXPECT_NE(0U, current_surface());
+ EXPECT_EQ(1U, in_flight_surfaces().size());
+ SwapBuffers();
+ CheckUnique();
+ EXPECT_EQ(2U, in_flight_surfaces().size());
+ output_surface_->PageFlipComplete();
+ CheckUnique();
+ EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_EQ(1U, available_surfaces().size());
+ output_surface_->BindFramebuffer();
+ EXPECT_EQ(2, CountBuffers());
+ CheckUnique();
+ EXPECT_TRUE(available_surfaces().empty());
+}
+
+TEST_F(BufferQueueTest, CheckTripleBuffering) {
+ // Check buffer flow through triple buffering path.
+
+ // This bit is the same sequence tested in the doublebuffering case.
+ output_surface_->BindFramebuffer();
+ SwapBuffers();
+ output_surface_->PageFlipComplete();
+ output_surface_->BindFramebuffer();
+ SwapBuffers();
+
+ EXPECT_EQ(2, CountBuffers());
+ CheckUnique();
+ EXPECT_EQ(2U, in_flight_surfaces().size());
+ output_surface_->BindFramebuffer();
+ EXPECT_EQ(3, CountBuffers());
+ CheckUnique();
+ EXPECT_NE(0U, current_surface());
+ EXPECT_EQ(2U, in_flight_surfaces().size());
+ output_surface_->PageFlipComplete();
+ EXPECT_EQ(3, CountBuffers());
+ CheckUnique();
+ EXPECT_NE(0U, current_surface());
+ EXPECT_EQ(1U, in_flight_surfaces().size());
+ EXPECT_EQ(1U, available_surfaces().size());
+}
+
+} // namespace
+} // namespace content
diff --git a/chromium/content/browser/compositor/delegated_frame_host.cc b/chromium/content/browser/compositor/delegated_frame_host.cc
index 5db69b70b4c..5dbaed130f5 100644
--- a/chromium/content/browser/compositor/delegated_frame_host.cc
+++ b/chromium/content/browser/compositor/delegated_frame_host.cc
@@ -11,16 +11,46 @@
#include "cc/output/copy_output_request.h"
#include "cc/resources/single_release_callback.h"
#include "cc/resources/texture_mailbox.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_manager.h"
#include "content/browser/compositor/resize_lock.h"
+#include "content/browser/gpu/compositor_util.h"
#include "content/common/gpu/client/gl_helper.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"
#include "media/base/video_util.h"
#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/effects/SkLumaColorFilter.h"
+#include "ui/gfx/frame_time.h"
namespace content {
+namespace {
+
+void SatisfyCallback(cc::SurfaceManager* manager,
+ cc::SurfaceSequence sequence) {
+ std::vector<uint32_t> sequences;
+ sequences.push_back(sequence.sequence);
+ manager->DidSatisfySequences(sequence.id_namespace, &sequences);
+}
+
+void RequireCallback(cc::SurfaceManager* manager,
+ cc::SurfaceId id,
+ cc::SurfaceSequence sequence) {
+ cc::Surface* surface = manager->GetSurfaceForId(id);
+ if (!surface) {
+ LOG(ERROR) << "Attempting to require callback on nonexistent surface";
+ return;
+ }
+ surface->AddDestructionDependency(sequence);
+}
+
+} // namespace
+
////////////////////////////////////////////////////////////////////////////////
// DelegatedFrameHostClient
@@ -48,6 +78,7 @@ void DelegatedFrameHostClient::RequestCopyOfOutput(
DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
: client_(client),
+ use_surfaces_(UseSurfacesEnabled()),
last_output_surface_id_(0),
pending_delegated_ack_count_(0),
skipped_frames_(false),
@@ -56,14 +87,24 @@ DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
ImageTransportFactory::GetInstance()->AddObserver(this);
}
-void DelegatedFrameHost::WasShown() {
+void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
delegated_frame_evictor_->SetVisible(true);
- if (!released_front_lock_.get()) {
+ if (surface_id_.is_null() && !frame_provider_.get() &&
+ !released_front_lock_.get()) {
ui::Compositor* compositor = client_->GetCompositor();
if (compositor)
released_front_lock_ = compositor->GetCompositorLock();
}
+
+ ui::Compositor* compositor = client_->GetCompositor();
+ if (compositor) {
+ compositor->SetLatencyInfo(latency_info);
+ }
+}
+
+bool DelegatedFrameHost::HasSavedFrame() {
+ return delegated_frame_evictor_->HasFrame();
}
void DelegatedFrameHost::WasHidden() {
@@ -118,29 +159,26 @@ void DelegatedFrameHost::RequestCopyOfOutput(
void DelegatedFrameHost::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) {
+ const gfx::Size& output_size,
+ CopyFromCompositingSurfaceCallback& callback,
+ const SkColorType color_type) {
// Only ARGB888 and RGB565 supported as of now.
- bool format_support = ((config == SkBitmap::kRGB_565_Config) ||
- (config == SkBitmap::kARGB_8888_Config));
+ bool format_support = ((color_type == kAlpha_8_SkColorType) ||
+ (color_type == kRGB_565_SkColorType) ||
+ (color_type == kN32_SkColorType));
DCHECK(format_support);
if (!CanCopyToBitmap()) {
callback.Run(false, SkBitmap());
return;
}
- const gfx::Size& dst_size_in_pixel =
- client_->ConvertViewSizeToPixel(dst_size);
scoped_ptr<cc::CopyOutputRequest> request =
cc::CopyOutputRequest::CreateRequest(base::Bind(
&DelegatedFrameHost::CopyFromCompositingSurfaceHasResult,
- dst_size_in_pixel,
- config,
+ output_size,
+ color_type,
callback));
- gfx::Rect src_subrect_in_pixel =
- ConvertRectToPixel(client_->CurrentDeviceScaleFactor(), src_subrect);
- request->set_area(src_subrect_in_pixel);
+ request->set_area(src_subrect);
client_->RequestCopyOfOutput(request.Pass());
}
@@ -173,9 +211,7 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
subscriber_texture,
target,
callback));
- gfx::Rect src_subrect_in_pixel =
- ConvertRectToPixel(client_->CurrentDeviceScaleFactor(), src_subrect);
- request->set_area(src_subrect_in_pixel);
+ request->set_area(src_subrect);
if (subscriber_texture.get()) {
request->SetTextureMailbox(
cc::TextureMailbox(subscriber_texture->mailbox(),
@@ -222,6 +258,9 @@ bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip) const {
}
void DelegatedFrameHost::WasResized() {
+ if (client_->DesiredFrameSize() != current_frame_size_in_dip_ &&
+ client_->GetHost()->is_hidden())
+ EvictDelegatedFrame();
MaybeCreateResizeLock();
}
@@ -248,18 +287,28 @@ void DelegatedFrameHost::CheckResizeLock() {
}
}
-void DelegatedFrameHost::DidReceiveFrameFromRenderer() {
- if (frame_subscriber() && CanCopyToVideoFrame()) {
- const base::TimeTicks present_time = base::TimeTicks::Now();
- scoped_refptr<media::VideoFrame> frame;
- RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
- if (frame_subscriber()->ShouldCaptureFrame(present_time,
- &frame, &callback)) {
- CopyFromCompositingSurfaceToVideoFrame(
- gfx::Rect(current_frame_size_in_dip_),
- frame,
- base::Bind(callback, present_time));
- }
+void DelegatedFrameHost::DidReceiveFrameFromRenderer(
+ const gfx::Rect& damage_rect) {
+ if (!frame_subscriber() || !CanCopyToVideoFrame())
+ return;
+
+ const base::TimeTicks now = gfx::FrameTime::Now();
+ base::TimeTicks present_time;
+ if (vsync_timebase_.is_null() || vsync_interval_ <= base::TimeDelta()) {
+ present_time = now;
+ } else {
+ const int64 intervals_elapsed = (now - vsync_timebase_) / vsync_interval_;
+ present_time = vsync_timebase_ + (intervals_elapsed + 1) * vsync_interval_;
+ }
+
+ scoped_refptr<media::VideoFrame> frame;
+ RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
+ if (frame_subscriber()->ShouldCaptureFrame(damage_rect, present_time,
+ &frame, &callback)) {
+ CopyFromCompositingSurfaceToVideoFrame(
+ gfx::Rect(current_frame_size_in_dip_),
+ frame,
+ base::Bind(callback, present_time));
}
}
@@ -317,6 +366,10 @@ void DelegatedFrameHost::SwapDelegatedFrame(
// the DelegatedRendererLayer.
EvictDelegatedFrame();
+ surface_factory_.reset();
+ 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()) {
@@ -329,41 +382,86 @@ void DelegatedFrameHost::SwapDelegatedFrame(
}
last_output_surface_id_ = output_surface_id;
}
+ ui::Compositor* compositor = client_->GetCompositor();
if (frame_size.IsEmpty()) {
DCHECK(frame_data->resource_list.empty());
EvictDelegatedFrame();
} else {
- if (!resource_collection_) {
- 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(), frame_data.Pass());
- client_->GetLayer()->SetShowDelegatedContent(frame_provider_.get(),
- frame_size_in_dip);
+ if (use_surfaces_) {
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ cc::SurfaceManager* manager = factory->GetSurfaceManager();
+ if (!surface_factory_) {
+ id_allocator_ =
+ factory->GetContextFactory()->CreateSurfaceIdAllocator();
+ 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_, frame_size);
+ // manager must outlive compositors using it.
+ client_->GetLayer()->SetShowSurface(
+ surface_id_,
+ base::Bind(&SatisfyCallback, base::Unretained(manager)),
+ base::Bind(&RequireCallback, base::Unretained(manager)), frame_size,
+ frame_size_in_dip);
+ current_surface_size_ = frame_size;
+ }
+ scoped_ptr<cc::CompositorFrame> compositor_frame =
+ make_scoped_ptr(new cc::CompositorFrame());
+ compositor_frame->delegated_frame_data = frame_data.Pass();
+
+ compositor_frame->metadata.latency_info.swap(skipped_latency_info_list_);
+ compositor_frame->metadata.latency_info.insert(
+ compositor_frame->metadata.latency_info.end(),
+ latency_info.begin(),
+ latency_info.end());
+
+ base::Closure ack_callback;
+ if (compositor) {
+ ack_callback = base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
+ AsWeakPtr(),
+ output_surface_id);
+ }
+ surface_factory_->SubmitFrame(
+ surface_id_, compositor_frame.Pass(), ack_callback);
} else {
- frame_provider_->SetFrameData(frame_data.Pass());
+ 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(), frame_data.Pass());
+ client_->GetLayer()->SetShowDelegatedContent(frame_provider_.get(),
+ frame_size_in_dip);
+ } else {
+ frame_provider_->SetFrameData(frame_data.Pass());
+ }
}
}
released_front_lock_ = NULL;
current_frame_size_in_dip_ = frame_size_in_dip;
CheckResizeLock();
- client_->SchedulePaintInRect(damage_rect_in_dip);
+ if (!damage_rect_in_dip.IsEmpty())
+ client_->GetLayer()->OnDelegatedFrameDamage(damage_rect_in_dip);
pending_delegated_ack_count_++;
- ui::Compositor* compositor = client_->GetCompositor();
if (!compositor) {
SendDelegatedFrameAck(output_surface_id);
- } else {
+ } else if (!use_surfaces_) {
std::vector<ui::LatencyInfo>::const_iterator it;
for (it = latency_info.begin(); it != latency_info.end(); ++it)
compositor->SetLatencyInfo(*it);
@@ -377,9 +475,11 @@ void DelegatedFrameHost::SwapDelegatedFrame(
base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
AsWeakPtr(),
output_surface_id));
+ } else {
+ AddOnCommitCallbackAndDisableLocks(base::Closure());
}
- DidReceiveFrameFromRenderer();
- if (frame_provider_.get())
+ DidReceiveFrameFromRenderer(damage_rect);
+ if (frame_provider_.get() || !surface_id_.is_null())
delegated_frame_evictor_->SwappedFrame(!host->is_hidden());
// Note: the frame may have been evicted immediately.
}
@@ -387,7 +487,9 @@ void DelegatedFrameHost::SwapDelegatedFrame(
void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id) {
RenderWidgetHostImpl* host = client_->GetHost();
cc::CompositorFrameAck ack;
- if (resource_collection_)
+ if (!surface_returned_resources_.empty())
+ ack.resources.swap(surface_returned_resources_);
+ if (resource_collection_.get())
resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
RenderWidgetHostImpl::SendSwapCompositorFrameAck(host->GetRoutingID(),
output_surface_id,
@@ -407,10 +509,14 @@ void DelegatedFrameHost::UnusedResourcesAreAvailable() {
void DelegatedFrameHost::SendReturnedDelegatedResources(
uint32 output_surface_id) {
RenderWidgetHostImpl* host = client_->GetHost();
- DCHECK(resource_collection_);
cc::CompositorFrameAck ack;
- resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
+ 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());
RenderWidgetHostImpl::SendReclaimCompositorResources(
@@ -420,16 +526,31 @@ void DelegatedFrameHost::SendReturnedDelegatedResources(
ack);
}
+void DelegatedFrameHost::ReturnResources(
+ const cc::ReturnedResourceArray& resources) {
+ if (resources.empty())
+ return;
+ std::copy(resources.begin(),
+ resources.end(),
+ std::back_inserter(surface_returned_resources_));
+ if (!pending_delegated_ack_count_)
+ SendReturnedDelegatedResources(last_output_surface_id_);
+}
+
void DelegatedFrameHost::EvictDelegatedFrame() {
- client_->GetLayer()->SetShowPaintedContent();
+ client_->GetLayer()->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 SkBitmap::Config config,
+ const SkColorType color_type,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result) {
if (result->IsEmpty() || result->size().IsEmpty()) {
@@ -438,14 +559,16 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
}
if (result->HasTexture()) {
- PrepareTextureCopyOutputResult(dst_size_in_pixel, config,
+ // GPU-accelerated path
+ PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type,
callback,
result.Pass());
return;
}
DCHECK(result->HasBitmap());
- PrepareBitmapCopyOutputResult(dst_size_in_pixel, config, callback,
+ // Software path
+ PrepareBitmapCopyOutputResult(dst_size_in_pixel, color_type, callback,
result.Pass());
}
@@ -471,18 +594,21 @@ static void CopyFromCompositingSurfaceFinished(
// static
void DelegatedFrameHost::PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config config,
+ const SkColorType color_type,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result) {
DCHECK(result->HasTexture());
base::ScopedClosureRunner scoped_callback_runner(
base::Bind(callback, false, SkBitmap()));
+ // TODO(sikugu): We should be able to validate the format here using
+ // GLHelper::IsReadbackConfigSupported before we processs the result.
+ // See crbug.com/415682.
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- bitmap->setConfig(config,
- dst_size_in_pixel.width(), dst_size_in_pixel.height(),
- 0, kOpaque_SkAlphaType);
- if (!bitmap->allocPixels())
+ if (!bitmap->tryAllocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
+ dst_size_in_pixel.height(),
+ color_type,
+ kOpaque_SkAlphaType)))
return;
ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
@@ -508,7 +634,7 @@ void DelegatedFrameHost::PrepareTextureCopyOutputResult(
gfx::Rect(result->size()),
dst_size_in_pixel,
pixels,
- config,
+ color_type,
base::Bind(&CopyFromCompositingSurfaceFinished,
callback,
base::Passed(&release_callback),
@@ -520,10 +646,10 @@ void DelegatedFrameHost::PrepareTextureCopyOutputResult(
// static
void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config config,
+ const SkColorType color_type,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result) {
- if (config != SkBitmap::kARGB_8888_Config) {
+ if (color_type != kN32_SkColorType && color_type != kAlpha_8_SkColorType) {
NOTIMPLEMENTED();
callback.Run(false, SkBitmap());
return;
@@ -531,12 +657,41 @@ void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
DCHECK(result->HasBitmap());
scoped_ptr<SkBitmap> source = result->TakeBitmap();
DCHECK(source);
- SkBitmap bitmap = skia::ImageOperations::Resize(
- *source,
- skia::ImageOperations::RESIZE_BEST,
- dst_size_in_pixel.width(),
- dst_size_in_pixel.height());
- callback.Run(true, bitmap);
+ 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(true, scaled_bitmap);
+ 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(false, SkBitmap());
+ 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(true, grayscale_bitmap);
}
// static
@@ -555,6 +710,7 @@ void DelegatedFrameHost::ReturnSubscriberTexture(
dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
}
+// static
void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
base::WeakPtr<DelegatedFrameHost> dfh,
const base::Callback<void(bool)>& callback,
@@ -571,7 +727,7 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
if (release_callback) {
// A release callback means the texture came from the compositor, so there
// should be no |subscriber_texture|.
- DCHECK(!subscriber_texture);
+ DCHECK(!subscriber_texture.get());
bool lost_resource = sync_point == 0;
release_callback->Run(sync_point, lost_resource);
}
@@ -670,7 +826,8 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
quality_switch = switches::kTabCaptureUpscaleQuality;
std::string switch_value =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(quality_switch);
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ quality_switch);
if (switch_value == "fast")
quality = GLHelper::SCALER_QUALITY_FAST;
else if (switch_value == "good")
@@ -750,6 +907,8 @@ void DelegatedFrameHost::OnCompositingLockStateChanged(
void DelegatedFrameHost::OnUpdateVSyncParameters(
base::TimeTicks timebase,
base::TimeDelta interval) {
+ vsync_timebase_ = timebase;
+ vsync_interval_ = interval;
RenderWidgetHostImpl* host = client_->GetHost();
if (client_->IsVisible())
host->UpdateVSyncParameters(timebase, interval);
@@ -760,7 +919,7 @@ void DelegatedFrameHost::OnUpdateVSyncParameters(
void DelegatedFrameHost::OnLostResources() {
RenderWidgetHostImpl* host = client_->GetHost();
- if (frame_provider_.get())
+ if (frame_provider_.get() || !surface_id_.is_null())
EvictDelegatedFrame();
idle_frame_subscriber_textures_.clear();
yuv_readback_pipeline_.reset();
@@ -774,10 +933,12 @@ void DelegatedFrameHost::OnLostResources() {
DelegatedFrameHost::~DelegatedFrameHost() {
ImageTransportFactory::GetInstance()->RemoveObserver(this);
+ if (!surface_id_.is_null())
+ surface_factory_->Destroy(surface_id_);
if (resource_collection_.get())
resource_collection_->SetClient(NULL);
- DCHECK(!vsync_manager_);
+ DCHECK(!vsync_manager_.get());
}
void DelegatedFrameHost::RunOnCommitCallbacks() {
@@ -798,13 +959,14 @@ void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
compositor->AddObserver(this);
can_lock_compositor_ = NO_PENDING_COMMIT;
- on_compositing_did_commit_callbacks_.push_back(callback);
+ if (!callback.is_null())
+ on_compositing_did_commit_callbacks_.push_back(callback);
}
void DelegatedFrameHost::AddedToWindow() {
ui::Compositor* compositor = client_->GetCompositor();
if (compositor) {
- DCHECK(!vsync_manager_);
+ DCHECK(!vsync_manager_.get());
vsync_manager_ = compositor->vsync_manager();
vsync_manager_->AddObserver(this);
}
@@ -818,19 +980,19 @@ void DelegatedFrameHost::RemovingFromWindow() {
if (compositor && compositor->HasObserver(this))
compositor->RemoveObserver(this);
- if (vsync_manager_) {
+ if (vsync_manager_.get()) {
vsync_manager_->RemoveObserver(this);
vsync_manager_ = NULL;
}
}
void DelegatedFrameHost::LockResources() {
- DCHECK(frame_provider_);
+ DCHECK(frame_provider_.get() || !surface_id_.is_null());
delegated_frame_evictor_->LockFrame();
}
void DelegatedFrameHost::UnlockResources() {
- DCHECK(frame_provider_);
+ DCHECK(frame_provider_.get() || !surface_id_.is_null());
delegated_frame_evictor_->UnlockFrame();
}
@@ -846,7 +1008,14 @@ void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
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();
+ new_layer->SetShowSurface(
+ surface_id_, base::Bind(&SatisfyCallback, base::Unretained(manager)),
+ base::Bind(&RequireCallback, base::Unretained(manager)),
+ current_surface_size_, current_frame_size_in_dip_);
+ }
}
} // namespace content
-
diff --git a/chromium/content/browser/compositor/delegated_frame_host.h b/chromium/content/browser/compositor/delegated_frame_host.h
index bcbc758ffad..a789ef6e1f0 100644
--- a/chromium/content/browser/compositor/delegated_frame_host.h
+++ b/chromium/content/browser/compositor/delegated_frame_host.h
@@ -8,11 +8,13 @@
#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"
#include "content/browser/compositor/owned_mailbox.h"
#include "content/browser/renderer_host/delegated_frame_evictor.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/public/browser/render_process_host.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
@@ -21,6 +23,10 @@
#include "ui/compositor/layer_owner_delegate.h"
#include "ui/gfx/rect_conversions.h"
+namespace cc {
+class SurfaceFactory;
+}
+
namespace media {
class VideoFrame;
}
@@ -41,7 +47,6 @@ class CONTENT_EXPORT DelegatedFrameHostClient {
virtual ui::Compositor* GetCompositor() const = 0;
virtual ui::Layer* GetLayer() = 0;
virtual RenderWidgetHostImpl* GetHost() = 0;
- virtual void SchedulePaintInRect(const gfx::Rect& damage_rect_in_dip) = 0;
virtual bool IsVisible() = 0;
virtual scoped_ptr<ResizeLock> CreateResizeLock(
bool defer_compositor_lock) = 0;
@@ -72,10 +77,11 @@ class CONTENT_EXPORT DelegatedFrameHost
public ImageTransportFactoryObserver,
public DelegatedFrameEvictorClient,
public cc::DelegatedFrameResourceCollectionClient,
+ public cc::SurfaceFactoryClient,
public base::SupportsWeakPtr<DelegatedFrameHost> {
public:
DelegatedFrameHost(DelegatedFrameHostClient* client);
- virtual ~DelegatedFrameHost();
+ ~DelegatedFrameHost() override;
bool CanCopyToBitmap() const;
@@ -86,16 +92,16 @@ class CONTENT_EXPORT DelegatedFrameHost
float frame_device_scale_factor,
const std::vector<ui::LatencyInfo>& latency_info);
void WasHidden();
- void WasShown();
+ void WasShown(const ui::LatencyInfo& latency_info);
void WasResized();
+ bool HasSavedFrame();
gfx::Size GetRequestedRendererSize() const;
void AddedToWindow();
void RemovingFromWindow();
- void CopyFromCompositingSurface(
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config);
+ void CopyFromCompositingSurface(const gfx::Rect& src_subrect,
+ const gfx::Size& output_size,
+ CopyFromCompositingSurfaceCallback& callback,
+ const SkColorType color_type);
void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
@@ -105,15 +111,20 @@ class CONTENT_EXPORT DelegatedFrameHost
void BeginFrameSubscription(
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber);
void EndFrameSubscription();
+ bool HasFrameSubscriber() const { return frame_subscriber_; }
// 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);
}
bool ShouldCreateResizeLockForTesting() { return ShouldCreateResizeLock(); }
+ bool ReleasedFrontLockActiveForTesting() const {
+ return !!released_front_lock_.get();
+ }
private:
friend class DelegatedFrameHostClient;
@@ -134,24 +145,22 @@ class CONTENT_EXPORT DelegatedFrameHost
void UnlockResources();
// Overridden from ui::CompositorObserver:
- virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE;
- virtual void OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) OVERRIDE;
- virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE;
- virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE;
- virtual void OnCompositingLockStateChanged(
- ui::Compositor* compositor) OVERRIDE;
+ 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;
// Overridden from ui::CompositorVSyncManager::Observer:
- virtual void OnUpdateVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval) OVERRIDE;
+ void OnUpdateVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override;
// Overridden from ui::LayerOwnerObserver:
- virtual void OnLayerRecreated(ui::Layer* old_layer,
- ui::Layer* new_layer) OVERRIDE;
+ void OnLayerRecreated(ui::Layer* old_layer, ui::Layer* new_layer) override;
// Overridden from ImageTransportFactoryObserver:
- virtual void OnLostResources() OVERRIDE;
+ void OnLostResources() override;
bool ShouldSkipFrame(gfx::Size size_in_dip) const;
@@ -172,17 +181,17 @@ class CONTENT_EXPORT DelegatedFrameHost
// of the copy.
static void CopyFromCompositingSurfaceHasResult(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config config,
+ const SkColorType color_type,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result);
static void PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config config,
+ const SkColorType color_type,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result);
static void PrepareBitmapCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config config,
+ const SkColorType color_type,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result);
static void CopyFromCompositingSurfaceHasResultForVideo(
@@ -206,20 +215,32 @@ class CONTENT_EXPORT DelegatedFrameHost
void SendReturnedDelegatedResources(uint32 output_surface_id);
// DelegatedFrameEvictorClient implementation.
- virtual void EvictDelegatedFrame() OVERRIDE;
+ void EvictDelegatedFrame() override;
// cc::DelegatedFrameProviderClient implementation.
- virtual void UnusedResourcesAreAvailable() OVERRIDE;
+ void UnusedResourcesAreAvailable() override;
- void DidReceiveFrameFromRenderer();
+ // cc::SurfaceFactoryClient implementation.
+ void ReturnResources(const cc::ReturnedResourceArray& resources) override;
+
+ void DidReceiveFrameFromRenderer(const gfx::Rect& damage_rect);
DelegatedFrameHostClient* client_;
+ // 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_;
+ // The current VSync timebase and interval. These are zero until the first
+ // call to OnUpdateVSyncParameters().
+ base::TimeTicks vsync_timebase_;
+ base::TimeDelta vsync_interval_;
+
// With delegated renderer, this is the last output surface, used to
// disambiguate resources with the same id coming from different output
// surfaces.
@@ -242,6 +263,13 @@ class CONTENT_EXPORT DelegatedFrameHost
// Provides delegated frame updates to the cc::DelegatedRendererLayer.
scoped_refptr<cc::DelegatedFrameProvider> frame_provider_;
+ // State for rendering into a Surface.
+ scoped_ptr<cc::SurfaceIdAllocator> id_allocator_;
+ scoped_ptr<cc::SurfaceFactory> surface_factory_;
+ cc::SurfaceId surface_id_;
+ gfx::Size current_surface_size_;
+ cc::ReturnedResourceArray surface_returned_resources_;
+
// This lock is the one waiting for a frame of the right size to come back
// from the renderer/GPU process. It is set from the moment the aura window
// got resized, to the moment we committed the renderer frame of the same
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 3b79d546d42..e68c5c8fd20 100644
--- a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -5,8 +5,12 @@
#include "content/browser/compositor/gpu_browser_compositor_output_surface.h"
#include "cc/output/compositor_frame.h"
+#include "cc/output/output_surface_client.h"
#include "content/browser/compositor/reflector_impl.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
+#include "content/public/browser/browser_thread.h"
+#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
namespace content {
@@ -20,23 +24,41 @@ GpuBrowserCompositorOutputSurface::GpuBrowserCompositorOutputSurface(
: BrowserCompositorOutputSurface(context,
surface_id,
output_surface_map,
- vsync_manager) {
+ vsync_manager),
+ swap_buffers_completion_callback_(
+ base::Bind(&GpuBrowserCompositorOutputSurface::OnSwapBuffersCompleted,
+ base::Unretained(this))) {
overlay_candidate_validator_ = overlay_candidate_validator.Pass();
}
GpuBrowserCompositorOutputSurface::~GpuBrowserCompositorOutputSurface() {}
-void GpuBrowserCompositorOutputSurface::SwapBuffers(
- cc::CompositorFrame* frame) {
- DCHECK(frame->gl_frame_data);
-
+CommandBufferProxyImpl*
+GpuBrowserCompositorOutputSurface::GetCommandBufferProxy() {
ContextProviderCommandBuffer* provider_command_buffer =
- static_cast<ContextProviderCommandBuffer*>(context_provider_.get());
+ static_cast<content::ContextProviderCommandBuffer*>(
+ context_provider_.get());
CommandBufferProxyImpl* command_buffer_proxy =
provider_command_buffer->GetCommandBufferProxy();
DCHECK(command_buffer_proxy);
- context_provider_->ContextGL()->ShallowFlushCHROMIUM();
- command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
+ return command_buffer_proxy;
+}
+
+bool GpuBrowserCompositorOutputSurface::BindToClient(
+ cc::OutputSurfaceClient* client) {
+ if (!BrowserCompositorOutputSurface::BindToClient(client))
+ return false;
+
+ GetCommandBufferProxy()->SetSwapBuffersCompletionCallback(
+ swap_buffers_completion_callback_.callback());
+ return true;
+}
+
+void GpuBrowserCompositorOutputSurface::SwapBuffers(
+ cc::CompositorFrame* frame) {
+ DCHECK(frame->gl_frame_data);
+
+ GetCommandBufferProxy()->SetLatencyInfo(frame->metadata.latency_info);
if (reflector_.get()) {
if (frame->gl_frame_data->sub_buffer_rect ==
@@ -46,7 +68,40 @@ void GpuBrowserCompositorOutputSurface::SwapBuffers(
reflector_->OnPostSubBuffer(frame->gl_frame_data->sub_buffer_rect);
}
- OutputSurface::SwapBuffers(frame);
+ if (frame->gl_frame_data->sub_buffer_rect ==
+ gfx::Rect(frame->gl_frame_data->size)) {
+ context_provider_->ContextSupport()->Swap();
+ } else {
+ context_provider_->ContextSupport()->PartialSwapBuffers(
+ frame->gl_frame_data->sub_buffer_rect);
+ }
+
+ client_->DidSwapBuffers();
+}
+
+void GpuBrowserCompositorOutputSurface::OnSwapBuffersCompleted(
+ const std::vector<ui::LatencyInfo>& latency_info) {
+#if defined(OS_MACOSX)
+ // On Mac, delay acknowledging the swap to the output surface client until
+ // it has been drawn, see OnSurfaceDisplayed();
+ NOTREACHED();
+#else
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&RenderWidgetHostImpl::CompositorFrameDrawn, latency_info));
+ }
+ OnSwapBuffersComplete();
+#endif
+}
+
+#if defined(OS_MACOSX)
+void GpuBrowserCompositorOutputSurface::OnSurfaceDisplayed() {
+ cc::OutputSurface::OnSwapBuffersComplete();
}
+#endif
} // namespace content
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 dd1ac3f693d..c558b56c04b 100644
--- a/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/gpu_browser_compositor_output_surface.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_COMPOSITOR_GPU_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
#define CONTENT_BROWSER_COMPOSITOR_GPU_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
+#include "base/cancelable_callback.h"
#include "content/browser/compositor/browser_compositor_output_surface.h"
namespace ui {
@@ -16,6 +17,7 @@ class OverlayCandidateValidator;
}
namespace content {
+class CommandBufferProxyImpl;
// Adapts a WebGraphicsContext3DCommandBufferImpl into a
// cc::OutputSurface that also handles vsync parameter updates
@@ -30,11 +32,22 @@ class GpuBrowserCompositorOutputSurface
const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
scoped_ptr<cc::OverlayCandidateValidator> overlay_candidate_validator);
- virtual ~GpuBrowserCompositorOutputSurface();
+ ~GpuBrowserCompositorOutputSurface() override;
- private:
+ protected:
// cc::OutputSurface implementation.
- virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE;
+ void SwapBuffers(cc::CompositorFrame* frame) override;
+ bool BindToClient(cc::OutputSurfaceClient* client) override;
+
+#if defined(OS_MACOSX)
+ void OnSurfaceDisplayed() override;
+#endif
+
+ CommandBufferProxyImpl* GetCommandBufferProxy();
+ void OnSwapBuffersCompleted(const std::vector<ui::LatencyInfo>& latency_info);
+
+ base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&)>
+ swap_buffers_completion_callback_;
DISALLOW_COPY_AND_ASSIGN(GpuBrowserCompositorOutputSurface);
};
diff --git a/chromium/content/browser/compositor/gpu_process_transport_factory.cc b/chromium/content/browser/compositor/gpu_process_transport_factory.cc
index bdf7cb4904a..24e721f4201 100644
--- a/chromium/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/chromium/content/browser/compositor/gpu_process_transport_factory.cc
@@ -18,11 +18,14 @@
#include "content/browser/compositor/browser_compositor_output_surface.h"
#include "content/browser/compositor/browser_compositor_output_surface_proxy.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/onscreen_display_client.h"
#include "content/browser/compositor/reflector_impl.h"
#include "content/browser/compositor/software_browser_compositor_output_surface.h"
#include "content/browser/compositor/surface_display_output_surface.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"
@@ -67,11 +70,12 @@ struct GpuProcessTransportFactory::PerCompositorData {
};
GpuProcessTransportFactory::GpuProcessTransportFactory()
- : callback_factory_(this) {
+ : next_surface_id_namespace_(1u),
+ callback_factory_(this) {
output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy(
&output_surface_map_);
#if defined(OS_CHROMEOS)
- bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
+ bool use_thread = !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUIDisableThreadedCompositing);
#else
bool use_thread = false;
@@ -80,10 +84,8 @@ GpuProcessTransportFactory::GpuProcessTransportFactory()
compositor_thread_.reset(new base::Thread("Browser Compositor"));
compositor_thread_->Start();
}
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseSurfaces)) {
+ if (UseSurfacesEnabled())
surface_manager_ = make_scoped_ptr(new cc::SurfaceManager);
- }
}
GpuProcessTransportFactory::~GpuProcessTransportFactory() {
@@ -95,7 +97,11 @@ GpuProcessTransportFactory::~GpuProcessTransportFactory() {
scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
GpuProcessTransportFactory::CreateOffscreenCommandBufferContext() {
- return CreateContextCommon(0);
+ CauseForGpuLaunch cause =
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
+ scoped_refptr<GpuChannelHost> gpu_channel_host(
+ BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(cause));
+ return CreateContextCommon(gpu_channel_host, 0);
}
scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
@@ -123,8 +129,9 @@ scoped_ptr<cc::OverlayCandidateValidator> CreateOverlayCandidateValidator(
#if defined(USE_OZONE)
ui::OverlayCandidatesOzone* overlay_candidates =
ui::SurfaceFactoryOzone::GetInstance()->GetOverlayCandidates(widget);
- if (overlay_candidates && CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableHardwareOverlays)) {
+ if (overlay_candidates &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableHardwareOverlays)) {
return scoped_ptr<cc::OverlayCandidateValidator>(
new OverlayCandidateValidatorOzone(widget, overlay_candidates));
}
@@ -132,11 +139,13 @@ scoped_ptr<cc::OverlayCandidateValidator> CreateOverlayCandidateValidator(
return scoped_ptr<cc::OverlayCandidateValidator>();
}
-scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
- ui::Compositor* compositor, bool software_fallback) {
- PerCompositorData* data = per_compositor_data_[compositor];
+void GpuProcessTransportFactory::CreateOutputSurface(
+ base::WeakPtr<ui::Compositor> compositor,
+ bool software_fallback) {
+ DCHECK(!!compositor);
+ PerCompositorData* data = per_compositor_data_[compositor.get()];
if (!data)
- data = CreatePerCompositorData(compositor);
+ data = CreatePerCompositorData(compositor.get());
bool create_software_renderer = software_fallback;
#if defined(OS_CHROMEOS)
@@ -148,50 +157,89 @@ scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
create_software_renderer = true;
}
#endif
-
- scoped_refptr<ContextProviderCommandBuffer> context_provider;
+ if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
+ create_software_renderer = true;
if (!create_software_renderer) {
+ CauseForGpuLaunch cause =
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
+ BrowserGpuChannelHostFactory::instance()->EstablishGpuChannel(
+ cause,
+ base::Bind(&GpuProcessTransportFactory::EstablishedGpuChannel,
+ callback_factory_.GetWeakPtr(),
+ compositor,
+ create_software_renderer));
+ } else {
+ EstablishedGpuChannel(compositor, create_software_renderer);
+ }
+}
+
+void GpuProcessTransportFactory::EstablishedGpuChannel(
+ base::WeakPtr<ui::Compositor> compositor,
+ bool create_software_renderer) {
+ if (!compositor)
+ return;
+ PerCompositorData* data = per_compositor_data_[compositor.get()];
+ DCHECK(data);
+ scoped_refptr<GpuChannelHost> gpu_channel_host =
+ BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
+ scoped_refptr<ContextProviderCommandBuffer> context_provider;
+ if (gpu_channel_host.get() && !create_software_renderer) {
context_provider = ContextProviderCommandBuffer::Create(
- GpuProcessTransportFactory::CreateContextCommon(data->surface_id),
+ GpuProcessTransportFactory::CreateContextCommon(gpu_channel_host,
+ data->surface_id),
"Compositor");
}
- UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor", !!context_provider);
+ UMA_HISTOGRAM_BOOLEAN("Aura.CreatedGpuBrowserCompositor",
+ !!context_provider.get());
+
+ if (context_provider.get()) {
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner =
+ GetCompositorMessageLoop();
+ if (!compositor_thread_task_runner.get())
+ compositor_thread_task_runner = base::MessageLoopProxy::current();
+
+ // Here we know the GpuProcessHost has been set up, because we created a
+ // context.
+ output_surface_proxy_->ConnectToGpuProcessHost(
+ compositor_thread_task_runner.get());
+ }
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseSurfaces)) {
+ if (UseSurfacesEnabled()) {
// This gets a bit confusing. Here we have a ContextProvider configured to
// render directly to this widget. We need to make an OnscreenDisplayClient
// associated with this context, then return a SurfaceDisplayOutputSurface
// set up to draw to the display's surface.
cc::SurfaceManager* manager = surface_manager_.get();
- scoped_ptr<cc::OutputSurface> software_surface;
- if (!context_provider) {
- software_surface =
+ scoped_ptr<cc::OutputSurface> display_surface;
+ if (!context_provider.get()) {
+ display_surface =
make_scoped_ptr(new SoftwareBrowserCompositorOutputSurface(
output_surface_proxy_,
- CreateSoftwareOutputDevice(compositor),
- per_compositor_data_[compositor]->surface_id,
+ CreateSoftwareOutputDevice(compositor.get()),
+ data->surface_id,
&output_surface_map_,
compositor->vsync_manager()));
+ } else {
+ display_surface = make_scoped_ptr(new GpuBrowserCompositorOutputSurface(
+ context_provider,
+ data->surface_id,
+ &output_surface_map_,
+ compositor->vsync_manager(),
+ CreateOverlayCandidateValidator(compositor->widget())));
}
scoped_ptr<OnscreenDisplayClient> display_client(new OnscreenDisplayClient(
- context_provider, software_surface.Pass(), manager));
- // TODO(jamesr): Need to set up filtering for the
- // GpuHostMsg_UpdateVSyncParameters message.
-
- scoped_refptr<cc::ContextProvider> offscreen_context_provider;
- if (context_provider) {
- offscreen_context_provider = ContextProviderCommandBuffer::Create(
- GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
- "Offscreen-Compositor");
- }
+ display_surface.Pass(), manager, compositor->task_runner()));
+
scoped_ptr<SurfaceDisplayOutputSurface> output_surface(
new SurfaceDisplayOutputSurface(
- display_client->display(), manager, offscreen_context_provider));
+ manager, compositor->surface_id_allocator(), context_provider));
+ display_client->set_surface_output_surface(output_surface.get());
+ output_surface->set_display_client(display_client.get());
data->display_client = display_client.Pass();
- return output_surface.PassAs<cc::OutputSurface>();
+ compositor->SetOutputSurface(output_surface.Pass());
+ return;
}
if (!context_provider.get()) {
@@ -203,34 +251,39 @@ scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
scoped_ptr<SoftwareBrowserCompositorOutputSurface> surface(
new SoftwareBrowserCompositorOutputSurface(
output_surface_proxy_,
- CreateSoftwareOutputDevice(compositor),
- per_compositor_data_[compositor]->surface_id,
+ CreateSoftwareOutputDevice(compositor.get()),
+ data->surface_id,
&output_surface_map_,
compositor->vsync_manager()));
- return surface.PassAs<cc::OutputSurface>();
+ compositor->SetOutputSurface(surface.Pass());
+ return;
}
- scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner =
- GetCompositorMessageLoop();
- if (!compositor_thread_task_runner.get())
- compositor_thread_task_runner = base::MessageLoopProxy::current();
-
- // Here we know the GpuProcessHost has been set up, because we created a
- // context.
- output_surface_proxy_->ConnectToGpuProcessHost(
- compositor_thread_task_runner.get());
+ scoped_ptr<BrowserCompositorOutputSurface> surface;
+#if defined(USE_OZONE)
+ if (ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) {
+ surface.reset(new GpuSurfacelessBrowserCompositorOutputSurface(
+ context_provider,
+ data->surface_id,
+ &output_surface_map_,
+ compositor->vsync_manager(),
+ CreateOverlayCandidateValidator(compositor->widget()),
+ GL_RGB,
+ compositor_thread_ != nullptr));
+ }
+#endif
+ if (!surface)
+ surface.reset(new GpuBrowserCompositorOutputSurface(
+ context_provider,
+ data->surface_id,
+ &output_surface_map_,
+ compositor->vsync_manager(),
+ CreateOverlayCandidateValidator(compositor->widget())));
- scoped_ptr<BrowserCompositorOutputSurface> surface(
- new GpuBrowserCompositorOutputSurface(
- context_provider,
- per_compositor_data_[compositor]->surface_id,
- &output_surface_map_,
- compositor->vsync_manager(),
- CreateOverlayCandidateValidator(compositor->widget())));
if (data->reflector.get())
data->reflector->ReattachToOutputSurfaceFromMainThread(surface.get());
- return surface.PassAs<cc::OutputSurface>();
+ compositor->SetOutputSurface(surface.Pass());
}
scoped_refptr<ui::Reflector> GpuProcessTransportFactory::CreateReflector(
@@ -292,6 +345,11 @@ cc::SharedBitmapManager* GpuProcessTransportFactory::GetSharedBitmapManager() {
return HostSharedBitmapManager::current();
}
+gpu::GpuMemoryBufferManager*
+GpuProcessTransportFactory::GetGpuMemoryBufferManager() {
+ return BrowserGpuMemoryBufferManager::current();
+}
+
ui::ContextFactory* GpuProcessTransportFactory::GetContextFactory() {
return this;
}
@@ -299,17 +357,27 @@ ui::ContextFactory* GpuProcessTransportFactory::GetContextFactory() {
base::MessageLoopProxy* GpuProcessTransportFactory::GetCompositorMessageLoop() {
if (!compositor_thread_)
return NULL;
- return compositor_thread_->message_loop_proxy();
+ return compositor_thread_->message_loop_proxy().get();
}
gfx::GLSurfaceHandle GpuProcessTransportFactory::GetSharedSurfaceHandle() {
gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
- gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
+ gfx::kNullPluginWindow, gfx::NULL_TRANSPORT);
handle.parent_client_id =
BrowserGpuChannelHostFactory::instance()->GetGpuChannelId();
return handle;
}
+scoped_ptr<cc::SurfaceIdAllocator>
+GpuProcessTransportFactory::CreateSurfaceIdAllocator() {
+ return make_scoped_ptr(
+ new cc::SurfaceIdAllocator(next_surface_id_namespace_++));
+}
+
+cc::SurfaceManager* GpuProcessTransportFactory::GetSurfaceManager() {
+ return surface_manager_.get();
+}
+
GLHelper* GpuProcessTransportFactory::GetGLHelper() {
if (!gl_helper_ && !per_compositor_data_.empty()) {
scoped_refptr<cc::ContextProvider> provider =
@@ -353,7 +421,7 @@ GpuProcessTransportFactory::SharedMainThreadContextProvider() {
GpuProcessTransportFactory::CreateOffscreenCommandBufferContext(),
"Offscreen-MainThread");
- if (shared_main_thread_contexts_) {
+ if (shared_main_thread_contexts_.get()) {
shared_main_thread_contexts_->SetLostContextCallback(
base::Bind(&GpuProcessTransportFactory::
OnLostMainThreadSharedContextInsideCallback,
@@ -384,7 +452,9 @@ GpuProcessTransportFactory::CreatePerCompositorData(
}
scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
-GpuProcessTransportFactory::CreateContextCommon(int surface_id) {
+GpuProcessTransportFactory::CreateContextCommon(
+ scoped_refptr<GpuChannelHost> gpu_channel_host,
+ int surface_id) {
if (!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor())
return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
blink::WebGraphicsContext3D::Attributes attrs;
@@ -394,11 +464,7 @@ GpuProcessTransportFactory::CreateContextCommon(int surface_id) {
attrs.antialias = false;
attrs.noAutomaticFlushes = true;
bool lose_context_when_out_of_memory = true;
- CauseForGpuLaunch cause =
- CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
- scoped_refptr<GpuChannelHost> gpu_channel_host(
- BrowserGpuChannelHostFactory::instance()->EstablishGpuChannelSync(cause));
- if (!gpu_channel_host) {
+ if (!gpu_channel_host.get()) {
LOG(ERROR) << "Failed to establish GPU channel.";
return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
}
diff --git a/chromium/content/browser/compositor/gpu_process_transport_factory.h b/chromium/content/browser/compositor/gpu_process_transport_factory.h
index b9c1bee1209..25cfbc0c53a 100644
--- a/chromium/content/browser/compositor/gpu_process_transport_factory.h
+++ b/chromium/content/browser/compositor/gpu_process_transport_factory.h
@@ -13,6 +13,7 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "content/browser/compositor/image_transport_factory.h"
+#include "content/common/gpu/client/gpu_channel_host.h"
#include "ui/compositor/compositor.h"
namespace base {
@@ -37,43 +38,45 @@ class GpuProcessTransportFactory
public:
GpuProcessTransportFactory();
- virtual ~GpuProcessTransportFactory();
+ ~GpuProcessTransportFactory() override;
scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
CreateOffscreenCommandBufferContext();
// ui::ContextFactory implementation.
- virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
- ui::Compositor* compositor, bool software_fallback) OVERRIDE;
- virtual scoped_refptr<ui::Reflector> CreateReflector(
- ui::Compositor* source,
- ui::Layer* target) OVERRIDE;
- virtual void RemoveReflector(
- scoped_refptr<ui::Reflector> reflector) OVERRIDE;
- virtual void RemoveCompositor(ui::Compositor* compositor) OVERRIDE;
- virtual scoped_refptr<cc::ContextProvider>
- SharedMainThreadContextProvider() OVERRIDE;
- virtual bool DoesCreateTestContexts() OVERRIDE;
- virtual cc::SharedBitmapManager* GetSharedBitmapManager() OVERRIDE;
- virtual base::MessageLoopProxy* GetCompositorMessageLoop() OVERRIDE;
+ void CreateOutputSurface(base::WeakPtr<ui::Compositor> compositor,
+ bool software_fallback) override;
+ scoped_refptr<ui::Reflector> CreateReflector(ui::Compositor* source,
+ ui::Layer* target) override;
+ void RemoveReflector(scoped_refptr<ui::Reflector> reflector) override;
+ void RemoveCompositor(ui::Compositor* compositor) override;
+ scoped_refptr<cc::ContextProvider> SharedMainThreadContextProvider() override;
+ bool DoesCreateTestContexts() override;
+ cc::SharedBitmapManager* GetSharedBitmapManager() override;
+ gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
+ base::MessageLoopProxy* GetCompositorMessageLoop() override;
+ scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() override;
// ImageTransportFactory implementation.
- virtual ui::ContextFactory* GetContextFactory() OVERRIDE;
- virtual gfx::GLSurfaceHandle GetSharedSurfaceHandle() OVERRIDE;
- virtual GLHelper* GetGLHelper() OVERRIDE;
- virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE;
- virtual void RemoveObserver(
- ImageTransportFactoryObserver* observer) OVERRIDE;
+ ui::ContextFactory* GetContextFactory() override;
+ gfx::GLSurfaceHandle GetSharedSurfaceHandle() override;
+ cc::SurfaceManager* GetSurfaceManager() override;
+ GLHelper* GetGLHelper() override;
+ void AddObserver(ImageTransportFactoryObserver* observer) override;
+ void RemoveObserver(ImageTransportFactoryObserver* observer) override;
#if defined(OS_MACOSX)
- virtual void OnSurfaceDisplayed(int surface_id) OVERRIDE;
+ void OnSurfaceDisplayed(int surface_id) override;
#endif
private:
struct PerCompositorData;
PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor);
- scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
- CreateContextCommon(int surface_id);
+ void EstablishedGpuChannel(base::WeakPtr<ui::Compositor> compositor,
+ bool create_software_renderer);
+ scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateContextCommon(
+ scoped_refptr<GpuChannelHost> gpu_channel_host,
+ int surface_id);
void OnLostMainThreadSharedContextInsideCallback();
void OnLostMainThreadSharedContext();
@@ -84,8 +87,8 @@ class GpuProcessTransportFactory
scoped_refptr<ContextProviderCommandBuffer> shared_main_thread_contexts_;
scoped_ptr<GLHelper> gl_helper_;
ObserverList<ImageTransportFactoryObserver> observer_list_;
- base::WeakPtrFactory<GpuProcessTransportFactory> callback_factory_;
scoped_ptr<cc::SurfaceManager> surface_manager_;
+ uint32_t next_surface_id_namespace_;
// The contents of this map and its methods may only be used on the compositor
// thread.
@@ -93,6 +96,8 @@ class GpuProcessTransportFactory
scoped_refptr<BrowserCompositorOutputSurfaceProxy> output_surface_proxy_;
+ base::WeakPtrFactory<GpuProcessTransportFactory> callback_factory_;
+
DISALLOW_COPY_AND_ASSIGN(GpuProcessTransportFactory);
};
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
new file mode 100644
index 00000000000..c3d9cbbc056
--- /dev/null
+++ b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -0,0 +1,100 @@
+// 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/gpu_surfaceless_browser_compositor_output_surface.h"
+
+#include "cc/output/compositor_frame.h"
+#include "content/browser/compositor/buffer_queue.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"
+
+namespace content {
+
+GpuSurfacelessBrowserCompositorOutputSurface::
+ GpuSurfacelessBrowserCompositorOutputSurface(
+ const scoped_refptr<ContextProviderCommandBuffer>& context,
+ int surface_id,
+ IDMap<BrowserCompositorOutputSurface>* output_surface_map,
+ const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
+ scoped_ptr<cc::OverlayCandidateValidator> overlay_candidate_validator,
+ unsigned internalformat,
+ bool use_own_gl_helper)
+ : GpuBrowserCompositorOutputSurface(context,
+ surface_id,
+ output_surface_map,
+ vsync_manager,
+ overlay_candidate_validator.Pass()),
+ internalformat_(internalformat),
+ use_own_gl_helper_(use_own_gl_helper) {
+ capabilities_.uses_default_gl_framebuffer = false;
+ capabilities_.flipped_output_surface = true;
+}
+
+GpuSurfacelessBrowserCompositorOutputSurface::
+ ~GpuSurfacelessBrowserCompositorOutputSurface() {
+}
+
+void GpuSurfacelessBrowserCompositorOutputSurface::SwapBuffers(
+ cc::CompositorFrame* frame) {
+ DCHECK(output_surface_);
+
+ GLuint texture = output_surface_->current_texture_id();
+ output_surface_->SwapBuffers(frame->gl_frame_data->sub_buffer_rect);
+ const gfx::Size& size = frame->gl_frame_data->size;
+ context_provider_->ContextGL()->ScheduleOverlayPlaneCHROMIUM(
+ 0,
+ GL_OVERLAY_TRANSFORM_NONE_CHROMIUM,
+ texture,
+ 0,
+ 0,
+ size.width(),
+ size.height(),
+ 0,
+ 0,
+ 1.0f,
+ 1.0f);
+ GpuBrowserCompositorOutputSurface::SwapBuffers(frame);
+}
+
+void GpuSurfacelessBrowserCompositorOutputSurface::OnSwapBuffersComplete() {
+ DCHECK(output_surface_);
+ output_surface_->PageFlipComplete();
+ GpuBrowserCompositorOutputSurface::OnSwapBuffersComplete();
+}
+
+void GpuSurfacelessBrowserCompositorOutputSurface::BindFramebuffer() {
+ DCHECK(output_surface_);
+ output_surface_->BindFramebuffer();
+}
+
+void GpuSurfacelessBrowserCompositorOutputSurface::Reshape(
+ const gfx::Size& size,
+ float scale_factor) {
+ GpuBrowserCompositorOutputSurface::Reshape(size, scale_factor);
+ DCHECK(output_surface_);
+ output_surface_->Reshape(SurfaceSize(), scale_factor);
+}
+
+bool GpuSurfacelessBrowserCompositorOutputSurface::BindToClient(
+ cc::OutputSurfaceClient* client) {
+ if (!GpuBrowserCompositorOutputSurface::BindToClient(client))
+ return false;
+ GLHelper* helper;
+ if (use_own_gl_helper_) {
+ gl_helper_.reset(new GLHelper(context_provider_->ContextGL(),
+ context_provider_->ContextSupport()));
+ helper = gl_helper_.get();
+ } else {
+ helper = ImageTransportFactory::GetInstance()->GetGLHelper();
+ }
+ output_surface_.reset(
+ new BufferQueue(context_provider_, internalformat_, helper));
+ return output_surface_->Initialize();
+}
+
+} // namespace content
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
new file mode 100644
index 00000000000..e95ab7a5223
--- /dev/null
+++ b/chromium/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -0,0 +1,44 @@
+// 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_GPU_SURFACELESS_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
+#define CONTENT_BROWSER_COMPOSITOR_GPU_SURFACELESS_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
+
+#include "content/browser/compositor/gpu_browser_compositor_output_surface.h"
+
+namespace content {
+
+class BufferQueue;
+class GLHelper;
+
+class GpuSurfacelessBrowserCompositorOutputSurface
+ : public GpuBrowserCompositorOutputSurface {
+ public:
+ GpuSurfacelessBrowserCompositorOutputSurface(
+ const scoped_refptr<ContextProviderCommandBuffer>& context,
+ int surface_id,
+ IDMap<BrowserCompositorOutputSurface>* output_surface_map,
+ const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
+ scoped_ptr<cc::OverlayCandidateValidator> overlay_candidate_validator,
+ unsigned internalformat,
+ bool use_own_gl_helper);
+ ~GpuSurfacelessBrowserCompositorOutputSurface() override;
+
+ private:
+ // cc::OutputSurface implementation.
+ void SwapBuffers(cc::CompositorFrame* frame) override;
+ void OnSwapBuffersComplete() override;
+ void BindFramebuffer() override;
+ void Reshape(const gfx::Size& size, float scale_factor) override;
+ bool BindToClient(cc::OutputSurfaceClient* client) override;
+
+ unsigned int internalformat_;
+ bool use_own_gl_helper_;
+ scoped_ptr<GLHelper> gl_helper_;
+ scoped_ptr<BufferQueue> output_surface_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_GPU_SURFACELESS_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_
diff --git a/chromium/content/browser/compositor/image_transport_factory.cc b/chromium/content/browser/compositor/image_transport_factory.cc
index 66d484f51eb..6f06a973168 100644
--- a/chromium/content/browser/compositor/image_transport_factory.cc
+++ b/chromium/content/browser/compositor/image_transport_factory.cc
@@ -6,7 +6,6 @@
#include "base/command_line.h"
#include "content/browser/compositor/gpu_process_transport_factory.h"
-#include "content/browser/compositor/no_transport_image_transport_factory.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/gl/gl_implementation.h"
@@ -33,16 +32,17 @@ void ImageTransportFactory::Initialize() {
}
void ImageTransportFactory::InitializeForUnitTests(
- scoped_ptr<ui::ContextFactory> test_factory) {
+ scoped_ptr<ImageTransportFactory> factory) {
DCHECK(!g_factory);
DCHECK(!g_initialized_for_unit_tests);
g_initialized_for_unit_tests = true;
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnablePixelOutputInTests))
g_disable_null_draw = new gfx::DisableNullDrawGLBindings;
- SetFactory(new NoTransportImageTransportFactory(test_factory.Pass()));
+ SetFactory(factory.release());
}
// static
diff --git a/chromium/content/browser/compositor/image_transport_factory.h b/chromium/content/browser/compositor/image_transport_factory.h
index f53c4a7028f..4b5dec10629 100644
--- a/chromium/content/browser/compositor/image_transport_factory.h
+++ b/chromium/content/browser/compositor/image_transport_factory.h
@@ -9,9 +9,14 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "cc/surfaces/surface_id_allocator.h"
#include "content/common/content_export.h"
#include "ui/gfx/native_widget_types.h"
+namespace cc {
+class SurfaceManager;
+}
+
namespace gfx {
class Size;
}
@@ -55,8 +60,7 @@ class CONTENT_EXPORT ImageTransportFactory {
// Initializes the global transport factory for unit tests using the provided
// context factory.
- static void InitializeForUnitTests(
- scoped_ptr<ui::ContextFactory> test_factory);
+ static void InitializeForUnitTests(scoped_ptr<ImageTransportFactory> factory);
// Terminates the global transport factory.
static void Terminate();
@@ -68,6 +72,7 @@ class CONTENT_EXPORT ImageTransportFactory {
virtual ui::ContextFactory* GetContextFactory() = 0;
virtual gfx::GLSurfaceHandle GetSharedSurfaceHandle() = 0;
+ virtual cc::SurfaceManager* GetSurfaceManager() = 0;
// Gets a GLHelper instance, associated with the shared context. This
// GLHelper will get destroyed whenever the shared context is lost
diff --git a/chromium/content/browser/compositor/image_transport_factory_browsertest.cc b/chromium/content/browser/compositor/image_transport_factory_browsertest.cc
index 61f1bbf107f..327db05f62f 100644
--- a/chromium/content/browser/compositor/image_transport_factory_browsertest.cc
+++ b/chromium/content/browser/compositor/image_transport_factory_browsertest.cc
@@ -24,9 +24,9 @@ class MockImageTransportFactoryObserver : public ImageTransportFactoryObserver {
MOCK_METHOD0(OnLostResources, void());
};
-// This crashes on Mac ASAN
-// http://crbug.com/335083
-#if defined(OS_MACOSX)
+// This crashes on Mac ASAN: http://crbug.com/335083
+// Flaky on ChromeOS: crbug.com/394083
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
#define MAYBE_TestLostContext DISABLED_TestLostContext
#else
#define MAYBE_TestLostContext TestLostContext
@@ -72,8 +72,8 @@ class ImageTransportFactoryTearDownBrowserTest : public ContentBrowserTest {
public:
ImageTransportFactoryTearDownBrowserTest() {}
- virtual void TearDown() {
- if (mailbox_)
+ void TearDown() override {
+ if (mailbox_.get())
EXPECT_TRUE(mailbox_->mailbox().IsZero());
ContentBrowserTest::TearDown();
}
diff --git a/chromium/content/browser/compositor/io_surface_context_mac.h b/chromium/content/browser/compositor/io_surface_context_mac.h
new file mode 100644
index 00000000000..4e5802a0175
--- /dev/null
+++ b/chromium/content/browser/compositor/io_surface_context_mac.h
@@ -0,0 +1,72 @@
+// 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_IO_SURFACE_CONTEXT_MAC_H_
+#define CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_CONTEXT_MAC_H_
+
+#include <OpenGL/OpenGL.h>
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gl/gpu_switching_observer.h"
+#include "ui/gl/scoped_cgl.h"
+
+namespace content {
+
+class IOSurfaceContext
+ : public base::RefCounted<IOSurfaceContext>,
+ public ui::GpuSwitchingObserver {
+ public:
+ enum Type {
+ // The number used to look up the context used for async readback and for
+ // initializing the IOSurface.
+ kOffscreenContext = -2,
+ // The number used to look up the context used by CAOpenGLLayers.
+ kCALayerContext = -3,
+ };
+
+ // Get or create a GL context of the specified type. Share these GL contexts
+ // as much as possible because creating and destroying them can be expensive.
+ // http://crbug.com/180463
+ static scoped_refptr<IOSurfaceContext> Get(Type type);
+
+ // Mark that all the GL contexts in the same sharegroup as this context as
+ // invalid, so they shouldn't be returned anymore by Get, but rather, new
+ // contexts should be created. This is called as a precaution when unexpected
+ // GL errors occur, or after a GPU switch.
+ void PoisonContextAndSharegroup();
+ bool HasBeenPoisoned() const { return poisoned_; }
+
+ CGLContextObj cgl_context() const { return cgl_context_; }
+
+ // content::GpuDataManagerObserver implementation.
+ void OnGpuSwitched() override;
+
+ private:
+ friend class base::RefCounted<IOSurfaceContext>;
+
+ IOSurfaceContext(
+ Type type,
+ base::ScopedTypeRef<CGLContextObj> clg_context_strong);
+ virtual ~IOSurfaceContext();
+
+ Type type_;
+ base::ScopedTypeRef<CGLContextObj> cgl_context_;
+
+ bool poisoned_;
+
+ // The global map from window number and window ordering to
+ // context data.
+ typedef std::map<Type, IOSurfaceContext*> TypeMap;
+ static base::LazyInstance<TypeMap> type_map_;
+ static TypeMap* type_map();
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_CONTEXT_MAC_H_
diff --git a/chromium/content/browser/compositor/io_surface_context_mac.mm b/chromium/content/browser/compositor/io_surface_context_mac.mm
new file mode 100644
index 00000000000..82c81b1a949
--- /dev/null
+++ b/chromium/content/browser/compositor/io_surface_context_mac.mm
@@ -0,0 +1,121 @@
+// 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/compositor/io_surface_context_mac.h"
+
+#include <OpenGL/gl.h>
+#include <OpenGL/OpenGL.h>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "ui/base/ui_base_switches.h"
+#include "ui/gl/gl_switches.h"
+#include "ui/gl/gpu_switching_manager.h"
+
+namespace content {
+
+// static
+scoped_refptr<IOSurfaceContext>
+IOSurfaceContext::Get(Type type) {
+ TRACE_EVENT0("browser", "IOSurfaceContext::Get");
+
+ // Return the context for this type, if it exists.
+ TypeMap::iterator found = type_map()->find(type);
+ if (found != type_map()->end()) {
+ DCHECK(!found->second->poisoned_);
+ return found->second;
+ }
+
+ base::ScopedTypeRef<CGLContextObj> cgl_context;
+ CGLError error = kCGLNoError;
+
+ // Create the pixel format object for the context.
+ std::vector<CGLPixelFormatAttribute> attribs;
+ attribs.push_back(kCGLPFADepthSize);
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
+ if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
+ attribs.push_back(kCGLPFAAllowOfflineRenderers);
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(1));
+ }
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
+ GLint number_virtual_screens = 0;
+ base::ScopedTypeRef<CGLPixelFormatObj> pixel_format;
+ error = CGLChoosePixelFormat(&attribs.front(),
+ pixel_format.InitializeInto(),
+ &number_virtual_screens);
+ if (error != kCGLNoError) {
+ LOG(ERROR) << "Failed to create pixel format object.";
+ return NULL;
+ }
+
+ // Create all contexts in the same share group so that the textures don't
+ // need to be recreated when transitioning contexts.
+ CGLContextObj share_context = NULL;
+ if (!type_map()->empty())
+ share_context = type_map()->begin()->second->cgl_context();
+ error = CGLCreateContext(
+ pixel_format, share_context, cgl_context.InitializeInto());
+ if (error != kCGLNoError) {
+ LOG(ERROR) << "Failed to create context object.";
+ return NULL;
+ }
+
+ return new IOSurfaceContext(type, cgl_context);
+}
+
+void IOSurfaceContext::PoisonContextAndSharegroup() {
+ if (poisoned_)
+ return;
+
+ for (TypeMap::iterator it = type_map()->begin();
+ it != type_map()->end();
+ ++it) {
+ it->second->poisoned_ = true;
+ }
+ type_map()->clear();
+}
+
+IOSurfaceContext::IOSurfaceContext(
+ Type type, base::ScopedTypeRef<CGLContextObj> cgl_context)
+ : type_(type), cgl_context_(cgl_context), poisoned_(false) {
+ DCHECK(type_map()->find(type_) == type_map()->end());
+ type_map()->insert(std::make_pair(type_, this));
+
+ ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
+}
+
+IOSurfaceContext::~IOSurfaceContext() {
+ ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
+
+ if (!poisoned_) {
+ DCHECK(type_map()->find(type_) != type_map()->end());
+ DCHECK(type_map()->find(type_)->second == this);
+ type_map()->erase(type_);
+ } else {
+ TypeMap::const_iterator found = type_map()->find(type_);
+ if (found != type_map()->end())
+ DCHECK(found->second != this);
+ }
+}
+
+void IOSurfaceContext::OnGpuSwitched() {
+ // Recreate all browser-side GL contexts whenever the GPU switches. If this
+ // is not done, performance will suffer.
+ // http://crbug.com/361493
+ PoisonContextAndSharegroup();
+}
+
+// static
+IOSurfaceContext::TypeMap*
+ IOSurfaceContext::type_map() {
+ return type_map_.Pointer();
+}
+
+// static
+base::LazyInstance<IOSurfaceContext::TypeMap>
+ IOSurfaceContext::type_map_;
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/io_surface_layer_mac.h b/chromium/content/browser/compositor/io_surface_layer_mac.h
new file mode 100644
index 00000000000..5a218e8f665
--- /dev/null
+++ b/chromium/content/browser/compositor/io_surface_layer_mac.h
@@ -0,0 +1,161 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_
+#define CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
+#include "base/timer/timer.h"
+#include "ui/gfx/size.h"
+
+@class IOSurfaceLayer;
+
+namespace content {
+class IOSurfaceTexture;
+class IOSurfaceContext;
+
+// The interface through which the IOSurfaceLayer calls back into
+// the structrue that created it (RenderWidgetHostViewMac or
+// BrowserCompositorViewMac).
+class IOSurfaceLayerClient {
+ public:
+ // Used to indicate that the layer should attempt to draw immediately and
+ // should (even if the draw is elided by the system), ack the frame
+ // immediately.
+ virtual bool IOSurfaceLayerShouldAckImmediately() const = 0;
+
+ // Called when a frame is drawn or when, because the layer is not visible, it
+ // is known that the frame will never drawn.
+ virtual void IOSurfaceLayerDidDrawFrame() = 0;
+
+ // Called when an error prevents the frame from being drawn.
+ virtual void IOSurfaceLayerHitError() = 0;
+};
+
+// IOSurfaceLayerHelper provides C++ functionality needed for the
+// IOSurfaceLayer class, and does most of the heavy lifting for the
+// class.
+// TODO(ccameron): This class should own IOSurfaceLayer, rather than
+// vice versa.
+class IOSurfaceLayerHelper {
+ public:
+ IOSurfaceLayerHelper(IOSurfaceLayerClient* client,
+ IOSurfaceLayer* layer);
+ ~IOSurfaceLayerHelper();
+
+ // Called when the IOSurfaceLayer gets a new frame.
+ void GotNewFrame();
+
+ // Called whenever -[IOSurfaceLayer setNeedsDisplay] is called.
+ void SetNeedsDisplay();
+
+ // Called whenever -[IOSurfaceLayer canDrawInCGLContext] is called,
+ // to determine if a new frame should be drawn.
+ bool CanDraw();
+
+ // Called whenever -[IOSurfaceLayer drawInCGLContext] draws a
+ // frame.
+ void DidDraw(bool success);
+
+ // Immediately re-draw the layer, even if the content has not changed, and
+ // ensure that the frame be acked.
+ void SetNeedsDisplayAndDisplayAndAck();
+
+ // Immediately draw the layer, only if one is pending, and ensure that the
+ // frame be acked.
+ void DisplayIfNeededAndAck();
+
+ // Mark a bracket in which new frames are being pumped in a restricted nested
+ // run loop. During this time frames are acked immediately and draws are
+ // deferred until the bracket ends.
+ void BeginPumpingFrames();
+ void EndPumpingFrames();
+
+ private:
+ // Called whenever the frame provided in GotNewFrame should be acknowledged
+ // (this may be because it was drawn, or it may be to unblock the
+ // compositor).
+ void AckPendingFrame(bool success);
+
+ void TimerFired();
+
+ // The client that the owning layer was created with.
+ content::IOSurfaceLayerClient* const client_;
+
+ // The layer that owns this helper.
+ IOSurfaceLayer* const layer_;
+
+ // Used to track when canDrawInCGLContext should return YES. This can be
+ // in response to receiving a new compositor frame, or from any of the events
+ // that cause setNeedsDisplay to be called on the layer.
+ bool needs_display_;
+
+ // This is set when a frame is received, and un-set when the frame is drawn.
+ bool has_pending_frame_;
+
+ // Incremented every time that this layer is asked to draw but does not have
+ // new content to draw.
+ uint64 did_not_draw_counter_;
+
+ // Set when inside a BeginPumpingFrames/EndPumpingFrames block.
+ bool is_pumping_frames_;
+
+ // The browser places back-pressure on the GPU by not acknowledging swap
+ // calls until they appear on the screen. This can lead to hangs if the
+ // view is moved offscreen (among other things). Prevent hangs by always
+ // acknowledging the frame after timeout of 1/6th of a second has passed.
+ base::DelayTimer<IOSurfaceLayerHelper> timer_;
+};
+
+} // namespace content
+
+// The CoreAnimation layer for drawing accelerated content.
+@interface IOSurfaceLayer : CAOpenGLLayer {
+ @private
+ scoped_refptr<content::IOSurfaceTexture> iosurface_;
+ scoped_refptr<content::IOSurfaceContext> context_;
+
+ scoped_ptr<content::IOSurfaceLayerHelper> helper_;
+}
+
+- (id)initWithClient:(content::IOSurfaceLayerClient*)client
+ withScaleFactor:(float)scale_factor;
+
+- (bool)gotFrameWithIOSurface:(IOSurfaceID)io_surface_id
+ withPixelSize:(gfx::Size)pixel_size
+ withScaleFactor:(float)scale_factor;
+
+// Context poison accessors.
+- (void)poisonContextAndSharegroup;
+- (bool)hasBeenPoisoned;
+
+- (float)scaleFactor;
+
+// The CGL renderer ID.
+- (int)rendererID;
+
+// Mark that the client is no longer valid and cannot be called back into. This
+// must be called before the layer is destroyed.
+- (void)resetClient;
+
+// Called when a new frame is received.
+- (void)gotNewFrame;
+
+// Force a draw immediately (even if this means re-displaying a previously
+// displayed frame).
+- (void)setNeedsDisplayAndDisplayAndAck;
+
+// Force a draw immediately, but only if one was requested.
+- (void)displayIfNeededAndAck;
+
+// Mark a bracket in which new frames are being pumped in a restricted nested
+// run loop.
+- (void)beginPumpingFrames;
+- (void)endPumpingFrames;
+@end
+
+#endif // CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_
diff --git a/chromium/content/browser/compositor/io_surface_layer_mac.mm b/chromium/content/browser/compositor/io_surface_layer_mac.mm
new file mode 100644
index 00000000000..d09f24c4902
--- /dev/null
+++ b/chromium/content/browser/compositor/io_surface_layer_mac.mm
@@ -0,0 +1,302 @@
+// 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.
+
+#include "content/browser/compositor/io_surface_layer_mac.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <OpenGL/CGLIOSurface.h>
+#include <OpenGL/CGLRenderers.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/OpenGL.h>
+
+#include "base/mac/mac_util.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "content/browser/compositor/io_surface_context_mac.h"
+#include "content/browser/compositor/io_surface_texture_mac.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_mac.h"
+#include "ui/base/cocoa/animation_utils.h"
+#include "ui/gfx/size_conversions.h"
+#include "ui/gl/gpu_switching_manager.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// IOSurfaceLayerHelper
+
+namespace content {
+
+IOSurfaceLayerHelper::IOSurfaceLayerHelper(
+ IOSurfaceLayerClient* client,
+ IOSurfaceLayer* layer)
+ : client_(client),
+ layer_(layer),
+ needs_display_(false),
+ has_pending_frame_(false),
+ did_not_draw_counter_(0),
+ is_pumping_frames_(false),
+ timer_(
+ FROM_HERE,
+ base::TimeDelta::FromSeconds(1) / 6,
+ this,
+ &IOSurfaceLayerHelper::TimerFired) {}
+
+IOSurfaceLayerHelper::~IOSurfaceLayerHelper() {
+ // Any acks that were waiting on this layer to draw will not occur, so ack
+ // them now to prevent blocking the renderer.
+ AckPendingFrame(true);
+}
+
+void IOSurfaceLayerHelper::GotNewFrame() {
+ // A trace value of 2 indicates that there is a pending swap ack. See
+ // canDrawInCGLContext for other value meanings.
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 2);
+
+ has_pending_frame_ = true;
+ needs_display_ = true;
+ timer_.Reset();
+
+ // If reqested, draw immediately and don't bother trying to use the
+ // isAsynchronous property to ensure smooth animation. If this is while
+ // frames are being pumped then ack and display immediately to get a
+ // correct-sized frame displayed as soon as possible.
+ if (is_pumping_frames_ || client_->IOSurfaceLayerShouldAckImmediately()) {
+ SetNeedsDisplayAndDisplayAndAck();
+ } else {
+ if (![layer_ isAsynchronous])
+ [layer_ setAsynchronous:YES];
+ }
+}
+
+void IOSurfaceLayerHelper::SetNeedsDisplay() {
+ needs_display_ = true;
+}
+
+bool IOSurfaceLayerHelper::CanDraw() {
+ // If we return NO 30 times in a row, switch to being synchronous to avoid
+ // burning CPU cycles on this callback.
+ if (needs_display_) {
+ did_not_draw_counter_ = 0;
+ } else {
+ did_not_draw_counter_ += 1;
+ if (did_not_draw_counter_ == 30)
+ [layer_ setAsynchronous:NO];
+ }
+
+ // Add an instantaneous blip to the PendingSwapAck state to indicate
+ // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually
+ // from 2, indicating that a swap ack is pending) indicates that we
+ // requested a draw. A blip up to 1 (usually from 0, indicating there is no
+ // pending swap ack) indicates that we did not request a draw. This would
+ // be more natural to do with a tracing pseudo-thread
+ // http://crbug.com/366300
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, needs_display_ ? 3 : 1);
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", this,
+ has_pending_frame_ ? 2 : 0);
+
+ return needs_display_;
+}
+
+void IOSurfaceLayerHelper::DidDraw(bool success) {
+ needs_display_ = false;
+ AckPendingFrame(success);
+}
+
+void IOSurfaceLayerHelper::AckPendingFrame(bool success) {
+ if (!has_pending_frame_)
+ return;
+ has_pending_frame_ = false;
+ if (success)
+ client_->IOSurfaceLayerDidDrawFrame();
+ else
+ client_->IOSurfaceLayerHitError();
+ // A trace value of 0 indicates that there is no longer a pending swap ack.
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 0);
+}
+
+void IOSurfaceLayerHelper::SetNeedsDisplayAndDisplayAndAck() {
+ // Drawing using setNeedsDisplay and displayIfNeeded will result in
+ // subsequent canDrawInCGLContext callbacks getting dropped, and jerky
+ // animation. Disable asynchronous drawing before issuing these calls as a
+ // workaround.
+ // http://crbug.com/395827
+ if ([layer_ isAsynchronous])
+ [layer_ setAsynchronous:NO];
+
+ [layer_ setNeedsDisplay];
+ DisplayIfNeededAndAck();
+}
+
+void IOSurfaceLayerHelper::DisplayIfNeededAndAck() {
+ if (!needs_display_)
+ return;
+
+ // As in SetNeedsDisplayAndDisplayAndAck, disable asynchronous drawing before
+ // issuing displayIfNeeded.
+ // http://crbug.com/395827
+ if ([layer_ isAsynchronous])
+ [layer_ setAsynchronous:NO];
+
+ // Do not bother drawing while pumping new frames -- wait until the waiting
+ // block ends to draw any of the new frames.
+ if (!is_pumping_frames_)
+ [layer_ displayIfNeeded];
+
+ // Calls to setNeedsDisplay can sometimes be ignored, especially if issued
+ // rapidly (e.g, with vsync off). This is unacceptable because the failure
+ // to ack a single frame will hang the renderer. Ensure that the renderer
+ // not be blocked by lying and claiming that we drew the frame.
+ AckPendingFrame(true);
+}
+
+void IOSurfaceLayerHelper::TimerFired() {
+ DisplayIfNeededAndAck();
+}
+
+void IOSurfaceLayerHelper::BeginPumpingFrames() {
+ is_pumping_frames_ = true;
+}
+
+void IOSurfaceLayerHelper::EndPumpingFrames() {
+ is_pumping_frames_ = false;
+ DisplayIfNeededAndAck();
+}
+
+} // namespace content
+
+////////////////////////////////////////////////////////////////////////////////
+// IOSurfaceLayer
+
+@implementation IOSurfaceLayer
+
+- (id)initWithClient:(content::IOSurfaceLayerClient*)client
+ withScaleFactor:(float)scale_factor {
+ if (self = [super init]) {
+ helper_.reset(new content::IOSurfaceLayerHelper(client, self));
+
+ iosurface_ = content::IOSurfaceTexture::Create();
+ context_ = content::IOSurfaceContext::Get(
+ content::IOSurfaceContext::kCALayerContext);
+ if (!iosurface_.get() || !context_.get()) {
+ LOG(ERROR) << "Failed create CompositingIOSurface or context";
+ [self resetClient];
+ [self release];
+ return nil;
+ }
+
+ [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
+ [self setAnchorPoint:CGPointMake(0, 0)];
+ // Setting contents gravity is necessary to prevent the layer from being
+ // scaled during dyanmic resizes (especially with devtools open).
+ [self setContentsGravity:kCAGravityTopLeft];
+ if ([self respondsToSelector:(@selector(setContentsScale:))]) {
+ [self setContentsScale:scale_factor];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ DCHECK(!helper_);
+ [super dealloc];
+}
+
+- (bool)gotFrameWithIOSurface:(IOSurfaceID)io_surface_id
+ withPixelSize:(gfx::Size)pixel_size
+ withScaleFactor:(float)scale_factor {
+ return iosurface_->SetIOSurface(io_surface_id, pixel_size);
+}
+
+- (void)poisonContextAndSharegroup {
+ context_->PoisonContextAndSharegroup();
+}
+
+- (bool)hasBeenPoisoned {
+ return context_->HasBeenPoisoned();
+}
+
+- (float)scaleFactor {
+ if ([self respondsToSelector:(@selector(contentsScale))])
+ return [self contentsScale];
+ return 1;
+}
+
+- (int)rendererID {
+ GLint current_renderer_id = -1;
+ if (CGLGetParameter(context_->cgl_context(),
+ kCGLCPCurrentRendererID,
+ &current_renderer_id) == kCGLNoError) {
+ return current_renderer_id & kCGLRendererIDMatchingMask;
+ }
+ return -1;
+}
+
+- (void)resetClient {
+ helper_.reset();
+}
+
+- (void)gotNewFrame {
+ helper_->GotNewFrame();
+}
+
+- (void)setNeedsDisplayAndDisplayAndAck {
+ helper_->SetNeedsDisplayAndDisplayAndAck();
+}
+
+- (void)displayIfNeededAndAck {
+ helper_->DisplayIfNeededAndAck();
+}
+
+- (void)beginPumpingFrames {
+ helper_->BeginPumpingFrames();
+}
+
+- (void)endPumpingFrames {
+ helper_->EndPumpingFrames();
+}
+
+// The remaining methods implement the CAOpenGLLayer interface.
+
+- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
+ if (!context_.get())
+ return [super copyCGLPixelFormatForDisplayMask:mask];
+ return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context()));
+}
+
+- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
+ if (!context_.get())
+ return [super copyCGLContextForPixelFormat:pixelFormat];
+ return CGLRetainContext(context_->cgl_context());
+}
+
+- (void)setNeedsDisplay {
+ if (helper_)
+ helper_->SetNeedsDisplay();
+ [super setNeedsDisplay];
+}
+
+- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
+ pixelFormat:(CGLPixelFormatObj)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval
+ displayTime:(const CVTimeStamp*)timeStamp {
+ if (helper_)
+ return helper_->CanDraw();
+ return NO;
+}
+
+- (void)drawInCGLContext:(CGLContextObj)glContext
+ pixelFormat:(CGLPixelFormatObj)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval
+ displayTime:(const CVTimeStamp*)timeStamp {
+ TRACE_EVENT0("browser", "IOSurfaceLayer::drawInCGLContext");
+
+ bool draw_succeeded = iosurface_->DrawIOSurface();
+ if (helper_)
+ helper_->DidDraw(draw_succeeded);
+
+ [super drawInCGLContext:glContext
+ pixelFormat:pixelFormat
+ forLayerTime:timeInterval
+ displayTime:timeStamp];
+}
+
+@end
diff --git a/chromium/content/browser/compositor/io_surface_texture_mac.h b/chromium/content/browser/compositor/io_surface_texture_mac.h
new file mode 100644
index 00000000000..595c91232dc
--- /dev/null
+++ b/chromium/content/browser/compositor/io_surface_texture_mac.h
@@ -0,0 +1,121 @@
+// 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_IO_SURFACE_TEXTURE_MAC_H_
+#define CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_TEXTURE_MAC_H_
+
+#include <deque>
+#include <list>
+#include <vector>
+
+#import <Cocoa/Cocoa.h>
+#include <IOSurface/IOSurfaceAPI.h>
+#include <QuartzCore/QuartzCore.h>
+
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "media/base/video_frame.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/size.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Rect;
+}
+
+namespace content {
+
+class IOSurfaceContext;
+class RenderWidgetHostViewFrameSubscriber;
+class RenderWidgetHostViewMac;
+
+// This class manages an OpenGL context and IOSurfaceTexture for the accelerated
+// compositing code path. The GL context is attached to
+// RenderWidgetHostViewCocoa for blitting the IOSurfaceTexture.
+class IOSurfaceTexture
+ : public base::RefCounted<IOSurfaceTexture> {
+ public:
+ // Returns NULL if IOSurfaceTexture or GL API calls fail.
+ static scoped_refptr<IOSurfaceTexture> Create();
+
+ // Set IOSurfaceTexture that will be drawn on the next NSView drawRect.
+ bool SetIOSurface(
+ IOSurfaceID io_surface_id,
+ const gfx::Size& pixel_size) WARN_UNUSED_RESULT;
+
+ // Blit the IOSurface to the rectangle specified by |window_rect| in DIPs,
+ // with the origin in the lower left corner. If the window rect's size is
+ // larger than the IOSurface, the remaining right and bottom edges will be
+ // white. |window_scale_factor| is 1 in normal views, 2 in HiDPI views.
+ bool DrawIOSurface() WARN_UNUSED_RESULT;
+
+ // Returns true if the offscreen context used by this surface has been
+ // poisoned.
+ bool HasBeenPoisoned() const;
+
+ private:
+ friend class base::RefCounted<IOSurfaceTexture>;
+
+ IOSurfaceTexture(
+ const scoped_refptr<IOSurfaceContext>& context);
+ ~IOSurfaceTexture();
+
+ // Unref the IOSurfaceTexture and delete the associated GL texture. If the GPU
+ // process is no longer referencing it, this will delete the IOSurface.
+ void ReleaseIOSurfaceAndTexture();
+
+ // Check for GL errors and store the result in error_. Only return new
+ // errors
+ GLenum GetAndSaveGLError();
+
+ // Offscreen context used for all operations other than drawing to the
+ // screen. This is in the same share group as the contexts used for
+ // drawing, and is the same for all IOSurfaces in all windows.
+ scoped_refptr<IOSurfaceContext> offscreen_context_;
+
+ // The IOSurface and its non-rounded size.
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
+ gfx::Size pixel_size_;
+
+ // The "live" OpenGL texture referring to this IOSurfaceRef. Note
+ // that per the CGLTexImageIOSurface2D API we do not need to
+ // explicitly update this texture's contents once created. All we
+ // need to do is ensure it is re-bound before attempting to draw
+ // with it.
+ GLuint texture_;
+
+ // Error saved by GetAndSaveGLError
+ GLint gl_error_;
+
+ // Aggressive IOSurface eviction logic. When using CoreAnimation, IOSurfaces
+ // are used only transiently to transfer from the GPU process to the browser
+ // process. Once the IOSurface has been drawn to its CALayer, the CALayer
+ // will not need updating again until its view is hidden and re-shown.
+ // Aggressively evict surfaces when more than 8 (the number allowed by the
+ // memory manager for fast tab switching) are allocated.
+ enum {
+ kMaximumUnevictedSurfaces = 8,
+ };
+ typedef std::list<IOSurfaceTexture*> EvictionQueue;
+ void EvictionMarkUpdated();
+ void EvictionMarkEvicted();
+ EvictionQueue::iterator eviction_queue_iterator_;
+ bool eviction_has_been_drawn_since_updated_;
+
+ static void EvictionScheduleDoEvict();
+ static void EvictionDoEvict();
+ static base::LazyInstance<EvictionQueue> eviction_queue_;
+ static bool eviction_scheduled_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_TEXTURE_MAC_H_
diff --git a/chromium/content/browser/compositor/io_surface_texture_mac.mm b/chromium/content/browser/compositor/io_surface_texture_mac.mm
new file mode 100644
index 00000000000..dea6b287682
--- /dev/null
+++ b/chromium/content/browser/compositor/io_surface_texture_mac.mm
@@ -0,0 +1,297 @@
+// 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/io_surface_texture_mac.h"
+
+#include <OpenGL/CGLIOSurface.h>
+#include <OpenGL/CGLRenderers.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/mac/mac_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/threading/platform_thread.h"
+#include "content/browser/compositor/io_surface_context_mac.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_mac.h"
+#include "content/common/content_constants_internal.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "media/base/video_util.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
+#include "ui/gfx/size_conversions.h"
+#include "ui/gl/gl_context.h"
+
+namespace content {
+
+// static
+scoped_refptr<IOSurfaceTexture> IOSurfaceTexture::Create() {
+ scoped_refptr<IOSurfaceContext> offscreen_context =
+ IOSurfaceContext::Get(
+ IOSurfaceContext::kOffscreenContext);
+ if (!offscreen_context.get()) {
+ LOG(ERROR) << "Failed to create context for offscreen operations";
+ return NULL;
+ }
+
+ return new IOSurfaceTexture(offscreen_context);
+}
+
+IOSurfaceTexture::IOSurfaceTexture(
+ const scoped_refptr<IOSurfaceContext>& offscreen_context)
+ : offscreen_context_(offscreen_context),
+ texture_(0),
+ gl_error_(GL_NO_ERROR),
+ eviction_queue_iterator_(eviction_queue_.Get().end()),
+ eviction_has_been_drawn_since_updated_(false) {
+ CHECK(offscreen_context_.get());
+}
+
+IOSurfaceTexture::~IOSurfaceTexture() {
+ ReleaseIOSurfaceAndTexture();
+ offscreen_context_ = NULL;
+ DCHECK(eviction_queue_iterator_ == eviction_queue_.Get().end());
+}
+
+bool IOSurfaceTexture::DrawIOSurface() {
+ TRACE_EVENT0("browser", "IOSurfaceTexture::DrawIOSurface");
+
+ // If we have release the IOSurface, clear the screen to light grey and
+ // early-out.
+ if (!io_surface_) {
+ glClearColor(0.9, 0.9, 0.9, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ return false;
+ }
+
+ // The viewport is the size of the CALayer, which should always match the
+ // IOSurface pixel size.
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ gfx::Rect viewport_rect(viewport[0], viewport[1], viewport[2], viewport[3]);
+ DCHECK_EQ(pixel_size_.ToString(), viewport_rect.size().ToString());
+
+ // Set the projection matrix to match 1 unit to 1 pixel.
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, viewport_rect.width(), 0, viewport_rect.height(), -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ // Draw a quad the size of the IOSurface. This should cover the full viewport.
+ glColor4f(1, 1, 1, 1);
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex2f(0, 0);
+ glTexCoord2f(pixel_size_.width(), 0);
+ glVertex2f(pixel_size_.width(), 0);
+ glTexCoord2f(pixel_size_.width(), pixel_size_.height());
+ glVertex2f(pixel_size_.width(), pixel_size_.height());
+ glTexCoord2f(0, pixel_size_.height());
+ glVertex2f(0, pixel_size_.height());
+ glEnd();
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ // Workaround for issue 158469. Issue a dummy draw call with texture_ not
+ // bound to a texture, in order to shake all references to the IOSurface out
+ // of the driver.
+ glBegin(GL_TRIANGLES);
+ glEnd();
+
+ bool workaround_needed =
+ GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
+ gpu::FORCE_GL_FINISH_AFTER_COMPOSITING);
+ if (workaround_needed) {
+ TRACE_EVENT0("gpu", "glFinish");
+ glFinish();
+ }
+
+ // Check if any of the drawing calls result in an error.
+ GetAndSaveGLError();
+ bool result = true;
+ if (gl_error_ != GL_NO_ERROR) {
+ LOG(ERROR) << "GL error in DrawIOSurface: " << gl_error_;
+ result = false;
+ // If there was an error, clear the screen to a light grey to avoid
+ // rendering artifacts.
+ glClearColor(0.8, 0.8, 0.8, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ eviction_has_been_drawn_since_updated_ = true;
+ return result;
+}
+
+bool IOSurfaceTexture::SetIOSurface(
+ IOSurfaceID io_surface_id,
+ const gfx::Size& pixel_size) {
+ TRACE_EVENT0("browser", "IOSurfaceTexture::MapIOSurfaceToTexture");
+
+ // Destroy the old IOSurface and texture if it is no longer needed.
+ bool needs_new_iosurface =
+ !io_surface_ || io_surface_id != IOSurfaceGetID(io_surface_);
+ if (needs_new_iosurface)
+ ReleaseIOSurfaceAndTexture();
+
+ // Note that because IOSurface sizes are rounded, the same IOSurface may have
+ // two different sizes associated with it, so update the sizes before the
+ // early-out.
+ pixel_size_ = pixel_size;
+
+ // Early-out if the IOSurface has not changed.
+ if (!needs_new_iosurface)
+ return true;
+
+ // If we early-out at any point from now on, it's because of an error, and we
+ // should destroy the texture and release the IOSurface.
+ base::ScopedClosureRunner error_runner(base::BindBlock(^{
+ ReleaseIOSurfaceAndTexture();
+ }));
+
+ // Open the IOSurface handle.
+ io_surface_.reset(IOSurfaceLookup(io_surface_id));
+ if (!io_surface_)
+ return false;
+
+ // Actual IOSurface size is rounded up to reduce reallocations during window
+ // resize. Get the actual size to properly map the texture.
+ gfx::Size rounded_size(IOSurfaceGetWidth(io_surface_),
+ IOSurfaceGetHeight(io_surface_));
+
+ // Create the GL texture and set it to be backed by the IOSurface.
+ CGLError cgl_error = kCGLNoError;
+ {
+ gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+ offscreen_context_->cgl_context());
+ glGenTextures(1, &texture_);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
+ glTexParameterf(
+ GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(
+ GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ cgl_error = CGLTexImageIOSurface2D(
+ offscreen_context_->cgl_context(),
+ GL_TEXTURE_RECTANGLE_ARB,
+ GL_RGBA,
+ rounded_size.width(),
+ rounded_size.height(),
+ GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ io_surface_.get(),
+ 0 /* plane */);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ GetAndSaveGLError();
+ }
+
+ // Return failure if an error was encountered by CGL or GL.
+ if (cgl_error != kCGLNoError) {
+ LOG(ERROR) << "CGLTexImageIOSurface2D failed with CGL error: " << cgl_error;
+ return false;
+ }
+ if (gl_error_ != GL_NO_ERROR) {
+ LOG(ERROR) << "Hit GL error in SetIOSurface: " << gl_error_;
+ return false;
+ }
+
+ ignore_result(error_runner.Release());
+ return true;
+}
+
+void IOSurfaceTexture::ReleaseIOSurfaceAndTexture() {
+ gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+ offscreen_context_->cgl_context());
+
+ if (texture_) {
+ glDeleteTextures(1, &texture_);
+ texture_ = 0;
+ }
+ pixel_size_ = gfx::Size();
+ io_surface_.reset();
+
+ EvictionMarkEvicted();
+}
+
+bool IOSurfaceTexture::HasBeenPoisoned() const {
+ return offscreen_context_->HasBeenPoisoned();
+}
+
+GLenum IOSurfaceTexture::GetAndSaveGLError() {
+ GLenum gl_error = glGetError();
+ if (gl_error_ == GL_NO_ERROR)
+ gl_error_ = gl_error;
+ return gl_error;
+}
+
+void IOSurfaceTexture::EvictionMarkUpdated() {
+ EvictionMarkEvicted();
+ eviction_queue_.Get().push_back(this);
+ eviction_queue_iterator_ = --eviction_queue_.Get().end();
+ eviction_has_been_drawn_since_updated_ = false;
+ EvictionScheduleDoEvict();
+}
+
+void IOSurfaceTexture::EvictionMarkEvicted() {
+ if (eviction_queue_iterator_ == eviction_queue_.Get().end())
+ return;
+ eviction_queue_.Get().erase(eviction_queue_iterator_);
+ eviction_queue_iterator_ = eviction_queue_.Get().end();
+ eviction_has_been_drawn_since_updated_ = false;
+}
+
+// static
+void IOSurfaceTexture::EvictionScheduleDoEvict() {
+ if (eviction_scheduled_)
+ return;
+ if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
+ return;
+
+ eviction_scheduled_ = true;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&IOSurfaceTexture::EvictionDoEvict));
+}
+
+// static
+void IOSurfaceTexture::EvictionDoEvict() {
+ eviction_scheduled_ = false;
+ // Walk the list of allocated surfaces from least recently used to most
+ // recently used.
+ for (EvictionQueue::iterator it = eviction_queue_.Get().begin();
+ it != eviction_queue_.Get().end();) {
+ IOSurfaceTexture* surface = *it;
+ ++it;
+
+ // If the number of IOSurfaces allocated is less than the threshold,
+ // stop walking the list of surfaces.
+ if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
+ break;
+
+ // Don't evict anything that has not yet been drawn.
+ if (!surface->eviction_has_been_drawn_since_updated_)
+ continue;
+
+ // Evict the surface.
+ surface->ReleaseIOSurfaceAndTexture();
+ }
+}
+
+// static
+base::LazyInstance<IOSurfaceTexture::EvictionQueue>
+ IOSurfaceTexture::eviction_queue_;
+
+// static
+bool IOSurfaceTexture::eviction_scheduled_ = false;
+
+} // namespace content
diff --git a/chromium/content/browser/compositor/no_transport_image_transport_factory.cc b/chromium/content/browser/compositor/no_transport_image_transport_factory.cc
deleted file mode 100644
index 03289c0f685..00000000000
--- a/chromium/content/browser/compositor/no_transport_image_transport_factory.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/compositor/no_transport_image_transport_factory.h"
-
-#include "cc/output/context_provider.h"
-#include "content/common/gpu/client/gl_helper.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ui/compositor/compositor.h"
-
-namespace content {
-
-NoTransportImageTransportFactory::NoTransportImageTransportFactory(
- scoped_ptr<ui::ContextFactory> context_factory)
- : context_factory_(context_factory.Pass()) {}
-
-NoTransportImageTransportFactory::~NoTransportImageTransportFactory() {
- scoped_ptr<GLHelper> lost_gl_helper = gl_helper_.Pass();
- FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
- observer_list_,
- OnLostResources());
-}
-
-ui::ContextFactory* NoTransportImageTransportFactory::GetContextFactory() {
- return context_factory_.get();
-}
-
-gfx::GLSurfaceHandle
-NoTransportImageTransportFactory::GetSharedSurfaceHandle() {
- return gfx::GLSurfaceHandle();
-}
-
-GLHelper* NoTransportImageTransportFactory::GetGLHelper() {
- if (!gl_helper_) {
- context_provider_ = context_factory_->SharedMainThreadContextProvider();
- gl_helper_.reset(new GLHelper(context_provider_->ContextGL(),
- context_provider_->ContextSupport()));
- }
- return gl_helper_.get();
-}
-
-void NoTransportImageTransportFactory::AddObserver(
- ImageTransportFactoryObserver* observer) {
- observer_list_.AddObserver(observer);
-}
-
-void NoTransportImageTransportFactory::RemoveObserver(
- ImageTransportFactoryObserver* observer) {
- observer_list_.RemoveObserver(observer);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/compositor/no_transport_image_transport_factory.h b/chromium/content/browser/compositor/no_transport_image_transport_factory.h
deleted file mode 100644
index fd5f6bf1be5..00000000000
--- a/chromium/content/browser/compositor/no_transport_image_transport_factory.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_COMPOSITOR_NO_TRANSPORT_IMAGE_TRANSPORT_FACTORY_H_
-#define CONTENT_BROWSER_COMPOSITOR_NO_TRANSPORT_IMAGE_TRANSPORT_FACTORY_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
-#include "content/browser/compositor/image_transport_factory.h"
-
-namespace cc {
-class ContextProvider;
-}
-
-namespace content {
-
-// An ImageTransportFactory that disables transport.
-class NoTransportImageTransportFactory : public ImageTransportFactory {
- public:
- explicit NoTransportImageTransportFactory(
- scoped_ptr<ui::ContextFactory> context_factory);
- virtual ~NoTransportImageTransportFactory();
-
- // ImageTransportFactory implementation.
- virtual ui::ContextFactory* GetContextFactory() OVERRIDE;
- virtual gfx::GLSurfaceHandle GetSharedSurfaceHandle() OVERRIDE;
- virtual GLHelper* GetGLHelper() OVERRIDE;
- virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE;
- virtual void RemoveObserver(ImageTransportFactoryObserver* observer) OVERRIDE;
-#if defined(OS_MACOSX)
- virtual void OnSurfaceDisplayed(int surface_id) OVERRIDE {}
-#endif
-
- private:
- scoped_ptr<ui::ContextFactory> context_factory_;
- scoped_refptr<cc::ContextProvider> context_provider_;
- scoped_ptr<GLHelper> gl_helper_;
- ObserverList<ImageTransportFactoryObserver> observer_list_;
-
- DISALLOW_COPY_AND_ASSIGN(NoTransportImageTransportFactory);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_COMPOSITOR_NO_TRANSPORT_IMAGE_TRANSPORT_FACTORY_H_
diff --git a/chromium/content/browser/compositor/onscreen_display_client.cc b/chromium/content/browser/compositor/onscreen_display_client.cc
index 814f0fcc53e..6e2241d6cb1 100644
--- a/chromium/content/browser/compositor/onscreen_display_client.cc
+++ b/chromium/content/browser/compositor/onscreen_display_client.cc
@@ -4,28 +4,93 @@
#include "content/browser/compositor/onscreen_display_client.h"
+#include "base/debug/trace_event.h"
#include "cc/output/output_surface.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_manager.h"
+#include "content/browser/compositor/surface_display_output_surface.h"
+#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/common/host_shared_bitmap_manager.h"
namespace content {
OnscreenDisplayClient::OnscreenDisplayClient(
- const scoped_refptr<cc::ContextProvider>& onscreen_context_provider,
- scoped_ptr<cc::OutputSurface> software_surface,
- cc::SurfaceManager* manager)
- : onscreen_context_provider_(onscreen_context_provider),
- software_surface_(software_surface.Pass()),
- display_(this, manager, HostSharedBitmapManager::current()) {
+ scoped_ptr<cc::OutputSurface> output_surface,
+ cc::SurfaceManager* manager,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : output_surface_(output_surface.Pass()),
+ display_(new cc::Display(this,
+ manager,
+ HostSharedBitmapManager::current(),
+ BrowserGpuMemoryBufferManager::current())),
+ task_runner_(task_runner),
+ scheduled_draw_(false),
+ output_surface_lost_(false),
+ deferred_draw_(false),
+ pending_frames_(0),
+ weak_ptr_factory_(this) {
}
OnscreenDisplayClient::~OnscreenDisplayClient() {
}
-scoped_ptr<cc::OutputSurface> OnscreenDisplayClient::CreateOutputSurface() {
- if (!onscreen_context_provider_)
- return software_surface_.Pass();
- return make_scoped_ptr(new cc::OutputSurface(onscreen_context_provider_))
- .Pass();
+bool OnscreenDisplayClient::Initialize() {
+ return display_->Initialize(output_surface_.Pass());
+}
+
+void OnscreenDisplayClient::CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ surface_display_output_surface_->ReceivedVSyncParameters(timebase, interval);
+}
+
+void OnscreenDisplayClient::DisplayDamaged() {
+ if (scheduled_draw_ || deferred_draw_)
+ return;
+ TRACE_EVENT0("content", "OnscreenDisplayClient::DisplayDamaged");
+ if (pending_frames_ >= display_->GetMaxFramesPending()) {
+ deferred_draw_ = true;
+ } else {
+ ScheduleDraw();
+ }
+}
+
+void OnscreenDisplayClient::ScheduleDraw() {
+ DCHECK(!deferred_draw_);
+ DCHECK(!scheduled_draw_);
+ scheduled_draw_ = true;
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&OnscreenDisplayClient::Draw, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void OnscreenDisplayClient::OutputSurfaceLost() {
+ output_surface_lost_ = true;
+ surface_display_output_surface_->DidLoseOutputSurface();
+}
+
+void OnscreenDisplayClient::Draw() {
+ TRACE_EVENT0("content", "OnscreenDisplayClient::Draw");
+ if (output_surface_lost_)
+ return;
+ scheduled_draw_ = false;
+ display_->Draw();
+}
+
+void OnscreenDisplayClient::DidSwapBuffers() {
+ pending_frames_++;
+}
+
+void OnscreenDisplayClient::DidSwapBuffersComplete() {
+ pending_frames_--;
+ if ((pending_frames_ < display_->GetMaxFramesPending()) && deferred_draw_) {
+ deferred_draw_ = false;
+ ScheduleDraw();
+ }
+}
+
+void OnscreenDisplayClient::SetMemoryPolicy(
+ const cc::ManagedMemoryPolicy& policy) {
+ surface_display_output_surface_->SetMemoryPolicy(policy);
}
} // namespace content
diff --git a/chromium/content/browser/compositor/onscreen_display_client.h b/chromium/content/browser/compositor/onscreen_display_client.h
index 7ab6ff7d02b..206f79a322c 100644
--- a/chromium/content/browser/compositor/onscreen_display_client.h
+++ b/chromium/content/browser/compositor/onscreen_display_client.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "cc/surfaces/display.h"
namespace cc {
@@ -17,26 +18,49 @@ class SurfaceManager;
}
namespace content {
+class SurfaceDisplayOutputSurface;
// This class provides a DisplayClient implementation for drawing directly to an
// onscreen context.
class OnscreenDisplayClient : cc::DisplayClient {
public:
OnscreenDisplayClient(
- const scoped_refptr<cc::ContextProvider>& onscreen_context_provider,
- scoped_ptr<cc::OutputSurface> software_surface,
- cc::SurfaceManager* manager);
- virtual ~OnscreenDisplayClient();
+ scoped_ptr<cc::OutputSurface> output_surface,
+ cc::SurfaceManager* manager,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ ~OnscreenDisplayClient() override;
- cc::Display* display() { return &display_; }
+ bool Initialize();
+ cc::Display* display() { return display_.get(); }
+ void set_surface_output_surface(SurfaceDisplayOutputSurface* surface) {
+ surface_display_output_surface_ = surface;
+ }
// cc::DisplayClient implementation.
- virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface() OVERRIDE;
+ void DisplayDamaged() override;
+ void DidSwapBuffers() override;
+ void DidSwapBuffersComplete() override;
+ void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override;
+ void OutputSurfaceLost() override;
+ void SetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override;
private:
- scoped_refptr<cc::ContextProvider> onscreen_context_provider_;
- scoped_ptr<cc::OutputSurface> software_surface_;
- cc::Display display_;
+ void ScheduleDraw();
+ void Draw();
+
+ scoped_ptr<cc::OutputSurface> output_surface_;
+ scoped_ptr<cc::Display> display_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ SurfaceDisplayOutputSurface* surface_display_output_surface_;
+ bool scheduled_draw_;
+ bool output_surface_lost_;
+ // True if a draw should be scheduled, but it's hit the limit on max frames
+ // pending.
+ bool deferred_draw_;
+ int pending_frames_;
+
+ base::WeakPtrFactory<OnscreenDisplayClient> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(OnscreenDisplayClient);
};
diff --git a/chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc b/chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc
index b4a3cfeace0..a92dc1011de 100644
--- a/chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc
+++ b/chromium/content/browser/compositor/overlay_candidate_validator_ozone.cc
@@ -15,6 +15,7 @@ static ui::SurfaceFactoryOzone::BufferFormat GetOzoneFormat(
return ui::SurfaceFactoryOzone::RGBA_8888;
case cc::RGBA_4444:
case cc::BGRA_8888:
+ case cc::ALPHA_8:
case cc::LUMINANCE_8:
case cc::RGB_565:
case cc::ETC1:
diff --git a/chromium/content/browser/compositor/overlay_candidate_validator_ozone.h b/chromium/content/browser/compositor/overlay_candidate_validator_ozone.h
index 8fb690b5196..0e81d53e7c0 100644
--- a/chromium/content/browser/compositor/overlay_candidate_validator_ozone.h
+++ b/chromium/content/browser/compositor/overlay_candidate_validator_ozone.h
@@ -25,7 +25,7 @@ class CONTENT_EXPORT OverlayCandidateValidatorOzone
virtual ~OverlayCandidateValidatorOzone();
// cc::OverlayCandidateValidator implementation.
- virtual void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) OVERRIDE;
+ virtual void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
private:
gfx::AcceleratedWidget widget_;
diff --git a/chromium/content/browser/compositor/owned_mailbox.h b/chromium/content/browser/compositor/owned_mailbox.h
index 3926c81e0fd..c8868148f4d 100644
--- a/chromium/content/browser/compositor/owned_mailbox.h
+++ b/chromium/content/browser/compositor/owned_mailbox.h
@@ -31,10 +31,10 @@ class CONTENT_EXPORT OwnedMailbox : public base::RefCounted<OwnedMailbox>,
void Destroy();
protected:
- virtual ~OwnedMailbox();
+ ~OwnedMailbox() override;
// ImageTransportFactoryObserver implementation.
- virtual void OnLostResources() OVERRIDE;
+ void OnLostResources() override;
private:
friend class base::RefCounted<OwnedMailbox>;
diff --git a/chromium/content/browser/compositor/reflector_impl.cc b/chromium/content/browser/compositor/reflector_impl.cc
index 2ccded325fe..ac3bdda748e 100644
--- a/chromium/content/browser/compositor/reflector_impl.cc
+++ b/chromium/content/browser/compositor/reflector_impl.cc
@@ -88,7 +88,7 @@ void ReflectorImpl::OnSourceSurfaceReady(
void ReflectorImpl::Shutdown() {
MainThreadData& main = GetMain();
main.mailbox = NULL;
- main.mirroring_layer->SetShowPaintedContent();
+ main.mirroring_layer->SetShowSolidColorContent();
main.mirroring_layer = NULL;
impl_message_loop_->PostTask(
FROM_HERE, base::Bind(&ReflectorImpl::ShutdownOnImplThread, this));
@@ -122,7 +122,7 @@ void ReflectorImpl::ReattachToOutputSurfaceFromMainThread(
GLHelper* helper = ImageTransportFactory::GetInstance()->GetGLHelper();
main.mailbox = new OwnedMailbox(helper);
main.needs_set_mailbox = true;
- main.mirroring_layer->SetShowPaintedContent();
+ main.mirroring_layer->SetShowSolidColorContent();
impl_message_loop_->PostTask(
FROM_HERE,
base::Bind(&ReflectorImpl::AttachToOutputSurfaceOnImplThread,
@@ -201,7 +201,7 @@ void ReflectorImpl::AttachToOutputSurfaceOnImplThread(
void ReflectorImpl::UpdateTextureSizeOnMainThread(gfx::Size size) {
MainThreadData& main = GetMain();
- if (!main.mirroring_layer || !main.mailbox ||
+ if (!main.mirroring_layer || !main.mailbox.get() ||
main.mailbox->mailbox().IsZero())
return;
if (main.needs_set_mailbox) {
diff --git a/chromium/content/browser/compositor/reflector_impl.h b/chromium/content/browser/compositor/reflector_impl.h
index 0a9af98ca61..f771fe46c33 100644
--- a/chromium/content/browser/compositor/reflector_impl.h
+++ b/chromium/content/browser/compositor/reflector_impl.h
@@ -53,7 +53,7 @@ class ReflectorImpl : public base::SupportsWeakPtr<ReflectorImpl>,
BrowserCompositorOutputSurface* surface);
// ui::Reflector implementation.
- virtual void OnMirroringCompositorResized() OVERRIDE;
+ void OnMirroringCompositorResized() override;
// Called in |BrowserCompositorOutputSurface::SwapBuffers| to copy
// the full screen image to the |texture_id_|. This must be called
@@ -99,7 +99,7 @@ class ReflectorImpl : public base::SupportsWeakPtr<ReflectorImpl>,
gpu::MailboxHolder mailbox_holder;
};
- virtual ~ReflectorImpl();
+ ~ReflectorImpl() override;
void AttachToOutputSurfaceOnImplThread(
const gpu::MailboxHolder& mailbox_holder,
diff --git a/chromium/content/browser/compositor/software_browser_compositor_output_surface.cc b/chromium/content/browser/compositor/software_browser_compositor_output_surface.cc
index 369fe930dbd..98c707f6611 100644
--- a/chromium/content/browser/compositor/software_browser_compositor_output_surface.cc
+++ b/chromium/content/browser/compositor/software_browser_compositor_output_surface.cc
@@ -8,6 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
#include "cc/output/compositor_frame.h"
+#include "cc/output/output_surface_client.h"
#include "cc/output/software_output_device.h"
#include "content/browser/compositor/browser_compositor_output_surface_proxy.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -51,6 +52,15 @@ void SoftwareBrowserCompositorOutputSurface::SwapBuffers(
output_surface_proxy_,
surface_id_));
}
+ PostSwapBuffersComplete();
+ client_->DidSwapBuffers();
}
+#if defined(OS_MACOSX)
+void SoftwareBrowserCompositorOutputSurface::OnSurfaceDisplayed() {
+ // See GpuBrowserCompositorOutputSurface for when and how this is used.
+ NOTREACHED() << "Not expected for software surfaces.";
+}
+#endif
+
} // namespace content
diff --git a/chromium/content/browser/compositor/software_browser_compositor_output_surface.h b/chromium/content/browser/compositor/software_browser_compositor_output_surface.h
index 788d9daa9e6..1df9b366edd 100644
--- a/chromium/content/browser/compositor/software_browser_compositor_output_surface.h
+++ b/chromium/content/browser/compositor/software_browser_compositor_output_surface.h
@@ -31,10 +31,14 @@ class CONTENT_EXPORT SoftwareBrowserCompositorOutputSurface
IDMap<BrowserCompositorOutputSurface>* output_surface_map,
const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager);
- virtual ~SoftwareBrowserCompositorOutputSurface();
+ ~SoftwareBrowserCompositorOutputSurface() override;
private:
- virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE;
+ void SwapBuffers(cc::CompositorFrame* frame) override;
+
+#if defined(OS_MACOSX)
+ void OnSurfaceDisplayed() override;
+#endif
// On the software path we need to explicitly call the proxy to update the
// VSync parameters.
diff --git a/chromium/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc b/chromium/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
index 79c3364d890..904fca2d2f4 100644
--- a/chromium/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
+++ b/chromium/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
@@ -4,6 +4,7 @@
#include "base/message_loop/message_loop.h"
#include "cc/output/compositor_frame.h"
+#include "cc/test/fake_output_surface_client.h"
#include "content/browser/compositor/browser_compositor_output_surface_proxy.h"
#include "content/browser/compositor/software_browser_compositor_output_surface.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -16,10 +17,9 @@ namespace {
class FakeVSyncProvider : public gfx::VSyncProvider {
public:
FakeVSyncProvider() : call_count_(0) {}
- virtual ~FakeVSyncProvider() {}
+ ~FakeVSyncProvider() override {}
- virtual void GetVSyncParameters(const UpdateVSyncCallback& callback)
- OVERRIDE {
+ void GetVSyncParameters(const UpdateVSyncCallback& callback) override {
callback.Run(timebase_, interval_);
call_count_++;
}
@@ -41,9 +41,9 @@ class FakeVSyncProvider : public gfx::VSyncProvider {
class FakeSoftwareOutputDevice : public cc::SoftwareOutputDevice {
public:
FakeSoftwareOutputDevice() : vsync_provider_(new FakeVSyncProvider()) {}
- virtual ~FakeSoftwareOutputDevice() {}
+ ~FakeSoftwareOutputDevice() override {}
- virtual gfx::VSyncProvider* GetVSyncProvider() OVERRIDE {
+ gfx::VSyncProvider* GetVSyncProvider() override {
return vsync_provider_.get();
}
@@ -58,10 +58,10 @@ class FakeSoftwareOutputDevice : public cc::SoftwareOutputDevice {
class SoftwareBrowserCompositorOutputSurfaceTest : public testing::Test {
public:
SoftwareBrowserCompositorOutputSurfaceTest();
- virtual ~SoftwareBrowserCompositorOutputSurfaceTest();
+ ~SoftwareBrowserCompositorOutputSurfaceTest() override;
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
+ void SetUp() override;
+ void TearDown() override;
scoped_ptr<content::BrowserCompositorOutputSurface> CreateSurface(
scoped_ptr<cc::SoftwareOutputDevice> device);
@@ -94,7 +94,8 @@ void SoftwareBrowserCompositorOutputSurfaceTest::SetUp() {
ui::InitializeContextFactoryForTests(enable_pixel_output);
compositor_.reset(new ui::Compositor(gfx::kNullAcceleratedWidget,
- context_factory));
+ context_factory,
+ base::MessageLoopProxy::current()));
surface_proxy_ =
new content::BrowserCompositorOutputSurfaceProxy(&surface_map_);
}
@@ -122,20 +123,25 @@ SoftwareBrowserCompositorOutputSurfaceTest::CreateSurface(
}
TEST_F(SoftwareBrowserCompositorOutputSurfaceTest, NoVSyncProvider) {
+ cc::FakeOutputSurfaceClient output_surface_client;
scoped_ptr<cc::SoftwareOutputDevice> software_device(
new cc::SoftwareOutputDevice());
output_surface_ = CreateSurface(software_device.Pass());
+ CHECK(output_surface_->BindToClient(&output_surface_client));
cc::CompositorFrame frame;
output_surface_->SwapBuffers(&frame);
+ EXPECT_EQ(1, output_surface_client.swap_count());
EXPECT_EQ(NULL, output_surface_->software_device()->GetVSyncProvider());
}
TEST_F(SoftwareBrowserCompositorOutputSurfaceTest, VSyncProviderUpdates) {
+ cc::FakeOutputSurfaceClient output_surface_client;
scoped_ptr<cc::SoftwareOutputDevice> software_device(
new FakeSoftwareOutputDevice());
output_surface_ = CreateSurface(software_device.Pass());
+ CHECK(output_surface_->BindToClient(&output_surface_client));
FakeVSyncProvider* vsync_provider = static_cast<FakeVSyncProvider*>(
output_surface_->software_device()->GetVSyncProvider());
@@ -144,5 +150,6 @@ TEST_F(SoftwareBrowserCompositorOutputSurfaceTest, VSyncProviderUpdates) {
cc::CompositorFrame frame;
output_surface_->SwapBuffers(&frame);
+ EXPECT_EQ(1, output_surface_client.swap_count());
EXPECT_EQ(1, vsync_provider->call_count());
}
diff --git a/chromium/content/browser/renderer_host/software_layer_mac.h b/chromium/content/browser/compositor/software_layer_mac.h
index 687070e500e..687070e500e 100644
--- a/chromium/content/browser/renderer_host/software_layer_mac.h
+++ b/chromium/content/browser/compositor/software_layer_mac.h
diff --git a/chromium/content/browser/renderer_host/software_layer_mac.mm b/chromium/content/browser/compositor/software_layer_mac.mm
index 896e3d25595..eb2f03c2547 100644
--- a/chromium/content/browser/renderer_host/software_layer_mac.mm
+++ b/chromium/content/browser/compositor/software_layer_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/renderer_host/software_layer_mac.h"
+#include "content/browser/compositor/software_layer_mac.h"
#include "base/debug/trace_event.h"
#include "base/mac/mac_util.h"
@@ -54,6 +54,8 @@
false,
kCGRenderingIntentDefault));
[self setContents:(id)image.get()];
+ [self setBounds:CGRectMake(
+ 0, 0, pixelSize.width() / scaleFactor, pixelSize.height() / scaleFactor)];
// Set the contents scale of the software CALayer.
if ([self respondsToSelector:(@selector(contentsScale))] &&
diff --git a/chromium/content/browser/compositor/software_output_device_mac.h b/chromium/content/browser/compositor/software_output_device_mac.h
index 8220a3bd14f..4721c61881e 100644
--- a/chromium/content/browser/compositor/software_output_device_mac.h
+++ b/chromium/content/browser/compositor/software_output_device_mac.h
@@ -20,9 +20,9 @@ namespace content {
class SoftwareOutputDeviceMac : public cc::SoftwareOutputDevice {
public:
explicit SoftwareOutputDeviceMac(ui::Compositor* compositor);
- virtual ~SoftwareOutputDeviceMac();
+ ~SoftwareOutputDeviceMac() override;
- virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE;
+ void EndPaint(cc::SoftwareFrameData* frame_data) override;
private:
ui::Compositor* compositor_;
diff --git a/chromium/content/browser/compositor/software_output_device_mac.mm b/chromium/content/browser/compositor/software_output_device_mac.mm
index ab734078f73..6fc3aefb0ec 100644
--- a/chromium/content/browser/compositor/software_output_device_mac.mm
+++ b/chromium/content/browser/compositor/software_output_device_mac.mm
@@ -6,7 +6,7 @@
#include "content/browser/compositor/software_output_device_mac.h"
-#include "content/browser/compositor/browser_compositor_view_mac.h"
+#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h"
#include "ui/compositor/compositor.h"
namespace content {
@@ -20,11 +20,8 @@ SoftwareOutputDeviceMac::~SoftwareOutputDeviceMac() {
void SoftwareOutputDeviceMac::EndPaint(cc::SoftwareFrameData* frame_data) {
SoftwareOutputDevice::EndPaint(frame_data);
-
- NSView* view = compositor_->widget();
- [view gotSoftwareFrame:frame_data
- withScaleFactor:scale_factor_
- withCanvas:canvas_.get()];
+ BrowserCompositorCALayerTreeMacGotSoftwareFrame(
+ compositor_->widget(), frame_data, scale_factor_, canvas_.get());
}
} // namespace content
diff --git a/chromium/content/browser/compositor/software_output_device_ozone.cc b/chromium/content/browser/compositor/software_output_device_ozone.cc
index b97b8b746a2..62d8bce3347 100644
--- a/chromium/content/browser/compositor/software_output_device_ozone.cc
+++ b/chromium/content/browser/compositor/software_output_device_ozone.cc
@@ -16,9 +16,6 @@ SoftwareOutputDeviceOzone::SoftwareOutputDeviceOzone(ui::Compositor* compositor)
: compositor_(compositor) {
ui::SurfaceFactoryOzone* factory = ui::SurfaceFactoryOzone::GetInstance();
- if (factory->InitializeHardware() != ui::SurfaceFactoryOzone::INITIALIZED)
- LOG(FATAL) << "Failed to initialize hardware in OZONE";
-
surface_ozone_ = factory->CreateCanvasForWidget(compositor_->widget());
if (!surface_ozone_)
diff --git a/chromium/content/browser/compositor/software_output_device_ozone.h b/chromium/content/browser/compositor/software_output_device_ozone.h
index 600138ff96e..ef947e16c44 100644
--- a/chromium/content/browser/compositor/software_output_device_ozone.h
+++ b/chromium/content/browser/compositor/software_output_device_ozone.h
@@ -26,9 +26,9 @@ class CONTENT_EXPORT SoftwareOutputDeviceOzone
virtual ~SoftwareOutputDeviceOzone();
virtual void Resize(const gfx::Size& viewport_pixel_size,
- float scale_factor) OVERRIDE;
- virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) OVERRIDE;
- virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE;
+ float scale_factor) override;
+ virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
+ virtual void EndPaint(cc::SoftwareFrameData* frame_data) override;
private:
ui::Compositor* compositor_;
diff --git a/chromium/content/browser/compositor/software_output_device_ozone_unittest.cc b/chromium/content/browser/compositor/software_output_device_ozone_unittest.cc
index a2176a6ffc0..8b720055d8f 100644
--- a/chromium/content/browser/compositor/software_output_device_ozone_unittest.cc
+++ b/chromium/content/browser/compositor/software_output_device_ozone_unittest.cc
@@ -7,6 +7,7 @@
#include "cc/output/software_frame_data.h"
#include "content/browser/compositor/software_output_device_ozone.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkDevice.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/test/context_factories_for_test.h"
@@ -25,15 +26,15 @@ class MockSurfaceOzone : public ui::SurfaceOzoneCanvas {
virtual ~MockSurfaceOzone() {}
// ui::SurfaceOzoneCanvas overrides:
- virtual void ResizeCanvas(const gfx::Size& size) OVERRIDE {
+ virtual void ResizeCanvas(const gfx::Size& size) override {
surface_ = skia::AdoptRef(SkSurface::NewRaster(
SkImageInfo::MakeN32Premul(size.width(), size.height())));
}
- virtual skia::RefPtr<SkCanvas> GetCanvas() OVERRIDE {
+ virtual skia::RefPtr<SkCanvas> GetCanvas() override {
return skia::SharePtr(surface_->getCanvas());
}
- virtual void PresentCanvas(const gfx::Rect& damage) OVERRIDE {}
- virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() OVERRIDE {
+ virtual void PresentCanvas(const gfx::Rect& damage) override {}
+ virtual scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
return scoped_ptr<gfx::VSyncProvider>();
}
@@ -48,19 +49,13 @@ class MockSurfaceFactoryOzone : public ui::SurfaceFactoryOzone {
MockSurfaceFactoryOzone() {}
virtual ~MockSurfaceFactoryOzone() {}
- virtual HardwareState InitializeHardware() OVERRIDE {
- return SurfaceFactoryOzone::INITIALIZED;
- }
-
- virtual void ShutdownHardware() OVERRIDE {}
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE { return 1; }
virtual bool LoadEGLGLES2Bindings(
AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE {
+ SetGLGetProcAddressProcCallback set_gl_get_proc_address) override {
return false;
}
virtual scoped_ptr<ui::SurfaceOzoneCanvas> CreateCanvasForWidget(
- gfx::AcceleratedWidget widget) OVERRIDE {
+ gfx::AcceleratedWidget widget) override {
return make_scoped_ptr<ui::SurfaceOzoneCanvas>(new MockSurfaceOzone());
}
@@ -75,8 +70,8 @@ class SoftwareOutputDeviceOzoneTest : public testing::Test {
SoftwareOutputDeviceOzoneTest();
virtual ~SoftwareOutputDeviceOzoneTest();
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
+ virtual void SetUp() override;
+ virtual void TearDown() override;
protected:
scoped_ptr<content::SoftwareOutputDeviceOzone> output_device_;
@@ -105,9 +100,11 @@ void SoftwareOutputDeviceOzoneTest::SetUp() {
surface_factory_.reset(new MockSurfaceFactoryOzone());
const gfx::Size size(500, 400);
- compositor_.reset(new ui::Compositor(
- ui::SurfaceFactoryOzone::GetInstance()->GetAcceleratedWidget(),
- context_factory));
+ const gfx::AcceleratedWidget kTestAcceleratedWidget = 1;
+ compositor_.reset(
+ new ui::Compositor(kTestAcceleratedWidget,
+ context_factory,
+ base::MessageLoopProxy::current()));
compositor_->SetScaleAndSize(1.0f, size);
output_device_.reset(new content::SoftwareOutputDeviceOzone(
@@ -125,7 +122,7 @@ void SoftwareOutputDeviceOzoneTest::TearDown() {
class SoftwareOutputDeviceOzonePixelTest
: public SoftwareOutputDeviceOzoneTest {
protected:
- virtual void SetUp() OVERRIDE;
+ virtual void SetUp() override;
};
void SoftwareOutputDeviceOzonePixelTest::SetUp() {
diff --git a/chromium/content/browser/compositor/software_output_device_win.h b/chromium/content/browser/compositor/software_output_device_win.h
index 3724f0217f5..85873fb12b6 100644
--- a/chromium/content/browser/compositor/software_output_device_win.h
+++ b/chromium/content/browser/compositor/software_output_device_win.h
@@ -26,10 +26,10 @@ class SoftwareOutputDeviceWin : public cc::SoftwareOutputDevice {
virtual ~SoftwareOutputDeviceWin();
virtual void Resize(const gfx::Size& viewport_pixel_size,
- float scale_factor) OVERRIDE;
- virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) OVERRIDE;
- virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE;
- virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) OVERRIDE;
+ float scale_factor) override;
+ virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
+ virtual void EndPaint(cc::SoftwareFrameData* frame_data) override;
+ virtual void CopyToPixels(const gfx::Rect& rect, void* pixels) override;
private:
HWND hwnd_;
diff --git a/chromium/content/browser/compositor/software_output_device_x11.h b/chromium/content/browser/compositor/software_output_device_x11.h
index 20ae6428e63..88c80a32f6c 100644
--- a/chromium/content/browser/compositor/software_output_device_x11.h
+++ b/chromium/content/browser/compositor/software_output_device_x11.h
@@ -20,9 +20,9 @@ class SoftwareOutputDeviceX11 : public cc::SoftwareOutputDevice {
public:
explicit SoftwareOutputDeviceX11(ui::Compositor* compositor);
- virtual ~SoftwareOutputDeviceX11();
+ ~SoftwareOutputDeviceX11() override;
- virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE;
+ void EndPaint(cc::SoftwareFrameData* frame_data) override;
private:
ui::Compositor* compositor_;
diff --git a/chromium/content/browser/compositor/surface_display_output_surface.cc b/chromium/content/browser/compositor/surface_display_output_surface.cc
index 46c4ad75f95..d3971dadbaa 100644
--- a/chromium/content/browser/compositor/surface_display_output_surface.cc
+++ b/chromium/content/browser/compositor/surface_display_output_surface.cc
@@ -5,44 +5,85 @@
#include "content/browser/compositor/surface_display_output_surface.h"
#include "cc/output/compositor_frame.h"
+#include "cc/output/compositor_frame_ack.h"
#include "cc/surfaces/display.h"
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_manager.h"
+#include "content/browser/compositor/onscreen_display_client.h"
namespace content {
SurfaceDisplayOutputSurface::SurfaceDisplayOutputSurface(
- cc::Display* display,
cc::SurfaceManager* surface_manager,
+ cc::SurfaceIdAllocator* allocator,
const scoped_refptr<cc::ContextProvider>& context_provider)
: cc::OutputSurface(context_provider,
scoped_ptr<cc::SoftwareOutputDevice>()),
- display_(display),
- surface_manager_(surface_manager) {
+ display_client_(NULL),
+ surface_manager_(surface_manager),
+ factory_(surface_manager, this),
+ allocator_(allocator) {
capabilities_.delegated_rendering = true;
capabilities_.max_frames_pending = 1;
}
SurfaceDisplayOutputSurface::~SurfaceDisplayOutputSurface() {
+ client_ = NULL;
+ if (!surface_id_.is_null()) {
+ factory_.Destroy(surface_id_);
+ }
+}
+
+void SurfaceDisplayOutputSurface::ReceivedVSyncParameters(
+ base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ CommitVSyncParameters(timebase, interval);
}
void SurfaceDisplayOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
gfx::Size frame_size =
frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
- display_->Resize(frame_size);
- cc::SurfaceId surface_id = display_->CurrentSurfaceId();
- cc::Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
- if (!surface)
- return;
+ if (frame_size != display_size_) {
+ if (!surface_id_.is_null()) {
+ factory_.Destroy(surface_id_);
+ }
+ surface_id_ = allocator_->GenerateId();
+ factory_.Create(surface_id_, frame_size);
+ display_size_ = frame_size;
+ }
+ display_client_->display()->Resize(
+ surface_id_, frame_size, frame->metadata.device_scale_factor);
scoped_ptr<cc::CompositorFrame> frame_copy(new cc::CompositorFrame());
frame->AssignTo(frame_copy.get());
- surface->QueueFrame(frame_copy.Pass());
-
- if (!display_->Draw())
- return;
+ factory_.SubmitFrame(
+ surface_id_,
+ frame_copy.Pass(),
+ base::Bind(&SurfaceDisplayOutputSurface::SwapBuffersComplete,
+ base::Unretained(this)));
client_->DidSwapBuffers();
+}
+
+bool SurfaceDisplayOutputSurface::BindToClient(
+ cc::OutputSurfaceClient* client) {
+ DCHECK(client);
+ DCHECK(display_client_);
+ client_ = client;
+ // Avoid initializing GL context here, as this should be sharing the
+ // Display's context.
+ return display_client_->Initialize();
+}
+
+void SurfaceDisplayOutputSurface::ReturnResources(
+ const cc::ReturnedResourceArray& resources) {
+ cc::CompositorFrameAck ack;
+ ack.resources = resources;
+ if (client_)
+ client_->ReclaimResources(&ack);
+}
+
+void SurfaceDisplayOutputSurface::SwapBuffersComplete() {
client_->DidSwapBuffersComplete();
}
diff --git a/chromium/content/browser/compositor/surface_display_output_surface.h b/chromium/content/browser/compositor/surface_display_output_surface.h
index 185e0ffc1d2..698b9f5553c 100644
--- a/chromium/content/browser/compositor/surface_display_output_surface.h
+++ b/chromium/content/browser/compositor/surface_display_output_surface.h
@@ -6,6 +6,9 @@
#define CONTENT_BROWSER_COMPOSITOR_SURFACE_DISPLAY_OUTPUT_SURFACE_H_
#include "cc/output/output_surface.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_id_allocator.h"
namespace cc {
class Display;
@@ -13,25 +16,44 @@ class SurfaceManager;
}
namespace content {
+class OnscreenDisplayClient;
// This class is maps a compositor OutputSurface to the surface system's Display
// concept, allowing a compositor client to submit frames for a native root
// window or physical display.
-class SurfaceDisplayOutputSurface : public cc::OutputSurface {
+class SurfaceDisplayOutputSurface : public cc::OutputSurface,
+ public cc::SurfaceFactoryClient {
public:
// The underlying cc::Display and cc::SurfaceManager must outlive this class.
SurfaceDisplayOutputSurface(
- cc::Display* display,
cc::SurfaceManager* surface_manager,
+ cc::SurfaceIdAllocator* allocator,
const scoped_refptr<cc::ContextProvider>& context_provider);
- virtual ~SurfaceDisplayOutputSurface();
+ ~SurfaceDisplayOutputSurface() override;
+
+ void set_display_client(OnscreenDisplayClient* display_client) {
+ display_client_ = display_client;
+ }
+ cc::SurfaceFactory* factory() { return &factory_; }
+ void ReceivedVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval);
// cc::OutputSurface implementation.
- virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE;
+ void SwapBuffers(cc::CompositorFrame* frame) override;
+ bool BindToClient(cc::OutputSurfaceClient* client) override;
+
+ // cc::SurfaceFactoryClient implementation.
+ void ReturnResources(const cc::ReturnedResourceArray& resources) override;
private:
- cc::Display* display_;
+ void SwapBuffersComplete();
+
+ OnscreenDisplayClient* display_client_;
cc::SurfaceManager* surface_manager_;
+ cc::SurfaceFactory factory_;
+ gfx::Size display_size_;
+ cc::SurfaceId surface_id_;
+ cc::SurfaceIdAllocator* allocator_;
DISALLOW_COPY_AND_ASSIGN(SurfaceDisplayOutputSurface);
};
diff --git a/chromium/content/browser/cross_site_request_manager.cc b/chromium/content/browser/cross_site_request_manager.cc
deleted file mode 100644
index 2fa38b185ab..00000000000
--- a/chromium/content/browser/cross_site_request_manager.cc
+++ /dev/null
@@ -1,42 +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 "content/browser/cross_site_request_manager.h"
-
-#include "base/memory/singleton.h"
-
-namespace content {
-
-bool CrossSiteRequestManager::HasPendingCrossSiteRequest(int renderer_id,
- int render_view_id) {
- base::AutoLock lock(lock_);
-
- std::pair<int, int> key(renderer_id, render_view_id);
- return pending_cross_site_views_.find(key) !=
- pending_cross_site_views_.end();
-}
-
-void CrossSiteRequestManager::SetHasPendingCrossSiteRequest(int renderer_id,
- int render_view_id,
- bool has_pending) {
- base::AutoLock lock(lock_);
-
- std::pair<int, int> key(renderer_id, render_view_id);
- if (has_pending) {
- pending_cross_site_views_.insert(key);
- } else {
- pending_cross_site_views_.erase(key);
- }
-}
-
-CrossSiteRequestManager::CrossSiteRequestManager() {}
-
-CrossSiteRequestManager::~CrossSiteRequestManager() {}
-
-// static
-CrossSiteRequestManager* CrossSiteRequestManager::GetInstance() {
- return Singleton<CrossSiteRequestManager>::get();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/cross_site_request_manager.h b/chromium/content/browser/cross_site_request_manager.h
deleted file mode 100644
index 29417d7a868..00000000000
--- a/chromium/content/browser/cross_site_request_manager.h
+++ /dev/null
@@ -1,64 +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_CROSS_SITE_REQUEST_MANAGER_H_
-#define CONTENT_BROWSER_CROSS_SITE_REQUEST_MANAGER_H_
-
-#include <set>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/synchronization/lock.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-namespace content {
-
-// CrossSiteRequestManager is used to handle bookkeeping for cross-site
-// requests and responses between the UI and IO threads. Such requests involve
-// a transition from one RenderViewHost to another within WebContentsImpl, and
-// involve coordination with ResourceDispatcherHost.
-//
-// CrossSiteRequestManager is a singleton that may be used on any thread.
-//
-class CrossSiteRequestManager {
- public:
- // Returns the singleton instance.
- static CrossSiteRequestManager* GetInstance();
-
- // Returns whether the RenderViewHost specified by the given IDs currently
- // has a pending cross-site request. If so, we will have to delay the
- // response until the previous RenderViewHost runs its onunload handler.
- // Called by ResourceDispatcherHost on the IO thread and RenderViewHost on
- // the UI thread.
- bool HasPendingCrossSiteRequest(int renderer_id, int render_view_id);
-
- // Sets whether the RenderViewHost specified by the given IDs currently has a
- // pending cross-site request. Called by RenderViewHost on the UI thread.
- void SetHasPendingCrossSiteRequest(int renderer_id,
- int render_view_id,
- bool has_pending);
-
- private:
- friend struct DefaultSingletonTraits<CrossSiteRequestManager>;
- typedef std::set<std::pair<int, int> > RenderViewSet;
-
- CrossSiteRequestManager();
- ~CrossSiteRequestManager();
-
- // You must acquire this lock before reading or writing any members of this
- // class. You must not block while holding this lock.
- base::Lock lock_;
-
- // Set of (render_process_host_id, render_view_id) pairs of all
- // RenderViewHosts that have pending cross-site requests. Used to pass
- // information about the RenderViewHosts between the UI and IO threads.
- RenderViewSet pending_cross_site_views_;
-
- DISALLOW_COPY_AND_ASSIGN(CrossSiteRequestManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_CROSS_SITE_REQUEST_MANAGER_H_
diff --git a/chromium/content/browser/cross_site_transfer_browsertest.cc b/chromium/content/browser/cross_site_transfer_browsertest.cc
index fff180d72c4..f611030bf9a 100644
--- a/chromium/content/browser/cross_site_transfer_browsertest.cc
+++ b/chromium/content/browser/cross_site_transfer_browsertest.cc
@@ -33,18 +33,14 @@ class TrackingResourceDispatcherHostDelegate
TrackingResourceDispatcherHostDelegate() : throttle_created_(false) {
}
- virtual void RequestBeginning(
- net::URLRequest* request,
- ResourceContext* resource_context,
- appcache::AppCacheService* appcache_service,
- ResourceType::Type resource_type,
- int child_id,
- int route_id,
- ScopedVector<ResourceThrottle>* throttles) OVERRIDE {
+ void RequestBeginning(net::URLRequest* request,
+ ResourceContext* resource_context,
+ AppCacheService* appcache_service,
+ ResourceType resource_type,
+ ScopedVector<ResourceThrottle>* throttles) override {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
ShellResourceDispatcherHostDelegate::RequestBeginning(
- request, resource_context, appcache_service, resource_type, child_id,
- route_id, throttles);
+ request, resource_context, appcache_service, resource_type, throttles);
// Expect only a single request for the tracked url.
ASSERT_FALSE(throttle_created_);
// If this is a request for the tracked URL, add a throttle to track it.
@@ -91,7 +87,7 @@ class TrackingResourceDispatcherHostDelegate
: request_(request), tracker_(tracker) {
}
- virtual ~TrackingThrottle() {
+ ~TrackingThrottle() 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.
@@ -100,7 +96,7 @@ class TrackingResourceDispatcherHostDelegate
}
// ResourceThrottle implementation:
- virtual const char* GetNameForLogging() const OVERRIDE {
+ const char* GetNameForLogging() const override {
return "TrackingThrottle";
}
@@ -147,8 +143,8 @@ class NoTransferRequestDelegate : public WebContentsDelegate {
public:
NoTransferRequestDelegate() {}
- virtual WebContents* OpenURLFromTab(WebContents* source,
- const OpenURLParams& params) OVERRIDE {
+ WebContents* OpenURLFromTab(WebContents* source,
+ const OpenURLParams& params) override {
bool is_transfer =
(params.transferred_global_request_id != GlobalRequestID());
if (is_transfer)
@@ -175,7 +171,7 @@ class CrossSiteTransferTest : public ContentBrowserTest {
}
// ContentBrowserTest implementation:
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(
@@ -183,7 +179,7 @@ class CrossSiteTransferTest : public ContentBrowserTest {
base::Unretained(this)));
}
- virtual void TearDownOnMainThread() OVERRIDE {
+ void TearDownOnMainThread() override {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(
@@ -208,7 +204,7 @@ class CrossSiteTransferTest : public ContentBrowserTest {
load_observer.Wait();
}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
// Use --site-per-process to force process swaps for cross-site transfers.
command_line->AppendSwitch(switches::kSitePerProcess);
}
diff --git a/chromium/content/browser/database_browsertest.cc b/chromium/content/browser/database_browsertest.cc
index d3cc669d256..e38e4173744 100644
--- a/chromium/content/browser/database_browsertest.cc
+++ b/chromium/content/browser/database_browsertest.cc
@@ -14,7 +14,6 @@
#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/net/url_request_mock_http_job.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
diff --git a/chromium/content/browser/database_quota_client_unittest.cc b/chromium/content/browser/database_quota_client_unittest.cc
index 4ac6cb3cb2d..a439b5176d4 100644
--- a/chromium/content/browser/database_quota_client_unittest.cc
+++ b/chromium/content/browser/database_quota_client_unittest.cc
@@ -11,21 +11,21 @@
#include "base/strings/utf_string_conversions.h"
#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
+#include "storage/browser/database/database_quota_client.h"
+#include "storage/browser/database/database_tracker.h"
+#include "storage/browser/database/database_util.h"
+#include "storage/common/database/database_identifier.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/database/database_quota_client.h"
-#include "webkit/browser/database/database_tracker.h"
-#include "webkit/browser/database/database_util.h"
-#include "webkit/common/database/database_identifier.h"
-using webkit_database::DatabaseQuotaClient;
-using webkit_database::DatabaseTracker;
-using webkit_database::OriginInfo;
+using storage::DatabaseQuotaClient;
+using storage::DatabaseTracker;
+using storage::OriginInfo;
namespace content {
// Declared to shorten the line lengths.
-static const quota::StorageType kTemp = quota::kStorageTypeTemporary;
-static const quota::StorageType kPerm = quota::kStorageTypePersistent;
+static const storage::StorageType kTemp = storage::kStorageTypeTemporary;
+static const storage::StorageType kPerm = storage::kStorageTypePersistent;
// Mock tracker class the mocks up those methods of the tracker
// that are used by the QuotaClient.
@@ -36,20 +36,19 @@ class MockDatabaseTracker : public DatabaseTracker {
delete_called_count_(0),
async_delete_(false) {}
- virtual bool GetOriginInfo(
- const std::string& origin_identifier,
- OriginInfo* info) OVERRIDE {
+ bool GetOriginInfo(const std::string& origin_identifier,
+ OriginInfo* info) override {
std::map<GURL, MockOriginInfo>::const_iterator found =
mock_origin_infos_.find(
- webkit_database::GetOriginFromIdentifier(origin_identifier));
+ storage::GetOriginFromIdentifier(origin_identifier));
if (found == mock_origin_infos_.end())
return false;
*info = OriginInfo(found->second);
return true;
}
- virtual bool GetAllOriginIdentifiers(
- std::vector<std::string>* origins_identifiers) OVERRIDE {
+ bool GetAllOriginIdentifiers(
+ std::vector<std::string>* origins_identifiers) override {
std::map<GURL, MockOriginInfo>::const_iterator iter;
for (iter = mock_origin_infos_.begin();
iter != mock_origin_infos_.end();
@@ -59,8 +58,7 @@ class MockDatabaseTracker : public DatabaseTracker {
return true;
}
- virtual bool GetAllOriginsInfo(
- std::vector<OriginInfo>* origins_info) OVERRIDE {
+ bool GetAllOriginsInfo(std::vector<OriginInfo>* origins_info) override {
std::map<GURL, MockOriginInfo>::const_iterator iter;
for (iter = mock_origin_infos_.begin();
iter != mock_origin_infos_.end();
@@ -70,9 +68,8 @@ class MockDatabaseTracker : public DatabaseTracker {
return true;
}
- virtual int DeleteDataForOrigin(
- const std::string& origin_identifier,
- const net::CompletionCallback& callback) OVERRIDE {
+ int DeleteDataForOrigin(const std::string& origin_identifier,
+ const net::CompletionCallback& callback) override {
++delete_called_count_;
if (async_delete()) {
base::MessageLoopProxy::current()->PostTask(
@@ -90,7 +87,7 @@ class MockDatabaseTracker : public DatabaseTracker {
void AddMockDatabase(const GURL& origin, const char* name, int size) {
MockOriginInfo& info = mock_origin_infos_[origin];
- info.set_origin(webkit_database::GetIdentifierFromOrigin(origin));
+ info.set_origin(storage::GetIdentifierFromOrigin(origin));
info.AddMockDatabase(base::ASCIIToUTF16(name), size);
}
@@ -99,7 +96,7 @@ class MockDatabaseTracker : public DatabaseTracker {
void set_async_delete(bool async) { async_delete_ = async; }
protected:
- virtual ~MockDatabaseTracker() {}
+ ~MockDatabaseTracker() override {}
private:
class MockOriginInfo : public OriginInfo {
@@ -137,10 +134,9 @@ class DatabaseQuotaClientTest : public testing::Test {
weak_factory_(this) {
}
- int64 GetOriginUsage(
- quota::QuotaClient* client,
- const GURL& origin,
- quota::StorageType type) {
+ int64 GetOriginUsage(storage::QuotaClient* client,
+ const GURL& origin,
+ storage::StorageType type) {
usage_ = 0;
client->GetOriginUsage(
origin, type,
@@ -150,9 +146,8 @@ class DatabaseQuotaClientTest : public testing::Test {
return usage_;
}
- const std::set<GURL>& GetOriginsForType(
- quota::QuotaClient* client,
- quota::StorageType type) {
+ const std::set<GURL>& GetOriginsForType(storage::QuotaClient* client,
+ storage::StorageType type) {
origins_.clear();
client->GetOriginsForType(
type,
@@ -162,10 +157,9 @@ class DatabaseQuotaClientTest : public testing::Test {
return origins_;
}
- const std::set<GURL>& GetOriginsForHost(
- quota::QuotaClient* client,
- quota::StorageType type,
- const std::string& host) {
+ const std::set<GURL>& GetOriginsForHost(storage::QuotaClient* client,
+ storage::StorageType type,
+ const std::string& host) {
origins_.clear();
client->GetOriginsForHost(
type, host,
@@ -175,17 +169,16 @@ class DatabaseQuotaClientTest : public testing::Test {
return origins_;
}
- bool DeleteOriginData(
- quota::QuotaClient* client,
- quota::StorageType type,
- const GURL& origin) {
- delete_status_ = quota::kQuotaStatusUnknown;
+ bool DeleteOriginData(storage::QuotaClient* client,
+ storage::StorageType type,
+ const GURL& origin) {
+ delete_status_ = storage::kQuotaStatusUnknown;
client->DeleteOriginData(
origin, type,
base::Bind(&DatabaseQuotaClientTest::OnDeleteOriginDataComplete,
weak_factory_.GetWeakPtr()));
base::RunLoop().RunUntilIdle();
- return delete_status_ == quota::kQuotaStatusOk;
+ return delete_status_ == storage::kQuotaStatusOk;
}
MockDatabaseTracker* mock_tracker() { return mock_tracker_.get(); }
@@ -200,14 +193,14 @@ class DatabaseQuotaClientTest : public testing::Test {
origins_ = origins;
}
- void OnDeleteOriginDataComplete(quota::QuotaStatusCode status) {
+ void OnDeleteOriginDataComplete(storage::QuotaStatusCode status) {
delete_status_ = status;
}
base::MessageLoop message_loop_;
int64 usage_;
std::set<GURL> origins_;
- quota::QuotaStatusCode delete_status_;
+ storage::QuotaStatusCode delete_status_;
scoped_refptr<MockDatabaseTracker> mock_tracker_;
base::WeakPtrFactory<DatabaseQuotaClientTest> weak_factory_;
};
diff --git a/chromium/content/browser/database_tracker_unittest.cc b/chromium/content/browser/database_tracker_unittest.cc
index baece0a4bfd..14557de29c8 100644
--- a/chromium/content/browser/database_tracker_unittest.cc
+++ b/chromium/content/browser/database_tracker_unittest.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 "base/file_util.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/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
@@ -14,23 +14,23 @@
#include "content/public/test/mock_special_storage_policy.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
+#include "storage/browser/database/database_tracker.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/database/database_identifier.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h"
-#include "webkit/browser/database/database_tracker.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-#include "webkit/common/database/database_identifier.h"
using base::ASCIIToUTF16;
-using webkit_database::DatabaseConnections;
-using webkit_database::DatabaseTracker;
-using webkit_database::OriginInfo;
+using storage::DatabaseConnections;
+using storage::DatabaseTracker;
+using storage::OriginInfo;
namespace {
const char kOrigin1Url[] = "http://origin1";
const char kOrigin2Url[] = "http://protected_origin2";
-class TestObserver : public webkit_database::DatabaseTracker::Observer {
+class TestObserver : public storage::DatabaseTracker::Observer {
public:
TestObserver()
: new_notification_received_(false),
@@ -43,10 +43,10 @@ class TestObserver : public webkit_database::DatabaseTracker::Observer {
observe_scheduled_deletions_(observe_scheduled_deletions) {
}
- virtual ~TestObserver() {}
- virtual void OnDatabaseSizeChanged(const std::string& origin_identifier,
- const base::string16& database_name,
- int64 database_size) OVERRIDE {
+ ~TestObserver() override {}
+ void OnDatabaseSizeChanged(const std::string& origin_identifier,
+ const base::string16& database_name,
+ int64 database_size) override {
if (!observe_size_changes_)
return;
new_notification_received_ = true;
@@ -54,9 +54,9 @@ class TestObserver : public webkit_database::DatabaseTracker::Observer {
database_name_ = database_name;
database_size_ = database_size;
}
- virtual void OnDatabaseScheduledForDeletion(
+ void OnDatabaseScheduledForDeletion(
const std::string& origin_identifier,
- const base::string16& database_name) OVERRIDE {
+ const base::string16& database_name) override {
if (!observe_scheduled_deletions_)
return;
new_notification_received_ = true;
@@ -96,48 +96,47 @@ void CheckNotificationReceived(TestObserver* observer,
observer->GetNotificationDatabaseSize());
}
-class TestQuotaManagerProxy : public quota::QuotaManagerProxy {
+class TestQuotaManagerProxy : public storage::QuotaManagerProxy {
public:
TestQuotaManagerProxy()
: QuotaManagerProxy(NULL, NULL),
registered_client_(NULL) {
}
- virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {
+ void RegisterClient(storage::QuotaClient* client) override {
EXPECT_FALSE(registered_client_);
registered_client_ = client;
}
- virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type) OVERRIDE {
- EXPECT_EQ(quota::QuotaClient::kDatabase, client_id);
- EXPECT_EQ(quota::kStorageTypeTemporary, type);
+ void NotifyStorageAccessed(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type) override {
+ EXPECT_EQ(storage::QuotaClient::kDatabase, client_id);
+ EXPECT_EQ(storage::kStorageTypeTemporary, type);
accesses_[origin] += 1;
}
- virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type,
- int64 delta) OVERRIDE {
- EXPECT_EQ(quota::QuotaClient::kDatabase, client_id);
- EXPECT_EQ(quota::kStorageTypeTemporary, type);
+ void NotifyStorageModified(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type,
+ int64 delta) override {
+ EXPECT_EQ(storage::QuotaClient::kDatabase, client_id);
+ EXPECT_EQ(storage::kStorageTypeTemporary, type);
modifications_[origin].first += 1;
modifications_[origin].second += delta;
}
// Not needed for our tests.
- virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
- virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
- virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type,
- bool enabled) OVERRIDE {}
- virtual void GetUsageAndQuota(
- base::SequencedTaskRunner* original_task_runner,
- const GURL& origin,
- quota::StorageType type,
- const GetUsageAndQuotaCallback& callback) OVERRIDE {}
+ void NotifyOriginInUse(const GURL& origin) override {}
+ void NotifyOriginNoLongerInUse(const GURL& origin) override {}
+ void SetUsageCacheEnabled(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type,
+ bool enabled) override {}
+ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
+ const GURL& origin,
+ storage::StorageType type,
+ const GetUsageAndQuotaCallback& callback) override {}
void SimulateQuotaManagerDestroyed() {
if (registered_client_) {
@@ -160,7 +159,7 @@ class TestQuotaManagerProxy : public quota::QuotaManagerProxy {
modifications_.clear();
}
- quota::QuotaClient* registered_client_;
+ storage::QuotaClient* registered_client_;
// Map from origin to count of access notifications.
std::map<GURL, int> accesses_;
@@ -169,9 +168,7 @@ class TestQuotaManagerProxy : public quota::QuotaManagerProxy {
std::map<GURL, std::pair<int, int64> > modifications_;
protected:
- virtual ~TestQuotaManagerProxy() {
- EXPECT_FALSE(registered_client_);
- }
+ ~TestQuotaManagerProxy() override { EXPECT_FALSE(registered_client_); }
};
@@ -211,9 +208,9 @@ class DatabaseTracker_TestHelper_Test {
// Create and open three databases.
int64 database_size = 0;
const std::string kOrigin1 =
- webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
+ storage::GetIdentifierFromOrigin(GURL(kOrigin1Url));
const std::string kOrigin2 =
- webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
+ storage::GetIdentifierFromOrigin(GURL(kOrigin2Url));
const base::string16 kDB1 = ASCIIToUTF16("db1");
const base::string16 kDB2 = ASCIIToUTF16("db2");
const base::string16 kDB3 = ASCIIToUTF16("db3");
@@ -325,9 +322,9 @@ class DatabaseTracker_TestHelper_Test {
// Open three new databases.
int64 database_size = 0;
const std::string kOrigin1 =
- webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
+ storage::GetIdentifierFromOrigin(GURL(kOrigin1Url));
const std::string kOrigin2 =
- webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
+ storage::GetIdentifierFromOrigin(GURL(kOrigin2Url));
const base::string16 kDB1 = ASCIIToUTF16("db1");
const base::string16 kDB2 = ASCIIToUTF16("db2");
const base::string16 kDB3 = ASCIIToUTF16("db3");
@@ -452,8 +449,7 @@ class DatabaseTracker_TestHelper_Test {
static void DatabaseTrackerQuotaIntegration() {
const GURL kOrigin(kOrigin1Url);
- const std::string kOriginId =
- webkit_database::GetIdentifierFromOrigin(kOrigin);
+ const std::string kOriginId = storage::GetIdentifierFromOrigin(kOrigin);
const base::string16 kName = ASCIIToUTF16("name");
const base::string16 kDescription = ASCIIToUTF16("description");
@@ -551,9 +547,9 @@ class DatabaseTracker_TestHelper_Test {
static void DatabaseTrackerClearSessionOnlyDatabasesOnExit() {
int64 database_size = 0;
const std::string kOrigin1 =
- webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
+ storage::GetIdentifierFromOrigin(GURL(kOrigin1Url));
const std::string kOrigin2 =
- webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
+ storage::GetIdentifierFromOrigin(GURL(kOrigin2Url));
const base::string16 kDB1 = ASCIIToUTF16("db1");
const base::string16 kDB2 = ASCIIToUTF16("db2");
const base::string16 kDescription = ASCIIToUTF16("database_description");
@@ -631,9 +627,9 @@ class DatabaseTracker_TestHelper_Test {
static void DatabaseTrackerSetForceKeepSessionState() {
int64 database_size = 0;
const std::string kOrigin1 =
- webkit_database::GetIdentifierFromOrigin(GURL(kOrigin1Url));
+ storage::GetIdentifierFromOrigin(GURL(kOrigin1Url));
const std::string kOrigin2 =
- webkit_database::GetIdentifierFromOrigin(GURL(kOrigin2Url));
+ storage::GetIdentifierFromOrigin(GURL(kOrigin2Url));
const base::string16 kDB1 = ASCIIToUTF16("db1");
const base::string16 kDB2 = ASCIIToUTF16("db2");
const base::string16 kDescription = ASCIIToUTF16("database_description");
@@ -708,8 +704,7 @@ class DatabaseTracker_TestHelper_Test {
static void EmptyDatabaseNameIsValid() {
const GURL kOrigin(kOrigin1Url);
- const std::string kOriginId =
- webkit_database::GetIdentifierFromOrigin(kOrigin);
+ const std::string kOriginId = storage::GetIdentifierFromOrigin(kOrigin);
const base::string16 kEmptyName;
const base::string16 kDescription(ASCIIToUTF16("description"));
const base::string16 kChangedDescription(
@@ -757,8 +752,7 @@ class DatabaseTracker_TestHelper_Test {
static void HandleSqliteError() {
const GURL kOrigin(kOrigin1Url);
- const std::string kOriginId =
- webkit_database::GetIdentifierFromOrigin(kOrigin);
+ const std::string kOriginId = storage::GetIdentifierFromOrigin(kOrigin);
const base::string16 kName(ASCIIToUTF16("name"));
const base::string16 kDescription(ASCIIToUTF16("description"));
diff --git a/chromium/content/browser/database_util_unittest.cc b/chromium/content/browser/database_util_unittest.cc
index 23f0a47900d..50d68952b4a 100644
--- a/chromium/content/browser/database_util_unittest.cc
+++ b/chromium/content/browser/database_util_unittest.cc
@@ -4,12 +4,12 @@
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
+#include "storage/browser/database/database_util.h"
+#include "storage/common/database/database_identifier.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/database/database_util.h"
-#include "webkit/common/database/database_identifier.h"
using base::ASCIIToUTF16;
-using webkit_database::DatabaseUtil;
+using storage::DatabaseUtil;
static void TestVfsFilePath(bool expected_result,
const char* vfs_file_name,
@@ -30,8 +30,8 @@ static void TestVfsFilePath(bool expected_result,
}
static GURL ToAndFromOriginIdentifier(const GURL origin_url) {
- std::string id = webkit_database::GetIdentifierFromOrigin(origin_url);
- return webkit_database::GetOriginFromIdentifier(id);
+ std::string id = storage::GetIdentifierFromOrigin(origin_url);
+ return storage::GetOriginFromIdentifier(id);
}
static void TestValidOriginIdentifier(bool expected_result,
diff --git a/chromium/content/browser/databases_table_unittest.cc b/chromium/content/browser/databases_table_unittest.cc
index b82176fe247..ee864cd3a8e 100644
--- a/chromium/content/browser/databases_table_unittest.cc
+++ b/chromium/content/browser/databases_table_unittest.cc
@@ -8,13 +8,13 @@
#include "sql/connection.h"
#include "sql/statement.h"
#include "sql/test/scoped_error_ignorer.h"
+#include "storage/browser/database/databases_table.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h"
-#include "webkit/browser/database/databases_table.h"
using base::ASCIIToUTF16;
-using webkit_database::DatabaseDetails;
-using webkit_database::DatabasesTable;
+using storage::DatabaseDetails;
+using storage::DatabasesTable;
namespace content {
diff --git a/chromium/content/browser/device_monitor_mac.mm b/chromium/content/browser/device_monitor_mac.mm
index eb429afe640..f33c09752ea 100644
--- a/chromium/content/browser/device_monitor_mac.mm
+++ b/chromium/content/browser/device_monitor_mac.mm
@@ -10,10 +10,13 @@
#include "base/bind_helpers.h"
#include "base/logging.h"
+#include "base/mac/bind_objc_block.h"
#include "base/mac/scoped_nsobject.h"
#include "base/threading/thread_checker.h"
#include "content/public/browser/browser_thread.h"
-#import "media/video/capture/mac/avfoundation_glue.h"
+#import "media/base/mac/avfoundation_glue.h"
+
+using content::BrowserThread;
namespace {
@@ -133,9 +136,10 @@ void DeviceMonitorMacImpl::ConsolidateDevicesListAndNotify(
class QTKitMonitorImpl : public DeviceMonitorMacImpl {
public:
explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
- virtual ~QTKitMonitorImpl();
+ ~QTKitMonitorImpl() override;
+
+ void OnDeviceChanged() override;
- virtual void OnDeviceChanged() OVERRIDE;
private:
void CountDevices();
void OnAttributeChanged(NSNotification* notification);
@@ -216,57 +220,131 @@ class SuspendObserverDelegate;
// 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 Device Thread by SuspendedObserverDelegate.
+// destroyed on the UI Thread by SuspendObserverDelegate.
@interface CrAVFoundationDeviceObserver : NSObject {
@private
- SuspendObserverDelegate* receiver_; // weak
+ // 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<CrAVCaptureDevice*> monitoredDevices_;
+ std::set<base::scoped_nsobject<CrAVCaptureDevice> > monitoredDevices_;
}
-- (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver;
-- (void)startObserving:(CrAVCaptureDevice*)device;
+- (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.
-// Provides a callback for this device observer to indicate that there has been
-// a device change of some kind. Created by AVFoundationMonitorImpl in UI thread
-// but living in Device Thread.
+// 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)
- : avfoundation_monitor_impl_(monitor) {
- device_thread_checker_.DetachFromThread();
- }
-
- void OnDeviceChanged();
- void StartObserver();
- void ResetDeviceMonitorOnUIThread();
+ 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() {}
+ virtual ~SuspendObserverDelegate();
- void OnDeviceChangedOnUIThread(
- const std::vector<DeviceInfo>& snapshot_devices);
+ // 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::ThreadChecker device_thread_checker_;
base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
DeviceMonitorMacImpl* avfoundation_monitor_impl_;
};
-void SuspendObserverDelegate::OnDeviceChanged() {
- DCHECK(device_thread_checker_.CalledOnValidThread());
- NSArray* devices = [AVCaptureDeviceGlue devices];
+SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
+ : avfoundation_monitor_impl_(monitor) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void SuspendObserverDelegate::StartObserver(
+ const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
+ DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ avfoundation_monitor_impl_ = NULL;
+ [suspend_observer_ clearOnDeviceChangedCallback];
+}
+
+SuspendObserverDelegate::~SuspendObserverDelegate() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
+ DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::scoped_nsobject<NSArray> auto_release(devices);
std::vector<DeviceInfo> snapshot_devices;
for (CrAVCaptureDevice* device in devices) {
- [suspend_observer_ startObserving:device];
+ 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;
@@ -282,28 +360,7 @@ void SuspendObserverDelegate::OnDeviceChanged() {
snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
device_type));
}
- // Post the consolidation of enumerated devices to be done on UI thread.
- content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
- base::Bind(&SuspendObserverDelegate::OnDeviceChangedOnUIThread,
- this, snapshot_devices));
-}
-void SuspendObserverDelegate::StartObserver() {
- DCHECK(device_thread_checker_.CalledOnValidThread());
- suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
- initWithChangeReceiver:this]);
- for (CrAVCaptureDevice* device in [AVCaptureDeviceGlue devices])
- [suspend_observer_ startObserving:device];
-}
-
-void SuspendObserverDelegate::ResetDeviceMonitorOnUIThread() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- avfoundation_monitor_impl_ = NULL;
-}
-
-void SuspendObserverDelegate::OnDeviceChangedOnUIThread(
- const std::vector<DeviceInfo>& snapshot_devices) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// |avfoundation_monitor_impl_| might have been NULLed asynchronously before
// arriving at this line.
if (avfoundation_monitor_impl_) {
@@ -314,21 +371,18 @@ void SuspendObserverDelegate::OnDeviceChangedOnUIThread(
// AVFoundation implementation of the Mac Device Monitor, registers as a global
// device connect/disconnect observer and plugs suspend/wake up device observers
-// per device. Owns a SuspendObserverDelegate living in |device_task_runner_|
-// and gets notified when a device is suspended/resumed. This class is created
-// and lives in UI thread;
+// 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);
- virtual ~AVFoundationMonitorImpl();
+ ~AVFoundationMonitorImpl() override;
- virtual void OnDeviceChanged() OVERRIDE;
+ void OnDeviceChanged() override;
private:
- base::ThreadChecker thread_checker_;
-
// {Video,AudioInput}DeviceManager's "Device" thread task runner used for
// posting tasks to |suspend_observer_delegate_|; valid after
// MediaStreamManager calls StartMonitoring().
@@ -345,6 +399,7 @@ AVFoundationMonitorImpl::AVFoundationMonitorImpl(
: DeviceMonitorMacImpl(monitor),
device_task_runner_(device_task_runner),
suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
device_arrival_ =
[nc addObserverForName:AVFoundationGlue::
@@ -360,86 +415,97 @@ AVFoundationMonitorImpl::AVFoundationMonitorImpl(
queue:nil
usingBlock:^(NSNotification* notification) {
OnDeviceChanged();}];
- device_task_runner_->PostTask(FROM_HERE,
- base::Bind(&SuspendObserverDelegate::StartObserver,
- suspend_observer_delegate_));
+ suspend_observer_delegate_->StartObserver(device_task_runner_);
}
AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
- DCHECK(thread_checker_.CalledOnValidThread());
- suspend_observer_delegate_->ResetDeviceMonitorOnUIThread();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ suspend_observer_delegate_->ResetDeviceMonitor();
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:device_arrival_];
[nc removeObserver:device_removal_];
}
void AVFoundationMonitorImpl::OnDeviceChanged() {
- DCHECK(thread_checker_.CalledOnValidThread());
- device_task_runner_->PostTask(FROM_HERE,
- base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
- suspend_observer_delegate_));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
}
} // namespace
@implementation CrAVFoundationDeviceObserver
-- (id)initWithChangeReceiver:(SuspendObserverDelegate*)receiver {
+- (id)initWithOnChangedCallback:(const base::Closure&)callback {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if ((self = [super init])) {
- DCHECK(receiver != NULL);
- receiver_ = receiver;
+ DCHECK(!callback.is_null());
+ onDeviceChangedCallback_ = callback;
}
return self;
}
- (void)dealloc {
- std::set<CrAVCaptureDevice*>::iterator it = monitoredDevices_.begin();
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it =
+ monitoredDevices_.begin();
while (it != monitoredDevices_.end())
- [self stopObserving:*it++];
+ [self removeObservers:*(it++)];
[super dealloc];
}
-- (void)startObserving:(CrAVCaptureDevice*)device {
+- (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
+ DCHECK(BrowserThread::CurrentlyOn(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()) {
+ monitoredDevices_.end()) {
return;
}
[device addObserver:self
forKeyPath:@"suspended"
options:0
- context:device];
+ context:device.get()];
[device addObserver:self
forKeyPath:@"connected"
options:0
- context:device];
+ context:device.get()];
monitoredDevices_.insert(device);
}
- (void)stopObserving:(CrAVCaptureDevice*)device {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(device != nil);
- std::set<CrAVCaptureDevice*>::iterator found =
+
+ std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found =
std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device);
DCHECK(found != monitoredDevices_.end());
- // Every so seldom, |device| might be gone when getting here, in that case
- // removing the observer causes a crash. Try to avoid it by checking sanity of
- // the |device| via its -observationInfo. http://crbug.com/371271.
+ [self removeObservers:*found];
+ monitoredDevices_.erase(found);
+}
+
+- (void)clearOnDeviceChangedCallback {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ onDeviceChangedCallback_.Reset();
+}
+
+- (void)removeObservers:(CrAVCaptureDevice*)device {
+ DCHECK(BrowserThread::CurrentlyOn(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"];
}
- monitoredDevices_.erase(found);
}
- (void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if ([keyPath isEqual:@"suspended"])
- receiver_->OnDeviceChanged();
+ onDeviceChangedCallback_.Run();
if ([keyPath isEqual:@"connected"])
[self stopObserving:static_cast<CrAVCaptureDevice*>(context)];
}
diff --git a/chromium/content/browser/device_monitor_udev.h b/chromium/content/browser/device_monitor_udev.h
index b65cfc5a29b..4a879ef5d4d 100644
--- a/chromium/content/browser/device_monitor_udev.h
+++ b/chromium/content/browser/device_monitor_udev.h
@@ -23,13 +23,13 @@ class UdevLinux;
class DeviceMonitorLinux : public base::MessageLoop::DestructionObserver {
public:
DeviceMonitorLinux();
- virtual ~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_.
- virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+ void WillDestroyCurrentMessageLoop() override;
void Initialize();
void OnDevicesChanged(udev_device* device);
diff --git a/chromium/content/browser/device_sensors/OWNERS b/chromium/content/browser/device_sensors/OWNERS
index d523461a382..9bf80a3a416 100644
--- a/chromium/content/browser/device_sensors/OWNERS
+++ b/chromium/content/browser/device_sensors/OWNERS
@@ -1,4 +1,3 @@
hans@chromium.org
-bulach@chromium.org
leandrogracia@chromium.org
timvolodine@chromium.org
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory.h b/chromium/content/browser/device_sensors/data_fetcher_shared_memory.h
index ec6e1a2bfbc..e42f45f9528 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory.h
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory.h
@@ -8,6 +8,7 @@
#include "content/browser/device_sensors/data_fetcher_shared_memory_base.h"
#if !defined(OS_ANDROID)
+#include "content/common/device_sensors/device_light_hardware_buffer.h"
#include "content/common/device_sensors/device_motion_hardware_buffer.h"
#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
#endif
@@ -26,19 +27,20 @@ class CONTENT_EXPORT DataFetcherSharedMemory
public:
DataFetcherSharedMemory();
- virtual ~DataFetcherSharedMemory();
+ ~DataFetcherSharedMemory() override;
private:
- virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE;
- virtual bool Stop(ConsumerType consumer_type) OVERRIDE;
+ bool Start(ConsumerType consumer_type, void* buffer) override;
+ bool Stop(ConsumerType consumer_type) override;
#if !defined(OS_ANDROID)
DeviceMotionHardwareBuffer* motion_buffer_;
DeviceOrientationHardwareBuffer* orientation_buffer_;
+ DeviceLightHardwareBuffer* light_buffer_;
#endif
#if defined(OS_MACOSX)
- virtual void Fetch(unsigned consumer_bitmask) OVERRIDE;
- virtual FetcherType GetType() const OVERRIDE;
+ void Fetch(unsigned consumer_bitmask) override;
+ FetcherType GetType() const override;
scoped_ptr<SuddenMotionSensor> sudden_motion_sensor_;
#elif defined(OS_WIN)
@@ -46,7 +48,7 @@ class CONTENT_EXPORT DataFetcherSharedMemory
class SensorEventSinkMotion;
class SensorEventSinkOrientation;
- virtual FetcherType GetType() const OVERRIDE;
+ virtual FetcherType GetType() const override;
bool RegisterForSensor(REFSENSOR_TYPE_ID sensor_type, ISensor** sensor,
scoped_refptr<SensorEventSink> event_sink);
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_android.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_android.cc
index 2ed5f7fc0f9..477be76585a 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_android.cc
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_android.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "content/browser/device_sensors/sensor_manager_android.h"
+#include "content/common/device_sensors/device_light_hardware_buffer.h"
#include "content/common/device_sensors/device_motion_hardware_buffer.h"
#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
@@ -29,6 +30,9 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
return SensorManagerAndroid::GetInstance()->
StartFetchingDeviceOrientationData(
static_cast<DeviceOrientationHardwareBuffer*>(buffer));
+ case CONSUMER_TYPE_LIGHT:
+ return SensorManagerAndroid::GetInstance()->StartFetchingDeviceLightData(
+ static_cast<DeviceLightHardwareBuffer*>(buffer));
default:
NOTREACHED();
}
@@ -43,6 +47,9 @@ bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
case CONSUMER_TYPE_ORIENTATION:
SensorManagerAndroid::GetInstance()->StopFetchingDeviceOrientationData();
return true;
+ case CONSUMER_TYPE_LIGHT:
+ SensorManagerAndroid::GetInstance()->StopFetchingDeviceLightData();
+ return true;
default:
NOTREACHED();
}
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
index 6a9b7d287d3..d997537c059 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
@@ -9,6 +9,7 @@
#include "base/stl_util.h"
#include "base/threading/thread.h"
#include "base/timer/timer.h"
+#include "content/common/device_sensors/device_light_hardware_buffer.h"
#include "content/common/device_sensors/device_motion_hardware_buffer.h"
#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
@@ -22,6 +23,8 @@ static size_t GetConsumerSharedMemoryBufferSize(ConsumerType consumer_type) {
return sizeof(DeviceMotionHardwareBuffer);
case CONSUMER_TYPE_ORIENTATION:
return sizeof(DeviceOrientationHardwareBuffer);
+ case CONSUMER_TYPE_LIGHT:
+ return sizeof(DeviceLightHardwareBuffer);
default:
NOTREACHED();
}
@@ -33,7 +36,7 @@ static size_t GetConsumerSharedMemoryBufferSize(ConsumerType consumer_type) {
class DataFetcherSharedMemoryBase::PollingThread : public base::Thread {
public:
PollingThread(const char* name, DataFetcherSharedMemoryBase* fetcher);
- virtual ~PollingThread();
+ ~PollingThread() override;
void AddConsumer(ConsumerType consumer_type, void* buffer);
void RemoveConsumer(ConsumerType consumer_type);
@@ -104,8 +107,7 @@ DataFetcherSharedMemoryBase::DataFetcherSharedMemoryBase()
}
DataFetcherSharedMemoryBase::~DataFetcherSharedMemoryBase() {
- StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
- StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
+ DCHECK_EQ(0u, started_consumers_);
// make sure polling thread stops asap.
if (polling_thread_)
@@ -163,6 +165,12 @@ bool DataFetcherSharedMemoryBase::StopFetchingDeviceData(
return true;
}
+void DataFetcherSharedMemoryBase::StopFetchingAllDeviceData() {
+ StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
+ StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
+ StopFetchingDeviceData(CONSUMER_TYPE_LIGHT);
+}
+
base::SharedMemoryHandle
DataFetcherSharedMemoryBase::GetSharedMemoryHandleForProcess(
ConsumerType consumer_type, base::ProcessHandle process) {
@@ -199,7 +207,7 @@ DataFetcherSharedMemoryBase::GetType() const {
}
base::TimeDelta DataFetcherSharedMemoryBase::GetInterval() const {
- return base::TimeDelta::FromMilliseconds(kInertialSensorIntervalMillis);
+ return base::TimeDelta::FromMicroseconds(kInertialSensorIntervalMicroseconds);
}
base::SharedMemory* DataFetcherSharedMemoryBase::GetSharedMemory(
@@ -240,5 +248,4 @@ bool DataFetcherSharedMemoryBase::IsPollingTimerRunningForTesting() const {
return polling_thread_ ? polling_thread_->IsTimerRunning() : false;
}
-
} // namespace content
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.h b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.h
index c959e8254fd..fc1f031d499 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.h
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.h
@@ -31,6 +31,10 @@ class CONTENT_EXPORT DataFetcherSharedMemoryBase {
// relevant sensors could be successfully deactivated.
bool StopFetchingDeviceData(ConsumerType consumer_type);
+ // Should be called before destruction to make sure all active
+ // sensors are unregistered.
+ void StopFetchingAllDeviceData();
+
// Returns the shared memory handle of the device sensor data
// duplicated into the given process. This method should only be
// called after a call to StartFetchingDeviceData method with
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc
index 3a86108b7b5..aa1a9a93153 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc
@@ -8,6 +8,7 @@
#include "base/process/process_handle.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
+#include "content/common/device_sensors/device_light_hardware_buffer.h"
#include "content/common/device_sensors/device_motion_hardware_buffer.h"
#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,16 +20,19 @@ namespace {
class FakeDataFetcher : public DataFetcherSharedMemoryBase {
public:
FakeDataFetcher()
- : start_motion_(false, false),
+ : start_light_(false, false),
+ start_motion_(false, false),
start_orientation_(false, false),
+ stop_light_(false, false),
stop_motion_(false, false),
stop_orientation_(false, false),
+ updated_light_(false, false),
updated_motion_(false, false),
updated_orientation_(false, false),
+ light_buffer_(NULL),
motion_buffer_(NULL),
- orientation_buffer_(NULL) {
- }
- virtual ~FakeDataFetcher() { }
+ orientation_buffer_(NULL) {}
+ ~FakeDataFetcher() override {}
bool Init(ConsumerType consumer_type, void* buffer) {
EXPECT_TRUE(buffer);
@@ -41,17 +45,29 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase {
orientation_buffer_ =
static_cast<DeviceOrientationHardwareBuffer*>(buffer);
break;
+ case CONSUMER_TYPE_LIGHT:
+ light_buffer_ = static_cast<DeviceLightHardwareBuffer*>(buffer);
+ break;
default:
return false;
}
return true;
}
+ void UpdateLight() {
+ DeviceLightHardwareBuffer* buffer = GetLightBuffer();
+ ASSERT_TRUE(buffer);
+ buffer->seqlock.WriteBegin();
+ buffer->data.value = 100;
+ buffer->seqlock.WriteEnd();
+ updated_light_.Signal();
+ }
+
void UpdateMotion() {
DeviceMotionHardwareBuffer* buffer = GetMotionBuffer();
ASSERT_TRUE(buffer);
buffer->seqlock.WriteBegin();
- buffer->data.interval = kInertialSensorIntervalMillis;
+ buffer->data.interval = kInertialSensorIntervalMicroseconds / 1000.;
buffer->seqlock.WriteEnd();
updated_motion_.Signal();
}
@@ -65,6 +81,8 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase {
updated_orientation_.Signal();
}
+ DeviceLightHardwareBuffer* GetLightBuffer() const { return light_buffer_; }
+
DeviceMotionHardwareBuffer* GetMotionBuffer() const {
return motion_buffer_;
}
@@ -81,6 +99,9 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase {
case CONSUMER_TYPE_ORIENTATION:
start_orientation_.Wait();
break;
+ case CONSUMER_TYPE_LIGHT:
+ start_light_.Wait();
+ break;
}
}
@@ -92,6 +113,9 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase {
case CONSUMER_TYPE_ORIENTATION:
stop_orientation_.Wait();
break;
+ case CONSUMER_TYPE_LIGHT:
+ stop_light_.Wait();
+ break;
}
}
@@ -103,18 +127,25 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase {
case CONSUMER_TYPE_ORIENTATION:
updated_orientation_.Wait();
break;
+ case CONSUMER_TYPE_LIGHT:
+ updated_light_.Wait();
+ break;
}
}
protected:
+ base::WaitableEvent start_light_;
base::WaitableEvent start_motion_;
base::WaitableEvent start_orientation_;
+ base::WaitableEvent stop_light_;
base::WaitableEvent stop_motion_;
base::WaitableEvent stop_orientation_;
+ base::WaitableEvent updated_light_;
base::WaitableEvent updated_motion_;
base::WaitableEvent updated_orientation_;
private:
+ DeviceLightHardwareBuffer* light_buffer_;
DeviceMotionHardwareBuffer* motion_buffer_;
DeviceOrientationHardwareBuffer* orientation_buffer_;
@@ -124,9 +155,9 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase {
class FakeNonPollingDataFetcher : public FakeDataFetcher {
public:
FakeNonPollingDataFetcher() { }
- virtual ~FakeNonPollingDataFetcher() { }
+ ~FakeNonPollingDataFetcher() override {}
- virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE {
+ bool Start(ConsumerType consumer_type, void* buffer) override {
Init(consumer_type, buffer);
switch (consumer_type) {
case CONSUMER_TYPE_MOTION:
@@ -137,13 +168,17 @@ class FakeNonPollingDataFetcher : public FakeDataFetcher {
UpdateOrientation();
start_orientation_.Signal();
break;
+ case CONSUMER_TYPE_LIGHT:
+ UpdateLight();
+ start_light_.Signal();
+ break;
default:
return false;
}
return true;
}
- virtual bool Stop(ConsumerType consumer_type) OVERRIDE {
+ bool Stop(ConsumerType consumer_type) override {
switch (consumer_type) {
case CONSUMER_TYPE_MOTION:
stop_motion_.Signal();
@@ -151,20 +186,21 @@ class FakeNonPollingDataFetcher : public FakeDataFetcher {
case CONSUMER_TYPE_ORIENTATION:
stop_orientation_.Signal();
break;
+ case CONSUMER_TYPE_LIGHT:
+ stop_light_.Signal();
+ break;
default:
return false;
}
return true;
}
- virtual void Fetch(unsigned consumer_bitmask) OVERRIDE {
+ void Fetch(unsigned consumer_bitmask) override {
FAIL() << "fetch should not be called, "
<< "because this is a non-polling fetcher";
}
- virtual FetcherType GetType() const OVERRIDE {
- return FakeDataFetcher::GetType();
- }
+ FetcherType GetType() const override { return FakeDataFetcher::GetType(); }
private:
DISALLOW_COPY_AND_ASSIGN(FakeNonPollingDataFetcher);
@@ -173,9 +209,9 @@ class FakeNonPollingDataFetcher : public FakeDataFetcher {
class FakePollingDataFetcher : public FakeDataFetcher {
public:
FakePollingDataFetcher() { }
- virtual ~FakePollingDataFetcher() { }
+ ~FakePollingDataFetcher() override {}
- virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE {
+ bool Start(ConsumerType consumer_type, void* buffer) override {
EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
Init(consumer_type, buffer);
@@ -186,13 +222,16 @@ class FakePollingDataFetcher : public FakeDataFetcher {
case CONSUMER_TYPE_ORIENTATION:
start_orientation_.Signal();
break;
+ case CONSUMER_TYPE_LIGHT:
+ start_light_.Signal();
+ break;
default:
return false;
}
return true;
}
- virtual bool Stop(ConsumerType consumer_type) OVERRIDE {
+ bool Stop(ConsumerType consumer_type) override {
EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
switch (consumer_type) {
@@ -202,26 +241,30 @@ class FakePollingDataFetcher : public FakeDataFetcher {
case CONSUMER_TYPE_ORIENTATION:
stop_orientation_.Signal();
break;
+ case CONSUMER_TYPE_LIGHT:
+ stop_light_.Signal();
+ break;
default:
return false;
}
return true;
}
- virtual void Fetch(unsigned consumer_bitmask) OVERRIDE {
+ void Fetch(unsigned consumer_bitmask) override {
EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
EXPECT_TRUE(consumer_bitmask & CONSUMER_TYPE_ORIENTATION ||
- consumer_bitmask & CONSUMER_TYPE_MOTION);
+ consumer_bitmask & CONSUMER_TYPE_MOTION ||
+ consumer_bitmask & CONSUMER_TYPE_LIGHT);
if (consumer_bitmask & CONSUMER_TYPE_ORIENTATION)
UpdateOrientation();
if (consumer_bitmask & CONSUMER_TYPE_MOTION)
UpdateMotion();
+ if (consumer_bitmask & CONSUMER_TYPE_LIGHT)
+ UpdateLight();
}
- virtual FetcherType GetType() const OVERRIDE {
- return FETCHER_TYPE_POLLING_CALLBACK;
- }
+ FetcherType GetType() const override { return FETCHER_TYPE_POLLING_CALLBACK; }
private:
DISALLOW_COPY_AND_ASSIGN(FakePollingDataFetcher);
@@ -230,9 +273,9 @@ class FakePollingDataFetcher : public FakeDataFetcher {
class FakeZeroDelayPollingDataFetcher : public FakeDataFetcher {
public:
FakeZeroDelayPollingDataFetcher() { }
- virtual ~FakeZeroDelayPollingDataFetcher() { }
+ ~FakeZeroDelayPollingDataFetcher() override {}
- virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE {
+ bool Start(ConsumerType consumer_type, void* buffer) override {
EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
Init(consumer_type, buffer);
@@ -243,13 +286,16 @@ class FakeZeroDelayPollingDataFetcher : public FakeDataFetcher {
case CONSUMER_TYPE_ORIENTATION:
start_orientation_.Signal();
break;
+ case CONSUMER_TYPE_LIGHT:
+ start_light_.Signal();
+ break;
default:
return false;
}
return true;
}
- virtual bool Stop(ConsumerType consumer_type) OVERRIDE {
+ bool Stop(ConsumerType consumer_type) override {
EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
switch (consumer_type) {
@@ -259,19 +305,20 @@ class FakeZeroDelayPollingDataFetcher : public FakeDataFetcher {
case CONSUMER_TYPE_ORIENTATION:
stop_orientation_.Signal();
break;
+ case CONSUMER_TYPE_LIGHT:
+ stop_light_.Signal();
+ break;
default:
return false;
}
return true;
}
- virtual void Fetch(unsigned consumer_bitmask) OVERRIDE {
+ void Fetch(unsigned consumer_bitmask) override {
FAIL() << "fetch should not be called";
}
- virtual FetcherType GetType() const OVERRIDE {
- return FETCHER_TYPE_SEPARATE_THREAD;
- }
+ FetcherType GetType() const override { return FETCHER_TYPE_SEPARATE_THREAD; }
bool IsPollingTimerRunningForTesting() const {
return FakeDataFetcher::IsPollingTimerRunningForTesting();
@@ -290,8 +337,8 @@ TEST(DataFetcherSharedMemoryBaseTest, DoesStartMotion) {
EXPECT_TRUE(fake_data_fetcher.StartFetchingDeviceData(CONSUMER_TYPE_MOTION));
fake_data_fetcher.WaitForStart(CONSUMER_TYPE_MOTION);
- EXPECT_EQ(kInertialSensorIntervalMillis,
- fake_data_fetcher.GetMotionBuffer()->data.interval);
+ EXPECT_EQ(kInertialSensorIntervalMicroseconds / 1000.,
+ fake_data_fetcher.GetMotionBuffer()->data.interval);
fake_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
fake_data_fetcher.WaitForStop(CONSUMER_TYPE_MOTION);
@@ -312,6 +359,20 @@ TEST(DataFetcherSharedMemoryBaseTest, DoesStartOrientation) {
fake_data_fetcher.WaitForStop(CONSUMER_TYPE_ORIENTATION);
}
+TEST(DataFetcherSharedMemoryBaseTest, DoesStartLight) {
+ FakeNonPollingDataFetcher fake_data_fetcher;
+ EXPECT_EQ(DataFetcherSharedMemoryBase::FETCHER_TYPE_DEFAULT,
+ fake_data_fetcher.GetType());
+
+ EXPECT_TRUE(fake_data_fetcher.StartFetchingDeviceData(CONSUMER_TYPE_LIGHT));
+ fake_data_fetcher.WaitForStart(CONSUMER_TYPE_LIGHT);
+
+ EXPECT_EQ(100, fake_data_fetcher.GetLightBuffer()->data.value);
+
+ fake_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_LIGHT);
+ fake_data_fetcher.WaitForStop(CONSUMER_TYPE_LIGHT);
+}
+
TEST(DataFetcherSharedMemoryBaseTest, DoesPollMotion) {
FakePollingDataFetcher fake_data_fetcher;
EXPECT_EQ(DataFetcherSharedMemoryBase::FETCHER_TYPE_POLLING_CALLBACK,
@@ -321,8 +382,8 @@ TEST(DataFetcherSharedMemoryBaseTest, DoesPollMotion) {
fake_data_fetcher.WaitForStart(CONSUMER_TYPE_MOTION);
fake_data_fetcher.WaitForUpdate(CONSUMER_TYPE_MOTION);
- EXPECT_EQ(kInertialSensorIntervalMillis,
- fake_data_fetcher.GetMotionBuffer()->data.interval);
+ EXPECT_EQ(kInertialSensorIntervalMicroseconds / 1000.,
+ fake_data_fetcher.GetMotionBuffer()->data.interval);
fake_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
fake_data_fetcher.WaitForStop(CONSUMER_TYPE_MOTION);
@@ -344,6 +405,21 @@ TEST(DataFetcherSharedMemoryBaseTest, DoesPollOrientation) {
fake_data_fetcher.WaitForStop(CONSUMER_TYPE_ORIENTATION);
}
+TEST(DataFetcherSharedMemoryBaseTest, DoesPollLight) {
+ FakePollingDataFetcher fake_data_fetcher;
+ EXPECT_EQ(DataFetcherSharedMemoryBase::FETCHER_TYPE_POLLING_CALLBACK,
+ fake_data_fetcher.GetType());
+
+ EXPECT_TRUE(fake_data_fetcher.StartFetchingDeviceData(CONSUMER_TYPE_LIGHT));
+ fake_data_fetcher.WaitForStart(CONSUMER_TYPE_LIGHT);
+ fake_data_fetcher.WaitForUpdate(CONSUMER_TYPE_LIGHT);
+
+ EXPECT_EQ(100, fake_data_fetcher.GetLightBuffer()->data.value);
+
+ fake_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_LIGHT);
+ fake_data_fetcher.WaitForStop(CONSUMER_TYPE_LIGHT);
+}
+
TEST(DataFetcherSharedMemoryBaseTest, DoesPollMotionAndOrientation) {
FakePollingDataFetcher fake_data_fetcher;
EXPECT_EQ(DataFetcherSharedMemoryBase::FETCHER_TYPE_POLLING_CALLBACK,
@@ -370,8 +446,8 @@ TEST(DataFetcherSharedMemoryBaseTest, DoesPollMotionAndOrientation) {
fake_data_fetcher.WaitForUpdate(CONSUMER_TYPE_MOTION);
EXPECT_EQ(1, fake_data_fetcher.GetOrientationBuffer()->data.alpha);
- EXPECT_EQ(kInertialSensorIntervalMillis,
- fake_data_fetcher.GetMotionBuffer()->data.interval);
+ EXPECT_EQ(kInertialSensorIntervalMicroseconds / 1000.,
+ fake_data_fetcher.GetMotionBuffer()->data.interval);
fake_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
fake_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_default.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_default.cc
index 457fd8d5b47..5294e8ee5db 100644
--- a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_default.cc
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_default.cc
@@ -29,12 +29,22 @@ static bool SetOrientationBuffer(
return true;
}
+static bool SetLightBuffer(content::DeviceLightHardwareBuffer* buffer,
+ double lux) {
+ if (!buffer)
+ return false;
+ buffer->seqlock.WriteBegin();
+ buffer->data.value = lux;
+ buffer->seqlock.WriteEnd();
+ return true;
+}
+
} // namespace
namespace content {
DataFetcherSharedMemory::DataFetcherSharedMemory()
- : motion_buffer_(NULL), orientation_buffer_(NULL) {
+ : motion_buffer_(NULL), orientation_buffer_(NULL), light_buffer_(NULL) {
}
DataFetcherSharedMemory::~DataFetcherSharedMemory() {
@@ -54,6 +64,10 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
UMA_HISTOGRAM_BOOLEAN("InertialSensor.OrientationDefaultAvailable",
false);
return SetOrientationBuffer(orientation_buffer_, true);
+ case CONSUMER_TYPE_LIGHT:
+ light_buffer_ = static_cast<DeviceLightHardwareBuffer*>(buffer);
+ return SetLightBuffer(light_buffer_,
+ std::numeric_limits<double>::infinity());
default:
NOTREACHED();
}
@@ -66,6 +80,8 @@ bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
return SetMotionBuffer(motion_buffer_, false);
case CONSUMER_TYPE_ORIENTATION:
return SetOrientationBuffer(orientation_buffer_, false);
+ case CONSUMER_TYPE_LIGHT:
+ return SetLightBuffer(light_buffer_, -1);
default:
NOTREACHED();
}
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 96f4a14215e..c537e032551 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
@@ -30,15 +30,15 @@ class DataFetcherSharedMemory::SensorEventSink
virtual ~SensorEventSink() {}
// IUnknown interface
- virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE {
+ virtual ULONG STDMETHODCALLTYPE AddRef() override {
return IUnknownImpl::AddRef();
}
- virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE {
+ virtual ULONG STDMETHODCALLTYPE Release() override {
return IUnknownImpl::Release();
}
- virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) OVERRIDE {
+ virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override {
if (riid == __uuidof(ISensorEvents)) {
*ppv = static_cast<ISensorEvents*>(this);
AddRef();
@@ -50,20 +50,20 @@ class DataFetcherSharedMemory::SensorEventSink
// ISensorEvents interface
STDMETHODIMP OnEvent(ISensor* sensor,
REFGUID event_id,
- IPortableDeviceValues* event_data) OVERRIDE {
+ IPortableDeviceValues* event_data) override {
return S_OK;
}
- STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) OVERRIDE {
+ STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) override {
return S_OK;
}
- STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) OVERRIDE {
+ STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) override {
return S_OK;
}
STDMETHODIMP OnDataUpdated(ISensor* sensor,
- ISensorDataReport* new_data) OVERRIDE {
+ ISensorDataReport* new_data) override {
if (NULL == new_data || NULL == sensor)
return E_INVALIDARG;
return UpdateSharedMemoryBuffer(sensor, new_data) ? S_OK : E_FAIL;
@@ -102,7 +102,7 @@ class DataFetcherSharedMemory::SensorEventSinkOrientation
protected:
virtual bool UpdateSharedMemoryBuffer(
- ISensor* sensor, ISensorDataReport* new_data) OVERRIDE {
+ ISensor* sensor, ISensorDataReport* new_data) override {
double alpha, beta, gamma;
bool has_alpha, has_beta, has_gamma;
@@ -145,7 +145,7 @@ class DataFetcherSharedMemory::SensorEventSinkMotion
protected:
virtual bool UpdateSharedMemoryBuffer(
- ISensor* sensor, ISensorDataReport* new_data) OVERRIDE {
+ ISensor* sensor, ISensorDataReport* new_data) override {
SENSOR_TYPE_ID sensor_type = GUID_NULL;
if (!SUCCEEDED(sensor->GetType(&sensor_type)))
diff --git a/chromium/content/browser/device_sensors/device_inertial_sensor_browsertest.cc b/chromium/content/browser/device_sensors/device_inertial_sensor_browsertest.cc
index ff65895e5ac..3380d8a2e74 100644
--- a/chromium/content/browser/device_sensors/device_inertial_sensor_browsertest.cc
+++ b/chromium/content/browser/device_sensors/device_inertial_sensor_browsertest.cc
@@ -7,6 +7,7 @@
#include "base/threading/platform_thread.h"
#include "content/browser/device_sensors/data_fetcher_shared_memory.h"
#include "content/browser/device_sensors/device_inertial_sensor_service.h"
+#include "content/common/device_sensors/device_light_hardware_buffer.h"
#include "content/common/device_sensors/device_motion_hardware_buffer.h"
#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
#include "content/public/browser/browser_thread.h"
@@ -30,11 +31,12 @@ class FakeDataFetcher : public DataFetcherSharedMemory {
stopped_orientation_(false, false),
started_motion_(false, false),
stopped_motion_(false, false),
- sensor_data_available_(true) {
- }
- virtual ~FakeDataFetcher() { }
+ started_light_(false, false),
+ stopped_light_(false, false),
+ sensor_data_available_(true) {}
+ ~FakeDataFetcher() override {}
- virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE {
+ bool Start(ConsumerType consumer_type, void* buffer) override {
EXPECT_TRUE(buffer);
switch (consumer_type) {
@@ -58,13 +60,24 @@ class FakeDataFetcher : public DataFetcherSharedMemory {
started_orientation_.Signal();
}
break;
+ case CONSUMER_TYPE_LIGHT:
+ {
+ DeviceLightHardwareBuffer* light_buffer =
+ static_cast<DeviceLightHardwareBuffer*>(buffer);
+ UpdateLight(light_buffer,
+ sensor_data_available_
+ ? 100
+ : std::numeric_limits<double>::infinity());
+ started_light_.Signal();
+ }
+ break;
default:
return false;
}
return true;
}
- virtual bool Stop(ConsumerType consumer_type) OVERRIDE {
+ bool Stop(ConsumerType consumer_type) override {
switch (consumer_type) {
case CONSUMER_TYPE_MOTION:
stopped_motion_.Signal();
@@ -72,19 +85,20 @@ class FakeDataFetcher : public DataFetcherSharedMemory {
case CONSUMER_TYPE_ORIENTATION:
stopped_orientation_.Signal();
break;
+ case CONSUMER_TYPE_LIGHT:
+ stopped_light_.Signal();
+ break;
default:
return false;
}
return true;
}
- virtual void Fetch(unsigned consumer_bitmask) OVERRIDE {
+ void Fetch(unsigned consumer_bitmask) override {
FAIL() << "fetch should not be called";
}
- virtual FetcherType GetType() const OVERRIDE {
- return FETCHER_TYPE_DEFAULT;
- }
+ FetcherType GetType() const override { return FETCHER_TYPE_DEFAULT; }
void SetSensorDataAvailable(bool available) {
sensor_data_available_ = available;
@@ -142,10 +156,18 @@ class FakeDataFetcher : public DataFetcherSharedMemory {
buffer->seqlock.WriteEnd();
}
+ void UpdateLight(DeviceLightHardwareBuffer* buffer, double lux) {
+ buffer->seqlock.WriteBegin();
+ buffer->data.value = lux;
+ buffer->seqlock.WriteEnd();
+ }
+
base::WaitableEvent started_orientation_;
base::WaitableEvent stopped_orientation_;
base::WaitableEvent started_motion_;
base::WaitableEvent stopped_motion_;
+ base::WaitableEvent started_light_;
+ base::WaitableEvent stopped_light_;
bool sensor_data_available_;
private:
@@ -160,7 +182,7 @@ class DeviceInertialSensorBrowserTest : public ContentBrowserTest {
io_loop_finished_event_(false, false) {
}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&DeviceInertialSensorBrowserTest::SetUpOnIOThread, this));
@@ -197,13 +219,11 @@ class DeviceInertialSensorBrowserTest : public ContentBrowserTest {
base::WaitableEvent io_loop_finished_event_;
};
-
IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, OrientationTest) {
// The test page will register an event handler for orientation events,
// expects to get an event with fake values, then removes the event
// handler and navigates to #pass.
- GURL test_url = GetTestUrl(
- "device_orientation", "device_orientation_test.html");
+ GURL test_url = GetTestUrl("device_sensors", "device_orientation_test.html");
NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
@@ -211,12 +231,31 @@ IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, OrientationTest) {
fetcher_->stopped_orientation_.Wait();
}
+IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, LightTest) {
+ // The test page will register an event handler for light events,
+ // expects to get an event with fake values, then removes the event
+ // handler and navigates to #pass.
+ GURL test_url = GetTestUrl("device_sensors", "device_light_test.html");
+
+ // TODO(riju): remove command line args when the feature goes stable.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures)) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+ }
+
+ NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
+
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+ fetcher_->started_light_.Wait();
+ fetcher_->stopped_light_.Wait();
+}
+
IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, MotionTest) {
// The test page will register an event handler for motion events,
// expects to get an event with fake values, then removes the event
// handler and navigates to #pass.
- GURL test_url = GetTestUrl(
- "device_orientation", "device_motion_test.html");
+ GURL test_url = GetTestUrl("device_sensors", "device_motion_test.html");
NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
@@ -224,6 +263,36 @@ IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, MotionTest) {
fetcher_->stopped_motion_.Wait();
}
+// crbug/416406. The test is flaky.
+IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
+ DISABLED_LightOneOffInfintyTest) {
+ // The test page will register an event handler for light events,
+ // expects to get an event with value equal to Infinity. This tests that the
+ // one-off infinity event still propagates to window after the alert is
+ // dismissed and the callback is invoked which navigates to #pass.
+ fetcher_->SetSensorDataAvailable(false);
+
+ // TODO(riju): remove command line args when the feature goes stable.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures)) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+ }
+
+ TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
+
+ GURL test_url =
+ GetTestUrl("device_sensors", "device_light_infinity_test.html");
+ shell()->LoadURL(test_url);
+
+ WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000));
+
+ fetcher_->started_light_.Wait();
+ fetcher_->stopped_light_.Wait();
+ same_tab_observer.Wait();
+ EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
+}
+
// Flaking in the android try bot. See http://crbug.com/360578.
#if defined(OS_ANDROID)
#define MAYBE_OrientationNullTestWithAlert DISABLED_OrientationNullTestWithAlert
@@ -240,8 +309,8 @@ IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
fetcher_->SetSensorDataAvailable(false);
TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
- GURL test_url = GetTestUrl(
- "device_orientation", "device_orientation_null_test_with_alert.html");
+ GURL test_url = GetTestUrl("device_sensors",
+ "device_orientation_null_test_with_alert.html");
shell()->LoadURL(test_url);
// TODO(timvolodine): investigate if it is possible to test this without
@@ -255,7 +324,7 @@ IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
}
// Flaking in the android try bot. See http://crbug.com/360578.
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_WIN)
#define MAYBE_MotionNullTestWithAlert DISABLED_MotionNullTestWithAlert
#else
#define MAYBE_MotionNullTestWithAlert MotionNullTestWithAlert
@@ -270,8 +339,8 @@ IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
fetcher_->SetSensorDataAvailable(false);
TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
- GURL test_url = GetTestUrl(
- "device_orientation", "device_motion_null_test_with_alert.html");
+ GURL test_url =
+ GetTestUrl("device_sensors", "device_motion_null_test_with_alert.html");
shell()->LoadURL(test_url);
// TODO(timvolodine): investigate if it is possible to test this without
diff --git a/chromium/content/browser/device_sensors/device_inertial_sensor_service.cc b/chromium/content/browser/device_sensors/device_inertial_sensor_service.cc
index cf96820649e..840ce254bc1 100644
--- a/chromium/content/browser/device_sensors/device_inertial_sensor_service.cc
+++ b/chromium/content/browser/device_sensors/device_inertial_sensor_service.cc
@@ -12,7 +12,8 @@
namespace content {
DeviceInertialSensorService::DeviceInertialSensorService()
- : num_motion_readers_(0),
+ : num_light_readers_(0),
+ num_motion_readers_(0),
num_orientation_readers_(0),
is_shutdown_(false) {
}
@@ -59,6 +60,10 @@ bool DeviceInertialSensorService::ChangeNumberConsumers(
num_orientation_readers_ += delta;
DCHECK_GE(num_orientation_readers_ , 0);
return true;
+ case CONSUMER_TYPE_LIGHT:
+ num_light_readers_ += delta;
+ DCHECK_GE(num_light_readers_, 0);
+ return true;
default:
NOTREACHED();
}
@@ -72,6 +77,8 @@ int DeviceInertialSensorService::GetNumberConsumers(
return num_motion_readers_;
case CONSUMER_TYPE_ORIENTATION:
return num_orientation_readers_;
+ case CONSUMER_TYPE_LIGHT:
+ return num_light_readers_;
default:
NOTREACHED();
}
@@ -86,12 +93,17 @@ DeviceInertialSensorService::GetSharedMemoryHandleForProcess(
}
void DeviceInertialSensorService::Shutdown() {
- data_fetcher_.reset();
+ if (data_fetcher_) {
+ data_fetcher_->StopFetchingAllDeviceData();
+ data_fetcher_.reset();
+ }
is_shutdown_ = true;
}
void DeviceInertialSensorService::SetDataFetcherForTesting(
DataFetcherSharedMemory* test_data_fetcher) {
+ if (data_fetcher_)
+ data_fetcher_->StopFetchingAllDeviceData();
data_fetcher_.reset(test_data_fetcher);
}
diff --git a/chromium/content/browser/device_sensors/device_inertial_sensor_service.h b/chromium/content/browser/device_sensors/device_inertial_sensor_service.h
index 1d8cfd14497..c372903ad30 100644
--- a/chromium/content/browser/device_sensors/device_inertial_sensor_service.h
+++ b/chromium/content/browser/device_sensors/device_inertial_sensor_service.h
@@ -57,6 +57,7 @@ class CONTENT_EXPORT DeviceInertialSensorService {
int delta);
int GetNumberConsumers(ConsumerType consumer_type) const;
+ int num_light_readers_;
int num_motion_readers_;
int num_orientation_readers_;
bool is_shutdown_;
diff --git a/chromium/content/browser/device_sensors/device_light_message_filter.cc b/chromium/content/browser/device_sensors/device_light_message_filter.cc
new file mode 100644
index 00000000000..751b6f11ce3
--- /dev/null
+++ b/chromium/content/browser/device_sensors/device_light_message_filter.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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) {
+}
+
+DeviceLightMessageFilter::~DeviceLightMessageFilter() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (is_started_) {
+ DeviceInertialSensorService::GetInstance()->RemoveConsumer(
+ CONSUMER_TYPE_LIGHT);
+ }
+}
+
+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_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())));
+}
+
+} // 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
new file mode 100644
index 00000000000..eb10bbfab24
--- /dev/null
+++ b/chromium/content/browser/device_sensors/device_light_message_filter.h
@@ -0,0 +1,33 @@
+// 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_DEVICE_SENSORS_DEVICE_LIGHT_MESSAGE_FILTER_H_
+#define CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_LIGHT_MESSAGE_FILTER_H_
+
+#include "content/public/browser/browser_message_filter.h"
+
+namespace content {
+
+class DeviceLightMessageFilter : public BrowserMessageFilter {
+ public:
+ DeviceLightMessageFilter();
+
+ // BrowserMessageFilter implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ private:
+ ~DeviceLightMessageFilter() override;
+
+ void OnDeviceLightStartPolling();
+ void OnDeviceLightStopPolling();
+ void DidStartDeviceLightPolling();
+
+ bool is_started_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceLightMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVICE_SENSORS_DEVICE_LIGHT_MESSAGE_FILTER_H_
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 cd4859472d5..ffe9ff76c9b 100644
--- a/chromium/content/browser/device_sensors/device_motion_message_filter.h
+++ b/chromium/content/browser/device_sensors/device_motion_message_filter.h
@@ -14,10 +14,10 @@ class DeviceMotionMessageFilter : public BrowserMessageFilter {
DeviceMotionMessageFilter();
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
- virtual ~DeviceMotionMessageFilter();
+ ~DeviceMotionMessageFilter() override;
void OnDeviceMotionStartPolling();
void OnDeviceMotionStopPolling();
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 56893c83a16..acc772d48e5 100644
--- a/chromium/content/browser/device_sensors/device_orientation_message_filter.h
+++ b/chromium/content/browser/device_sensors/device_orientation_message_filter.h
@@ -14,10 +14,10 @@ class DeviceOrientationMessageFilter : public BrowserMessageFilter {
DeviceOrientationMessageFilter();
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
- virtual ~DeviceOrientationMessageFilter();
+ ~DeviceOrientationMessageFilter() override;
void OnDeviceOrientationStartPolling();
void OnDeviceOrientationStopPolling();
diff --git a/chromium/content/browser/device_sensors/inertial_sensor_consts.h b/chromium/content/browser/device_sensors/inertial_sensor_consts.h
index 6ca6a98e96a..1f665bdbb5d 100644
--- a/chromium/content/browser/device_sensors/inertial_sensor_consts.h
+++ b/chromium/content/browser/device_sensors/inertial_sensor_consts.h
@@ -5,20 +5,31 @@
#ifndef CONTENT_BROWSER_DEVICE_SENSORS_INERTIAL_SENSOR_CONSTS_H_
#define CONTENT_BROWSER_DEVICE_SENSORS_INERTIAL_SENSOR_CONSTS_H_
+#include "base/time/time.h"
+
namespace content {
-// Constants related to the Device Motion/Device Orientation APIs.
+// Constants related to the Device {Motion|Orientation|Light} APIs.
enum ConsumerType {
CONSUMER_TYPE_MOTION = 1 << 0,
CONSUMER_TYPE_ORIENTATION = 1 << 1,
+ CONSUMER_TYPE_LIGHT = 1 << 2,
};
-// Specifies the minimal interval between subsequent sensor data updates.
+// Specifies the sampling rate for sensor data updates.
// Note that when changing this value it is desirable to have an adequate
-// matching value |DeviceSensorEventPump::kDefaultPumpDelayMillis| in
+// matching value |DeviceSensorEventPump::kDefaultPumpFrequencyHz| in
// content/renderer/device_orientation/device_sensor_event_pump.cc.
-const int kInertialSensorIntervalMillis = 50;
+const int kInertialSensorSamplingRateHz = 60;
+const int kInertialSensorIntervalMicroseconds =
+ base::Time::kMicrosecondsPerSecond / kInertialSensorSamplingRateHz;
+
+// Corresponding |kDefaultLightPumpFrequencyHz| is in
+// content/renderer/device_sensors/device_light_event_pump.cc.
+const int kLightSensorSamplingRateHz = 5;
+const int kLightSensorIntervalMicroseconds =
+ base::Time::kMicrosecondsPerSecond / kLightSensorSamplingRateHz;
} // namespace content
diff --git a/chromium/content/browser/device_sensors/sensor_manager_android.cc b/chromium/content/browser/device_sensors/sensor_manager_android.cc
index 400adfa355b..11de85ae68c 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_android.cc
+++ b/chromium/content/browser/device_sensors/sensor_manager_android.cc
@@ -26,15 +26,16 @@ namespace content {
SensorManagerAndroid::SensorManagerAndroid()
: number_active_device_motion_sensors_(0),
+ device_light_buffer_(NULL),
device_motion_buffer_(NULL),
device_orientation_buffer_(NULL),
+ is_light_buffer_ready_(false),
is_motion_buffer_ready_(false),
- is_orientation_buffer_ready_(false) {
+ is_orientation_buffer_ready_(false),
+ is_using_backup_sensors_for_orientation_(false) {
memset(received_motion_data_, 0, sizeof(received_motion_data_));
- device_orientation_.Reset(
- Java_DeviceSensors_getInstance(
- AttachCurrentThread(),
- base::android::GetApplicationContext()));
+ device_sensors_.Reset(Java_DeviceSensors_getInstance(
+ AttachCurrentThread(), base::android::GetApplicationContext()));
}
SensorManagerAndroid::~SensorManagerAndroid() {
@@ -67,7 +68,7 @@ void SensorManagerAndroid::GotOrientation(
if (!is_orientation_buffer_ready_) {
SetOrientationBufferReadyStatus(true);
- updateRotationVectorHistogram(true);
+ updateRotationVectorHistogram(!is_using_backup_sensors_for_orientation_);
}
}
@@ -137,30 +138,84 @@ void SensorManagerAndroid::GotRotationRate(
}
}
+void SensorManagerAndroid::GotLight(JNIEnv*, jobject, double value) {
+ base::AutoLock autolock(light_buffer_lock_);
+
+ if (!device_light_buffer_)
+ return;
+
+ device_light_buffer_->seqlock.WriteBegin();
+ device_light_buffer_->data.value = value;
+ device_light_buffer_->seqlock.WriteEnd();
+}
+
bool SensorManagerAndroid::Start(EventType event_type) {
- DCHECK(!device_orientation_.is_null());
- return Java_DeviceSensors_start(
- AttachCurrentThread(), device_orientation_.obj(),
- reinterpret_cast<intptr_t>(this), static_cast<jint>(event_type),
- kInertialSensorIntervalMillis);
+ DCHECK(!device_sensors_.is_null());
+ int rate_in_microseconds = (event_type == kTypeLight)
+ ? kLightSensorIntervalMicroseconds
+ : kInertialSensorIntervalMicroseconds;
+ return Java_DeviceSensors_start(AttachCurrentThread(),
+ device_sensors_.obj(),
+ reinterpret_cast<intptr_t>(this),
+ static_cast<jint>(event_type),
+ rate_in_microseconds);
}
void SensorManagerAndroid::Stop(EventType event_type) {
- DCHECK(!device_orientation_.is_null());
- Java_DeviceSensors_stop(
- AttachCurrentThread(), device_orientation_.obj(),
- static_cast<jint>(event_type));
+ DCHECK(!device_sensors_.is_null());
+ Java_DeviceSensors_stop(AttachCurrentThread(),
+ device_sensors_.obj(),
+ static_cast<jint>(event_type));
}
int SensorManagerAndroid::GetNumberActiveDeviceMotionSensors() {
- DCHECK(!device_orientation_.is_null());
+ DCHECK(!device_sensors_.is_null());
return Java_DeviceSensors_getNumberActiveDeviceMotionSensors(
- AttachCurrentThread(), device_orientation_.obj());
+ AttachCurrentThread(), device_sensors_.obj());
}
+bool SensorManagerAndroid::isUsingBackupSensorsForOrientation() {
+ DCHECK(!device_sensors_.is_null());
+ return Java_DeviceSensors_isUsingBackupSensorsForOrientation(
+ AttachCurrentThread(), device_sensors_.obj());
+}
// ----- Shared memory API methods
+// --- Device Light
+
+bool SensorManagerAndroid::StartFetchingDeviceLightData(
+ DeviceLightHardwareBuffer* buffer) {
+ DCHECK(buffer);
+ {
+ base::AutoLock autolock(light_buffer_lock_);
+ device_light_buffer_ = buffer;
+ SetLightBufferValue(-1);
+ }
+ bool success = Start(kTypeLight);
+ if (!success) {
+ base::AutoLock autolock(light_buffer_lock_);
+ SetLightBufferValue(std::numeric_limits<double>::infinity());
+ }
+ return success;
+}
+
+void SensorManagerAndroid::StopFetchingDeviceLightData() {
+ Stop(kTypeLight);
+ {
+ base::AutoLock autolock(light_buffer_lock_);
+ if (device_light_buffer_) {
+ SetLightBufferValue(-1);
+ device_light_buffer_ = NULL;
+ }
+ }
+}
+
+void SensorManagerAndroid::SetLightBufferValue(double lux) {
+ device_light_buffer_->seqlock.WriteBegin();
+ device_light_buffer_->data.value = lux;
+ device_light_buffer_->seqlock.WriteEnd();
+}
// --- Device Motion
bool SensorManagerAndroid::StartFetchingDeviceMotionData(
@@ -201,7 +256,8 @@ void SensorManagerAndroid::CheckMotionBufferReadyToRead() {
received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] ==
number_active_device_motion_sensors_) {
device_motion_buffer_->seqlock.WriteBegin();
- device_motion_buffer_->data.interval = kInertialSensorIntervalMillis;
+ device_motion_buffer_->data.interval =
+ kInertialSensorIntervalMicroseconds / 1000.;
device_motion_buffer_->seqlock.WriteEnd();
SetMotionBufferReadyStatus(true);
@@ -258,6 +314,9 @@ bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
if (!success)
updateRotationVectorHistogram(false);
+ else
+ is_using_backup_sensors_for_orientation_ =
+ isUsingBackupSensorsForOrientation();
return success;
}
diff --git a/chromium/content/browser/device_sensors/sensor_manager_android.h b/chromium/content/browser/device_sensors/sensor_manager_android.h
index f2a552ecf5c..714b8ec0416 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_android.h
+++ b/chromium/content/browser/device_sensors/sensor_manager_android.h
@@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
+#include "content/common/device_sensors/device_light_hardware_buffer.h"
#include "content/common/device_sensors/device_motion_hardware_buffer.h"
#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
@@ -16,7 +17,7 @@ template<typename T> struct DefaultSingletonTraits;
namespace content {
-// Android implementation of Device Orientation API.
+// Android implementation of Device {Motion|Orientation|Light} API.
//
// Android's SensorManager has a push API, so when Got*() methods are called
// by the system the browser process puts the received data into a shared
@@ -30,6 +31,7 @@ class CONTENT_EXPORT SensorManagerAndroid {
static SensorManagerAndroid* GetInstance();
// Called from Java via JNI.
+ void GotLight(JNIEnv*, jobject, double value);
void GotOrientation(JNIEnv*, jobject,
double alpha, double beta, double gamma);
void GotAcceleration(JNIEnv*, jobject,
@@ -40,6 +42,9 @@ class CONTENT_EXPORT SensorManagerAndroid {
double alpha, double beta, double gamma);
// Shared memory related methods.
+ bool StartFetchingDeviceLightData(DeviceLightHardwareBuffer* buffer);
+ void StopFetchingDeviceLightData();
+
bool StartFetchingDeviceMotionData(DeviceMotionHardwareBuffer* buffer);
void StopFetchingDeviceMotionData();
@@ -49,11 +54,12 @@ class CONTENT_EXPORT SensorManagerAndroid {
protected:
enum EventType {
- // These constants should match DEVICE_ORIENTATION and DEVICE_MOTION
- // constants in content/public/android/java/src/org/chromium/content/
- // browser/DeviceMotionAndOrientation.java
+ // These constants should match DEVICE_ORIENTATION, DEVICE_MOTION and
+ // DEVICE_LIGHT constants in content/public/android/java/src/org/
+ // chromium/content/browser/DeviceSensors.java
kTypeOrientation = 0,
- kTypeMotion = 1
+ kTypeMotion = 1,
+ kTypeLight = 2
};
SensorManagerAndroid();
@@ -73,24 +79,32 @@ class CONTENT_EXPORT SensorManagerAndroid {
RECEIVED_MOTION_DATA_MAX = 3,
};
+ void SetLightBufferValue(double lux);
+
void CheckMotionBufferReadyToRead();
void SetMotionBufferReadyStatus(bool ready);
void ClearInternalMotionBuffers();
void SetOrientationBufferReadyStatus(bool ready);
+ bool isUsingBackupSensorsForOrientation();
- // The Java provider of orientation info.
- base::android::ScopedJavaGlobalRef<jobject> device_orientation_;
+ // The Java provider of sensors info.
+ base::android::ScopedJavaGlobalRef<jobject> device_sensors_;
int number_active_device_motion_sensors_;
int received_motion_data_[RECEIVED_MOTION_DATA_MAX];
+ DeviceLightHardwareBuffer* device_light_buffer_;
DeviceMotionHardwareBuffer* device_motion_buffer_;
DeviceOrientationHardwareBuffer* device_orientation_buffer_;
+ bool is_light_buffer_ready_;
bool is_motion_buffer_ready_;
bool is_orientation_buffer_ready_;
+ base::Lock light_buffer_lock_;
base::Lock motion_buffer_lock_;
base::Lock orientation_buffer_lock_;
+ bool is_using_backup_sensors_for_orientation_;
+
DISALLOW_COPY_AND_ASSIGN(SensorManagerAndroid);
};
diff --git a/chromium/content/browser/device_sensors/sensor_manager_android_unittest.cc b/chromium/content/browser/device_sensors/sensor_manager_android_unittest.cc
index 8299164c910..b5f0c5fb933 100644
--- a/chromium/content/browser/device_sensors/sensor_manager_android_unittest.cc
+++ b/chromium/content/browser/device_sensors/sensor_manager_android_unittest.cc
@@ -19,7 +19,7 @@ class FakeSensorManagerAndroid : public SensorManagerAndroid {
FakeSensorManagerAndroid() { }
virtual ~FakeSensorManagerAndroid() { }
- virtual int GetNumberActiveDeviceMotionSensors() OVERRIDE {
+ virtual int GetNumberActiveDeviceMotionSensors() override {
return number_active_sensors_;
}
@@ -28,11 +28,11 @@ class FakeSensorManagerAndroid : public SensorManagerAndroid {
}
protected:
- virtual bool Start(EventType event_type) OVERRIDE {
+ virtual bool Start(EventType event_type) override {
return true;
}
- virtual void Stop(EventType event_type) OVERRIDE {
+ virtual void Stop(EventType event_type) override {
}
private:
@@ -42,10 +42,12 @@ class FakeSensorManagerAndroid : public SensorManagerAndroid {
class AndroidSensorManagerTest : public testing::Test {
protected:
AndroidSensorManagerTest() {
+ light_buffer_.reset(new DeviceLightHardwareBuffer);
motion_buffer_.reset(new DeviceMotionHardwareBuffer);
orientation_buffer_.reset(new DeviceOrientationHardwareBuffer);
}
+ scoped_ptr<DeviceLightHardwareBuffer> light_buffer_;
scoped_ptr<DeviceMotionHardwareBuffer> motion_buffer_;
scoped_ptr<DeviceOrientationHardwareBuffer> orientation_buffer_;
};
@@ -84,7 +86,8 @@ TEST_F(AndroidSensorManagerTest, ThreeDeviceMotionSensorsActive) {
ASSERT_TRUE(motion_buffer_->data.hasRotationRateBeta);
ASSERT_EQ(9, motion_buffer_->data.rotationRateGamma);
ASSERT_TRUE(motion_buffer_->data.hasRotationRateGamma);
- ASSERT_EQ(kInertialSensorIntervalMillis, motion_buffer_->data.interval);
+ ASSERT_EQ(kInertialSensorIntervalMicroseconds / 1000.,
+ motion_buffer_->data.interval);
sensorManager.StopFetchingDeviceMotionData();
ASSERT_FALSE(motion_buffer_->data.allAvailableSensorsAreActive);
@@ -103,7 +106,8 @@ TEST_F(AndroidSensorManagerTest, TwoDeviceMotionSensorsActive) {
sensorManager.GotAccelerationIncludingGravity(0, 0, 1, 2, 3);
ASSERT_TRUE(motion_buffer_->data.allAvailableSensorsAreActive);
- ASSERT_EQ(kInertialSensorIntervalMillis, motion_buffer_->data.interval);
+ ASSERT_EQ(kInertialSensorIntervalMicroseconds / 1000.,
+ motion_buffer_->data.interval);
sensorManager.StopFetchingDeviceMotionData();
ASSERT_FALSE(motion_buffer_->data.allAvailableSensorsAreActive);
@@ -116,7 +120,8 @@ TEST_F(AndroidSensorManagerTest, ZeroDeviceMotionSensorsActive) {
sensorManager.StartFetchingDeviceMotionData(motion_buffer_.get());
ASSERT_TRUE(motion_buffer_->data.allAvailableSensorsAreActive);
- ASSERT_EQ(kInertialSensorIntervalMillis, motion_buffer_->data.interval);
+ ASSERT_EQ(kInertialSensorIntervalMicroseconds / 1000.,
+ motion_buffer_->data.interval);
sensorManager.StopFetchingDeviceMotionData();
ASSERT_FALSE(motion_buffer_->data.allAvailableSensorsAreActive);
@@ -142,6 +147,19 @@ TEST_F(AndroidSensorManagerTest, DeviceOrientationSensorsActive) {
ASSERT_FALSE(orientation_buffer_->data.allAvailableSensorsAreActive);
}
+// DeviceLight
+TEST_F(AndroidSensorManagerTest, DeviceLightSensorsActive) {
+ FakeSensorManagerAndroid::Register(base::android::AttachCurrentThread());
+ FakeSensorManagerAndroid sensorManager;
+
+ sensorManager.StartFetchingDeviceLightData(light_buffer_.get());
+
+ sensorManager.GotLight(0, 0, 100);
+ ASSERT_EQ(100, light_buffer_->data.value);
+
+ sensorManager.StopFetchingDeviceLightData();
+ ASSERT_EQ(-1, light_buffer_->data.value);
+}
} // namespace
diff --git a/chromium/content/browser/devtools/BUILD.gn b/chromium/content/browser/devtools/BUILD.gn
index 4aab2bab11e..75777316dcd 100644
--- a/chromium/content/browser/devtools/BUILD.gn
+++ b/chromium/content/browser/devtools/BUILD.gn
@@ -9,40 +9,27 @@ group("resources") {
deps = [
":devtools_resources",
":devtools_protocol_constants",
+ ":devtools_protocol_handler",
]
}
# In GYP: devtools_resources action in the devtools_resources target.
-action("devtools_resources") {
- visibility = ":resources"
+grit("devtools_resources") {
+ source = "$root_gen_dir/devtools/devtools_resources.grd"
- # This can't use grit_rule.gni because the grd file is generated at build
- # time, so the trick of using grit_info to get the real inputs/outputs at GYP
- # time isn't possible.
- script = "//tools/grit/grit.py"
-
- grdfile = "$root_gen_dir/devtools/devtools_resources.grd"
-
- source_prereqs = [ grdfile ] +
- rebase_path(exec_script("//tools/grit/grit_info.py", [ "--inputs" ],
- "list lines"),
- ".", "//")
-
- out_dir = "$root_gen_dir/webkit"
+ # TOOD(brettw) remove this so the output file goes into the target_gen_dir,
+ # but keep this for not for GYP compat.
+ output_dir = "$root_gen_dir/webkit"
outputs = [
- "$out_dir/grit/devtools_resources.h",
- "$out_dir/devtools_resources.pak",
- "$out_dir/grit/devtools_resources_map.cc",
- "$out_dir/grit/devtools_resources_map.h",
+ "grit/devtools_resources.h",
+ "devtools_resources.pak",
+ "grit/devtools_resources_map.cc",
+ "grit/devtools_resources_map.h",
]
- args = [
- "-i", rebase_path(grdfile, root_build_dir), "build",
- "-f", rebase_path("//tools/gritsettings/resource_ids", root_build_dir),
- "-o", rebase_path(out_dir, root_build_dir),
- "-D", "SHARED_INTERMEDIATE_DIR=" +
- rebase_path(root_gen_dir, root_build_dir),
- ] + grit_defines
+ defines = [
+ "SHARED_INTERMEDIATE_DIR=" + rebase_path(root_gen_dir, root_build_dir),
+ ]
deps = [
# This is the action that generates out .grd input file.
@@ -50,14 +37,14 @@ action("devtools_resources") {
]
}
-action("devtools_protocol_constants") {
- visibility = ":resources"
+action("gen_devtools_protocol_constants") {
+ visibility = [ ":devtools_protocol_constants" ]
script = "//content/public/browser/devtools_protocol_constants_generator.py"
blink_protocol = "//third_party/WebKit/Source/devtools/protocol.json"
browser_protocol = "browser_protocol.json"
- source_prereqs = [ blink_protocol, browser_protocol ]
+ inputs = [ blink_protocol, browser_protocol ]
outputs = [
"$target_gen_dir/devtools_protocol_constants.cc",
@@ -69,3 +56,32 @@ action("devtools_protocol_constants") {
rebase_path(browser_protocol, root_build_dir),
]
}
+
+action("gen_devtools_protocol_handler") {
+ visibility = [ ":devtools_protocol_handler" ]
+
+ script = "//content/browser/devtools/protocol/" +
+ "devtools_protocol_handler_generator.py"
+
+ blink_protocol = "//third_party/WebKit/Source/devtools/protocol.json"
+ inputs = [ blink_protocol ]
+
+ outputs = [
+ "$target_gen_dir/protocol/devtools_protocol_handler_impl.cc",
+ "$target_gen_dir/protocol/devtools_protocol_handler_impl.h",
+ ]
+
+ args = [
+ rebase_path(blink_protocol, root_build_dir),
+ ] + rebase_path(outputs, root_build_dir)
+}
+
+source_set("devtools_protocol_constants") {
+ visibility = [ ":resources" ]
+ sources = get_target_outputs(":gen_devtools_protocol_constants")
+}
+
+source_set("devtools_protocol_handler") {
+ visibility = [ ":resources" ]
+ sources = get_target_outputs(":gen_devtools_protocol_handler")
+}
diff --git a/chromium/content/browser/devtools/OWNERS b/chromium/content/browser/devtools/OWNERS
index d995b0f999c..88a3d57bb91 100644
--- a/chromium/content/browser/devtools/OWNERS
+++ b/chromium/content/browser/devtools/OWNERS
@@ -1,4 +1,4 @@
-kaznacheev@chromium.org
+dgozman@chromium.org
pfeldman@chromium.org
vsevik@chromium.org
yurys@chromium.org
diff --git a/chromium/content/browser/devtools/browser_protocol.json b/chromium/content/browser/devtools/browser_protocol.json
index dfb462febf2..f4b67407d2e 100644
--- a/chromium/content/browser/devtools/browser_protocol.json
+++ b/chromium/content/browser/devtools/browser_protocol.json
@@ -47,5 +47,39 @@
"handlers": ["browser"]
}
]
+ },
+ {
+ "domain": "Tethering",
+ "description": "The Tethering domain defines methods and events for browser port binding.",
+ "hidden": true,
+ "commands": [
+ {
+ "name": "bind",
+ "description": "Request browser port binding.",
+ "parameters": [
+ { "name": "port", "type": "number", "description": "Port number to bind." }
+ ],
+ "handlers": ["browser"]
+ },
+ {
+ "name": "unbind",
+ "description": "Request browser port unbinding.",
+ "parameters": [
+ { "name": "port", "type": "number", "description": "Port number to unbind." }
+ ],
+ "handlers": ["browser"]
+ }
+ ],
+ "events": [
+ {
+ "name": "accepted",
+ "description": "Informs that port was successfully bound and got a specified connection id.",
+ "parameters": [
+ {"name": "port", "type": "number", "description": "Port number that was successfully bound." },
+ {"name": "connectionId", "type": "string", "description": "Connection id to be used." }
+ ],
+ "handlers": ["browser"]
+ }
+ ]
}]
}
diff --git a/chromium/content/browser/devtools/devtools.gyp b/chromium/content/browser/devtools/devtools.gyp
new file mode 100644
index 00000000000..a67eca87890
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools.gyp
@@ -0,0 +1,44 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'devtools_protocol_handler',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'devtools_protocol_handler',
+ 'variables': {
+ 'blink_protocol': '../../../third_party/WebKit/Source/devtools/protocol.json',
+ 'generator': 'protocol/devtools_protocol_handler_generator.py',
+ 'output_cc': '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_handler_impl.cc',
+ 'output_h': '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_handler_impl.h',
+ },
+ 'inputs': [
+ '<(blink_protocol)',
+ '<(generator)',
+ ],
+ 'outputs': [
+ '<(output_cc)',
+ '<(output_h)',
+ ],
+ 'action':[
+ 'python',
+ '<(generator)',
+ '<(blink_protocol)',
+ '<(output_cc)',
+ '<(output_h)',
+ ],
+ 'message': 'Generating DevTools protocol browser-side handlers from <(blink_protocol)'
+ },
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)',
+ ]
+ },
+ },
+ ],
+}
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.cc b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
index bcb60b55b78..b7f9b24b59f 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.cc
@@ -5,24 +5,45 @@
#include "content/browser/devtools/devtools_agent_host_impl.h"
#include <map>
+#include <vector>
#include "base/basictypes.h"
#include "base/guid.h"
#include "base/lazy_instance.h"
-#include "content/browser/devtools/devtools_manager_impl.h"
+#include "content/browser/devtools/devtools_manager.h"
+#include "content/browser/devtools/embedded_worker_devtools_manager.h"
#include "content/browser/devtools/forwarding_agent_host.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/devtools_manager_delegate.h"
namespace content {
namespace {
typedef std::map<std::string, DevToolsAgentHostImpl*> Instances;
base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
+
+typedef std::vector<const DevToolsAgentHost::AgentStateCallback*>
+ AgentStateCallbacks;
+base::LazyInstance<AgentStateCallbacks>::Leaky g_callbacks =
+ LAZY_INSTANCE_INITIALIZER;
} // namespace
+// static
+DevToolsAgentHost::List DevToolsAgentHost::GetOrCreateAll() {
+ List result = EmbeddedWorkerDevToolsManager::GetInstance()
+ ->GetOrCreateAllAgentHosts();
+ std::vector<WebContents*> wc_list =
+ DevToolsAgentHostImpl::GetInspectableWebContents();
+ for (std::vector<WebContents*>::iterator it = wc_list.begin();
+ it != wc_list.end(); ++it) {
+ result.push_back(GetOrCreateFor(*it));
+ }
+ return result;
+}
+
DevToolsAgentHostImpl::DevToolsAgentHostImpl()
- : close_listener_(NULL),
- id_(base::GenerateGUID()) {
+ : id_(base::GenerateGUID()),
+ client_(NULL) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
g_instances.Get()[id_] = this;
}
@@ -32,7 +53,7 @@ DevToolsAgentHostImpl::~DevToolsAgentHostImpl() {
g_instances.Get().erase(g_instances.Get().find(id_));
}
-//static
+// static
scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForId(
const std::string& id) {
if (g_instances == NULL)
@@ -49,8 +70,29 @@ scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::Create(
return new ForwardingAgentHost(delegate);
}
+void DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) {
+ scoped_refptr<DevToolsAgentHostImpl> protect(this);
+ if (client_) {
+ client_->AgentHostClosed(this, true);
+ Detach();
+ }
+ client_ = client;
+ Attach();
+ DevToolsManager::GetInstance()->AgentHostChanged(this);
+}
+
+void DevToolsAgentHostImpl::DetachClient() {
+ if (!client_)
+ return;
+
+ scoped_refptr<DevToolsAgentHostImpl> protect(this);
+ client_ = NULL;
+ Detach();
+ DevToolsManager::GetInstance()->AgentHostChanged(this);
+}
+
bool DevToolsAgentHostImpl::IsAttached() {
- return !!DevToolsManagerImpl::GetInstance()->GetDevToolsClientHostFor(this);
+ return !!client_;
}
void DevToolsAgentHostImpl::InspectElement(int x, int y) {
@@ -60,24 +102,94 @@ std::string DevToolsAgentHostImpl::GetId() {
return id_;
}
-RenderViewHost* DevToolsAgentHostImpl::GetRenderViewHost() {
+WebContents* DevToolsAgentHostImpl::GetWebContents() {
return NULL;
}
-void DevToolsAgentHostImpl::DisconnectRenderViewHost() {}
+void DevToolsAgentHostImpl::DisconnectWebContents() {
+}
-void DevToolsAgentHostImpl::ConnectRenderViewHost(RenderViewHost* rvh) {}
+void DevToolsAgentHostImpl::ConnectWebContents(WebContents* wc) {
+}
bool DevToolsAgentHostImpl::IsWorker() const {
return false;
}
-void DevToolsAgentHostImpl::NotifyCloseListener() {
- if (close_listener_) {
- scoped_refptr<DevToolsAgentHostImpl> protect(this);
- close_listener_->AgentHostClosing(this);
- close_listener_ = NULL;
+void DevToolsAgentHostImpl::HostClosed() {
+ if (!client_)
+ return;
+
+ scoped_refptr<DevToolsAgentHostImpl> protect(this);
+ // Clear |client_| before notifying it.
+ DevToolsAgentHostClient* client = client_;
+ client_ = NULL;
+ client->AgentHostClosed(this, false);
+ DevToolsManager::GetInstance()->AgentHostChanged(this);
+}
+
+void DevToolsAgentHostImpl::SendMessageToClient(const std::string& message) {
+ if (!client_)
+ return;
+ client_->DispatchProtocolMessage(this, message);
+}
+
+// static
+void DevToolsAgentHost::DetachAllClients() {
+ if (g_instances == NULL)
+ return;
+
+ // Make a copy, since detaching may lead to agent destruction, which
+ // removes it from the instances.
+ Instances copy = g_instances.Get();
+ for (Instances::iterator it(copy.begin()); it != copy.end(); ++it) {
+ DevToolsAgentHostImpl* agent_host = it->second;
+ if (agent_host->client_) {
+ scoped_refptr<DevToolsAgentHostImpl> protect(agent_host);
+ // Clear |client_| before notifying it.
+ DevToolsAgentHostClient* client = agent_host->client_;
+ agent_host->client_ = NULL;
+ client->AgentHostClosed(agent_host, true);
+ agent_host->Detach();
+ DevToolsManager::GetInstance()->AgentHostChanged(protect);
+ }
}
}
+// static
+void DevToolsAgentHost::AddAgentStateCallback(
+ const AgentStateCallback& callback) {
+ g_callbacks.Get().push_back(&callback);
+}
+
+// static
+void DevToolsAgentHost::RemoveAgentStateCallback(
+ const AgentStateCallback& callback) {
+ if (g_callbacks == NULL)
+ return;
+
+ AgentStateCallbacks* callbacks_ = g_callbacks.Pointer();
+ AgentStateCallbacks::iterator it =
+ std::find(callbacks_->begin(), callbacks_->end(), &callback);
+ DCHECK(it != callbacks_->end());
+ callbacks_->erase(it);
+}
+
+// static
+void DevToolsAgentHostImpl::NotifyCallbacks(
+ DevToolsAgentHostImpl* agent_host, bool attached) {
+ AgentStateCallbacks copy(g_callbacks.Get());
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+ if (manager->delegate())
+ manager->delegate()->DevToolsAgentStateChanged(agent_host, attached);
+ for (AgentStateCallbacks::iterator it = copy.begin(); it != copy.end(); ++it)
+ (*it)->Run(agent_host, attached);
+}
+
+void DevToolsAgentHostImpl::Inspect(BrowserContext* browser_context) {
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+ if (manager->delegate())
+ manager->delegate()->Inspect(browser_context, this);
+}
+
} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.h b/chromium/content/browser/devtools/devtools_agent_host_impl.h
index d0fad668b49..694590acf1c 100644
--- a/chromium/content/browser/devtools/devtools_agent_host_impl.h
+++ b/chromium/content/browser/devtools/devtools_agent_host_impl.h
@@ -17,15 +17,13 @@ class Message;
namespace content {
+class BrowserContext;
+
// Describes interface for managing devtools agents from the browser process.
class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
public:
- class CONTENT_EXPORT CloseListener {
- public:
- virtual void AgentHostClosing(DevToolsAgentHostImpl*) = 0;
- protected:
- virtual ~CloseListener() {}
- };
+ // Returns a list of all existing WebContents that can be debugged.
+ static std::vector<WebContents*> GetInspectableWebContents();
// Informs the hosted agent that a client host has attached.
virtual void Attach() = 0;
@@ -33,37 +31,36 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
// Informs the hosted agent that a client host has detached.
virtual void Detach() = 0;
- // Sends a message to the agent hosted by this object.
- virtual void DispatchOnInspectorBackend(const std::string& message) = 0;
+ // Sends a message to the agent.
+ virtual void DispatchProtocolMessage(const std::string& message) = 0;
- void set_close_listener(CloseListener* listener) {
- close_listener_ = listener;
- }
+ // Opens the inspector for this host.
+ void Inspect(BrowserContext* browser_context);
// DevToolsAgentHost implementation.
- virtual bool IsAttached() OVERRIDE;
-
- virtual void InspectElement(int x, int y) OVERRIDE;
-
- virtual std::string GetId() OVERRIDE;
-
- virtual RenderViewHost* GetRenderViewHost() OVERRIDE;
-
- virtual void DisconnectRenderViewHost() OVERRIDE;
-
- virtual void ConnectRenderViewHost(RenderViewHost* rvh) OVERRIDE;
-
- virtual bool IsWorker() const OVERRIDE;
+ void AttachClient(DevToolsAgentHostClient* client) override;
+ void DetachClient() override;
+ bool IsAttached() override;
+ void InspectElement(int x, int y) override;
+ std::string GetId() override;
+ WebContents* GetWebContents() override;
+ void DisconnectWebContents() override;
+ void ConnectWebContents(WebContents* wc) override;
+ bool IsWorker() const override;
protected:
DevToolsAgentHostImpl();
- virtual ~DevToolsAgentHostImpl();
+ ~DevToolsAgentHostImpl() override;
- void NotifyCloseListener();
+ void HostClosed();
+ void SendMessageToClient(const std::string& message);
+ static void NotifyCallbacks(DevToolsAgentHostImpl* agent_host, bool attached);
private:
- CloseListener* close_listener_;
+ friend class DevToolsAgentHost; // for static methods
+
const std::string id_;
+ DevToolsAgentHostClient* client_;
};
} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_browser_target.cc b/chromium/content/browser/devtools/devtools_browser_target.cc
deleted file mode 100644
index b050152d2e4..00000000000
--- a/chromium/content/browser/devtools/devtools_browser_target.cc
+++ /dev/null
@@ -1,180 +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/devtools/devtools_browser_target.h"
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/server/http_server.h"
-
-namespace content {
-
-DevToolsBrowserTarget::DevToolsBrowserTarget(
- net::HttpServer* http_server,
- int connection_id)
- : message_loop_proxy_(base::MessageLoopProxy::current()),
- http_server_(http_server),
- connection_id_(connection_id),
- weak_factory_(this) {
-}
-
-void DevToolsBrowserTarget::RegisterDomainHandler(
- const std::string& domain,
- DevToolsProtocol::Handler* handler,
- bool handle_on_ui_thread) {
- DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
-
- DCHECK(handlers_.find(domain) == handlers_.end());
- handlers_[domain] = handler;
- if (handle_on_ui_thread) {
- handle_on_ui_thread_.insert(domain);
- handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::RespondFromUIThread,
- weak_factory_.GetWeakPtr()));
- } else {
- handler->SetNotifier(base::Bind(&DevToolsBrowserTarget::Respond,
- base::Unretained(this)));
- }
-}
-
-typedef std::map<std::string, DevToolsBrowserTarget*> DomainMap;
-base::LazyInstance<DomainMap>::Leaky g_used_domains = LAZY_INSTANCE_INITIALIZER;
-
-void DevToolsBrowserTarget::HandleMessage(const std::string& data) {
- DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
- std::string error_response;
- scoped_refptr<DevToolsProtocol::Command> command =
- DevToolsProtocol::ParseCommand(data, &error_response);
- if (!command) {
- Respond(error_response);
- return;
- }
-
- DomainHandlerMap::iterator it = handlers_.find(command->domain());
- if (it == handlers_.end()) {
- Respond(command->NoSuchMethodErrorResponse()->Serialize());
- return;
- }
- DomainMap& used_domains(g_used_domains.Get());
- std::string domain = command->domain();
- DomainMap::iterator jt = used_domains.find(domain);
- if (jt == used_domains.end()) {
- used_domains[domain] = this;
- } else if (jt->second != this) {
- std::string message =
- base::StringPrintf("'%s' is held by another connection",
- domain.c_str());
- Respond(command->ServerErrorResponse(message)->Serialize());
- return;
- }
-
- DevToolsProtocol::Handler* handler = it->second;
- bool handle_directly = handle_on_ui_thread_.find(domain) ==
- handle_on_ui_thread_.end();
- if (handle_directly) {
- scoped_refptr<DevToolsProtocol::Response> response =
- handler->HandleCommand(command);
- if (response && response->is_async_promise())
- return;
- if (response)
- Respond(response->Serialize());
- else
- Respond(command->NoSuchMethodErrorResponse()->Serialize());
- return;
- }
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread,
- this,
- handler,
- command));
-}
-
-void DevToolsBrowserTarget::Detach() {
- DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
- DCHECK(http_server_);
-
- http_server_ = NULL;
-
- DomainMap& used_domains(g_used_domains.Get());
- for (DomainMap::iterator it = used_domains.begin();
- it != used_domains.end();) {
- if (it->second == this) {
- DomainMap::iterator to_erase = it;
- ++it;
- used_domains.erase(to_erase);
- } else {
- ++it;
- }
- }
-
- std::vector<DevToolsProtocol::Handler*> ui_handlers;
- for (std::set<std::string>::iterator domain_it = handle_on_ui_thread_.begin();
- domain_it != handle_on_ui_thread_.end();
- ++domain_it) {
- DomainHandlerMap::iterator handler_it = handlers_.find(*domain_it);
- CHECK(handler_it != handlers_.end());
- ui_handlers.push_back(handler_it->second);
- handlers_.erase(handler_it);
- }
-
- STLDeleteValues(&handlers_);
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&DevToolsBrowserTarget::DeleteHandlersOnUIThread,
- this,
- ui_handlers));
-}
-
-DevToolsBrowserTarget::~DevToolsBrowserTarget() {
- // DCHECK that Detach has been called or no handler has ever been registered.
- DCHECK(handlers_.empty());
-}
-
-void DevToolsBrowserTarget::HandleCommandOnUIThread(
- DevToolsProtocol::Handler* handler,
- scoped_refptr<DevToolsProtocol::Command> command) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- scoped_refptr<DevToolsProtocol::Response> response =
- handler->HandleCommand(command);
- if (response && response->is_async_promise())
- return;
-
- if (response)
- RespondFromUIThread(response->Serialize());
- else
- RespondFromUIThread(command->NoSuchMethodErrorResponse()->Serialize());
-}
-
-void DevToolsBrowserTarget::DeleteHandlersOnUIThread(
- std::vector<DevToolsProtocol::Handler*> handlers) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- STLDeleteElements(&handlers);
-}
-
-void DevToolsBrowserTarget::Respond(const std::string& message) {
- DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current());
- if (!http_server_)
- return;
- http_server_->SendOverWebSocket(connection_id_, message);
-}
-
-void DevToolsBrowserTarget::RespondFromUIThread(const std::string& message) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&DevToolsBrowserTarget::Respond, this, message));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_browser_target.h b/chromium/content/browser/devtools/devtools_browser_target.h
deleted file mode 100644
index 0dda59b2ad4..00000000000
--- a/chromium/content/browser/devtools/devtools_browser_target.h
+++ /dev/null
@@ -1,75 +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_DEVTOOLS_DEVTOOLS_BROWSER_TARGET_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_BROWSER_TARGET_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/devtools/devtools_protocol.h"
-
-namespace base {
-class DictionaryValue;
-class MessageLoopProxy;
-class Value;
-} // namespace base
-
-namespace net {
-class HttpServer;
-} // namespace net
-
-namespace content {
-
-// This class handles the "Browser" target for remote debugging.
-class DevToolsBrowserTarget
- : public base::RefCountedThreadSafe<DevToolsBrowserTarget> {
- public:
- DevToolsBrowserTarget(net::HttpServer* server, int connection_id);
-
- int connection_id() const { return connection_id_; }
-
- // Takes ownership of |handler|.
- void RegisterDomainHandler(const std::string& domain,
- DevToolsProtocol::Handler* handler,
- bool handle_on_ui_thread);
-
- void HandleMessage(const std::string& data);
-
- void Detach();
-
- private:
- friend class base::RefCountedThreadSafe<DevToolsBrowserTarget>;
- ~DevToolsBrowserTarget();
-
- void HandleCommandOnUIThread(
- DevToolsProtocol::Handler*,
- scoped_refptr<DevToolsProtocol::Command> command);
-
- void DeleteHandlersOnUIThread(
- std::vector<DevToolsProtocol::Handler*> handlers);
-
- void Respond(const std::string& message);
- void RespondFromUIThread(const std::string& message);
-
- scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
- net::HttpServer* http_server_;
- const int connection_id_;
-
- typedef std::map<std::string, DevToolsProtocol::Handler*> DomainHandlerMap;
- DomainHandlerMap handlers_;
- std::set<std::string> handle_on_ui_thread_;
- base::WeakPtrFactory<DevToolsBrowserTarget> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(DevToolsBrowserTarget);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_BROWSER_TARGET_H_
diff --git a/chromium/content/browser/devtools/devtools_frontend_host.cc b/chromium/content/browser/devtools/devtools_frontend_host.cc
deleted file mode 100644
index bfa623a140e..00000000000
--- a/chromium/content/browser/devtools/devtools_frontend_host.cc
+++ /dev/null
@@ -1,96 +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/devtools/devtools_frontend_host.h"
-
-#include "content/browser/devtools/devtools_manager_impl.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/devtools_messages.h"
-#include "content/public/browser/devtools_client_host.h"
-#include "content/public/browser/devtools_frontend_host_delegate.h"
-
-namespace content {
-
-// static
-DevToolsClientHost* DevToolsClientHost::CreateDevToolsFrontendHost(
- WebContents* client_web_contents,
- DevToolsFrontendHostDelegate* delegate) {
- return new DevToolsFrontendHost(
- static_cast<WebContentsImpl*>(client_web_contents), delegate);
-}
-
-// static
-void DevToolsClientHost::SetupDevToolsFrontendClient(
- RenderViewHost* frontend_rvh) {
- frontend_rvh->Send(new DevToolsMsg_SetupDevToolsClient(
- frontend_rvh->GetRoutingID()));
-}
-
-DevToolsFrontendHost::DevToolsFrontendHost(
- WebContentsImpl* web_contents,
- DevToolsFrontendHostDelegate* delegate)
- : WebContentsObserver(web_contents),
- delegate_(delegate) {
-}
-
-DevToolsFrontendHost::~DevToolsFrontendHost() {
- DevToolsManager::GetInstance()->ClientHostClosing(this);
-}
-
-void DevToolsFrontendHost::DispatchOnInspectorFrontend(
- const std::string& message) {
- if (!web_contents())
- return;
- RenderViewHostImpl* target_host =
- static_cast<RenderViewHostImpl*>(web_contents()->GetRenderViewHost());
- target_host->Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(
- target_host->GetRoutingID(),
- message));
-}
-
-void DevToolsFrontendHost::InspectedContentsClosing() {
- delegate_->InspectedContentsClosing();
-}
-
-void DevToolsFrontendHost::ReplacedWithAnotherClient() {
-}
-
-bool DevToolsFrontendHost::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(DevToolsFrontendHost, message)
- IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DispatchOnInspectorBackend,
- OnDispatchOnInspectorBackend)
- IPC_MESSAGE_HANDLER(DevToolsHostMsg_DispatchOnEmbedder,
- OnDispatchOnEmbedder)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void DevToolsFrontendHost::RenderProcessGone(
- base::TerminationStatus status) {
- switch(status) {
- case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
- case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
- case base::TERMINATION_STATUS_PROCESS_CRASHED:
- DevToolsManager::GetInstance()->ClientHostClosing(this);
- break;
- default:
- break;
- }
-}
-
-void DevToolsFrontendHost::OnDispatchOnInspectorBackend(
- const std::string& message) {
- DevToolsManagerImpl::GetInstance()->DispatchOnInspectorBackend(this, message);
-}
-
-void DevToolsFrontendHost::OnDispatchOnEmbedder(
- const std::string& message) {
- delegate_->DispatchOnEmbedder(message);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_frontend_host.h b/chromium/content/browser/devtools/devtools_frontend_host.h
deleted file mode 100644
index 469d162bf9c..00000000000
--- a/chromium/content/browser/devtools/devtools_frontend_host.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_DEVTOOLS_DEVTOOLS_FRONTEND_HOST_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRONTEND_HOST_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "content/public/browser/devtools_client_host.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace content {
-
-class DevToolsFrontendHostDelegate;
-class WebContentsImpl;
-
-// This class handles messages from DevToolsClient and calls corresponding
-// methods on DevToolsFrontendHostDelegate which is implemented by the
-// embedder. This allows us to avoid exposing DevTools client messages through
-// the content public API.
-class DevToolsFrontendHost : public DevToolsClientHost,
- public WebContentsObserver {
- public:
- DevToolsFrontendHost(WebContentsImpl* web_contents,
- DevToolsFrontendHostDelegate* delegate);
-
- private:
- virtual ~DevToolsFrontendHost();
-
- // DevToolsClientHost implementation.
- virtual void DispatchOnInspectorFrontend(const std::string& message) OVERRIDE;
- virtual void InspectedContentsClosing() OVERRIDE;
- virtual void ReplacedWithAnotherClient() OVERRIDE;
-
- // WebContentsObserver overrides.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
-
- void OnDispatchOnInspectorBackend(const std::string& message);
- void OnDispatchOnEmbedder(const std::string& message);
-
- DevToolsFrontendHostDelegate* delegate_;
- DISALLOW_COPY_AND_ASSIGN(DevToolsFrontendHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRONTEND_HOST_H_
diff --git a/chromium/content/browser/devtools/devtools_frontend_host_impl.cc b/chromium/content/browser/devtools/devtools_frontend_host_impl.cc
new file mode 100644
index 00000000000..a73e88cb50a
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_frontend_host_impl.cc
@@ -0,0 +1,56 @@
+// 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/devtools/devtools_frontend_host_impl.h"
+
+#include "content/common/devtools_messages.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+// static
+DevToolsFrontendHost* DevToolsFrontendHost::Create(
+ RenderViewHost* frontend_rvh,
+ DevToolsFrontendHost::Delegate* delegate) {
+ return new DevToolsFrontendHostImpl(frontend_rvh, delegate);
+}
+
+DevToolsFrontendHostImpl::DevToolsFrontendHostImpl(
+ RenderViewHost* frontend_rvh,
+ DevToolsFrontendHost::Delegate* delegate)
+ : WebContentsObserver(WebContents::FromRenderViewHost(frontend_rvh)),
+ delegate_(delegate) {
+ frontend_rvh->Send(new DevToolsMsg_SetupDevToolsClient(
+ frontend_rvh->GetRoutingID()));
+}
+
+DevToolsFrontendHostImpl::~DevToolsFrontendHostImpl() {
+}
+
+bool DevToolsFrontendHostImpl::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(DevToolsFrontendHostImpl, message)
+ IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DispatchOnInspectorBackend,
+ OnDispatchOnInspectorBackend)
+ IPC_MESSAGE_HANDLER(DevToolsHostMsg_DispatchOnEmbedder,
+ OnDispatchOnEmbedder)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void DevToolsFrontendHostImpl::OnDispatchOnInspectorBackend(
+ const std::string& message) {
+ delegate_->HandleMessageFromDevToolsFrontendToBackend(message);
+}
+
+void DevToolsFrontendHostImpl::OnDispatchOnEmbedder(
+ const std::string& message) {
+ delegate_->HandleMessageFromDevToolsFrontend(message);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_frontend_host_impl.h b/chromium/content/browser/devtools/devtools_frontend_host_impl.h
new file mode 100644
index 00000000000..98b907497a1
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_frontend_host_impl.h
@@ -0,0 +1,33 @@
+// 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_DEVTOOLS_DEVTOOLS_FRONTEND_HOST_IMPL_H_
+#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRONTEND_HOST_IMPL_H_
+
+#include "content/public/browser/devtools_frontend_host.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+
+class DevToolsFrontendHostImpl : public DevToolsFrontendHost,
+ public WebContentsObserver {
+ public:
+ DevToolsFrontendHostImpl(RenderViewHost* frontend_rvh,
+ DevToolsFrontendHost::Delegate* delegate);
+ ~DevToolsFrontendHostImpl() override;
+
+ private:
+ // WebContentsObserver overrides.
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ void OnDispatchOnInspectorBackend(const std::string& message);
+ void OnDispatchOnEmbedder(const std::string& message);
+
+ DevToolsFrontendHost::Delegate* delegate_;
+ DISALLOW_COPY_AND_ASSIGN(DevToolsFrontendHostImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_FRONTEND_HOST_IMPL_H_
diff --git a/chromium/content/browser/devtools/devtools_http_handler_impl.cc b/chromium/content/browser/devtools/devtools_http_handler_impl.cc
index d1b5b1e6724..e7b7fb9b99e 100644
--- a/chromium/content/browser/devtools/devtools_http_handler_impl.cc
+++ b/chromium/content/browser/devtools/devtools_http_handler_impl.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
@@ -17,23 +17,21 @@
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread.h"
#include "base/values.h"
-#include "content/browser/devtools/devtools_browser_target.h"
+#include "content/browser/devtools/devtools_manager.h"
#include "content/browser/devtools/devtools_protocol.h"
#include "content/browser/devtools/devtools_protocol_constants.h"
#include "content/browser/devtools/devtools_system_info_handler.h"
-#include "content/browser/devtools/devtools_tracing_handler.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+#include "content/browser/devtools/protocol/tracing_handler.h"
#include "content/browser/devtools/tethering_handler.h"
#include "content/common/devtools_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_http_handler_delegate.h"
-#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/devtools_target.h"
#include "content/public/common/content_client.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/user_agent.h"
-#include "content/public/common/user_agent.h"
#include "grit/devtools_resources_map.h"
#include "net/base/escape.h"
#include "net/base/io_buffer.h"
@@ -41,6 +39,7 @@
#include "net/base/net_errors.h"
#include "net/server/http_server_request_info.h"
#include "net/server/http_server_response_info.h"
+#include "net/socket/server_socket.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
@@ -69,64 +68,79 @@ const char kTargetFaviconUrlField[] = "faviconUrl";
const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl";
const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl";
-// An internal implementation of DevToolsClientHost that delegates
-// messages sent for DevToolsClient to a DebuggerShell instance.
-class DevToolsClientHostImpl : public DevToolsClientHost {
+// Maximum write buffer size of devtools http/websocket connectinos.
+const int32 kSendBufferSizeForDevTools = 100 * 1024 * 1024; // 100Mb
+
+// DevToolsAgentHostClientImpl -----------------------------------------------
+
+// An internal implementation of DevToolsAgentHostClient that delegates
+// messages sent to a DebuggerShell instance.
+class DevToolsAgentHostClientImpl : public DevToolsAgentHostClient {
public:
- DevToolsClientHostImpl(base::MessageLoop* message_loop,
- net::HttpServer* server,
- int connection_id)
+ DevToolsAgentHostClientImpl(base::MessageLoop* message_loop,
+ net::HttpServer* server,
+ int connection_id,
+ DevToolsAgentHost* agent_host)
: message_loop_(message_loop),
server_(server),
connection_id_(connection_id),
- is_closed_(false),
- detach_reason_("target_closed") {}
+ agent_host_(agent_host) {
+ agent_host_->AttachClient(this);
+ }
- virtual ~DevToolsClientHostImpl() {}
+ ~DevToolsAgentHostClientImpl() override {
+ if (agent_host_.get())
+ agent_host_->DetachClient();
+ }
- // DevToolsClientHost interface
- virtual void InspectedContentsClosing() OVERRIDE {
- if (is_closed_)
- return;
- is_closed_ = true;
+ void AgentHostClosed(DevToolsAgentHost* agent_host,
+ bool replaced_with_another_client) override {
+ DCHECK(agent_host == agent_host_.get());
+ agent_host_ = NULL;
base::DictionaryValue notification;
notification.SetString(
- devtools::Inspector::detached::kParamReason, detach_reason_);
+ devtools::Inspector::detached::kParamReason,
+ replaced_with_another_client ?
+ "replaced_with_devtools" : "target_closed");
std::string response = DevToolsProtocol::CreateNotification(
devtools::Inspector::detached::kName,
notification.DeepCopy())->Serialize();
message_loop_->PostTask(
FROM_HERE,
base::Bind(&net::HttpServer::SendOverWebSocket,
- server_,
+ base::Unretained(server_),
connection_id_,
response));
message_loop_->PostTask(
FROM_HERE,
- base::Bind(&net::HttpServer::Close, server_, connection_id_));
+ base::Bind(&net::HttpServer::Close,
+ base::Unretained(server_),
+ connection_id_));
}
- virtual void DispatchOnInspectorFrontend(const std::string& data) OVERRIDE {
+ void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+ const std::string& message) override {
+ DCHECK(agent_host == agent_host_.get());
message_loop_->PostTask(
FROM_HERE,
base::Bind(&net::HttpServer::SendOverWebSocket,
- server_,
+ base::Unretained(server_),
connection_id_,
- data));
+ message));
}
- virtual void ReplacedWithAnotherClient() OVERRIDE {
- detach_reason_ = "replaced_with_devtools";
+ void OnMessage(const std::string& message) {
+ if (agent_host_.get())
+ agent_host_->DispatchProtocolMessage(message);
}
private:
- base::MessageLoop* message_loop_;
- net::HttpServer* server_;
- int connection_id_;
- bool is_closed_;
- std::string detach_reason_;
+ base::MessageLoop* const message_loop_;
+ net::HttpServer* const server_;
+ const int connection_id_;
+ scoped_refptr<DevToolsAgentHost> agent_host_;
};
static bool TimeComparator(const DevToolsTarget* target1,
@@ -136,6 +150,83 @@ static bool TimeComparator(const DevToolsTarget* target1,
} // namespace
+// DevToolsHttpHandlerImpl::BrowserTarget ------------------------------------
+
+class DevToolsHttpHandlerImpl::BrowserTarget {
+ public:
+ BrowserTarget(base::MessageLoop* message_loop,
+ net::HttpServer* server,
+ int connection_id)
+ : message_loop_(message_loop),
+ server_(server),
+ connection_id_(connection_id),
+ tracing_handler_(new devtools::tracing::TracingHandler(
+ devtools::tracing::TracingHandler::Browser)),
+ protocol_handler_(new DevToolsProtocolHandlerImpl()) {
+ protocol_handler_->SetNotifier(
+ base::Bind(&BrowserTarget::Respond, base::Unretained(this)));
+ protocol_handler_->SetTracingHandler(tracing_handler_.get());
+ }
+
+ ~BrowserTarget() {
+ STLDeleteElements(&handlers_);
+ }
+
+ // Takes ownership.
+ void RegisterHandler(DevToolsProtocol::Handler* handler) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ handler->SetNotifier(
+ base::Bind(&BrowserTarget::Respond, base::Unretained(this)));
+ handlers_.push_back(handler);
+ }
+
+ void HandleMessage(const std::string& message) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::string error_response;
+ scoped_refptr<DevToolsProtocol::Command> command =
+ DevToolsProtocol::ParseCommand(message, &error_response);
+ if (!command.get()) {
+ Respond(error_response);
+ return;
+ }
+
+ scoped_refptr<DevToolsProtocol::Response> response =
+ protocol_handler_->HandleCommand(command);
+ for (const auto& handler : handlers_) {
+ if (response.get())
+ break;
+ response = handler->HandleCommand(command);
+ }
+
+ if (response.get()) {
+ if (!response->is_async_promise())
+ Respond(response->Serialize());
+ } else {
+ Respond(command->NoSuchMethodErrorResponse()->Serialize());
+ }
+ }
+
+ void Respond(const std::string& message) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&net::HttpServer::SendOverWebSocket,
+ base::Unretained(server_),
+ connection_id_,
+ message));
+ }
+
+ private:
+ base::MessageLoop* const message_loop_;
+ net::HttpServer* const server_;
+ const int connection_id_;
+ scoped_ptr<devtools::tracing::TracingHandler> tracing_handler_;
+ scoped_ptr<DevToolsProtocolHandlerImpl> protocol_handler_;
+ std::vector<DevToolsProtocol::Handler*> handlers_;
+};
+
+// DevToolsHttpHandler -------------------------------------------------------
+
// static
bool DevToolsHttpHandler::IsSupportedProtocolVersion(
const std::string& version) {
@@ -153,12 +244,12 @@ int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) {
// static
DevToolsHttpHandler* DevToolsHttpHandler::Start(
- const net::StreamListenSocketFactory* socket_factory,
+ scoped_ptr<ServerSocketFactory> server_socket_factory,
const std::string& frontend_url,
DevToolsHttpHandlerDelegate* delegate,
const base::FilePath& active_port_output_directory) {
DevToolsHttpHandlerImpl* http_handler =
- new DevToolsHttpHandlerImpl(socket_factory,
+ new DevToolsHttpHandlerImpl(server_socket_factory.Pass(),
frontend_url,
delegate,
active_port_output_directory);
@@ -166,6 +257,32 @@ DevToolsHttpHandler* DevToolsHttpHandler::Start(
return http_handler;
}
+// DevToolsHttpHandler::ServerSocketFactory ----------------------------------
+
+DevToolsHttpHandler::ServerSocketFactory::ServerSocketFactory(
+ const std::string& address,
+ int port,
+ int backlog)
+ : address_(address),
+ port_(port),
+ backlog_(backlog) {
+}
+
+DevToolsHttpHandler::ServerSocketFactory::~ServerSocketFactory() {
+}
+
+scoped_ptr<net::ServerSocket>
+DevToolsHttpHandler::ServerSocketFactory::CreateAndListen() const {
+ scoped_ptr<net::ServerSocket> socket = Create();
+ if (socket &&
+ socket->ListenWithAddressAndPort(address_, port_, backlog_) == net::OK) {
+ return socket.Pass();
+ }
+ return scoped_ptr<net::ServerSocket>();
+}
+
+// DevToolsHttpHandlerImpl ---------------------------------------------------
+
DevToolsHttpHandlerImpl::~DevToolsHttpHandlerImpl() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Stop() must be called prior to destruction.
@@ -201,6 +318,7 @@ void DevToolsHttpHandlerImpl::StartHandlerThread() {
void DevToolsHttpHandlerImpl::ResetHandlerThread() {
thread_.reset();
+ server_ip_address_.reset();
}
void DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease() {
@@ -217,11 +335,19 @@ void DevToolsHttpHandlerImpl::Stop() {
base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThreadAndRelease, this));
}
+void DevToolsHttpHandlerImpl::StopWithoutRelease() {
+ if (!thread_)
+ return;
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&DevToolsHttpHandlerImpl::StopHandlerThread, this),
+ base::Bind(&DevToolsHttpHandlerImpl::ResetHandlerThread, this));
+}
+
GURL DevToolsHttpHandlerImpl::GetFrontendURL() {
- net::IPEndPoint ip_address;
- if (server_->GetLocalAddress(&ip_address))
+ if (!server_ip_address_)
return GURL();
- return GURL(std::string("http://") + ip_address.ToString() + frontend_url_);
+ return GURL(std::string("http://") + server_ip_address_->ToString() + frontend_url_);
}
static std::string PathWithoutParams(const std::string& path) {
@@ -255,6 +381,8 @@ static std::string GetMimeType(const std::string& filename) {
void DevToolsHttpHandlerImpl::OnHttpRequest(
int connection_id,
const net::HttpServerRequestInfo& info) {
+ server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);
+
if (info.path.find("/json") == 0) {
BrowserThread::PostTask(
BrowserThread::UI,
@@ -314,7 +442,7 @@ void DevToolsHttpHandlerImpl::OnHttpRequest(
int resource_id = DevToolsHttpHandler::GetFrontendResourceId(filename);
if (resource_id != -1) {
base::StringPiece data = GetContentClient()->GetDataResource(
- resource_id, ui::SCALE_FACTOR_NONE);
+ resource_id, ui::SCALE_FACTOR_NONE);
server_->Send200(connection_id, data.as_string(), mime_type);
return;
}
@@ -325,29 +453,6 @@ void DevToolsHttpHandlerImpl::OnHttpRequest(
void DevToolsHttpHandlerImpl::OnWebSocketRequest(
int connection_id,
const net::HttpServerRequestInfo& request) {
- std::string browser_prefix = "/devtools/browser";
- size_t browser_pos = request.path.find(browser_prefix);
- if (browser_pos == 0) {
- scoped_refptr<DevToolsBrowserTarget> browser_target =
- new DevToolsBrowserTarget(server_.get(), connection_id);
- browser_target->RegisterDomainHandler(
- devtools::Tracing::kName,
- new DevToolsTracingHandler(DevToolsTracingHandler::Browser),
- true /* handle on UI thread */);
- browser_target->RegisterDomainHandler(
- TetheringHandler::kDomain,
- new TetheringHandler(delegate_.get()),
- false /* handle on this thread */);
- browser_target->RegisterDomainHandler(
- devtools::SystemInfo::kName,
- new DevToolsSystemInfoHandler(),
- true /* handle on UI thread */);
- browser_targets_[connection_id] = browser_target;
-
- server_->AcceptWebSocket(connection_id, request);
- return;
- }
-
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -361,12 +466,6 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequest(
void DevToolsHttpHandlerImpl::OnWebSocketMessage(
int connection_id,
const std::string& data) {
- BrowserTargets::iterator it = browser_targets_.find(connection_id);
- if (it != browser_targets_.end()) {
- it->second->HandleMessage(data);
- return;
- }
-
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -378,13 +477,6 @@ void DevToolsHttpHandlerImpl::OnWebSocketMessage(
}
void DevToolsHttpHandlerImpl::OnClose(int connection_id) {
- BrowserTargets::iterator it = browser_targets_.find(connection_id);
- if (it != browser_targets_.end()) {
- it->second->Detach();
- browser_targets_.erase(it);
- return;
- }
-
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -476,9 +568,16 @@ void DevToolsHttpHandlerImpl::OnJsonRequestUI(
if (command == "list") {
std::string host = info.headers["host"];
AddRef(); // Balanced in OnTargetListReceived.
- delegate_->EnumerateTargets(
- base::Bind(&DevToolsHttpHandlerImpl::OnTargetListReceived,
- this, connection_id, host));
+ DevToolsManagerDelegate* manager_delegate =
+ DevToolsManager::GetInstance()->delegate();
+ if (manager_delegate) {
+ manager_delegate->EnumerateTargets(
+ base::Bind(&DevToolsHttpHandlerImpl::OnTargetListReceived,
+ this, connection_id, host));
+ } else {
+ DevToolsManagerDelegate::TargetList empty_list;
+ OnTargetListReceived(connection_id, host, empty_list);
+ }
return;
}
@@ -487,7 +586,11 @@ void DevToolsHttpHandlerImpl::OnJsonRequestUI(
query, net::UnescapeRule::URL_SPECIAL_CHARS));
if (!url.is_valid())
url = GURL(url::kAboutBlankURL);
- scoped_ptr<DevToolsTarget> target(delegate_->CreateNewTarget(url));
+ scoped_ptr<DevToolsTarget> target;
+ DevToolsManagerDelegate* manager_delegate =
+ DevToolsManager::GetInstance()->delegate();
+ if (manager_delegate)
+ target = manager_delegate->CreateNewTarget(url);
if (!target) {
SendJson(connection_id,
net::HTTP_INTERNAL_SERVER_ERROR,
@@ -548,13 +651,13 @@ void DevToolsHttpHandlerImpl::OnJsonRequestUI(
void DevToolsHttpHandlerImpl::OnTargetListReceived(
int connection_id,
const std::string& host,
- const DevToolsHttpHandlerDelegate::TargetList& targets) {
- DevToolsHttpHandlerDelegate::TargetList sorted_targets = targets;
+ const DevToolsManagerDelegate::TargetList& targets) {
+ DevToolsManagerDelegate::TargetList sorted_targets = targets;
std::sort(sorted_targets.begin(), sorted_targets.end(), TimeComparator);
STLDeleteValues(&target_map_);
base::ListValue list_value;
- for (DevToolsHttpHandlerDelegate::TargetList::const_iterator it =
+ for (DevToolsManagerDelegate::TargetList::const_iterator it =
sorted_targets.begin(); it != sorted_targets.end(); ++it) {
DevToolsTarget* target = *it;
target_map_[target->GetId()] = target;
@@ -573,7 +676,10 @@ DevToolsTarget* DevToolsHttpHandlerImpl::GetTarget(const std::string& id) {
void DevToolsHttpHandlerImpl::OnThumbnailRequestUI(
int connection_id, const GURL& page_url) {
- std::string data = delegate_->GetPageThumbnailData(page_url);
+ DevToolsManagerDelegate* manager_delegate =
+ DevToolsManager::GetInstance()->delegate();
+ std::string data =
+ manager_delegate ? manager_delegate->GetPageThumbnailData(page_url) : "";
if (!data.empty())
Send200(connection_id, data, "image/png");
else
@@ -591,6 +697,20 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
if (!thread_)
return;
+ std::string browser_prefix = "/devtools/browser";
+ size_t browser_pos = request.path.find(browser_prefix);
+ if (browser_pos == 0) {
+ BrowserTarget* browser_target = new BrowserTarget(
+ thread_->message_loop(), server_.get(), connection_id);
+ browser_target->RegisterHandler(
+ new TetheringHandler(delegate_.get(), thread_->message_loop_proxy()));
+ browser_target->RegisterHandler(
+ new DevToolsSystemInfoHandler());
+ browser_targets_[connection_id] = browser_target;
+ AcceptWebSocket(connection_id, request);
+ return;
+ }
+
size_t pos = request.path.find(kPageUrlPrefix);
if (pos != 0) {
Send404(connection_id);
@@ -601,7 +721,7 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
DevToolsTarget* target = GetTarget(page_id);
scoped_refptr<DevToolsAgentHost> agent =
target ? target->GetAgentHost() : NULL;
- if (!agent) {
+ if (!agent.get()) {
Send500(connection_id, "No such target id: " + page_id);
return;
}
@@ -612,12 +732,9 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
return;
}
- DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl(
- thread_->message_loop(), server_.get(), connection_id);
- connection_to_client_host_ui_[connection_id] = client_host;
-
- DevToolsManager::GetInstance()->
- RegisterDevToolsClientHostFor(agent, client_host);
+ DevToolsAgentHostClientImpl* client_host = new DevToolsAgentHostClientImpl(
+ thread_->message_loop(), server_.get(), connection_id, agent.get());
+ connection_to_client_ui_[connection_id] = client_host;
AcceptWebSocket(connection_id, request);
}
@@ -625,38 +742,56 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequestUI(
void DevToolsHttpHandlerImpl::OnWebSocketMessageUI(
int connection_id,
const std::string& data) {
- ConnectionToClientHostMap::iterator it =
- connection_to_client_host_ui_.find(connection_id);
- if (it == connection_to_client_host_ui_.end())
+ BrowserTargets::iterator browser_it = browser_targets_.find(connection_id);
+ if (browser_it != browser_targets_.end()) {
+ browser_it->second->HandleMessage(data);
+ return;
+ }
+
+ ConnectionToClientMap::iterator it =
+ connection_to_client_ui_.find(connection_id);
+ if (it == connection_to_client_ui_.end())
return;
- DevToolsManager* manager = DevToolsManager::GetInstance();
- manager->DispatchOnInspectorBackend(it->second, data);
+ DevToolsAgentHostClientImpl* client =
+ static_cast<DevToolsAgentHostClientImpl*>(it->second);
+ client->OnMessage(data);
}
void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) {
- ConnectionToClientHostMap::iterator it =
- connection_to_client_host_ui_.find(connection_id);
- if (it != connection_to_client_host_ui_.end()) {
- DevToolsClientHostImpl* client_host =
- static_cast<DevToolsClientHostImpl*>(it->second);
- DevToolsManager::GetInstance()->ClientHostClosing(client_host);
- delete client_host;
- connection_to_client_host_ui_.erase(connection_id);
+ BrowserTargets::iterator browser_it = browser_targets_.find(connection_id);
+ if (browser_it != browser_targets_.end()) {
+ delete browser_it->second;
+ browser_targets_.erase(connection_id);
+ return;
+ }
+
+ ConnectionToClientMap::iterator it =
+ connection_to_client_ui_.find(connection_id);
+ if (it != connection_to_client_ui_.end()) {
+ DevToolsAgentHostClientImpl* client =
+ static_cast<DevToolsAgentHostClientImpl*>(it->second);
+ delete client;
+ connection_to_client_ui_.erase(connection_id);
}
}
+void DevToolsHttpHandlerImpl::OnHttpServerInitialized(
+ const net::IPEndPoint& ip_address) {
+ server_ip_address_.reset(new net::IPEndPoint(ip_address));
+}
+
DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
- const net::StreamListenSocketFactory* socket_factory,
+ scoped_ptr<ServerSocketFactory> server_socket_factory,
const std::string& frontend_url,
DevToolsHttpHandlerDelegate* delegate,
const base::FilePath& active_port_output_directory)
: frontend_url_(frontend_url),
- socket_factory_(socket_factory),
+ server_socket_factory_(server_socket_factory.Pass()),
delegate_(delegate),
active_port_output_directory_(active_port_output_directory) {
if (frontend_url_.empty())
- frontend_url_ = "/devtools/devtools.html";
+ frontend_url_ = "/devtools/devtools.html";
// Balanced in ResetHandlerThreadAndRelease().
AddRef();
@@ -664,14 +799,30 @@ DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
// Runs on the handler thread
void DevToolsHttpHandlerImpl::Init() {
- server_ = new net::HttpServer(*socket_factory_.get(), this);
+ scoped_ptr<net::ServerSocket> server_socket =
+ server_socket_factory_->CreateAndListen();
+ if (!server_socket) {
+ LOG(ERROR) << "Cannot start http server for devtools. Stop devtools.";
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DevToolsHttpHandlerImpl::StopWithoutRelease, this));
+ return;
+ }
+
+ server_.reset(new net::HttpServer(server_socket.Pass(), this));
+ net::IPEndPoint ip_address;
+ server_->GetLocalAddress(&ip_address);
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&DevToolsHttpHandlerImpl::OnHttpServerInitialized,
+ this, ip_address));
if (!active_port_output_directory_.empty())
WriteActivePortToUserProfile();
}
// Runs on the handler thread
void DevToolsHttpHandlerImpl::Teardown() {
- server_ = NULL;
+ server_.reset();
}
// Runs on FILE thread to make sure that it is serialized against
@@ -729,7 +880,7 @@ void DevToolsHttpHandlerImpl::SendJson(int connection_id,
thread_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&net::HttpServer::SendResponse,
- server_.get(),
+ base::Unretained(server_.get()),
connection_id,
response));
}
@@ -742,7 +893,7 @@ void DevToolsHttpHandlerImpl::Send200(int connection_id,
thread_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&net::HttpServer::Send200,
- server_.get(),
+ base::Unretained(server_.get()),
connection_id,
data,
mime_type));
@@ -753,7 +904,9 @@ void DevToolsHttpHandlerImpl::Send404(int connection_id) {
return;
thread_->message_loop()->PostTask(
FROM_HERE,
- base::Bind(&net::HttpServer::Send404, server_.get(), connection_id));
+ base::Bind(&net::HttpServer::Send404,
+ base::Unretained(server_.get()),
+ connection_id));
}
void DevToolsHttpHandlerImpl::Send500(int connection_id,
@@ -762,7 +915,9 @@ void DevToolsHttpHandlerImpl::Send500(int connection_id,
return;
thread_->message_loop()->PostTask(
FROM_HERE,
- base::Bind(&net::HttpServer::Send500, server_.get(), connection_id,
+ base::Bind(&net::HttpServer::Send500,
+ base::Unretained(server_.get()),
+ connection_id,
message));
}
@@ -773,8 +928,16 @@ void DevToolsHttpHandlerImpl::AcceptWebSocket(
return;
thread_->message_loop()->PostTask(
FROM_HERE,
- base::Bind(&net::HttpServer::AcceptWebSocket, server_.get(),
- connection_id, request));
+ base::Bind(&net::HttpServer::SetSendBufferSize,
+ base::Unretained(server_.get()),
+ connection_id,
+ kSendBufferSizeForDevTools));
+ thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&net::HttpServer::AcceptWebSocket,
+ base::Unretained(server_.get()),
+ connection_id,
+ request));
}
base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget(
@@ -799,7 +962,10 @@ base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget(
if (favicon_url.is_valid())
dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
- if (!delegate_->GetPageThumbnailData(url).empty()) {
+ DevToolsManagerDelegate* manager_delegate =
+ DevToolsManager::GetInstance()->delegate();
+ if (manager_delegate &&
+ !manager_delegate->GetPageThumbnailData(url).empty()) {
dictionary->SetString(kTargetThumbnailUrlField,
std::string(kThumbUrlPrefix) + id);
}
diff --git a/chromium/content/browser/devtools/devtools_http_handler_impl.h b/chromium/content/browser/devtools/devtools_http_handler_impl.h
index 0d08d9897aa..5750dede955 100644
--- a/chromium/content/browser/devtools/devtools_http_handler_impl.h
+++ b/chromium/content/browser/devtools/devtools_http_handler_impl.h
@@ -13,8 +13,10 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
+#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_http_handler_delegate.h"
+#include "content/public/browser/devtools_manager_delegate.h"
#include "net/http/http_status_code.h"
#include "net/server/http_server.h"
@@ -26,15 +28,12 @@ class Value;
}
namespace net {
-class StreamListenSocketFactory;
+class ServerSocketFactory;
class URLRequestContextGetter;
}
namespace content {
-class DevToolsBrowserTarget;
-class DevToolsClientHost;
-
class DevToolsHttpHandlerImpl
: public DevToolsHttpHandler,
public base::RefCountedThreadSafe<DevToolsHttpHandlerImpl>,
@@ -43,27 +42,27 @@ class DevToolsHttpHandlerImpl
friend class base::RefCountedThreadSafe<DevToolsHttpHandlerImpl>;
friend class DevToolsHttpHandler;
- // Takes ownership over |socket_factory|.
- DevToolsHttpHandlerImpl(const net::StreamListenSocketFactory* socket_factory,
+ class BrowserTarget;
+
+ DevToolsHttpHandlerImpl(scoped_ptr<ServerSocketFactory> server_socket_factory,
const std::string& frontend_url,
DevToolsHttpHandlerDelegate* delegate,
const base::FilePath& active_port_output_directory);
- virtual ~DevToolsHttpHandlerImpl();
+ ~DevToolsHttpHandlerImpl() override;
void Start();
// DevToolsHttpHandler implementation.
- virtual void Stop() OVERRIDE;
- virtual GURL GetFrontendURL() OVERRIDE;
+ void Stop() override;
+ GURL GetFrontendURL() override;
// net::HttpServer::Delegate implementation.
- virtual void OnHttpRequest(int connection_id,
- const net::HttpServerRequestInfo& info) OVERRIDE;
- virtual void OnWebSocketRequest(
- int connection_id,
- const net::HttpServerRequestInfo& info) OVERRIDE;
- virtual void OnWebSocketMessage(int connection_id,
- const std::string& data) OVERRIDE;
- virtual void OnClose(int connection_id) OVERRIDE;
+ void OnConnect(int connection_id) override {}
+ void OnHttpRequest(int connection_id,
+ const net::HttpServerRequestInfo& info) override;
+ void OnWebSocketRequest(int connection_id,
+ const net::HttpServerRequestInfo& info) override;
+ void OnWebSocketMessage(int connection_id, const std::string& data) override;
+ void OnClose(int connection_id) override;
void OnJsonRequestUI(int connection_id,
const net::HttpServerRequestInfo& info);
@@ -81,7 +80,9 @@ class DevToolsHttpHandlerImpl
void OnTargetListReceived(
int connection_id,
const std::string& host,
- const DevToolsHttpHandlerDelegate::TargetList& targets);
+ const DevToolsManagerDelegate::TargetList& targets);
+
+ void OnHttpServerInitialized(const net::IPEndPoint& ip_address);
DevToolsTarget* GetTarget(const std::string& id);
@@ -90,6 +91,7 @@ class DevToolsHttpHandlerImpl
void StartHandlerThread();
void StopHandlerThread();
+ void StopWithoutRelease();
void WriteActivePortToUserProfile();
@@ -117,15 +119,16 @@ class DevToolsHttpHandlerImpl
scoped_ptr<base::Thread> thread_;
std::string frontend_url_;
- scoped_ptr<const net::StreamListenSocketFactory> socket_factory_;
- scoped_refptr<net::HttpServer> server_;
- typedef std::map<int, DevToolsClientHost*> ConnectionToClientHostMap;
- ConnectionToClientHostMap connection_to_client_host_ui_;
- scoped_ptr<DevToolsHttpHandlerDelegate> delegate_;
- base::FilePath active_port_output_directory_;
+ const scoped_ptr<ServerSocketFactory> server_socket_factory_;
+ scoped_ptr<net::HttpServer> server_;
+ scoped_ptr<net::IPEndPoint> server_ip_address_;
+ typedef std::map<int, DevToolsAgentHostClient*> ConnectionToClientMap;
+ ConnectionToClientMap connection_to_client_ui_;
+ const scoped_ptr<DevToolsHttpHandlerDelegate> delegate_;
+ const base::FilePath active_port_output_directory_;
typedef std::map<std::string, DevToolsTarget*> TargetMap;
TargetMap target_map_;
- typedef std::map<int, scoped_refptr<DevToolsBrowserTarget> > BrowserTargets;
+ typedef std::map<int, BrowserTarget*> BrowserTargets;
BrowserTargets browser_targets_;
DISALLOW_COPY_AND_ASSIGN(DevToolsHttpHandlerImpl);
};
diff --git a/chromium/content/browser/devtools/devtools_http_handler_unittest.cc b/chromium/content/browser/devtools/devtools_http_handler_unittest.cc
index 88710924c2a..28630ead75a 100644
--- a/chromium/content/browser/devtools/devtools_http_handler_unittest.cc
+++ b/chromium/content/browser/devtools/devtools_http_handler_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/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -13,7 +13,7 @@
#include "content/public/browser/devtools_target.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
-#include "net/socket/stream_listen_socket.h"
+#include "net/socket/server_socket.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -23,72 +23,70 @@ const int kDummyPort = 4321;
const base::FilePath::CharType kDevToolsActivePortFileName[] =
FILE_PATH_LITERAL("DevToolsActivePort");
-using net::StreamListenSocket;
-
-class DummyListenSocket : public StreamListenSocket,
- public StreamListenSocket::Delegate {
+class DummyServerSocket : public net::ServerSocket {
public:
- DummyListenSocket()
- : StreamListenSocket(net::kInvalidSocket, this) {}
-
- // StreamListenSocket::Delegate "implementation"
- virtual void DidAccept(StreamListenSocket* server,
- scoped_ptr<StreamListenSocket> connection) OVERRIDE {}
- virtual void DidRead(StreamListenSocket* connection,
- const char* data,
- int len) OVERRIDE {}
- virtual void DidClose(StreamListenSocket* sock) OVERRIDE {}
- protected:
- virtual ~DummyListenSocket() {}
- virtual void Accept() OVERRIDE {}
- virtual int GetLocalAddress(net::IPEndPoint* address) OVERRIDE {
+ DummyServerSocket() {}
+
+ // net::ServerSocket "implementation"
+ int Listen(const net::IPEndPoint& address, int backlog) override {
+ return net::OK;
+ }
+
+ int ListenWithAddressAndPort(const std::string& ip_address,
+ int port,
+ int backlog) override {
+ return net::OK;
+ }
+
+ int GetLocalAddress(net::IPEndPoint* address) const override {
net::IPAddressNumber number;
EXPECT_TRUE(net::ParseIPLiteralToNumber("127.0.0.1", &number));
*address = net::IPEndPoint(number, kDummyPort);
return net::OK;
}
+
+ int Accept(scoped_ptr<net::StreamSocket>* socket,
+ const net::CompletionCallback& callback) override {
+ return net::ERR_IO_PENDING;
+ }
};
-class DummyListenSocketFactory : public net::StreamListenSocketFactory {
+class DummyServerSocketFactory
+ : public DevToolsHttpHandler::ServerSocketFactory {
public:
- DummyListenSocketFactory(
- base::Closure quit_closure_1, base::Closure quit_closure_2)
- : quit_closure_1_(quit_closure_1), quit_closure_2_(quit_closure_2) {}
- virtual ~DummyListenSocketFactory() {
+ DummyServerSocketFactory(base::Closure quit_closure_1,
+ base::Closure quit_closure_2)
+ : DevToolsHttpHandler::ServerSocketFactory("", 0, 0),
+ quit_closure_1_(quit_closure_1),
+ quit_closure_2_(quit_closure_2) {}
+
+ ~DummyServerSocketFactory() override {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, quit_closure_2_);
}
- virtual scoped_ptr<StreamListenSocket> CreateAndListen(
- StreamListenSocket::Delegate* delegate) const OVERRIDE {
+ private:
+ scoped_ptr<net::ServerSocket> Create() const override {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, quit_closure_1_);
- return scoped_ptr<net::StreamListenSocket>(new DummyListenSocket());
+ return scoped_ptr<net::ServerSocket>(new DummyServerSocket());
}
- private:
+
base::Closure quit_closure_1_;
base::Closure quit_closure_2_;
};
class DummyDelegate : public DevToolsHttpHandlerDelegate {
public:
- virtual std::string GetDiscoveryPageHTML() OVERRIDE { return std::string(); }
- virtual bool BundlesFrontendResources() OVERRIDE { return true; }
- virtual base::FilePath GetDebugFrontendDir() OVERRIDE {
- return base::FilePath();
- }
- virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE {
- return std::string();
- }
- virtual scoped_ptr<DevToolsTarget> CreateNewTarget(const GURL& url) OVERRIDE {
- return scoped_ptr<DevToolsTarget>();
- }
- virtual void EnumerateTargets(TargetCallback callback) OVERRIDE {
- callback.Run(TargetList());
- }
- virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(
- net::StreamListenSocket::Delegate* delegate,
- std::string* name) OVERRIDE {
+ std::string GetDiscoveryPageHTML() override { return std::string(); }
+
+ bool BundlesFrontendResources() override { return true; }
+
+ base::FilePath GetDebugFrontendDir() override { return base::FilePath(); }
+
+ scoped_ptr<net::StreamListenSocket> CreateSocketForTethering(
+ net::StreamListenSocket::Delegate* delegate,
+ std::string* name) override {
return scoped_ptr<net::StreamListenSocket>();
}
};
@@ -100,14 +98,15 @@ class DevToolsHttpHandlerTest : public testing::Test {
DevToolsHttpHandlerTest()
: ui_thread_(BrowserThread::UI, &message_loop_) {
}
+
protected:
- virtual void SetUp() {
+ void SetUp() override {
file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE));
file_thread_->Start();
}
- virtual void TearDown() {
- file_thread_->Stop();
- }
+
+ void TearDown() override { file_thread_->Stop(); }
+
private:
base::MessageLoopForIO message_loop_;
BrowserThreadImpl ui_thread_;
@@ -116,13 +115,14 @@ class DevToolsHttpHandlerTest : public testing::Test {
TEST_F(DevToolsHttpHandlerTest, TestStartStop) {
base::RunLoop run_loop, run_loop_2;
+ scoped_ptr<DevToolsHttpHandler::ServerSocketFactory> factory(
+ new DummyServerSocketFactory(run_loop.QuitClosure(),
+ run_loop_2.QuitClosure()));
content::DevToolsHttpHandler* devtools_http_handler_ =
- content::DevToolsHttpHandler::Start(
- new DummyListenSocketFactory(run_loop.QuitClosure(),
- run_loop_2.QuitClosure()),
- std::string(),
- new DummyDelegate(),
- base::FilePath());
+ content::DevToolsHttpHandler::Start(factory.Pass(),
+ std::string(),
+ new DummyDelegate(),
+ base::FilePath());
// Our dummy socket factory will post a quit message once the server will
// become ready.
run_loop.Run();
@@ -135,13 +135,14 @@ TEST_F(DevToolsHttpHandlerTest, TestDevToolsActivePort) {
base::RunLoop run_loop, run_loop_2;
base::ScopedTempDir temp_dir;
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+ scoped_ptr<DevToolsHttpHandler::ServerSocketFactory> factory(
+ new DummyServerSocketFactory(run_loop.QuitClosure(),
+ run_loop_2.QuitClosure()));
content::DevToolsHttpHandler* devtools_http_handler_ =
- content::DevToolsHttpHandler::Start(
- new DummyListenSocketFactory(run_loop.QuitClosure(),
- run_loop_2.QuitClosure()),
- std::string(),
- new DummyDelegate(),
- temp_dir.path());
+ content::DevToolsHttpHandler::Start(factory.Pass(),
+ std::string(),
+ new DummyDelegate(),
+ temp_dir.path());
// Our dummy socket factory will post a quit message once the server will
// become ready.
run_loop.Run();
diff --git a/chromium/content/browser/devtools/devtools_manager.cc b/chromium/content/browser/devtools/devtools_manager.cc
new file mode 100644
index 00000000000..f405185a24d
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_manager.cc
@@ -0,0 +1,130 @@
+// 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/devtools/devtools_manager.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
+#include "content/browser/devtools/devtools_netlog_observer.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/devtools_target.h"
+
+namespace content {
+
+namespace {
+
+int kObserverThrottleInterval = 500; // ms
+
+} // namespace
+
+// static
+DevToolsManager* DevToolsManager::GetInstance() {
+ return Singleton<DevToolsManager>::get();
+}
+
+DevToolsManager::DevToolsManager()
+ : delegate_(GetContentClient()->browser()->GetDevToolsManagerDelegate()),
+ update_target_list_required_(false),
+ update_target_list_scheduled_(false),
+ update_target_list_callback_(base::Bind(
+ &DevToolsManager::UpdateTargetListThrottled,
+ base::Unretained(this))) {
+}
+
+DevToolsManager::~DevToolsManager() {
+ DCHECK(!attached_hosts_.size());
+ update_target_list_callback_.Cancel();
+}
+
+void DevToolsManager::RenderViewCreated(
+ WebContents* web_contents, RenderViewHost* rvh) {
+ if (observer_list_.might_have_observers()) {
+ // Force agent host creation.
+ DevToolsAgentHost::GetOrCreateFor(web_contents);
+ }
+}
+
+void DevToolsManager::AgentHostChanged(
+ scoped_refptr<DevToolsAgentHost> agent_host) {
+ bool was_attached =
+ attached_hosts_.find(agent_host.get()) != attached_hosts_.end();
+ if (agent_host->IsAttached() && !was_attached) {
+ if (!attached_hosts_.size()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DevToolsNetLogObserver::Attach));
+ }
+ attached_hosts_.insert(agent_host.get());
+ } else if (!agent_host->IsAttached() && was_attached) {
+ attached_hosts_.erase(agent_host.get());
+ if (!attached_hosts_.size()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&DevToolsNetLogObserver::Detach));
+ }
+ }
+
+ UpdateTargetList();
+}
+
+void DevToolsManager::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+ UpdateTargetList();
+}
+
+void DevToolsManager::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void DevToolsManager::UpdateTargetList() {
+ if (!observer_list_.might_have_observers())
+ return;
+
+ update_target_list_required_ = true;
+ if (!update_target_list_scheduled_)
+ UpdateTargetListThrottled();
+}
+
+void DevToolsManager::UpdateTargetListThrottled() {
+ if (!update_target_list_required_) {
+ update_target_list_scheduled_ = false;
+ return;
+ }
+
+ update_target_list_scheduled_ = true;
+ if (scheduler_.is_null()) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ update_target_list_callback_.callback(),
+ base::TimeDelta::FromMilliseconds(kObserverThrottleInterval));
+ } else {
+ scheduler_.Run(update_target_list_callback_.callback());
+ }
+
+ update_target_list_required_ = false;
+ if (!delegate_) {
+ Observer::TargetList empty_list;
+ NotifyTargetListChanged(empty_list);
+ return;
+ }
+ delegate_->EnumerateTargets(base::Bind(
+ &DevToolsManager::NotifyTargetListChanged,
+ base::Unretained(this)));
+}
+
+void DevToolsManager::NotifyTargetListChanged(
+ const Observer::TargetList& targets) {
+ FOR_EACH_OBSERVER(Observer, observer_list_, TargetListChanged(targets));
+ STLDeleteContainerPointers(targets.begin(), targets.end());
+}
+
+void DevToolsManager::SetSchedulerForTest(Scheduler scheduler) {
+ scheduler_ = scheduler;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_manager.h b/chromium/content/browser/devtools/devtools_manager.h
new file mode 100644
index 00000000000..979424f1c66
--- /dev/null
+++ b/chromium/content/browser/devtools/devtools_manager.h
@@ -0,0 +1,80 @@
+// 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_DEVTOOLS_DEVTOOLS_MANAGER_H_
+#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/cancelable_callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/singleton.h"
+#include "base/observer_list.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/devtools_manager_delegate.h"
+
+namespace content {
+
+class DevToolsAgentHost;
+class RenderViewHost;
+class WebContents;
+
+// This class is a singleton that manage global DevTools state for the whole
+// browser.
+class CONTENT_EXPORT DevToolsManager {
+ public:
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ typedef DevToolsManagerDelegate::TargetList TargetList;
+
+ // Called when any target information changed. Targets in the list are
+ // owned by DevToolsManager, so they should not be accessed outside of
+ // this method.
+ virtual void TargetListChanged(const TargetList& targets) {}
+ };
+
+ // Returns single instance of this class. The instance is destroyed on the
+ // browser main loop exit so this method MUST NOT be called after that point.
+ static DevToolsManager* GetInstance();
+
+ DevToolsManager();
+ virtual ~DevToolsManager();
+
+ DevToolsManagerDelegate* delegate() const { return delegate_.get(); }
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ void RenderViewCreated(WebContents* web_contents, RenderViewHost* rvh);
+ void AgentHostChanged(scoped_refptr<DevToolsAgentHost> agent_host);
+
+ typedef base::Callback<void(base::Closure)> Scheduler;
+ void SetSchedulerForTest(Scheduler scheduler);
+
+ private:
+ friend struct DefaultSingletonTraits<DevToolsManager>;
+
+ void UpdateTargetList();
+ void UpdateTargetListThrottled();
+ void NotifyTargetListChanged(const Observer::TargetList& targets);
+
+ scoped_ptr<DevToolsManagerDelegate> delegate_;
+ ObserverList<Observer> observer_list_;
+ std::set<DevToolsAgentHost*> attached_hosts_;
+ bool update_target_list_required_;
+ bool update_target_list_scheduled_;
+ base::CancelableClosure update_target_list_callback_;
+ Scheduler scheduler_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_H_
diff --git a/chromium/content/browser/devtools/devtools_manager_impl.cc b/chromium/content/browser/devtools/devtools_manager_impl.cc
deleted file mode 100644
index 3aafd1c2e2e..00000000000
--- a/chromium/content/browser/devtools/devtools_manager_impl.cc
+++ /dev/null
@@ -1,202 +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/devtools/devtools_manager_impl.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "content/browser/devtools/devtools_netlog_observer.h"
-#include "content/browser/devtools/render_view_devtools_agent_host.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_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/devtools_client_host.h"
-#include "content/public/browser/devtools_manager_delegate.h"
-
-namespace content {
-
-// static
-DevToolsManager* DevToolsManager::GetInstance() {
- return DevToolsManagerImpl::GetInstance();
-}
-
-// static
-DevToolsManagerImpl* DevToolsManagerImpl::GetInstance() {
- return Singleton<DevToolsManagerImpl>::get();
-}
-
-DevToolsManagerImpl::DevToolsManagerImpl()
- : delegate_(GetContentClient()->browser()->GetDevToolsManagerDelegate()) {
-}
-
-DevToolsManagerImpl::~DevToolsManagerImpl() {
- DCHECK(agent_to_client_host_.empty());
- DCHECK(client_to_agent_host_.empty());
-}
-
-void DevToolsManagerImpl::Inspect(BrowserContext* browser_context,
- DevToolsAgentHost* agent_host) {
- if (delegate_)
- delegate_->Inspect(browser_context, agent_host);
-}
-
-DevToolsClientHost* DevToolsManagerImpl::GetDevToolsClientHostFor(
- DevToolsAgentHostImpl* agent_host_impl) {
- AgentToClientHostMap::iterator it =
- agent_to_client_host_.find(agent_host_impl);
- if (it != agent_to_client_host_.end())
- return it->second;
- return NULL;
-}
-
-DevToolsAgentHost* DevToolsManagerImpl::GetDevToolsAgentHostFor(
- DevToolsClientHost* client_host) {
- ClientToAgentHostMap::iterator it = client_to_agent_host_.find(client_host);
- if (it != client_to_agent_host_.end())
- return it->second.get();
- return NULL;
-}
-
-void DevToolsManagerImpl::RegisterDevToolsClientHostFor(
- DevToolsAgentHost* agent_host,
- DevToolsClientHost* client_host) {
- DevToolsAgentHostImpl* agent_host_impl =
- static_cast<DevToolsAgentHostImpl*>(agent_host);
- DevToolsClientHost* old_client_host =
- GetDevToolsClientHostFor(agent_host_impl);
- if (old_client_host) {
- old_client_host->ReplacedWithAnotherClient();
- UnregisterDevToolsClientHostFor(agent_host_impl);
- }
- BindClientHost(agent_host_impl, client_host);
- agent_host_impl->Attach();
-}
-
-bool DevToolsManagerImpl::DispatchOnInspectorBackend(
- DevToolsClientHost* from,
- const std::string& message) {
- DevToolsAgentHost* agent_host = GetDevToolsAgentHostFor(from);
- if (!agent_host)
- return false;
- DevToolsAgentHostImpl* agent_host_impl =
- static_cast<DevToolsAgentHostImpl*>(agent_host);
- agent_host_impl->DispatchOnInspectorBackend(message);
- return true;
-}
-
-void DevToolsManagerImpl::DispatchOnInspectorFrontend(
- DevToolsAgentHost* agent_host,
- const std::string& message) {
- DevToolsAgentHostImpl* agent_host_impl =
- static_cast<DevToolsAgentHostImpl*>(agent_host);
- DevToolsClientHost* client_host = GetDevToolsClientHostFor(agent_host_impl);
- if (!client_host) {
- // Client window was closed while there were messages
- // being sent to it.
- return;
- }
- client_host->DispatchOnInspectorFrontend(message);
-}
-
-void DevToolsManagerImpl::ClientHostClosing(DevToolsClientHost* client_host) {
- DevToolsAgentHost* agent_host = GetDevToolsAgentHostFor(client_host);
- if (!agent_host)
- return;
- DevToolsAgentHostImpl* agent_host_impl =
- static_cast<DevToolsAgentHostImpl*>(agent_host);
- UnbindClientHost(agent_host_impl, client_host);
-}
-
-void DevToolsManagerImpl::AgentHostClosing(DevToolsAgentHostImpl* agent_host) {
- UnregisterDevToolsClientHostFor(agent_host);
-}
-
-void DevToolsManagerImpl::UnregisterDevToolsClientHostFor(
- DevToolsAgentHostImpl* agent_host_impl) {
- DevToolsClientHost* client_host = GetDevToolsClientHostFor(agent_host_impl);
- if (!client_host)
- return;
- UnbindClientHost(agent_host_impl, client_host);
- client_host->InspectedContentsClosing();
-}
-
-void DevToolsManagerImpl::BindClientHost(
- DevToolsAgentHostImpl* agent_host,
- DevToolsClientHost* client_host) {
- DCHECK(agent_to_client_host_.find(agent_host) ==
- agent_to_client_host_.end());
- DCHECK(client_to_agent_host_.find(client_host) ==
- client_to_agent_host_.end());
-
- if (client_to_agent_host_.empty()) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&DevToolsNetLogObserver::Attach));
- }
- agent_to_client_host_[agent_host] = client_host;
- client_to_agent_host_[client_host] = agent_host;
- agent_host->set_close_listener(this);
-}
-
-void DevToolsManagerImpl::UnbindClientHost(DevToolsAgentHostImpl* agent_host,
- DevToolsClientHost* client_host) {
- DCHECK(agent_host);
- scoped_refptr<DevToolsAgentHostImpl> protect(agent_host);
- DCHECK(agent_to_client_host_.find(agent_host)->second ==
- client_host);
- DCHECK(client_to_agent_host_.find(client_host)->second.get() == agent_host);
- agent_host->set_close_listener(NULL);
-
- agent_to_client_host_.erase(agent_host);
- client_to_agent_host_.erase(client_host);
-
- if (client_to_agent_host_.empty()) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&DevToolsNetLogObserver::Detach));
- }
- // Lazy agent hosts can be deleted from within detach.
- // Do not access agent_host below this line.
- agent_host->Detach();
-}
-
-void DevToolsManagerImpl::CloseAllClientHosts() {
- std::vector<DevToolsAgentHostImpl*> agents;
- for (AgentToClientHostMap::iterator it =
- agent_to_client_host_.begin();
- it != agent_to_client_host_.end(); ++it) {
- agents.push_back(it->first);
- }
- for (std::vector<DevToolsAgentHostImpl*>::iterator it = agents.begin();
- it != agents.end(); ++it) {
- UnregisterDevToolsClientHostFor(*it);
- }
-}
-
-void DevToolsManagerImpl::AddAgentStateCallback(const Callback& callback) {
- callbacks_.push_back(&callback);
-}
-
-void DevToolsManagerImpl::RemoveAgentStateCallback(const Callback& callback) {
- CallbackContainer::iterator it =
- std::find(callbacks_.begin(), callbacks_.end(), &callback);
- DCHECK(it != callbacks_.end());
- callbacks_.erase(it);
-}
-
-void DevToolsManagerImpl::NotifyObservers(DevToolsAgentHost* agent_host,
- bool attached) {
- CallbackContainer copy(callbacks_);
- if (delegate_)
- delegate_->DevToolsAgentStateChanged(agent_host, attached);
- for (CallbackContainer::iterator it = copy.begin(); it != copy.end(); ++it)
- (*it)->Run(agent_host, attached);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_manager_impl.h b/chromium/content/browser/devtools/devtools_manager_impl.h
deleted file mode 100644
index 19b6918518b..00000000000
--- a/chromium/content/browser/devtools/devtools_manager_impl.h
+++ /dev/null
@@ -1,113 +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_DEVTOOLS_DEVTOOLS_MANAGER_IMPL_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_IMPL_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/memory/singleton.h"
-#include "content/browser/devtools/devtools_agent_host_impl.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/devtools_client_host.h"
-#include "content/public/browser/devtools_manager.h"
-
-class GURL;
-
-namespace IPC {
-class Message;
-}
-
-namespace content {
-
-class BrowserContext;
-class DevToolsManagerDelegate;
-class RenderViewHost;
-
-// This class is a singleton that manages DevToolsClientHost instances and
-// routes messages between developer tools clients and agents.
-//
-// Methods below that accept inspected RenderViewHost as a parameter are
-// just convenience methods that call corresponding methods accepting
-// DevToolAgentHost.
-class CONTENT_EXPORT DevToolsManagerImpl
- : public DevToolsAgentHostImpl::CloseListener,
- public DevToolsManager {
- public:
- // Returns single instance of this class. The instance is destroyed on the
- // browser main loop exit so this method MUST NOT be called after that point.
- static DevToolsManagerImpl* GetInstance();
-
- DevToolsManagerImpl();
- virtual ~DevToolsManagerImpl();
-
- // Opens the inspector for |agent_host|.
- void Inspect(BrowserContext* browser_context, DevToolsAgentHost* agent_host);
-
- void DispatchOnInspectorFrontend(DevToolsAgentHost* agent_host,
- const std::string& message);
-
- DevToolsManagerDelegate* delegate() const { return delegate_.get(); }
-
- // DevToolsManager implementation
- virtual bool DispatchOnInspectorBackend(DevToolsClientHost* from,
- const std::string& message) OVERRIDE;
- virtual void CloseAllClientHosts() OVERRIDE;
- virtual DevToolsAgentHost* GetDevToolsAgentHostFor(
- DevToolsClientHost* client_host) OVERRIDE;
- virtual void RegisterDevToolsClientHostFor(
- DevToolsAgentHost* agent_host,
- DevToolsClientHost* client_host) OVERRIDE;
- virtual void ClientHostClosing(DevToolsClientHost* host) OVERRIDE;
- virtual void AddAgentStateCallback(const Callback& callback) OVERRIDE;
- virtual void RemoveAgentStateCallback(const Callback& callback) OVERRIDE;
-
- private:
- friend class DevToolsAgentHostImpl;
- friend class RenderViewDevToolsAgentHost;
- friend struct DefaultSingletonTraits<DevToolsManagerImpl>;
-
- // DevToolsAgentHost::CloseListener implementation.
- virtual void AgentHostClosing(DevToolsAgentHostImpl* host) OVERRIDE;
-
- void BindClientHost(DevToolsAgentHostImpl* agent_host,
- DevToolsClientHost* client_host);
- void UnbindClientHost(DevToolsAgentHostImpl* agent_host,
- DevToolsClientHost* client_host);
-
- DevToolsClientHost* GetDevToolsClientHostFor(
- DevToolsAgentHostImpl* agent_host);
-
- void UnregisterDevToolsClientHostFor(DevToolsAgentHostImpl* agent_host);
-
- void NotifyObservers(DevToolsAgentHost* agent_host, bool attached);
-
- // These two maps are for tracking dependencies between inspected contents and
- // their DevToolsClientHosts. They are useful for routing devtools messages
- // and allow us to have at most one devtools client host per contents.
- //
- // DevToolsManagerImpl starts listening to DevToolsClientHosts when they are
- // put into these maps and removes them when they are closing.
- typedef std::map<DevToolsAgentHostImpl*, DevToolsClientHost*>
- AgentToClientHostMap;
- AgentToClientHostMap agent_to_client_host_;
-
- typedef std::map<DevToolsClientHost*, scoped_refptr<DevToolsAgentHostImpl> >
- ClientToAgentHostMap;
- ClientToAgentHostMap client_to_agent_host_;
-
- typedef std::vector<const Callback*> CallbackContainer;
- CallbackContainer callbacks_;
-
- scoped_ptr<DevToolsManagerDelegate> delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(DevToolsManagerImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_IMPL_H_
diff --git a/chromium/content/browser/devtools/devtools_manager_unittest.cc b/chromium/content/browser/devtools/devtools_manager_unittest.cc
index 75c527388b4..988ffb752fb 100644
--- a/chromium/content/browser/devtools/devtools_manager_unittest.cc
+++ b/chromium/content/browser/devtools/devtools_manager_unittest.cc
@@ -5,15 +5,20 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
-#include "content/browser/devtools/devtools_manager_impl.h"
+#include "content/browser/devtools/devtools_manager.h"
+#include "content/browser/devtools/embedded_worker_devtools_manager.h"
#include "content/browser/devtools/render_view_devtools_agent_host.h"
+#include "content/browser/shared_worker/shared_worker_instance.h"
+#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/common/view_messages.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_external_agent_proxy.h"
#include "content/public/browser/devtools_external_agent_proxy_delegate.h"
+#include "content/public/browser/devtools_target.h"
#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/test/test_utils.h"
#include "content/test/test_content_browser_client.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
@@ -24,35 +29,38 @@ using base::TimeDelta;
namespace content {
namespace {
-class TestDevToolsClientHost : public DevToolsClientHost {
+class TestDevToolsClientHost : public DevToolsAgentHostClient {
public:
TestDevToolsClientHost()
: last_sent_message(NULL),
closed_(false) {
}
- virtual ~TestDevToolsClientHost() {
- EXPECT_TRUE(closed_);
- }
+ ~TestDevToolsClientHost() override { EXPECT_TRUE(closed_); }
- virtual void Close(DevToolsManager* manager) {
+ void Close() {
EXPECT_FALSE(closed_);
close_counter++;
- manager->ClientHostClosing(this);
+ agent_host_->DetachClient();
closed_ = true;
}
- virtual void InspectedContentsClosing() OVERRIDE {
+
+ void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {
FAIL();
}
- virtual void DispatchOnInspectorFrontend(
- const std::string& message) OVERRIDE {
+ void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+ const std::string& message) override {
last_sent_message = &message;
}
- virtual void ReplacedWithAnotherClient() OVERRIDE {
+ void InspectAgentHost(DevToolsAgentHost* agent_host) {
+ agent_host_ = agent_host;
+ agent_host_->AttachClient(this);
}
+ DevToolsAgentHost* agent_host() { return agent_host_.get(); }
+
static void ResetCounters() {
close_counter = 0;
}
@@ -63,6 +71,7 @@ class TestDevToolsClientHost : public DevToolsClientHost {
private:
bool closed_;
+ scoped_refptr<DevToolsAgentHost> agent_host_;
DISALLOW_COPY_AND_ASSIGN(TestDevToolsClientHost);
};
@@ -75,7 +84,7 @@ class TestWebContentsDelegate : public WebContentsDelegate {
TestWebContentsDelegate() : renderer_unresponsive_received_(false) {}
// Notification that the contents is hung.
- virtual void RendererUnresponsive(WebContents* source) OVERRIDE {
+ void RendererUnresponsive(WebContents* source) override {
renderer_unresponsive_received_ = true;
}
@@ -87,53 +96,143 @@ class TestWebContentsDelegate : public WebContentsDelegate {
bool renderer_unresponsive_received_;
};
+class TestTarget : public DevToolsTarget {
+ public:
+ explicit TestTarget(scoped_refptr<DevToolsAgentHost> agent_host)
+ : agent_host_(agent_host) {}
+ ~TestTarget() override {}
+
+ std::string GetId() const override { return agent_host_->GetId(); }
+ std::string GetParentId() const override { return std::string(); }
+ std::string GetType() const override { return std::string(); }
+ std::string GetTitle() const override { return agent_host_->GetTitle(); }
+ std::string GetDescription() const override { return std::string(); }
+ GURL GetURL() const override { return agent_host_->GetURL(); }
+ GURL GetFaviconURL() const override { return GURL(); }
+ base::TimeTicks GetLastActivityTime() const override {
+ return base::TimeTicks();
+ }
+ bool IsAttached() const override { return agent_host_->IsAttached(); }
+ scoped_refptr<DevToolsAgentHost> GetAgentHost() const override {
+ return agent_host_;
+ }
+ bool Activate() const override { return agent_host_->Activate(); }
+ bool Close() const override { return agent_host_->Close(); }
+
+ private:
+ scoped_refptr<DevToolsAgentHost> agent_host_;
+};
+
+class TestDevToolsManagerDelegate : public DevToolsManagerDelegate {
+ public:
+ ~TestDevToolsManagerDelegate() override {}
+
+ void Inspect(BrowserContext* browser_context,
+ DevToolsAgentHost* agent_host) override {}
+
+ void DevToolsAgentStateChanged(DevToolsAgentHost* agent_host,
+ bool attached) override {}
+
+ base::DictionaryValue* HandleCommand(
+ DevToolsAgentHost* agent_host,
+ base::DictionaryValue* command) override {
+ return NULL;
+ }
+
+ scoped_ptr<DevToolsTarget> CreateNewTarget(const GURL& url) override {
+ return scoped_ptr<DevToolsTarget>();
+ }
+
+ void EnumerateTargets(TargetCallback callback) override {
+ TargetList result;
+ DevToolsAgentHost::List agents = DevToolsAgentHost::GetOrCreateAll();
+ for (DevToolsAgentHost::List::iterator it = agents.begin();
+ it != agents.end(); ++it) {
+ if ((*it)->GetType() == DevToolsAgentHost::TYPE_WEB_CONTENTS)
+ result.insert(result.begin(), new TestTarget(*it));
+ else
+ result.push_back(new TestTarget(*it));
+ }
+ callback.Run(result);
+ }
+
+ std::string GetPageThumbnailData(const GURL& url) override {
+ return std::string();
+ }
+};
+
+class ContentBrowserClientWithDevTools : public TestContentBrowserClient {
+ public:
+ ~ContentBrowserClientWithDevTools() override {}
+ content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override {
+ return new TestDevToolsManagerDelegate();
+ }
+};
+
+class TestDevToolsManagerObserver : public DevToolsManager::Observer {
+ public:
+ TestDevToolsManagerObserver()
+ : updates_count_(0) {}
+ ~TestDevToolsManagerObserver() override {}
+
+ int updates_count() { return updates_count_; }
+ const std::vector<scoped_refptr<DevToolsAgentHost>> hosts() {
+ return hosts_;
+ }
+
+ void TargetListChanged(const TargetList& targets) override {
+ updates_count_++;
+ hosts_.clear();
+ for (TargetList::const_iterator it = targets.begin();
+ it != targets.end(); ++it) {
+ hosts_.push_back((*it)->GetAgentHost());
+ }
+ }
+
+ private:
+ int updates_count_;
+ std::vector<scoped_refptr<DevToolsAgentHost>> hosts_;
+};
+
} // namespace
class DevToolsManagerTest : public RenderViewHostImplTestHarness {
+ public:
+ DevToolsManagerTest()
+ : old_browser_client_(NULL) {}
+
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
TestDevToolsClientHost::ResetCounters();
+ old_browser_client_ = SetBrowserClientForTesting(&browser_client_);
+ }
+
+ void TearDown() override {
+ SetBrowserClientForTesting(old_browser_client_);
+ RenderViewHostImplTestHarness::TearDown();
}
+
+ ContentBrowserClientWithDevTools browser_client_;
+ ContentBrowserClient* old_browser_client_;
};
TEST_F(DevToolsManagerTest, OpenAndManuallyCloseDevToolsClientHost) {
- DevToolsManager* manager = DevToolsManager::GetInstance();
-
scoped_refptr<DevToolsAgentHost> agent(
- DevToolsAgentHost::GetOrCreateFor(rvh()));
+ DevToolsAgentHost::GetOrCreateFor(web_contents()));
EXPECT_FALSE(agent->IsAttached());
TestDevToolsClientHost client_host;
- manager->RegisterDevToolsClientHostFor(agent.get(), &client_host);
+ client_host.InspectAgentHost(agent.get());
// Test that the connection is established.
EXPECT_TRUE(agent->IsAttached());
- EXPECT_EQ(agent, manager->GetDevToolsAgentHostFor(&client_host));
EXPECT_EQ(0, TestDevToolsClientHost::close_counter);
- client_host.Close(manager);
+ client_host.Close();
EXPECT_EQ(1, TestDevToolsClientHost::close_counter);
EXPECT_FALSE(agent->IsAttached());
}
-TEST_F(DevToolsManagerTest, ForwardMessageToClient) {
- DevToolsManagerImpl* manager = DevToolsManagerImpl::GetInstance();
-
- TestDevToolsClientHost client_host;
- scoped_refptr<DevToolsAgentHost> agent_host(
- DevToolsAgentHost::GetOrCreateFor(rvh()));
- manager->RegisterDevToolsClientHostFor(agent_host.get(), &client_host);
- EXPECT_EQ(0, TestDevToolsClientHost::close_counter);
-
- std::string m = "test message";
- agent_host = DevToolsAgentHost::GetOrCreateFor(rvh());
- manager->DispatchOnInspectorFrontend(agent_host.get(), m);
- EXPECT_TRUE(&m == client_host.last_sent_message);
-
- client_host.Close(manager);
- EXPECT_EQ(1, TestDevToolsClientHost::close_counter);
-}
-
TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) {
TestRenderViewHost* inspected_rvh = test_rvh();
inspected_rvh->set_render_view_created(true);
@@ -142,10 +241,9 @@ TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) {
contents()->SetDelegate(&delegate);
TestDevToolsClientHost client_host;
- scoped_refptr<DevToolsAgentHost> agent_host(
- DevToolsAgentHost::GetOrCreateFor(inspected_rvh));
- DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
- agent_host.get(), &client_host);
+ scoped_refptr<DevToolsAgentHost> agent_host(DevToolsAgentHost::GetOrCreateFor(
+ WebContents::FromRenderViewHost(inspected_rvh)));
+ client_host.InspectAgentHost(agent_host.get());
// Start with a short timeout.
inspected_rvh->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
@@ -158,7 +256,7 @@ TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) {
EXPECT_FALSE(delegate.renderer_unresponsive_received());
// Now close devtools and check that the notification is delivered.
- client_host.Close(DevToolsManager::GetInstance());
+ client_host.Close();
// Start with a short timeout.
inspected_rvh->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
// Wait long enough for first timeout and see if it fired.
@@ -176,31 +274,32 @@ TEST_F(DevToolsManagerTest, ReattachOnCancelPendingNavigation) {
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(rvh(), 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(
+ contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
TestDevToolsClientHost client_host;
- DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
- devtools_manager->RegisterDevToolsClientHostFor(
- DevToolsAgentHost::GetOrCreateFor(rvh()).get(), &client_host);
+ client_host.InspectAgentHost(
+ DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
// Navigate to new site which should get a new RenderViewHost.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_EQ(devtools_manager->GetDevToolsAgentHostFor(&client_host),
- DevToolsAgentHost::GetOrCreateFor(pending_rvh()));
+ EXPECT_EQ(client_host.agent_host(),
+ DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
// Interrupt pending navigation and navigate back to the original site.
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(rvh(), 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(
+ contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(devtools_manager->GetDevToolsAgentHostFor(&client_host),
- DevToolsAgentHost::GetOrCreateFor(rvh()));
- client_host.Close(DevToolsManager::GetInstance());
+ EXPECT_EQ(client_host.agent_host(),
+ DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
+ client_host.Close();
}
class TestExternalAgentDelegate: public DevToolsExternalAgentProxyDelegate {
@@ -216,20 +315,18 @@ class TestExternalAgentDelegate: public DevToolsExternalAgentProxyDelegate {
EXPECT_EQ(count, event_counter_[name]);
}
- virtual void Attach(DevToolsExternalAgentProxy* proxy) OVERRIDE {
+ void Attach(DevToolsExternalAgentProxy* proxy) override {
recordEvent("Attach");
};
- virtual void Detach() OVERRIDE {
- recordEvent("Detach");
- };
+ void Detach() override { recordEvent("Detach"); };
- virtual void SendMessageToBackend(const std::string& message) OVERRIDE {
+ void SendMessageToBackend(const std::string& message) override {
recordEvent(std::string("SendMessageToBackend.") + message);
};
public :
- virtual ~TestExternalAgentDelegate() {
+ ~TestExternalAgentDelegate() override {
expectEvent(1, "Attach");
expectEvent(1, "Detach");
expectEvent(0, "SendMessageToBackend.message0");
@@ -245,16 +342,119 @@ TEST_F(DevToolsManagerTest, TestExternalProxy) {
DevToolsAgentHost::Create(delegate);
EXPECT_EQ(agent_host, DevToolsAgentHost::GetForId(agent_host->GetId()));
- DevToolsManager* manager = DevToolsManager::GetInstance();
-
TestDevToolsClientHost client_host;
- manager->RegisterDevToolsClientHostFor(agent_host.get(), &client_host);
+ client_host.InspectAgentHost(agent_host.get());
+ agent_host->DispatchProtocolMessage("message1");
+ agent_host->DispatchProtocolMessage("message2");
+ agent_host->DispatchProtocolMessage("message2");
- manager->DispatchOnInspectorBackend(&client_host, "message1");
- manager->DispatchOnInspectorBackend(&client_host, "message2");
- manager->DispatchOnInspectorBackend(&client_host, "message2");
+ client_host.Close();
+}
- client_host.Close(manager);
+class TestDevToolsManagerScheduler {
+ public:
+ DevToolsManager::Scheduler callback() {
+ return base::Bind(&TestDevToolsManagerScheduler::Schedule,
+ base::Unretained(this));
+ }
+
+ void Run() {
+ ASSERT_FALSE(closure_.is_null());
+ base::Closure copy = closure_;
+ closure_.Reset();
+ copy.Run();
+ }
+
+ bool IsEmpty() {
+ return closure_.is_null();
+ }
+
+ private:
+ void Schedule(base::Closure closure) {
+ EXPECT_TRUE(closure_.is_null());
+ closure_ = closure;
+ }
+
+ base::Closure closure_;
+};
+
+TEST_F(DevToolsManagerTest, TestObserver) {
+ GURL url1("data:text/html,<body>Body1</body>");
+ GURL url2("data:text/html,<body>Body2</body>");
+ GURL url3("data:text/html,<body>Body3</body>");
+
+ TestDevToolsManagerScheduler scheduler;
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+ manager->SetSchedulerForTest(scheduler.callback());
+
+ contents()->NavigateAndCommit(url1);
+ RunAllPendingInMessageLoop();
+
+ scoped_ptr<TestDevToolsManagerObserver> observer(
+ new TestDevToolsManagerObserver());
+ manager->AddObserver(observer.get());
+ // Added observer should get an update.
+ EXPECT_EQ(1, observer->updates_count());
+ ASSERT_EQ(1u, observer->hosts().size());
+ EXPECT_EQ(contents(), observer->hosts()[0]->GetWebContents());
+ EXPECT_EQ(url1.spec(), observer->hosts()[0]->GetURL().spec());
+
+ contents()->NavigateAndCommit(url2);
+ RunAllPendingInMessageLoop();
+ contents()->NavigateAndCommit(url3);
+ scheduler.Run();
+ // Updates should be coalesced.
+ EXPECT_EQ(2, observer->updates_count());
+ ASSERT_EQ(1u, observer->hosts().size());
+ EXPECT_EQ(contents(), observer->hosts()[0]->GetWebContents());
+ EXPECT_EQ(url3.spec(), observer->hosts()[0]->GetURL().spec());
+
+ // Check there were no extra updates.
+ scheduler.Run();
+ EXPECT_TRUE(scheduler.IsEmpty());
+ EXPECT_EQ(2, observer->updates_count());
+
+ scoped_ptr<WorkerStoragePartition> partition(new WorkerStoragePartition(
+ browser_context()->GetRequestContext(),
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL));
+ WorkerStoragePartitionId partition_id(*partition.get());
+
+ GURL shared_worker_url("http://example.com/shared_worker.js");
+ SharedWorkerInstance shared_worker(
+ shared_worker_url,
+ base::string16(),
+ base::string16(),
+ blink::WebContentSecurityPolicyTypeReport,
+ browser_context()->GetResourceContext(),
+ partition_id);
+ EmbeddedWorkerDevToolsManager::GetInstance()->SharedWorkerCreated(
+ 1, 1, shared_worker);
+ contents()->NavigateAndCommit(url2);
+
+ EXPECT_EQ(3, observer->updates_count());
+ ASSERT_EQ(2u, observer->hosts().size());
+ EXPECT_EQ(contents(), observer->hosts()[0]->GetWebContents());
+ EXPECT_EQ(url2.spec(), observer->hosts()[0]->GetURL().spec());
+ EXPECT_EQ(DevToolsAgentHost::TYPE_SHARED_WORKER,
+ observer->hosts()[1]->GetType());
+ EXPECT_EQ(shared_worker_url.spec(), observer->hosts()[1]->GetURL().spec());
+
+ EmbeddedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(1, 1);
+ scheduler.Run();
+ EXPECT_EQ(4, observer->updates_count());
+ ASSERT_EQ(1u, observer->hosts().size());
+ EXPECT_EQ(contents(), observer->hosts()[0]->GetWebContents());
+ EXPECT_EQ(url2.spec(), observer->hosts()[0]->GetURL().spec());
+
+ // Check there were no extra updates.
+ scheduler.Run();
+ EXPECT_TRUE(scheduler.IsEmpty());
+ EXPECT_EQ(4, observer->updates_count());
+
+ manager->RemoveObserver(observer.get());
+
+ EXPECT_TRUE(scheduler.IsEmpty());
+ manager->SetSchedulerForTest(DevToolsManager::Scheduler());
}
} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_netlog_observer.h b/chromium/content/browser/devtools/devtools_netlog_observer.h
index f063a3d432c..2155f06a11f 100644
--- a/chromium/content/browser/devtools/devtools_netlog_observer.h
+++ b/chromium/content/browser/devtools/devtools_netlog_observer.h
@@ -29,7 +29,7 @@ class DevToolsNetLogObserver : public net::NetLog::ThreadSafeObserver {
public:
// net::NetLog::ThreadSafeObserver implementation:
- virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
+ void OnAddEntry(const net::NetLog::Entry& entry) override;
void OnAddURLRequestEntry(const net::NetLog::Entry& entry);
@@ -46,7 +46,7 @@ class DevToolsNetLogObserver : public net::NetLog::ThreadSafeObserver {
static DevToolsNetLogObserver* instance_;
DevToolsNetLogObserver();
- virtual ~DevToolsNetLogObserver();
+ ~DevToolsNetLogObserver() override;
ResourceInfo* GetResourceInfo(uint32 id);
diff --git a/chromium/content/browser/devtools/devtools_power_handler.cc b/chromium/content/browser/devtools/devtools_power_handler.cc
deleted file mode 100644
index 43772b47607..00000000000
--- a/chromium/content/browser/devtools/devtools_power_handler.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/devtools/devtools_power_handler.h"
-
-#include "base/bind.h"
-#include "base/values.h"
-#include "content/browser/devtools/devtools_protocol_constants.h"
-#include "content/browser/power_profiler/power_profiler_service.h"
-
-namespace content {
-
-DevToolsPowerHandler::DevToolsPowerHandler() {
- RegisterCommandHandler(devtools::Power::start::kName,
- base::Bind(&DevToolsPowerHandler::OnStart,
- base::Unretained(this)));
- RegisterCommandHandler(devtools::Power::end::kName,
- base::Bind(&DevToolsPowerHandler::OnEnd,
- base::Unretained(this)));
- RegisterCommandHandler(devtools::Power::canProfilePower::kName,
- base::Bind(&DevToolsPowerHandler::OnCanProfilePower,
- base::Unretained(this)));
-}
-
-DevToolsPowerHandler::~DevToolsPowerHandler() {
- PowerProfilerService::GetInstance()->RemoveObserver(this);
-}
-
-void DevToolsPowerHandler::OnPowerEvent(const PowerEventVector& events) {
- base::DictionaryValue* params = new base::DictionaryValue();
- base::ListValue* event_list = new base::ListValue();
-
- std::vector<PowerEvent>::const_iterator iter;
- for (iter = events.begin(); iter != events.end(); ++iter) {
- base::DictionaryValue* event_body = new base::DictionaryValue();
-
- DCHECK(iter->type < PowerEvent::ID_COUNT);
- event_body->SetString("type", kPowerTypeNames[iter->type]);
- // Use internal value to be consistent with Blink's
- // monotonicallyIncreasingTime.
- event_body->SetDouble("timestamp", iter->time.ToInternalValue() /
- static_cast<double>(base::Time::kMicrosecondsPerMillisecond));
- event_body->SetDouble("value", iter->value);
- event_list->Append(event_body);
- }
-
- params->Set(devtools::Power::dataAvailable::kParamValue, event_list);
- SendNotification(devtools::Power::dataAvailable::kName, params);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsPowerHandler::OnStart(
- scoped_refptr<DevToolsProtocol::Command> command) {
- if (PowerProfilerService::GetInstance()->IsAvailable()) {
- PowerProfilerService::GetInstance()->AddObserver(this);
- return command->SuccessResponse(NULL);
- }
-
- return command->InternalErrorResponse("Power profiler service unavailable");
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsPowerHandler::OnEnd(scoped_refptr<DevToolsProtocol::Command> command) {
- if (PowerProfilerService::GetInstance()->IsAvailable()) {
- PowerProfilerService::GetInstance()->RemoveObserver(this);
- return command->SuccessResponse(NULL);
- }
-
- return command->InternalErrorResponse("Power profiler service unavailable");
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsPowerHandler::OnCanProfilePower(
- scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* result = new base::DictionaryValue();
- result->SetBoolean(devtools::kResult,
- PowerProfilerService::GetInstance()->IsAvailable());
-
- return command->SuccessResponse(result);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_power_handler.h b/chromium/content/browser/devtools/devtools_power_handler.h
deleted file mode 100644
index f645392a199..00000000000
--- a/chromium/content/browser/devtools/devtools_power_handler.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_POWER_HANDLER_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_POWER_HANDLER_H_
-
-#include "base/time/time.h"
-#include "content/browser/devtools/devtools_protocol.h"
-#include "content/browser/power_profiler/power_profiler_observer.h"
-
-namespace content {
-
-// This class provides power information to DevTools.
-class DevToolsPowerHandler
- : public DevToolsProtocol::Handler,
- public PowerProfilerObserver {
- public:
- DevToolsPowerHandler();
- virtual ~DevToolsPowerHandler();
-
- // PowerProfilerObserver override.
- virtual void OnPowerEvent(const PowerEventVector&) OVERRIDE;
-
- private:
- scoped_refptr<DevToolsProtocol::Response> OnStart(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> OnEnd(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> OnCanProfilePower(
- scoped_refptr<DevToolsProtocol::Command> command);
-
- DISALLOW_COPY_AND_ASSIGN(DevToolsPowerHandler);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_POWER_HANDLER_H_
diff --git a/chromium/content/browser/devtools/devtools_protocol.cc b/chromium/content/browser/devtools/devtools_protocol.cc
index 5e127f1dcba..e3d531489d5 100644
--- a/chromium/content/browser/devtools/devtools_protocol.cc
+++ b/chromium/content/browser/devtools/devtools_protocol.cc
@@ -119,8 +119,11 @@ std::string DevToolsProtocol::Response::Serialize() {
error_object->SetInteger(kErrorCodeParam, error_code_);
if (!error_message_.empty())
error_object->SetString(kErrorMessageParam, error_message_);
- } else if (result_) {
- response.Set(kResultParam, result_->DeepCopy());
+ } else {
+ if (result_)
+ response.Set(kResultParam, result_->DeepCopy());
+ else
+ response.Set(kResultParam, new base::DictionaryValue());
}
std::string json_response;
diff --git a/chromium/content/browser/devtools/devtools_protocol.h b/chromium/content/browser/devtools/devtools_protocol.h
index cbc075b3715..50dc8a649dc 100644
--- a/chromium/content/browser/devtools/devtools_protocol.h
+++ b/chromium/content/browser/devtools/devtools_protocol.h
@@ -50,7 +50,7 @@ class DevToolsProtocol {
public:
int id() { return id_; }
- virtual std::string Serialize() OVERRIDE;
+ std::string Serialize() override;
// Creates success response. Takes ownership of |result|.
scoped_refptr<Response> SuccessResponse(base::DictionaryValue* result);
@@ -71,7 +71,7 @@ class DevToolsProtocol {
scoped_refptr<Response> AsyncResponsePromise();
protected:
- virtual ~Command();
+ ~Command() override;
private:
friend class DevToolsProtocol;
@@ -109,12 +109,12 @@ class DevToolsProtocol {
class Notification : public Message {
public:
-
- virtual std::string Serialize() OVERRIDE;
+ std::string Serialize() override;
private:
friend class DevToolsProtocol;
- virtual ~Notification();
+ friend class DevToolsProtocolClient;
+ ~Notification() override;
// Takes ownership of |params|.
Notification(const std::string& method,
diff --git a/chromium/content/browser/devtools/devtools_system_info_handler.cc b/chromium/content/browser/devtools/devtools_system_info_handler.cc
index 6e0336d2c08..15261b3e466 100644
--- a/chromium/content/browser/devtools/devtools_system_info_handler.cc
+++ b/chromium/content/browser/devtools/devtools_system_info_handler.cc
@@ -34,45 +34,43 @@ class AuxGPUInfoEnumerator : public gpu::GPUInfo::Enumerator {
: dictionary_(dictionary),
in_aux_attributes_(false) { }
- virtual void AddInt64(const char* name, int64 value) OVERRIDE {
+ void AddInt64(const char* name, int64 value) override {
if (in_aux_attributes_)
dictionary_->SetDouble(name, value);
}
- virtual void AddInt(const char* name, int value) OVERRIDE {
+ void AddInt(const char* name, int value) override {
if (in_aux_attributes_)
dictionary_->SetInteger(name, value);
}
- virtual void AddString(const char* name, const std::string& value) OVERRIDE {
+ void AddString(const char* name, const std::string& value) override {
if (in_aux_attributes_)
dictionary_->SetString(name, value);
}
- virtual void AddBool(const char* name, bool value) OVERRIDE {
+ void AddBool(const char* name, bool value) override {
if (in_aux_attributes_)
dictionary_->SetBoolean(name, value);
}
- virtual void AddTimeDeltaInSecondsF(const char* name,
- const base::TimeDelta& value) OVERRIDE {
+ void AddTimeDeltaInSecondsF(const char* name,
+ const base::TimeDelta& value) override {
if (in_aux_attributes_)
dictionary_->SetDouble(name, value.InSecondsF());
}
- virtual void BeginGPUDevice() OVERRIDE {
- }
+ void BeginGPUDevice() override {}
- virtual void EndGPUDevice() OVERRIDE {
- }
+ void EndGPUDevice() override {}
- virtual void BeginAuxAttributes() OVERRIDE {
- in_aux_attributes_ = true;
- }
+ void BeginVideoEncodeAcceleratorSupportedProfile() override {}
- virtual void EndAuxAttributes() OVERRIDE {
- in_aux_attributes_ = false;
- }
+ void EndVideoEncodeAcceleratorSupportedProfile() override {}
+
+ void BeginAuxAttributes() override { in_aux_attributes_ = true; }
+
+ void EndAuxAttributes() override { in_aux_attributes_ = false; }
private:
base::DictionaryValue* dictionary_;
diff --git a/chromium/content/browser/devtools/devtools_system_info_handler.h b/chromium/content/browser/devtools/devtools_system_info_handler.h
index afaf042b5b6..6217f7aef1c 100644
--- a/chromium/content/browser/devtools/devtools_system_info_handler.h
+++ b/chromium/content/browser/devtools/devtools_system_info_handler.h
@@ -14,7 +14,7 @@ class DevToolsSystemInfoHandler
: public DevToolsProtocol::Handler {
public:
DevToolsSystemInfoHandler();
- virtual ~DevToolsSystemInfoHandler();
+ ~DevToolsSystemInfoHandler() override;
private:
scoped_refptr<DevToolsProtocol::Response> OnGetInfo(
diff --git a/chromium/content/browser/devtools/devtools_tracing_handler.cc b/chromium/content/browser/devtools/devtools_tracing_handler.cc
deleted file mode 100644
index 7d308642212..00000000000
--- a/chromium/content/browser/devtools/devtools_tracing_handler.cc
+++ /dev/null
@@ -1,248 +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/devtools/devtools_tracing_handler.h"
-
-#include <cmath>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/file_util.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/location.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/values.h"
-#include "content/browser/devtools/devtools_http_handler_impl.h"
-#include "content/browser/devtools/devtools_protocol_constants.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/tracing_controller.h"
-
-namespace content {
-
-namespace {
-
-const char kRecordUntilFull[] = "record-until-full";
-const char kRecordContinuously[] = "record-continuously";
-const char kEnableSampling[] = "enable-sampling";
-
-void ReadFile(
- const base::FilePath& path,
- const base::Callback<void(const scoped_refptr<base::RefCountedString>&)>
- callback) {
- std::string trace_data;
- if (!base::ReadFileToString(path, &trace_data))
- LOG(ERROR) << "Failed to read file: " << path.value();
- base::DeleteFile(path, false);
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(callback, make_scoped_refptr(
- base::RefCountedString::TakeString(&trace_data))));
-}
-
-} // namespace
-
-DevToolsTracingHandler::DevToolsTracingHandler(
- DevToolsTracingHandler::Target target)
- : weak_factory_(this), target_(target) {
- RegisterCommandHandler(devtools::Tracing::start::kName,
- base::Bind(&DevToolsTracingHandler::OnStart,
- base::Unretained(this)));
- RegisterCommandHandler(devtools::Tracing::end::kName,
- base::Bind(&DevToolsTracingHandler::OnEnd,
- base::Unretained(this)));
- RegisterCommandHandler(devtools::Tracing::getCategories::kName,
- base::Bind(&DevToolsTracingHandler::OnGetCategories,
- base::Unretained(this)));
-}
-
-DevToolsTracingHandler::~DevToolsTracingHandler() {
-}
-
-void DevToolsTracingHandler::BeginReadingRecordingResult(
- const base::FilePath& path) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&ReadFile, path,
- base::Bind(&DevToolsTracingHandler::ReadRecordingResult,
- weak_factory_.GetWeakPtr())));
-}
-
-void DevToolsTracingHandler::ReadRecordingResult(
- const scoped_refptr<base::RefCountedString>& trace_data) {
- if (trace_data->data().size()) {
- scoped_ptr<base::Value> trace_value(base::JSONReader::Read(
- trace_data->data()));
- base::DictionaryValue* dictionary = NULL;
- bool ok = trace_value->GetAsDictionary(&dictionary);
- DCHECK(ok);
- base::ListValue* list = NULL;
- ok = dictionary->GetList("traceEvents", &list);
- DCHECK(ok);
- std::string buffer;
- for (size_t i = 0; i < list->GetSize(); ++i) {
- std::string item;
- base::Value* item_value;
- list->Get(i, &item_value);
- base::JSONWriter::Write(item_value, &item);
- if (buffer.size())
- buffer.append(",");
- buffer.append(item);
- if (i % 1000 == 0) {
- OnTraceDataCollected(buffer);
- buffer.clear();
- }
- }
- if (buffer.size())
- OnTraceDataCollected(buffer);
- }
-
- SendNotification(devtools::Tracing::tracingComplete::kName, NULL);
-}
-
-void DevToolsTracingHandler::OnTraceDataCollected(
- const std::string& trace_fragment) {
- // Hand-craft protocol notification message so we can substitute JSON
- // that we already got as string as a bare object, not a quoted string.
- std::string message = base::StringPrintf(
- "{ \"method\": \"%s\", \"params\": { \"%s\": [ %s ] } }",
- devtools::Tracing::dataCollected::kName,
- devtools::Tracing::dataCollected::kParamValue,
- trace_fragment.c_str());
- SendRawMessage(message);
-}
-
-TracingController::Options DevToolsTracingHandler::TraceOptionsFromString(
- const std::string& options) {
- std::vector<std::string> split;
- std::vector<std::string>::iterator iter;
- int ret = 0;
-
- base::SplitString(options, ',', &split);
- for (iter = split.begin(); iter != split.end(); ++iter) {
- if (*iter == kRecordUntilFull) {
- ret &= ~TracingController::RECORD_CONTINUOUSLY;
- } else if (*iter == kRecordContinuously) {
- ret |= TracingController::RECORD_CONTINUOUSLY;
- } else if (*iter == kEnableSampling) {
- ret |= TracingController::ENABLE_SAMPLING;
- }
- }
- return static_cast<TracingController::Options>(ret);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsTracingHandler::OnStart(
- scoped_refptr<DevToolsProtocol::Command> command) {
- std::string categories;
- base::DictionaryValue* params = command->params();
- if (params)
- params->GetString(devtools::Tracing::start::kParamCategories, &categories);
-
- TracingController::Options options = TracingController::DEFAULT_OPTIONS;
- if (params && params->HasKey(devtools::Tracing::start::kParamOptions)) {
- std::string options_param;
- params->GetString(devtools::Tracing::start::kParamOptions, &options_param);
- options = TraceOptionsFromString(options_param);
- }
-
- if (params && params->HasKey(
- devtools::Tracing::start::kParamBufferUsageReportingInterval)) {
- double usage_reporting_interval = 0.0;
- params->GetDouble(
- devtools::Tracing::start::kParamBufferUsageReportingInterval,
- &usage_reporting_interval);
- if (usage_reporting_interval > 0) {
- base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
- std::ceil(usage_reporting_interval));
- buffer_usage_poll_timer_.reset(new base::Timer(
- FROM_HERE,
- interval,
- base::Bind(
- base::IgnoreResult(&TracingController::GetTraceBufferPercentFull),
- base::Unretained(TracingController::GetInstance()),
- base::Bind(&DevToolsTracingHandler::OnBufferUsage,
- weak_factory_.GetWeakPtr())),
- true));
- buffer_usage_poll_timer_->Reset();
- }
- }
-
- // If inspected target is a render process Tracing.start will be handled by
- // tracing agent in the renderer.
- if (target_ == Renderer) {
- TracingController::GetInstance()->EnableRecording(
- categories, options, TracingController::EnableRecordingDoneCallback());
- return NULL;
- }
-
- TracingController::GetInstance()->EnableRecording(
- categories, options,
- base::Bind(&DevToolsTracingHandler::OnTracingStarted,
- weak_factory_.GetWeakPtr(),
- command));
-
- return command->AsyncResponsePromise();
-}
-
-void DevToolsTracingHandler::OnTracingStarted(
- scoped_refptr<DevToolsProtocol::Command> command) {
- SendAsyncResponse(command->SuccessResponse(NULL));
-}
-
-void DevToolsTracingHandler::OnBufferUsage(float usage) {
- base::DictionaryValue* params = new base::DictionaryValue();
- params->SetDouble(devtools::Tracing::bufferUsage::kParamValue, usage);
- SendNotification(devtools::Tracing::bufferUsage::kName, params);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsTracingHandler::OnEnd(
- scoped_refptr<DevToolsProtocol::Command> command) {
- DisableRecording(
- base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult,
- weak_factory_.GetWeakPtr()));
- return command->SuccessResponse(NULL);
-}
-
-void DevToolsTracingHandler::DisableRecording(
- const TracingController::TracingFileResultCallback& callback) {
- buffer_usage_poll_timer_.reset();
- TracingController::GetInstance()->DisableRecording(base::FilePath(),
- callback);
-}
-
-void DevToolsTracingHandler::OnClientDetached() {
- DisableRecording();
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-DevToolsTracingHandler::OnGetCategories(
- scoped_refptr<DevToolsProtocol::Command> command) {
- TracingController::GetInstance()->GetCategories(
- base::Bind(&DevToolsTracingHandler::OnCategoriesReceived,
- weak_factory_.GetWeakPtr(),
- command));
- return command->AsyncResponsePromise();
-}
-
-void DevToolsTracingHandler::OnCategoriesReceived(
- scoped_refptr<DevToolsProtocol::Command> command,
- const std::set<std::string>& category_set) {
- base::DictionaryValue* response = new base::DictionaryValue;
- base::ListValue* category_list = new base::ListValue;
- for (std::set<std::string>::const_iterator it = category_set.begin();
- it != category_set.end(); ++it) {
- category_list->AppendString(*it);
- }
-
- response->Set(devtools::Tracing::getCategories::kResponseCategories,
- category_list);
- SendAsyncResponse(command->SuccessResponse(response));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/devtools_tracing_handler.h b/chromium/content/browser/devtools/devtools_tracing_handler.h
deleted file mode 100644
index 7c3b8e645e4..00000000000
--- a/chromium/content/browser/devtools/devtools_tracing_handler.h
+++ /dev/null
@@ -1,63 +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_DEVTOOLS_DEVTOOLS_TRACING_HANDLER_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_TRACING_HANDLER_H_
-
-#include <set>
-#include <string>
-
-#include "base/memory/weak_ptr.h"
-#include "content/browser/devtools/devtools_protocol.h"
-#include "content/public/browser/tracing_controller.h"
-
-namespace base {
-class RefCountedString;
-class Timer;
-}
-
-namespace content {
-
-// This class bridges DevTools remote debugging server with the trace
-// infrastructure.
-class DevToolsTracingHandler : public DevToolsProtocol::Handler {
- public:
- enum Target { Browser, Renderer };
- explicit DevToolsTracingHandler(Target target);
- virtual ~DevToolsTracingHandler();
-
- void OnClientDetached();
-
- private:
- void BeginReadingRecordingResult(const base::FilePath& path);
- void ReadRecordingResult(const scoped_refptr<base::RefCountedString>& result);
- void OnTraceDataCollected(const std::string& trace_fragment);
- void OnTracingStarted(scoped_refptr<DevToolsProtocol::Command> command);
- void OnBufferUsage(float usage);
-
- scoped_refptr<DevToolsProtocol::Response> OnStart(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> OnEnd(
- scoped_refptr<DevToolsProtocol::Command> command);
-
- scoped_refptr<DevToolsProtocol::Response> OnGetCategories(
- scoped_refptr<DevToolsProtocol::Command> command);
- void OnCategoriesReceived(scoped_refptr<DevToolsProtocol::Command> command,
- const std::set<std::string>& category_set);
-
- TracingController::Options TraceOptionsFromString(const std::string& options);
-
- void DisableRecording(
- const TracingController::TracingFileResultCallback& callback =
- TracingController::TracingFileResultCallback());
-
- base::WeakPtrFactory<DevToolsTracingHandler> weak_factory_;
- scoped_ptr<base::Timer> buffer_usage_poll_timer_;
- Target target_;
- DISALLOW_COPY_AND_ASSIGN(DevToolsTracingHandler);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_TRACING_HANDLER_H_
diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_agent_host.cc b/chromium/content/browser/devtools/embedded_worker_devtools_agent_host.cc
new file mode 100644
index 00000000000..dede4d93d8a
--- /dev/null
+++ b/chromium/content/browser/devtools/embedded_worker_devtools_agent_host.cc
@@ -0,0 +1,232 @@
+// 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/devtools/embedded_worker_devtools_agent_host.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/devtools/devtools_protocol.h"
+#include "content/browser/devtools/devtools_protocol_constants.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_version.h"
+#include "content/browser/shared_worker/shared_worker_service_impl.h"
+#include "content/common/devtools_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+
+namespace {
+
+void TerminateSharedWorkerOnIO(
+ EmbeddedWorkerDevToolsAgentHost::WorkerId worker_id) {
+ SharedWorkerServiceImpl::GetInstance()->TerminateWorker(
+ worker_id.first, worker_id.second);
+}
+
+void StatusNoOp(ServiceWorkerStatusCode status) {
+}
+
+void TerminateServiceWorkerOnIO(
+ base::WeakPtr<ServiceWorkerContextCore> context_weak,
+ int64 version_id) {
+ if (ServiceWorkerContextCore* context = context_weak.get()) {
+ if (ServiceWorkerVersion* version = context->GetLiveVersion(version_id))
+ version->StopWorker(base::Bind(&StatusNoOp));
+ }
+}
+
+}
+
+EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
+ WorkerId worker_id,
+ const SharedWorkerInstance& shared_worker)
+ : shared_worker_(new SharedWorkerInstance(shared_worker)),
+ state_(WORKER_UNINSPECTED),
+ worker_id_(worker_id) {
+ WorkerCreated();
+}
+
+EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
+ WorkerId worker_id,
+ const ServiceWorkerIdentifier& service_worker,
+ bool debug_service_worker_on_start)
+ : service_worker_(new ServiceWorkerIdentifier(service_worker)),
+ state_(WORKER_UNINSPECTED),
+ worker_id_(worker_id) {
+ if (debug_service_worker_on_start)
+ state_ = WORKER_PAUSED_FOR_DEBUG_ON_START;
+ WorkerCreated();
+}
+
+bool EmbeddedWorkerDevToolsAgentHost::IsWorker() const {
+ return true;
+}
+
+DevToolsAgentHost::Type EmbeddedWorkerDevToolsAgentHost::GetType() {
+ return shared_worker_ ? TYPE_SHARED_WORKER : TYPE_SERVICE_WORKER;
+}
+
+std::string EmbeddedWorkerDevToolsAgentHost::GetTitle() {
+ if (shared_worker_ && shared_worker_->name().length())
+ return base::UTF16ToUTF8(shared_worker_->name());
+ if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
+ return base::StringPrintf("Worker pid:%d",
+ base::GetProcId(host->GetHandle()));
+ }
+ return "";
+}
+
+GURL EmbeddedWorkerDevToolsAgentHost::GetURL() {
+ if (shared_worker_)
+ return shared_worker_->url();
+ if (service_worker_)
+ return service_worker_->url();
+ return GURL();
+}
+
+bool EmbeddedWorkerDevToolsAgentHost::Activate() {
+ return false;
+}
+
+bool EmbeddedWorkerDevToolsAgentHost::Close() {
+ if (shared_worker_) {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&TerminateSharedWorkerOnIO, worker_id_));
+ return true;
+ }
+ if (service_worker_) {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&TerminateServiceWorkerOnIO,
+ service_worker_->context_weak(),
+ service_worker_->version_id()));
+ return true;
+ }
+ return false;
+}
+
+void EmbeddedWorkerDevToolsAgentHost::SendMessageToAgent(
+ IPC::Message* message_raw) {
+ scoped_ptr<IPC::Message> message(message_raw);
+ if (state_ != WORKER_INSPECTED)
+ return;
+ if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
+ message->set_routing_id(worker_id_.second);
+ host->Send(message.release());
+ }
+}
+
+void EmbeddedWorkerDevToolsAgentHost::Attach() {
+ if (state_ != WORKER_INSPECTED) {
+ state_ = WORKER_INSPECTED;
+ AttachToWorker();
+ }
+ IPCDevToolsAgentHost::Attach();
+}
+
+void EmbeddedWorkerDevToolsAgentHost::OnClientDetached() {
+ if (state_ == WORKER_INSPECTED) {
+ state_ = WORKER_UNINSPECTED;
+ DetachFromWorker();
+ } else if (state_ == WORKER_PAUSED_FOR_REATTACH) {
+ state_ = WORKER_UNINSPECTED;
+ }
+}
+
+bool EmbeddedWorkerDevToolsAgentHost::OnMessageReceived(
+ const IPC::Message& msg) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerDevToolsAgentHost, msg)
+ IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
+ OnDispatchOnInspectorFrontend)
+ IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
+ OnSaveAgentRuntimeState)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void EmbeddedWorkerDevToolsAgentHost::WorkerReadyForInspection() {
+ if (state_ == WORKER_PAUSED_FOR_DEBUG_ON_START) {
+ RenderProcessHost* rph = RenderProcessHost::FromID(worker_id_.first);
+ Inspect(rph->GetBrowserContext());
+ } else if (state_ == WORKER_PAUSED_FOR_REATTACH) {
+ DCHECK(IsAttached());
+ state_ = WORKER_INSPECTED;
+ AttachToWorker();
+ Reattach(saved_agent_state_);
+ }
+}
+
+void EmbeddedWorkerDevToolsAgentHost::WorkerRestarted(WorkerId worker_id) {
+ DCHECK_EQ(WORKER_TERMINATED, state_);
+ state_ = IsAttached() ? WORKER_PAUSED_FOR_REATTACH : WORKER_UNINSPECTED;
+ worker_id_ = worker_id;
+ WorkerCreated();
+}
+
+void EmbeddedWorkerDevToolsAgentHost::WorkerDestroyed() {
+ DCHECK_NE(WORKER_TERMINATED, state_);
+ if (state_ == WORKER_INSPECTED) {
+ DCHECK(IsAttached());
+ // Client host is debugging this worker agent host.
+ std::string notification =
+ DevToolsProtocol::CreateNotification(
+ devtools::Worker::disconnectedFromWorker::kName, NULL)->Serialize();
+ SendMessageToClient(notification);
+ DetachFromWorker();
+ }
+ state_ = WORKER_TERMINATED;
+ Release(); // Balanced in WorkerCreated()
+}
+
+bool EmbeddedWorkerDevToolsAgentHost::Matches(
+ const SharedWorkerInstance& other) {
+ return shared_worker_ && shared_worker_->Matches(other);
+}
+
+bool EmbeddedWorkerDevToolsAgentHost::Matches(
+ const ServiceWorkerIdentifier& other) {
+ return service_worker_ && service_worker_->Matches(other);
+}
+
+bool EmbeddedWorkerDevToolsAgentHost::IsTerminated() {
+ return state_ == WORKER_TERMINATED;
+}
+
+EmbeddedWorkerDevToolsAgentHost::~EmbeddedWorkerDevToolsAgentHost() {
+ DCHECK_EQ(WORKER_TERMINATED, state_);
+ EmbeddedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
+ worker_id_);
+}
+
+void EmbeddedWorkerDevToolsAgentHost::AttachToWorker() {
+ if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
+ host->AddRoute(worker_id_.second, this);
+}
+
+void EmbeddedWorkerDevToolsAgentHost::DetachFromWorker() {
+ if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
+ host->RemoveRoute(worker_id_.second);
+}
+
+void EmbeddedWorkerDevToolsAgentHost::WorkerCreated() {
+ AddRef(); // Balanced in WorkerDestroyed()
+}
+
+void EmbeddedWorkerDevToolsAgentHost::OnDispatchOnInspectorFrontend(
+ const std::string& message,
+ uint32 total_size) {
+ if (!IsAttached())
+ return;
+
+ ProcessChunkedMessageFromAgent(message, total_size);
+}
+
+void EmbeddedWorkerDevToolsAgentHost::OnSaveAgentRuntimeState(
+ const std::string& state) {
+ saved_agent_state_ = state;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_agent_host.h b/chromium/content/browser/devtools/embedded_worker_devtools_agent_host.h
new file mode 100644
index 00000000000..cb0e45f3369
--- /dev/null
+++ b/chromium/content/browser/devtools/embedded_worker_devtools_agent_host.h
@@ -0,0 +1,84 @@
+// 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_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_AGENT_HOST_H_
+#define CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_AGENT_HOST_H_
+
+#include "content/browser/devtools/embedded_worker_devtools_manager.h"
+#include "content/browser/devtools/ipc_devtools_agent_host.h"
+#include "ipc/ipc_listener.h"
+
+namespace content {
+
+class SharedWorkerInstance;
+
+class EmbeddedWorkerDevToolsAgentHost : public IPCDevToolsAgentHost,
+ public IPC::Listener {
+ public:
+ typedef EmbeddedWorkerDevToolsManager::WorkerId WorkerId;
+ typedef EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier
+ ServiceWorkerIdentifier;
+
+ EmbeddedWorkerDevToolsAgentHost(WorkerId worker_id,
+ const SharedWorkerInstance& shared_worker);
+
+ EmbeddedWorkerDevToolsAgentHost(WorkerId worker_id,
+ const ServiceWorkerIdentifier& service_worker,
+ bool debug_service_worker_on_start);
+
+ // DevToolsAgentHost override.
+ bool IsWorker() const override;
+ Type GetType() override;
+ std::string GetTitle() override;
+ GURL GetURL() override;
+ bool Activate() override;
+ bool Close() override;
+
+ // IPCDevToolsAgentHost implementation.
+ void SendMessageToAgent(IPC::Message* message) override;
+ void Attach() override;
+ void OnClientAttached() override {}
+ void OnClientDetached() override;
+
+ // IPC::Listener implementation.
+ bool OnMessageReceived(const IPC::Message& msg) override;
+
+ void WorkerReadyForInspection();
+ void WorkerRestarted(WorkerId worker_id);
+ void WorkerDestroyed();
+ bool Matches(const SharedWorkerInstance& other);
+ bool Matches(const ServiceWorkerIdentifier& other);
+ bool IsTerminated();
+
+ private:
+ friend class EmbeddedWorkerDevToolsManagerTest;
+
+ ~EmbeddedWorkerDevToolsAgentHost() override;
+
+ enum WorkerState {
+ WORKER_UNINSPECTED,
+ WORKER_INSPECTED,
+ WORKER_TERMINATED,
+ WORKER_PAUSED_FOR_DEBUG_ON_START,
+ WORKER_PAUSED_FOR_REATTACH,
+ };
+
+ void AttachToWorker();
+ void DetachFromWorker();
+ void WorkerCreated();
+ void OnDispatchOnInspectorFrontend(const std::string& message,
+ uint32 total_size);
+ void OnSaveAgentRuntimeState(const std::string& state);
+
+ scoped_ptr<SharedWorkerInstance> shared_worker_;
+ scoped_ptr<ServiceWorkerIdentifier> service_worker_;
+ WorkerState state_;
+ WorkerId worker_id_;
+ std::string saved_agent_state_;
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerDevToolsAgentHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_AGENT_HOST_H_
diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_manager.cc b/chromium/content/browser/devtools/embedded_worker_devtools_manager.cc
index 3ba61aafeea..be0bbbf9bc2 100644
--- a/chromium/content/browser/devtools/embedded_worker_devtools_manager.cc
+++ b/chromium/content/browser/devtools/embedded_worker_devtools_manager.cc
@@ -4,9 +4,10 @@
#include "content/browser/devtools/embedded_worker_devtools_manager.h"
-#include "content/browser/devtools/devtools_manager_impl.h"
+#include "content/browser/devtools/devtools_manager.h"
#include "content/browser/devtools/devtools_protocol.h"
#include "content/browser/devtools/devtools_protocol_constants.h"
+#include "content/browser/devtools/embedded_worker_devtools_agent_host.h"
#include "content/browser/devtools/ipc_devtools_agent_host.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
#include "content/common/devtools_messages.h"
@@ -17,197 +18,75 @@
namespace content {
-namespace {
-
-bool SendMessageToWorker(
- const EmbeddedWorkerDevToolsManager::WorkerId& worker_id,
- IPC::Message* message) {
- RenderProcessHost* host = RenderProcessHost::FromID(worker_id.first);
- if (!host) {
- delete message;
- return false;
- }
- message->set_routing_id(worker_id.second);
- host->Send(message);
- return true;
+// Called on the UI thread.
+// static
+scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForWorker(
+ int worker_process_id,
+ int worker_route_id) {
+ return EmbeddedWorkerDevToolsManager::GetInstance()
+ ->GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id);
}
-} // namespace
-
EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
- const ServiceWorkerContextCore* const service_worker_context,
- int64 service_worker_version_id)
- : service_worker_context_(service_worker_context),
- service_worker_version_id_(service_worker_version_id) {
+ const ServiceWorkerContextCore* context,
+ base::WeakPtr<ServiceWorkerContextCore> context_weak,
+ int64 version_id,
+ const GURL& url)
+ : context_(context),
+ context_weak_(context_weak),
+ version_id_(version_id),
+ url_(url) {
}
EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier(
const ServiceWorkerIdentifier& other)
- : service_worker_context_(other.service_worker_context_),
- service_worker_version_id_(other.service_worker_version_id_) {
+ : context_(other.context_),
+ context_weak_(other.context_weak_),
+ version_id_(other.version_id_),
+ url_(other.url_) {
}
-bool EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::Matches(
- const ServiceWorkerIdentifier& other) const {
- return service_worker_context_ == other.service_worker_context_ &&
- service_worker_version_id_ == other.service_worker_version_id_;
+EmbeddedWorkerDevToolsManager::
+ServiceWorkerIdentifier::~ServiceWorkerIdentifier() {
}
-EmbeddedWorkerDevToolsManager::WorkerInfo::WorkerInfo(
- const SharedWorkerInstance& instance)
- : shared_worker_instance_(new SharedWorkerInstance(instance)),
- state_(WORKER_UNINSPECTED),
- agent_host_(NULL) {
+bool EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::Matches(
+ const ServiceWorkerIdentifier& other) const {
+ return context_ == other.context_ && version_id_ == other.version_id_;
}
-EmbeddedWorkerDevToolsManager::WorkerInfo::WorkerInfo(
- const ServiceWorkerIdentifier& service_worker_id)
- : service_worker_id_(new ServiceWorkerIdentifier(service_worker_id)),
- state_(WORKER_UNINSPECTED),
- agent_host_(NULL) {
+const ServiceWorkerContextCore*
+EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::context() const {
+ return context_;
}
-bool EmbeddedWorkerDevToolsManager::WorkerInfo::Matches(
- const SharedWorkerInstance& other) {
- if (!shared_worker_instance_)
- return false;
- return shared_worker_instance_->Matches(other);
+base::WeakPtr<ServiceWorkerContextCore>
+EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::context_weak() const {
+ return context_weak_;
}
-bool EmbeddedWorkerDevToolsManager::WorkerInfo::Matches(
- const ServiceWorkerIdentifier& other) {
- if (!service_worker_id_)
- return false;
- return service_worker_id_->Matches(other);
+int64
+EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::version_id() const {
+ return version_id_;
}
-EmbeddedWorkerDevToolsManager::WorkerInfo::~WorkerInfo() {
+GURL EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::url() const {
+ return url_;
}
-class EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsAgentHost
- : public IPCDevToolsAgentHost,
- public IPC::Listener {
- public:
- explicit EmbeddedWorkerDevToolsAgentHost(WorkerId worker_id)
- : worker_id_(worker_id), worker_attached_(false) {
- AttachToWorker();
- }
-
- // DevToolsAgentHost override.
- virtual bool IsWorker() const OVERRIDE { return true; }
-
- // IPCDevToolsAgentHost implementation.
- virtual void SendMessageToAgent(IPC::Message* message) OVERRIDE {
- if (worker_attached_)
- SendMessageToWorker(worker_id_, message);
- else
- delete message;
- }
- virtual void Attach() OVERRIDE {
- AttachToWorker();
- IPCDevToolsAgentHost::Attach();
- }
- virtual void OnClientAttached() OVERRIDE {}
- virtual void OnClientDetached() OVERRIDE { DetachFromWorker(); }
-
- // IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerDevToolsAgentHost, msg)
- IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
- OnDispatchOnInspectorFrontend)
- IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
- OnSaveAgentRuntimeState)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
- }
-
- void ReattachToWorker(WorkerId worker_id) {
- CHECK(!worker_attached_);
- worker_id_ = worker_id;
- if (!IsAttached())
- return;
- AttachToWorker();
- Reattach(state_);
- }
-
- void DetachFromWorker() {
- if (!worker_attached_)
- return;
- worker_attached_ = false;
- if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
- host->RemoveRoute(worker_id_.second);
- Release();
- }
-
- WorkerId worker_id() const { return worker_id_; }
-
- private:
- virtual ~EmbeddedWorkerDevToolsAgentHost() {
- CHECK(!worker_attached_);
- EmbeddedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
- this);
- }
-
- void OnDispatchOnInspectorFrontend(const std::string& message) {
- DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(this,
- message);
- }
-
- void OnSaveAgentRuntimeState(const std::string& state) { state_ = state; }
-
- void AttachToWorker() {
- if (worker_attached_)
- return;
- worker_attached_ = true;
- AddRef();
- if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
- host->AddRoute(worker_id_.second, this);
- }
-
- WorkerId worker_id_;
- bool worker_attached_;
- std::string state_;
- DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerDevToolsAgentHost);
-};
-
// static
EmbeddedWorkerDevToolsManager* EmbeddedWorkerDevToolsManager::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return Singleton<EmbeddedWorkerDevToolsManager>::get();
}
-DevToolsAgentHost* EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker(
+DevToolsAgentHostImpl*
+EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker(
int worker_process_id,
int worker_route_id) {
- WorkerId id(worker_process_id, worker_route_id);
-
- WorkerInfoMap::iterator it = workers_.find(id);
- if (it == workers_.end())
- return NULL;
-
- WorkerInfo* info = it->second;
- if (info->state() != WORKER_UNINSPECTED &&
- info->state() != WORKER_PAUSED_FOR_DEBUG_ON_START) {
- return info->agent_host();
- }
-
- EmbeddedWorkerDevToolsAgentHost* agent_host =
- new EmbeddedWorkerDevToolsAgentHost(id);
- info->set_agent_host(agent_host);
- info->set_state(WORKER_INSPECTED);
- return agent_host;
-}
-
-DevToolsAgentHost*
-EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForServiceWorker(
- const ServiceWorkerIdentifier& service_worker_id) {
- WorkerInfoMap::iterator it = FindExistingServiceWorkerInfo(service_worker_id);
- if (it == workers_.end())
- return NULL;
- return GetDevToolsAgentHostForWorker(it->first.first, it->first.second);
+ AgentHostMap::iterator it = workers_.find(
+ WorkerId(worker_process_id, worker_route_id));
+ return it == workers_.end() ? NULL : it->second;
}
EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsManager()
@@ -223,13 +102,13 @@ bool EmbeddedWorkerDevToolsManager::SharedWorkerCreated(
const SharedWorkerInstance& instance) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const WorkerId id(worker_process_id, worker_route_id);
- WorkerInfoMap::iterator it = FindExistingSharedWorkerInfo(instance);
+ AgentHostMap::iterator it = FindExistingSharedWorkerAgentHost(instance);
if (it == workers_.end()) {
- scoped_ptr<WorkerInfo> info(new WorkerInfo(instance));
- workers_.set(id, info.Pass());
+ workers_[id] = new EmbeddedWorkerDevToolsAgentHost(id, instance);
+ DevToolsManager::GetInstance()->AgentHostChanged(workers_[id]);
return false;
}
- MoveToPausedState(id, it);
+ WorkerRestarted(id, it);
return true;
}
@@ -239,15 +118,15 @@ bool EmbeddedWorkerDevToolsManager::ServiceWorkerCreated(
const ServiceWorkerIdentifier& service_worker_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const WorkerId id(worker_process_id, worker_route_id);
- WorkerInfoMap::iterator it = FindExistingServiceWorkerInfo(service_worker_id);
+ AgentHostMap::iterator it =
+ FindExistingServiceWorkerAgentHost(service_worker_id);
if (it == workers_.end()) {
- scoped_ptr<WorkerInfo> info(new WorkerInfo(service_worker_id));
- if (debug_service_worker_on_start_)
- info->set_state(WORKER_PAUSED_FOR_DEBUG_ON_START);
- workers_.set(id, info.Pass());
+ workers_[id] = new EmbeddedWorkerDevToolsAgentHost(
+ id, service_worker_id, debug_service_worker_on_start_);
+ DevToolsManager::GetInstance()->AgentHostChanged(workers_[id]);
return debug_service_worker_on_start_;
}
- MoveToPausedState(id, it);
+ WorkerRestarted(id, it);
return true;
}
@@ -255,96 +134,32 @@ void EmbeddedWorkerDevToolsManager::WorkerDestroyed(int worker_process_id,
int worker_route_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const WorkerId id(worker_process_id, worker_route_id);
- WorkerInfoMap::iterator it = workers_.find(id);
+ AgentHostMap::iterator it = workers_.find(id);
DCHECK(it != workers_.end());
- WorkerInfo* info = it->second;
- switch (info->state()) {
- case WORKER_UNINSPECTED:
- case WORKER_PAUSED_FOR_DEBUG_ON_START:
- workers_.erase(it);
- break;
- case WORKER_INSPECTED: {
- EmbeddedWorkerDevToolsAgentHost* agent_host = info->agent_host();
- info->set_state(WORKER_TERMINATED);
- if (!agent_host->IsAttached()) {
- agent_host->DetachFromWorker();
- return;
- }
- // Client host is debugging this worker agent host.
- std::string notification =
- DevToolsProtocol::CreateNotification(
- devtools::Worker::disconnectedFromWorker::kName, NULL)
- ->Serialize();
- DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(
- agent_host, notification);
- agent_host->DetachFromWorker();
- break;
- }
- case WORKER_TERMINATED:
- NOTREACHED();
- break;
- case WORKER_PAUSED_FOR_REATTACH: {
- scoped_ptr<WorkerInfo> worker_info = workers_.take_and_erase(it);
- worker_info->set_state(WORKER_TERMINATED);
- const WorkerId old_id = worker_info->agent_host()->worker_id();
- workers_.set(old_id, worker_info.Pass());
- break;
- }
- }
+ scoped_refptr<EmbeddedWorkerDevToolsAgentHost> agent_host(it->second);
+ agent_host->WorkerDestroyed();
+ DevToolsManager::GetInstance()->AgentHostChanged(agent_host);
}
-void EmbeddedWorkerDevToolsManager::WorkerContextStarted(int worker_process_id,
- int worker_route_id) {
+void EmbeddedWorkerDevToolsManager::WorkerReadyForInspection(
+ int worker_process_id,
+ int worker_route_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const WorkerId id(worker_process_id, worker_route_id);
- WorkerInfoMap::iterator it = workers_.find(id);
+ AgentHostMap::iterator it = workers_.find(id);
DCHECK(it != workers_.end());
- WorkerInfo* info = it->second;
- if (info->state() == WORKER_PAUSED_FOR_DEBUG_ON_START) {
- RenderProcessHost* rph = RenderProcessHost::FromID(worker_process_id);
- scoped_refptr<DevToolsAgentHost> agent_host(
- GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id));
- DevToolsManagerImpl::GetInstance()->Inspect(rph->GetBrowserContext(),
- agent_host.get());
- } else if (info->state() == WORKER_PAUSED_FOR_REATTACH) {
- info->agent_host()->ReattachToWorker(id);
- info->set_state(WORKER_INSPECTED);
- }
+ it->second->WorkerReadyForInspection();
}
-void EmbeddedWorkerDevToolsManager::RemoveInspectedWorkerData(
- EmbeddedWorkerDevToolsAgentHost* agent_host) {
+void EmbeddedWorkerDevToolsManager::RemoveInspectedWorkerData(WorkerId id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- const WorkerId id(agent_host->worker_id());
- scoped_ptr<WorkerInfo> worker_info = workers_.take_and_erase(id);
- if (worker_info) {
- DCHECK_EQ(worker_info->agent_host(), agent_host);
- if (worker_info->state() == WORKER_TERMINATED)
- return;
- DCHECK_EQ(worker_info->state(), WORKER_INSPECTED);
- worker_info->set_agent_host(NULL);
- worker_info->set_state(WORKER_UNINSPECTED);
- workers_.set(id, worker_info.Pass());
- return;
- }
- for (WorkerInfoMap::iterator it = workers_.begin(); it != workers_.end();
- ++it) {
- if (it->second->agent_host() == agent_host) {
- DCHECK_EQ(WORKER_PAUSED_FOR_REATTACH, it->second->state());
- SendMessageToWorker(
- it->first,
- new DevToolsAgentMsg_ResumeWorkerContext(it->first.second));
- it->second->set_agent_host(NULL);
- it->second->set_state(WORKER_UNINSPECTED);
- return;
- }
- }
+ workers_.erase(id);
}
-EmbeddedWorkerDevToolsManager::WorkerInfoMap::iterator
-EmbeddedWorkerDevToolsManager::FindExistingSharedWorkerInfo(
+EmbeddedWorkerDevToolsManager::AgentHostMap::iterator
+EmbeddedWorkerDevToolsManager::FindExistingSharedWorkerAgentHost(
const SharedWorkerInstance& instance) {
- WorkerInfoMap::iterator it = workers_.begin();
+ AgentHostMap::iterator it = workers_.begin();
for (; it != workers_.end(); ++it) {
if (it->second->Matches(instance))
break;
@@ -352,10 +167,10 @@ EmbeddedWorkerDevToolsManager::FindExistingSharedWorkerInfo(
return it;
}
-EmbeddedWorkerDevToolsManager::WorkerInfoMap::iterator
-EmbeddedWorkerDevToolsManager::FindExistingServiceWorkerInfo(
+EmbeddedWorkerDevToolsManager::AgentHostMap::iterator
+EmbeddedWorkerDevToolsManager::FindExistingServiceWorkerAgentHost(
const ServiceWorkerIdentifier& service_worker_id) {
- WorkerInfoMap::iterator it = workers_.begin();
+ AgentHostMap::iterator it = workers_.begin();
for (; it != workers_.end(); ++it) {
if (it->second->Matches(service_worker_id))
break;
@@ -363,13 +178,26 @@ EmbeddedWorkerDevToolsManager::FindExistingServiceWorkerInfo(
return it;
}
-void EmbeddedWorkerDevToolsManager::MoveToPausedState(
+DevToolsAgentHost::List
+EmbeddedWorkerDevToolsManager::GetOrCreateAllAgentHosts() {
+ DevToolsAgentHost::List result;
+ EmbeddedWorkerDevToolsManager* instance = GetInstance();
+ for (AgentHostMap::iterator it = instance->workers_.begin();
+ it != instance->workers_.end(); ++it) {
+ if (!it->second->IsTerminated())
+ result.push_back(it->second);
+ }
+ return result;
+}
+
+void EmbeddedWorkerDevToolsManager::WorkerRestarted(
const WorkerId& id,
- const WorkerInfoMap::iterator& it) {
- DCHECK_EQ(WORKER_TERMINATED, it->second->state());
- scoped_ptr<WorkerInfo> info = workers_.take_and_erase(it);
- info->set_state(WORKER_PAUSED_FOR_REATTACH);
- workers_.set(id, info.Pass());
+ const AgentHostMap::iterator& it) {
+ EmbeddedWorkerDevToolsAgentHost* agent_host = it->second;
+ agent_host->WorkerRestarted(id);
+ workers_.erase(it);
+ workers_[id] = agent_host;
+ DevToolsManager::GetInstance()->AgentHostChanged(agent_host);
}
void EmbeddedWorkerDevToolsManager::ResetForTesting() {
diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_manager.h b/chromium/content/browser/devtools/embedded_worker_devtools_manager.h
index 3b15c8f2099..7103877be11 100644
--- a/chromium/content/browser/devtools/embedded_worker_devtools_manager.h
+++ b/chromium/content/browser/devtools/embedded_worker_devtools_manager.h
@@ -5,11 +5,13 @@
#ifndef CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_MANAGER_H_
#define CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_MANAGER_H_
+#include <map>
+
#include "base/basictypes.h"
-#include "base/containers/scoped_ptr_hash_map.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/singleton.h"
+#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
#include "content/common/content_export.h"
@@ -17,6 +19,8 @@
namespace content {
class DevToolsAgentHost;
+class DevToolsAgentHostImpl;
+class EmbeddedWorkerDevToolsAgentHost;
class ServiceWorkerContextCore;
// EmbeddedWorkerDevToolsManager is used instead of WorkerDevToolsManager when
@@ -25,30 +29,38 @@ class ServiceWorkerContextCore;
class CONTENT_EXPORT EmbeddedWorkerDevToolsManager {
public:
typedef std::pair<int, int> WorkerId;
- class EmbeddedWorkerDevToolsAgentHost;
class ServiceWorkerIdentifier {
public:
ServiceWorkerIdentifier(
- const ServiceWorkerContextCore* const service_worker_context,
- int64 service_worker_version_id);
- explicit ServiceWorkerIdentifier(const ServiceWorkerIdentifier& other);
- ~ServiceWorkerIdentifier() {}
+ const ServiceWorkerContextCore* context,
+ base::WeakPtr<ServiceWorkerContextCore> context_weak,
+ int64 version_id,
+ const GURL& url);
+ ServiceWorkerIdentifier(const ServiceWorkerIdentifier& other);
+ ~ServiceWorkerIdentifier();
bool Matches(const ServiceWorkerIdentifier& other) const;
+ const ServiceWorkerContextCore* context() const;
+ base::WeakPtr<ServiceWorkerContextCore> context_weak() const;
+ int64 version_id() const;
+ GURL url() const;
+
private:
- const ServiceWorkerContextCore* const service_worker_context_;
- const int64 service_worker_version_id_;
+ const ServiceWorkerContextCore* const context_;
+ const base::WeakPtr<ServiceWorkerContextCore> context_weak_;
+ const int64 version_id_;
+ const GURL url_;
};
// Returns the EmbeddedWorkerDevToolsManager singleton.
static EmbeddedWorkerDevToolsManager* GetInstance();
- DevToolsAgentHost* GetDevToolsAgentHostForWorker(int worker_process_id,
+ DevToolsAgentHostImpl* GetDevToolsAgentHostForWorker(int worker_process_id,
int worker_route_id);
- DevToolsAgentHost* GetDevToolsAgentHostForServiceWorker(
- const ServiceWorkerIdentifier& service_worker_id);
+
+ std::vector<scoped_refptr<DevToolsAgentHost> > GetOrCreateAllAgentHosts();
// Returns true when the worker must be paused on start because a DevTool
// window for the same former SharedWorkerInstance is still opened.
@@ -61,7 +73,7 @@ class CONTENT_EXPORT EmbeddedWorkerDevToolsManager {
bool ServiceWorkerCreated(int worker_process_id,
int worker_route_id,
const ServiceWorkerIdentifier& service_worker_id);
- void WorkerContextStarted(int worker_process_id, int worker_route_id);
+ void WorkerReadyForInspection(int worker_process_id, int worker_route_id);
void WorkerDestroyed(int worker_process_id, int worker_route_id);
void set_debug_service_worker_on_start(bool debug_on_start) {
@@ -73,60 +85,29 @@ class CONTENT_EXPORT EmbeddedWorkerDevToolsManager {
private:
friend struct DefaultSingletonTraits<EmbeddedWorkerDevToolsManager>;
+ friend class EmbeddedWorkerDevToolsAgentHost;
friend class EmbeddedWorkerDevToolsManagerTest;
FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerDevToolsManagerTest, BasicTest);
FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerDevToolsManagerTest, AttachTest);
- enum WorkerState {
- WORKER_UNINSPECTED,
- WORKER_INSPECTED,
- WORKER_TERMINATED,
- WORKER_PAUSED_FOR_DEBUG_ON_START,
- WORKER_PAUSED_FOR_REATTACH,
- };
-
- class WorkerInfo {
- public:
- // Creates WorkerInfo for SharedWorker.
- explicit WorkerInfo(const SharedWorkerInstance& instance);
- // Creates WorkerInfo for ServiceWorker.
- explicit WorkerInfo(const ServiceWorkerIdentifier& service_worker_id);
- ~WorkerInfo();
-
- WorkerState state() { return state_; }
- void set_state(WorkerState new_state) { state_ = new_state; }
- EmbeddedWorkerDevToolsAgentHost* agent_host() { return agent_host_; }
- void set_agent_host(EmbeddedWorkerDevToolsAgentHost* agent_host) {
- agent_host_ = agent_host;
- }
- bool Matches(const SharedWorkerInstance& other);
- bool Matches(const ServiceWorkerIdentifier& other);
-
- private:
- scoped_ptr<SharedWorkerInstance> shared_worker_instance_;
- scoped_ptr<ServiceWorkerIdentifier> service_worker_id_;
- WorkerState state_;
- EmbeddedWorkerDevToolsAgentHost* agent_host_;
- };
-
- typedef base::ScopedPtrHashMap<WorkerId, WorkerInfo> WorkerInfoMap;
+ typedef std::map<WorkerId, EmbeddedWorkerDevToolsAgentHost*> AgentHostMap;
EmbeddedWorkerDevToolsManager();
virtual ~EmbeddedWorkerDevToolsManager();
- void RemoveInspectedWorkerData(EmbeddedWorkerDevToolsAgentHost* agent_host);
+ void RemoveInspectedWorkerData(WorkerId id);
- WorkerInfoMap::iterator FindExistingSharedWorkerInfo(
+ AgentHostMap::iterator FindExistingSharedWorkerAgentHost(
const SharedWorkerInstance& instance);
- WorkerInfoMap::iterator FindExistingServiceWorkerInfo(
+ AgentHostMap::iterator FindExistingServiceWorkerAgentHost(
const ServiceWorkerIdentifier& service_worker_id);
- void MoveToPausedState(const WorkerId& id, const WorkerInfoMap::iterator& it);
+ void WorkerRestarted(const WorkerId& id, const AgentHostMap::iterator& it);
// Resets to its initial state as if newly created.
void ResetForTesting();
- WorkerInfoMap workers_;
+ AgentHostMap workers_;
bool debug_service_worker_on_start_;
diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc b/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc
index 69b23052425..35a0b301ac2 100644
--- a/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc
+++ b/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc
@@ -8,33 +8,41 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "content/browser/browser_thread_impl.h"
-#include "content/browser/devtools/devtools_manager_impl.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
+#include "content/browser/devtools/embedded_worker_devtools_agent_host.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
-#include "content/browser/worker_host/worker_storage_partition.h"
-#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/devtools_client_host.h"
+#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/public/test/test_browser_context.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace {
-class TestDevToolsClientHost : public DevToolsClientHost {
+class TestDevToolsClientHost : public DevToolsAgentHostClient {
public:
TestDevToolsClientHost() {}
- virtual ~TestDevToolsClientHost() {}
- virtual void DispatchOnInspectorFrontend(
- const std::string& message) OVERRIDE {}
- virtual void InspectedContentsClosing() OVERRIDE {}
- virtual void ReplacedWithAnotherClient() OVERRIDE {}
+ ~TestDevToolsClientHost() override {}
+ void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+ const std::string& message) override {}
+ void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {}
+ void InspectAgentHost(DevToolsAgentHost* agent_host) {
+ if (agent_host_.get())
+ agent_host_->DetachClient();
+ agent_host_ = agent_host;
+ if (agent_host_.get())
+ agent_host_->AttachClient(this);
+ }
private:
+ scoped_refptr<DevToolsAgentHost> agent_host_;
DISALLOW_COPY_AND_ASSIGN(TestDevToolsClientHost);
};
}
class EmbeddedWorkerDevToolsManagerTest : public testing::Test {
public:
+ typedef EmbeddedWorkerDevToolsAgentHost::WorkerState WorkerState;
+
EmbeddedWorkerDevToolsManagerTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
browser_context_(new TestBrowserContext()),
@@ -50,22 +58,22 @@ class EmbeddedWorkerDevToolsManagerTest : public testing::Test {
partition_id_(*partition_.get()) {}
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
manager_ = EmbeddedWorkerDevToolsManager::GetInstance();
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
EmbeddedWorkerDevToolsManager::GetInstance()->ResetForTesting();
}
void CheckWorkerState(int worker_process_id,
int worker_route_id,
- EmbeddedWorkerDevToolsManager::WorkerState state) {
+ WorkerState state) {
const EmbeddedWorkerDevToolsManager::WorkerId id(worker_process_id,
worker_route_id);
- EmbeddedWorkerDevToolsManager::WorkerInfoMap::iterator it =
+ EmbeddedWorkerDevToolsManager::AgentHostMap::iterator it =
manager_->workers_.find(id);
EXPECT_TRUE(manager_->workers_.end() != it);
- EXPECT_EQ(state, it->second->state());
+ EXPECT_EQ(state, it->second->state_);
}
void CheckWorkerNotExist(int worker_process_id, int worker_route_id) {
@@ -78,16 +86,6 @@ class EmbeddedWorkerDevToolsManagerTest : public testing::Test {
EXPECT_EQ(size, manager_->workers_.size());
}
- void RegisterDevToolsClientHostFor(DevToolsAgentHost* agent_host,
- DevToolsClientHost* client_host) {
- DevToolsManagerImpl::GetInstance()->RegisterDevToolsClientHostFor(
- agent_host, client_host);
- }
-
- void ClientHostClosing(DevToolsClientHost* client_host) {
- DevToolsManagerImpl::GetInstance()->ClientHostClosing(client_host);
- }
-
base::MessageLoopForIO message_loop_;
BrowserThreadImpl ui_thread_;
scoped_ptr<TestBrowserContext> browser_context_;
@@ -97,7 +95,7 @@ class EmbeddedWorkerDevToolsManagerTest : public testing::Test {
};
TEST_F(EmbeddedWorkerDevToolsManagerTest, BasicTest) {
- scoped_refptr<DevToolsAgentHost> agent_host;
+ scoped_refptr<DevToolsAgentHostImpl> agent_host;
SharedWorkerInstance instance1(GURL("http://example.com/w.js"),
base::string16(),
@@ -112,75 +110,75 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, BasicTest) {
// Created -> Started -> Destroyed
CheckWorkerNotExist(1, 1);
manager_->SharedWorkerCreated(1, 1, instance1);
- CheckWorkerState(1, 1, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
- manager_->WorkerContextStarted(1, 1);
- CheckWorkerState(1, 1, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
+ CheckWorkerState(1, 1, WorkerState::WORKER_UNINSPECTED);
+ manager_->WorkerReadyForInspection(1, 1);
+ CheckWorkerState(1, 1, WorkerState::WORKER_UNINSPECTED);
manager_->WorkerDestroyed(1, 1);
CheckWorkerNotExist(1, 1);
// Created -> GetDevToolsAgentHost -> Started -> Destroyed
CheckWorkerNotExist(1, 2);
manager_->SharedWorkerCreated(1, 2, instance1);
- CheckWorkerState(1, 2, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
+ CheckWorkerState(1, 2, WorkerState::WORKER_UNINSPECTED);
agent_host = manager_->GetDevToolsAgentHostForWorker(1, 2);
EXPECT_TRUE(agent_host.get());
- CheckWorkerState(1, 2, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
+ CheckWorkerState(1, 2, WorkerState::WORKER_UNINSPECTED);
EXPECT_EQ(agent_host.get(), manager_->GetDevToolsAgentHostForWorker(1, 2));
- manager_->WorkerContextStarted(1, 2);
- CheckWorkerState(1, 2, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
+ manager_->WorkerReadyForInspection(1, 2);
+ CheckWorkerState(1, 2, WorkerState::WORKER_UNINSPECTED);
manager_->WorkerDestroyed(1, 2);
- CheckWorkerState(1, 2, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerState(1, 2, WorkerState::WORKER_TERMINATED);
agent_host = NULL;
CheckWorkerNotExist(1, 2);
// Created -> Started -> GetDevToolsAgentHost -> Destroyed
CheckWorkerNotExist(1, 3);
manager_->SharedWorkerCreated(1, 3, instance1);
- CheckWorkerState(1, 3, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
- manager_->WorkerContextStarted(1, 3);
- CheckWorkerState(1, 3, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
+ CheckWorkerState(1, 3, WorkerState::WORKER_UNINSPECTED);
+ manager_->WorkerReadyForInspection(1, 3);
+ CheckWorkerState(1, 3, WorkerState::WORKER_UNINSPECTED);
agent_host = manager_->GetDevToolsAgentHostForWorker(1, 3);
EXPECT_TRUE(agent_host.get());
- CheckWorkerState(1, 3, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
+ CheckWorkerState(1, 3, WorkerState::WORKER_UNINSPECTED);
manager_->WorkerDestroyed(1, 3);
- CheckWorkerState(1, 3, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerState(1, 3, WorkerState::WORKER_TERMINATED);
agent_host = NULL;
CheckWorkerNotExist(1, 3);
// Created -> Destroyed
CheckWorkerNotExist(1, 4);
manager_->SharedWorkerCreated(1, 4, instance1);
- CheckWorkerState(1, 4, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
+ CheckWorkerState(1, 4, WorkerState::WORKER_UNINSPECTED);
manager_->WorkerDestroyed(1, 4);
CheckWorkerNotExist(1, 4);
// Created -> GetDevToolsAgentHost -> Destroyed
CheckWorkerNotExist(1, 5);
manager_->SharedWorkerCreated(1, 5, instance1);
- CheckWorkerState(1, 5, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
+ CheckWorkerState(1, 5, WorkerState::WORKER_UNINSPECTED);
agent_host = manager_->GetDevToolsAgentHostForWorker(1, 5);
EXPECT_TRUE(agent_host.get());
- CheckWorkerState(1, 5, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
+ CheckWorkerState(1, 5, WorkerState::WORKER_UNINSPECTED);
manager_->WorkerDestroyed(1, 5);
- CheckWorkerState(1, 5, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerState(1, 5, WorkerState::WORKER_TERMINATED);
agent_host = NULL;
CheckWorkerNotExist(1, 5);
// Created -> GetDevToolsAgentHost -> Free agent_host -> Destroyed
CheckWorkerNotExist(1, 6);
manager_->SharedWorkerCreated(1, 6, instance1);
- CheckWorkerState(1, 6, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
+ CheckWorkerState(1, 6, WorkerState::WORKER_UNINSPECTED);
agent_host = manager_->GetDevToolsAgentHostForWorker(1, 6);
EXPECT_TRUE(agent_host.get());
- CheckWorkerState(1, 6, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
+ CheckWorkerState(1, 6, WorkerState::WORKER_UNINSPECTED);
agent_host = NULL;
manager_->WorkerDestroyed(1, 6);
CheckWorkerNotExist(1, 6);
}
TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) {
- scoped_refptr<DevToolsAgentHost> agent_host1;
- scoped_refptr<DevToolsAgentHost> agent_host2;
+ scoped_refptr<DevToolsAgentHostImpl> agent_host1;
+ scoped_refptr<DevToolsAgentHostImpl> agent_host2;
SharedWorkerInstance instance1(GURL("http://example.com/w1.js"),
base::string16(),
@@ -199,69 +197,66 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) {
scoped_ptr<TestDevToolsClientHost> client_host1(new TestDevToolsClientHost());
CheckWorkerNotExist(2, 1);
manager_->SharedWorkerCreated(2, 1, instance1);
- CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
+ CheckWorkerState(2, 1, WorkerState::WORKER_UNINSPECTED);
agent_host1 = manager_->GetDevToolsAgentHostForWorker(2, 1);
EXPECT_TRUE(agent_host1.get());
- CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
+ CheckWorkerState(2, 1, WorkerState::WORKER_UNINSPECTED);
EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 1));
- RegisterDevToolsClientHostFor(agent_host1.get(), client_host1.get());
- CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
- manager_->WorkerContextStarted(2, 1);
- CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
+ client_host1->InspectAgentHost(agent_host1.get());
+ CheckWorkerState(2, 1, WorkerState::WORKER_INSPECTED);
+ manager_->WorkerReadyForInspection(2, 1);
+ CheckWorkerState(2, 1, WorkerState::WORKER_INSPECTED);
manager_->WorkerDestroyed(2, 1);
- CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerState(2, 1, WorkerState::WORKER_TERMINATED);
EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 1));
// Created -> Started -> GetDevToolsAgentHost -> Register -> Destroyed
scoped_ptr<TestDevToolsClientHost> client_host2(new TestDevToolsClientHost());
manager_->SharedWorkerCreated(2, 2, instance2);
- CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
- manager_->WorkerContextStarted(2, 2);
- CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED);
+ CheckWorkerState(2, 2, WorkerState::WORKER_UNINSPECTED);
+ manager_->WorkerReadyForInspection(2, 2);
+ CheckWorkerState(2, 2, WorkerState::WORKER_UNINSPECTED);
agent_host2 = manager_->GetDevToolsAgentHostForWorker(2, 2);
EXPECT_TRUE(agent_host2.get());
EXPECT_NE(agent_host1.get(), agent_host2.get());
EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 2));
- CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
- RegisterDevToolsClientHostFor(agent_host2.get(), client_host2.get());
- CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
+ CheckWorkerState(2, 2, WorkerState::WORKER_UNINSPECTED);
+ client_host2->InspectAgentHost(agent_host2.get());
+ CheckWorkerState(2, 2, WorkerState::WORKER_INSPECTED);
manager_->WorkerDestroyed(2, 2);
- CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerState(2, 2, WorkerState::WORKER_TERMINATED);
EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 2));
// Re-created -> Started -> ClientHostClosing -> Destroyed
- CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerState(2, 1, WorkerState::WORKER_TERMINATED);
manager_->SharedWorkerCreated(2, 3, instance1);
CheckWorkerNotExist(2, 1);
- CheckWorkerState(
- 2, 3, EmbeddedWorkerDevToolsManager::WORKER_PAUSED_FOR_REATTACH);
+ CheckWorkerState(2, 3, WorkerState::WORKER_PAUSED_FOR_REATTACH);
EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 3));
- manager_->WorkerContextStarted(2, 3);
- CheckWorkerState(2, 3, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED);
- ClientHostClosing(client_host1.get());
+ manager_->WorkerReadyForInspection(2, 3);
+ CheckWorkerState(2, 3, WorkerState::WORKER_INSPECTED);
+ client_host1->InspectAgentHost(NULL);
manager_->WorkerDestroyed(2, 3);
- CheckWorkerState(2, 3, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerState(2, 3, WorkerState::WORKER_TERMINATED);
agent_host1 = NULL;
CheckWorkerNotExist(2, 3);
// Re-created -> Destroyed
- CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerState(2, 2, WorkerState::WORKER_TERMINATED);
manager_->SharedWorkerCreated(2, 4, instance2);
CheckWorkerNotExist(2, 2);
- CheckWorkerState(
- 2, 4, EmbeddedWorkerDevToolsManager::WORKER_PAUSED_FOR_REATTACH);
+ CheckWorkerState(2, 4, WorkerState::WORKER_PAUSED_FOR_REATTACH);
EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 4));
manager_->WorkerDestroyed(2, 4);
- CheckWorkerNotExist(2, 4);
- CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED);
+ CheckWorkerNotExist(2, 2);
+ CheckWorkerState(2, 4, WorkerState::WORKER_TERMINATED);
// Re-created -> ClientHostClosing -> Destroyed
manager_->SharedWorkerCreated(2, 5, instance2);
CheckWorkerNotExist(2, 2);
- CheckWorkerState(
- 2, 5, EmbeddedWorkerDevToolsManager::WORKER_PAUSED_FOR_REATTACH);
+ CheckWorkerState(2, 5, WorkerState::WORKER_PAUSED_FOR_REATTACH);
EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 5));
- ClientHostClosing(client_host2.get());
+ client_host2->InspectAgentHost(NULL);
CheckWorkerCount(1);
agent_host2 = NULL;
CheckWorkerCount(1);
@@ -269,4 +264,35 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) {
CheckWorkerCount(0);
}
+TEST_F(EmbeddedWorkerDevToolsManagerTest, ReattachTest) {
+ SharedWorkerInstance instance(GURL("http://example.com/w3.js"),
+ base::string16(),
+ base::string16(),
+ blink::WebContentSecurityPolicyTypeReport,
+ browser_context_->GetResourceContext(),
+ partition_id_);
+ scoped_ptr<TestDevToolsClientHost> client_host(new TestDevToolsClientHost());
+ // Created -> GetDevToolsAgentHost -> Register -> Destroyed
+ manager_->SharedWorkerCreated(3, 1, instance);
+ CheckWorkerState(3, 1, WorkerState::WORKER_UNINSPECTED);
+ scoped_refptr<DevToolsAgentHost> agent_host(
+ manager_->GetDevToolsAgentHostForWorker(3, 1));
+ EXPECT_TRUE(agent_host.get());
+ CheckWorkerState(3, 1, WorkerState::WORKER_UNINSPECTED);
+ client_host->InspectAgentHost(agent_host.get());
+ CheckWorkerState(3, 1, WorkerState::WORKER_INSPECTED);
+ manager_->WorkerDestroyed(3, 1);
+ CheckWorkerState(3, 1, WorkerState::WORKER_TERMINATED);
+ // ClientHostClosing -> Re-created -> release agent_host -> Destroyed
+ client_host->InspectAgentHost(NULL);
+ CheckWorkerState(3, 1, WorkerState::WORKER_TERMINATED);
+ manager_->SharedWorkerCreated(3, 2, instance);
+ CheckWorkerState(3, 2, WorkerState::WORKER_UNINSPECTED);
+ agent_host = NULL;
+ CheckWorkerState(3, 2, WorkerState::WORKER_UNINSPECTED);
+ manager_->WorkerDestroyed(3, 2);
+ CheckWorkerNotExist(3, 2);
+ CheckWorkerCount(0);
+}
+
} // namespace content
diff --git a/chromium/content/browser/devtools/forwarding_agent_host.cc b/chromium/content/browser/devtools/forwarding_agent_host.cc
index f1524e1b7e1..4d3e4fff0b0 100644
--- a/chromium/content/browser/devtools/forwarding_agent_host.cc
+++ b/chromium/content/browser/devtools/forwarding_agent_host.cc
@@ -4,8 +4,6 @@
#include "content/browser/devtools/forwarding_agent_host.h"
-#include "content/browser/devtools/devtools_manager_impl.h"
-
namespace content {
ForwardingAgentHost::ForwardingAgentHost(
@@ -17,12 +15,11 @@ ForwardingAgentHost::~ForwardingAgentHost() {
}
void ForwardingAgentHost::DispatchOnClientHost(const std::string& message) {
- DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(
- this, message);
+ SendMessageToClient(message);
}
void ForwardingAgentHost::ConnectionClosed() {
- NotifyCloseListener();
+ HostClosed();
}
void ForwardingAgentHost::Attach() {
@@ -33,9 +30,29 @@ void ForwardingAgentHost::Detach() {
delegate_->Detach();
}
-void ForwardingAgentHost::DispatchOnInspectorBackend(
+void ForwardingAgentHost::DispatchProtocolMessage(
const std::string& message) {
delegate_->SendMessageToBackend(message);
}
+DevToolsAgentHost::Type ForwardingAgentHost::GetType() {
+ return TYPE_EXTERNAL;
+}
+
+std::string ForwardingAgentHost::GetTitle() {
+ return "";
+}
+
+GURL ForwardingAgentHost::GetURL() {
+ return GURL();
+}
+
+bool ForwardingAgentHost::Activate() {
+ return false;
+}
+
+bool ForwardingAgentHost::Close() {
+ return false;
+}
+
} // content
diff --git a/chromium/content/browser/devtools/forwarding_agent_host.h b/chromium/content/browser/devtools/forwarding_agent_host.h
index 81e4aed5419..7f9bcec5ff9 100644
--- a/chromium/content/browser/devtools/forwarding_agent_host.h
+++ b/chromium/content/browser/devtools/forwarding_agent_host.h
@@ -20,16 +20,23 @@ class ForwardingAgentHost
ForwardingAgentHost(DevToolsExternalAgentProxyDelegate* delegate);
private:
- virtual ~ForwardingAgentHost();
+ ~ForwardingAgentHost() override;
// DevToolsExternalAgentProxy implementation.
- virtual void DispatchOnClientHost(const std::string& message) OVERRIDE;
- virtual void ConnectionClosed() OVERRIDE;
+ void DispatchOnClientHost(const std::string& message) override;
+ void ConnectionClosed() override;
// DevToolsAgentHostImpl implementation.
- virtual void Attach() OVERRIDE;
- virtual void Detach() OVERRIDE;
- virtual void DispatchOnInspectorBackend(const std::string& message) OVERRIDE;
+ void Attach() override;
+ void Detach() override;
+ void DispatchProtocolMessage(const std::string& message) override;
+
+ // DevToolsAgentHost implementation
+ Type GetType() override;
+ std::string GetTitle() override;
+ GURL GetURL() override;
+ bool Activate() override;
+ bool Close() override;
scoped_ptr<DevToolsExternalAgentProxyDelegate> delegate_;
};
diff --git a/chromium/content/browser/devtools/ipc_devtools_agent_host.cc b/chromium/content/browser/devtools/ipc_devtools_agent_host.cc
index 294a679c7f6..9218d5809bb 100644
--- a/chromium/content/browser/devtools/ipc_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/ipc_devtools_agent_host.cc
@@ -18,7 +18,7 @@ void IPCDevToolsAgentHost::Detach() {
OnClientDetached();
}
-void IPCDevToolsAgentHost::DispatchOnInspectorBackend(
+void IPCDevToolsAgentHost::DispatchProtocolMessage(
const std::string& message) {
SendMessageToAgent(new DevToolsAgentMsg_DispatchOnInspectorBackend(
MSG_ROUTING_NONE, message));
@@ -29,6 +29,10 @@ void IPCDevToolsAgentHost::InspectElement(int x, int y) {
GetId(), x, y));
}
+IPCDevToolsAgentHost::IPCDevToolsAgentHost()
+ : message_buffer_size_(0) {
+}
+
IPCDevToolsAgentHost::~IPCDevToolsAgentHost() {
}
@@ -38,4 +42,29 @@ void IPCDevToolsAgentHost::Reattach(const std::string& saved_agent_state) {
OnClientAttached();
}
+void IPCDevToolsAgentHost::ProcessChunkedMessageFromAgent(
+ const std::string& message, uint32 total_size) {
+ if (total_size && total_size == message.length()) {
+ DCHECK(message_buffer_size_ == 0);
+ SendMessageToClient(message);
+ return;
+ }
+
+ if (total_size) {
+ DCHECK(message_buffer_size_ == 0);
+ message_buffer_ = std::string();
+ message_buffer_.reserve(total_size);
+ message_buffer_size_ = total_size;
+ }
+
+ message_buffer_.append(message);
+
+ if (message_buffer_.size() >= message_buffer_size_) {
+ DCHECK(message_buffer_.size() == message_buffer_size_);
+ SendMessageToClient(message_buffer_);
+ message_buffer_ = std::string();
+ message_buffer_size_ = 0;
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/devtools/ipc_devtools_agent_host.h b/chromium/content/browser/devtools/ipc_devtools_agent_host.h
index 98c2794ac6e..a952588f758 100644
--- a/chromium/content/browser/devtools/ipc_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/ipc_devtools_agent_host.h
@@ -16,19 +16,26 @@ namespace content {
class CONTENT_EXPORT IPCDevToolsAgentHost : public DevToolsAgentHostImpl {
public:
// DevToolsAgentHostImpl implementation.
- virtual void Attach() OVERRIDE;
- virtual void Detach() OVERRIDE;
- virtual void DispatchOnInspectorBackend(const std::string& message) OVERRIDE;
- virtual void InspectElement(int x, int y) OVERRIDE;
+ void Attach() override;
+ void Detach() override;
+ void DispatchProtocolMessage(const std::string& message) override;
+ void InspectElement(int x, int y) override;
protected:
- virtual ~IPCDevToolsAgentHost();
+ IPCDevToolsAgentHost();
+ ~IPCDevToolsAgentHost() override;
void Reattach(const std::string& saved_agent_state);
+ void ProcessChunkedMessageFromAgent(const std::string& message,
+ uint32 total_size);
virtual void SendMessageToAgent(IPC::Message* msg) = 0;
virtual void OnClientAttached() = 0;
virtual void OnClientDetached() = 0;
+
+ private:
+ std::string message_buffer_;
+ uint32 message_buffer_size_;
};
} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/color_picker.cc b/chromium/content/browser/devtools/protocol/color_picker.cc
new file mode 100644
index 00000000000..dec4f3103b3
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/color_picker.cc
@@ -0,0 +1,265 @@
+// 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/devtools/protocol/color_picker.h"
+
+#include "base/bind.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/common/cursors/webcursor.h"
+#include "third_party/WebKit/public/platform/WebCursorInfo.h"
+#include "third_party/WebKit/public/platform/WebScreenInfo.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/size_conversions.h"
+
+namespace content {
+namespace devtools {
+namespace page {
+
+ColorPicker::ColorPicker(ColorPickedCallback callback)
+ : callback_(callback),
+ enabled_(false),
+ last_cursor_x_(-1),
+ last_cursor_y_(-1),
+ host_(nullptr),
+ weak_factory_(this) {
+ mouse_event_callback_ = base::Bind(
+ &ColorPicker::HandleMouseEvent,
+ base::Unretained(this));
+}
+
+ColorPicker::~ColorPicker() {
+}
+
+void ColorPicker::SetRenderViewHost(RenderViewHostImpl* host) {
+ if (host_ == host)
+ return;
+
+ if (host_)
+ host_->RemoveMouseEventCallback(mouse_event_callback_);
+ ResetFrame();
+ host_ = host;
+ if (enabled_ && host)
+ host->AddMouseEventCallback(mouse_event_callback_);
+}
+
+void ColorPicker::SetEnabled(bool enabled) {
+ if (enabled_ == enabled)
+ return;
+
+ enabled_ = enabled;
+ if (!host_)
+ return;
+
+ if (enabled) {
+ host_->AddMouseEventCallback(mouse_event_callback_);
+ UpdateFrame();
+ } else {
+ host_->RemoveMouseEventCallback(mouse_event_callback_);
+ ResetFrame();
+
+ WebCursor pointer_cursor;
+ WebCursor::CursorInfo cursor_info;
+ cursor_info.type = blink::WebCursorInfo::TypePointer;
+ pointer_cursor.InitFromCursorInfo(cursor_info);
+ host_->SetCursor(pointer_cursor);
+ }
+}
+
+void ColorPicker::OnSwapCompositorFrame() {
+ if (enabled_)
+ UpdateFrame();
+}
+
+void ColorPicker::UpdateFrame() {
+ if (!host_)
+ return;
+ RenderWidgetHostViewBase* view =
+ static_cast<RenderWidgetHostViewBase*>(host_->GetView());
+ if (!view)
+ return;
+
+ gfx::Size size = view->GetViewBounds().size();
+ view->CopyFromCompositingSurface(
+ gfx::Rect(size), size,
+ base::Bind(&ColorPicker::FrameUpdated,
+ weak_factory_.GetWeakPtr()),
+ kN32_SkColorType);
+}
+
+void ColorPicker::ResetFrame() {
+ frame_.reset();
+ last_cursor_x_ = -1;
+ last_cursor_y_ = -1;
+}
+
+void ColorPicker::FrameUpdated(bool succeeded, const SkBitmap& bitmap) {
+ if (!enabled_)
+ return;
+
+ if (succeeded) {
+ frame_ = bitmap;
+ UpdateCursor();
+ }
+}
+
+bool ColorPicker::HandleMouseEvent(const blink::WebMouseEvent& event) {
+ last_cursor_x_ = event.x;
+ last_cursor_y_ = event.y;
+ if (frame_.drawsNothing())
+ return true;
+
+ if (event.button == blink::WebMouseEvent::ButtonLeft &&
+ event.type == blink::WebInputEvent::MouseDown) {
+ if (last_cursor_x_ < 0 || last_cursor_x_ >= frame_.width() ||
+ last_cursor_y_ < 0 || last_cursor_y_ >= frame_.height()) {
+ return true;
+ }
+
+ SkAutoLockPixels lock_image(frame_);
+ SkColor sk_color = frame_.getColor(last_cursor_x_, last_cursor_y_);
+ callback_.Run(SkColorGetR(sk_color), SkColorGetG(sk_color),
+ SkColorGetB(sk_color), SkColorGetA(sk_color));
+ }
+ UpdateCursor();
+ return true;
+}
+
+void ColorPicker::UpdateCursor() {
+ if (!host_ || frame_.drawsNothing())
+ return;
+
+ if (last_cursor_x_ < 0 || last_cursor_x_ >= frame_.width() ||
+ last_cursor_y_ < 0 || last_cursor_y_ >= frame_.height()) {
+ return;
+ }
+
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ host_->GetView());
+ if (!view)
+ return;
+
+ // Due to platform limitations, we are using two different cursors
+ // depending on the platform. Mac and Win have large cursors with two circles
+ // for original spot and its magnified projection; Linux gets smaller (64 px)
+ // magnified projection only with centered hotspot.
+ // Mac Retina requires cursor to be > 120px in order to render smoothly.
+
+#if defined(OS_LINUX)
+ const float kCursorSize = 63;
+ const float kDiameter = 63;
+ const float kHotspotOffset = 32;
+ const float kHotspotRadius = 0;
+ const float kPixelSize = 9;
+#else
+ const float kCursorSize = 150;
+ const float kDiameter = 110;
+ const float kHotspotOffset = 25;
+ const float kHotspotRadius = 5;
+ const float kPixelSize = 10;
+#endif
+
+ blink::WebScreenInfo screen_info;
+ view->GetScreenInfo(&screen_info);
+ double device_scale_factor = screen_info.deviceScaleFactor;
+
+ skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(SkCanvas::NewRasterN32(
+ kCursorSize * device_scale_factor,
+ kCursorSize * device_scale_factor));
+ canvas->scale(device_scale_factor, device_scale_factor);
+ canvas->translate(0.5f, 0.5f);
+
+ SkPaint paint;
+
+ // Paint original spot with cross.
+ if (kHotspotRadius) {
+ paint.setStrokeWidth(1);
+ paint.setAntiAlias(false);
+ paint.setColor(SK_ColorDKGRAY);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawLine(kHotspotOffset, kHotspotOffset - 2 * kHotspotRadius,
+ kHotspotOffset, kHotspotOffset - kHotspotRadius,
+ paint);
+ canvas->drawLine(kHotspotOffset, kHotspotOffset + kHotspotRadius,
+ kHotspotOffset, kHotspotOffset + 2 * kHotspotRadius,
+ paint);
+ canvas->drawLine(kHotspotOffset - 2 * kHotspotRadius, kHotspotOffset,
+ kHotspotOffset - kHotspotRadius, kHotspotOffset,
+ paint);
+ canvas->drawLine(kHotspotOffset + kHotspotRadius, kHotspotOffset,
+ kHotspotOffset + 2 * kHotspotRadius, kHotspotOffset,
+ paint);
+
+ paint.setStrokeWidth(2);
+ paint.setAntiAlias(true);
+ canvas->drawCircle(kHotspotOffset, kHotspotOffset, kHotspotRadius, paint);
+ }
+
+ // Clip circle for magnified projection.
+ float padding = (kCursorSize - kDiameter) / 2;
+ SkPath clip_path;
+ clip_path.addOval(SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter));
+ clip_path.close();
+ canvas->clipPath(clip_path, SkRegion::kIntersect_Op, true);
+
+ // Project pixels.
+ int pixel_count = kDiameter / kPixelSize;
+ SkRect src_rect = SkRect::MakeXYWH(last_cursor_x_ - pixel_count / 2,
+ last_cursor_y_ - pixel_count / 2,
+ pixel_count, pixel_count);
+ SkRect dst_rect = SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter);
+ canvas->drawBitmapRectToRect(frame_, &src_rect, dst_rect);
+
+ // Paint grid.
+ paint.setStrokeWidth(1);
+ paint.setAntiAlias(false);
+ paint.setColor(SK_ColorGRAY);
+ for (int i = 0; i < pixel_count; ++i) {
+ canvas->drawLine(padding + i * kPixelSize, padding,
+ padding + i * kPixelSize, kCursorSize - padding, paint);
+ canvas->drawLine(padding, padding + i * kPixelSize,
+ kCursorSize - padding, padding + i * kPixelSize, paint);
+ }
+
+ // Paint central pixel in red.
+ SkRect pixel = SkRect::MakeXYWH((kCursorSize - kPixelSize) / 2,
+ (kCursorSize - kPixelSize) / 2,
+ kPixelSize, kPixelSize);
+ paint.setColor(SK_ColorRED);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawRect(pixel, paint);
+
+ // Paint outline.
+ paint.setStrokeWidth(2);
+ paint.setColor(SK_ColorDKGRAY);
+ paint.setAntiAlias(true);
+ canvas->drawCircle(kCursorSize / 2, kCursorSize / 2, kDiameter / 2, paint);
+
+ SkBitmap result;
+ result.allocN32Pixels(kCursorSize * device_scale_factor,
+ kCursorSize * device_scale_factor);
+ canvas->readPixels(&result, 0, 0);
+
+ WebCursor cursor;
+ WebCursor::CursorInfo cursor_info;
+ cursor_info.type = blink::WebCursorInfo::TypeCustom;
+ cursor_info.image_scale_factor = device_scale_factor;
+ cursor_info.custom_image = result;
+ cursor_info.hotspot =
+ gfx::Point(kHotspotOffset * device_scale_factor,
+ kHotspotOffset * device_scale_factor);
+#if defined(OS_WIN)
+ cursor_info.external_handle = 0;
+#endif
+
+ cursor.InitFromCursorInfo(cursor_info);
+ DCHECK(host_);
+ host_->SetCursor(cursor);
+}
+
+} // namespace page
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/color_picker.h b/chromium/content/browser/devtools/protocol/color_picker.h
new file mode 100644
index 00000000000..e59a35137fd
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/color_picker.h
@@ -0,0 +1,57 @@
+// 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_DEVTOOLS_PROTOCOL_COLOR_PICKER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_COLOR_PICKER_H_
+
+#include "base/callback.h"
+#include "content/public/browser/render_widget_host.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace blink {
+class WebMouseEvent;
+}
+
+namespace content {
+
+class RenderViewHostImpl;
+
+namespace devtools {
+namespace page {
+
+class ColorPicker {
+ public:
+ typedef base::Callback<void(int, int, int, int)> ColorPickedCallback;
+
+ explicit ColorPicker(ColorPickedCallback callback);
+ virtual ~ColorPicker();
+
+ void SetRenderViewHost(RenderViewHostImpl* host);
+ void SetEnabled(bool enabled);
+ void OnSwapCompositorFrame();
+
+ private:
+ void UpdateFrame();
+ void ResetFrame();
+ void FrameUpdated(bool succeeded, const SkBitmap& bitmap);
+ bool HandleMouseEvent(const blink::WebMouseEvent& event);
+ void UpdateCursor();
+
+ ColorPickedCallback callback_;
+ bool enabled_;
+ SkBitmap frame_;
+ int last_cursor_x_;
+ int last_cursor_y_;
+ RenderWidgetHost::MouseEventCallback mouse_event_callback_;
+ RenderViewHostImpl* host_;
+ base::WeakPtrFactory<ColorPicker> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ColorPicker);
+};
+
+} // namespace page
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_COLOR_PICKER_H_
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_client.cc b/chromium/content/browser/devtools/protocol/devtools_protocol_client.cc
new file mode 100644
index 00000000000..a34189e0efc
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_client.cc
@@ -0,0 +1,97 @@
+// 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/devtools/protocol/devtools_protocol_client.h"
+
+namespace content {
+
+DevToolsProtocolClient::DevToolsProtocolClient(
+ const RawMessageCallback& raw_message_callback)
+ : raw_message_callback_(raw_message_callback) {
+}
+
+DevToolsProtocolClient::~DevToolsProtocolClient() {
+}
+
+void DevToolsProtocolClient::SendNotification(const std::string& method,
+ base::DictionaryValue* params) {
+ scoped_refptr<DevToolsProtocol::Notification> notification =
+ new DevToolsProtocol::Notification(method, params);
+ SendRawMessage(notification->Serialize());
+}
+
+void DevToolsProtocolClient::SendAsyncResponse(
+ scoped_refptr<DevToolsProtocol::Response> response) {
+ SendRawMessage(response->Serialize());
+}
+
+void DevToolsProtocolClient::SendRawMessage(const std::string& message) {
+ raw_message_callback_.Run(message);
+}
+
+void DevToolsProtocolClient::SendInvalidParamsResponse(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message) {
+ SendAsyncResponse(command->InvalidParamResponse(message));
+}
+
+void DevToolsProtocolClient::SendInternalErrorResponse(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message) {
+ SendAsyncResponse(command->InternalErrorResponse(message));
+}
+
+void DevToolsProtocolClient::SendServerErrorResponse(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message) {
+ SendAsyncResponse(command->ServerErrorResponse(message));
+}
+
+typedef DevToolsProtocolClient::Response Response;
+
+Response Response::FallThrough() {
+ Response response;
+ response.status_ = ResponseStatus::RESPONSE_STATUS_FALLTHROUGH;
+ return response;
+}
+
+Response Response::OK() {
+ Response response;
+ response.status_ = ResponseStatus::RESPONSE_STATUS_OK;
+ return response;
+}
+
+Response Response::InvalidParams(const std::string& message) {
+ Response response;
+ response.status_ = ResponseStatus::RESPONSE_STATUS_INVALID_PARAMS;
+ response.message_ = message;
+ return response;
+}
+
+Response Response::InternalError(const std::string& message) {
+ Response response;
+ response.status_ = ResponseStatus::RESPONSE_STATUS_INTERNAL_ERROR;
+ response.message_ = message;
+ return response;
+}
+
+Response Response::ServerError(const std::string& message) {
+ Response response;
+ response.status_ = ResponseStatus::RESPONSE_STATUS_SERVER_ERROR;
+ response.message_ = message;
+ return response;
+}
+
+DevToolsProtocolClient::ResponseStatus Response::status() const {
+ return status_;
+}
+
+const std::string& Response::message() const {
+ return message_;
+}
+
+Response::Response() {
+}
+
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_client.h b/chromium/content/browser/devtools/protocol/devtools_protocol_client.h
new file mode 100644
index 00000000000..620a7c14995
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_client.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_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_CLIENT_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_CLIENT_H_
+
+#include "content/browser/devtools/devtools_protocol.h"
+
+namespace content {
+
+class DevToolsProtocolClient {
+ public:
+ typedef base::Callback<void(const std::string& message)>
+ RawMessageCallback;
+
+ enum ResponseStatus {
+ RESPONSE_STATUS_FALLTHROUGH,
+ RESPONSE_STATUS_OK,
+ RESPONSE_STATUS_INVALID_PARAMS,
+ RESPONSE_STATUS_INTERNAL_ERROR,
+ RESPONSE_STATUS_SERVER_ERROR,
+ };
+
+ struct Response {
+ public:
+ static Response FallThrough();
+ static Response OK();
+ static Response InvalidParams(const std::string& message);
+ static Response InternalError(const std::string& message);
+ static Response ServerError(const std::string& message);
+
+ ResponseStatus status() const;
+ const std::string& message() const;
+
+ private:
+ Response();
+
+ ResponseStatus status_;
+ std::string message_;
+ };
+
+ void SendInvalidParamsResponse(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message);
+ void SendInternalErrorResponse(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message);
+ void SendServerErrorResponse(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message);
+
+ // Sends message to client, the caller is presumed to properly
+ // format the message. Do not use unless you must.
+ void SendRawMessage(const std::string& message);
+
+ protected:
+ DevToolsProtocolClient(const RawMessageCallback& raw_message_callback);
+
+ virtual ~DevToolsProtocolClient();
+
+ void SendNotification(const std::string& method,
+ base::DictionaryValue* params);
+
+ void SendAsyncResponse(scoped_refptr<DevToolsProtocol::Response> response);
+
+ private:
+ RawMessageCallback raw_message_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsProtocolClient);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_CLIENT_H_
diff --git a/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
new file mode 100755
index 00000000000..dd165faec5f
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -0,0 +1,776 @@
+#!/usr/bin/env python
+# 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.
+
+import sys
+import string
+import json
+
+input_json_path = sys.argv[1]
+output_cc_path = sys.argv[2]
+output_h_path = sys.argv[3]
+
+header = """\
+// 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.
+
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// Generated by
+// content/public/browser/devtools_protocol_handler_generator.py from
+// third_party/WebKit/Source/devtools/protocol.json
+"""
+
+template_h = string.Template(header + """\
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_HANDLER_IMPL_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_HANDLER_IMPL_H_
+
+#include "content/browser/devtools/devtools_protocol.h"
+#include "content/browser/devtools/protocol/devtools_protocol_client.h"
+
+namespace content {
+
+class DevToolsProtocolHandlerImpl;
+
+namespace devtools {
+
+${types}\
+
+} // namespace devtools
+
+class DevToolsProtocolHandlerImpl : public DevToolsProtocol::Handler {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+ typedef DevToolsProtocolClient::ResponseStatus ResponseStatus;
+
+ DevToolsProtocolHandlerImpl();
+ virtual ~DevToolsProtocolHandlerImpl();
+
+${setters}\
+
+ private:
+${friends}\
+
+${methods}\
+
+${fields}\
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_HANDLER_IMPL_H_
+""")
+
+tmpl_typedef = string.Template("""\
+namespace ${domain} {
+typedef ${param_type} ${declared_name};
+} // namespace ${domain}
+""")
+
+tmpl_struct = string.Template("""\
+namespace ${domain} {
+struct ${declared_name} {
+ public:
+ ${declared_name}();
+
+${methods}\
+
+ private:
+ friend class ::content::DevToolsProtocolHandlerImpl;
+
+${fields}\
+};
+} // namespace ${domain}
+""")
+
+tmpl_struct_setter = string.Template("""\
+ void set_${param}(${pass_type} ${param});
+""")
+
+tmpl_struct_field = string.Template("""\
+ ${param_type} ${param}_;
+ bool has_${param}_;
+""")
+
+tmpl_enum = string.Template("""\
+namespace ${domain} {
+namespace ${subdomain} {
+${values}\
+} // namespace ${subdomain}
+} // namespace ${domain}
+""")
+
+tmpl_enum_value = string.Template("""\
+extern const char k${Param}${Value}[];
+""")
+
+tmpl_enum_value_def = string.Template("""\
+const char k${Param}${Value}[] = "${value}";
+""")
+
+tmpl_handler = string.Template("""\
+namespace ${domain} {
+class ${Domain}Handler;
+} // namespace domain
+""")
+
+tmpl_client = string.Template("""\
+namespace ${domain} {
+class Client : public DevToolsProtocolClient {
+ public:
+ Client(const RawMessageCallback& raw_message_callback);
+ virtual ~Client();
+
+${methods}\
+};
+} // namespace ${domain}
+""")
+
+tmpl_event = string.Template("""\
+ void ${Command}(
+ const ${Command}Params& params);
+""")
+
+tmpl_response = string.Template("""\
+ void Send${Command}Response(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const ${Command}Response& params);
+""")
+
+tmpl_setter = string.Template("""\
+ void Set${Domain}Handler(
+ devtools::${domain}::${Domain}Handler* ${domain}_handler);
+""")
+
+tmpl_friend = string.Template("""\
+ friend class devtools::${domain}::Client;
+""")
+
+tmpl_callback = string.Template("""\
+ scoped_refptr<DevToolsProtocol::Response>
+ On${Domain}${Command}(
+ scoped_refptr<DevToolsProtocol::Command> command);
+""")
+
+tmpl_to_value = string.Template("""\
+ static base::DictionaryValue* ToValue(
+ const devtools::${domain}::${declared_name}& src);
+""")
+
+tmpl_field = string.Template("""\
+ devtools::${domain}::${Domain}Handler* ${domain}_handler_;
+""")
+
+template_cc = string.Template(header + """\
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+
+#include "base/bind.h"
+${includes}\
+
+namespace content {
+
+DevToolsProtocolHandlerImpl::DevToolsProtocolHandlerImpl()
+ : ${fields_init} {
+}
+
+DevToolsProtocolHandlerImpl::~DevToolsProtocolHandlerImpl() {
+}
+
+namespace {
+
+typedef DevToolsProtocolClient::ResponseStatus ResponseStatus;
+
+bool CreateCommonResponse(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const DevToolsProtocolClient::Response& response,
+ scoped_refptr<DevToolsProtocol::Response>* protocol_response) {
+ switch (response.status()) {
+ case ResponseStatus::RESPONSE_STATUS_FALLTHROUGH:
+ *protocol_response = NULL;
+ break;
+ case ResponseStatus::RESPONSE_STATUS_OK:
+ return false;
+ case ResponseStatus::RESPONSE_STATUS_INVALID_PARAMS:
+ *protocol_response = command->InvalidParamResponse(response.message());
+ break;
+ case ResponseStatus::RESPONSE_STATUS_INTERNAL_ERROR:
+ *protocol_response = command->InternalErrorResponse(response.message());
+ break;
+ case ResponseStatus::RESPONSE_STATUS_SERVER_ERROR:
+ *protocol_response = command->ServerErrorResponse(response.message());
+ break;
+ }
+ return true;
+}
+
+} // namespace
+
+${methods}\
+
+namespace devtools {
+
+${types}\
+
+} // namespace devtools
+
+} // namespace content
+""")
+
+tmpl_include = string.Template("""\
+#include "content/browser/devtools/protocol/${domain}_handler.h"
+""")
+
+tmpl_field_init = string.Template("${domain}_handler_(NULL)")
+
+tmpl_setter_impl = string.Template("""\
+void DevToolsProtocolHandlerImpl::Set${Domain}Handler(
+ devtools::${domain}::${Domain}Handler* ${domain}_handler) {
+ DCHECK(!${domain}_handler_);
+ ${domain}_handler_ = ${domain}_handler;
+${initializations}\
+}
+""")
+
+tmpl_register = string.Template("""\
+ RegisterCommandHandler(
+ "${Domain}.${command}",
+ base::Bind(
+ &DevToolsProtocolHandlerImpl::On${Domain}${Command},
+ base::Unretained(this)));
+""")
+
+tmpl_init_client = string.Template("""\
+ ${domain}_handler_->SetClient(make_scoped_ptr(
+ new devtools::${domain}::Client(
+ base::Bind(&DevToolsProtocolHandlerImpl::SendRawMessage,
+ base::Unretained(this)))));
+""")
+
+tmpl_callback_impl = string.Template("""\
+scoped_refptr<DevToolsProtocol::Response>
+DevToolsProtocolHandlerImpl::On${Domain}${Command}(
+ scoped_refptr<DevToolsProtocol::Command> command) {
+${prep}\
+ Response response = ${domain}_handler_->${Command}(${args});
+ scoped_refptr<DevToolsProtocol::Response> protocol_response;
+ if (CreateCommonResponse(command, response, &protocol_response))
+ return protocol_response;
+ base::DictionaryValue* dict = new base::DictionaryValue();
+${wrap}\
+ return command->SuccessResponse(dict);
+}
+""")
+
+tmpl_callback_async_impl = string.Template("""\
+scoped_refptr<DevToolsProtocol::Response>
+DevToolsProtocolHandlerImpl::On${Domain}${Command}(
+ scoped_refptr<DevToolsProtocol::Command> command) {
+${prep}\
+ return ${domain}_handler_->${Command}(${args});
+}
+""")
+
+params_prep = """\
+ base::DictionaryValue* params = command->params();
+"""
+
+tmpl_prep_req = string.Template("""\
+ ${param_type} in_${param}${init};
+ if (!params ||
+ !params->Get${Type}("${proto_param}", &in_${param}))
+ return command->InvalidParamResponse("${proto_param}");
+""")
+
+tmpl_prep_req_list = string.Template("""\
+ base::ListValue* list_${param} = NULL;
+ if (!params || !params->GetList("${proto_param}", &list_${param}))
+ return command->InvalidParamResponse("${proto_param}");
+ ${param_type} in_${param};
+ for (base::ListValue::const_iterator it =
+ list_${param}->begin(); it != list_${param}->end(); ++it) {
+ ${item_type} item${item_init};
+ if (!(*it)->GetAs${ItemType}(&item))
+ return command->InvalidParamResponse("${proto_param}");
+ in_${param}.push_back(item);
+ }
+""")
+
+tmpl_prep_opt = string.Template("""\
+ ${param_type} in_${param}${init};
+ bool ${param}_found = params && params->Get${Type}(
+ "${proto_param}",
+ &in_${param});
+""")
+
+tmpl_prep_output = string.Template("""\
+ ${param_type} out_${param}${init};
+""")
+
+tmpl_arg_req = string.Template("in_${param}")
+
+tmpl_arg_opt = string.Template(
+ "${param}_found ?\n &in_${param} : NULL")
+
+tmpl_arg_output = string.Template("&out_${param}")
+
+tmpl_to_value_impl = string.Template("""\
+// static
+base::DictionaryValue* DevToolsProtocolHandlerImpl::ToValue(
+ const devtools::${domain}::${declared_name}& src) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+${dchecks}\
+${wrap}\
+ return dict;
+}
+""")
+
+tmpl_dcheck = string.Template("""\
+ DCHECK(${cond_name});
+""")
+
+tmpl_struct_impl = string.Template("""\
+namespace ${domain} {
+
+${declared_name}::${declared_name}()${fields} {
+}
+
+${methods}\
+
+} // namespace ${domain}
+""")
+
+tmpl_struct_field_init = string.Template("has_${param}_(false)")
+
+tmpl_struct_setter_impl = string.Template("""\
+void ${declared_name}::set_${param}(
+ ${pass_type} ${param}) {
+ ${param}_ = ${param};
+ has_${param}_ = true;
+}
+""")
+
+tmpl_client_impl = string.Template("""\
+namespace ${domain} {
+
+Client::Client(const RawMessageCallback& raw_message_callback)
+ : DevToolsProtocolClient(raw_message_callback) {
+}
+
+Client::~Client() {
+}
+
+${methods}\
+
+} // namespace ${domain}
+""")
+
+tmpl_event_impl = string.Template("""\
+void Client::${Command}(
+ const ${Command}Params& params) {
+ SendNotification("${Domain}.${command}",
+ DevToolsProtocolHandlerImpl::ToValue(params));
+}
+""")
+
+tmpl_response_impl = string.Template("""\
+void Client::Send${Command}Response(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const ${Command}Response& params) {
+ SendAsyncResponse(
+ command->SuccessResponse(DevToolsProtocolHandlerImpl::ToValue(params)));
+}
+""")
+
+tmpl_wrap = string.Template("""\
+ dict->Set${Type}("${proto_param}", ${var_name});
+""")
+
+tmpl_wrap_dict = string.Template("""\
+ dict->Set("${proto_param}",
+ DevToolsProtocolHandlerImpl::ToValue(${var_name}));
+""")
+
+tmpl_wrap_obj = string.Template("""\
+ dict->Set("${proto_param}", ${var_name});
+""")
+
+tmpl_wrap_list = string.Template("""\
+ base::ListValue* list_${param} = new base::ListValue();
+ for (${param_type}::const_iterator it =
+ ${var_name}.begin(); it != ${var_name}.end(); ++it) {
+${append}\
+ }
+ dict->Set("${proto_param}", list_${param});
+""")
+
+tmpl_append = string.Template("""\
+ list_${param}->Append${Type}(*it);
+""")
+
+tmpl_append_dict = string.Template("""\
+ list_${param}->Append(DevToolsProtocolHandlerImpl::ToValue(*it));
+""")
+
+tmpl_append_obj = string.Template("""\
+ list_${param}->Append(*it);
+""")
+
+tmpl_wrap_opt = string.Template("""\
+ if (${cond_name})
+ dict->Set${Type}("${proto_param}", ${var_name});
+""")
+
+tmpl_typename = string.Template("devtools::${domain}::${declared_name}")
+
+def Capitalize(s):
+ return s[:1].upper() + s[1:]
+
+def Decapitalize(s):
+ return s.lower()
+
+def Uncamelcase(s):
+ result = ""
+ for i, c in enumerate(s):
+ if c.isupper():
+ if (i > 0) and ((i < len(s)-1) and s[i+1].islower() or s[i-1].islower()):
+ result += "_"
+ result += c.lower()
+ else:
+ result += c
+ return result
+
+types = {}
+json_api = json.loads(open(input_json_path, "r").read())
+type_decls = []
+type_impls = []
+handler_methods = []
+handler_method_impls = []
+
+for json_domain in json_api["domains"]:
+ if "types" in json_domain:
+ for json_type in json_domain["types"]:
+ types["%s.%s" % (json_domain["domain"], json_type["id"])] = json_type
+
+def DeclareStruct(json_properties, mapping):
+ methods = []
+ fields = []
+ fields_init = []
+ method_impls = []
+ dchecks = []
+ wrap = []
+ for json_prop in json_properties:
+ prop_map = mapping.copy()
+ prop_map["proto_param"] = json_prop["name"]
+ prop_map["param"] = Uncamelcase(json_prop["name"])
+ prop_map["var_name"] = "src.%s_" % prop_map["param"]
+ prop_map["cond_name"] = "src.has_%s_" % prop_map["param"]
+ ResolveType(json_prop, prop_map)
+ prop_map["declared_name"] = mapping["declared_name"]
+ methods.append(tmpl_struct_setter.substitute(prop_map))
+ fields.append(tmpl_struct_field.substitute(prop_map))
+ fields_init.append(tmpl_struct_field_init.substitute(prop_map))
+ method_impls.append(tmpl_struct_setter_impl.substitute(prop_map))
+ if json_prop.get("optional"):
+ if param_map["Type"] in ["List", "Dictionary"]:
+ # TODO(vkuzkokov) Implement.
+ raise Exception(
+ "Optional array and object properties are not implemented")
+ wrap.append(tmpl_wrap_opt.substitute(prop_map))
+ else:
+ dchecks.append(tmpl_dcheck.substitute(prop_map));
+ if not "wrap" in prop_map:
+ raise Exception("Arrays of arrays are not implemented")
+ wrap.append(prop_map["wrap"])
+
+ type_decls.append(tmpl_struct.substitute(mapping,
+ methods = "".join(methods),
+ fields = "".join(fields)))
+ fields_init_str = ""
+ if len(fields_init) > 0:
+ fields_init_str = "\n : " + (",\n ".join(fields_init))
+ type_impls.append(tmpl_struct_impl.substitute(mapping,
+ fields = fields_init_str,
+ methods = "\n".join(method_impls)))
+ handler_methods.append(tmpl_to_value.substitute(mapping))
+ handler_method_impls.append(tmpl_to_value_impl.substitute(mapping,
+ dchecks = "".join(dchecks),
+ wrap = "".join(wrap)))
+
+def ResolveRef(json, mapping):
+ dot_pos = json["$ref"].find(".")
+ if dot_pos == -1:
+ domain_name = mapping["Domain"]
+ type_name = json["$ref"]
+ else:
+ domain_name = json["$ref"][:dot_pos]
+ type_name = json["$ref"][dot_pos + 1:]
+ json_type = types["%s.%s" % (domain_name, type_name)]
+ mapping["declared_name"] = Capitalize(type_name)
+ mapping["Domain"] = domain_name
+ mapping["domain"] = Decapitalize(domain_name)
+ mapping["param_type"] = tmpl_typename.substitute(mapping)
+ if json_type.get("enum"):
+ # TODO(vkuzkokov) Implement. Approximate template:
+ # namespace ${domain} { const char k${declared_name}${Value}; }
+ raise Exception("Named enumerations are not implemented")
+ ResolveType(json_type, mapping)
+ if not "___struct_declared" in json_type:
+ json_type["___struct_declared"] = True;
+ if (json_type.get("type") == "object") and ("properties" in json_type):
+ DeclareStruct(json_type["properties"], mapping)
+ else:
+ type_decls.append(tmpl_typedef.substitute(mapping))
+ mapping["param_type"] = tmpl_typename.substitute(mapping)
+
+def ResolveArray(json, mapping):
+ items_map = mapping.copy()
+ ResolveType(json["items"], items_map)
+ mapping["param_type"] = "std::vector<%s>" % items_map["param_type"]
+ mapping["Type"] = "List"
+ if "append" in items_map:
+ mapping["wrap"] = tmpl_wrap_list.substitute(mapping,
+ append = items_map["append"])
+ mapping["pass_type"] = "const %s&" % mapping["param_type"]
+ mapping["prep_req"] = tmpl_prep_req_list.substitute(mapping,
+ item_type = items_map["param_type"],
+ item_init = items_map["init"],
+ ItemType = items_map["Type"])
+ # TODO(vkuzkokov) mapping["append"]: template for array of arrays.
+
+def ResolveObject(json, mapping):
+ mapping["Type"] = "Dictionary"
+ if "properties" in json:
+ if not "declared_name" in mapping:
+ mapping["declared_name"] = ("%s%s" %
+ (mapping["Command"], Capitalize(mapping["proto_param"])))
+ mapping["param_type"] = tmpl_typename.substitute(mapping)
+ DeclareStruct(json["properties"], mapping)
+ mapping["append"] = tmpl_append_dict.substitute(mapping)
+ mapping["wrap"] = tmpl_wrap_dict.substitute(mapping)
+ mapping["pass_type"] = "const %s&" % mapping["param_type"]
+ else:
+ mapping["param_type"] = "base::DictionaryValue*"
+ mapping["append"] = tmpl_append_obj.substitute(mapping)
+ mapping["wrap"] = tmpl_wrap_obj.substitute(mapping)
+ mapping["pass_type"] = mapping["param_type"]
+
+def ResolvePrimitive(json, mapping):
+ jsonrpc_type = json["type"]
+ if jsonrpc_type == "boolean":
+ mapping["param_type"] = "bool"
+ mapping["Type"] = "Boolean"
+ mapping["init"] = " = false"
+ elif jsonrpc_type == "integer":
+ mapping["param_type"] = "int"
+ mapping["Type"] = "Integer"
+ mapping["init"] = " = 0"
+ elif jsonrpc_type == "number":
+ mapping["param_type"] = "double"
+ mapping["Type"] = "Double"
+ mapping["init"] = " = 0.0"
+ elif jsonrpc_type == "string":
+ mapping["param_type"] = "std::string"
+ mapping["pass_type"] = "const std::string&"
+ mapping["Type"] = "String"
+ if "enum" in json:
+ values = []
+ value_defs = []
+ if "declared_name" in mapping:
+ mapping["subdomain"] = Uncamelcase(mapping["declared_name"])
+ else:
+ mapping["subdomain"] = Uncamelcase(mapping["command"])
+ mapping["Param"] = Capitalize(mapping["proto_param"])
+ for enum_value in json["enum"]:
+ values.append(tmpl_enum_value.substitute(mapping,
+ Value = Capitalize(enum_value)))
+ value_defs.append(tmpl_enum_value_def.substitute(mapping,
+ value = enum_value,
+ Value = Capitalize(enum_value)))
+ type_decls.append(tmpl_enum.substitute(mapping,
+ values = "".join(values)))
+ type_impls.append(tmpl_enum.substitute(mapping,
+ values = "".join(value_defs)))
+ else:
+ raise Exception("Unknown type: %s" % json_type)
+ mapping["wrap"] = tmpl_wrap.substitute(mapping)
+ mapping["append"] = tmpl_append.substitute(mapping)
+ mapping["prep_req"] = tmpl_prep_req.substitute(mapping)
+ if jsonrpc_type != "string":
+ mapping["pass_type"] = mapping["param_type"]
+
+def ResolveType(json, mapping):
+ mapping["init"] = ""
+ if "$ref" in json:
+ ResolveRef(json, mapping)
+ elif "type" in json:
+ jsonrpc_type = json["type"]
+ if jsonrpc_type == "array":
+ ResolveArray(json, mapping)
+ elif jsonrpc_type == "object":
+ ResolveObject(json, mapping)
+ else:
+ ResolvePrimitive(json, mapping)
+ else:
+ raise Exception("Unknown type at %s.%s %s" %
+ (mapping["Domain"], mapping["command"], mapping["proto_param"]))
+
+setters = []
+friends = []
+fields = []
+
+includes = []
+fields_init = []
+
+for json_domain in json_api["domains"]:
+ domain_map = {}
+ domain_map["Domain"] = json_domain["domain"]
+ domain_map["domain"] = Decapitalize(json_domain["domain"])
+
+ initializations = []
+ client_methods = []
+ client_method_impls = []
+ domain_empty = True
+ domain_needs_client = False
+
+ if "commands" in json_domain:
+ for json_command in json_domain["commands"]:
+ if (not ("handlers" in json_command) or
+ not ("browser" in json_command["handlers"])):
+ continue
+ domain_empty = False
+
+ command_map = domain_map.copy()
+ command_map["command"] = json_command["name"]
+ command_map["Command"] = Capitalize(json_command["name"])
+
+ prep = []
+ args = []
+
+ if "parameters" in json_command:
+ for json_param in json_command["parameters"]:
+ param_map = command_map.copy()
+ param_map["proto_param"] = json_param["name"]
+ param_map["param"] = Uncamelcase(json_param["name"])
+ param_map["var_name"] = "in_%s" % param_map["param"]
+
+ ResolveType(json_param, param_map)
+ if len(prep) == 0:
+ prep.append(params_prep)
+ if json_param.get("optional"):
+ if param_map["Type"] in ["List", "Dictionary"]:
+ # TODO(vkuzkokov) Implement transformation of base::ListValue
+ # to std::vector and base::DictonaryValue to struct.
+ raise Exception(
+ "Optional array and object parameters are not implemented")
+ prep.append(tmpl_prep_opt.substitute(param_map))
+ args.append(tmpl_arg_opt.substitute(param_map))
+ else:
+ prep.append(param_map["prep_req"])
+ args.append(tmpl_arg_req.substitute(param_map))
+
+ if json_command.get("async"):
+ domain_needs_client = True
+ json_returns = []
+ if "returns" in json_command:
+ json_returns = json_command["returns"]
+ command_map["declared_name"] = "%sResponse" % command_map["Command"]
+ DeclareStruct(json_returns, command_map)
+ # TODO(vkuzkokov) Pass async callback instance similar to how
+ # InspectorBackendDispatcher does it. This, however, can work
+ # only if Blink and Chrome are in the same repo.
+ args.append("command")
+ handler_method_impls.append(
+ tmpl_callback_async_impl.substitute(command_map,
+ prep = "".join(prep),
+ args = "\n " + ",\n ".join(args)))
+ client_methods.append(tmpl_response.substitute(command_map))
+ client_method_impls.append(tmpl_response_impl.substitute(command_map))
+ else:
+ wrap = []
+ if "returns" in json_command:
+ for json_param in json_command["returns"]:
+ param_map = command_map.copy()
+ param_map["proto_param"] = json_param["name"]
+ param_map["param"] = Uncamelcase(json_param["name"])
+ param_map["var_name"] = "out_%s" % param_map["param"]
+
+ if json_param.get("optional"):
+ # TODO(vkuzkokov) Implement Optional<T> for value types.
+ raise Exception("Optional return values are not implemented")
+ ResolveType(json_param, param_map)
+ prep.append(tmpl_prep_output.substitute(param_map))
+ args.append(tmpl_arg_output.substitute(param_map))
+ if not "wrap" in param_map:
+ raise Exception("Arrays of arrays are not implemented")
+ wrap.append(param_map["wrap"])
+
+ args_str = ""
+ if len(args) > 0:
+ args_str = "\n " + ",\n ".join(args)
+ handler_method_impls.append(tmpl_callback_impl.substitute(command_map,
+ prep = "".join(prep),
+ args = args_str,
+ wrap = "".join(wrap)))
+
+ initializations.append(tmpl_register.substitute(command_map))
+ handler_methods.append(tmpl_callback.substitute(command_map))
+
+ if "events" in json_domain:
+ for json_event in json_domain["events"]:
+ if (not ("handlers" in json_event) or
+ not ("browser" in json_event["handlers"])):
+ continue
+ domain_empty = False
+ domain_needs_client = True
+
+ event_map = domain_map.copy()
+ event_map["command"] = json_event["name"]
+ event_map["Command"] = Capitalize(json_event["name"])
+
+ json_parameters = []
+ if "parameters" in json_event:
+ json_parameters = json_event["parameters"]
+ event_map["declared_name"] = "%sParams" % event_map["Command"]
+ DeclareStruct(json_parameters, event_map);
+
+ client_methods.append(tmpl_event.substitute(event_map))
+ client_method_impls.append(tmpl_event_impl.substitute(event_map))
+
+ if domain_empty:
+ continue
+ type_decls.append(tmpl_handler.substitute(domain_map))
+ setters.append(tmpl_setter.substitute(domain_map))
+ fields.append(tmpl_field.substitute(domain_map))
+ includes.append(tmpl_include.substitute(domain_map))
+ fields_init.append(tmpl_field_init.substitute(domain_map))
+ if domain_needs_client:
+ type_decls.append(tmpl_client.substitute(domain_map,
+ methods = "".join(client_methods)))
+ friends.append(tmpl_friend.substitute(domain_map))
+ initializations.append(tmpl_init_client.substitute(domain_map))
+ type_impls.append(tmpl_client_impl.substitute(domain_map,
+ methods = "\n".join(client_method_impls)))
+ handler_method_impls.append(tmpl_setter_impl.substitute(domain_map,
+ initializations = "".join(initializations)))
+
+
+output_h_file = open(output_h_path, "w")
+output_cc_file = open(output_cc_path, "w")
+
+output_h_file.write(template_h.substitute({},
+ types = "\n".join(type_decls),
+ setters = "".join(setters),
+ friends = "".join(friends),
+ methods = "".join(handler_methods),
+ fields = "".join(fields)))
+output_h_file.close()
+
+output_cc_file.write(template_cc.substitute({},
+ includes = "".join(sorted(includes)),
+ fields_init = ",\n ".join(fields_init),
+ methods = "\n".join(handler_method_impls),
+ types = "\n".join(type_impls)))
+output_cc_file.close()
diff --git a/chromium/content/browser/devtools/protocol/dom_handler.cc b/chromium/content/browser/devtools/protocol/dom_handler.cc
new file mode 100644
index 00000000000..9ddf4092b52
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/dom_handler.cc
@@ -0,0 +1,47 @@
+// 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/devtools/protocol/dom_handler.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+
+namespace content {
+namespace devtools {
+namespace dom {
+
+typedef DevToolsProtocolClient::Response Response;
+
+DOMHandler::DOMHandler() : host_(nullptr) {
+}
+
+DOMHandler::~DOMHandler() {
+}
+
+void DOMHandler::SetRenderViewHost(RenderViewHostImpl* host) {
+ host_ = host;
+}
+
+Response DOMHandler::SetFileInputFiles(NodeId node_id,
+ const std::vector<std::string>& files) {
+ if (host_) {
+ for (const auto& file : files) {
+#if defined(OS_WIN)
+ ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
+ host_->GetProcess()->GetID(),
+ base::FilePath(base::UTF8ToUTF16(file)));
+#else
+ ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
+ host_->GetProcess()->GetID(),
+ base::FilePath(file));
+#endif // OS_WIN
+ }
+ }
+ return Response::FallThrough();
+}
+
+} // namespace dom
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/dom_handler.h b/chromium/content/browser/devtools/protocol/dom_handler.h
new file mode 100644
index 00000000000..d2b20e24e0c
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/dom_handler.h
@@ -0,0 +1,38 @@
+// 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_DEVTOOLS_PROTOCOL_DOM_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DOM_HANDLER_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+
+namespace content {
+
+class RenderViewHostImpl;
+
+namespace devtools {
+namespace dom {
+
+class DOMHandler {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+
+ DOMHandler();
+ virtual ~DOMHandler();
+
+ void SetRenderViewHost(RenderViewHostImpl* host);
+
+ Response SetFileInputFiles(NodeId node_id,
+ const std::vector<std::string>& files);
+
+ private:
+ RenderViewHostImpl* host_;
+ DISALLOW_COPY_AND_ASSIGN(DOMHandler);
+};
+
+} // namespace dom
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DOM_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/input_handler.cc b/chromium/content/browser/devtools/protocol/input_handler.cc
new file mode 100644
index 00000000000..05cff6195a1
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/input_handler.cc
@@ -0,0 +1,111 @@
+// 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/devtools/protocol/input_handler.h"
+
+#include "base/strings/stringprintf.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+namespace content {
+namespace devtools {
+namespace input {
+
+typedef DevToolsProtocolClient::Response Response;
+
+InputHandler::InputHandler()
+ : host_(NULL) {
+}
+
+InputHandler::~InputHandler() {
+}
+
+void InputHandler::SetRenderViewHost(RenderViewHostImpl* host) {
+ host_ = host;
+}
+
+Response InputHandler::EmulateTouchFromMouseEvent(const std::string& type,
+ int x,
+ int y,
+ double timestamp,
+ const std::string& button,
+ double* delta_x,
+ double* delta_y,
+ int* modifiers,
+ int* click_count) {
+ blink::WebMouseWheelEvent wheel_event;
+ blink::WebMouseEvent mouse_event;
+ blink::WebMouseEvent* event = &mouse_event;
+
+ if (type == emulate_touch_from_mouse_event::kTypeMousePressed) {
+ event->type = blink::WebInputEvent::MouseDown;
+ } else if (type == emulate_touch_from_mouse_event::kTypeMouseReleased) {
+ event->type = blink::WebInputEvent::MouseUp;
+ } else if (type == emulate_touch_from_mouse_event::kTypeMouseMoved) {
+ event->type = blink::WebInputEvent::MouseMove;
+ } else if (type == emulate_touch_from_mouse_event::kTypeMouseWheel) {
+ if (!delta_x || !delta_y) {
+ return Response::InvalidParams(
+ "'deltaX' and 'deltaY' are expected for mouseWheel event");
+ }
+ wheel_event.deltaX = static_cast<float>(*delta_x);
+ wheel_event.deltaY = static_cast<float>(*delta_y);
+ event = &wheel_event;
+ event->type = blink::WebInputEvent::MouseWheel;
+ } else {
+ return Response::InvalidParams(
+ base::StringPrintf("Unexpected event type '%s'", type.c_str()));
+ }
+
+ if (modifiers) {
+ if (*modifiers & 1)
+ event->modifiers |= blink::WebInputEvent::AltKey;
+ if (*modifiers & 2)
+ event->modifiers |= blink::WebInputEvent::ControlKey;
+ if (*modifiers & 4)
+ event->modifiers |= blink::WebInputEvent::MetaKey;
+ if (*modifiers & 8)
+ event->modifiers |= blink::WebInputEvent::ShiftKey;
+ }
+
+ event->timeStampSeconds = timestamp;
+ event->x = x;
+ event->y = y;
+ event->windowX = x;
+ event->windowY = y;
+ event->globalX = x;
+ event->globalY = y;
+
+ if (click_count)
+ event->clickCount = *click_count;
+
+ if (button == emulate_touch_from_mouse_event::kButtonNone) {
+ event->button = blink::WebMouseEvent::ButtonNone;
+ } else if (button == emulate_touch_from_mouse_event::kButtonLeft) {
+ event->button = blink::WebMouseEvent::ButtonLeft;
+ event->modifiers |= blink::WebInputEvent::LeftButtonDown;
+ } else if (button == emulate_touch_from_mouse_event::kButtonMiddle) {
+ event->button = blink::WebMouseEvent::ButtonMiddle;
+ event->modifiers |= blink::WebInputEvent::MiddleButtonDown;
+ } else if (button == emulate_touch_from_mouse_event::kButtonRight) {
+ event->button = blink::WebMouseEvent::ButtonRight;
+ event->modifiers |= blink::WebInputEvent::RightButtonDown;
+ } else {
+ return Response::InvalidParams(
+ base::StringPrintf("Unexpected mouse button '%s'", button.c_str()));
+ }
+
+ if (!host_)
+ return Response::ServerError("Could not connect to view");
+
+ if (event->type == blink::WebInputEvent::MouseWheel)
+ host_->ForwardWheelEvent(wheel_event);
+ else
+ host_->ForwardMouseEvent(mouse_event);
+ return Response::OK();
+}
+
+} // namespace input
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/input_handler.h b/chromium/content/browser/devtools/protocol/input_handler.h
new file mode 100644
index 00000000000..1a85b2a48c8
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/input_handler.h
@@ -0,0 +1,46 @@
+// 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_DEVTOOLS_PROTOCOL_INPUT_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_INPUT_HANDLER_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+
+namespace content {
+
+class RenderViewHostImpl;
+
+namespace devtools {
+namespace input {
+
+class InputHandler {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+
+ InputHandler();
+ virtual ~InputHandler();
+
+ void SetRenderViewHost(RenderViewHostImpl* host);
+
+ Response EmulateTouchFromMouseEvent(const std::string& type,
+ int x,
+ int y,
+ double timestamp,
+ const std::string& button,
+ double* delta_x,
+ double* delta_y,
+ int* modifiers,
+ int* click_count);
+
+ private:
+ RenderViewHostImpl* host_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputHandler);
+};
+
+} // namespace inpue
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_INPUT_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/inspector_handler.cc b/chromium/content/browser/devtools/protocol/inspector_handler.cc
new file mode 100644
index 00000000000..4dbbd045449
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/inspector_handler.cc
@@ -0,0 +1,23 @@
+// 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/devtools/protocol/inspector_handler.h"
+
+namespace content {
+namespace devtools {
+namespace inspector {
+
+InspectorHandler::InspectorHandler() {
+}
+
+InspectorHandler::~InspectorHandler() {
+}
+
+void InspectorHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+} // namespace inspector
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/inspector_handler.h b/chromium/content/browser/devtools/protocol/inspector_handler.h
new file mode 100644
index 00000000000..d6b449e8d11
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/inspector_handler.h
@@ -0,0 +1,31 @@
+// 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_DEVTOOLS_PROTOCOL_INSPECTOR_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_INSPECTOR_HANDLER_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+
+namespace content {
+namespace devtools {
+namespace inspector {
+
+class InspectorHandler {
+ public:
+ InspectorHandler();
+ virtual ~InspectorHandler();
+
+ void SetClient(scoped_ptr<Client> client);
+
+ private:
+ scoped_ptr<Client> client_;
+
+ DISALLOW_COPY_AND_ASSIGN(InspectorHandler);
+};
+
+} // namespace inspector
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_INSPECTOR_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/network_handler.cc b/chromium/content/browser/devtools/protocol/network_handler.cc
new file mode 100644
index 00000000000..d5b8f77a867
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/network_handler.cc
@@ -0,0 +1,52 @@
+// 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/devtools/protocol/network_handler.h"
+
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_client.h"
+
+namespace content {
+namespace devtools {
+namespace network {
+
+typedef DevToolsProtocolClient::Response Response;
+
+NetworkHandler::NetworkHandler() : host_(nullptr) {
+}
+
+NetworkHandler::~NetworkHandler() {
+}
+
+void NetworkHandler::SetRenderViewHost(RenderViewHost* host) {
+ host_ = host;
+}
+
+Response NetworkHandler::ClearBrowserCache() {
+ if (host_)
+ GetContentClient()->browser()->ClearCache(host_);
+ return Response::OK();
+}
+
+Response NetworkHandler::ClearBrowserCookies() {
+ if (host_)
+ GetContentClient()->browser()->ClearCookies(host_);
+ return Response::OK();
+}
+
+Response NetworkHandler::CanEmulateNetworkConditions(bool* result) {
+ *result = false;
+ return Response::OK();
+}
+
+Response NetworkHandler::EmulateNetworkConditions(bool offline,
+ double latency,
+ double download_throughput,
+ double upload_throughput) {
+ return Response::FallThrough();
+}
+
+} // namespace dom
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/network_handler.h b/chromium/content/browser/devtools/protocol/network_handler.h
new file mode 100644
index 00000000000..c045a86f2de
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/network_handler.h
@@ -0,0 +1,45 @@
+// 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_DEVTOOLS_PROTOCOL_NETWORK_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_NETWORK_HANDLER_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+
+namespace content {
+
+class RenderViewHost;
+
+namespace devtools {
+namespace network {
+
+class NetworkHandler {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+
+ NetworkHandler();
+ virtual ~NetworkHandler();
+
+ void SetRenderViewHost(RenderViewHost* host);
+
+ Response ClearBrowserCache();
+ Response ClearBrowserCookies();
+ Response CanEmulateNetworkConditions(bool* result);
+
+ Response EmulateNetworkConditions(bool offline,
+ double latency,
+ double download_throughput,
+ double upload_throughput);
+
+ private:
+ RenderViewHost* host_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkHandler);
+};
+
+} // namespace network
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_NETWORK_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/page_handler.cc b/chromium/content/browser/devtools/protocol/page_handler.cc
new file mode 100644
index 00000000000..b336d8cb6c8
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/page_handler.cc
@@ -0,0 +1,615 @@
+// 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/devtools/protocol/page_handler.h"
+
+#include <string>
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/devtools/protocol/color_picker.h"
+#include "content/browser/devtools/protocol/usage_and_quota_query.h"
+#include "content/browser/geolocation/geolocation_service_context.h"
+#include "content/browser/renderer_host/render_view_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/view_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/javascript_dialog_manager.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/common/referrer.h"
+#include "content/public/common/url_constants.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "third_party/WebKit/public/platform/WebScreenInfo.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/page_transition_types.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/size_conversions.h"
+#include "ui/snapshot/snapshot.h"
+#include "url/gurl.h"
+
+namespace content {
+namespace devtools {
+namespace page {
+
+namespace {
+
+static const char kPng[] = "png";
+static const char kJpeg[] = "jpeg";
+static int kDefaultScreenshotQuality = 80;
+static int kFrameRateThresholdMs = 100;
+static int kCaptureRetryLimit = 2;
+
+void QueryUsageAndQuotaCompletedOnIOThread(
+ const UsageAndQuotaQuery::Callback& callback,
+ scoped_ptr<QueryUsageAndQuotaResponse> response) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, base::Passed(&response)));
+}
+
+void QueryUsageAndQuotaOnIOThread(
+ scoped_refptr<storage::QuotaManager> quota_manager,
+ const GURL& security_origin,
+ const UsageAndQuotaQuery::Callback& callback) {
+ new UsageAndQuotaQuery(
+ quota_manager,
+ security_origin,
+ base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
+ callback));
+}
+
+} // namespace
+
+typedef DevToolsProtocolClient::Response Response;
+
+PageHandler::PageHandler()
+ : enabled_(false),
+ touch_emulation_enabled_(false),
+ screencast_enabled_(false),
+ screencast_quality_(kDefaultScreenshotQuality),
+ screencast_max_width_(-1),
+ screencast_max_height_(-1),
+ capture_retry_count_(0),
+ has_last_compositor_frame_metadata_(false),
+ color_picker_(new ColorPicker(base::Bind(
+ &PageHandler::OnColorPicked, base::Unretained(this)))),
+ host_(nullptr),
+ weak_factory_(this) {
+}
+
+PageHandler::~PageHandler() {
+}
+
+void PageHandler::SetRenderViewHost(RenderViewHostImpl* host) {
+ if (host_ == host)
+ return;
+
+ color_picker_->SetRenderViewHost(host);
+ host_ = host;
+ UpdateTouchEventEmulationState();
+}
+
+void PageHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+void PageHandler::Detached() {
+ Disable();
+}
+
+void PageHandler::OnSwapCompositorFrame(
+ const cc::CompositorFrameMetadata& frame_metadata) {
+ last_compositor_frame_metadata_ = frame_metadata;
+ has_last_compositor_frame_metadata_ = true;
+
+ if (screencast_enabled_)
+ InnerSwapCompositorFrame();
+ color_picker_->OnSwapCompositorFrame();
+}
+
+void PageHandler::OnVisibilityChanged(bool visible) {
+ if (!screencast_enabled_)
+ return;
+ NotifyScreencastVisibility(visible);
+}
+
+void PageHandler::DidAttachInterstitialPage() {
+ if (!enabled_)
+ return;
+ InterstitialShownParams params;
+ client_->InterstitialShown(params);
+}
+
+void PageHandler::DidDetachInterstitialPage() {
+ if (!enabled_)
+ return;
+ InterstitialHiddenParams params;
+ client_->InterstitialHidden(params);
+}
+
+Response PageHandler::Enable() {
+ enabled_ = true;
+ return Response::FallThrough();
+}
+
+Response PageHandler::Disable() {
+ enabled_ = false;
+ touch_emulation_enabled_ = false;
+ screencast_enabled_ = false;
+ UpdateTouchEventEmulationState();
+ color_picker_->SetEnabled(false);
+ return Response::FallThrough();
+}
+
+Response PageHandler::Reload(const bool* ignoreCache,
+ const std::string* script_to_evaluate_on_load,
+ const std::string* script_preprocessor) {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ WebContents* web_contents = WebContents::FromRenderViewHost(host_);
+ if (!web_contents)
+ return Response::InternalError("No WebContents to reload");
+
+ // Handle in browser only if it is crashed.
+ if (!web_contents->IsCrashed())
+ return Response::FallThrough();
+
+ web_contents->GetController().Reload(false);
+ return Response::OK();
+}
+
+Response PageHandler::Navigate(const std::string& url,
+ FrameId* frame_id) {
+ GURL gurl(url);
+ if (!gurl.is_valid())
+ return Response::InternalError("Cannot navigate to invalid URL");
+
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ WebContents* web_contents = WebContents::FromRenderViewHost(host_);
+ if (!web_contents)
+ return Response::InternalError("No WebContents to navigate");
+
+ web_contents->GetController()
+ .LoadURL(gurl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ return Response::FallThrough();
+}
+
+Response PageHandler::GetNavigationHistory(
+ int* current_index,
+ std::vector<NavigationEntry>* entries) {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ WebContents* web_contents = WebContents::FromRenderViewHost(host_);
+ if (!web_contents)
+ return Response::InternalError("No WebContents to navigate");
+
+ NavigationController& controller = web_contents->GetController();
+ *current_index = controller.GetCurrentEntryIndex();
+ for (int i = 0; i != controller.GetEntryCount(); ++i) {
+ NavigationEntry entry;
+ entry.set_id(controller.GetEntryAtIndex(i)->GetUniqueID());
+ entry.set_url(controller.GetEntryAtIndex(i)->GetURL().spec());
+ entry.set_title(
+ base::UTF16ToUTF8(controller.GetEntryAtIndex(i)->GetTitle()));
+ entries->push_back(entry);
+ }
+ return Response::OK();
+}
+
+Response PageHandler::NavigateToHistoryEntry(int entry_id) {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ WebContents* web_contents = WebContents::FromRenderViewHost(host_);
+ if (!web_contents)
+ return Response::InternalError("No WebContents to navigate");
+
+ NavigationController& controller = web_contents->GetController();
+ for (int i = 0; i != controller.GetEntryCount(); ++i) {
+ if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
+ controller.GoToIndex(i);
+ return Response::OK();
+ }
+ }
+
+ return Response::InvalidParams("No entry with passed id");
+}
+
+Response PageHandler::SetGeolocationOverride(double* latitude,
+ double* longitude,
+ double* accuracy) {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderViewHost(host_));
+ if (!web_contents)
+ return Response::InternalError("No WebContents to override");
+
+ GeolocationServiceContext* geolocation_context =
+ web_contents->GetGeolocationServiceContext();
+ scoped_ptr<Geoposition> geoposition(new Geoposition());
+ if (latitude && longitude && accuracy) {
+ geoposition->latitude = *latitude;
+ geoposition->longitude = *longitude;
+ geoposition->accuracy = *accuracy;
+ geoposition->timestamp = base::Time::Now();
+ if (!geoposition->Validate()) {
+ return Response::InternalError("Invalid geolocation");
+ }
+ } else {
+ geoposition->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ }
+ geolocation_context->SetOverride(geoposition.Pass());
+ return Response::OK();
+}
+
+Response PageHandler::ClearGeolocationOverride() {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderViewHost(host_));
+ if (!web_contents)
+ return Response::InternalError("No WebContents to override");
+
+ GeolocationServiceContext* geolocation_context =
+ web_contents->GetGeolocationServiceContext();
+ geolocation_context->ClearOverride();
+ return Response::OK();
+}
+
+Response PageHandler::SetTouchEmulationEnabled(bool enabled) {
+ touch_emulation_enabled_ = enabled;
+ UpdateTouchEventEmulationState();
+ return Response::FallThrough();
+}
+
+Response PageHandler::SetTouchEmulationEnabled(
+ bool enabled, const std::string* configuration) {
+ touch_emulation_enabled_ = enabled;
+ touch_emulation_configuration_ =
+ configuration ? *configuration : std::string();
+ UpdateTouchEventEmulationState();
+ return Response::FallThrough();
+}
+
+scoped_refptr<DevToolsProtocol::Response> PageHandler::CaptureScreenshot(
+ scoped_refptr<DevToolsProtocol::Command> command) {
+ if (!host_ || !host_->GetView())
+ return command->InternalErrorResponse("Could not connect to view");
+
+ host_->GetSnapshotFromBrowser(
+ base::Bind(&PageHandler::ScreenshotCaptured,
+ weak_factory_.GetWeakPtr(), command));
+ return command->AsyncResponsePromise();
+}
+
+Response PageHandler::CanScreencast(bool* result) {
+#if defined(OS_ANDROID)
+ *result = true;
+#else
+ *result = false;
+#endif // defined(OS_ANDROID)
+ return Response::OK();
+}
+
+Response PageHandler::CanEmulate(bool* result) {
+#if defined(OS_ANDROID)
+ *result = false;
+#else
+ if (host_) {
+ if (WebContents* web_contents = WebContents::FromRenderViewHost(host_)) {
+ *result = !web_contents->GetVisibleURL().SchemeIs(kChromeDevToolsScheme);
+ } else {
+ *result = true;
+ }
+ } else {
+ *result = true;
+ }
+#endif // defined(OS_ANDROID)
+ return Response::OK();
+}
+
+Response PageHandler::StartScreencast(const std::string* format,
+ const int* quality,
+ const int* max_width,
+ const int* max_height) {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ screencast_enabled_ = true;
+ screencast_format_ = format ? *format : kPng;
+ screencast_quality_ = quality ? *quality : kDefaultScreenshotQuality;
+ if (screencast_quality_ < 0 || screencast_quality_ > 100)
+ screencast_quality_ = kDefaultScreenshotQuality;
+ screencast_max_width_ = max_width ? *max_width : -1;
+ screencast_max_height_ = max_height ? *max_height : -1;
+
+ UpdateTouchEventEmulationState();
+ bool visible = !host_->is_hidden();
+ NotifyScreencastVisibility(visible);
+ if (visible) {
+ if (has_last_compositor_frame_metadata_)
+ InnerSwapCompositorFrame();
+ else
+ host_->Send(new ViewMsg_ForceRedraw(host_->GetRoutingID(), 0));
+ }
+ return Response::FallThrough();
+}
+
+Response PageHandler::StopScreencast() {
+ last_frame_time_ = base::TimeTicks();
+ screencast_enabled_ = false;
+ UpdateTouchEventEmulationState();
+ return Response::FallThrough();
+}
+
+Response PageHandler::HandleJavaScriptDialog(bool accept,
+ const std::string* prompt_text) {
+ base::string16 prompt_override;
+ if (prompt_text)
+ prompt_override = base::UTF8ToUTF16(*prompt_text);
+
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ WebContents* web_contents = WebContents::FromRenderViewHost(host_);
+ if (!web_contents)
+ return Response::InternalError("No JavaScript dialog to handle");
+
+ JavaScriptDialogManager* manager =
+ web_contents->GetDelegate()->GetJavaScriptDialogManager();
+ if (manager && manager->HandleJavaScriptDialog(
+ web_contents, accept, prompt_text ? &prompt_override : nullptr)) {
+ return Response::OK();
+ }
+
+ return Response::InternalError("Could not handle JavaScript dialog");
+}
+
+scoped_refptr<DevToolsProtocol::Response> PageHandler::QueryUsageAndQuota(
+ const std::string& security_origin,
+ scoped_refptr<DevToolsProtocol::Command> command) {
+ if (!host_)
+ return command->InternalErrorResponse("Could not connect to view");
+
+ scoped_refptr<storage::QuotaManager> quota_manager =
+ host_->GetProcess()->GetStoragePartition()->GetQuotaManager();
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&QueryUsageAndQuotaOnIOThread,
+ quota_manager,
+ GURL(security_origin),
+ base::Bind(&PageHandler::QueryUsageAndQuotaCompleted,
+ weak_factory_.GetWeakPtr(),
+ command)));
+
+ return command->AsyncResponsePromise();
+}
+
+Response PageHandler::SetColorPickerEnabled(bool enabled) {
+ if (!host_)
+ return Response::InternalError("Could not connect to view");
+
+ color_picker_->SetEnabled(enabled);
+ return Response::OK();
+}
+
+void PageHandler::UpdateTouchEventEmulationState() {
+ if (!host_)
+ return;
+ bool enabled = touch_emulation_enabled_ || screencast_enabled_;
+ // TODO(dgozman): pass |touch_emulation_configuration_| once supported.
+ host_->SetTouchEventEmulationEnabled(enabled);
+ WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
+ WebContents::FromRenderViewHost(host_));
+ if (web_contents)
+ web_contents->SetForceDisableOverscrollContent(enabled);
+}
+
+void PageHandler::NotifyScreencastVisibility(bool visible) {
+ if (visible)
+ capture_retry_count_ = kCaptureRetryLimit;
+ ScreencastVisibilityChangedParams params;
+ params.set_visible(visible);
+ client_->ScreencastVisibilityChanged(params);
+}
+
+void PageHandler::InnerSwapCompositorFrame() {
+ if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
+ kFrameRateThresholdMs) {
+ return;
+ }
+
+ if (!host_ || !host_->GetView())
+ return;
+
+ last_frame_time_ = base::TimeTicks::Now();
+
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ host_->GetView());
+ // TODO(vkuzkokov): do not use previous frame metadata.
+ cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_;
+
+ gfx::SizeF viewport_size_dip = gfx::ScaleSize(
+ metadata.scrollable_viewport_size, metadata.page_scale_factor);
+ gfx::SizeF screen_size_dip = gfx::ScaleSize(view->GetPhysicalBackingSize(),
+ 1 / metadata.device_scale_factor);
+
+ blink::WebScreenInfo screen_info;
+ view->GetScreenInfo(&screen_info);
+ double device_scale_factor = screen_info.deviceScaleFactor;
+ double scale = 1;
+
+ if (screencast_max_width_ > 0) {
+ double max_width_dip = screencast_max_width_ / device_scale_factor;
+ scale = std::min(scale, max_width_dip / screen_size_dip.width());
+ }
+ if (screencast_max_height_ > 0) {
+ double max_height_dip = screencast_max_height_ / device_scale_factor;
+ scale = std::min(scale, max_height_dip / screen_size_dip.height());
+ }
+
+ if (scale <= 0)
+ scale = 0.1;
+
+ gfx::Size snapshot_size_dip(gfx::ToRoundedSize(
+ gfx::ScaleSize(viewport_size_dip, scale)));
+
+ if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) {
+ gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip));
+ view->CopyFromCompositingSurface(
+ viewport_bounds_dip,
+ snapshot_size_dip,
+ base::Bind(&PageHandler::ScreencastFrameCaptured,
+ weak_factory_.GetWeakPtr(),
+ screencast_format_,
+ screencast_quality_,
+ last_compositor_frame_metadata_),
+ kN32_SkColorType);
+ }
+}
+
+void PageHandler::ScreencastFrameCaptured(
+ const std::string& format,
+ int quality,
+ const cc::CompositorFrameMetadata& metadata,
+ bool success,
+ const SkBitmap& bitmap) {
+ if (!success) {
+ if (capture_retry_count_) {
+ --capture_retry_count_;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&PageHandler::InnerSwapCompositorFrame,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
+ }
+ return;
+ }
+
+ std::vector<unsigned char> data;
+ SkAutoLockPixels lock_image(bitmap);
+ bool encoded;
+ if (format == kPng) {
+ encoded = gfx::PNGCodec::Encode(
+ reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
+ gfx::PNGCodec::FORMAT_SkBitmap,
+ gfx::Size(bitmap.width(), bitmap.height()),
+ bitmap.width() * bitmap.bytesPerPixel(),
+ false, std::vector<gfx::PNGCodec::Comment>(), &data);
+ } else if (format == kJpeg) {
+ encoded = gfx::JPEGCodec::Encode(
+ reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
+ gfx::JPEGCodec::FORMAT_SkBitmap,
+ bitmap.width(),
+ bitmap.height(),
+ bitmap.width() * bitmap.bytesPerPixel(),
+ quality, &data);
+ } else {
+ encoded = false;
+ }
+
+ if (!encoded)
+ return;
+
+ std::string base_64_data;
+ base::Base64Encode(
+ base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
+ &base_64_data);
+
+ ScreencastFrameMetadata param_metadata;
+ // Consider metadata empty in case it has no device scale factor.
+ if (metadata.device_scale_factor != 0 && host_) {
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ host_->GetView());
+ if (!view)
+ return;
+
+ gfx::SizeF viewport_size_dip = gfx::ScaleSize(
+ metadata.scrollable_viewport_size, metadata.page_scale_factor);
+ gfx::SizeF screen_size_dip = gfx::ScaleSize(
+ view->GetPhysicalBackingSize(), 1 / metadata.device_scale_factor);
+
+ param_metadata.set_device_scale_factor(metadata.device_scale_factor);
+ param_metadata.set_page_scale_factor(metadata.page_scale_factor);
+ param_metadata.set_page_scale_factor_min(metadata.min_page_scale_factor);
+ param_metadata.set_page_scale_factor_max(metadata.max_page_scale_factor);
+ param_metadata.set_offset_top(
+ metadata.location_bar_content_translation.y());
+ param_metadata.set_offset_bottom(screen_size_dip.height() -
+ metadata.location_bar_content_translation.y() -
+ viewport_size_dip.height());
+ param_metadata.set_device_width(screen_size_dip.width());
+ param_metadata.set_device_height(screen_size_dip.height());
+ param_metadata.set_scroll_offset_x(metadata.root_scroll_offset.x());
+ param_metadata.set_scroll_offset_y(metadata.root_scroll_offset.y());
+
+ devtools::dom::Rect viewport;
+ viewport.set_x(metadata.root_scroll_offset.x());
+ viewport.set_y(metadata.root_scroll_offset.y());
+ viewport.set_width(metadata.scrollable_viewport_size.width());
+ viewport.set_height(metadata.scrollable_viewport_size.height());
+ param_metadata.set_viewport(viewport);
+ }
+
+ ScreencastFrameParams params;
+ params.set_data(base_64_data);
+ params.set_metadata(param_metadata);
+ client_->ScreencastFrame(params);
+}
+
+void PageHandler::ScreenshotCaptured(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const unsigned char* png_data,
+ size_t png_size) {
+ if (!png_data || !png_size) {
+ client_->SendInternalErrorResponse(command,
+ "Unable to capture screenshot");
+ return;
+ }
+
+ std::string base_64_data;
+ base::Base64Encode(
+ base::StringPiece(reinterpret_cast<const char*>(png_data), png_size),
+ &base_64_data);
+
+ CaptureScreenshotResponse response;
+ response.set_data(base_64_data);
+ client_->SendCaptureScreenshotResponse(command, response);
+}
+
+void PageHandler::OnColorPicked(int r, int g, int b, int a) {
+ dom::RGBA color;
+ color.set_r(r);
+ color.set_g(g);
+ color.set_b(b);
+ color.set_a(a);
+ ColorPickedParams params;
+ params.set_color(color);
+ client_->ColorPicked(params);
+}
+
+void PageHandler::QueryUsageAndQuotaCompleted(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ scoped_ptr<QueryUsageAndQuotaResponse> response_data) {
+ client_->SendQueryUsageAndQuotaResponse(command, *response_data);
+}
+
+} // namespace page
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/page_handler.h b/chromium/content/browser/devtools/protocol/page_handler.h
new file mode 100644
index 00000000000..913655d7b06
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/page_handler.h
@@ -0,0 +1,135 @@
+// 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_DEVTOOLS_PROTOCOL_PAGE_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_PAGE_HANDLER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "cc/output/compositor_frame_metadata.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+
+class SkBitmap;
+
+namespace content {
+
+class RenderViewHostImpl;
+
+namespace devtools {
+namespace page {
+
+class ColorPicker;
+
+class PageHandler {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+
+ PageHandler();
+ virtual ~PageHandler();
+
+ void SetRenderViewHost(RenderViewHostImpl* host);
+ void SetClient(scoped_ptr<Client> client);
+ void Detached();
+ void OnSwapCompositorFrame(const cc::CompositorFrameMetadata& frame_metadata);
+ void OnVisibilityChanged(bool visible);
+ void DidAttachInterstitialPage();
+ void DidDetachInterstitialPage();
+
+ Response Enable();
+ Response Disable();
+
+ Response Reload(const bool* ignoreCache,
+ const std::string* script_to_evaluate_on_load,
+ const std::string* script_preprocessor);
+
+ Response Navigate(const std::string& url, FrameId* frame_id);
+
+ Response GetNavigationHistory(int* current_index,
+ std::vector<NavigationEntry>* entries);
+
+ Response NavigateToHistoryEntry(int entry_id);
+
+ Response SetGeolocationOverride(double* latitude,
+ double* longitude,
+ double* accuracy);
+
+ Response ClearGeolocationOverride();
+
+ Response SetTouchEmulationEnabled(bool enabled);
+ Response SetTouchEmulationEnabled(bool enabled,
+ const std::string* configuration);
+
+ scoped_refptr<DevToolsProtocol::Response> CaptureScreenshot(
+ scoped_refptr<DevToolsProtocol::Command> command);
+
+ Response CanScreencast(bool* result);
+ Response CanEmulate(bool* result);
+
+ Response StartScreencast(const std::string* format,
+ const int* quality,
+ const int* max_width,
+ const int* max_height);
+
+ Response StopScreencast();
+ Response HandleJavaScriptDialog(bool accept, const std::string* prompt_text);
+
+ scoped_refptr<DevToolsProtocol::Response> QueryUsageAndQuota(
+ const std::string& security_origin,
+ scoped_refptr<DevToolsProtocol::Command> command);
+
+ Response SetColorPickerEnabled(bool enabled);
+
+ private:
+ void UpdateTouchEventEmulationState();
+
+ void NotifyScreencastVisibility(bool visible);
+ void InnerSwapCompositorFrame();
+ void ScreencastFrameCaptured(
+ const std::string& format,
+ int quality,
+ const cc::CompositorFrameMetadata& metadata,
+ bool success,
+ const SkBitmap& bitmap);
+
+ void ScreenshotCaptured(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const unsigned char* png_data,
+ size_t png_size);
+
+ void OnColorPicked(int r, int g, int b, int a);
+
+ void QueryUsageAndQuotaCompleted(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ scoped_ptr<QueryUsageAndQuotaResponse> response);
+
+ bool enabled_;
+ bool touch_emulation_enabled_;
+ std::string touch_emulation_configuration_;
+
+ bool screencast_enabled_;
+ std::string screencast_format_;
+ int screencast_quality_;
+ int screencast_max_width_;
+ int screencast_max_height_;
+ int capture_retry_count_;
+ bool has_last_compositor_frame_metadata_;
+ cc::CompositorFrameMetadata last_compositor_frame_metadata_;
+ base::TimeTicks last_frame_time_;
+
+ scoped_ptr<ColorPicker> color_picker_;
+
+ RenderViewHostImpl* host_;
+ scoped_ptr<Client> client_;
+ base::WeakPtrFactory<PageHandler> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PageHandler);
+};
+
+} // namespace page
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_PAGE_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/power_handler.cc b/chromium/content/browser/devtools/protocol/power_handler.cc
new file mode 100644
index 00000000000..c121ac3cf2d
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/power_handler.cc
@@ -0,0 +1,86 @@
+// 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/devtools/protocol/power_handler.h"
+
+#include "content/browser/power_profiler/power_profiler_service.h"
+
+namespace content {
+namespace devtools {
+namespace power {
+
+typedef DevToolsProtocolClient::Response Response;
+
+PowerHandler::PowerHandler() : enabled_(false) {
+}
+
+PowerHandler::~PowerHandler() {
+ if (enabled_)
+ PowerProfilerService::GetInstance()->RemoveObserver(this);
+}
+
+void PowerHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+void PowerHandler::OnPowerEvent(const PowerEventVector& events) {
+ std::vector<PowerEvent> event_list;
+ for (const auto& event : events) {
+ PowerEvent event_body;
+ DCHECK(event.type < content::PowerEvent::ID_COUNT);
+ event_body.set_type(kPowerTypeNames[event.type]);
+ // Use internal value to be consistent with Blink's
+ // monotonicallyIncreasingTime.
+ event_body.set_timestamp(event.time.ToInternalValue() /
+ static_cast<double>(base::Time::kMicrosecondsPerMillisecond));
+ event_body.set_value(event.value);
+ event_list.push_back(event_body);
+ }
+ DataAvailableParams params;
+ params.set_value(event_list);
+ client_->DataAvailable(params);
+}
+
+void PowerHandler::Detached() {
+ if (enabled_) {
+ PowerProfilerService::GetInstance()->RemoveObserver(this);
+ enabled_ = false;
+ }
+}
+
+Response PowerHandler::Start() {
+ if (!PowerProfilerService::GetInstance()->IsAvailable())
+ return Response::InternalError("Power profiler service unavailable");
+ if (!enabled_) {
+ PowerProfilerService::GetInstance()->AddObserver(this);
+ enabled_ = true;
+ }
+ return Response::OK();
+}
+
+Response PowerHandler::End() {
+ if (!PowerProfilerService::GetInstance()->IsAvailable())
+ return Response::InternalError("Power profiler service unavailable");
+ if (enabled_) {
+ PowerProfilerService::GetInstance()->RemoveObserver(this);
+ enabled_ = false;
+ }
+ return Response::OK();
+}
+
+Response PowerHandler::CanProfilePower(bool* result) {
+ *result = PowerProfilerService::GetInstance()->IsAvailable();
+ return Response::OK();
+}
+
+Response PowerHandler::GetAccuracyLevel(std::string* result) {
+ if (!PowerProfilerService::GetInstance()->IsAvailable())
+ return Response::InternalError("Power profiler service unavailable");
+ *result = PowerProfilerService::GetInstance()->GetAccuracyLevel();
+ return Response::OK();
+}
+
+} // namespace power
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/power_handler.h b/chromium/content/browser/devtools/protocol/power_handler.h
new file mode 100644
index 00000000000..f0892c70c3f
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/power_handler.h
@@ -0,0 +1,45 @@
+// 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_DEVTOOLS_PROTOCOL_POWER_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_POWER_HANDLER_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+#include "content/browser/power_profiler/power_profiler_observer.h"
+
+namespace content {
+namespace devtools {
+namespace power {
+
+class PowerHandler : public PowerProfilerObserver {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+
+ PowerHandler();
+ ~PowerHandler() override;
+
+ void SetClient(scoped_ptr<Client> client);
+
+ // PowerProfilerObserver override.
+ void OnPowerEvent(const PowerEventVector& events) override;
+
+ void Detached();
+
+ Response Start();
+ Response End();
+ Response CanProfilePower(bool* result);
+ Response GetAccuracyLevel(std::string* result);
+
+ private:
+ scoped_ptr<Client> client_;
+ bool enabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(PowerHandler);
+};
+
+} // namespace power
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_POWER_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/tracing_handler.cc b/chromium/content/browser/devtools/protocol/tracing_handler.cc
new file mode 100644
index 00000000000..7515da87b74
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.cc
@@ -0,0 +1,215 @@
+// 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/devtools/protocol/tracing_handler.h"
+
+#include <cmath>
+
+#include "base/bind.h"
+#include "base/debug/trace_event_impl.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace content {
+namespace devtools {
+namespace tracing {
+
+typedef DevToolsProtocolClient::Response Response;
+
+namespace {
+
+const char kRecordUntilFull[] = "record-until-full";
+const char kRecordContinuously[] = "record-continuously";
+const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
+const char kEnableSampling[] = "enable-sampling";
+const double kMinimumReportingInterval = 250.0;
+
+class DevToolsTraceSinkProxy : public TracingController::TraceDataSink {
+ public:
+ explicit DevToolsTraceSinkProxy(base::WeakPtr<TracingHandler> handler)
+ : tracing_handler_(handler) {}
+
+ void AddTraceChunk(const std::string& chunk) override {
+ if (TracingHandler* h = tracing_handler_.get())
+ h->OnTraceDataCollected(chunk);
+ }
+ void Close() override {
+ if (TracingHandler* h = tracing_handler_.get())
+ h->OnTraceComplete();
+ }
+
+ private:
+ ~DevToolsTraceSinkProxy() override {}
+
+ base::WeakPtr<TracingHandler> tracing_handler_;
+};
+
+} // namespace
+
+TracingHandler::TracingHandler(TracingHandler::Target target)
+ : target_(target),
+ is_recording_(false),
+ weak_factory_(this) {
+}
+
+TracingHandler::~TracingHandler() {
+}
+
+void TracingHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+void TracingHandler::Detached() {
+ if (is_recording_)
+ DisableRecording(true);
+}
+
+void TracingHandler::OnTraceDataCollected(const std::string& trace_fragment) {
+ // Hand-craft protocol notification message so we can substitute JSON
+ // that we already got as string as a bare object, not a quoted string.
+ std::string message(
+ "{ \"method\": \"Tracing.dataCollected\", \"params\": { \"value\": [");
+ const size_t messageSuffixSize = 10;
+ message.reserve(message.size() + trace_fragment.size() + messageSuffixSize);
+ message += trace_fragment;
+ message += "] } }";
+ client_->SendRawMessage(message);
+}
+
+void TracingHandler::OnTraceComplete() {
+ TracingCompleteParams params;
+ client_->TracingComplete(params);
+}
+
+scoped_refptr<DevToolsProtocol::Response> TracingHandler::Start(
+ const std::string* categories,
+ const std::string* options_str,
+ const double* buffer_usage_reporting_interval,
+ scoped_refptr<DevToolsProtocol::Command> command) {
+ if (is_recording_)
+ return command->InternalErrorResponse("Tracing is already started");
+ is_recording_ = true;
+
+ base::debug::TraceOptions options = TraceOptionsFromString(options_str);
+ base::debug::CategoryFilter filter(categories ? *categories : 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()->EnableRecording(
+ filter,
+ options,
+ TracingController::EnableRecordingDoneCallback());
+ return nullptr;
+ }
+
+ TracingController::GetInstance()->EnableRecording(
+ filter,
+ options,
+ base::Bind(&TracingHandler::OnRecordingEnabled,
+ weak_factory_.GetWeakPtr(),
+ command));
+ return command->AsyncResponsePromise();
+}
+
+scoped_refptr<DevToolsProtocol::Response> TracingHandler::End(
+ scoped_refptr<DevToolsProtocol::Command> command) {
+ if (!is_recording_)
+ return command->InternalErrorResponse("Tracing is not started");
+ DisableRecording(false);
+ // If inspected target is a render process Tracing.end will be handled by
+ // tracing agent in the renderer.
+ if (target_ == Renderer)
+ return nullptr;
+ return command->SuccessResponse(nullptr);
+}
+
+scoped_refptr<DevToolsProtocol::Response> TracingHandler::GetCategories(
+ scoped_refptr<DevToolsProtocol::Command> command) {
+ TracingController::GetInstance()->GetCategories(
+ base::Bind(&TracingHandler::OnCategoriesReceived,
+ weak_factory_.GetWeakPtr(),
+ command));
+ return command->AsyncResponsePromise();
+}
+
+void TracingHandler::OnRecordingEnabled(
+ scoped_refptr<DevToolsProtocol::Command> command) {
+ StartResponse response;
+ client_->SendStartResponse(command, response);
+}
+
+void TracingHandler::OnBufferUsage(float usage) {
+ BufferUsageParams params;
+ params.set_value(usage);
+ client_->BufferUsage(params);
+}
+
+void TracingHandler::OnCategoriesReceived(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::set<std::string>& category_set) {
+ std::vector<std::string> categories(category_set.begin(), category_set.end());
+ GetCategoriesResponse response;
+ response.set_categories(categories);
+ client_->SendGetCategoriesResponse(command, response);
+}
+
+base::debug::TraceOptions TracingHandler::TraceOptionsFromString(
+ const std::string* options) {
+ base::debug::TraceOptions ret;
+ if (!options)
+ return ret;
+
+ std::vector<std::string> split;
+ std::vector<std::string>::iterator iter;
+
+ base::SplitString(*options, ',', &split);
+ for (iter = split.begin(); iter != split.end(); ++iter) {
+ if (*iter == kRecordUntilFull) {
+ ret.record_mode = base::debug::RECORD_UNTIL_FULL;
+ } else if (*iter == kRecordContinuously) {
+ ret.record_mode = base::debug::RECORD_CONTINUOUSLY;
+ } else if (*iter == kRecordAsMuchAsPossible) {
+ ret.record_mode = base::debug::RECORD_AS_MUCH_AS_POSSIBLE;
+ } else if (*iter == kEnableSampling) {
+ ret.enable_sampling = true;
+ }
+ }
+ return ret;
+}
+
+void TracingHandler::SetupTimer(double usage_reporting_interval) {
+ if (usage_reporting_interval == 0) return;
+
+ if (usage_reporting_interval < kMinimumReportingInterval)
+ usage_reporting_interval = kMinimumReportingInterval;
+
+ base::TimeDelta interval = base::TimeDelta::FromMilliseconds(
+ std::ceil(usage_reporting_interval));
+ buffer_usage_poll_timer_.reset(new base::Timer(
+ FROM_HERE,
+ interval,
+ base::Bind(
+ base::IgnoreResult(&TracingController::GetTraceBufferPercentFull),
+ base::Unretained(TracingController::GetInstance()),
+ base::Bind(&TracingHandler::OnBufferUsage,
+ weak_factory_.GetWeakPtr())),
+ true));
+ buffer_usage_poll_timer_->Reset();
+}
+
+void TracingHandler::DisableRecording(bool abort) {
+ is_recording_ = false;
+ buffer_usage_poll_timer_.reset();
+ TracingController::GetInstance()->DisableRecording(
+ abort ? nullptr : new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr()));
+}
+
+} // 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
new file mode 100644
index 00000000000..b20e5854a3b
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/tracing_handler.h
@@ -0,0 +1,77 @@
+// 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_DEVTOOLS_PROTOCOL_TRACING_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_TRACING_HANDLER_H_
+
+#include <set>
+#include <string>
+
+#include "base/debug/trace_event.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+#include "content/public/browser/tracing_controller.h"
+
+namespace base {
+class RefCountedString;
+class Timer;
+}
+
+namespace content {
+namespace devtools {
+namespace tracing {
+
+class TracingHandler {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+
+ enum Target { Browser, Renderer };
+ explicit TracingHandler(Target target);
+ virtual ~TracingHandler();
+
+ void SetClient(scoped_ptr<Client> client);
+ void Detached();
+
+ void OnTraceDataCollected(const std::string& trace_fragment);
+ void OnTraceComplete();
+
+ scoped_refptr<DevToolsProtocol::Response> Start(
+ const std::string* categories,
+ const std::string* options,
+ const double* buffer_usage_reporting_interval,
+ scoped_refptr<DevToolsProtocol::Command> command);
+
+ scoped_refptr<DevToolsProtocol::Response> End(
+ scoped_refptr<DevToolsProtocol::Command> command);
+ scoped_refptr<DevToolsProtocol::Response> GetCategories(
+ scoped_refptr<DevToolsProtocol::Command> command);
+
+ private:
+ void OnRecordingEnabled(scoped_refptr<DevToolsProtocol::Command> command);
+ void OnBufferUsage(float usage);
+
+ void OnCategoriesReceived(scoped_refptr<DevToolsProtocol::Command> command,
+ const std::set<std::string>& category_set);
+
+ base::debug::TraceOptions TraceOptionsFromString(const std::string* options);
+
+ void SetupTimer(double usage_reporting_interval);
+
+ void DisableRecording(bool abort);
+
+ scoped_ptr<base::Timer> buffer_usage_poll_timer_;
+ Target target_;
+ bool is_recording_;
+
+ scoped_ptr<Client> client_;
+ base::WeakPtrFactory<TracingHandler> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TracingHandler);
+};
+
+} // namespace tracing
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_TRACING_HANDLER_H_
diff --git a/chromium/content/browser/devtools/protocol/usage_and_quota_query.cc b/chromium/content/browser/devtools/protocol/usage_and_quota_query.cc
new file mode 100644
index 00000000000..2936fe1e079
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/usage_and_quota_query.cc
@@ -0,0 +1,136 @@
+// 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/devtools/protocol/usage_and_quota_query.h"
+
+#include "net/base/net_util.h"
+
+namespace content {
+namespace devtools {
+namespace page {
+
+namespace {
+
+class UsageQuery : public base::RefCounted<UsageQuery> {
+ public:
+ using Callback = base::Callback<void(const std::vector<UsageItem>&)>;
+
+ UsageQuery(scoped_refptr<storage::QuotaManager> quota_manager,
+ const std::string& host,
+ storage::StorageType storage_type,
+ const Callback& callback)
+ : quota_manager_(quota_manager),
+ host_(host),
+ storage_type_(storage_type),
+ callback_(callback) {
+ AddRef();
+ GetForClient(storage::QuotaClient::kFileSystem,
+ usage_item::kIdFilesystem);
+ GetForClient(storage::QuotaClient::kDatabase,
+ usage_item::kIdDatabase);
+ GetForClient(storage::QuotaClient::kAppcache,
+ usage_item::kIdAppcache);
+ GetForClient(storage::QuotaClient::kIndexedDatabase,
+ usage_item::kIdIndexeddatabase);
+ Release();
+ }
+
+ private:
+ friend class base::RefCounted<UsageQuery>;
+
+ ~UsageQuery() {
+ callback_.Run(usage_list_);
+ }
+
+ void GetForClient(storage::QuotaClient::ID client_id,
+ const std::string& client_name) {
+ if (!quota_manager_->IsTrackingHostUsage(storage_type_, client_id))
+ return;
+ quota_manager_->GetHostUsage(
+ host_, storage_type_, client_id,
+ base::Bind(&UsageQuery::DidGetForClient, this, client_name));
+ }
+
+ void DidGetForClient(const std::string& client_name, int64 value) {
+ UsageItem usage_item;
+ usage_item.set_id(client_name);
+ usage_item.set_value(value);
+ usage_list_.push_back(usage_item);
+ }
+
+ scoped_refptr<storage::QuotaManager> quota_manager_;
+ std::string host_;
+ storage::StorageType storage_type_;
+ std::vector<UsageItem> usage_list_;
+ Callback callback_;
+};
+
+} // namespace
+
+UsageAndQuotaQuery::UsageAndQuotaQuery(
+ scoped_refptr<storage::QuotaManager> quota_manager,
+ const GURL& security_origin,
+ const Callback& callback)
+ : quota_manager_(quota_manager),
+ security_origin_(security_origin),
+ callback_(callback) {
+ AddRef();
+ quota_manager->GetUsageAndQuotaForWebApps(
+ security_origin,
+ storage::kStorageTypeTemporary,
+ base::Bind(&UsageAndQuotaQuery::DidGetTemporaryQuota, this));
+ quota_manager->GetPersistentHostQuota(
+ net::GetHostOrSpecFromURL(security_origin),
+ base::Bind(&UsageAndQuotaQuery::DidGetPersistentQuota, this));
+ GetHostUsage(storage::kStorageTypeTemporary,
+ base::Bind(&Usage::set_temporary, base::Unretained(&usage_)));
+ GetHostUsage(storage::kStorageTypePersistent,
+ base::Bind(&Usage::set_persistent, base::Unretained(&usage_)));
+ GetHostUsage(storage::kStorageTypeSyncable,
+ base::Bind(&Usage::set_syncable, base::Unretained(&usage_)));
+ Release();
+}
+
+UsageAndQuotaQuery::~UsageAndQuotaQuery() {
+ scoped_ptr<QueryUsageAndQuotaResponse> response(
+ new QueryUsageAndQuotaResponse);
+ response->set_quota(quota_);
+ response->set_usage(usage_);
+ callback_.Run(response.Pass());
+}
+
+void UsageAndQuotaQuery::DidGetTemporaryQuota(storage::QuotaStatusCode status,
+ int64 used_bytes,
+ int64 quota_in_bytes) {
+ if (status == storage::kQuotaStatusOk)
+ quota_.set_temporary(quota_in_bytes);
+}
+
+void UsageAndQuotaQuery::DidGetPersistentQuota(storage::QuotaStatusCode status,
+ int64 value) {
+ if (status == storage::kQuotaStatusOk)
+ quota_.set_persistent(value);
+}
+
+void UsageAndQuotaQuery::GetHostUsage(
+ storage::StorageType storage_type,
+ const UsageItemsCallback& items_callback) {
+ // |base::Bind| is used instead of passing |items_callback| directly
+ // so that |this| is retained.
+ new UsageQuery(quota_manager_,
+ net::GetHostOrSpecFromURL(security_origin_),
+ storage_type,
+ base::Bind(&UsageAndQuotaQuery::DidGetHostUsage,
+ this, items_callback));
+}
+
+void UsageAndQuotaQuery::DidGetHostUsage(
+ const UsageItemsCallback& items_callback,
+ const std::vector<UsageItem>& usage_list) {
+ items_callback.Run(usage_list);
+}
+
+} // namespace page
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/usage_and_quota_query.h b/chromium/content/browser/devtools/protocol/usage_and_quota_query.h
new file mode 100644
index 00000000000..ffbf7010a18
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/usage_and_quota_query.h
@@ -0,0 +1,55 @@
+// 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_DEVTOOLS_PROTOCOL_QUOTA_AND_USAGE_QUERY_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_QUOTA_AND_USAGE_QUERY_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+#include "storage/browser/quota/quota_manager.h"
+
+namespace content {
+namespace devtools {
+namespace page {
+
+// This class can only be used on IO thread.
+class UsageAndQuotaQuery : public base::RefCounted<UsageAndQuotaQuery> {
+ public:
+ using Callback = base::Callback<void(scoped_ptr<QueryUsageAndQuotaResponse>)>;
+
+ UsageAndQuotaQuery(scoped_refptr<storage::QuotaManager> quota_manager,
+ const GURL& security_origin,
+ const Callback& callback);
+
+ private:
+ friend class base::RefCounted<UsageAndQuotaQuery>;
+
+ virtual ~UsageAndQuotaQuery();
+
+ void DidGetTemporaryQuota(storage::QuotaStatusCode status,
+ int64 used_bytes,
+ int64 quota_in_bytes);
+
+ void DidGetPersistentQuota(storage::QuotaStatusCode status, int64 value);
+
+ using UsageItemsCallback =
+ base::Callback<void(const std::vector<UsageItem>&)>;
+
+ void GetHostUsage(storage::StorageType storage_type,
+ const UsageItemsCallback& items_callback);
+
+ void DidGetHostUsage(const UsageItemsCallback& items_callback,
+ const std::vector<UsageItem>& usage_list);
+
+ scoped_refptr<storage::QuotaManager> quota_manager_;
+ GURL security_origin_;
+ Callback callback_;
+ Quota quota_;
+ Usage usage_;
+};
+
+} // namespace page
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_QUOTA_AND_USAGE_QUERY_H_
diff --git a/chromium/content/browser/devtools/protocol/worker_handler.cc b/chromium/content/browser/devtools/protocol/worker_handler.cc
new file mode 100644
index 00000000000..fd8fc09a253
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/worker_handler.cc
@@ -0,0 +1,30 @@
+// 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/devtools/protocol/worker_handler.h"
+
+namespace content {
+namespace devtools {
+namespace worker {
+
+typedef DevToolsProtocolClient::Response Response;
+typedef DevToolsProtocolClient::ResponseStatus ResponseStatus;
+
+WorkerHandler::WorkerHandler() {
+}
+
+WorkerHandler::~WorkerHandler() {
+}
+
+void WorkerHandler::SetClient(scoped_ptr<Client> client) {
+ client_.swap(client);
+}
+
+Response WorkerHandler::DisconnectFromWorker(int worker_id) {
+ return Response::FallThrough();
+}
+
+} // namespace worker
+} // namespace devtools
+} // namespace content
diff --git a/chromium/content/browser/devtools/protocol/worker_handler.h b/chromium/content/browser/devtools/protocol/worker_handler.h
new file mode 100644
index 00000000000..1c1faafed2b
--- /dev/null
+++ b/chromium/content/browser/devtools/protocol/worker_handler.h
@@ -0,0 +1,35 @@
+// 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_DEVTOOLS_PROTOCOL_WORKER_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_WORKER_HANDLER_H_
+
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+
+namespace content {
+namespace devtools {
+namespace worker {
+
+class WorkerHandler {
+ public:
+ typedef DevToolsProtocolClient::Response Response;
+
+ WorkerHandler();
+ virtual ~WorkerHandler();
+
+ void SetClient(scoped_ptr<Client> client);
+
+ Response DisconnectFromWorker(int worker_id);
+
+ private:
+ scoped_ptr<Client> client_;
+
+ DISALLOW_COPY_AND_ASSIGN(WorkerHandler);
+};
+
+} // namespace worker
+} // namespace devtools
+} // namespace content
+
+#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_WORKER_HANDLER_H_
diff --git a/chromium/content/browser/devtools/render_view_devtools_agent_host.cc b/chromium/content/browser/devtools/render_view_devtools_agent_host.cc
index 82df7ed2f0d..5115ba21e45 100644
--- a/chromium/content/browser/devtools/render_view_devtools_agent_host.cc
+++ b/chromium/content/browser/devtools/render_view_devtools_agent_host.cc
@@ -6,13 +6,18 @@
#include "base/basictypes.h"
#include "base/lazy_instance.h"
+#include "base/strings/utf_string_conversions.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/devtools/devtools_manager_impl.h"
-#include "content/browser/devtools/devtools_power_handler.h"
+#include "content/browser/devtools/devtools_manager.h"
#include "content/browser/devtools/devtools_protocol.h"
#include "content/browser/devtools/devtools_protocol_constants.h"
-#include "content/browser/devtools/devtools_tracing_handler.h"
-#include "content/browser/devtools/renderer_overrides_handler.h"
+#include "content/browser/devtools/protocol/devtools_protocol_handler_impl.h"
+#include "content/browser/devtools/protocol/dom_handler.h"
+#include "content/browser/devtools/protocol/input_handler.h"
+#include "content/browser/devtools/protocol/network_handler.h"
+#include "content/browser/devtools/protocol/page_handler.h"
+#include "content/browser/devtools/protocol/power_handler.h"
+#include "content/browser/devtools/protocol/tracing_handler.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"
@@ -24,6 +29,7 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_widget_host_iterator.h"
+#include "content/public/browser/web_contents_delegate.h"
#if defined(OS_ANDROID)
#include "content/browser/power_save_blocker_impl.h"
@@ -42,23 +48,9 @@ base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER;
static RenderViewDevToolsAgentHost* FindAgentHost(WebContents* web_contents) {
if (g_instances == NULL)
return NULL;
- RenderViewHostDelegate* delegate =
- static_cast<WebContentsImpl*>(web_contents);
for (Instances::iterator it = g_instances.Get().begin();
it != g_instances.Get().end(); ++it) {
- RenderViewHost* rvh = (*it)->render_view_host();
- if (rvh && rvh->GetDelegate() == delegate)
- return *it;
- }
- return NULL;
-}
-
-static RenderViewDevToolsAgentHost* FindAgentHost(RenderViewHost* rvh) {
- if (g_instances == NULL)
- return NULL;
- for (Instances::iterator it = g_instances.Get().begin();
- it != g_instances.Get().end(); ++it) {
- if (rvh == (*it)->render_view_host())
+ if ((*it)->GetWebContents() == web_contents)
return *it;
}
return NULL;
@@ -75,42 +67,19 @@ DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
}
// static
-scoped_refptr<DevToolsAgentHost>
-DevToolsAgentHost::GetOrCreateFor(RenderViewHost* rvh) {
- RenderViewDevToolsAgentHost* result = FindAgentHost(rvh);
- if (!result)
- result = new RenderViewDevToolsAgentHost(rvh);
- return result;
-}
-
-// static
-bool DevToolsAgentHost::HasFor(RenderViewHost* rvh) {
- return FindAgentHost(rvh) != NULL;
+bool DevToolsAgentHost::HasFor(WebContents* web_contents) {
+ return FindAgentHost(web_contents) != NULL;
}
// static
bool DevToolsAgentHost::IsDebuggerAttached(WebContents* web_contents) {
- if (g_instances == NULL)
- return false;
- DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
- if (!devtools_manager)
- return false;
- RenderViewHostDelegate* delegate =
- static_cast<WebContentsImpl*>(web_contents);
- for (Instances::iterator it = g_instances.Get().begin();
- it != g_instances.Get().end(); ++it) {
- RenderViewHost* rvh = (*it)->render_view_host_;
- if (rvh && rvh->GetDelegate() != delegate)
- continue;
- if ((*it)->IsAttached())
- return true;
- }
- return false;
+ RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
+ return agent_host && agent_host->IsAttached();
}
//static
-std::vector<RenderViewHost*> DevToolsAgentHost::GetValidRenderViewHosts() {
- std::vector<RenderViewHost*> result;
+std::vector<WebContents*> DevToolsAgentHostImpl::GetInspectableWebContents() {
+ std::set<WebContents*> set;
scoped_ptr<RenderWidgetHostIterator> widgets(
RenderWidgetHost::GetRenderWidgetHosts());
while (RenderWidgetHost* widget = widgets->GetNextHost()) {
@@ -122,23 +91,11 @@ std::vector<RenderViewHost*> DevToolsAgentHost::GetValidRenderViewHosts() {
RenderViewHost* rvh = RenderViewHost::From(widget);
WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
- if (!web_contents)
- continue;
-
- // Don't report a RenderViewHost if it is not the current RenderViewHost
- // for some WebContents (this filters out pre-render RVHs and similar).
- // However report a RenderViewHost created for an out of process iframe.
- // TODO (kaznacheev): Revisit this when it is clear how OOP iframes
- // interact with pre-rendering.
- // TODO (kaznacheev): GetMainFrame() call is a temporary hack. Iterate over
- // all RenderFrameHost instances when multiple OOP frames are supported.
- if (rvh != web_contents->GetRenderViewHost() &&
- !rvh->GetMainFrame()->IsCrossProcessSubframe()) {
- continue;
- }
-
- result.push_back(rvh);
+ if (web_contents)
+ set.insert(web_contents);
}
+ std::vector<WebContents*> result(set.size());
+ std::copy(set.begin(), set.end(), result.begin());
return result;
}
@@ -146,44 +103,46 @@ std::vector<RenderViewHost*> DevToolsAgentHost::GetValidRenderViewHosts() {
void RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
RenderViewHost* pending,
RenderViewHost* current) {
- RenderViewDevToolsAgentHost* agent_host = FindAgentHost(pending);
+ WebContents* web_contents = WebContents::FromRenderViewHost(pending);
+ RenderViewDevToolsAgentHost* agent_host = FindAgentHost(web_contents);
if (!agent_host)
return;
agent_host->DisconnectRenderViewHost();
agent_host->ConnectRenderViewHost(current);
}
-// static
-bool RenderViewDevToolsAgentHost::DispatchIPCMessage(
- RenderViewHost* source,
- const IPC::Message& message) {
- RenderViewDevToolsAgentHost* agent_host = FindAgentHost(source);
- return agent_host && agent_host->DispatchIPCMessage(message);
-}
-
RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(RenderViewHost* rvh)
: render_view_host_(NULL),
- overrides_handler_(new RendererOverridesHandler(this)),
- tracing_handler_(
- new DevToolsTracingHandler(DevToolsTracingHandler::Renderer)),
- power_handler_(new DevToolsPowerHandler()),
+ dom_handler_(new devtools::dom::DOMHandler()),
+ input_handler_(new devtools::input::InputHandler()),
+ network_handler_(new devtools::network::NetworkHandler()),
+ page_handler_(new devtools::page::PageHandler()),
+ power_handler_(new devtools::power::PowerHandler()),
+ tracing_handler_(new devtools::tracing::TracingHandler(
+ devtools::tracing::TracingHandler::Renderer)),
+ handler_impl_(new DevToolsProtocolHandlerImpl()),
reattaching_(false) {
+ handler_impl_->SetDOMHandler(dom_handler_.get());
+ handler_impl_->SetInputHandler(input_handler_.get());
+ handler_impl_->SetNetworkHandler(network_handler_.get());
+ handler_impl_->SetPageHandler(page_handler_.get());
+ handler_impl_->SetPowerHandler(power_handler_.get());
+ handler_impl_->SetTracingHandler(tracing_handler_.get());
SetRenderViewHost(rvh);
DevToolsProtocol::Notifier notifier(base::Bind(
- &RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend,
+ &RenderViewDevToolsAgentHost::DispatchOnInspectorFrontend,
base::Unretained(this)));
- overrides_handler_->SetNotifier(notifier);
- tracing_handler_->SetNotifier(notifier);
- power_handler_->SetNotifier(notifier);
+ handler_impl_->SetNotifier(notifier);
g_instances.Get().push_back(this);
AddRef(); // Balanced in RenderViewHostDestroyed.
+ DevToolsManager::GetInstance()->AgentHostChanged(this);
}
-RenderViewHost* RenderViewDevToolsAgentHost::GetRenderViewHost() {
- return render_view_host_;
+WebContents* RenderViewDevToolsAgentHost::GetWebContents() {
+ return web_contents();
}
-void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend(
+void RenderViewDevToolsAgentHost::DispatchProtocolMessage(
const std::string& message) {
std::string error_message;
@@ -192,11 +151,11 @@ void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend(
scoped_refptr<DevToolsProtocol::Command> command =
DevToolsProtocol::ParseCommand(message_dict.get(), &error_message);
- if (command) {
+ if (command.get()) {
scoped_refptr<DevToolsProtocol::Response> overridden_response;
DevToolsManagerDelegate* delegate =
- DevToolsManagerImpl::GetInstance()->delegate();
+ DevToolsManager::GetInstance()->delegate();
if (delegate) {
scoped_ptr<base::DictionaryValue> overridden_response_value(
delegate->HandleCommand(this, message_dict.get()));
@@ -204,20 +163,16 @@ void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend(
overridden_response = DevToolsProtocol::ParseResponse(
overridden_response_value.get());
}
- if (!overridden_response)
- overridden_response = overrides_handler_->HandleCommand(command);
- if (!overridden_response)
- overridden_response = tracing_handler_->HandleCommand(command);
- if (!overridden_response)
- overridden_response = power_handler_->HandleCommand(command);
- if (overridden_response) {
+ if (!overridden_response.get())
+ overridden_response = handler_impl_->HandleCommand(command);
+ if (overridden_response.get()) {
if (!overridden_response->is_async_promise())
- OnDispatchOnInspectorFrontend(overridden_response->Serialize());
+ DispatchOnInspectorFrontend(overridden_response->Serialize());
return;
}
}
- IPCDevToolsAgentHost::DispatchOnInspectorBackend(message);
+ IPCDevToolsAgentHost::DispatchProtocolMessage(message);
}
void RenderViewDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) {
@@ -233,10 +188,10 @@ void RenderViewDevToolsAgentHost::OnClientAttached() {
InnerOnClientAttached();
- // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when
+ // TODO(kaznacheev): Move this call back to DevToolsManager when
// extensions::ProcessManager no longer relies on this notification.
if (!reattaching_)
- DevToolsManagerImpl::GetInstance()->NotifyObservers(this, true);
+ DevToolsAgentHostImpl::NotifyCallbacks(this, true);
}
void RenderViewDevToolsAgentHost::InnerOnClientAttached() {
@@ -260,9 +215,15 @@ void RenderViewDevToolsAgentHost::OnClientDetached() {
#if defined(OS_ANDROID)
power_save_blocker_.reset();
#endif
- overrides_handler_->OnClientDetached();
- tracing_handler_->OnClientDetached();
+ page_handler_->Detached();
+ power_handler_->Detached();
+ tracing_handler_->Detached();
ClientDetachedFromRenderer();
+
+ // TODO(kaznacheev): Move this call back to DevToolsManager when
+ // extensions::ProcessManager no longer relies on this notification.
+ if (!reattaching_)
+ DevToolsAgentHostImpl::NotifyCallbacks(this, false);
}
void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() {
@@ -270,11 +231,6 @@ void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() {
return;
InnerClientDetachedFromRenderer();
-
- // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when
- // extensions::ProcessManager no longer relies on this notification.
- if (!reattaching_)
- DevToolsManagerImpl::GetInstance()->NotifyObservers(this, false);
}
void RenderViewDevToolsAgentHost::InnerClientDetachedFromRenderer() {
@@ -284,7 +240,7 @@ void RenderViewDevToolsAgentHost::InnerClientDetachedFromRenderer() {
it != g_instances.Get().end(); ++it) {
if (*it == this || !(*it)->IsAttached())
continue;
- RenderViewHost* rvh = (*it)->render_view_host();
+ RenderViewHost* rvh = (*it)->render_view_host_;
if (rvh && rvh->GetProcess() == render_process_host)
process_has_agents = true;
}
@@ -309,8 +265,8 @@ void RenderViewDevToolsAgentHost::AboutToNavigateRenderView(
if (!render_view_host_)
return;
- if (render_view_host_ == dest_rvh && static_cast<RenderViewHostImpl*>(
- render_view_host_)->render_view_termination_status() ==
+ if (render_view_host_ == dest_rvh &&
+ render_view_host_->render_view_termination_status() ==
base::TERMINATION_STATUS_STILL_RUNNING)
return;
ReattachToRenderViewHost(dest_rvh);
@@ -341,8 +297,9 @@ void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) {
DCHECK(render_view_host_);
scoped_refptr<RenderViewDevToolsAgentHost> protect(this);
- NotifyCloseListener();
+ HostClosed();
ClearRenderViewHost();
+ DevToolsManager::GetInstance()->AgentHostChanged(this);
Release();
}
@@ -362,7 +319,20 @@ void RenderViewDevToolsAgentHost::RenderProcessGone(
}
}
+bool RenderViewDevToolsAgentHost::OnMessageReceived(
+ const IPC::Message& message,
+ RenderFrameHost* render_frame_host) {
+ return DispatchIPCMessage(message);
+}
+
+bool RenderViewDevToolsAgentHost::OnMessageReceived(
+ const IPC::Message& message) {
+ return DispatchIPCMessage(message);
+}
+
void RenderViewDevToolsAgentHost::DidAttachInterstitialPage() {
+ page_handler_->DidAttachInterstitialPage();
+
if (!render_view_host_)
return;
// The rvh set in AboutToNavigateRenderView turned out to be interstitial.
@@ -375,20 +345,38 @@ void RenderViewDevToolsAgentHost::DidAttachInterstitialPage() {
ConnectRenderViewHost(web_contents->GetRenderViewHost());
}
+void RenderViewDevToolsAgentHost::DidDetachInterstitialPage() {
+ page_handler_->DidDetachInterstitialPage();
+}
+
+void RenderViewDevToolsAgentHost::TitleWasSet(
+ NavigationEntry* entry, bool explicit_set) {
+ DevToolsManager::GetInstance()->AgentHostChanged(this);
+}
+
+void RenderViewDevToolsAgentHost::NavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) {
+ DevToolsManager::GetInstance()->AgentHostChanged(this);
+}
+
void RenderViewDevToolsAgentHost::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
bool visible = *Details<bool>(details).ptr();
- overrides_handler_->OnVisibilityChanged(visible);
+ page_handler_->OnVisibilityChanged(visible);
}
}
void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
DCHECK(!render_view_host_);
- render_view_host_ = rvh;
+ render_view_host_ = static_cast<RenderViewHostImpl*>(rvh);
WebContentsObserver::Observe(WebContents::FromRenderViewHost(rvh));
+ dom_handler_->SetRenderViewHost(render_view_host_);
+ input_handler_->SetRenderViewHost(render_view_host_);
+ network_handler_->SetRenderViewHost(render_view_host_);
+ page_handler_->SetRenderViewHost(render_view_host_);
registrar_.Add(
this,
@@ -402,7 +390,52 @@ void RenderViewDevToolsAgentHost::ClearRenderViewHost() {
this,
content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
content::Source<RenderWidgetHost>(render_view_host_));
- render_view_host_ = NULL;
+ render_view_host_ = nullptr;
+ dom_handler_->SetRenderViewHost(nullptr);
+ input_handler_->SetRenderViewHost(nullptr);
+ network_handler_->SetRenderViewHost(nullptr);
+ page_handler_->SetRenderViewHost(nullptr);
+}
+
+void RenderViewDevToolsAgentHost::DisconnectWebContents() {
+ DisconnectRenderViewHost();
+}
+
+void RenderViewDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
+ ConnectRenderViewHost(wc->GetRenderViewHost());
+}
+
+DevToolsAgentHost::Type RenderViewDevToolsAgentHost::GetType() {
+ return TYPE_WEB_CONTENTS;
+}
+
+std::string RenderViewDevToolsAgentHost::GetTitle() {
+ if (WebContents* web_contents = GetWebContents())
+ return base::UTF16ToUTF8(web_contents->GetTitle());
+ return "";
+}
+
+GURL RenderViewDevToolsAgentHost::GetURL() {
+ if (WebContents* web_contents = GetWebContents())
+ return web_contents->GetVisibleURL();
+ return render_view_host_ ?
+ render_view_host_->GetMainFrame()->GetLastCommittedURL() : GURL();
+}
+
+bool RenderViewDevToolsAgentHost::Activate() {
+ if (render_view_host_) {
+ render_view_host_->GetDelegate()->Activate();
+ return true;
+ }
+ return false;
+}
+
+bool RenderViewDevToolsAgentHost::Close() {
+ if (render_view_host_) {
+ render_view_host_->ClosePage();
+ return true;
+ }
+ return false;
}
void RenderViewDevToolsAgentHost::ConnectRenderViewHost(RenderViewHost* rvh) {
@@ -420,8 +453,7 @@ void RenderViewDevToolsAgentHost::RenderViewCrashed() {
scoped_refptr<DevToolsProtocol::Notification> notification =
DevToolsProtocol::CreateNotification(
devtools::Inspector::targetCrashed::kName, NULL);
- DevToolsManagerImpl::GetInstance()->
- DispatchOnInspectorFrontend(this, notification->Serialize());
+ SendMessageToClient(notification->Serialize());
}
bool RenderViewDevToolsAgentHost::DispatchIPCMessage(
@@ -447,14 +479,14 @@ void RenderViewDevToolsAgentHost::OnSwapCompositorFrame(
ViewHostMsg_SwapCompositorFrame::Param param;
if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
return;
- overrides_handler_->OnSwapCompositorFrame(param.b.metadata);
+ page_handler_->OnSwapCompositorFrame(param.b.metadata);
}
void RenderViewDevToolsAgentHost::SynchronousSwapCompositorFrame(
const cc::CompositorFrameMetadata& frame_metadata) {
if (!render_view_host_)
return;
- overrides_handler_->OnSwapCompositorFrame(frame_metadata);
+ page_handler_->OnSwapCompositorFrame(frame_metadata);
}
void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
@@ -465,11 +497,18 @@ void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
}
void RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend(
+ const std::string& message,
+ uint32 total_size) {
+ if (!IsAttached() || !render_view_host_)
+ return;
+ ProcessChunkedMessageFromAgent(message, total_size);
+}
+
+void RenderViewDevToolsAgentHost::DispatchOnInspectorFrontend(
const std::string& message) {
- if (!render_view_host_)
+ if (!IsAttached() || !render_view_host_)
return;
- DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(
- this, message);
+ SendMessageToClient(message);
}
} // namespace content
diff --git a/chromium/content/browser/devtools/render_view_devtools_agent_host.h b/chromium/content/browser/devtools/render_view_devtools_agent_host.h
index f4e9baf4a5f..204d87e8544 100644
--- a/chromium/content/browser/devtools/render_view_devtools_agent_host.h
+++ b/chromium/content/browser/devtools/render_view_devtools_agent_host.h
@@ -22,15 +22,23 @@ class CompositorFrameMetadata;
namespace content {
-class DevToolsPowerHandler;
-class DevToolsTracingHandler;
-class RendererOverridesHandler;
+class DevToolsProtocolHandlerImpl;
class RenderViewHost;
+class RenderViewHostImpl;
#if defined(OS_ANDROID)
class PowerSaveBlockerImpl;
#endif
+namespace devtools {
+namespace dom { class DOMHandler; }
+namespace input { class InputHandler; }
+namespace network { class NetworkHandler; }
+namespace page { class PageHandler; }
+namespace power { class PowerHandler; }
+namespace tracing { class TracingHandler; }
+}
+
class CONTENT_EXPORT RenderViewDevToolsAgentHost
: public IPCDevToolsAgentHost,
private WebContentsObserver,
@@ -39,45 +47,53 @@ class CONTENT_EXPORT RenderViewDevToolsAgentHost
static void OnCancelPendingNavigation(RenderViewHost* pending,
RenderViewHost* current);
- static bool DispatchIPCMessage(RenderViewHost* source,
- const IPC::Message& message);
-
RenderViewDevToolsAgentHost(RenderViewHost*);
- RenderViewHost* render_view_host() { return render_view_host_; }
-
void SynchronousSwapCompositorFrame(
const cc::CompositorFrameMetadata& frame_metadata);
+ // DevTooolsAgentHost overrides.
+ void DisconnectWebContents() override;
+ void ConnectWebContents(WebContents* web_contents) override;
+ WebContents* GetWebContents() override;
+ Type GetType() override;
+ std::string GetTitle() override;
+ GURL GetURL() override;
+ bool Activate() override;
+ bool Close() override;
+
private:
friend class DevToolsAgentHost;
-
- virtual ~RenderViewDevToolsAgentHost();
-
- // DevTooolsAgentHost overrides.
- virtual void DisconnectRenderViewHost() OVERRIDE;
- virtual void ConnectRenderViewHost(RenderViewHost* rvh) OVERRIDE;
- virtual RenderViewHost* GetRenderViewHost() OVERRIDE;
+ ~RenderViewDevToolsAgentHost() override;
// IPCDevToolsAgentHost overrides.
- virtual void DispatchOnInspectorBackend(const std::string& message) OVERRIDE;
- virtual void SendMessageToAgent(IPC::Message* msg) OVERRIDE;
- virtual void OnClientAttached() OVERRIDE;
- virtual void OnClientDetached() OVERRIDE;
+ void DispatchProtocolMessage(const std::string& message) override;
+ void SendMessageToAgent(IPC::Message* msg) override;
+ void OnClientAttached() override;
+ void OnClientDetached() override;
// WebContentsObserver overrides.
- virtual void AboutToNavigateRenderView(RenderViewHost* dest_rvh) OVERRIDE;
- virtual void RenderViewHostChanged(RenderViewHost* old_host,
- RenderViewHost* new_host) OVERRIDE;
- virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE;
- virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
- virtual void DidAttachInterstitialPage() OVERRIDE;
+ void AboutToNavigateRenderView(RenderViewHost* dest_rvh) override;
+ void RenderViewHostChanged(RenderViewHost* old_host,
+ RenderViewHost* new_host) override;
+ void RenderViewDeleted(RenderViewHost* rvh) override;
+ void RenderProcessGone(base::TerminationStatus status) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void DidAttachInterstitialPage() override;
+ void DidDetachInterstitialPage() override;
+ void TitleWasSet(NavigationEntry* entry, bool explicit_set) override;
+ void NavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) override;
// NotificationObserver overrides:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
+ void DisconnectRenderViewHost();
+ void ConnectRenderViewHost(RenderViewHost* rvh);
void ReattachToRenderViewHost(RenderViewHost* rvh);
bool DispatchIPCMessage(const IPC::Message& message);
@@ -87,8 +103,11 @@ class CONTENT_EXPORT RenderViewDevToolsAgentHost
void RenderViewCrashed();
void OnSwapCompositorFrame(const IPC::Message& message);
+ bool OnSetTouchEventEmulationEnabled(const IPC::Message& message);
- void OnDispatchOnInspectorFrontend(const std::string& message);
+ void OnDispatchOnInspectorFrontend(const std::string& message,
+ uint32 total_size);
+ void DispatchOnInspectorFrontend(const std::string& message);
void OnSaveAgentRuntimeState(const std::string& state);
void ClientDetachedFromRenderer();
@@ -96,10 +115,14 @@ class CONTENT_EXPORT RenderViewDevToolsAgentHost
void InnerOnClientAttached();
void InnerClientDetachedFromRenderer();
- RenderViewHost* render_view_host_;
- scoped_ptr<RendererOverridesHandler> overrides_handler_;
- scoped_ptr<DevToolsTracingHandler> tracing_handler_;
- scoped_ptr<DevToolsPowerHandler> power_handler_;
+ RenderViewHostImpl* render_view_host_;
+ scoped_ptr<devtools::dom::DOMHandler> dom_handler_;
+ scoped_ptr<devtools::input::InputHandler> input_handler_;
+ scoped_ptr<devtools::network::NetworkHandler> network_handler_;
+ scoped_ptr<devtools::page::PageHandler> page_handler_;
+ scoped_ptr<devtools::power::PowerHandler> power_handler_;
+ scoped_ptr<devtools::tracing::TracingHandler> tracing_handler_;
+ scoped_ptr<DevToolsProtocolHandlerImpl> handler_impl_;
#if defined(OS_ANDROID)
scoped_ptr<PowerSaveBlockerImpl> power_save_blocker_;
#endif
diff --git a/chromium/content/browser/devtools/renderer_overrides_handler.cc b/chromium/content/browser/devtools/renderer_overrides_handler.cc
deleted file mode 100644
index 7370275cd45..00000000000
--- a/chromium/content/browser/devtools/renderer_overrides_handler.cc
+++ /dev/null
@@ -1,1007 +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/devtools/renderer_overrides_handler.h"
-
-#include <map>
-#include <string>
-
-#include "base/barrier_closure.h"
-#include "base/base64.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/files/file_path.h"
-#include "base/strings/string16.h"
-#include "base/thread_task_runner_handle.h"
-#include "base/values.h"
-#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/devtools/devtools_protocol_constants.h"
-#include "content/browser/devtools/devtools_tracing_handler.h"
-#include "content/browser/renderer_host/dip_util.h"
-#include "content/browser/renderer_host/render_view_host_delegate.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/renderer_host/render_widget_host_view_base.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/devtools_agent_host.h"
-#include "content/public/browser/javascript_dialog_manager.h"
-#include "content/public/browser/navigation_controller.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/render_widget_host_view.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"
-#include "content/public/common/page_transition_types.h"
-#include "content/public/common/referrer.h"
-#include "ipc/ipc_sender.h"
-#include "net/base/net_util.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/gfx/codec/jpeg_codec.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/display.h"
-#include "ui/gfx/screen.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/snapshot/snapshot.h"
-#include "url/gurl.h"
-#include "webkit/browser/quota/quota_manager.h"
-
-using blink::WebGestureEvent;
-using blink::WebInputEvent;
-using blink::WebMouseEvent;
-
-namespace content {
-
-namespace {
-
-static const char kPng[] = "png";
-static const char kJpeg[] = "jpeg";
-static int kDefaultScreenshotQuality = 80;
-static int kFrameRateThresholdMs = 100;
-static int kCaptureRetryLimit = 2;
-
-void ParseGenericInputParams(base::DictionaryValue* params,
- WebInputEvent* event) {
- int modifiers = 0;
- if (params->GetInteger(devtools::Input::dispatchMouseEvent::kParamModifiers,
- &modifiers)) {
- if (modifiers & 1)
- event->modifiers |= WebInputEvent::AltKey;
- if (modifiers & 2)
- event->modifiers |= WebInputEvent::ControlKey;
- if (modifiers & 4)
- event->modifiers |= WebInputEvent::MetaKey;
- if (modifiers & 8)
- event->modifiers |= WebInputEvent::ShiftKey;
- }
-
- params->GetDouble(devtools::Input::dispatchMouseEvent::kParamTimestamp,
- &event->timeStampSeconds);
-}
-
-} // namespace
-
-RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
- : agent_(agent),
- capture_retry_count_(0),
- weak_factory_(this) {
- RegisterCommandHandler(
- devtools::DOM::setFileInputFiles::kName,
- base::Bind(
- &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Network::clearBrowserCache::kName,
- base::Bind(
- &RendererOverridesHandler::ClearBrowserCache,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Network::clearBrowserCookies::kName,
- base::Bind(
- &RendererOverridesHandler::ClearBrowserCookies,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::disable::kName,
- base::Bind(
- &RendererOverridesHandler::PageDisable, base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::handleJavaScriptDialog::kName,
- base::Bind(
- &RendererOverridesHandler::PageHandleJavaScriptDialog,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::navigate::kName,
- base::Bind(
- &RendererOverridesHandler::PageNavigate,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::reload::kName,
- base::Bind(
- &RendererOverridesHandler::PageReload,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::getNavigationHistory::kName,
- base::Bind(
- &RendererOverridesHandler::PageGetNavigationHistory,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::navigateToHistoryEntry::kName,
- base::Bind(
- &RendererOverridesHandler::PageNavigateToHistoryEntry,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::captureScreenshot::kName,
- base::Bind(
- &RendererOverridesHandler::PageCaptureScreenshot,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::canScreencast::kName,
- base::Bind(
- &RendererOverridesHandler::PageCanScreencast,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::startScreencast::kName,
- base::Bind(
- &RendererOverridesHandler::PageStartScreencast,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::stopScreencast::kName,
- base::Bind(
- &RendererOverridesHandler::PageStopScreencast,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Page::queryUsageAndQuota::kName,
- base::Bind(
- &RendererOverridesHandler::PageQueryUsageAndQuota,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Input::dispatchMouseEvent::kName,
- base::Bind(
- &RendererOverridesHandler::InputDispatchMouseEvent,
- base::Unretained(this)));
- RegisterCommandHandler(
- devtools::Input::dispatchGestureEvent::kName,
- base::Bind(
- &RendererOverridesHandler::InputDispatchGestureEvent,
- base::Unretained(this)));
-}
-
-RendererOverridesHandler::~RendererOverridesHandler() {}
-
-void RendererOverridesHandler::OnClientDetached() {
- screencast_command_ = NULL;
-}
-
-void RendererOverridesHandler::OnSwapCompositorFrame(
- const cc::CompositorFrameMetadata& frame_metadata) {
- last_compositor_frame_metadata_ = frame_metadata;
-
- if (screencast_command_)
- InnerSwapCompositorFrame();
-}
-
-void RendererOverridesHandler::OnVisibilityChanged(bool visible) {
- if (!screencast_command_)
- return;
- NotifyScreencastVisibility(visible);
-}
-
-void RendererOverridesHandler::InnerSwapCompositorFrame() {
- if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
- kFrameRateThresholdMs) {
- return;
- }
-
- RenderViewHost* host = agent_->GetRenderViewHost();
- if (!host->GetView())
- return;
-
- last_frame_time_ = base::TimeTicks::Now();
- std::string format;
- int quality = kDefaultScreenshotQuality;
- double scale = 1;
- ParseCaptureParameters(screencast_command_.get(), &format, &quality, &scale);
-
- const gfx::Display& display =
- gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
- float device_scale_factor = display.device_scale_factor();
-
- gfx::Rect view_bounds = host->GetView()->GetViewBounds();
- gfx::Size snapshot_size(gfx::ToCeiledSize(
- gfx::ScaleSize(view_bounds.size(), scale / device_scale_factor)));
-
- RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
- host->GetView());
- view->CopyFromCompositingSurface(
- view_bounds, snapshot_size,
- base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured,
- weak_factory_.GetWeakPtr(),
- format, quality, last_compositor_frame_metadata_),
- SkBitmap::kARGB_8888_Config);
-}
-
-void RendererOverridesHandler::ParseCaptureParameters(
- DevToolsProtocol::Command* command,
- std::string* format,
- int* quality,
- double* scale) {
- *quality = kDefaultScreenshotQuality;
- *scale = 1;
- double max_width = -1;
- double max_height = -1;
- base::DictionaryValue* params = command->params();
- if (params) {
- params->GetString(devtools::Page::startScreencast::kParamFormat,
- format);
- params->GetInteger(devtools::Page::startScreencast::kParamQuality,
- quality);
- params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth,
- &max_width);
- params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight,
- &max_height);
- }
-
- RenderViewHost* host = agent_->GetRenderViewHost();
- CHECK(host->GetView());
- gfx::Rect view_bounds = host->GetView()->GetViewBounds();
- if (max_width > 0)
- *scale = std::min(*scale, max_width / view_bounds.width());
- if (max_height > 0)
- *scale = std::min(*scale, max_height / view_bounds.height());
-
- if (format->empty())
- *format = kPng;
- if (*quality < 0 || *quality > 100)
- *quality = kDefaultScreenshotQuality;
- if (*scale <= 0)
- *scale = 0.1;
- if (*scale > 5)
- *scale = 5;
-}
-
-base::DictionaryValue* RendererOverridesHandler::CreateScreenshotResponse(
- const std::vector<unsigned char>& png_data) {
- std::string base_64_data;
- base::Base64Encode(
- base::StringPiece(reinterpret_cast<const char*>(&png_data[0]),
- png_data.size()),
- &base_64_data);
-
- base::DictionaryValue* response = new base::DictionaryValue();
- response->SetString(
- devtools::Page::captureScreenshot::kResponseData, base_64_data);
- return response;
-}
-
-// DOM agent handlers --------------------------------------------------------
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
- scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* params = command->params();
- base::ListValue* file_list = NULL;
- const char* param =
- devtools::DOM::setFileInputFiles::kParamFiles;
- if (!params || !params->GetList(param, &file_list))
- return command->InvalidParamResponse(param);
- RenderViewHost* host = agent_->GetRenderViewHost();
- if (!host)
- return NULL;
-
- for (size_t i = 0; i < file_list->GetSize(); ++i) {
- base::FilePath::StringType file;
- if (!file_list->GetString(i, &file))
- return command->InvalidParamResponse(param);
- ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
- host->GetProcess()->GetID(), base::FilePath(file));
- }
- return NULL;
-}
-
-
-// Network agent handlers ----------------------------------------------------
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::ClearBrowserCache(
- scoped_refptr<DevToolsProtocol::Command> command) {
- GetContentClient()->browser()->ClearCache(agent_->GetRenderViewHost());
- return command->SuccessResponse(NULL);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::ClearBrowserCookies(
- scoped_refptr<DevToolsProtocol::Command> command) {
- GetContentClient()->browser()->ClearCookies(agent_->GetRenderViewHost());
- return command->SuccessResponse(NULL);
-}
-
-
-// Page agent handlers -------------------------------------------------------
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageDisable(
- scoped_refptr<DevToolsProtocol::Command> command) {
- screencast_command_ = NULL;
- return NULL;
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageHandleJavaScriptDialog(
- scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* params = command->params();
- const char* paramAccept =
- devtools::Page::handleJavaScriptDialog::kParamAccept;
- bool accept;
- if (!params || !params->GetBoolean(paramAccept, &accept))
- return command->InvalidParamResponse(paramAccept);
- base::string16 prompt_override;
- base::string16* prompt_override_ptr = &prompt_override;
- if (!params || !params->GetString(
- devtools::Page::handleJavaScriptDialog::kParamPromptText,
- prompt_override_ptr)) {
- prompt_override_ptr = NULL;
- }
-
- RenderViewHost* host = agent_->GetRenderViewHost();
- if (host) {
- WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
- if (web_contents) {
- JavaScriptDialogManager* manager =
- web_contents->GetDelegate()->GetJavaScriptDialogManager();
- if (manager && manager->HandleJavaScriptDialog(
- web_contents, accept, prompt_override_ptr)) {
- return command->SuccessResponse(new base::DictionaryValue());
- }
- }
- }
- return command->InternalErrorResponse("No JavaScript dialog to handle");
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageNavigate(
- scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* params = command->params();
- std::string url;
- const char* param = devtools::Page::navigate::kParamUrl;
- if (!params || !params->GetString(param, &url))
- return command->InvalidParamResponse(param);
- GURL gurl(url);
- if (!gurl.is_valid()) {
- return command->InternalErrorResponse("Cannot navigate to invalid URL");
- }
- RenderViewHost* host = agent_->GetRenderViewHost();
- if (host) {
- WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
- if (web_contents) {
- web_contents->GetController()
- .LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- return command->SuccessResponse(new base::DictionaryValue());
- }
- }
- return command->InternalErrorResponse("No WebContents to navigate");
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageReload(
- scoped_refptr<DevToolsProtocol::Command> command) {
- RenderViewHost* host = agent_->GetRenderViewHost();
- if (host) {
- WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
- if (web_contents) {
- // Override only if it is crashed.
- if (!web_contents->IsCrashed())
- return NULL;
-
- web_contents->GetController().Reload(false);
- return command->SuccessResponse(NULL);
- }
- }
- return command->InternalErrorResponse("No WebContents to reload");
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageGetNavigationHistory(
- scoped_refptr<DevToolsProtocol::Command> command) {
- RenderViewHost* host = agent_->GetRenderViewHost();
- if (host) {
- WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
- if (web_contents) {
- base::DictionaryValue* result = new base::DictionaryValue();
- NavigationController& controller = web_contents->GetController();
- result->SetInteger(
- devtools::Page::getNavigationHistory::kResponseCurrentIndex,
- controller.GetCurrentEntryIndex());
- base::ListValue* entries = new base::ListValue();
- for (int i = 0; i != controller.GetEntryCount(); ++i) {
- const NavigationEntry* entry = controller.GetEntryAtIndex(i);
- base::DictionaryValue* entry_value = new base::DictionaryValue();
- entry_value->SetInteger(
- devtools::Page::NavigationEntry::kParamId,
- entry->GetUniqueID());
- entry_value->SetString(
- devtools::Page::NavigationEntry::kParamUrl,
- entry->GetURL().spec());
- entry_value->SetString(
- devtools::Page::NavigationEntry::kParamTitle,
- entry->GetTitle());
- entries->Append(entry_value);
- }
- result->Set(
- devtools::Page::getNavigationHistory::kResponseEntries,
- entries);
- return command->SuccessResponse(result);
- }
- }
- return command->InternalErrorResponse("No WebContents to navigate");
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageNavigateToHistoryEntry(
- scoped_refptr<DevToolsProtocol::Command> command) {
- int entry_id;
-
- base::DictionaryValue* params = command->params();
- const char* param = devtools::Page::navigateToHistoryEntry::kParamEntryId;
- if (!params || !params->GetInteger(param, &entry_id)) {
- return command->InvalidParamResponse(param);
- }
-
- RenderViewHost* host = agent_->GetRenderViewHost();
- if (host) {
- WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
- if (web_contents) {
- NavigationController& controller = web_contents->GetController();
- for (int i = 0; i != controller.GetEntryCount(); ++i) {
- if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
- controller.GoToIndex(i);
- return command->SuccessResponse(new base::DictionaryValue());
- }
- }
- return command->InvalidParamResponse(param);
- }
- }
- return command->InternalErrorResponse("No WebContents to navigate");
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageCaptureScreenshot(
- scoped_refptr<DevToolsProtocol::Command> command) {
- RenderViewHost* host = agent_->GetRenderViewHost();
- if (!host->GetView())
- return command->InternalErrorResponse("Unable to access the view");
-
- gfx::Rect view_bounds = host->GetView()->GetViewBounds();
- gfx::Rect snapshot_bounds(view_bounds.size());
- gfx::Size snapshot_size = snapshot_bounds.size();
-
- std::vector<unsigned char> png_data;
- if (ui::GrabViewSnapshot(host->GetView()->GetNativeView(),
- &png_data,
- snapshot_bounds)) {
- if (png_data.size())
- return command->SuccessResponse(CreateScreenshotResponse(png_data));
- else
- return command->InternalErrorResponse("Unable to capture screenshot");
- }
-
- ui::GrabViewSnapshotAsync(
- host->GetView()->GetNativeView(),
- snapshot_bounds,
- base::ThreadTaskRunnerHandle::Get(),
- base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
- weak_factory_.GetWeakPtr(), command));
- return command->AsyncResponsePromise();
-}
-
-void RendererOverridesHandler::ScreenshotCaptured(
- scoped_refptr<DevToolsProtocol::Command> command,
- scoped_refptr<base::RefCountedBytes> png_data) {
- if (png_data) {
- SendAsyncResponse(
- command->SuccessResponse(CreateScreenshotResponse(png_data->data())));
- } else {
- SendAsyncResponse(
- command->InternalErrorResponse("Unable to capture screenshot"));
- }
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageCanScreencast(
- scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* result = new base::DictionaryValue();
-#if defined(OS_ANDROID)
- result->SetBoolean(devtools::kResult, true);
-#else
- result->SetBoolean(devtools::kResult, false);
-#endif // defined(OS_ANDROID)
- return command->SuccessResponse(result);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageStartScreencast(
- scoped_refptr<DevToolsProtocol::Command> command) {
- screencast_command_ = command;
- RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
- agent_->GetRenderViewHost());
- bool visible = !host->is_hidden();
- NotifyScreencastVisibility(visible);
- if (visible)
- InnerSwapCompositorFrame();
- return command->SuccessResponse(NULL);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageStopScreencast(
- scoped_refptr<DevToolsProtocol::Command> command) {
- last_frame_time_ = base::TimeTicks();
- screencast_command_ = NULL;
- return command->SuccessResponse(NULL);
-}
-
-void RendererOverridesHandler::ScreencastFrameCaptured(
- const std::string& format,
- int quality,
- const cc::CompositorFrameMetadata& metadata,
- bool success,
- const SkBitmap& bitmap) {
- if (!success) {
- if (capture_retry_count_) {
- --capture_retry_count_;
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame,
- weak_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
- }
- return;
- }
-
- std::vector<unsigned char> data;
- SkAutoLockPixels lock_image(bitmap);
- bool encoded;
- if (format == kPng) {
- encoded = gfx::PNGCodec::Encode(
- reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
- gfx::PNGCodec::FORMAT_SkBitmap,
- gfx::Size(bitmap.width(), bitmap.height()),
- bitmap.width() * bitmap.bytesPerPixel(),
- false, std::vector<gfx::PNGCodec::Comment>(), &data);
- } else if (format == kJpeg) {
- encoded = gfx::JPEGCodec::Encode(
- reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
- gfx::JPEGCodec::FORMAT_SkBitmap,
- bitmap.width(),
- bitmap.height(),
- bitmap.width() * bitmap.bytesPerPixel(),
- quality, &data);
- } else {
- encoded = false;
- }
-
- if (!encoded)
- return;
-
- std::string base_64_data;
- base::Base64Encode(
- base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
- &base_64_data);
-
- base::DictionaryValue* response = new base::DictionaryValue();
- response->SetString(devtools::Page::screencastFrame::kParamData,
- base_64_data);
-
- // Consider metadata empty in case it has no device scale factor.
- if (metadata.device_scale_factor != 0) {
- base::DictionaryValue* response_metadata = new base::DictionaryValue();
-
- response_metadata->SetDouble(
- devtools::Page::ScreencastFrameMetadata::kParamDeviceScaleFactor,
- metadata.device_scale_factor);
- response_metadata->SetDouble(
- devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactor,
- metadata.page_scale_factor);
- response_metadata->SetDouble(
- devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMin,
- metadata.min_page_scale_factor);
- response_metadata->SetDouble(
- devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMax,
- metadata.max_page_scale_factor);
- response_metadata->SetDouble(
- devtools::Page::ScreencastFrameMetadata::kParamOffsetTop,
- metadata.location_bar_content_translation.y());
- response_metadata->SetDouble(
- devtools::Page::ScreencastFrameMetadata::kParamOffsetBottom,
- metadata.overdraw_bottom_height);
-
- base::DictionaryValue* viewport = new base::DictionaryValue();
- viewport->SetDouble(devtools::DOM::Rect::kParamX,
- metadata.root_scroll_offset.x());
- viewport->SetDouble(devtools::DOM::Rect::kParamY,
- metadata.root_scroll_offset.y());
- viewport->SetDouble(devtools::DOM::Rect::kParamWidth,
- metadata.viewport_size.width());
- viewport->SetDouble(devtools::DOM::Rect::kParamHeight,
- metadata.viewport_size.height());
- response_metadata->Set(
- devtools::Page::ScreencastFrameMetadata::kParamViewport, viewport);
-
- response->Set(devtools::Page::screencastFrame::kParamMetadata,
- response_metadata);
- }
-
- SendNotification(devtools::Page::screencastFrame::kName, response);
-}
-
-// Quota and Usage ------------------------------------------
-
-namespace {
-
-typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)>
- ResponseCallback;
-
-void QueryUsageAndQuotaCompletedOnIOThread(
- scoped_ptr<base::DictionaryValue> quota,
- scoped_ptr<base::DictionaryValue> usage,
- ResponseCallback callback) {
-
- scoped_ptr<base::DictionaryValue> response_data(new base::DictionaryValue);
- response_data->Set(devtools::Page::queryUsageAndQuota::kResponseQuota,
- quota.release());
- response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage,
- usage.release());
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(callback, base::Passed(&response_data)));
-}
-
-void DidGetHostUsage(
- base::ListValue* list,
- const std::string& client_id,
- const base::Closure& barrier,
- int64 value) {
- base::DictionaryValue* usage_item = new base::DictionaryValue;
- usage_item->SetString(devtools::Page::UsageItem::kParamId, client_id);
- usage_item->SetDouble(devtools::Page::UsageItem::kParamValue, value);
- list->Append(usage_item);
- barrier.Run();
-}
-
-void DidGetQuotaValue(
- base::DictionaryValue* dictionary,
- const std::string& item_name,
- const base::Closure& barrier,
- quota::QuotaStatusCode status,
- int64 value) {
- if (status == quota::kQuotaStatusOk)
- dictionary->SetDouble(item_name, value);
- barrier.Run();
-}
-
-void DidGetUsageAndQuotaForWebApps(
- base::DictionaryValue* quota,
- const std::string& item_name,
- const base::Closure& barrier,
- quota::QuotaStatusCode status,
- int64 used_bytes,
- int64 quota_in_bytes) {
- if (status == quota::kQuotaStatusOk)
- quota->SetDouble(item_name, quota_in_bytes);
- barrier.Run();
-}
-
-std::string GetStorageTypeName(quota::StorageType type) {
- switch (type) {
- case quota::kStorageTypeTemporary:
- return devtools::Page::Usage::kParamTemporary;
- case quota::kStorageTypePersistent:
- return devtools::Page::Usage::kParamPersistent;
- case quota::kStorageTypeSyncable:
- return devtools::Page::Usage::kParamSyncable;
- case quota::kStorageTypeQuotaNotManaged:
- case quota::kStorageTypeUnknown:
- NOTREACHED();
- }
- return "";
-}
-
-std::string GetQuotaClientName(quota::QuotaClient::ID id) {
- switch (id) {
- case quota::QuotaClient::kFileSystem:
- return devtools::Page::UsageItem::Id::kEnumFilesystem;
- case quota::QuotaClient::kDatabase:
- return devtools::Page::UsageItem::Id::kEnumDatabase;
- case quota::QuotaClient::kAppcache:
- return devtools::Page::UsageItem::Id::kEnumAppcache;
- case quota::QuotaClient::kIndexedDatabase:
- return devtools::Page::UsageItem::Id::kEnumIndexeddatabase;
- default:
- NOTREACHED();
- return "";
- }
-}
-
-void QueryUsageAndQuotaOnIOThread(
- scoped_refptr<quota::QuotaManager> quota_manager,
- const GURL& security_origin,
- const ResponseCallback& callback) {
- scoped_ptr<base::DictionaryValue> quota(new base::DictionaryValue);
- scoped_ptr<base::DictionaryValue> usage(new base::DictionaryValue);
-
- static quota::QuotaClient::ID kQuotaClients[] = {
- quota::QuotaClient::kFileSystem,
- quota::QuotaClient::kDatabase,
- quota::QuotaClient::kAppcache,
- quota::QuotaClient::kIndexedDatabase
- };
-
- static const size_t kStorageTypeCount = quota::kStorageTypeUnknown;
- std::map<quota::StorageType, base::ListValue*> storage_type_lists;
-
- for (size_t i = 0; i != kStorageTypeCount; i++) {
- const quota::StorageType type = static_cast<quota::StorageType>(i);
- if (type == quota::kStorageTypeQuotaNotManaged)
- continue;
- storage_type_lists[type] = new base::ListValue;
- usage->Set(GetStorageTypeName(type), storage_type_lists[type]);
- }
-
- const int kExpectedResults =
- 2 + arraysize(kQuotaClients) * storage_type_lists.size();
- base::DictionaryValue* quota_raw_ptr = quota.get();
-
- // Takes ownership on usage and quota.
- base::Closure barrier = BarrierClosure(
- kExpectedResults,
- base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
- base::Passed(&quota),
- base::Passed(&usage),
- callback));
- std::string host = net::GetHostOrSpecFromURL(security_origin);
-
- quota_manager->GetUsageAndQuotaForWebApps(
- security_origin,
- quota::kStorageTypeTemporary,
- base::Bind(&DidGetUsageAndQuotaForWebApps, quota_raw_ptr,
- std::string(devtools::Page::Quota::kParamTemporary), barrier));
-
- quota_manager->GetPersistentHostQuota(
- host,
- base::Bind(&DidGetQuotaValue, quota_raw_ptr,
- std::string(devtools::Page::Quota::kParamPersistent),
- barrier));
-
- for (size_t i = 0; i != arraysize(kQuotaClients); i++) {
- std::map<quota::StorageType, base::ListValue*>::const_iterator iter;
- for (iter = storage_type_lists.begin();
- iter != storage_type_lists.end(); ++iter) {
- const quota::StorageType type = (*iter).first;
- if (!quota_manager->IsTrackingHostUsage(type, kQuotaClients[i])) {
- barrier.Run();
- continue;
- }
- quota_manager->GetHostUsage(
- host, type, kQuotaClients[i],
- base::Bind(&DidGetHostUsage, (*iter).second,
- GetQuotaClientName(kQuotaClients[i]),
- barrier));
- }
- }
-}
-
-} // namespace
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::PageQueryUsageAndQuota(
- scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* params = command->params();
- std::string security_origin;
- if (!params || !params->GetString(
- devtools::Page::queryUsageAndQuota::kParamSecurityOrigin,
- &security_origin)) {
- return command->InvalidParamResponse(
- devtools::Page::queryUsageAndQuota::kParamSecurityOrigin);
- }
-
- ResponseCallback callback = base::Bind(
- &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted,
- weak_factory_.GetWeakPtr(),
- command);
-
- scoped_refptr<quota::QuotaManager> quota_manager =
- agent_->GetRenderViewHost()->GetProcess()->
- GetStoragePartition()->GetQuotaManager();
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(
- &QueryUsageAndQuotaOnIOThread,
- quota_manager,
- GURL(security_origin),
- callback));
-
- return command->AsyncResponsePromise();
-}
-
-void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted(
- scoped_refptr<DevToolsProtocol::Command> command,
- scoped_ptr<base::DictionaryValue> response_data) {
- SendAsyncResponse(command->SuccessResponse(response_data.release()));
-}
-
-void RendererOverridesHandler::NotifyScreencastVisibility(bool visible) {
- if (visible)
- capture_retry_count_ = kCaptureRetryLimit;
- base::DictionaryValue* params = new base::DictionaryValue();
- params->SetBoolean(
- devtools::Page::screencastVisibilityChanged::kParamVisible, visible);
- SendNotification(
- devtools::Page::screencastVisibilityChanged::kName, params);
-}
-
-// Input agent handlers ------------------------------------------------------
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::InputDispatchMouseEvent(
- scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* params = command->params();
- if (!params)
- return NULL;
-
- bool device_space = false;
- if (!params->GetBoolean(
- devtools::Input::dispatchMouseEvent::kParamDeviceSpace,
- &device_space) ||
- !device_space) {
- return NULL;
- }
-
- RenderViewHost* host = agent_->GetRenderViewHost();
- blink::WebMouseEvent mouse_event;
- ParseGenericInputParams(params, &mouse_event);
-
- std::string type;
- if (params->GetString(devtools::Input::dispatchMouseEvent::kParamType,
- &type)) {
- if (type ==
- devtools::Input::dispatchMouseEvent::Type::kEnumMousePressed)
- mouse_event.type = WebInputEvent::MouseDown;
- else if (type ==
- devtools::Input::dispatchMouseEvent::Type::kEnumMouseReleased)
- mouse_event.type = WebInputEvent::MouseUp;
- else if (type ==
- devtools::Input::dispatchMouseEvent::Type::kEnumMouseMoved)
- mouse_event.type = WebInputEvent::MouseMove;
- else
- return NULL;
- } else {
- return NULL;
- }
-
- if (!params->GetInteger(devtools::Input::dispatchMouseEvent::kParamX,
- &mouse_event.x) ||
- !params->GetInteger(devtools::Input::dispatchMouseEvent::kParamY,
- &mouse_event.y)) {
- return NULL;
- }
-
- mouse_event.windowX = mouse_event.x;
- mouse_event.windowY = mouse_event.y;
- mouse_event.globalX = mouse_event.x;
- mouse_event.globalY = mouse_event.y;
-
- params->GetInteger(devtools::Input::dispatchMouseEvent::kParamClickCount,
- &mouse_event.clickCount);
-
- std::string button;
- if (!params->GetString(devtools::Input::dispatchMouseEvent::kParamButton,
- &button)) {
- return NULL;
- }
-
- if (button == "none") {
- mouse_event.button = WebMouseEvent::ButtonNone;
- } else if (button == "left") {
- mouse_event.button = WebMouseEvent::ButtonLeft;
- mouse_event.modifiers |= WebInputEvent::LeftButtonDown;
- } else if (button == "middle") {
- mouse_event.button = WebMouseEvent::ButtonMiddle;
- mouse_event.modifiers |= WebInputEvent::MiddleButtonDown;
- } else if (button == "right") {
- mouse_event.button = WebMouseEvent::ButtonRight;
- mouse_event.modifiers |= WebInputEvent::RightButtonDown;
- } else {
- return NULL;
- }
-
- host->ForwardMouseEvent(mouse_event);
- return command->SuccessResponse(NULL);
-}
-
-scoped_refptr<DevToolsProtocol::Response>
-RendererOverridesHandler::InputDispatchGestureEvent(
- scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* params = command->params();
- if (!params)
- return NULL;
-
- RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
- agent_->GetRenderViewHost());
- blink::WebGestureEvent event;
- ParseGenericInputParams(params, &event);
- event.sourceDevice = blink::WebGestureDeviceTouchscreen;
-
- std::string type;
- if (params->GetString(devtools::Input::dispatchGestureEvent::kParamType,
- &type)) {
- if (type ==
- devtools::Input::dispatchGestureEvent::Type::kEnumScrollBegin)
- event.type = WebInputEvent::GestureScrollBegin;
- else if (type ==
- devtools::Input::dispatchGestureEvent::Type::kEnumScrollUpdate)
- event.type = WebInputEvent::GestureScrollUpdate;
- else if (type ==
- devtools::Input::dispatchGestureEvent::Type::kEnumScrollEnd)
- event.type = WebInputEvent::GestureScrollEnd;
- else if (type ==
- devtools::Input::dispatchGestureEvent::Type::kEnumTapDown)
- event.type = WebInputEvent::GestureTapDown;
- else if (type ==
- devtools::Input::dispatchGestureEvent::Type::kEnumTap)
- event.type = WebInputEvent::GestureTap;
- else if (type ==
- devtools::Input::dispatchGestureEvent::Type::kEnumPinchBegin)
- event.type = WebInputEvent::GesturePinchBegin;
- else if (type ==
- devtools::Input::dispatchGestureEvent::Type::kEnumPinchUpdate)
- event.type = WebInputEvent::GesturePinchUpdate;
- else if (type ==
- devtools::Input::dispatchGestureEvent::Type::kEnumPinchEnd)
- event.type = WebInputEvent::GesturePinchEnd;
- else
- return NULL;
- } else {
- return NULL;
- }
-
- if (!params->GetInteger(devtools::Input::dispatchGestureEvent::kParamX,
- &event.x) ||
- !params->GetInteger(devtools::Input::dispatchGestureEvent::kParamY,
- &event.y)) {
- return NULL;
- }
- event.globalX = event.x;
- event.globalY = event.y;
-
- if (type == "scrollUpdate") {
- int dx;
- int dy;
- if (!params->GetInteger(
- devtools::Input::dispatchGestureEvent::kParamDeltaX, &dx) ||
- !params->GetInteger(
- devtools::Input::dispatchGestureEvent::kParamDeltaY, &dy)) {
- return NULL;
- }
- event.data.scrollUpdate.deltaX = dx;
- event.data.scrollUpdate.deltaY = dy;
- }
-
- if (type == "pinchUpdate") {
- double scale;
- if (!params->GetDouble(
- devtools::Input::dispatchGestureEvent::kParamPinchScale,
- &scale)) {
- return NULL;
- }
- event.data.pinchUpdate.scale = static_cast<float>(scale);
- }
-
- host->ForwardGestureEvent(event);
- return command->SuccessResponse(NULL);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/renderer_overrides_handler.h b/chromium/content/browser/devtools/renderer_overrides_handler.h
deleted file mode 100644
index 0f7f8bc6cba..00000000000
--- a/chromium/content/browser/devtools/renderer_overrides_handler.h
+++ /dev/null
@@ -1,119 +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_DEVTOOLS_RENDERER_OVERRIDES_HANDLER_H_
-#define CONTENT_BROWSER_DEVTOOLS_RENDERER_OVERRIDES_HANDLER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "cc/output/compositor_frame_metadata.h"
-#include "content/browser/devtools/devtools_protocol.h"
-#include "content/common/content_export.h"
-
-class SkBitmap;
-
-namespace IPC {
-class Message;
-}
-
-namespace content {
-
-class DevToolsAgentHost;
-class DevToolsTracingHandler;
-
-// Overrides Inspector commands before they are sent to the renderer.
-// May override the implementation completely, ignore it, or handle
-// additional browser process implementation details.
-class CONTENT_EXPORT RendererOverridesHandler
- : public DevToolsProtocol::Handler {
- public:
- explicit RendererOverridesHandler(DevToolsAgentHost* agent);
- virtual ~RendererOverridesHandler();
-
- void OnClientDetached();
- void OnSwapCompositorFrame(const cc::CompositorFrameMetadata& frame_metadata);
- void OnVisibilityChanged(bool visible);
-
- private:
- void InnerSwapCompositorFrame();
- void ParseCaptureParameters(DevToolsProtocol::Command* command,
- std::string* format, int* quality,
- double* scale);
- base::DictionaryValue* CreateScreenshotResponse(
- const std::vector<unsigned char>& png_data);
-
- // DOM domain.
- scoped_refptr<DevToolsProtocol::Response>
- GrantPermissionsForSetFileInputFiles(
- scoped_refptr<DevToolsProtocol::Command> command);
-
- // Network domain.
- scoped_refptr<DevToolsProtocol::Response> ClearBrowserCache(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> ClearBrowserCookies(
- scoped_refptr<DevToolsProtocol::Command> command);
-
- // Page domain.
- scoped_refptr<DevToolsProtocol::Response> PageDisable(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageHandleJavaScriptDialog(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageNavigate(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageReload(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageGetNavigationHistory(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageNavigateToHistoryEntry(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageCaptureScreenshot(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageCanScreencast(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageStartScreencast(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageStopScreencast(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> PageQueryUsageAndQuota(
- scoped_refptr<DevToolsProtocol::Command>);
-
- void ScreenshotCaptured(
- scoped_refptr<DevToolsProtocol::Command> command,
- scoped_refptr<base::RefCountedBytes> png_data);
-
- void ScreencastFrameCaptured(
- const std::string& format,
- int quality,
- const cc::CompositorFrameMetadata& metadata,
- bool success,
- const SkBitmap& bitmap);
-
- void PageQueryUsageAndQuotaCompleted(
- scoped_refptr<DevToolsProtocol::Command>,
- scoped_ptr<base::DictionaryValue> response_data);
-
- void NotifyScreencastVisibility(bool visible);
-
- // Input domain.
- scoped_refptr<DevToolsProtocol::Response> InputDispatchMouseEvent(
- scoped_refptr<DevToolsProtocol::Command> command);
- scoped_refptr<DevToolsProtocol::Response> InputDispatchGestureEvent(
- scoped_refptr<DevToolsProtocol::Command> command);
-
- DevToolsAgentHost* agent_;
- scoped_refptr<DevToolsProtocol::Command> screencast_command_;
- cc::CompositorFrameMetadata last_compositor_frame_metadata_;
- base::TimeTicks last_frame_time_;
- int capture_retry_count_;
- base::WeakPtrFactory<RendererOverridesHandler> weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(RendererOverridesHandler);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_RENDERER_OVERRIDES_HANDLER_H_
diff --git a/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc b/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc
index d869d9d6e6c..fd02c091234 100644
--- a/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc
+++ b/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc
@@ -2,37 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/basictypes.h"
+#include "base/base64.h"
+#include "base/command_line.h"
#include "base/json/json_reader.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/browser/devtools/renderer_overrides_handler.h"
+#include "content/browser/devtools/devtools_protocol.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/web_contents.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 "third_party/skia/include/core/SkBitmap.h"
+#include "ui/compositor/compositor_switches.h"
+#include "ui/gfx/codec/png_codec.h"
namespace content {
-class RendererOverridesHandlerTest : public ContentBrowserTest {
+class RendererOverridesHandlerTest : public ContentBrowserTest,
+ public DevToolsAgentHostClient {
protected:
- scoped_refptr<DevToolsProtocol::Response> SendCommand(
- const std::string& method,
- base::DictionaryValue* params) {
- scoped_ptr<RendererOverridesHandler> handler(CreateHandler());
- scoped_refptr<DevToolsProtocol::Command> command(
- DevToolsProtocol::CreateCommand(1, method, params));
- return handler->HandleCommand(command);
- }
-
- void SendAsyncCommand(const std::string& method,
- base::DictionaryValue* params) {
- scoped_ptr<RendererOverridesHandler> handler(CreateHandler());
- scoped_refptr<DevToolsProtocol::Command> command(
- DevToolsProtocol::CreateCommand(1, method, params));
- scoped_refptr<DevToolsProtocol::Response> response =
- handler->HandleCommand(command);
- EXPECT_TRUE(response->is_async_promise());
+ void SendCommand(const std::string& method,
+ base::DictionaryValue* params) {
+ agent_host_->DispatchProtocolMessage(
+ DevToolsProtocol::CreateCommand(1, method, params)->Serialize());
base::MessageLoop::current()->Run();
}
@@ -62,32 +53,38 @@ class RendererOverridesHandlerTest : public ContentBrowserTest {
}
scoped_ptr<base::DictionaryValue> result_;
+ scoped_refptr<DevToolsAgentHost> agent_host_;
private:
- RendererOverridesHandler* CreateHandler() {
- RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
- DevToolsAgentHost* agent = DevToolsAgentHost::GetOrCreateFor(rvh).get();
- scoped_ptr<RendererOverridesHandler> handler(
- new RendererOverridesHandler(agent));
- handler->SetNotifier(base::Bind(
- &RendererOverridesHandlerTest::OnMessageSent, base::Unretained(this)));
- return handler.release();
+ void SetUpOnMainThread() override {
+ agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
+ agent_host_->AttachClient(this);
+ }
+
+ void TearDownOnMainThread() override {
+ agent_host_->DetachClient();
+ agent_host_ = NULL;
}
- void OnMessageSent(const std::string& message) {
+ void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+ const std::string& message) override {
scoped_ptr<base::DictionaryValue> root(
static_cast<base::DictionaryValue*>(base::JSONReader::Read(message)));
base::DictionaryValue* result;
- root->GetDictionary("result", &result);
+ EXPECT_TRUE(root->GetDictionary("result", &result));
result_.reset(result->DeepCopy());
base::MessageLoop::current()->QuitNow();
}
+
+ void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {
+ EXPECT_TRUE(false);
+ }
};
IN_PROC_BROWSER_TEST_F(RendererOverridesHandlerTest, QueryUsageAndQuota) {
base::DictionaryValue* params = new base::DictionaryValue();
params->SetString("securityOrigin", "http://example.com");
- SendAsyncCommand("Page.queryUsageAndQuota", params);
+ SendCommand("Page.queryUsageAndQuota", params);
EXPECT_TRUE(HasValue("quota.persistent"));
EXPECT_TRUE(HasValue("quota.temporary"));
@@ -98,4 +95,43 @@ IN_PROC_BROWSER_TEST_F(RendererOverridesHandlerTest, QueryUsageAndQuota) {
EXPECT_TRUE(HasListItem("usage.persistent", "id", "filesystem"));
}
+class CaptureScreenshotTest : public RendererOverridesHandlerTest {
+ private:
+#if !defined(OS_ANDROID)
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
+ }
+#endif
+};
+
+// Does not link on Android
+#if defined(OS_ANDROID)
+#define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
+#elif defined(OS_MACOSX) // Fails on 10.9. http://crbug.com/430620
+#define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
+#elif defined(MEMORY_SANITIZER)
+// Also fails under MSAN. http://crbug.com/423583
+#define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
+#else
+#define MAYBE_CaptureScreenshot CaptureScreenshot
+#endif
+IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, MAYBE_CaptureScreenshot) {
+ shell()->LoadURL(GURL("about:blank"));
+ EXPECT_TRUE(content::ExecuteScript(
+ shell()->web_contents()->GetRenderViewHost(),
+ "document.body.style.background = '#123456'"));
+ SendCommand("Page.captureScreenshot", new base::DictionaryValue());
+ std::string base64;
+ EXPECT_TRUE(result_->GetString("data", &base64));
+ std::string png;
+ EXPECT_TRUE(base::Base64Decode(base64, &png));
+ SkBitmap bitmap;
+ gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(png.data()),
+ png.size(), &bitmap);
+ SkColor color(bitmap.getColor(0, 0));
+ EXPECT_TRUE(std::abs(0x12-(int)SkColorGetR(color)) <= 1);
+ EXPECT_TRUE(std::abs(0x34-(int)SkColorGetG(color)) <= 1);
+ EXPECT_TRUE(std::abs(0x56-(int)SkColorGetB(color)) <= 1);
+}
+
} // namespace content
diff --git a/chromium/content/browser/devtools/tethering_handler.cc b/chromium/content/browser/devtools/tethering_handler.cc
index 9b3b7fa005a..e0c083dd8ea 100644
--- a/chromium/content/browser/devtools/tethering_handler.cc
+++ b/chromium/content/browser/devtools/tethering_handler.cc
@@ -9,7 +9,8 @@
#include "base/stl_util.h"
#include "base/values.h"
#include "content/browser/devtools/devtools_http_handler_impl.h"
-#include "content/public/browser/devtools_client_host.h"
+#include "content/browser/devtools/devtools_protocol_constants.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_http_handler_delegate.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
@@ -23,21 +24,13 @@ namespace content {
namespace {
-const char kTetheringBind[] = "Tethering.bind";
-const char kTetheringUnbind[] = "Tethering.unbind";
-
-const char kTetheringAccepted[] = "Tethering.accepted";
-
-const char kPortParam[] = "port";
-const char kConnectionIdParam[] = "connectionId";
-
const char kLocalhost[] = "127.0.0.1";
const int kListenBacklog = 5;
const int kBufferSize = 16 * 1024;
-const int kMinTetheringPort = 5000;
-const int kMaxTetheringPort = 10000;
+const int kMinTetheringPort = 1024;
+const int kMaxTetheringPort = 32767;
class SocketPump : public net::StreamListenSocket::Delegate {
public:
@@ -57,11 +50,11 @@ class SocketPump : public net::StreamListenSocket::Delegate {
return channel_name;
}
- virtual ~SocketPump() { }
+ ~SocketPump() override {}
private:
- virtual void DidAccept(net::StreamListenSocket* server,
- scoped_ptr<net::StreamListenSocket> socket) OVERRIDE {
+ void DidAccept(net::StreamListenSocket* server,
+ scoped_ptr<net::StreamListenSocket> socket) override {
if (accepted_socket_.get())
return;
@@ -78,9 +71,9 @@ class SocketPump : public net::StreamListenSocket::Delegate {
OnClientRead(result);
}
- virtual void DidRead(net::StreamListenSocket* socket,
- const char* data,
- int len) OVERRIDE {
+ void DidRead(net::StreamListenSocket* socket,
+ const char* data,
+ int len) override {
int old_size = wire_buffer_size_;
wire_buffer_size_ += len;
while (wire_buffer_->capacity() < wire_buffer_size_)
@@ -91,9 +84,7 @@ class SocketPump : public net::StreamListenSocket::Delegate {
OnClientWrite(0);
}
- virtual void DidClose(net::StreamListenSocket* socket) OVERRIDE {
- SelfDestruct();
- }
+ void DidClose(net::StreamListenSocket* socket) override { SelfDestruct(); }
void OnClientRead(int result) {
if (result <= 0) {
@@ -111,8 +102,10 @@ class SocketPump : public net::StreamListenSocket::Delegate {
}
void OnClientWrite(int result) {
- if (result < 0)
+ if (result < 0) {
SelfDestruct();
+ return;
+ }
wire_buffer_->set_offset(wire_buffer_->offset() + result);
@@ -149,7 +142,7 @@ class SocketPump : public net::StreamListenSocket::Delegate {
}
void SelfDestruct() {
- if (wire_buffer_ && wire_buffer_->offset() != wire_buffer_size_) {
+ if (wire_buffer_.get() && wire_buffer_->offset() != wire_buffer_size_) {
pending_destruction_ = true;
return;
}
@@ -167,15 +160,24 @@ class SocketPump : public net::StreamListenSocket::Delegate {
bool pending_destruction_;
};
-} // namespace
-
-const char TetheringHandler::kDomain[] = "Tethering";
+static int GetPort(scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& paramName) {
+ base::DictionaryValue* params = command->params();
+ int port = 0;
+ if (!params ||
+ !params->GetInteger(paramName, &port) ||
+ port < kMinTetheringPort || port > kMaxTetheringPort)
+ return 0;
+ return port;
+}
-class TetheringHandler::BoundSocket {
+class BoundSocket {
public:
- BoundSocket(TetheringHandler* handler,
+ typedef base::Callback<void(int, const std::string&)> AcceptedCallback;
+
+ BoundSocket(AcceptedCallback accepted_callback,
DevToolsHttpHandlerDelegate* delegate)
- : handler_(handler),
+ : accepted_callback_(accepted_callback),
delegate_(delegate),
socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
port_(0) {
@@ -232,77 +234,208 @@ class TetheringHandler::BoundSocket {
SocketPump* pump = new SocketPump(delegate_, accept_socket_.release());
std::string name = pump->Init();
if (!name.empty())
- handler_->Accepted(port_, name);
+ accepted_callback_.Run(port_, name);
}
- TetheringHandler* handler_;
+ AcceptedCallback accepted_callback_;
DevToolsHttpHandlerDelegate* delegate_;
scoped_ptr<net::ServerSocket> socket_;
scoped_ptr<net::StreamSocket> accept_socket_;
int port_;
};
-TetheringHandler::TetheringHandler(DevToolsHttpHandlerDelegate* delegate)
- : delegate_(delegate) {
- RegisterCommandHandler(kTetheringBind,
+} // namespace
+
+// TetheringHandler::TetheringImpl -------------------------------------------
+
+class TetheringHandler::TetheringImpl {
+ public:
+ TetheringImpl(
+ base::WeakPtr<TetheringHandler> handler,
+ DevToolsHttpHandlerDelegate* delegate);
+ ~TetheringImpl();
+
+ void Bind(scoped_refptr<DevToolsProtocol::Command> command, int port);
+ void Unbind(scoped_refptr<DevToolsProtocol::Command> command, int port);
+ void Accepted(int port, const std::string& name);
+
+ private:
+ void SendInternalError(scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message);
+
+ base::WeakPtr<TetheringHandler> handler_;
+ DevToolsHttpHandlerDelegate* delegate_;
+
+ typedef std::map<int, BoundSocket*> BoundSockets;
+ BoundSockets bound_sockets_;
+};
+
+TetheringHandler::TetheringImpl::TetheringImpl(
+ base::WeakPtr<TetheringHandler> handler,
+ DevToolsHttpHandlerDelegate* delegate)
+ : handler_(handler),
+ delegate_(delegate) {
+}
+
+TetheringHandler::TetheringImpl::~TetheringImpl() {
+ STLDeleteContainerPairSecondPointers(bound_sockets_.begin(),
+ bound_sockets_.end());
+}
+
+void TetheringHandler::TetheringImpl::Bind(
+ scoped_refptr<DevToolsProtocol::Command> command, int port) {
+ if (bound_sockets_.find(port) != bound_sockets_.end()) {
+ SendInternalError(command, "Port already bound");
+ return;
+ }
+
+ BoundSocket::AcceptedCallback callback = base::Bind(
+ &TetheringHandler::TetheringImpl::Accepted, base::Unretained(this));
+ scoped_ptr<BoundSocket> bound_socket(new BoundSocket(callback, delegate_));
+ if (!bound_socket->Listen(port)) {
+ SendInternalError(command, "Could not bind port");
+ return;
+ }
+
+ bound_sockets_[port] = bound_socket.release();
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&TetheringHandler::SendBindSuccess, handler_, command));
+}
+
+void TetheringHandler::TetheringImpl::Unbind(
+ scoped_refptr<DevToolsProtocol::Command> command, int port) {
+
+ BoundSockets::iterator it = bound_sockets_.find(port);
+ if (it == bound_sockets_.end()) {
+ SendInternalError(command, "Port is not bound");
+ return;
+ }
+
+ delete it->second;
+ bound_sockets_.erase(it);
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&TetheringHandler::SendUnbindSuccess, handler_, command));
+}
+
+void TetheringHandler::TetheringImpl::Accepted(
+ int port, const std::string& name) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&TetheringHandler::Accepted, handler_, port, name));
+}
+
+void TetheringHandler::TetheringImpl::SendInternalError(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&TetheringHandler::SendInternalError, handler_,
+ command, message));
+}
+
+
+// TetheringHandler ----------------------------------------------------------
+
+// static
+TetheringHandler::TetheringImpl* TetheringHandler::impl_ = nullptr;
+
+TetheringHandler::TetheringHandler(
+ DevToolsHttpHandlerDelegate* delegate,
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy)
+ : delegate_(delegate),
+ message_loop_proxy_(message_loop_proxy),
+ is_active_(false),
+ weak_factory_(this) {
+ RegisterCommandHandler(devtools::Tethering::bind::kName,
base::Bind(&TetheringHandler::OnBind,
base::Unretained(this)));
- RegisterCommandHandler(kTetheringUnbind,
+ RegisterCommandHandler(devtools::Tethering::unbind::kName,
base::Bind(&TetheringHandler::OnUnbind,
base::Unretained(this)));
}
TetheringHandler::~TetheringHandler() {
- STLDeleteContainerPairSecondPointers(bound_sockets_.begin(),
- bound_sockets_.end());
+ if (is_active_) {
+ message_loop_proxy_->DeleteSoon(FROM_HERE, impl_);
+ impl_ = nullptr;
+ }
}
void TetheringHandler::Accepted(int port, const std::string& name) {
base::DictionaryValue* params = new base::DictionaryValue();
- params->SetInteger(kPortParam, port);
- params->SetString(kConnectionIdParam, name);
- SendNotification(kTetheringAccepted, params);
+ params->SetInteger(devtools::Tethering::accepted::kParamPort, port);
+ params->SetString(devtools::Tethering::accepted::kParamConnectionId, name);
+ SendNotification(devtools::Tethering::accepted::kName, params);
}
-static int GetPort(scoped_refptr<DevToolsProtocol::Command> command) {
- base::DictionaryValue* params = command->params();
- int port = 0;
- if (!params || !params->GetInteger(kPortParam, &port) ||
- port < kMinTetheringPort || port > kMaxTetheringPort)
- return 0;
- return port;
+bool TetheringHandler::Activate() {
+ if (is_active_)
+ return true;
+ if (impl_)
+ return false;
+ is_active_ = true;
+ impl_ = new TetheringImpl(weak_factory_.GetWeakPtr(), delegate_);
+ return true;
}
scoped_refptr<DevToolsProtocol::Response>
TetheringHandler::OnBind(scoped_refptr<DevToolsProtocol::Command> command) {
- int port = GetPort(command);
+ const std::string& portParamName = devtools::Tethering::bind::kParamPort;
+ int port = GetPort(command, portParamName);
if (port == 0)
- return command->InvalidParamResponse(kPortParam);
-
- if (bound_sockets_.find(port) != bound_sockets_.end())
- return command->InternalErrorResponse("Port already bound");
+ return command->InvalidParamResponse(portParamName);
- scoped_ptr<BoundSocket> bound_socket(new BoundSocket(this, delegate_));
- if (!bound_socket->Listen(port))
- return command->InternalErrorResponse("Could not bind port");
-
- bound_sockets_[port] = bound_socket.release();
- return command->SuccessResponse(NULL);
+ if (!Activate()) {
+ return command->ServerErrorResponse(
+ "Tethering is used by another connection");
+ }
+ DCHECK(impl_);
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(&TetheringImpl::Bind, base::Unretained(impl_),
+ command, port));
+ return command->AsyncResponsePromise();
}
scoped_refptr<DevToolsProtocol::Response>
TetheringHandler::OnUnbind(scoped_refptr<DevToolsProtocol::Command> command) {
- int port = GetPort(command);
+ const std::string& portParamName = devtools::Tethering::unbind::kParamPort;
+ int port = GetPort(command, portParamName);
if (port == 0)
- return command->InvalidParamResponse(kPortParam);
+ return command->InvalidParamResponse(portParamName);
- BoundSockets::iterator it = bound_sockets_.find(port);
- if (it == bound_sockets_.end())
- return command->InternalErrorResponse("Port is not bound");
+ if (!Activate()) {
+ return command->ServerErrorResponse(
+ "Tethering is used by another connection");
+ }
+ DCHECK(impl_);
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(&TetheringImpl::Unbind, base::Unretained(impl_),
+ command, port));
+ return command->AsyncResponsePromise();
+}
- delete it->second;
- bound_sockets_.erase(it);
- return command->SuccessResponse(NULL);
+void TetheringHandler::SendBindSuccess(
+ scoped_refptr<DevToolsProtocol::Command> command) {
+ SendAsyncResponse(command->SuccessResponse(nullptr));
+}
+
+void TetheringHandler::SendUnbindSuccess(
+ scoped_refptr<DevToolsProtocol::Command> command) {
+ SendAsyncResponse(command->SuccessResponse(nullptr));
+}
+
+void TetheringHandler::SendInternalError(
+ scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message) {
+ SendAsyncResponse(command->InternalErrorResponse(message));
}
} // namespace content
diff --git a/chromium/content/browser/devtools/tethering_handler.h b/chromium/content/browser/devtools/tethering_handler.h
index 7086e1747db..d6e56b592fd 100644
--- a/chromium/content/browser/devtools/tethering_handler.h
+++ b/chromium/content/browser/devtools/tethering_handler.h
@@ -7,6 +7,8 @@
#include <map>
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "content/browser/devtools/devtools_protocol.h"
namespace content {
@@ -16,23 +18,33 @@ class DevToolsHttpHandlerDelegate;
// This class implements reversed tethering handler.
class TetheringHandler : public DevToolsProtocol::Handler {
public:
- static const char kDomain[];
+ TetheringHandler(DevToolsHttpHandlerDelegate* delegate,
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy);
+ ~TetheringHandler() override;
- TetheringHandler(DevToolsHttpHandlerDelegate* delegate);
- virtual ~TetheringHandler();
+ private:
+ class TetheringImpl;
void Accepted(int port, const std::string& name);
+ bool Activate();
- private:
- class BoundSocket;
scoped_refptr<DevToolsProtocol::Response> OnBind(
scoped_refptr<DevToolsProtocol::Command> command);
scoped_refptr<DevToolsProtocol::Response> OnUnbind(
scoped_refptr<DevToolsProtocol::Command> command);
- typedef std::map<int, BoundSocket*> BoundSockets;
- BoundSockets bound_sockets_;
+ void SendBindSuccess(scoped_refptr<DevToolsProtocol::Command> command);
+ void SendUnbindSuccess(scoped_refptr<DevToolsProtocol::Command> command);
+ void SendInternalError(scoped_refptr<DevToolsProtocol::Command> command,
+ const std::string& message);
+
DevToolsHttpHandlerDelegate* delegate_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ bool is_active_;
+ base::WeakPtrFactory<TetheringHandler> weak_factory_;
+
+ static TetheringImpl* impl_;
+
DISALLOW_COPY_AND_ASSIGN(TetheringHandler);
};
diff --git a/chromium/content/browser/devtools/worker_devtools_manager.cc b/chromium/content/browser/devtools/worker_devtools_manager.cc
deleted file mode 100644
index 0658c353c64..00000000000
--- a/chromium/content/browser/devtools/worker_devtools_manager.cc
+++ /dev/null
@@ -1,453 +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 "content/browser/devtools/worker_devtools_manager.h"
-
-#include <list>
-#include <map>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "content/browser/devtools/devtools_manager_impl.h"
-#include "content/browser/devtools/devtools_protocol.h"
-#include "content/browser/devtools/devtools_protocol_constants.h"
-#include "content/browser/devtools/embedded_worker_devtools_manager.h"
-#include "content/browser/devtools/ipc_devtools_agent_host.h"
-#include "content/browser/devtools/worker_devtools_message_filter.h"
-#include "content/browser/worker_host/worker_service_impl.h"
-#include "content/common/devtools_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/child_process_data.h"
-#include "content/public/common/process_type.h"
-
-namespace content {
-
-// Called on the UI thread.
-// static
-scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForWorker(
- int worker_process_id,
- int worker_route_id) {
- if (WorkerService::EmbeddedSharedWorkerEnabled()) {
- return EmbeddedWorkerDevToolsManager::GetInstance()
- ->GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id);
- } else {
- return WorkerDevToolsManager::GetDevToolsAgentHostForWorker(
- worker_process_id, worker_route_id);
- }
-}
-
-namespace {
-
-typedef std::map<WorkerDevToolsManager::WorkerId,
- WorkerDevToolsManager::WorkerDevToolsAgentHost*> AgentHosts;
-base::LazyInstance<AgentHosts>::Leaky g_agent_map = LAZY_INSTANCE_INITIALIZER;
-base::LazyInstance<AgentHosts>::Leaky g_orphan_map = LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-struct WorkerDevToolsManager::TerminatedInspectedWorker {
- TerminatedInspectedWorker(WorkerId id,
- const GURL& url,
- const base::string16& name)
- : old_worker_id(id),
- worker_url(url),
- worker_name(name) {}
- WorkerId old_worker_id;
- GURL worker_url;
- base::string16 worker_name;
-};
-
-
-class WorkerDevToolsManager::WorkerDevToolsAgentHost
- : public IPCDevToolsAgentHost {
- public:
- explicit WorkerDevToolsAgentHost(WorkerId worker_id)
- : has_worker_id_(false) {
- SetWorkerId(worker_id, false);
- }
-
- void SetWorkerId(WorkerId worker_id, bool reattach) {
- worker_id_ = worker_id;
- if (!has_worker_id_)
- AddRef(); // Balanced in ResetWorkerId.
- has_worker_id_ = true;
- g_agent_map.Get()[worker_id_] = this;
-
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(
- &ConnectToWorker,
- worker_id.first,
- worker_id.second));
-
- if (reattach)
- Reattach(state_);
- }
-
- void ResetWorkerId() {
- g_agent_map.Get().erase(worker_id_);
- has_worker_id_ = false;
- Release(); // Balanced in SetWorkerId.
- }
-
- void SaveAgentRuntimeState(const std::string& state) {
- state_ = state;
- }
-
- void ConnectionFailed() {
- NotifyCloseListener();
- // Object can be deleted here.
- }
-
- private:
- virtual ~WorkerDevToolsAgentHost();
-
- static void ConnectToWorker(
- int worker_process_id,
- int worker_route_id) {
- WorkerDevToolsManager::GetInstance()->ConnectDevToolsAgentHostToWorker(
- worker_process_id, worker_route_id);
- }
-
- static void ForwardToWorkerDevToolsAgent(
- int worker_process_id,
- int worker_route_id,
- IPC::Message* message) {
- WorkerDevToolsManager::GetInstance()->ForwardToWorkerDevToolsAgent(
- worker_process_id, worker_route_id, *message);
- }
-
- // IPCDevToolsAgentHost implementation.
- virtual void SendMessageToAgent(IPC::Message* message) OVERRIDE {
- if (!has_worker_id_) {
- delete message;
- return;
- }
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(
- &WorkerDevToolsAgentHost::ForwardToWorkerDevToolsAgent,
- worker_id_.first,
- worker_id_.second,
- base::Owned(message)));
- }
-
- virtual void OnClientAttached() OVERRIDE {}
- virtual void OnClientDetached() OVERRIDE {}
-
- bool has_worker_id_;
- WorkerId worker_id_;
- std::string state_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkerDevToolsAgentHost);
-};
-
-
-class WorkerDevToolsManager::DetachedClientHosts {
- public:
- static void WorkerReloaded(WorkerId old_id, WorkerId new_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- AgentHosts::iterator it = g_orphan_map.Get().find(old_id);
- if (it != g_orphan_map.Get().end()) {
- it->second->SetWorkerId(new_id, true);
- g_orphan_map.Get().erase(old_id);
- return;
- }
- RemovePendingWorkerData(old_id);
- }
-
- static void WorkerDestroyed(WorkerId id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- AgentHosts::iterator it = g_agent_map.Get().find(id);
- if (it == g_agent_map.Get().end()) {
- RemovePendingWorkerData(id);
- return;
- }
-
- WorkerDevToolsAgentHost* agent = it->second;
- DevToolsManagerImpl* devtools_manager = DevToolsManagerImpl::GetInstance();
- if (!agent->IsAttached()) {
- // Agent has no client hosts -> delete it.
- RemovePendingWorkerData(id);
- return;
- }
-
- // Client host is debugging this worker agent host.
- std::string notification = DevToolsProtocol::CreateNotification(
- devtools::Worker::disconnectedFromWorker::kName, NULL)->Serialize();
- devtools_manager->DispatchOnInspectorFrontend(agent, notification);
- g_orphan_map.Get()[id] = agent;
- agent->ResetWorkerId();
- }
-
- static void RemovePendingWorkerData(WorkerId id) {
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&RemoveInspectedWorkerDataOnIOThread, id));
- }
-
- private:
- DetachedClientHosts() {}
- ~DetachedClientHosts() {}
-
- static void RemoveInspectedWorkerDataOnIOThread(WorkerId id) {
- WorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(id);
- }
-};
-
-struct WorkerDevToolsManager::InspectedWorker {
- InspectedWorker(WorkerProcessHost* host, int route_id, const GURL& url,
- const base::string16& name)
- : host(host),
- route_id(route_id),
- worker_url(url),
- worker_name(name) {}
- WorkerProcessHost* const host;
- int const route_id;
- GURL worker_url;
- base::string16 worker_name;
-};
-
-// static
-WorkerDevToolsManager* WorkerDevToolsManager::GetInstance() {
- DCHECK(!WorkerService::EmbeddedSharedWorkerEnabled());
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- return Singleton<WorkerDevToolsManager>::get();
-}
-
-// static
-DevToolsAgentHost* WorkerDevToolsManager::GetDevToolsAgentHostForWorker(
- int worker_process_id,
- int worker_route_id) {
- DCHECK(!WorkerService::EmbeddedSharedWorkerEnabled());
- WorkerId id(worker_process_id, worker_route_id);
- AgentHosts::iterator it = g_agent_map.Get().find(id);
- if (it == g_agent_map.Get().end())
- return new WorkerDevToolsAgentHost(id);
- return it->second;
-}
-
-WorkerDevToolsManager::WorkerDevToolsManager() {
-}
-
-WorkerDevToolsManager::~WorkerDevToolsManager() {
-}
-
-bool WorkerDevToolsManager::WorkerCreated(
- WorkerProcessHost* worker,
- const WorkerProcessHost::WorkerInstance& instance) {
- for (TerminatedInspectedWorkers::iterator it = terminated_workers_.begin();
- it != terminated_workers_.end(); ++it) {
- if (instance.Matches(it->worker_url, it->worker_name,
- instance.partition(),
- instance.resource_context())) {
- WorkerId new_worker_id(worker->GetData().id, instance.worker_route_id());
- paused_workers_[new_worker_id] = it->old_worker_id;
- terminated_workers_.erase(it);
- return true;
- }
- }
- return false;
-}
-
-void WorkerDevToolsManager::WorkerDestroyed(
- WorkerProcessHost* worker,
- int worker_route_id) {
- InspectedWorkersList::iterator it = FindInspectedWorker(
- worker->GetData().id,
- worker_route_id);
- if (it == inspected_workers_.end())
- return;
-
- WorkerId worker_id(worker->GetData().id, worker_route_id);
- terminated_workers_.push_back(TerminatedInspectedWorker(
- worker_id,
- it->worker_url,
- it->worker_name));
- inspected_workers_.erase(it);
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DetachedClientHosts::WorkerDestroyed, worker_id));
-}
-
-void WorkerDevToolsManager::WorkerContextStarted(WorkerProcessHost* process,
- int worker_route_id) {
- WorkerId new_worker_id(process->GetData().id, worker_route_id);
- PausedWorkers::iterator it = paused_workers_.find(new_worker_id);
- if (it == paused_workers_.end())
- return;
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(
- &DetachedClientHosts::WorkerReloaded,
- it->second,
- new_worker_id));
- paused_workers_.erase(it);
-}
-
-void WorkerDevToolsManager::RemoveInspectedWorkerData(
- const WorkerId& id) {
- for (TerminatedInspectedWorkers::iterator it = terminated_workers_.begin();
- it != terminated_workers_.end(); ++it) {
- if (it->old_worker_id == id) {
- terminated_workers_.erase(it);
- return;
- }
- }
-
- for (PausedWorkers::iterator it = paused_workers_.begin();
- it != paused_workers_.end(); ++it) {
- if (it->second == id) {
- SendResumeToWorker(it->first);
- paused_workers_.erase(it);
- return;
- }
- }
-}
-
-WorkerDevToolsManager::InspectedWorkersList::iterator
-WorkerDevToolsManager::FindInspectedWorker(
- int host_id, int route_id) {
- InspectedWorkersList::iterator it = inspected_workers_.begin();
- while (it != inspected_workers_.end()) {
- if (it->host->GetData().id == host_id && it->route_id == route_id)
- break;
- ++it;
- }
- return it;
-}
-
-static WorkerProcessHost* FindWorkerProcess(int worker_process_id) {
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- if (iter.GetData().id == worker_process_id)
- return *iter;
- }
- return NULL;
-}
-
-void WorkerDevToolsManager::ConnectDevToolsAgentHostToWorker(
- int worker_process_id,
- int worker_route_id) {
- if (WorkerProcessHost* process = FindWorkerProcess(worker_process_id)) {
- const WorkerProcessHost::Instances& instances = process->instances();
- for (WorkerProcessHost::Instances::const_iterator i = instances.begin();
- i != instances.end(); ++i) {
- if (i->worker_route_id() == worker_route_id) {
- DCHECK(FindInspectedWorker(worker_process_id, worker_route_id) ==
- inspected_workers_.end());
- inspected_workers_.push_back(
- InspectedWorker(process, worker_route_id, i->url(), i->name()));
- return;
- }
- }
- }
- NotifyConnectionFailedOnIOThread(worker_process_id, worker_route_id);
-}
-
-void WorkerDevToolsManager::ForwardToDevToolsClient(
- int worker_process_id,
- int worker_route_id,
- const std::string& message) {
- if (FindInspectedWorker(worker_process_id, worker_route_id) ==
- inspected_workers_.end()) {
- NOTREACHED();
- return;
- }
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(
- &ForwardToDevToolsClientOnUIThread,
- worker_process_id,
- worker_route_id,
- message));
-}
-
-void WorkerDevToolsManager::SaveAgentRuntimeState(int worker_process_id,
- int worker_route_id,
- const std::string& state) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(
- &SaveAgentRuntimeStateOnUIThread,
- worker_process_id,
- worker_route_id,
- state));
-}
-
-void WorkerDevToolsManager::ForwardToWorkerDevToolsAgent(
- int worker_process_id,
- int worker_route_id,
- const IPC::Message& message) {
- InspectedWorkersList::iterator it = FindInspectedWorker(
- worker_process_id,
- worker_route_id);
- if (it == inspected_workers_.end())
- return;
- IPC::Message* msg = new IPC::Message(message);
- msg->set_routing_id(worker_route_id);
- it->host->Send(msg);
-}
-
-// static
-void WorkerDevToolsManager::ForwardToDevToolsClientOnUIThread(
- int worker_process_id,
- int worker_route_id,
- const std::string& message) {
- AgentHosts::iterator it = g_agent_map.Get().find(WorkerId(worker_process_id,
- worker_route_id));
- if (it == g_agent_map.Get().end())
- return;
- DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(it->second,
- message);
-}
-
-// static
-void WorkerDevToolsManager::SaveAgentRuntimeStateOnUIThread(
- int worker_process_id,
- int worker_route_id,
- const std::string& state) {
- AgentHosts::iterator it = g_agent_map.Get().find(WorkerId(worker_process_id,
- worker_route_id));
- if (it == g_agent_map.Get().end())
- return;
- it->second->SaveAgentRuntimeState(state);
-}
-
-// static
-void WorkerDevToolsManager::NotifyConnectionFailedOnIOThread(
- int worker_process_id,
- int worker_route_id) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(
- &WorkerDevToolsManager::NotifyConnectionFailedOnUIThread,
- worker_process_id,
- worker_route_id));
-}
-
-// static
-void WorkerDevToolsManager::NotifyConnectionFailedOnUIThread(
- int worker_process_id,
- int worker_route_id) {
- AgentHosts::iterator it = g_agent_map.Get().find(WorkerId(worker_process_id,
- worker_route_id));
- if (it != g_agent_map.Get().end())
- it->second->ConnectionFailed();
-}
-
-// static
-void WorkerDevToolsManager::SendResumeToWorker(const WorkerId& id) {
- if (WorkerProcessHost* process = FindWorkerProcess(id.first))
- process->Send(new DevToolsAgentMsg_ResumeWorkerContext(id.second));
-}
-
-WorkerDevToolsManager::WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() {
- DetachedClientHosts::RemovePendingWorkerData(worker_id_);
- g_agent_map.Get().erase(worker_id_);
- g_orphan_map.Get().erase(worker_id_);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/worker_devtools_manager.h b/chromium/content/browser/devtools/worker_devtools_manager.h
deleted file mode 100644
index 73916c30fe2..00000000000
--- a/chromium/content/browser/devtools/worker_devtools_manager.h
+++ /dev/null
@@ -1,110 +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_DEVTOOLS_WORKER_DEVTOOLS_MANAGER_H_
-#define CONTENT_BROWSER_DEVTOOLS_WORKER_DEVTOOLS_MANAGER_H_
-
-#include <list>
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/singleton.h"
-#include "content/browser/worker_host/worker_process_host.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class DevToolsAgentHost;
-
-// All methods are supposed to be called on the IO thread.
-// This class is not used when "enable-embedded-shared-worker" flag is set.
-class WorkerDevToolsManager {
- public:
- typedef std::pair<int, int> WorkerId;
- class WorkerDevToolsAgentHost;
-
- // Returns the WorkerDevToolsManager singleton.
- static WorkerDevToolsManager* GetInstance();
-
- // Called on the UI thread.
- static DevToolsAgentHost* GetDevToolsAgentHostForWorker(
- int worker_process_id,
- int worker_route_id);
-
- void ForwardToDevToolsClient(int worker_process_id,
- int worker_route_id,
- const std::string& message);
- void SaveAgentRuntimeState(int worker_process_id,
- int worker_route_id,
- const std::string& state);
-
- // Called on the IO thread.
- // Returns true when the worker must be paused on start.
- bool WorkerCreated(WorkerProcessHost* process,
- const WorkerProcessHost::WorkerInstance& instance);
- void WorkerDestroyed(WorkerProcessHost* process, int worker_route_id);
- void WorkerContextStarted(WorkerProcessHost* process, int worker_route_id);
-
- private:
- friend struct DefaultSingletonTraits<WorkerDevToolsManager>;
- class DetachedClientHosts;
- struct InspectedWorker;
- typedef std::list<InspectedWorker> InspectedWorkersList;
-
- WorkerDevToolsManager();
- virtual ~WorkerDevToolsManager();
-
- void RemoveInspectedWorkerData(const WorkerId& id);
- InspectedWorkersList::iterator FindInspectedWorker(int host_id, int route_id);
-
- void ConnectDevToolsAgentHostToWorker(int worker_process_id,
- int worker_route_id);
- void ForwardToWorkerDevToolsAgent(int worker_process_host_id,
- int worker_route_id,
- const IPC::Message& message);
- static void ForwardToDevToolsClientOnUIThread(
- int worker_process_id,
- int worker_route_id,
- const std::string& message);
- static void SaveAgentRuntimeStateOnUIThread(
- int worker_process_id,
- int worker_route_id,
- const std::string& state);
- static void NotifyConnectionFailedOnIOThread(int worker_process_id,
- int worker_route_id);
- static void NotifyConnectionFailedOnUIThread(int worker_process_id,
- int worker_route_id);
- static void SendResumeToWorker(const WorkerId& id);
-
- InspectedWorkersList inspected_workers_;
-
- struct TerminatedInspectedWorker;
- typedef std::list<TerminatedInspectedWorker> TerminatedInspectedWorkers;
- // List of terminated workers for which there may be a devtools client on
- // the UI thread. Worker entry is added into this list when inspected worker
- // is terminated and will be removed in one of two cases:
- // - shared worker with the same URL and name is started(in wich case we will
- // try to reattach existing DevTools client to the new worker).
- // - DevTools client which was inspecting terminated worker is closed on the
- // UI thread and and WorkerDevToolsManager is notified about that on the IO
- // thread.
- TerminatedInspectedWorkers terminated_workers_;
-
- typedef std::map<WorkerId, WorkerId> PausedWorkers;
- // Map from old to new worker id for the inspected workers that have been
- // terminated and started again in paused state. Worker data will be removed
- // from this list in one of two cases:
- // - DevTools client is closed on the UI thread, WorkerDevToolsManager was
- // notified about that on the IO thread and sent "resume" message to the
- // worker.
- // - Existing DevTools client was reattached to the new worker.
- PausedWorkers paused_workers_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkerDevToolsManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_WORKER_DEVTOOLS_MANAGER_H_
diff --git a/chromium/content/browser/devtools/worker_devtools_message_filter.cc b/chromium/content/browser/devtools/worker_devtools_message_filter.cc
deleted file mode 100644
index 23c068b5405..00000000000
--- a/chromium/content/browser/devtools/worker_devtools_message_filter.cc
+++ /dev/null
@@ -1,49 +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 "content/browser/devtools/worker_devtools_message_filter.h"
-
-#include "content/browser/devtools/worker_devtools_manager.h"
-#include "content/common/devtools_messages.h"
-#include "content/common/worker_messages.h"
-
-namespace content {
-
-WorkerDevToolsMessageFilter::WorkerDevToolsMessageFilter(
- int worker_process_host_id)
- : BrowserMessageFilter(DevToolsMsgStart),
- worker_process_host_id_(worker_process_host_id),
- current_routing_id_(0) {
-}
-
-WorkerDevToolsMessageFilter::~WorkerDevToolsMessageFilter() {
-}
-
-bool WorkerDevToolsMessageFilter::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- current_routing_id_ = message.routing_id();
- IPC_BEGIN_MESSAGE_MAP(WorkerDevToolsMessageFilter, message)
- IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
- OnDispatchOnInspectorFrontend)
- IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
- OnSaveAgentRumtimeState)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void WorkerDevToolsMessageFilter::OnDispatchOnInspectorFrontend(
- const std::string& message) {
- WorkerDevToolsManager::GetInstance()->ForwardToDevToolsClient(
- worker_process_host_id_, current_routing_id_, message);
-}
-
-void WorkerDevToolsMessageFilter::OnSaveAgentRumtimeState(
- const std::string& state) {
- WorkerDevToolsManager::GetInstance()->SaveAgentRuntimeState(
- worker_process_host_id_, current_routing_id_, state);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/devtools/worker_devtools_message_filter.h b/chromium/content/browser/devtools/worker_devtools_message_filter.h
deleted file mode 100644
index c80658e8dbf..00000000000
--- a/chromium/content/browser/devtools/worker_devtools_message_filter.h
+++ /dev/null
@@ -1,34 +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_DEVTOOLS_WORKER_DEVTOOLS_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_DEVTOOLS_WORKER_DEVTOOLS_MESSAGE_FILTER_H_
-
-#include "base/callback_forward.h"
-#include "content/public/browser/browser_message_filter.h"
-
-namespace content {
-
-class WorkerDevToolsMessageFilter : public BrowserMessageFilter {
- public:
- explicit WorkerDevToolsMessageFilter(int worker_process_host_id);
-
- private:
- virtual ~WorkerDevToolsMessageFilter();
-
- // BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- // Message handlers.
- void OnDispatchOnInspectorFrontend(const std::string& message);
- void OnSaveAgentRumtimeState(const std::string& state);
-
- int worker_process_host_id_;
- int current_routing_id_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkerDevToolsMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_WORKER_DEVTOOLS_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/dom_storage/dom_storage_area.cc b/chromium/content/browser/dom_storage/dom_storage_area.cc
index b1e803a148d..90a55a0ed8b 100644
--- a/chromium/content/browser/dom_storage/dom_storage_area.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_area.cc
@@ -17,11 +17,11 @@
#include "content/browser/dom_storage/session_storage_database_adapter.h"
#include "content/common/dom_storage/dom_storage_map.h"
#include "content/common/dom_storage/dom_storage_types.h"
-#include "webkit/browser/database/database_util.h"
-#include "webkit/common/database/database_identifier.h"
-#include "webkit/common/fileapi/file_system_util.h"
+#include "storage/browser/database/database_util.h"
+#include "storage/common/database/database_identifier.h"
+#include "storage/common/fileapi/file_system_util.h"
-using webkit_database::DatabaseUtil;
+using storage::DatabaseUtil;
namespace content {
@@ -39,7 +39,7 @@ const base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] =
// static
base::FilePath DOMStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) {
- std::string filename = webkit_database::GetIdentifierFromOrigin(origin);
+ std::string filename = storage::GetIdentifierFromOrigin(origin);
// There is no base::FilePath.AppendExtension() method, so start with just the
// extension as the filename, and then InsertBeforeExtension the desired
// name.
@@ -52,7 +52,7 @@ GURL DOMStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) {
DCHECK(name.MatchesExtension(kDatabaseFileExtension));
std::string origin_id =
name.BaseName().RemoveExtension().MaybeAsASCII();
- return webkit_database::GetOriginFromIdentifier(origin_id);
+ return storage::GetOriginFromIdentifier(origin_id);
}
DOMStorageArea::DOMStorageArea(
diff --git a/chromium/content/browser/dom_storage/dom_storage_area_unittest.cc b/chromium/content/browser/dom_storage/dom_storage_area_unittest.cc
index c4d290c6a4d..c074cc0709b 100644
--- a/chromium/content/browser/dom_storage/dom_storage_area_unittest.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_area_unittest.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
@@ -58,7 +58,7 @@ class DOMStorageAreaTest : public testing::Test {
class VerifyChangesCommittedDatabase : public DOMStorageDatabase {
public:
VerifyChangesCommittedDatabase() {}
- virtual ~VerifyChangesCommittedDatabase() {
+ ~VerifyChangesCommittedDatabase() override {
const base::string16 kKey(ASCIIToUTF16("key"));
const base::string16 kValue(ASCIIToUTF16("value"));
DOMStorageValuesMap values;
@@ -443,7 +443,7 @@ TEST_F(DOMStorageAreaTest, DatabaseFileNames) {
"file__0.localstorage-journal" },
};
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCases); ++i) {
+ for (size_t i = 0; i < arraysize(kCases); ++i) {
GURL origin = GURL(kCases[i].origin).GetOrigin();
base::FilePath file_name =
base::FilePath().AppendASCII(kCases[i].file_name);
diff --git a/chromium/content/browser/dom_storage/dom_storage_browsertest.cc b/chromium/content/browser/dom_storage/dom_storage_browsertest.cc
index 8d9e31d9d6c..b0c1c63d65f 100644
--- a/chromium/content/browser/dom_storage/dom_storage_browsertest.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_browsertest.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/path_service.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/dom_storage/dom_storage_types.h"
#include "content/public/common/content_paths.h"
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_impl.cc b/chromium/content/browser/dom_storage/dom_storage_context_impl.cc
index 05a65870587..d8e7ac50411 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_impl.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_context_impl.cc
@@ -6,8 +6,8 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/file_util.h"
#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
#include "base/guid.h"
#include "base/location.h"
#include "base/time/time.h"
@@ -20,7 +20,7 @@
#include "content/public/browser/dom_storage_context.h"
#include "content/public/browser/local_storage_usage_info.h"
#include "content/public/browser/session_storage_usage_info.h"
-#include "webkit/browser/quota/special_storage_policy.h"
+#include "storage/browser/quota/special_storage_policy.h"
namespace content {
@@ -29,7 +29,7 @@ static const int kSessionStoraceScavengingSeconds = 60;
DOMStorageContextImpl::DOMStorageContextImpl(
const base::FilePath& localstorage_directory,
const base::FilePath& sessionstorage_directory,
- quota::SpecialStoragePolicy* special_storage_policy,
+ storage::SpecialStoragePolicy* special_storage_policy,
DOMStorageTaskRunner* task_runner)
: localstorage_directory_(localstorage_directory),
sessionstorage_directory_(sessionstorage_directory),
@@ -278,7 +278,7 @@ void DOMStorageContextImpl::DeleteSessionNamespace(
} else {
if (should_persist_data)
it->second->set_must_persist_at_shutdown(true);
- MaybeShutdownSessionNamespace(it->second);
+ MaybeShutdownSessionNamespace(it->second.get());
}
}
@@ -485,11 +485,11 @@ DOMStorageContextImpl::MergeSessionStorage(
StorageNamespaceMap::const_iterator it = namespaces_.find(namespace1_id);
if (it == namespaces_.end())
return SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND;
- DOMStorageNamespace* ns1 = it->second;
+ DOMStorageNamespace* ns1 = it->second.get();
it = namespaces_.find(namespace2_id);
if (it == namespaces_.end())
return SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND;
- DOMStorageNamespace* ns2 = it->second;
+ DOMStorageNamespace* ns2 = it->second.get();
return ns1->Merge(actually_merge, process_id, ns2, this);
}
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_impl.h b/chromium/content/browser/dom_storage/dom_storage_context_impl.h
index d256d9c5723..bd1acbfba22 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_impl.h
+++ b/chromium/content/browser/dom_storage/dom_storage_context_impl.h
@@ -27,7 +27,7 @@ class NullableString16;
class Time;
}
-namespace quota {
+namespace storage {
class SpecialStoragePolicy;
}
@@ -91,11 +91,10 @@ class CONTENT_EXPORT DOMStorageContextImpl
// |localstorage_directory| and |sessionstorage_directory| may be empty
// for incognito browser contexts.
- DOMStorageContextImpl(
- const base::FilePath& localstorage_directory,
- const base::FilePath& sessionstorage_directory,
- quota::SpecialStoragePolicy* special_storage_policy,
- DOMStorageTaskRunner* task_runner);
+ DOMStorageContextImpl(const base::FilePath& localstorage_directory,
+ const base::FilePath& sessionstorage_directory,
+ storage::SpecialStoragePolicy* special_storage_policy,
+ DOMStorageTaskRunner* task_runner);
// Returns the directory path for localStorage, or an empty directory, if
// there is no backing on disk.
@@ -231,7 +230,7 @@ class CONTENT_EXPORT DOMStorageContextImpl
bool is_shutdown_;
bool force_keep_session_state_;
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
scoped_refptr<SessionStorageDatabase> session_storage_database_;
// For cleaning up unused namespaces gradually.
diff --git a/chromium/content/browser/dom_storage/dom_storage_context_impl_unittest.cc b/chromium/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
index d29741f62ea..f3744ab157b 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
@@ -40,7 +40,7 @@ class DOMStorageContextImplTest : public testing::Test {
const bool kDontIncludeFileInfo;
const bool kDoIncludeFileInfo;
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
storage_policy_ = new MockSpecialStoragePolicy;
task_runner_ =
@@ -51,9 +51,7 @@ class DOMStorageContextImplTest : public testing::Test {
task_runner_.get());
}
- virtual void TearDown() {
- base::MessageLoop::current()->RunUntilIdle();
- }
+ void TearDown() override { base::MessageLoop::current()->RunUntilIdle(); }
void VerifySingleOriginRemains(const GURL& origin) {
// Use a new instance to examine the contexts of temp_dir_.
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 47d5b05be9a..d483d9b57a7 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -64,7 +64,7 @@ void GetSessionStorageUsageHelper(
DOMStorageContextWrapper::DOMStorageContextWrapper(
const base::FilePath& data_path,
- quota::SpecialStoragePolicy* special_storage_policy) {
+ storage::SpecialStoragePolicy* special_storage_policy) {
base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
context_ = new DOMStorageContextImpl(
data_path.empty() ? data_path
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 0ed95076a20..efd50914890 100644
--- a/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/chromium/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -13,7 +13,7 @@ namespace base {
class FilePath;
}
-namespace quota {
+namespace storage {
class SpecialStoragePolicy;
}
@@ -28,21 +28,21 @@ class CONTENT_EXPORT DOMStorageContextWrapper :
public base::RefCountedThreadSafe<DOMStorageContextWrapper> {
public:
// If |data_path| is empty, nothing will be saved to disk.
- DOMStorageContextWrapper(const base::FilePath& data_path,
- quota::SpecialStoragePolicy* special_storage_policy);
+ DOMStorageContextWrapper(
+ const base::FilePath& data_path,
+ storage::SpecialStoragePolicy* special_storage_policy);
// DOMStorageContext implementation.
- virtual void GetLocalStorageUsage(
- const GetLocalStorageUsageCallback& callback) OVERRIDE;
- virtual void GetSessionStorageUsage(
- const GetSessionStorageUsageCallback& callback) OVERRIDE;
- virtual void DeleteLocalStorage(const GURL& origin) OVERRIDE;
- virtual void DeleteSessionStorage(
- const SessionStorageUsageInfo& usage_info) OVERRIDE;
- virtual void SetSaveSessionStorageOnDisk() OVERRIDE;
- virtual scoped_refptr<SessionStorageNamespace>
- RecreateSessionStorage(const std::string& persistent_id) OVERRIDE;
- virtual void StartScavengingUnusedSessionStorage() OVERRIDE;
+ void GetLocalStorageUsage(
+ const GetLocalStorageUsageCallback& callback) override;
+ void GetSessionStorageUsage(
+ const GetSessionStorageUsageCallback& callback) override;
+ void DeleteLocalStorage(const GURL& origin) override;
+ void DeleteSessionStorage(const SessionStorageUsageInfo& usage_info) override;
+ void SetSaveSessionStorageOnDisk() override;
+ scoped_refptr<SessionStorageNamespace> RecreateSessionStorage(
+ const std::string& persistent_id) override;
+ void StartScavengingUnusedSessionStorage() override;
// Used by content settings to alter the behavior around
// what data to keep and what data to discard at shutdown.
@@ -58,7 +58,7 @@ class CONTENT_EXPORT DOMStorageContextWrapper :
friend class SessionStorageNamespaceImpl; // ditto
friend class base::RefCountedThreadSafe<DOMStorageContextWrapper>;
- virtual ~DOMStorageContextWrapper();
+ ~DOMStorageContextWrapper() override;
DOMStorageContextImpl* context() const { return context_.get(); }
scoped_refptr<DOMStorageContextImpl> context_;
diff --git a/chromium/content/browser/dom_storage/dom_storage_database.cc b/chromium/content/browser/dom_storage/dom_storage_database.cc
index aaf6bb03447..1e0166f68f8 100644
--- a/chromium/content/browser/dom_storage/dom_storage_database.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_database.cc
@@ -5,7 +5,7 @@
#include "content/browser/dom_storage/dom_storage_database.h"
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "sql/statement.h"
#include "sql/transaction.h"
diff --git a/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc b/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc
index e20e399ec6c..20b714c039b 100644
--- a/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_database_unittest.cc
@@ -4,11 +4,12 @@
#include "content/browser/dom_storage/dom_storage_database.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/public/common/content_paths.h"
#include "sql/statement.h"
#include "sql/test/scoped_error_ignorer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -309,11 +310,9 @@ TEST(DOMStorageDatabaseTest, TestSimpleRemoveOneValue) {
}
TEST(DOMStorageDatabaseTest, TestCanOpenAndReadWebCoreDatabase) {
- base::FilePath webcore_database;
- PathService::Get(base::DIR_SOURCE_ROOT, &webcore_database);
- webcore_database = webcore_database.AppendASCII("webkit");
- webcore_database = webcore_database.AppendASCII("data");
- webcore_database = webcore_database.AppendASCII("dom_storage");
+ base::FilePath dir_test_data;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data));
+ base::FilePath webcore_database = dir_test_data.AppendASCII("dom_storage");
webcore_database =
webcore_database.AppendASCII("webcore_test_database.localstorage");
diff --git a/chromium/content/browser/dom_storage/dom_storage_message_filter.h b/chromium/content/browser/dom_storage/dom_storage_message_filter.h
index 346a8ff5654..d93acfd06f6 100644
--- a/chromium/content/browser/dom_storage/dom_storage_message_filter.h
+++ b/chromium/content/browser/dom_storage/dom_storage_message_filter.h
@@ -34,17 +34,17 @@ class DOMStorageMessageFilter
DOMStorageContextWrapper* context);
private:
- virtual ~DOMStorageMessageFilter();
+ ~DOMStorageMessageFilter() override;
void InitializeInSequence();
void UninitializeInSequence();
// BrowserMessageFilter implementation
- virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE;
- virtual void OnFilterRemoved() OVERRIDE;
- virtual base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& message) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnFilterAdded(IPC::Sender* sender) override;
+ void OnFilterRemoved() override;
+ base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// Message Handlers.
void OnOpenStorageArea(int connection_id, int64 namespace_id,
@@ -63,21 +63,18 @@ class DOMStorageMessageFilter
// DOMStorageContextImpl::EventObserver implementation which
// sends events back to our renderer process.
- virtual void OnDOMStorageItemSet(
- const DOMStorageArea* area,
- const base::string16& key,
- const base::string16& new_value,
- const base::NullableString16& old_value,
- const GURL& page_url) OVERRIDE;
- virtual void OnDOMStorageItemRemoved(
- const DOMStorageArea* area,
- const base::string16& key,
- const base::string16& old_value,
- const GURL& page_url) OVERRIDE;
- virtual void OnDOMStorageAreaCleared(
- const DOMStorageArea* area,
- const GURL& page_url) OVERRIDE;
- virtual void OnDOMSessionStorageReset(int64 namespace_id) OVERRIDE;
+ void OnDOMStorageItemSet(const DOMStorageArea* area,
+ const base::string16& key,
+ const base::string16& new_value,
+ const base::NullableString16& old_value,
+ const GURL& page_url) override;
+ void OnDOMStorageItemRemoved(const DOMStorageArea* area,
+ const base::string16& key,
+ const base::string16& old_value,
+ const GURL& page_url) override;
+ void OnDOMStorageAreaCleared(const DOMStorageArea* area,
+ const GURL& page_url) override;
+ void OnDOMSessionStorageReset(int64 namespace_id) override;
void SendDOMStorageEvent(
const DOMStorageArea* area,
diff --git a/chromium/content/browser/dom_storage/dom_storage_namespace.cc b/chromium/content/browser/dom_storage/dom_storage_namespace.cc
index d36147f076e..fb76b6764ed 100644
--- a/chromium/content/browser/dom_storage/dom_storage_namespace.cc
+++ b/chromium/content/browser/dom_storage/dom_storage_namespace.cc
@@ -63,7 +63,7 @@ DOMStorageNamespace::~DOMStorageNamespace() {
}
DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
- if (alias_master_namespace_)
+ if (alias_master_namespace_.get())
return alias_master_namespace_->OpenStorageArea(origin);
if (AreaHolder* holder = GetAreaHolder(origin)) {
++(holder->open_count_);
@@ -83,7 +83,7 @@ DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
AreaHolder* holder = GetAreaHolder(area->origin());
- if (alias_master_namespace_) {
+ if (alias_master_namespace_.get()) {
DCHECK(!holder);
if (old_master_for_close_area_)
old_master_for_close_area_->CloseStorageArea(area);
@@ -99,7 +99,7 @@ void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
}
DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
- if (alias_master_namespace_)
+ if (alias_master_namespace_.get())
return alias_master_namespace_->GetOpenStorageArea(origin);
AreaHolder* holder = GetAreaHolder(origin);
if (holder && holder->open_count_)
@@ -110,7 +110,7 @@ DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
DOMStorageNamespace* DOMStorageNamespace::Clone(
int64 clone_namespace_id,
const std::string& clone_persistent_namespace_id) {
- if (alias_master_namespace_) {
+ if (alias_master_namespace_.get()) {
return alias_master_namespace_->Clone(clone_namespace_id,
clone_persistent_namespace_id);
}
@@ -153,8 +153,8 @@ DOMStorageNamespace* DOMStorageNamespace::CreateAlias(
DOMStorageNamespace* alias = new DOMStorageNamespace(
alias_namespace_id, persistent_namespace_id_,
session_storage_database_.get(), task_runner_.get());
- if (alias_master_namespace_ != NULL) {
- DCHECK(alias_master_namespace_->alias_master_namespace_ == NULL);
+ if (alias_master_namespace_.get() != NULL) {
+ DCHECK(alias_master_namespace_->alias_master_namespace_.get() == NULL);
alias->alias_master_namespace_ = alias_master_namespace_;
} else {
alias->alias_master_namespace_ = this;
@@ -179,7 +179,7 @@ void DOMStorageNamespace::DeleteLocalStorageOrigin(const GURL& origin) {
}
void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) {
- if (alias_master_namespace_) {
+ if (alias_master_namespace_.get()) {
alias_master_namespace_->DeleteSessionStorageOrigin(origin);
return;
}
@@ -189,7 +189,7 @@ void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) {
}
void DOMStorageNamespace::PurgeMemory(PurgeOption option) {
- if (alias_master_namespace_) {
+ if (alias_master_namespace_.get()) {
alias_master_namespace_->PurgeMemory(option);
return;
}
@@ -228,7 +228,7 @@ void DOMStorageNamespace::Shutdown() {
}
unsigned int DOMStorageNamespace::CountInMemoryAreas() const {
- if (alias_master_namespace_)
+ if (alias_master_namespace_.get())
return alias_master_namespace_->CountInMemoryAreas();
unsigned int area_count = 0;
for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) {
@@ -375,7 +375,7 @@ void DOMStorageNamespace::AddTransaction(
}
bool DOMStorageNamespace::DecrementMasterAliasCount() {
- if (!alias_master_namespace_ || master_alias_count_decremented_)
+ if (!alias_master_namespace_.get() || master_alias_count_decremented_)
return false;
DCHECK_GT(alias_master_namespace_->num_aliases_, 0);
alias_master_namespace_->num_aliases_--;
@@ -391,8 +391,8 @@ void DOMStorageNamespace::SwitchToNewAliasMaster(
if (new_master->alias_master_namespace())
new_master = new_master->alias_master_namespace();
DCHECK(!new_master->alias_master_namespace());
- DCHECK(old_master != this);
- DCHECK(old_master != new_master);
+ DCHECK(old_master.get() != this);
+ DCHECK(old_master.get() != new_master);
DecrementMasterAliasCount();
alias_master_namespace_ = new_master;
alias_master_namespace_->num_aliases_++;
diff --git a/chromium/content/browser/dom_storage/dom_storage_task_runner.h b/chromium/content/browser/dom_storage/dom_storage_task_runner.h
index 1fb8a19e73b..a2000a08c14 100644
--- a/chromium/content/browser/dom_storage/dom_storage_task_runner.h
+++ b/chromium/content/browser/dom_storage/dom_storage_task_runner.h
@@ -49,7 +49,7 @@ class CONTENT_EXPORT DOMStorageTaskRunner
// The TaskRunner override returns true if the current thread is running
// on the primary sequence.
- virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+ bool RunsTasksOnCurrentThread() const override;
// Returns true if the current thread is running on the given |sequence_id|.
virtual bool IsRunningOnSequence(SequenceID sequence_id) const = 0;
@@ -61,7 +61,7 @@ class CONTENT_EXPORT DOMStorageTaskRunner
}
protected:
- virtual ~DOMStorageTaskRunner() {}
+ ~DOMStorageTaskRunner() override {}
};
// A derived class used in chromium that utilizes a SequenceWorkerPool
@@ -76,20 +76,18 @@ class CONTENT_EXPORT DOMStorageWorkerPoolTaskRunner :
base::SequencedWorkerPool::SequenceToken commit_sequence_token,
base::MessageLoopProxy* delayed_task_loop);
- virtual bool PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) OVERRIDE;
+ bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override;
- virtual bool PostShutdownBlockingTask(
- const tracked_objects::Location& from_here,
- SequenceID sequence_id,
- const base::Closure& task) OVERRIDE;
+ bool PostShutdownBlockingTask(const tracked_objects::Location& from_here,
+ SequenceID sequence_id,
+ const base::Closure& task) override;
- virtual bool IsRunningOnSequence(SequenceID sequence_id) const OVERRIDE;
+ bool IsRunningOnSequence(SequenceID sequence_id) const override;
protected:
- virtual ~DOMStorageWorkerPoolTaskRunner();
+ ~DOMStorageWorkerPoolTaskRunner() override;
private:
@@ -111,20 +109,18 @@ class CONTENT_EXPORT MockDOMStorageTaskRunner :
public:
explicit MockDOMStorageTaskRunner(base::MessageLoopProxy* message_loop);
- virtual bool PostDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) OVERRIDE;
+ bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override;
- virtual bool PostShutdownBlockingTask(
- const tracked_objects::Location& from_here,
- SequenceID sequence_id,
- const base::Closure& task) OVERRIDE;
+ bool PostShutdownBlockingTask(const tracked_objects::Location& from_here,
+ SequenceID sequence_id,
+ const base::Closure& task) override;
- virtual bool IsRunningOnSequence(SequenceID sequence_id) const OVERRIDE;
+ bool IsRunningOnSequence(SequenceID sequence_id) const override;
protected:
- virtual ~MockDOMStorageTaskRunner();
+ ~MockDOMStorageTaskRunner() override;
private:
const scoped_refptr<base::MessageLoopProxy> message_loop_;
diff --git a/chromium/content/browser/dom_storage/local_storage_database_adapter.cc b/chromium/content/browser/dom_storage/local_storage_database_adapter.cc
index f5d87e31c19..0be1cc0927c 100644
--- a/chromium/content/browser/dom_storage/local_storage_database_adapter.cc
+++ b/chromium/content/browser/dom_storage/local_storage_database_adapter.cc
@@ -4,7 +4,7 @@
#include "content/browser/dom_storage/local_storage_database_adapter.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "content/browser/dom_storage/dom_storage_database.h"
namespace content {
diff --git a/chromium/content/browser/dom_storage/local_storage_database_adapter.h b/chromium/content/browser/dom_storage/local_storage_database_adapter.h
index 1298d9c3e30..fca55d0c4e0 100644
--- a/chromium/content/browser/dom_storage/local_storage_database_adapter.h
+++ b/chromium/content/browser/dom_storage/local_storage_database_adapter.h
@@ -22,12 +22,12 @@ class CONTENT_EXPORT LocalStorageDatabaseAdapter :
public DOMStorageDatabaseAdapter {
public:
explicit LocalStorageDatabaseAdapter(const base::FilePath& path);
- virtual ~LocalStorageDatabaseAdapter();
- virtual void ReadAllValues(DOMStorageValuesMap* result) OVERRIDE;
- virtual bool CommitChanges(bool clear_all_first,
- const DOMStorageValuesMap& changes) OVERRIDE;
- virtual void DeleteFiles() OVERRIDE;
- virtual void Reset() OVERRIDE;
+ ~LocalStorageDatabaseAdapter() override;
+ void ReadAllValues(DOMStorageValuesMap* result) override;
+ bool CommitChanges(bool clear_all_first,
+ const DOMStorageValuesMap& changes) override;
+ void DeleteFiles() override;
+ void Reset() override;
protected:
// Constructor that uses an in-memory sqlite database, for testing.
diff --git a/chromium/content/browser/dom_storage/session_storage_database.cc b/chromium/content/browser/dom_storage/session_storage_database.cc
index 30d3d86577e..6e47a1fdf1c 100644
--- a/chromium/content/browser/dom_storage/session_storage_database.cc
+++ b/chromium/content/browser/dom_storage/session_storage_database.cc
@@ -4,7 +4,7 @@
#include "content/browser/dom_storage/session_storage_database.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
diff --git a/chromium/content/browser/dom_storage/session_storage_database_adapter.h b/chromium/content/browser/dom_storage/session_storage_database_adapter.h
index 9db5f173341..1b5a91dd7da 100644
--- a/chromium/content/browser/dom_storage/session_storage_database_adapter.h
+++ b/chromium/content/browser/dom_storage/session_storage_database_adapter.h
@@ -18,10 +18,11 @@ class SessionStorageDatabaseAdapter : public DOMStorageDatabaseAdapter {
SessionStorageDatabaseAdapter(SessionStorageDatabase* db,
const std::string& permanent_namespace_id,
const GURL& origin);
- virtual ~SessionStorageDatabaseAdapter();
- virtual void ReadAllValues(DOMStorageValuesMap* result) OVERRIDE;
- virtual bool CommitChanges(bool clear_all_first,
- const DOMStorageValuesMap& changes) OVERRIDE;
+ ~SessionStorageDatabaseAdapter() override;
+ void ReadAllValues(DOMStorageValuesMap* result) override;
+ bool CommitChanges(bool clear_all_first,
+ const DOMStorageValuesMap& changes) override;
+
private:
scoped_refptr<SessionStorageDatabase> db_;
std::string permanent_namespace_id_;
diff --git a/chromium/content/browser/dom_storage/session_storage_database_unittest.cc b/chromium/content/browser/dom_storage/session_storage_database_unittest.cc
index 71c8063ef44..f8397ace3ea 100644
--- a/chromium/content/browser/dom_storage/session_storage_database_unittest.cc
+++ b/chromium/content/browser/dom_storage/session_storage_database_unittest.cc
@@ -9,7 +9,7 @@
#include <map>
#include <string>
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
@@ -26,8 +26,8 @@ namespace content {
class SessionStorageDatabaseTest : public testing::Test {
public:
SessionStorageDatabaseTest();
- virtual ~SessionStorageDatabaseTest();
- virtual void SetUp() OVERRIDE;
+ ~SessionStorageDatabaseTest() override;
+ void SetUp() override;
protected:
typedef std::map<std::string, std::string> DataMap;
diff --git a/chromium/content/browser/dom_storage/session_storage_namespace_impl.cc b/chromium/content/browser/dom_storage/session_storage_namespace_impl.cc
index dab20332d53..ee861b2fbf0 100644
--- a/chromium/content/browser/dom_storage/session_storage_namespace_impl.cc
+++ b/chromium/content/browser/dom_storage/session_storage_namespace_impl.cc
@@ -28,7 +28,7 @@ SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
SessionStorageNamespaceImpl* master_session_storage_namespace)
: session_(new DOMStorageSession(
- master_session_storage_namespace->session_)) {
+ master_session_storage_namespace->session_.get())) {
}
@@ -81,7 +81,8 @@ void SessionStorageNamespaceImpl::Merge(
const MergeResultCallback& callback) {
SessionStorageNamespaceImpl* other_impl =
static_cast<SessionStorageNamespaceImpl*>(other);
- session_->Merge(actually_merge, process_id, other_impl->session_, callback);
+ session_->Merge(
+ actually_merge, process_id, other_impl->session_.get(), callback);
}
bool SessionStorageNamespaceImpl::IsAliasOf(SessionStorageNamespace* other) {
diff --git a/chromium/content/browser/dom_storage/session_storage_namespace_impl.h b/chromium/content/browser/dom_storage/session_storage_namespace_impl.h
index ad010857243..025ee8729da 100644
--- a/chromium/content/browser/dom_storage/session_storage_namespace_impl.h
+++ b/chromium/content/browser/dom_storage/session_storage_namespace_impl.h
@@ -40,26 +40,26 @@ class SessionStorageNamespaceImpl
SessionStorageNamespaceImpl* master_session_storage_namespace);
// SessionStorageNamespace implementation.
- virtual int64 id() const OVERRIDE;
- virtual const std::string& persistent_id() const OVERRIDE;
- virtual void SetShouldPersist(bool should_persist) OVERRIDE;
- virtual bool should_persist() const OVERRIDE;
+ int64 id() const override;
+ const std::string& persistent_id() const override;
+ void SetShouldPersist(bool should_persist) override;
+ bool should_persist() const override;
SessionStorageNamespaceImpl* Clone();
bool IsFromContext(DOMStorageContextWrapper* context);
- virtual void AddTransactionLogProcessId(int process_id) OVERRIDE;
- virtual void RemoveTransactionLogProcessId(int process_id) OVERRIDE;
- virtual void Merge(bool actually_merge,
- int process_id,
- SessionStorageNamespace* other,
- const MergeResultCallback& callback) OVERRIDE;
- virtual bool IsAliasOf(SessionStorageNamespace* other) OVERRIDE;
- virtual SessionStorageNamespace* CreateAlias() OVERRIDE;
+ void AddTransactionLogProcessId(int process_id) override;
+ void RemoveTransactionLogProcessId(int process_id) override;
+ void Merge(bool actually_merge,
+ int process_id,
+ SessionStorageNamespace* other,
+ const MergeResultCallback& callback) override;
+ bool IsAliasOf(SessionStorageNamespace* other) override;
+ SessionStorageNamespace* CreateAlias() override;
private:
explicit SessionStorageNamespaceImpl(DOMStorageSession* clone);
- virtual ~SessionStorageNamespaceImpl();
+ ~SessionStorageNamespaceImpl() override;
scoped_refptr<DOMStorageSession> session_;
diff --git a/chromium/content/browser/download/base_file.cc b/chromium/content/browser/download/base_file.cc
index 362f64ea1e0..5bca7831a44 100644
--- a/chromium/content/browser/download/base_file.cc
+++ b/chromium/content/browser/download/base_file.cc
@@ -5,8 +5,8 @@
#include "content/browser/download/base_file.h"
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/pickle.h"
@@ -159,15 +159,18 @@ DownloadInterruptReason BaseFile::Rename(const base::FilePath& new_path) {
// permissions / security descriptors that makes sense in the new directory.
rename_result = MoveFileAndAdjustPermissions(new_path);
- if (rename_result == DOWNLOAD_INTERRUPT_REASON_NONE) {
+ if (rename_result == DOWNLOAD_INTERRUPT_REASON_NONE)
full_path_ = new_path;
- // Re-open the file if we were still using it.
- if (was_in_progress)
- rename_result = Open();
- }
+
+ // Re-open the file if we were still using it regardless of the interrupt
+ // reason.
+ DownloadInterruptReason open_result = DOWNLOAD_INTERRUPT_REASON_NONE;
+ if (was_in_progress)
+ open_result = Open();
bound_net_log_.EndEvent(net::NetLog::TYPE_DOWNLOAD_FILE_RENAMED);
- return rename_result;
+ return rename_result == DOWNLOAD_INTERRUPT_REASON_NONE ? open_result
+ : rename_result;
}
void BaseFile::Detach() {
@@ -326,11 +329,10 @@ DownloadInterruptReason BaseFile::LogSystemError(
const char* operation,
logging::SystemErrorCode os_error) {
// There's no direct conversion from a system error to an interrupt reason.
- net::Error net_error = net::MapSystemError(os_error);
+ base::File::Error file_error = base::File::OSErrorToFileError(os_error);
return LogInterruptReason(
operation, os_error,
- ConvertNetErrorToInterruptReason(
- net_error, DOWNLOAD_INTERRUPT_FROM_DISK));
+ ConvertFileErrorToInterruptReason(file_error));
}
DownloadInterruptReason BaseFile::LogInterruptReason(
diff --git a/chromium/content/browser/download/base_file.h b/chromium/content/browser/download/base_file.h
index a14c5daef31..037aecca3b5 100644
--- a/chromium/content/browser/download/base_file.h
+++ b/chromium/content/browser/download/base_file.h
@@ -56,7 +56,10 @@ class CONTENT_EXPORT BaseFile {
DownloadInterruptReason AppendDataToFile(const char* data, size_t data_len);
// Rename the download file. Returns a DownloadInterruptReason indicating the
- // result of the operation.
+ // 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.
@@ -79,8 +82,15 @@ class CONTENT_EXPORT BaseFile {
// Windows to ensure the correct app client ID is available.
DownloadInterruptReason AnnotateWithSourceInformation();
- base::FilePath full_path() const { return full_path_; }
+ // Returns the last known path to the download file. Can be empty if there's
+ // no file.
+ const base::FilePath& full_path() const { return full_path_; }
+
+ // Returns true if the file is open. If true, the file can be written to or
+ // renamed.
bool in_progress() const { return file_.IsValid(); }
+
+ // Returns the number of bytes in the file pointed to by full_path().
int64 bytes_so_far() const { return bytes_so_far_; }
// Fills |hash| with the hash digest for the file.
diff --git a/chromium/content/browser/download/base_file_posix.cc b/chromium/content/browser/download/base_file_posix.cc
index 4cf987c8b20..b5d8e014422 100644
--- a/chromium/content/browser/download/base_file_posix.cc
+++ b/chromium/content/browser/download/base_file_posix.cc
@@ -4,7 +4,7 @@
#include "content/browser/download/base_file.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "content/public/browser/download_interrupt_reasons.h"
namespace content {
@@ -27,8 +27,6 @@ DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions(
if (!stat_succeeded)
LogSystemError("stat", errno);
- // TODO(estade): Move() falls back to copying and deleting when a simple
- // rename fails. Copying sucks for large downloads. crbug.com/8737
if (!base::Move(full_path_, new_path))
return LogSystemError("Move", errno);
diff --git a/chromium/content/browser/download/base_file_unittest.cc b/chromium/content/browser/download/base_file_unittest.cc
index 8b45ce9ca0f..7e27ffe0969 100644
--- a/chromium/content/browser/download/base_file_unittest.cc
+++ b/chromium/content/browser/download/base_file_unittest.cc
@@ -4,8 +4,8 @@
#include "content/browser/download/base_file.h"
-#include "base/file_util.h"
#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
@@ -45,7 +45,7 @@ class BaseFileTest : public testing::Test {
file_thread_(BrowserThread::FILE, &message_loop_) {
}
- virtual void SetUp() {
+ void SetUp() override {
ResetHash();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base_file_.reset(new BaseFile(base::FilePath(),
@@ -58,7 +58,7 @@ class BaseFileTest : public testing::Test {
net::BoundNetLog()));
}
- virtual void TearDown() {
+ void TearDown() override {
EXPECT_FALSE(base_file_->in_progress());
if (!expected_error_) {
EXPECT_EQ(static_cast<int64>(expected_data_.size()),
@@ -195,6 +195,12 @@ class BaseFileTest : public testing::Test {
expected_error_ = err;
}
+ void ExpectPermissionError(DownloadInterruptReason err) {
+ EXPECT_TRUE(err == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR ||
+ err == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED)
+ << "Interrupt reason = " << err;
+ }
+
protected:
// BaseClass instance we are testing.
scoped_ptr<BaseFile> base_file_;
@@ -467,15 +473,63 @@ TEST_F(BaseFileTest, RenameWithError) {
EXPECT_FALSE(base::PathExists(new_path));
{
- file_util::PermissionRestorer restore_permissions_for(test_dir);
- ASSERT_TRUE(file_util::MakeFileUnwritable(test_dir));
- EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
- base_file_->Rename(new_path));
+ base::FilePermissionRestorer restore_permissions_for(test_dir);
+ ASSERT_TRUE(base::MakeFileUnwritable(test_dir));
+ ExpectPermissionError(base_file_->Rename(new_path));
}
base_file_->Finish();
}
+// Test that if a rename fails for an in-progress BaseFile, it remains writeable
+// and renameable.
+TEST_F(BaseFileTest, RenameWithErrorInProgress) {
+ ASSERT_TRUE(InitializeFile());
+
+ base::FilePath test_dir(temp_dir_.path().AppendASCII("TestDir"));
+ ASSERT_TRUE(base::CreateDirectory(test_dir));
+
+ base::FilePath new_path(test_dir.AppendASCII("TestFile"));
+ EXPECT_FALSE(base::PathExists(new_path));
+
+ // Write some data to start with.
+ ASSERT_TRUE(AppendDataToFile(kTestData1));
+ ASSERT_TRUE(base_file_->in_progress());
+
+ base::FilePath old_path = base_file_->full_path();
+
+ {
+ base::FilePermissionRestorer restore_permissions_for(test_dir);
+ ASSERT_TRUE(base::MakeFileUnwritable(test_dir));
+ ExpectPermissionError(base_file_->Rename(new_path));
+
+ // The file should still be open and we should be able to continue writing
+ // to it.
+ ASSERT_TRUE(base_file_->in_progress());
+ ASSERT_TRUE(AppendDataToFile(kTestData2));
+ ASSERT_EQ(old_path.value(), base_file_->full_path().value());
+
+ // Try to rename again, just for kicks. It should still fail.
+ ExpectPermissionError(base_file_->Rename(new_path));
+ }
+
+ // Now that TestDir is writeable again, we should be able to successfully
+ // rename the file.
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, base_file_->Rename(new_path));
+ 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);
+}
+
// Test that a failed write reports an error.
TEST_F(BaseFileTest, WriteWithError) {
base::FilePath path;
@@ -558,10 +612,10 @@ TEST_F(BaseFileTest, ReadonlyBaseFile) {
base::FilePath readonly_file_name = CreateTestFile();
// Restore permissions to the file when we are done with this test.
- file_util::PermissionRestorer restore_permissions(readonly_file_name);
+ base::FilePermissionRestorer restore_permissions(readonly_file_name);
// Make it read-only.
- EXPECT_TRUE(file_util::MakeFileUnwritable(readonly_file_name));
+ EXPECT_TRUE(base::MakeFileUnwritable(readonly_file_name));
// Try to overwrite it.
base_file_.reset(new BaseFile(readonly_file_name,
diff --git a/chromium/content/browser/download/base_file_win.cc b/chromium/content/browser/download/base_file_win.cc
index 252f0495d7d..fec1454d57b 100644
--- a/chromium/content/browser/download/base_file_win.cc
+++ b/chromium/content/browser/download/base_file_win.cc
@@ -9,7 +9,8 @@
#include <objbase.h>
#include <shellapi.h>
-#include "base/file_util.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/guid.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
@@ -25,6 +26,8 @@ namespace {
const int kAllSpecialShFileOperationCodes[] = {
// Should be kept in sync with the case statement below.
ERROR_ACCESS_DENIED,
+ ERROR_SHARING_VIOLATION,
+ ERROR_INVALID_PARAMETER,
0x71,
0x72,
0x73,
@@ -68,11 +71,28 @@ DownloadInterruptReason MapShFileOperationCodes(int code) {
// This switch statement should be kept in sync with the list of codes
// above.
switch (code) {
- // Not a pre-Win32 error code; here so that this particular
- // case shows up in our histograms. This is redundant with the
- // mapping function net::MapSystemError used later.
+ // Not a pre-Win32 error code; here so that this particular case shows up in
+ // our histograms. Unfortunately, it is used not just to signal actual
+ // ACCESS_DENIED errors, but many other errors as well. So we treat it as a
+ // transient error.
case ERROR_ACCESS_DENIED: // Access is denied.
- result = DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED;
+ result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
+ break;
+
+ // This isn't documented but returned from SHFileOperation. Sharing
+ // violations indicate that another process had the file open while we were
+ // trying to rename. Anti-virus is believed to be the cause of this error in
+ // the wild. Treated as a transient error on the assumption that the file
+ // will be made available for renaming at a later time.
+ case ERROR_SHARING_VIOLATION:
+ result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
+ break;
+
+ // This is also not a documented return value of SHFileOperation, but has
+ // been observed in the wild. We are treating it as a transient error based
+ // on the cases we have seen so far. See http://crbug.com/368455.
+ case ERROR_INVALID_PARAMETER:
+ result = DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
break;
// The source and destination files are the same file.
@@ -250,12 +270,20 @@ DownloadInterruptReason MapShFileOperationCodes(int code) {
arraysize(kAllSpecialShFileOperationCodes)));
}
+ if (result == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR) {
+ UMA_HISTOGRAM_CUSTOM_ENUMERATION(
+ "Download.MapWinShErrorTransientError", code,
+ base::CustomHistogram::ArrayToCustomRanges(
+ kAllSpecialShFileOperationCodes,
+ arraysize(kAllSpecialShFileOperationCodes)));
+ }
+
if (result != DOWNLOAD_INTERRUPT_REASON_NONE)
return result;
// If not one of the above codes, it should be a standard Windows error code.
- return ConvertNetErrorToInterruptReason(
- net::MapSystemError(code), DOWNLOAD_INTERRUPT_FROM_DISK);
+ return ConvertFileErrorToInterruptReason(
+ base::File::OSErrorToFileError(code));
}
// Maps a return code from ScanAndSaveDownloadedFile() to a
@@ -310,6 +338,7 @@ DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions(
move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI |
FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS;
+ base::TimeTicks now = base::TimeTicks::Now();
int result = SHFileOperation(&move_info);
DownloadInterruptReason interrupt_reason = DOWNLOAD_INTERRUPT_REASON_NONE;
diff --git a/chromium/content/browser/download/download_browsertest.cc b/chromium/content/browser/download/download_browsertest.cc
index 8f35b63e576..a011fc90015 100644
--- a/chromium/content/browser/download/download_browsertest.cc
+++ b/chromium/content/browser/download/download_browsertest.cc
@@ -6,9 +6,10 @@
// in a pure content context. Over time tests should be migrated here.
#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ref_counted.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/platform_thread.h"
@@ -19,7 +20,6 @@
#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/plugin_service_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/power_save_blocker.h"
#include "content/public/common/content_switches.h"
@@ -34,16 +34,20 @@
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_download_manager_delegate.h"
#include "content/shell/browser/shell_network_delegate.h"
-#include "content/test/net/url_request_mock_http_job.h"
#include "content/test/net/url_request_slow_download_job.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"
#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/url_request/url_request_mock_http_job.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+#if defined(ENABLE_PLUGINS)
+#include "content/browser/plugin_service_impl.h"
+#endif
+
using ::net::test_server::EmbeddedTestServer;
using ::testing::AllOf;
using ::testing::Field;
@@ -118,17 +122,15 @@ class DownloadFileWithDelay : public DownloadFileImpl {
base::WeakPtr<DownloadDestinationObserver> observer,
base::WeakPtr<DownloadFileWithDelayFactory> owner);
- virtual ~DownloadFileWithDelay();
+ ~DownloadFileWithDelay() override;
// Wraps DownloadFileImpl::Rename* and intercepts the return callback,
// storing it in the factory that produced this object for later
// retrieval.
- virtual void RenameAndUniquify(
- const base::FilePath& full_path,
- const RenameCompletionCallback& callback) OVERRIDE;
- virtual void RenameAndAnnotate(
- const base::FilePath& full_path,
- const RenameCompletionCallback& callback) OVERRIDE;
+ void RenameAndUniquify(const base::FilePath& full_path,
+ const RenameCompletionCallback& callback) override;
+ void RenameAndAnnotate(const base::FilePath& full_path,
+ const RenameCompletionCallback& callback) override;
private:
static void RenameCallbackWrapper(
@@ -151,10 +153,10 @@ class DownloadFileWithDelay : public DownloadFileImpl {
class DownloadFileWithDelayFactory : public DownloadFileFactory {
public:
DownloadFileWithDelayFactory();
- virtual ~DownloadFileWithDelayFactory();
+ ~DownloadFileWithDelayFactory() override;
// DownloadFileFactory interface.
- virtual DownloadFile* CreateFile(
+ DownloadFile* CreateFile(
scoped_ptr<DownloadSaveInfo> save_info,
const base::FilePath& default_download_directory,
const GURL& url,
@@ -162,7 +164,7 @@ class DownloadFileWithDelayFactory : public DownloadFileFactory {
bool calculate_hash,
scoped_ptr<ByteStreamReader> stream,
const net::BoundNetLog& bound_net_log,
- base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE;
+ base::WeakPtr<DownloadDestinationObserver> observer) override;
void AddRenameCallback(base::Closure callback);
void GetAllRenameCallbacks(std::vector<base::Closure>* results);
@@ -288,12 +290,12 @@ class CountingDownloadFile : public DownloadFileImpl {
url, referrer_url, calculate_hash,
stream.Pass(), bound_net_log, observer) {}
- virtual ~CountingDownloadFile() {
+ ~CountingDownloadFile() override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
active_files_--;
}
- virtual void Initialize(const InitializeCallback& callback) OVERRIDE {
+ void Initialize(const InitializeCallback& callback) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
active_files_++;
return DownloadFileImpl::Initialize(callback);
@@ -327,18 +329,18 @@ int CountingDownloadFile::active_files_ = 0;
class CountingDownloadFileFactory : public DownloadFileFactory {
public:
CountingDownloadFileFactory() {}
- virtual ~CountingDownloadFileFactory() {}
+ ~CountingDownloadFileFactory() override {}
// DownloadFileFactory interface.
- 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,
- const net::BoundNetLog& bound_net_log,
- base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE {
+ 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,
@@ -354,11 +356,11 @@ class TestShellDownloadManagerDelegate : public ShellDownloadManagerDelegate {
public:
TestShellDownloadManagerDelegate()
: delay_download_open_(false) {}
- virtual ~TestShellDownloadManagerDelegate() {}
+ ~TestShellDownloadManagerDelegate() override {}
- virtual bool ShouldOpenDownload(
+ bool ShouldOpenDownload(
DownloadItem* item,
- const DownloadOpenDelayedCallback& callback) OVERRIDE {
+ const DownloadOpenDelayedCallback& callback) override {
if (delay_download_open_) {
delayed_callbacks_.push_back(callback);
return false;
@@ -396,9 +398,7 @@ class RecordingDownloadObserver : DownloadItem::Observer {
download_->AddObserver(this);
}
- virtual ~RecordingDownloadObserver() {
- RemoveObserver();
- }
+ ~RecordingDownloadObserver() override { RemoveObserver(); }
void CompareToExpectedRecord(const RecordStruct expected[], size_t size) {
EXPECT_EQ(size, record_.size());
@@ -411,7 +411,7 @@ class RecordingDownloadObserver : DownloadItem::Observer {
}
private:
- virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE {
+ void OnDownloadUpdated(DownloadItem* download) override {
DCHECK_EQ(download_, download);
DownloadItem::DownloadState state = download->GetState();
int bytes = download->GetReceivedBytes();
@@ -422,7 +422,7 @@ class RecordingDownloadObserver : DownloadItem::Observer {
}
}
- virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE {
+ void OnDownloadDestroyed(DownloadItem* download) override {
DCHECK_EQ(download_, download);
RemoveObserver();
}
@@ -449,20 +449,20 @@ class DownloadCreateObserver : DownloadManager::Observer {
manager_->AddObserver(this);
}
- virtual ~DownloadCreateObserver() {
+ ~DownloadCreateObserver() override {
if (manager_)
manager_->RemoveObserver(this);
manager_ = NULL;
}
- virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE {
+ void ManagerGoingDown(DownloadManager* manager) override {
DCHECK_EQ(manager_, manager);
manager_->RemoveObserver(this);
manager_ = NULL;
}
- virtual void OnDownloadCreated(DownloadManager* manager,
- DownloadItem* download) OVERRIDE {
+ void OnDownloadCreated(DownloadManager* manager,
+ DownloadItem* download) override {
if (!item_)
item_ = download;
@@ -518,7 +518,7 @@ scoped_ptr<net::test_server::HttpResponse> HandleRequestAndSendRedirectResponse(
response->set_code(net::HTTP_FOUND);
response->AddCustomHeader("Location", target_url.spec());
}
- return response.PassAs<net::test_server::HttpResponse>();
+ return response.Pass();
}
// Creates a request handler for EmbeddedTestServer that responds with a HTTP
@@ -542,7 +542,7 @@ scoped_ptr<net::test_server::HttpResponse> HandleRequestAndSendBasicResponse(
response->set_content_type(content_type);
response->set_content(body);
}
- return response.PassAs<net::test_server::HttpResponse>();
+ return response.Pass();
}
// Creates a request handler for an EmbeddedTestServer that response with an
@@ -570,7 +570,7 @@ class DownloadContentTest : public ContentBrowserTest {
ByteStreamWriter::kFractionBufferBeforeSending) + 1;
}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
test_delegate_.reset(new TestShellDownloadManagerDelegate());
@@ -585,8 +585,12 @@ class DownloadContentTest : public ContentBrowserTest {
base::Bind(&URLRequestSlowDownloadJob::AddUrlHandler));
base::FilePath mock_base(GetTestFilePath("download", ""));
BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&URLRequestMockHTTPJob::AddUrlHandler, mock_base));
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &net::URLRequestMockHTTPJob::AddUrlHandler,
+ mock_base,
+ make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
}
TestShellDownloadManagerDelegate* GetDownloadManagerDelegate() {
@@ -798,7 +802,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, MultiDownload) {
// Start the second download and wait until it's done.
base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
- GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
// Download the file and wait.
NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
@@ -853,7 +857,8 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadOctetStream) {
PluginServiceImpl::GetInstance()->RegisterInternalPlugin(plugin_info, false);
// The following is served with a Content-Type of application/octet-stream.
- GURL url(URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kTestFilePath)));
+ GURL url(
+ net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(kTestFilePath)));
NavigateToURLAndWaitForDownload(shell(), url, DownloadItem::COMPLETE);
}
#endif
@@ -870,7 +875,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtFinalRename) {
// Create a download
base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
- NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file));
+ NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
// Wait until the first (intermediate file) rename and execute the callback.
file_factory->WaitForSomeCallback();
@@ -919,7 +924,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtRelease) {
// Create a download
base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
- NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file));
+ NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
// Wait until the first (intermediate file) rename and execute the callback.
file_factory->WaitForSomeCallback();
@@ -1029,7 +1034,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownAtRelease) {
// Create a download
base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
- NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file));
+ NavigateToURL(shell(), net::URLRequestMockHTTPJob::GetMockUrl(file));
// Wait until the first (intermediate file) rename and execute the callback.
file_factory->WaitForSomeCallback();
@@ -1070,7 +1075,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownAtRelease) {
}
IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownload) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
@@ -1137,7 +1142,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownload) {
// Confirm restart fallback happens if a range request is bounced.
IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownloadNoRange) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
@@ -1186,7 +1191,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownloadNoRange) {
// Confirm restart fallback happens if a precondition is failed.
IN_PROC_BROWSER_TEST_F(DownloadContentTest,
ResumeInterruptedDownloadBadPrecondition) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
@@ -1238,7 +1243,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
// Confirm we don't try to resume if we don't have a verifier.
IN_PROC_BROWSER_TEST_F(DownloadContentTest,
ResumeInterruptedDownloadNoVerifiers) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
@@ -1282,7 +1287,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
}
IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithDeletedFile) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
@@ -1333,10 +1338,10 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithDeletedFile) {
}
IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileInitError) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
- GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
// Setup the error injector.
scoped_refptr<TestFileErrorInjector> injector(
@@ -1384,10 +1389,10 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileInitError) {
IN_PROC_BROWSER_TEST_F(DownloadContentTest,
ResumeWithFileIntermediateRenameError) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
- GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
// Setup the error injector.
scoped_refptr<TestFileErrorInjector> injector(
@@ -1436,10 +1441,10 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
}
IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileFinalRenameError) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
- GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(file));
// Setup the error injector.
scoped_refptr<TestFileErrorInjector> injector(
@@ -1489,7 +1494,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileFinalRenameError) {
// An interrupted download should remove the intermediate file when it is
// cancelled.
IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelInterruptedDownload) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
@@ -1519,7 +1524,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelInterruptedDownload) {
}
IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveDownload) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
@@ -1554,7 +1559,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveDownload) {
{
// Start the second download and wait until it's done.
base::FilePath file2(FILE_PATH_LITERAL("download-test.lib"));
- GURL url2(URLRequestMockHTTPJob::GetMockUrl(file2));
+ GURL url2(net::URLRequestMockHTTPJob::GetMockUrl(file2));
scoped_ptr<DownloadTestObserver> completion_observer(
CreateWaiter(shell(), 1));
DownloadItem* download(StartDownloadAndReturnItem(url2));
@@ -1574,7 +1579,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveDownload) {
IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumingDownload) {
SetupEnsureNoPendingDownloads();
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
@@ -1621,7 +1626,7 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumingDownload) {
IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelResumingDownload) {
SetupEnsureNoPendingDownloads();
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
ASSERT_TRUE(test_server()->Start());
diff --git a/chromium/content/browser/download/download_create_info.cc b/chromium/content/browser/download/download_create_info.cc
index e381fa854bd..05b0992a26d 100644
--- a/chromium/content/browser/download/download_create_info.cc
+++ b/chromium/content/browser/download/download_create_info.cc
@@ -15,7 +15,7 @@ DownloadCreateInfo::DownloadCreateInfo(const base::Time& start_time,
int64 total_bytes,
const net::BoundNetLog& bound_net_log,
bool has_user_gesture,
- PageTransition transition_type,
+ ui::PageTransition transition_type,
scoped_ptr<DownloadSaveInfo> save_info)
: start_time(start_time),
total_bytes(total_bytes),
@@ -29,7 +29,7 @@ DownloadCreateInfo::DownloadCreateInfo()
: total_bytes(0),
download_id(DownloadItem::kInvalidId),
has_user_gesture(false),
- transition_type(PAGE_TRANSITION_LINK),
+ transition_type(ui::PAGE_TRANSITION_LINK),
save_info(new DownloadSaveInfo()) {
}
diff --git a/chromium/content/browser/download/download_create_info.h b/chromium/content/browser/download/download_create_info.h
index e8e1443b93a..cbf87119aa2 100644
--- a/chromium/content/browser/download/download_create_info.h
+++ b/chromium/content/browser/download/download_create_info.h
@@ -15,8 +15,8 @@
#include "content/browser/download/download_request_handle.h"
#include "content/common/content_export.h"
#include "content/public/browser/download_save_info.h"
-#include "content/public/common/page_transition_types.h"
#include "net/base/net_log.h"
+#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
namespace content {
@@ -28,7 +28,7 @@ struct CONTENT_EXPORT DownloadCreateInfo {
int64 total_bytes,
const net::BoundNetLog& bound_net_log,
bool has_user_gesture,
- PageTransition transition_type,
+ ui::PageTransition transition_type,
scoped_ptr<DownloadSaveInfo> save_info);
DownloadCreateInfo();
~DownloadCreateInfo();
@@ -63,7 +63,7 @@ struct CONTENT_EXPORT DownloadCreateInfo {
// True if the download was initiated by user action.
bool has_user_gesture;
- PageTransition transition_type;
+ ui::PageTransition transition_type;
// The content-disposition string from the response header.
std::string content_disposition;
diff --git a/chromium/content/browser/download/download_file_impl.cc b/chromium/content/browser/download/download_file_impl.cc
index 11e98cb726b..91b25dac35b 100644
--- a/chromium/content/browser/download/download_file_impl.cc
+++ b/chromium/content/browser/download/download_file_impl.cc
@@ -7,7 +7,7 @@
#include <string>
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
@@ -25,6 +25,12 @@ namespace content {
const int kUpdatePeriodMs = 500;
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;
DownloadFileImpl::DownloadFileImpl(
@@ -36,20 +42,20 @@ DownloadFileImpl::DownloadFileImpl(
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,
- save_info->file.Pass(),
- bound_net_log),
- default_download_directory_(default_download_directory),
- stream_reader_(stream.Pass()),
- bytes_seen_(0),
- bound_net_log_(bound_net_log),
- observer_(observer),
- weak_factory_(this) {
+ : file_(save_info->file_path,
+ url,
+ referrer_url,
+ save_info->offset,
+ calculate_hash,
+ save_info->hash_state,
+ save_info->file.Pass(),
+ bound_net_log),
+ default_download_directory_(default_download_directory),
+ stream_reader_(stream.Pass()),
+ bytes_seen_(0),
+ bound_net_log_(bound_net_log),
+ observer_(observer),
+ weak_factory_(this) {
}
DownloadFileImpl::~DownloadFileImpl() {
@@ -103,47 +109,84 @@ DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
void DownloadFileImpl::RenameAndUniquify(
const base::FilePath& full_path,
const RenameCompletionCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- base::FilePath new_path(full_path);
-
- int uniquifier = base::GetUniquePathNumber(
- new_path, base::FilePath::StringType());
- if (uniquifier > 0) {
- new_path = new_path.InsertBeforeExtensionASCII(
- base::StringPrintf(" (%d)", uniquifier));
- }
-
- DownloadInterruptReason reason = file_.Rename(new_path);
- if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
- // Make sure our information is updated, since we're about to
- // error out.
- SendUpdate();
+ RenameWithRetryInternal(
+ full_path, UNIQUIFY, kMaxRenameRetries, base::TimeTicks(), callback);
+}
- // Null out callback so that we don't do any more stream processing.
- stream_reader_->RegisterCallback(base::Closure());
+void DownloadFileImpl::RenameAndAnnotate(
+ const base::FilePath& full_path,
+ const RenameCompletionCallback& callback) {
+ RenameWithRetryInternal(full_path,
+ ANNOTATE_WITH_SOURCE_INFORMATION,
+ kMaxRenameRetries,
+ base::TimeTicks(),
+ callback);
+}
- new_path.clear();
- }
+base::TimeDelta DownloadFileImpl::GetRetryDelayForFailedRename(
+ int attempt_number) {
+ DCHECK_GE(attempt_number, 0);
+ // |delay| starts at kInitialRenameRetryDelayMs and increases by a factor of
+ // 2 at each subsequent retry. Assumes that |retries_left| starts at
+ // kMaxRenameRetries. Also assumes that kMaxRenameRetries is less than the
+ // number of bits in an int.
+ return base::TimeDelta::FromMilliseconds(kInitialRenameRetryDelayMs) *
+ (1 << attempt_number);
+}
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(callback, reason, new_path));
+bool DownloadFileImpl::ShouldRetryFailedRename(DownloadInterruptReason reason) {
+ return reason == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
}
-void DownloadFileImpl::RenameAndAnnotate(
+void DownloadFileImpl::RenameWithRetryInternal(
const base::FilePath& full_path,
+ RenameOption option,
+ int retries_left,
+ base::TimeTicks time_of_first_failure,
const RenameCompletionCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::FilePath new_path(full_path);
- DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
- // Short circuit null rename.
- if (full_path != file_.full_path())
- reason = file_.Rename(new_path);
+ if ((option & UNIQUIFY) && full_path != file_.full_path()) {
+ int uniquifier =
+ base::GetUniquePathNumber(new_path, base::FilePath::StringType());
+ if (uniquifier > 0)
+ new_path = new_path.InsertBeforeExtensionASCII(
+ base::StringPrintf(" (%d)", uniquifier));
+ }
+
+ DownloadInterruptReason reason = file_.Rename(new_path);
+
+ // Attempt to retry the rename if possible. If the rename failed and the
+ // subsequent open also failed, then in_progress() would be false. We don't
+ // try to retry renames if the in_progress() was false to begin with since we
+ // 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;
+ 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),
+ GetRetryDelayForFailedRename(attempt_number));
+ return;
+ }
+
+ if (!time_of_first_failure.is_null())
+ RecordDownloadFileRenameResultAfterRetry(
+ base::TimeTicks::Now() - time_of_first_failure, reason);
- if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
+ if (reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
+ (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
diff --git a/chromium/content/browser/download/download_file_impl.h b/chromium/content/browser/download/download_file_impl.h
index 2ba3d8d058e..9ff3f8583db 100644
--- a/chromium/content/browser/download/download_file_impl.h
+++ b/chromium/content/browser/download/download_file_impl.h
@@ -44,31 +44,58 @@ class CONTENT_EXPORT DownloadFileImpl : virtual public DownloadFile {
const net::BoundNetLog& bound_net_log,
base::WeakPtr<DownloadDestinationObserver> observer);
- virtual ~DownloadFileImpl();
+ ~DownloadFileImpl() override;
// DownloadFile functions.
- virtual void Initialize(const InitializeCallback& callback) OVERRIDE;
- virtual void RenameAndUniquify(
- const base::FilePath& full_path,
- const RenameCompletionCallback& callback) OVERRIDE;
- virtual void RenameAndAnnotate(
- const base::FilePath& full_path,
- const RenameCompletionCallback& callback) OVERRIDE;
- virtual void Detach() OVERRIDE;
- virtual void Cancel() OVERRIDE;
- virtual base::FilePath FullPath() const OVERRIDE;
- virtual bool InProgress() const OVERRIDE;
- virtual int64 CurrentSpeed() const OVERRIDE;
- virtual bool GetHash(std::string* hash) OVERRIDE;
- virtual std::string GetHashState() OVERRIDE;
- virtual void SetClientGuid(const std::string& guid) OVERRIDE;
+ void Initialize(const InitializeCallback& callback) override;
+ void RenameAndUniquify(const base::FilePath& full_path,
+ const RenameCompletionCallback& callback) override;
+ void RenameAndAnnotate(const base::FilePath& full_path,
+ const RenameCompletionCallback& callback) override;
+ void Detach() override;
+ void Cancel() override;
+ base::FilePath FullPath() const override;
+ bool InProgress() const override;
+ int64 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.
virtual DownloadInterruptReason AppendDataToFile(
const char* data, size_t data_len);
+ virtual base::TimeDelta GetRetryDelayForFailedRename(int attempt_number);
+
+ virtual bool ShouldRetryFailedRename(DownloadInterruptReason reason);
+
private:
+ friend class DownloadFileTest;
+
+ // Options for RenameWithRetryInternal.
+ enum RenameOption {
+ UNIQUIFY = 1 << 0, // If there's already a file on disk that conflicts with
+ // |new_path|, try to create a unique file by appending
+ // a uniquifier.
+ 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);
+
// Send an update on our progress.
void SendUpdate();
diff --git a/chromium/content/browser/download/download_file_unittest.cc b/chromium/content/browser/download/download_file_unittest.cc
index 1127908c260..620efa36ff0 100644
--- a/chromium/content/browser/download/download_file_unittest.cc
+++ b/chromium/content/browser/download/download_file_unittest.cc
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/file_util.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/test_file_util.h"
#include "content/browser/browser_thread_impl.h"
@@ -59,6 +61,46 @@ class MockDownloadDestinationObserver : public DownloadDestinationObserver {
MATCHER(IsNullCallback, "") { return (arg.is_null()); }
+typedef void (DownloadFile::*DownloadFileRenameMethodType)(
+ const base::FilePath&,
+ const DownloadFile::RenameCompletionCallback&);
+
+// This is a test DownloadFileImpl that has no retry delay and, on Posix,
+// retries renames failed due to ACCESS_DENIED.
+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(save_info.Pass(),
+ default_downloads_directory,
+ url,
+ referrer_url,
+ calculate_hash,
+ stream.Pass(),
+ bound_net_log,
+ observer) {}
+
+ protected:
+ base::TimeDelta GetRetryDelayForFailedRename(int attempt_count) override {
+ return base::TimeDelta::FromMilliseconds(0);
+ }
+
+#if !defined(OS_WIN)
+ // On Posix, we don't encounter transient errors during renames, except
+ // possibly EAGAIN, which is difficult to replicate reliably. So we resort to
+ // simulating a transient error using ACCESS_DENIED instead.
+ bool ShouldRetryFailedRename(DownloadInterruptReason reason) override {
+ return reason == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED;
+ }
+#endif
+};
+
} // namespace
class DownloadFileTest : public testing::Test {
@@ -83,8 +125,7 @@ class DownloadFileTest : public testing::Test {
file_thread_(BrowserThread::FILE, &loop_) {
}
- virtual ~DownloadFileTest() {
- }
+ ~DownloadFileTest() override {}
void SetUpdateDownloadInfo(int64 bytes, int64 bytes_per_sec,
const std::string& hash_state) {
@@ -97,22 +138,22 @@ class DownloadFileTest : public testing::Test {
observer_->CurrentUpdateStatus(bytes_, bytes_per_sec_, hash_state_);
}
- virtual void SetUp() {
+ void SetUp() override {
EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
.Times(AnyNumber())
.WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
}
// Mock calls to this function are forwarded here.
- void RegisterCallback(base::Closure sink_callback) {
+ void RegisterCallback(const base::Closure& sink_callback) {
sink_callback_ = sink_callback;
}
- void SetInterruptReasonCallback(bool* was_called,
+ void SetInterruptReasonCallback(const base::Closure& closure,
DownloadInterruptReason* reason_p,
DownloadInterruptReason reason) {
- *was_called = true;
*reason_p = reason;
+ closure.Run();
}
bool CreateDownloadFile(int offset, bool calculate_hash) {
@@ -128,30 +169,29 @@ class DownloadFileTest : public testing::Test {
.RetiresOnSaturation();
scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
- download_file_.reset(
- new DownloadFileImpl(save_info.Pass(),
- base::FilePath(),
- GURL(), // Source
- GURL(), // Referrer
- calculate_hash,
- scoped_ptr<ByteStreamReader>(input_stream_),
- net::BoundNetLog(),
- observer_factory_.GetWeakPtr()));
- download_file_->SetClientGuid(
- "12345678-ABCD-1234-DCBA-123456789ABC");
+ scoped_ptr<TestDownloadFileImpl> download_file_impl(
+ new TestDownloadFileImpl(save_info.Pass(),
+ 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_ = download_file_impl.Pass();
EXPECT_CALL(*input_stream_, Read(_, _))
.WillOnce(Return(ByteStreamReader::STREAM_EMPTY))
.RetiresOnSaturation();
base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
- bool called = false;
- DownloadInterruptReason result;
+ DownloadInterruptReason result = DOWNLOAD_INTERRUPT_REASON_NONE;
+ base::RunLoop loop_runner;
download_file_->Initialize(base::Bind(
&DownloadFileTest::SetInterruptReasonCallback,
- weak_ptr_factory.GetWeakPtr(), &called, &result));
- loop_.RunUntilIdle();
- EXPECT_TRUE(called);
+ weak_ptr_factory.GetWeakPtr(), loop_runner.QuitClosure(), &result));
+ loop_runner.Run();
::testing::Mock::VerifyAndClearExpectations(input_stream_);
return result == DOWNLOAD_INTERRUPT_REASON_NONE;
@@ -243,42 +283,42 @@ class DownloadFileTest : public testing::Test {
DownloadInterruptReason RenameAndUniquify(
const base::FilePath& full_path,
base::FilePath* result_path_p) {
- base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
- DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
- bool callback_was_called(false);
- base::FilePath result_path;
+ return InvokeRenameMethodAndWaitForCallback(
+ &DownloadFile::RenameAndUniquify, full_path, result_path_p);
+ }
- download_file_->RenameAndUniquify(
- full_path, base::Bind(&DownloadFileTest::SetRenameResult,
- weak_ptr_factory.GetWeakPtr(),
- &callback_was_called,
- &result_reason, result_path_p));
- loop_.RunUntilIdle();
+ DownloadInterruptReason RenameAndAnnotate(
+ const base::FilePath& full_path,
+ base::FilePath* result_path_p) {
+ return InvokeRenameMethodAndWaitForCallback(
+ &DownloadFile::RenameAndAnnotate, full_path, result_path_p);
+ }
- EXPECT_TRUE(callback_was_called);
- return result_reason;
+ void ExpectPermissionError(DownloadInterruptReason err) {
+ EXPECT_TRUE(err == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR ||
+ err == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED)
+ << "Interrupt reason = " << err;
}
- DownloadInterruptReason RenameAndAnnotate(
+ protected:
+ DownloadInterruptReason InvokeRenameMethodAndWaitForCallback(
+ DownloadFileRenameMethodType method,
const base::FilePath& full_path,
base::FilePath* result_path_p) {
- base::WeakPtrFactory<DownloadFileTest> weak_ptr_factory(this);
DownloadInterruptReason result_reason(DOWNLOAD_INTERRUPT_REASON_NONE);
- bool callback_was_called(false);
base::FilePath result_path;
- download_file_->RenameAndAnnotate(
- full_path, base::Bind(&DownloadFileTest::SetRenameResult,
- weak_ptr_factory.GetWeakPtr(),
- &callback_was_called,
- &result_reason, result_path_p));
- loop_.RunUntilIdle();
-
- EXPECT_TRUE(callback_was_called);
+ base::RunLoop loop_runner;
+ ((*download_file_).*method)(full_path,
+ base::Bind(&DownloadFileTest::SetRenameResult,
+ base::Unretained(this),
+ loop_runner.QuitClosure(),
+ &result_reason,
+ result_path_p));
+ loop_runner.Run();
return result_reason;
}
- protected:
scoped_ptr<StrictMock<MockDownloadDestinationObserver> > observer_;
base::WeakPtrFactory<DownloadDestinationObserver> observer_factory_;
@@ -300,17 +340,16 @@ class DownloadFileTest : public testing::Test {
base::MessageLoop loop_;
private:
- void SetRenameResult(bool* called_p,
+ void SetRenameResult(const base::Closure& closure,
DownloadInterruptReason* reason_p,
base::FilePath* result_path_p,
DownloadInterruptReason reason,
const base::FilePath& result_path) {
- if (called_p)
- *called_p = true;
if (reason_p)
*reason_p = reason;
if (result_path_p)
*result_path_p = result_path;
+ closure.Run();
}
// UI thread.
@@ -322,6 +361,33 @@ class DownloadFileTest : public testing::Test {
std::string expected_data_;
};
+// DownloadFile::RenameAndAnnotate and DownloadFile::RenameAndUniquify have a
+// considerable amount of functional overlap. In order to re-use test logic, we
+// are going to introduce this value parameterized test fixture. It will take a
+// DownloadFileRenameMethodType value which can be either of the two rename
+// methods.
+class DownloadFileTestWithRename
+ : public DownloadFileTest,
+ public ::testing::WithParamInterface<DownloadFileRenameMethodType> {
+ protected:
+ DownloadInterruptReason InvokeSelectedRenameMethod(
+ const base::FilePath& full_path,
+ base::FilePath* result_path_p) {
+ return InvokeRenameMethodAndWaitForCallback(
+ GetParam(), full_path, result_path_p);
+ }
+};
+
+// And now instantiate all DownloadFileTestWithRename tests using both
+// DownloadFile rename methods. Each test of the form
+// DownloadFileTestWithRename.<FooTest> will be instantiated once with
+// RenameAndAnnotate as the value parameter and once with RenameAndUniquify as
+// the value parameter.
+INSTANTIATE_TEST_CASE_P(DownloadFile,
+ DownloadFileTestWithRename,
+ ::testing::Values(&DownloadFile::RenameAndAnnotate,
+ &DownloadFile::RenameAndUniquify));
+
const char* DownloadFileTest::kTestData1 =
"Let's write some data to the file!\n";
const char* DownloadFileTest::kTestData2 = "Writing more data.\n";
@@ -335,7 +401,7 @@ const int DownloadFileTest::kDummyRequestId = 67;
// Rename the file before any data is downloaded, after some has, after it all
// has, and after it's closed.
-TEST_F(DownloadFileTest, RenameFileFinal) {
+TEST_P(DownloadFileTestWithRename, RenameFileFinal) {
ASSERT_TRUE(CreateDownloadFile(0, true));
base::FilePath initial_path(download_file_->FullPath());
EXPECT_TRUE(base::PathExists(initial_path));
@@ -343,12 +409,11 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
base::FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2"));
base::FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3"));
base::FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4"));
- base::FilePath path_5(initial_path.InsertBeforeExtensionASCII("_5"));
base::FilePath output_path;
// Rename the file before downloading any data.
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
- RenameAndUniquify(path_1, &output_path));
+ InvokeSelectedRenameMethod(path_1, &output_path));
base::FilePath renamed_path = download_file_->FullPath();
EXPECT_EQ(path_1, renamed_path);
EXPECT_EQ(path_1, output_path);
@@ -363,7 +428,7 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
// Rename the file after downloading some data.
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
- RenameAndUniquify(path_2, &output_path));
+ InvokeSelectedRenameMethod(path_2, &output_path));
renamed_path = download_file_->FullPath();
EXPECT_EQ(path_2, renamed_path);
EXPECT_EQ(path_2, output_path);
@@ -377,7 +442,7 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
// Rename the file after downloading all the data.
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
- RenameAndUniquify(path_3, &output_path));
+ InvokeSelectedRenameMethod(path_3, &output_path));
renamed_path = download_file_->FullPath();
EXPECT_EQ(path_3, renamed_path);
EXPECT_EQ(path_3, output_path);
@@ -394,7 +459,7 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
// Rename the file after downloading all the data and closing the file.
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
- RenameAndUniquify(path_4, &output_path));
+ InvokeSelectedRenameMethod(path_4, &output_path));
renamed_path = download_file_->FullPath();
EXPECT_EQ(path_4, renamed_path);
EXPECT_EQ(path_4, output_path);
@@ -407,29 +472,42 @@ TEST_F(DownloadFileTest, RenameFileFinal) {
EXPECT_TRUE(download_file_->GetHash(&hash));
EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size()));
- // Check that a rename with overwrite to an existing file succeeds.
- std::string file_contents;
- ASSERT_FALSE(base::PathExists(path_5));
+ DestroyDownloadFile(0);
+}
+
+// Test to make sure the rename overwrites when requested. This is separate from
+// the above test because it only applies to RenameAndAnnotate().
+// RenameAndUniquify() doesn't overwrite by design.
+TEST_F(DownloadFileTest, RenameOverwrites) {
+ ASSERT_TRUE(CreateDownloadFile(0, true));
+ base::FilePath initial_path(download_file_->FullPath());
+ EXPECT_TRUE(base::PathExists(initial_path));
+ base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
+
+ ASSERT_FALSE(base::PathExists(path_1));
static const char file_data[] = "xyzzy";
- ASSERT_EQ(static_cast<int>(sizeof(file_data) - 1),
- base::WriteFile(path_5, file_data, sizeof(file_data) - 1));
- ASSERT_TRUE(base::PathExists(path_5));
- EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
- EXPECT_EQ(std::string(file_data), file_contents);
+ ASSERT_EQ(static_cast<int>(sizeof(file_data)),
+ base::WriteFile(path_1, file_data, sizeof(file_data)));
+ ASSERT_TRUE(base::PathExists(path_1));
+ base::FilePath new_path;
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
- RenameAndAnnotate(path_5, &output_path));
- EXPECT_EQ(path_5, output_path);
+ RenameAndAnnotate(path_1, &new_path));
+ EXPECT_EQ(path_1.value(), new_path.value());
- file_contents = "";
- EXPECT_TRUE(base::ReadFileToString(path_5, &file_contents));
+ std::string file_contents;
+ ASSERT_TRUE(base::ReadFileToString(new_path, &file_contents));
EXPECT_NE(std::string(file_data), file_contents);
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ loop_.RunUntilIdle();
DestroyDownloadFile(0);
}
// Test to make sure the rename uniquifies if we aren't overwriting
-// and there's a file where we're aiming.
+// and there's a file where we're aiming. As above, not a
+// DownloadFileTestWithRename test because this only applies to
+// RenameAndUniquify().
TEST_F(DownloadFileTest, RenameUniquifies) {
ASSERT_TRUE(CreateDownloadFile(0, true));
base::FilePath initial_path(download_file_->FullPath());
@@ -451,16 +529,35 @@ TEST_F(DownloadFileTest, RenameUniquifies) {
DestroyDownloadFile(0);
}
+// Test that RenameAndUniquify doesn't try to uniquify in the case where the
+// target filename is the same as the current filename.
+TEST_F(DownloadFileTest, RenameRecognizesSelfConflict) {
+ ASSERT_TRUE(CreateDownloadFile(0, true));
+ base::FilePath initial_path(download_file_->FullPath());
+ EXPECT_TRUE(base::PathExists(initial_path));
+
+ base::FilePath new_path;
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
+ RenameAndUniquify(initial_path, &new_path));
+ EXPECT_TRUE(base::PathExists(initial_path));
+
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ loop_.RunUntilIdle();
+ DestroyDownloadFile(0);
+ EXPECT_EQ(initial_path.value(), new_path.value());
+}
+
// Test to make sure we get the proper error on failure.
-TEST_F(DownloadFileTest, RenameError) {
+TEST_P(DownloadFileTestWithRename, RenameError) {
ASSERT_TRUE(CreateDownloadFile(0, true));
base::FilePath initial_path(download_file_->FullPath());
// Create a subdirectory.
- base::FilePath tempdir(
- initial_path.DirName().Append(FILE_PATH_LITERAL("tempdir")));
- ASSERT_TRUE(base::CreateDirectory(tempdir));
- base::FilePath target_path(tempdir.Append(initial_path.BaseName()));
+ base::FilePath target_dir(
+ initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir")));
+ ASSERT_FALSE(base::DirectoryExists(target_dir));
+ ASSERT_TRUE(base::CreateDirectory(target_dir));
+ base::FilePath target_path(target_dir.Append(initial_path.BaseName()));
// Targets
base::FilePath target_path_suffixed(
@@ -470,13 +567,12 @@ TEST_F(DownloadFileTest, RenameError) {
// Make the directory unwritable and try to rename within it.
{
- file_util::PermissionRestorer restorer(tempdir);
- ASSERT_TRUE(file_util::MakeFileUnwritable(tempdir));
+ base::FilePermissionRestorer restorer(target_dir);
+ ASSERT_TRUE(base::MakeFileUnwritable(target_dir));
// Expect nulling out of further processing.
EXPECT_CALL(*input_stream_, RegisterCallback(IsNullCallback()));
- EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
- RenameAndAnnotate(target_path, NULL));
+ ExpectPermissionError(InvokeSelectedRenameMethod(target_path, NULL));
EXPECT_FALSE(base::PathExists(target_path_suffixed));
}
@@ -485,6 +581,98 @@ TEST_F(DownloadFileTest, RenameError) {
DestroyDownloadFile(0);
}
+namespace {
+
+void TestRenameCompletionCallback(const base::Closure& closure,
+ bool* did_run_callback,
+ DownloadInterruptReason interrupt_reason,
+ const base::FilePath& new_path) {
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
+ *did_run_callback = true;
+ closure.Run();
+}
+
+} // namespace
+
+// Test that the retry logic works. This test assumes that DownloadFileImpl will
+// post tasks to the current message loop (acting as the FILE thread)
+// asynchronously to retry the renames. We will stuff RunLoop::QuitClosures()
+// in between the retry tasks to stagger them and then allow the rename to
+// succeed.
+//
+// Note that there is only one queue of tasks to run, and that is in the tests'
+// base::MessageLoop::current(). Each RunLoop processes that queue until it sees
+// a QuitClosure() targeted at itself, at which point it stops processing.
+TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) {
+ ASSERT_TRUE(CreateDownloadFile(0, true));
+ base::FilePath initial_path(download_file_->FullPath());
+
+ // Create a subdirectory.
+ base::FilePath target_dir(
+ initial_path.DirName().Append(FILE_PATH_LITERAL("TargetDir")));
+ ASSERT_FALSE(base::DirectoryExists(target_dir));
+ ASSERT_TRUE(base::CreateDirectory(target_dir));
+ base::FilePath target_path(target_dir.Append(initial_path.BaseName()));
+
+ bool did_run_callback = false;
+
+ // Each RunLoop can be used the run the MessageLoop until the corresponding
+ // QuitClosure() is run. This one is used to produce the QuitClosure() that
+ // will be run when the entire rename operation is complete.
+ base::RunLoop succeeding_run;
+ {
+ // (Scope for the base::File or base::FilePermissionRestorer below.)
+#if defined(OS_WIN)
+ // On Windows we test with an actual transient error, a sharing violation.
+ // The rename will fail because we are holding the file open for READ. On
+ // Posix this doesn't cause a failure.
+ base::File locked_file(initial_path,
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+ ASSERT_TRUE(locked_file.IsValid());
+#else
+ // Simulate a transient failure by revoking write permission for target_dir.
+ // The TestDownloadFileImpl class treats this error as transient even though
+ // DownloadFileImpl itself doesn't.
+ base::FilePermissionRestorer restore_permissions_for(target_dir);
+ ASSERT_TRUE(base::MakeFileUnwritable(target_dir));
+#endif
+
+ // 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));
+ EXPECT_FALSE(did_run_callback);
+
+ base::RunLoop first_failing_run;
+ // Queue the QuitClosure() on the MessageLoop now. Any tasks queued by the
+ // Rename() will be in front of the QuitClosure(). Running the message loop
+ // now causes the just the first retry task to be run. The rename still
+ // fails, so another retry task would get queued behind the QuitClosure().
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ first_failing_run.QuitClosure());
+ first_failing_run.Run();
+ EXPECT_FALSE(did_run_callback);
+
+ // Running another loop should have the same effect as the above as long as
+ // kMaxRenameRetries is greater than 2.
+ base::RunLoop second_failing_run;
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ second_failing_run.QuitClosure());
+ second_failing_run.Run();
+ EXPECT_FALSE(did_run_callback);
+ }
+
+ // This time the QuitClosure from succeeding_run should get executed.
+ succeeding_run.Run();
+ EXPECT_TRUE(did_run_callback);
+
+ FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true);
+ loop_.RunUntilIdle();
+ DestroyDownloadFile(0);
+}
+
// Various tests of the StreamActive method.
TEST_F(DownloadFileTest, StreamEmptySuccess) {
ASSERT_TRUE(CreateDownloadFile(0, true));
diff --git a/chromium/content/browser/download/download_interrupt_reasons_impl.cc b/chromium/content/browser/download/download_interrupt_reasons_impl.cc
index 9a01f484f1d..2ed8f147ee0 100644
--- a/chromium/content/browser/download/download_interrupt_reasons_impl.cc
+++ b/chromium/content/browser/download/download_interrupt_reasons_impl.cc
@@ -8,6 +8,35 @@
namespace content {
+DownloadInterruptReason ConvertFileErrorToInterruptReason(
+ base::File::Error file_error) {
+ switch (file_error) {
+ case base::File::FILE_OK:
+ return DOWNLOAD_INTERRUPT_REASON_NONE;
+
+ case base::File::FILE_ERROR_IN_USE:
+ return DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
+
+ case base::File::FILE_ERROR_ACCESS_DENIED:
+ return DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED;
+
+ case base::File::FILE_ERROR_TOO_MANY_OPENED:
+ return DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
+
+ case base::File::FILE_ERROR_NO_MEMORY:
+ return DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR;
+
+ case base::File::FILE_ERROR_NO_SPACE:
+ return DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE;
+
+ case base::File::FILE_ERROR_SECURITY:
+ return DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED;
+
+ default:
+ return DOWNLOAD_INTERRUPT_REASON_FILE_FAILED;
+ }
+}
+
DownloadInterruptReason ConvertNetErrorToInterruptReason(
net::Error net_error, DownloadInterruptSource source) {
switch (net_error) {
diff --git a/chromium/content/browser/download/download_interrupt_reasons_impl.h b/chromium/content/browser/download/download_interrupt_reasons_impl.h
index 137dcb2abc5..61ccae1a441 100644
--- a/chromium/content/browser/download/download_interrupt_reasons_impl.h
+++ b/chromium/content/browser/download/download_interrupt_reasons_impl.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_INTERRUPT_REASONS_IMPL_H_
#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_INTERRUPT_REASONS_IMPL_H_
+#include "base/files/file.h"
#include "content/public/browser/download_interrupt_reasons.h"
#include "net/base/net_errors.h"
@@ -22,6 +23,10 @@ enum DownloadInterruptSource {
DownloadInterruptReason CONTENT_EXPORT ConvertNetErrorToInterruptReason(
net::Error file_error, DownloadInterruptSource source);
+// Safe to call from any thread.
+DownloadInterruptReason CONTENT_EXPORT ConvertFileErrorToInterruptReason(
+ base::File::Error file_error);
+
} // namespace content
#endif // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_INTERRUPT_REASONS_IMPL_H_
diff --git a/chromium/content/browser/download/download_item_impl.cc b/chromium/content/browser/download/download_item_impl.cc
index 433ac78f48b..f681486cdcb 100644
--- a/chromium/content/browser/download/download_item_impl.cc
+++ b/chromium/content/browser/download/download_item_impl.cc
@@ -28,7 +28,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
@@ -93,7 +93,7 @@ static void DownloadFileCancel(scoped_ptr<DownloadFile> download_file) {
}
bool IsDownloadResumptionEnabled() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableDownloadResumption);
}
@@ -133,7 +133,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
target_disposition_(TARGET_DISPOSITION_OVERWRITE),
url_chain_(url_chain),
referrer_url_(referrer_url),
- transition_type_(PAGE_TRANSITION_LINK),
+ transition_type_(ui::PAGE_TRANSITION_LINK),
has_user_gesture_(false),
mime_type_(mime_type),
original_mime_type_(original_mime_type),
@@ -242,7 +242,7 @@ DownloadItemImpl::DownloadItemImpl(
target_disposition_(TARGET_DISPOSITION_OVERWRITE),
url_chain_(1, url),
referrer_url_(GURL()),
- transition_type_(PAGE_TRANSITION_LINK),
+ transition_type_(ui::PAGE_TRANSITION_LINK),
has_user_gesture_(false),
mime_type_(mime_type),
original_mime_type_(mime_type),
@@ -588,7 +588,7 @@ bool DownloadItemImpl::HasUserGesture() const {
return has_user_gesture_;
};
-PageTransition DownloadItemImpl::GetTransitionType() const {
+ui::PageTransition DownloadItemImpl::GetTransitionType() const {
return transition_type_;
};
@@ -927,6 +927,8 @@ DownloadItemImpl::ResumeMode DownloadItemImpl::GetResumeMode() const {
case DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
case DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
case DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
+ case DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
+ case DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
mode = RESUME_MODE_INVALID;
break;
}
@@ -1680,7 +1682,8 @@ void DownloadItemImpl::ResumeInterruptedDownload() {
// If the flag for downloads resumption isn't enabled, ignore
// this request.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(switches::kEnableDownloadResumption))
return;
diff --git a/chromium/content/browser/download/download_item_impl.h b/chromium/content/browser/download/download_item_impl.h
index 34916ff6fd9..b6394f7469d 100644
--- a/chromium/content/browser/download/download_item_impl.h
+++ b/chromium/content/browser/download/download_item_impl.h
@@ -14,7 +14,6 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
-#include "base/timer/timer.h"
#include "content/browser/download/download_net_log_parameters.h"
#include "content/browser/download/download_request_handle.h"
#include "content/common/content_export.h"
@@ -87,77 +86,76 @@ class CONTENT_EXPORT DownloadItemImpl
scoped_ptr<DownloadRequestHandleInterface> request_handle,
const net::BoundNetLog& bound_net_log);
- virtual ~DownloadItemImpl();
+ ~DownloadItemImpl() override;
// DownloadItem
- virtual void AddObserver(DownloadItem::Observer* observer) OVERRIDE;
- virtual void RemoveObserver(DownloadItem::Observer* observer) OVERRIDE;
- virtual void UpdateObservers() OVERRIDE;
- virtual void ValidateDangerousDownload() OVERRIDE;
- virtual void StealDangerousDownload(const AcquireFileCallback& callback)
- OVERRIDE;
- virtual void Pause() OVERRIDE;
- virtual void Resume() OVERRIDE;
- virtual void Cancel(bool user_cancel) OVERRIDE;
- virtual void Remove() OVERRIDE;
- virtual void OpenDownload() OVERRIDE;
- virtual void ShowDownloadInShell() OVERRIDE;
- virtual uint32 GetId() const OVERRIDE;
- virtual DownloadState GetState() const OVERRIDE;
- virtual DownloadInterruptReason GetLastReason() const OVERRIDE;
- virtual bool IsPaused() const OVERRIDE;
- virtual bool IsTemporary() const OVERRIDE;
- virtual bool CanResume() const OVERRIDE;
- virtual bool IsDone() const OVERRIDE;
- virtual const GURL& GetURL() const OVERRIDE;
- virtual const std::vector<GURL>& GetUrlChain() const OVERRIDE;
- virtual const GURL& GetOriginalUrl() const OVERRIDE;
- virtual const GURL& GetReferrerUrl() const OVERRIDE;
- virtual const GURL& GetTabUrl() const OVERRIDE;
- virtual const GURL& GetTabReferrerUrl() const OVERRIDE;
- virtual std::string GetSuggestedFilename() const OVERRIDE;
- virtual std::string GetContentDisposition() const OVERRIDE;
- virtual std::string GetMimeType() const OVERRIDE;
- virtual std::string GetOriginalMimeType() const OVERRIDE;
- virtual std::string GetRemoteAddress() const OVERRIDE;
- virtual bool HasUserGesture() const OVERRIDE;
- virtual PageTransition GetTransitionType() const OVERRIDE;
- virtual const std::string& GetLastModifiedTime() const OVERRIDE;
- virtual const std::string& GetETag() const OVERRIDE;
- virtual bool IsSavePackageDownload() const OVERRIDE;
- virtual const base::FilePath& GetFullPath() const OVERRIDE;
- virtual const base::FilePath& GetTargetFilePath() const OVERRIDE;
- virtual const base::FilePath& GetForcedFilePath() const OVERRIDE;
- virtual base::FilePath GetFileNameToReportUser() const OVERRIDE;
- virtual TargetDisposition GetTargetDisposition() const OVERRIDE;
- virtual const std::string& GetHash() const OVERRIDE;
- virtual const std::string& GetHashState() const OVERRIDE;
- virtual bool GetFileExternallyRemoved() const OVERRIDE;
- virtual void DeleteFile(const base::Callback<void(bool)>& callback) OVERRIDE;
- virtual bool IsDangerous() const OVERRIDE;
- virtual DownloadDangerType GetDangerType() const OVERRIDE;
- virtual bool TimeRemaining(base::TimeDelta* remaining) const OVERRIDE;
- virtual int64 CurrentSpeed() const OVERRIDE;
- virtual int PercentComplete() const OVERRIDE;
- virtual bool AllDataSaved() const OVERRIDE;
- virtual int64 GetTotalBytes() const OVERRIDE;
- virtual int64 GetReceivedBytes() const OVERRIDE;
- virtual base::Time GetStartTime() const OVERRIDE;
- virtual base::Time GetEndTime() const OVERRIDE;
- virtual bool CanShowInFolder() OVERRIDE;
- virtual bool CanOpenDownload() OVERRIDE;
- virtual bool ShouldOpenFileBasedOnExtension() OVERRIDE;
- virtual bool GetOpenWhenComplete() const OVERRIDE;
- virtual bool GetAutoOpened() OVERRIDE;
- virtual bool GetOpened() const OVERRIDE;
- virtual BrowserContext* GetBrowserContext() const OVERRIDE;
- virtual WebContents* GetWebContents() const OVERRIDE;
- virtual void OnContentCheckCompleted(DownloadDangerType danger_type) OVERRIDE;
- virtual void SetOpenWhenComplete(bool open) OVERRIDE;
- virtual void SetIsTemporary(bool temporary) OVERRIDE;
- virtual void SetOpened(bool opened) OVERRIDE;
- virtual void SetDisplayName(const base::FilePath& name) OVERRIDE;
- virtual std::string DebugString(bool verbose) const OVERRIDE;
+ void AddObserver(DownloadItem::Observer* observer) override;
+ void RemoveObserver(DownloadItem::Observer* observer) override;
+ void UpdateObservers() override;
+ void ValidateDangerousDownload() override;
+ void StealDangerousDownload(const AcquireFileCallback& callback) override;
+ void Pause() override;
+ void Resume() override;
+ void Cancel(bool user_cancel) override;
+ void Remove() override;
+ void OpenDownload() override;
+ void ShowDownloadInShell() override;
+ uint32 GetId() const override;
+ DownloadState GetState() const override;
+ DownloadInterruptReason GetLastReason() const override;
+ bool IsPaused() const override;
+ bool IsTemporary() const override;
+ bool CanResume() const override;
+ bool IsDone() const override;
+ const GURL& GetURL() const override;
+ const std::vector<GURL>& GetUrlChain() const override;
+ const GURL& GetOriginalUrl() const override;
+ const GURL& GetReferrerUrl() const override;
+ const GURL& GetTabUrl() const override;
+ const GURL& GetTabReferrerUrl() const override;
+ std::string GetSuggestedFilename() const override;
+ std::string GetContentDisposition() const override;
+ std::string GetMimeType() const override;
+ std::string GetOriginalMimeType() const override;
+ std::string GetRemoteAddress() const override;
+ bool HasUserGesture() const override;
+ ui::PageTransition GetTransitionType() const override;
+ const std::string& GetLastModifiedTime() const override;
+ const std::string& GetETag() const override;
+ bool IsSavePackageDownload() const override;
+ const base::FilePath& GetFullPath() const override;
+ const base::FilePath& GetTargetFilePath() const override;
+ const base::FilePath& GetForcedFilePath() const override;
+ 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;
+ DownloadDangerType GetDangerType() const override;
+ bool TimeRemaining(base::TimeDelta* remaining) const override;
+ int64 CurrentSpeed() const override;
+ int PercentComplete() const override;
+ bool AllDataSaved() const override;
+ int64 GetTotalBytes() const override;
+ int64 GetReceivedBytes() const override;
+ base::Time GetStartTime() const override;
+ base::Time GetEndTime() const override;
+ bool CanShowInFolder() override;
+ bool CanOpenDownload() override;
+ bool ShouldOpenFileBasedOnExtension() override;
+ bool GetOpenWhenComplete() const override;
+ bool GetAutoOpened() override;
+ bool GetOpened() const override;
+ BrowserContext* GetBrowserContext() const override;
+ WebContents* GetWebContents() const override;
+ void OnContentCheckCompleted(DownloadDangerType danger_type) override;
+ void SetOpenWhenComplete(bool open) override;
+ void SetIsTemporary(bool temporary) override;
+ void SetOpened(bool opened) override;
+ void SetDisplayName(const base::FilePath& name) override;
+ std::string DebugString(bool verbose) const override;
// All remaining public interfaces virtual to allow for DownloadItemImpl
// mocks.
@@ -210,11 +208,11 @@ class CONTENT_EXPORT DownloadItemImpl
virtual void MarkAsComplete();
// DownloadDestinationObserver
- virtual void DestinationUpdate(int64 bytes_so_far,
- int64 bytes_per_sec,
- const std::string& hash_state) OVERRIDE;
- virtual void DestinationError(DownloadInterruptReason reason) OVERRIDE;
- virtual void DestinationCompleted(const std::string& final_hash) OVERRIDE;
+ void DestinationUpdate(int64 bytes_so_far,
+ int64 bytes_per_sec,
+ const std::string& hash_state) override;
+ void DestinationError(DownloadInterruptReason reason) override;
+ void DestinationCompleted(const std::string& final_hash) override;
private:
// Fine grained states of a download. Note that active downloads are created
@@ -437,7 +435,7 @@ class CONTENT_EXPORT DownloadItemImpl
base::FilePath forced_file_path_;
// Page transition that triggerred the download.
- PageTransition transition_type_;
+ ui::PageTransition transition_type_;
// Whether the download was triggered with a user gesture.
bool has_user_gesture_;
diff --git a/chromium/content/browser/download/download_item_impl_unittest.cc b/chromium/content/browser/download/download_item_impl_unittest.cc
index 1291ce11350..acbc55e2ef8 100644
--- a/chromium/content/browser/download/download_item_impl_unittest.cc
+++ b/chromium/content/browser/download/download_item_impl_unittest.cc
@@ -54,7 +54,7 @@ class MockDelegate : public DownloadItemImplDelegate {
MOCK_METHOD1(CheckForFileRemoval, void(DownloadItemImpl*));
virtual void ResumeInterruptedDownload(
- scoped_ptr<DownloadUrlParameters> params, uint32 id) OVERRIDE {
+ scoped_ptr<DownloadUrlParameters> params, uint32 id) override {
MockResumeInterruptedDownload(params.get(), id);
}
MOCK_METHOD2(MockResumeInterruptedDownload,
@@ -121,17 +121,17 @@ class DownloadItemTest : public testing::Test {
item_->AddObserver(this);
}
- virtual ~MockObserver() {
+ ~MockObserver() override {
if (item_) item_->RemoveObserver(this);
}
- virtual void OnDownloadRemoved(DownloadItem* download) OVERRIDE {
+ void OnDownloadRemoved(DownloadItem* download) override {
DVLOG(20) << " " << __FUNCTION__
<< " download = " << download->DebugString(false);
removed_ = true;
}
- virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE {
+ void OnDownloadUpdated(DownloadItem* download) override {
DVLOG(20) << " " << __FUNCTION__
<< " download = " << download->DebugString(false);
updated_ = true;
@@ -147,12 +147,12 @@ class DownloadItemTest : public testing::Test {
last_state_ = new_state;
}
- virtual void OnDownloadOpened(DownloadItem* download) OVERRIDE {
+ void OnDownloadOpened(DownloadItem* download) override {
DVLOG(20) << " " << __FUNCTION__
<< " download = " << download->DebugString(false);
}
- virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE {
+ void OnDownloadDestroyed(DownloadItem* download) override {
DVLOG(20) << " " << __FUNCTION__
<< " download = " << download->DebugString(false);
destroyed_ = true;
@@ -409,7 +409,7 @@ TEST_F(DownloadItemTest, NotificationAfterDestroyed) {
}
TEST_F(DownloadItemTest, ContinueAfterInterrupted) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
DownloadItemImpl* item = CreateDownloadItem();
@@ -437,7 +437,7 @@ TEST_F(DownloadItemTest, ContinueAfterInterrupted) {
// Same as above, but with a non-continuable interrupt.
TEST_F(DownloadItemTest, RestartAfterInterrupted) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
DownloadItemImpl* item = CreateDownloadItem();
@@ -461,7 +461,7 @@ TEST_F(DownloadItemTest, RestartAfterInterrupted) {
// Check we do correct cleanup for RESUME_MODE_INVALID interrupts.
TEST_F(DownloadItemTest, UnresumableInterrupt) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
DownloadItemImpl* item = CreateDownloadItem();
@@ -491,7 +491,7 @@ TEST_F(DownloadItemTest, UnresumableInterrupt) {
}
TEST_F(DownloadItemTest, LimitRestartsAfterInterrupted) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
DownloadItemImpl* item = CreateDownloadItem();
@@ -813,7 +813,7 @@ TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Restart) {
// intermediate path should be retained when the download is interrupted after
// the intermediate rename succeeds.
TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Continue) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
@@ -848,7 +848,7 @@ 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.
TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Failed) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
DownloadItemImpl* item = CreateDownloadItem();
DownloadItemImplDelegate::DownloadTargetCallback callback;
@@ -1248,7 +1248,7 @@ TEST_F(DownloadItemTest, StealDangerousDownload) {
}
TEST_F(DownloadItemTest, StealInterruptedDangerousDownload) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
base::FilePath returned_path;
DownloadItemImpl* item = CreateDownloadItem();
@@ -1274,7 +1274,7 @@ TEST_F(DownloadItemTest, StealInterruptedDangerousDownload) {
}
TEST_F(DownloadItemTest, StealInterruptedNonResumableDangerousDownload) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableDownloadResumption);
base::FilePath returned_path;
DownloadItemImpl* item = CreateDownloadItem();
diff --git a/chromium/content/browser/download/download_manager_impl.cc b/chromium/content/browser/download/download_manager_impl.cc
index 2bd747d5595..30296cb82e7 100644
--- a/chromium/content/browser/download/download_manager_impl.cc
+++ b/chromium/content/browser/download/download_manager_impl.cc
@@ -39,10 +39,10 @@
#include "content/public/browser/resource_context.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/referrer.h"
+#include "net/base/elements_upload_data_stream.h"
#include "net/base/load_flags.h"
#include "net/base/request_priority.h"
#include "net/base/upload_bytes_element_reader.h"
-#include "net/base/upload_data_stream.h"
#include "net/url_request/url_request_context.h"
namespace content {
@@ -63,8 +63,8 @@ void BeginDownload(scoped_ptr<DownloadUrlParameters> params,
const std::string& body = params->post_body();
scoped_ptr<net::UploadElementReader> reader(
net::UploadOwnedBytesElementReader::CreateWithString(body));
- request->set_upload(make_scoped_ptr(
- net::UploadDataStream::CreateWithReader(reader.Pass(), 0)));
+ request->set_upload(
+ net::ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0));
}
if (params->post_id() >= 0) {
// The POST in this case does not have an actual body, and only works
@@ -75,7 +75,8 @@ void BeginDownload(scoped_ptr<DownloadUrlParameters> params,
DCHECK_EQ("POST", params->method());
ScopedVector<net::UploadElementReader> element_readers;
request->set_upload(make_scoped_ptr(
- new net::UploadDataStream(element_readers.Pass(), params->post_id())));
+ new net::ElementsUploadDataStream(element_readers.Pass(),
+ params->post_id())));
}
// If we're not at the beginning of the file, retrieve only the remaining
@@ -160,9 +161,9 @@ class MapValueIteratorAdapter {
class DownloadItemFactoryImpl : public DownloadItemFactory {
public:
DownloadItemFactoryImpl() {}
- virtual ~DownloadItemFactoryImpl() {}
+ ~DownloadItemFactoryImpl() override {}
- virtual DownloadItemImpl* CreatePersistedItem(
+ DownloadItemImpl* CreatePersistedItem(
DownloadItemImplDelegate* delegate,
uint32 download_id,
const base::FilePath& current_path,
@@ -181,7 +182,7 @@ class DownloadItemFactoryImpl : public DownloadItemFactory {
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
bool opened,
- const net::BoundNetLog& bound_net_log) OVERRIDE {
+ const net::BoundNetLog& bound_net_log) override {
return new DownloadItemImpl(
delegate,
download_id,
@@ -204,22 +205,22 @@ class DownloadItemFactoryImpl : public DownloadItemFactory {
bound_net_log);
}
- virtual DownloadItemImpl* CreateActiveItem(
+ DownloadItemImpl* CreateActiveItem(
DownloadItemImplDelegate* delegate,
uint32 download_id,
const DownloadCreateInfo& info,
- const net::BoundNetLog& bound_net_log) OVERRIDE {
+ const net::BoundNetLog& bound_net_log) override {
return new DownloadItemImpl(delegate, download_id, info, bound_net_log);
}
- virtual DownloadItemImpl* CreateSavePageItem(
+ DownloadItemImpl* CreateSavePageItem(
DownloadItemImplDelegate* delegate,
uint32 download_id,
const base::FilePath& path,
const GURL& url,
const std::string& mime_type,
scoped_ptr<DownloadRequestHandleInterface> request_handle,
- const net::BoundNetLog& bound_net_log) OVERRIDE {
+ const net::BoundNetLog& bound_net_log) override {
return new DownloadItemImpl(delegate, download_id, path, url,
mime_type, request_handle.Pass(),
bound_net_log);
diff --git a/chromium/content/browser/download/download_manager_impl.h b/chromium/content/browser/download/download_manager_impl.h
index 630c83252a8..0c9c33bbbad 100644
--- a/chromium/content/browser/download/download_manager_impl.h
+++ b/chromium/content/browser/download/download_manager_impl.h
@@ -40,7 +40,7 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
// Caller guarantees that |net_log| will remain valid
// for the lifetime of DownloadManagerImpl (until Shutdown() is called).
DownloadManagerImpl(net::NetLog* net_log, BrowserContext* browser_context);
- virtual ~DownloadManagerImpl();
+ ~DownloadManagerImpl() override;
// Implementation functions (not part of the DownloadManager interface).
@@ -58,22 +58,22 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
void OnSavePackageSuccessfullyFinished(DownloadItem* download_item);
// DownloadManager functions.
- virtual void SetDelegate(DownloadManagerDelegate* delegate) OVERRIDE;
- virtual DownloadManagerDelegate* GetDelegate() const OVERRIDE;
- virtual void Shutdown() OVERRIDE;
- virtual void GetAllDownloads(DownloadVector* result) OVERRIDE;
- virtual void StartDownload(
+ void SetDelegate(DownloadManagerDelegate* delegate) override;
+ DownloadManagerDelegate* GetDelegate() const override;
+ void Shutdown() override;
+ void GetAllDownloads(DownloadVector* result) override;
+ void StartDownload(
scoped_ptr<DownloadCreateInfo> info,
scoped_ptr<ByteStreamReader> stream,
- const DownloadUrlParameters::OnStartedCallback& on_started) OVERRIDE;
- virtual int RemoveDownloadsBetween(base::Time remove_begin,
- base::Time remove_end) OVERRIDE;
- virtual int RemoveDownloads(base::Time remove_begin) OVERRIDE;
- virtual int RemoveAllDownloads() OVERRIDE;
- virtual void DownloadUrl(scoped_ptr<DownloadUrlParameters> params) OVERRIDE;
- virtual void AddObserver(Observer* observer) OVERRIDE;
- virtual void RemoveObserver(Observer* observer) OVERRIDE;
- virtual content::DownloadItem* CreateDownloadItem(
+ const DownloadUrlParameters::OnStartedCallback& on_started) override;
+ int RemoveDownloadsBetween(base::Time remove_begin,
+ base::Time remove_end) override;
+ int RemoveDownloads(base::Time remove_begin) override;
+ int RemoveAllDownloads() override;
+ void DownloadUrl(scoped_ptr<DownloadUrlParameters> params) override;
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+ content::DownloadItem* CreateDownloadItem(
uint32 id,
const base::FilePath& current_path,
const base::FilePath& target_path,
@@ -90,12 +90,12 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
content::DownloadItem::DownloadState state,
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
- bool opened) OVERRIDE;
- virtual int InProgressCount() const OVERRIDE;
- virtual int NonMaliciousInProgressCount() const OVERRIDE;
- virtual BrowserContext* GetBrowserContext() const OVERRIDE;
- virtual void CheckForHistoryFilesRemoval() OVERRIDE;
- virtual DownloadItem* GetDownload(uint32 id) OVERRIDE;
+ bool opened) override;
+ int InProgressCount() const override;
+ int NonMaliciousInProgressCount() const override;
+ BrowserContext* GetBrowserContext() const override;
+ void CheckForHistoryFilesRemoval() override;
+ DownloadItem* GetDownload(uint32 id) override;
// For testing; specifically, accessed from TestFileErrorInjector.
void SetDownloadItemFactoryForTesting(
@@ -144,22 +144,20 @@ class CONTENT_EXPORT DownloadManagerImpl : public DownloadManager,
// Overridden from DownloadItemImplDelegate
// (Note that |GetBrowserContext| are present in both interfaces.)
- virtual void DetermineDownloadTarget(
- DownloadItemImpl* item, const DownloadTargetCallback& callback) OVERRIDE;
- virtual bool ShouldCompleteDownload(
- DownloadItemImpl* item, const base::Closure& complete_callback) OVERRIDE;
- virtual bool ShouldOpenFileBasedOnExtension(
- const base::FilePath& path) OVERRIDE;
- virtual bool ShouldOpenDownload(
- DownloadItemImpl* item,
- const ShouldOpenDownloadCallback& callback) OVERRIDE;
- virtual void CheckForFileRemoval(DownloadItemImpl* download_item) OVERRIDE;
- virtual void ResumeInterruptedDownload(
+ void DetermineDownloadTarget(DownloadItemImpl* item,
+ const DownloadTargetCallback& callback) override;
+ bool ShouldCompleteDownload(DownloadItemImpl* item,
+ const base::Closure& complete_callback) override;
+ bool ShouldOpenFileBasedOnExtension(const base::FilePath& path) override;
+ bool ShouldOpenDownload(DownloadItemImpl* item,
+ const ShouldOpenDownloadCallback& callback) override;
+ void CheckForFileRemoval(DownloadItemImpl* download_item) override;
+ void ResumeInterruptedDownload(
scoped_ptr<content::DownloadUrlParameters> params,
- uint32 id) OVERRIDE;
- virtual void OpenDownload(DownloadItemImpl* download) OVERRIDE;
- virtual void ShowDownloadInShell(DownloadItemImpl* download) OVERRIDE;
- virtual void DownloadRemoved(DownloadItemImpl* download) OVERRIDE;
+ uint32 id) override;
+ void OpenDownload(DownloadItemImpl* download) override;
+ void ShowDownloadInShell(DownloadItemImpl* download) override;
+ void DownloadRemoved(DownloadItemImpl* download) override;
// Factory for creation of downloads items.
scoped_ptr<DownloadItemFactory> item_factory_;
diff --git a/chromium/content/browser/download/download_manager_impl_unittest.cc b/chromium/content/browser/download/download_manager_impl_unittest.cc
index 66430b4443a..0c5eb523966 100644
--- a/chromium/content/browser/download/download_manager_impl_unittest.cc
+++ b/chromium/content/browser/download/download_manager_impl_unittest.cc
@@ -111,7 +111,7 @@ class MockDownloadItemImpl : public DownloadItemImpl {
MOCK_METHOD0(OnDownloadedFileRemoved, void());
virtual void Start(
scoped_ptr<DownloadFile> download_file,
- scoped_ptr<DownloadRequestHandleInterface> req_handle) OVERRIDE {
+ scoped_ptr<DownloadRequestHandleInterface> req_handle) override {
MockStart(download_file.get(), req_handle.get());
}
@@ -159,7 +159,7 @@ class MockDownloadItemImpl : public DownloadItemImpl {
MOCK_METHOD0(GetAutoOpened, bool());
MOCK_CONST_METHOD0(GetForcedFilePath, const base::FilePath&());
MOCK_CONST_METHOD0(HasUserGesture, bool());
- MOCK_CONST_METHOD0(GetTransitionType, PageTransition());
+ MOCK_CONST_METHOD0(GetTransitionType, ui::PageTransition());
MOCK_CONST_METHOD0(IsTemporary, bool());
MOCK_METHOD1(SetIsTemporary, void(bool));
MOCK_METHOD1(SetOpened, void(bool));
@@ -173,7 +173,7 @@ class MockDownloadItemImpl : public DownloadItemImpl {
MOCK_METHOD1(SetDisplayName, void(const base::FilePath&));
MOCK_METHOD0(NotifyRemoved, void());
// May be called when vlog is on.
- virtual std::string DebugString(bool verbose) const OVERRIDE {
+ virtual std::string DebugString(bool verbose) const override {
return std::string();
}
};
@@ -211,7 +211,7 @@ class MockDownloadItemFactory
public base::SupportsWeakPtr<MockDownloadItemFactory> {
public:
MockDownloadItemFactory();
- virtual ~MockDownloadItemFactory();
+ ~MockDownloadItemFactory() override;
// Access to map of created items.
// TODO(rdsmith): Could add type (save page, persisted, etc.)
@@ -229,7 +229,7 @@ class MockDownloadItemFactory
void RemoveItem(int id);
// Overridden methods from DownloadItemFactory.
- virtual DownloadItemImpl* CreatePersistedItem(
+ DownloadItemImpl* CreatePersistedItem(
DownloadItemImplDelegate* delegate,
uint32 download_id,
const base::FilePath& current_path,
@@ -248,20 +248,20 @@ class MockDownloadItemFactory
DownloadDangerType danger_type,
DownloadInterruptReason interrupt_reason,
bool opened,
- const net::BoundNetLog& bound_net_log) OVERRIDE;
- virtual DownloadItemImpl* CreateActiveItem(
+ const net::BoundNetLog& bound_net_log) override;
+ DownloadItemImpl* CreateActiveItem(
DownloadItemImplDelegate* delegate,
uint32 download_id,
const DownloadCreateInfo& info,
- const net::BoundNetLog& bound_net_log) OVERRIDE;
- virtual DownloadItemImpl* CreateSavePageItem(
+ const net::BoundNetLog& bound_net_log) override;
+ DownloadItemImpl* CreateSavePageItem(
DownloadItemImplDelegate* delegate,
uint32 download_id,
const base::FilePath& path,
const GURL& url,
- const std::string& mime_type,
+ const std::string& mime_type,
scoped_ptr<DownloadRequestHandleInterface> request_handle,
- const net::BoundNetLog& bound_net_log) OVERRIDE;
+ const net::BoundNetLog& bound_net_log) override;
private:
std::map<uint32, MockDownloadItemImpl*> items_;
@@ -415,8 +415,9 @@ class MockBrowserContext : public BrowserContext {
MOCK_METHOD0(GetResourceContext, ResourceContext*());
MOCK_METHOD0(GetDownloadManagerDelegate, DownloadManagerDelegate*());
MOCK_METHOD0(GetGuestManager, BrowserPluginGuestManager* ());
- MOCK_METHOD0(GetSpecialStoragePolicy, quota::SpecialStoragePolicy*());
+ MOCK_METHOD0(GetSpecialStoragePolicy, storage::SpecialStoragePolicy*());
MOCK_METHOD0(GetPushMessagingService, PushMessagingService*());
+ MOCK_METHOD0(GetSSLHostStateDelegate, SSLHostStateDelegate*());
};
class MockDownloadManagerObserver : public DownloadManager::Observer {
@@ -445,12 +446,12 @@ class DownloadManagerTest : public testing::Test {
}
// We tear down everything in TearDown().
- virtual ~DownloadManagerTest() {}
+ ~DownloadManagerTest() override {}
// Create a MockDownloadItemFactory and MockDownloadManagerDelegate,
// then create a DownloadManager that points
// at all of those.
- virtual void SetUp() {
+ void SetUp() override {
DCHECK(!download_manager_);
mock_download_item_factory_ = (new MockDownloadItemFactory())->AsWeakPtr();
@@ -476,7 +477,7 @@ class DownloadManagerTest : public testing::Test {
download_manager_->SetDelegate(mock_download_manager_delegate_.get());
}
- virtual void TearDown() {
+ void TearDown() override {
while (MockDownloadItemImpl*
item = mock_download_item_factory_->PopItem()) {
EXPECT_CALL(*item, GetState())
diff --git a/chromium/content/browser/download/download_net_log_parameters.cc b/chromium/content/browser/download/download_net_log_parameters.cc
index 45321362273..36e7e1e2210 100644
--- a/chromium/content/browser/download/download_net_log_parameters.cc
+++ b/chromium/content/browser/download/download_net_log_parameters.cc
@@ -34,10 +34,9 @@ static const char* download_danger_names[] = {
"POTENTIALLY_UNWANTED"
};
-COMPILE_ASSERT(ARRAYSIZE_UNSAFE(download_type_names) == SRC_SAVE_PAGE_AS + 1,
+COMPILE_ASSERT(arraysize(download_type_names) == SRC_SAVE_PAGE_AS + 1,
download_type_enum_has_changed);
-COMPILE_ASSERT(ARRAYSIZE_UNSAFE(download_danger_names) ==
- DOWNLOAD_DANGER_TYPE_MAX,
+COMPILE_ASSERT(arraysize(download_danger_names) == DOWNLOAD_DANGER_TYPE_MAX,
download_danger_enum_has_changed);
} // namespace
diff --git a/chromium/content/browser/download/download_request_handle.h b/chromium/content/browser/download/download_request_handle.h
index de1d8ae83d1..76affae249e 100644
--- a/chromium/content/browser/download/download_request_handle.h
+++ b/chromium/content/browser/download/download_request_handle.h
@@ -45,7 +45,7 @@ class CONTENT_EXPORT DownloadRequestHandleInterface {
class CONTENT_EXPORT DownloadRequestHandle
: public DownloadRequestHandleInterface {
public:
- virtual ~DownloadRequestHandle();
+ ~DownloadRequestHandle() override;
// Create a null DownloadRequestHandle: getters will return null, and
// all actions are no-ops.
@@ -63,12 +63,12 @@ class CONTENT_EXPORT DownloadRequestHandle
int request_id);
// Implement DownloadRequestHandleInterface interface.
- virtual WebContents* GetWebContents() const OVERRIDE;
- virtual DownloadManager* GetDownloadManager() const OVERRIDE;
- virtual void PauseRequest() const OVERRIDE;
- virtual void ResumeRequest() const OVERRIDE;
- virtual void CancelRequest() const OVERRIDE;
- virtual std::string DebugString() const OVERRIDE;
+ WebContents* GetWebContents() const override;
+ DownloadManager* GetDownloadManager() const override;
+ void PauseRequest() const override;
+ void ResumeRequest() const override;
+ void CancelRequest() const override;
+ std::string DebugString() const override;
private:
base::WeakPtr<DownloadResourceHandler> handler_;
diff --git a/chromium/content/browser/download/download_resource_handler.cc b/chromium/content/browser/download/download_resource_handler.cc
index 0a19163c9c3..f2fb2a5b267 100644
--- a/chromium/content/browser/download/download_resource_handler.cc
+++ b/chromium/content/browser/download/download_resource_handler.cc
@@ -141,12 +141,9 @@ bool DownloadResourceHandler::OnUploadProgress(uint64 position,
}
bool DownloadResourceHandler::OnRequestRedirected(
- const GURL& url,
+ const net::RedirectInfo& redirect_info,
ResourceResponse* response,
bool* defer) {
- // We treat a download as a main frame load, and thus update the policy URL
- // on redirects.
- request()->set_first_party_for_cookies(url);
return true;
}
@@ -383,7 +380,10 @@ void DownloadResourceHandler::OnResponseCompleted(
// 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.
- reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED;
+ 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() &&
@@ -414,6 +414,10 @@ void DownloadResourceHandler::OnResponseCompleted(
// 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;
default: // All other errors.
// Redirection and informational codes should have been handled earlier
// in the stack.
diff --git a/chromium/content/browser/download/download_resource_handler.h b/chromium/content/browser/download/download_resource_handler.h
index de6efef2fe6..89587831496 100644
--- a/chromium/content/browser/download/download_resource_handler.h
+++ b/chromium/content/browser/download/download_resource_handler.h
@@ -9,7 +9,6 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
-#include "base/timer/timer.h"
#include "content/browser/loader/resource_handler.h"
#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_manager.h"
@@ -46,36 +45,35 @@ class CONTENT_EXPORT DownloadResourceHandler
const DownloadUrlParameters::OnStartedCallback& started_cb,
scoped_ptr<DownloadSaveInfo> save_info);
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
+ bool OnUploadProgress(uint64 position, uint64 size) override;
- virtual bool OnRequestRedirected(const GURL& url,
- ResourceResponse* response,
- bool* defer) OVERRIDE;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
// Send the download creation information to the download thread.
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
// Pass-through implementation.
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnWillStart(const GURL& url, bool* defer) override;
// Pass-through implementation.
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
// Create a new buffer, which will be handed to the download thread for file
// writing and deletion.
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
// N/A to this flavor of DownloadHandler.
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE;
+ void OnDataDownloaded(int bytes_downloaded) override;
void PauseRequest();
void ResumeRequest();
@@ -86,7 +84,7 @@ class CONTENT_EXPORT DownloadResourceHandler
std::string DebugString() const;
private:
- virtual ~DownloadResourceHandler();
+ ~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
diff --git a/chromium/content/browser/download/download_stats.cc b/chromium/content/browser/download/download_stats.cc
index 66716cac415..d88eef2c4e2 100644
--- a/chromium/content/browser/download/download_stats.cc
+++ b/chromium/content/browser/download/download_stats.cc
@@ -611,6 +611,18 @@ void RecordFileBandwidth(size_t length,
disk_write_time_ms * 100 / elapsed_time_ms);
}
+void RecordDownloadFileRenameResultAfterRetry(
+ base::TimeDelta time_since_first_failure,
+ DownloadInterruptReason interrupt_reason) {
+ if (interrupt_reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
+ UMA_HISTOGRAM_TIMES("Download.TimeToRenameSuccessAfterInitialFailure",
+ time_since_first_failure);
+ } else {
+ UMA_HISTOGRAM_TIMES("Download.TimeToRenameFailureAfterInitialFailure",
+ time_since_first_failure);
+ }
+}
+
void RecordSavePackageEvent(SavePackageEvent event) {
UMA_HISTOGRAM_ENUMERATION("Download.SavePackage",
event,
diff --git a/chromium/content/browser/download/download_stats.h b/chromium/content/browser/download/download_stats.h
index 65fad8d6b4a..3ae2612f8ea 100644
--- a/chromium/content/browser/download/download_stats.h
+++ b/chromium/content/browser/download/download_stats.h
@@ -200,6 +200,11 @@ void RecordFileBandwidth(size_t length,
base::TimeDelta disk_write_time,
base::TimeDelta elapsed_time);
+// Record the result of a download file rename.
+void RecordDownloadFileRenameResultAfterRetry(
+ base::TimeDelta time_since_first_failure,
+ DownloadInterruptReason interrupt_reason);
+
enum SavePackageEvent {
// The user has started to save a page as a package.
SAVE_PACKAGE_STARTED,
diff --git a/chromium/content/browser/download/drag_download_file.cc b/chromium/content/browser/download/drag_download_file.cc
index 29b8b5caa5c..ca68740a257 100644
--- a/chromium/content/browser/download/drag_download_file.cc
+++ b/chromium/content/browser/download/drag_download_file.cc
@@ -83,7 +83,7 @@ class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
}
private:
- virtual ~DragDownloadFileUI() {
+ ~DragDownloadFileUI() override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (download_item_)
download_item_->RemoveObserver(this);
@@ -103,7 +103,7 @@ class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
}
// DownloadItem::Observer:
- virtual void OnDownloadUpdated(DownloadItem* item) OVERRIDE {
+ void OnDownloadUpdated(DownloadItem* item) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(download_item_, item);
DownloadItem::DownloadState state = download_item_->GetState();
@@ -121,7 +121,7 @@ class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
// Ignore other states.
}
- virtual void OnDownloadDestroyed(DownloadItem* item) OVERRIDE {
+ void OnDownloadDestroyed(DownloadItem* item) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(download_item_, item);
if (!on_completed_.is_null()) {
diff --git a/chromium/content/browser/download/drag_download_file.h b/chromium/content/browser/download/drag_download_file.h
index 62e4ec2aa28..825f73668aa 100644
--- a/chromium/content/browser/download/drag_download_file.h
+++ b/chromium/content/browser/download/drag_download_file.h
@@ -42,15 +42,15 @@ class CONTENT_EXPORT DragDownloadFile : public ui::DownloadFileProvider {
WebContents* web_contents);
// DownloadFileProvider methods.
- virtual void Start(ui::DownloadFileObserver* observer) OVERRIDE;
- virtual bool Wait() OVERRIDE;
- virtual void Stop() OVERRIDE;
+ void Start(ui::DownloadFileObserver* observer) override;
+ bool Wait() override;
+ void Stop() override;
private:
class DragDownloadFileUI;
enum State {INITIALIZED, STARTED, SUCCESS, FAILURE};
- virtual ~DragDownloadFile();
+ ~DragDownloadFile() override;
void DownloadCompleted(bool is_successful);
void CheckThread();
diff --git a/chromium/content/browser/download/drag_download_file_browsertest.cc b/chromium/content/browser/download/drag_download_file_browsertest.cc
index 136fac3cf32..0b1de7d6fcd 100644
--- a/chromium/content/browser/download/drag_download_file_browsertest.cc
+++ b/chromium/content/browser/download/drag_download_file_browsertest.cc
@@ -4,6 +4,7 @@
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ref_counted.h"
#include "content/browser/download/download_file_factory.h"
#include "content/browser/download/download_file_impl.h"
#include "content/browser/download/download_item_impl.h"
@@ -21,8 +22,8 @@
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_download_manager_delegate.h"
-#include "content/test/net/url_request_mock_http_job.h"
#include "content/test/net/url_request_slow_download_job.h"
+#include "net/test/url_request/url_request_mock_http_job.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -48,7 +49,7 @@ class MockDownloadFileObserver : public ui::DownloadFileObserver {
class DragDownloadFileTest : public ContentBrowserTest {
public:
DragDownloadFileTest() {}
- virtual ~DragDownloadFileTest() {}
+ ~DragDownloadFileTest() override {}
void Succeed() {
BrowserThread::PostTask(BrowserThread::UI,
@@ -61,7 +62,7 @@ class DragDownloadFileTest : public ContentBrowserTest {
}
protected:
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
ShellDownloadManagerDelegate* delegate =
static_cast<ShellDownloadManagerDelegate*>(
@@ -73,8 +74,12 @@ class DragDownloadFileTest : public ContentBrowserTest {
void SetUpServer() {
base::FilePath mock_base(GetTestFilePath("download", ""));
BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&URLRequestMockHTTPJob::AddUrlHandler, mock_base));
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &net::URLRequestMockHTTPJob::AddUrlHandler,
+ mock_base,
+ make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
}
const base::FilePath& downloads_directory() const {
@@ -90,8 +95,8 @@ class DragDownloadFileTest : public ContentBrowserTest {
IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_NetError) {
base::FilePath name(downloads_directory().AppendASCII(
"DragDownloadFileTest_NetError.txt"));
- GURL url(URLRequestMockHTTPJob::GetMockUrl(base::FilePath(FILE_PATH_LITERAL(
- "download-test.lib"))));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(
+ base::FilePath(FILE_PATH_LITERAL("download-test.lib"))));
Referrer referrer;
std::string referrer_encoding;
scoped_refptr<DragDownloadFile> file(
@@ -110,8 +115,8 @@ IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_NetError) {
IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_Complete) {
base::FilePath name(downloads_directory().AppendASCII(
"DragDownloadFileTest_Complete.txt"));
- GURL url(URLRequestMockHTTPJob::GetMockUrl(base::FilePath(FILE_PATH_LITERAL(
- "download-test.lib"))));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(
+ base::FilePath(FILE_PATH_LITERAL("download-test.lib"))));
Referrer referrer;
std::string referrer_encoding;
SetUpServer();
diff --git a/chromium/content/browser/download/drag_download_util.h b/chromium/content/browser/download/drag_download_util.h
index 76b4e61068c..38b516c5854 100644
--- a/chromium/content/browser/download/drag_download_util.h
+++ b/chromium/content/browser/download/drag_download_util.h
@@ -45,11 +45,11 @@ class PromiseFileFinalizer : public ui::DownloadFileObserver {
explicit PromiseFileFinalizer(DragDownloadFile* drag_file_downloader);
// DownloadFileObserver methods.
- virtual void OnDownloadCompleted(const base::FilePath& file_path) OVERRIDE;
- virtual void OnDownloadAborted() OVERRIDE;
+ void OnDownloadCompleted(const base::FilePath& file_path) override;
+ void OnDownloadAborted() override;
protected:
- virtual ~PromiseFileFinalizer();
+ ~PromiseFileFinalizer() override;
private:
void Cleanup();
diff --git a/chromium/content/browser/download/file_metadata_linux.cc b/chromium/content/browser/download/file_metadata_linux.cc
index c06d3f1a90f..1864d29a717 100644
--- a/chromium/content/browser/download/file_metadata_linux.cc
+++ b/chromium/content/browser/download/file_metadata_linux.cc
@@ -7,8 +7,8 @@
#include <sys/types.h>
#include <sys/xattr.h>
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "url/gurl.h"
diff --git a/chromium/content/browser/download/file_metadata_unittest_linux.cc b/chromium/content/browser/download/file_metadata_unittest_linux.cc
index 96db2646470..ab7eb3c8044 100644
--- a/chromium/content/browser/download/file_metadata_unittest_linux.cc
+++ b/chromium/content/browser/download/file_metadata_unittest_linux.cc
@@ -10,8 +10,8 @@
#include <sstream>
#include <string>
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/strings/string_split.h"
@@ -50,7 +50,7 @@ class FileMetadataLinuxTest : public testing::Test {
}
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &test_file_));
int result = setxattr(test_file_.value().c_str(),
diff --git a/chromium/content/browser/download/mhtml_generation_browsertest.cc b/chromium/content/browser/download/mhtml_generation_browsertest.cc
index 283e53ac1e0..fbe9a1f6db9 100644
--- a/chromium/content/browser/download/mhtml_generation_browsertest.cc
+++ b/chromium/content/browser/download/mhtml_generation_browsertest.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "content/public/browser/web_contents.h"
@@ -28,7 +28,7 @@ class MHTMLGenerationTest : public ContentBrowserTest {
}
protected:
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ContentBrowserTest::SetUp();
}
diff --git a/chromium/content/browser/download/mhtml_generation_manager.cc b/chromium/content/browser/download/mhtml_generation_manager.cc
index db4ba30533f..d02d509996a 100644
--- a/chromium/content/browser/download/mhtml_generation_manager.cc
+++ b/chromium/content/browser/download/mhtml_generation_manager.cc
@@ -19,7 +19,7 @@ namespace content {
class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
public:
Job();
- virtual ~Job();
+ ~Job() override;
void SetWebContents(WebContents* web_contents);
@@ -33,12 +33,10 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
void set_callback(GenerateMHTMLCallback callback) { callback_ = callback; }
// RenderProcessHostObserver:
- virtual void RenderProcessExited(RenderProcessHost* host,
- base::ProcessHandle handle,
- base::TerminationStatus status,
- int exit_code) OVERRIDE;
- virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE;
-
+ void RenderProcessExited(RenderProcessHost* host,
+ base::TerminationStatus status,
+ int exit_code) override;
+ void RenderProcessHostDestroyed(RenderProcessHost* host) override;
private:
// The handle to the file the MHTML is saved to for the browser process.
@@ -76,7 +74,6 @@ void MHTMLGenerationManager::Job::SetWebContents(WebContents* web_contents) {
void MHTMLGenerationManager::Job::RenderProcessExited(
RenderProcessHost* host,
- base::ProcessHandle handle,
base::TerminationStatus status,
int exit_code) {
MHTMLGenerationManager::GetInstance()->RenderProcessExited(this);
diff --git a/chromium/content/browser/download/save_file_manager.cc b/chromium/content/browser/download/save_file_manager.cc
index 80ab95eefd0..e9c03f484ff 100644
--- a/chromium/content/browser/download/save_file_manager.cc
+++ b/chromium/content/browser/download/save_file_manager.cc
@@ -7,7 +7,7 @@
#include "content/browser/download/save_file_manager.h"
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
diff --git a/chromium/content/browser/download/save_file_resource_handler.cc b/chromium/content/browser/download/save_file_resource_handler.cc
index e1fc32b7fc4..17c29ed6593 100644
--- a/chromium/content/browser/download/save_file_resource_handler.cc
+++ b/chromium/content/browser/download/save_file_resource_handler.cc
@@ -11,6 +11,7 @@
#include "content/browser/download/save_file_manager.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
+#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request_status.h"
namespace content {
@@ -37,10 +38,10 @@ bool SaveFileResourceHandler::OnUploadProgress(uint64 position, uint64 size) {
}
bool SaveFileResourceHandler::OnRequestRedirected(
- const GURL& url,
+ const net::RedirectInfo& redirect_info,
ResourceResponse* response,
bool* defer) {
- final_url_ = url;
+ final_url_ = redirect_info.new_url;
return true;
}
diff --git a/chromium/content/browser/download/save_file_resource_handler.h b/chromium/content/browser/download/save_file_resource_handler.h
index 5adbc5c229a..b7425b49b01 100644
--- a/chromium/content/browser/download/save_file_resource_handler.h
+++ b/chromium/content/browser/download/save_file_resource_handler.h
@@ -26,42 +26,41 @@ class SaveFileResourceHandler : public ResourceHandler {
int render_view_id,
const GURL& url,
SaveFileManager* manager);
- virtual ~SaveFileResourceHandler();
+ ~SaveFileResourceHandler() override;
// ResourceHandler Implementation:
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
+ bool OnUploadProgress(uint64 position, uint64 size) override;
// Saves the redirected URL to final_url_, we need to use the original
// URL to match original request.
- virtual bool OnRequestRedirected(const GURL& url,
- ResourceResponse* response,
- bool* defer) OVERRIDE;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
// Sends the download creation information to the download thread.
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
// Pass-through implementation.
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnWillStart(const GURL& url, bool* defer) override;
// Pass-through implementation.
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
// Creates a new buffer, which will be handed to the download thread for file
// writing and deletion.
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
// Passes the buffer to the download file writer.
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
// N/A to this flavor of SaveFileResourceHandler.
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE;
+ void OnDataDownloaded(int bytes_downloaded) override;
// If the content-length header is not present (or contains something other
// than numbers), StringToInt64 returns 0, which indicates 'unknown size' and
diff --git a/chromium/content/browser/download/save_package.cc b/chromium/content/browser/download/save_package.cc
index 90ab2a5056d..486cb1057d1 100644
--- a/chromium/content/browser/download/save_package.cc
+++ b/chromium/content/browser/download/save_package.cc
@@ -7,8 +7,8 @@
#include <algorithm>
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/i18n/file_util_icu.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
@@ -113,16 +113,14 @@ class SavePackageRequestHandle : public DownloadRequestHandleInterface {
: save_package_(save_package) {}
// DownloadRequestHandleInterface
- virtual WebContents* GetWebContents() const OVERRIDE {
+ WebContents* GetWebContents() const override {
return save_package_.get() ? save_package_->web_contents() : NULL;
}
- virtual DownloadManager* GetDownloadManager() const OVERRIDE {
- return NULL;
- }
- virtual void PauseRequest() const OVERRIDE {}
- virtual void ResumeRequest() const OVERRIDE {}
- virtual void CancelRequest() const OVERRIDE {}
- virtual std::string DebugString() const OVERRIDE {
+ DownloadManager* GetDownloadManager() const override { return NULL; }
+ void PauseRequest() const override {}
+ void ResumeRequest() const override {}
+ void CancelRequest() const override {}
+ std::string DebugString() const override {
return "SavePackage DownloadRequestHandle";
}
@@ -133,11 +131,7 @@ class SavePackageRequestHandle : public DownloadRequestHandleInterface {
} // namespace
const base::FilePath::CharType SavePackage::kDefaultHtmlExtension[] =
-#if defined(OS_WIN)
- FILE_PATH_LITERAL("htm");
-#else
FILE_PATH_LITERAL("html");
-#endif
SavePackage::SavePackage(WebContents* web_contents,
SavePageType save_type,
@@ -471,7 +465,7 @@ bool SavePackage::GenerateFileName(const std::string& disposition,
file_path.RemoveExtension().BaseName().value();
base::FilePath::StringType file_name_ext = file_path.Extension();
- // If it is HTML resource, use ".htm{l,}" as its extension.
+ // If it is HTML resource, use ".html" as its extension.
if (need_html_ext) {
file_name_ext = FILE_PATH_LITERAL(".");
file_name_ext.append(kDefaultHtmlExtension);
@@ -1248,7 +1242,7 @@ base::FilePath SavePackage::GetSuggestedNameForSaveAs(
name_with_proper_ext = EnsureHtmlExtension(name_with_proper_ext);
base::FilePath::StringType file_name = name_with_proper_ext.value();
- file_util::ReplaceIllegalCharactersInPath(&file_name, ' ');
+ base::i18n::ReplaceIllegalCharactersInPath(&file_name, ' ');
return base::FilePath(file_name);
}
@@ -1301,17 +1295,13 @@ const base::FilePath::CharType* SavePackage::ExtensionForMimeType(
#elif defined(OS_WIN)
base::FilePath::StringType mime_type(base::UTF8ToWide(contents_mime_type));
#endif // OS_WIN
- for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(extensions); ++i) {
+ for (uint32 i = 0; i < arraysize(extensions); ++i) {
if (mime_type == extensions[i].mime_type)
return extensions[i].suggested_extension;
}
return FILE_PATH_LITERAL("");
}
-WebContents* SavePackage::web_contents() const {
- return WebContentsObserver::web_contents();
-}
-
void SavePackage::GetSaveInfo() {
// Can't use web_contents_ in the file thread, so get the data that we need
// before calling to it.
diff --git a/chromium/content/browser/download/save_package.h b/chromium/content/browser/download/save_package.h
index 1ab429e16b9..3507b1760b4 100644
--- a/chromium/content/browser/download/save_package.h
+++ b/chromium/content/browser/download/save_package.h
@@ -117,7 +117,6 @@ class CONTENT_EXPORT SavePackage
SavePageType save_type() const { return save_type_; }
int contents_id() const { return contents_id_; }
int id() const { return unique_id_; }
- WebContents* web_contents() const;
void GetSaveInfo();
@@ -136,7 +135,7 @@ class CONTENT_EXPORT SavePackage
const base::FilePath& file_full_path,
const base::FilePath& directory_full_path);
- virtual ~SavePackage();
+ ~SavePackage() override;
// Notes from Init() above applies here as well.
void InternalInit();
@@ -147,10 +146,10 @@ class CONTENT_EXPORT SavePackage
void DoSavingProcess();
// WebContentsObserver implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
// DownloadItem::Observer implementation.
- virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE;
+ void OnDownloadDestroyed(DownloadItem* download) override;
// Update the download history of this item upon completion.
void FinalizeDownloadEntry();
diff --git a/chromium/content/browser/download/save_package_browsertest.cc b/chromium/content/browser/download/save_package_browsertest.cc
index 2c7a652dd0d..5b3bc173634 100644
--- a/chromium/content/browser/download/save_package_browsertest.cc
+++ b/chromium/content/browser/download/save_package_browsertest.cc
@@ -14,7 +14,7 @@ const char kTestFile[] = "files/simple_page.html";
class SavePackageBrowserTest : public ContentBrowserTest {
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(save_dir_.CreateUniqueTempDir());
ContentBrowserTest::SetUp();
}
diff --git a/chromium/content/browser/download/save_package_unittest.cc b/chromium/content/browser/download/save_package_unittest.cc
index b0e38c0f18d..c0dcbf0a7eb 100644
--- a/chromium/content/browser/download/save_package_unittest.cc
+++ b/chromium/content/browser/download/save_package_unittest.cc
@@ -6,25 +6,23 @@
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/download/save_package.h"
-#include "content/test/net/url_request_mock_http_job.h"
+#include "content/public/common/url_constants.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
+#include "net/test/url_request/url_request_mock_http_job.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace content {
#define FPL FILE_PATH_LITERAL
+#define HTML_EXTENSION ".html"
#if defined(OS_WIN)
-#define HTML_EXTENSION ".htm"
-// This second define is needed because MSVC is broken.
-#define FPL_HTML_EXTENSION L".htm"
+#define FPL_HTML_EXTENSION L".html"
#else
-#define HTML_EXTENSION ".html"
#define FPL_HTML_EXTENSION ".html"
#endif
@@ -95,7 +93,7 @@ class SavePackageTest : public RenderViewHostImplTestHarness {
}
protected:
- virtual void SetUp() {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
// Do the initialization in SetUp so contents() is initialized by
@@ -176,7 +174,7 @@ static const struct {
};
TEST_F(SavePackageTest, TestSuccessfullyGenerateSavePackageFilename) {
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) {
+ for (size_t i = 0; i < arraysize(kGeneratedFiles); ++i) {
base::FilePath::StringType file_name;
bool ok = GetGeneratedFilename(true,
kGeneratedFiles[i].disposition,
@@ -189,7 +187,7 @@ TEST_F(SavePackageTest, TestSuccessfullyGenerateSavePackageFilename) {
}
TEST_F(SavePackageTest, TestUnSuccessfullyGenerateSavePackageFilename) {
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGeneratedFiles); ++i) {
+ for (size_t i = 0; i < arraysize(kGeneratedFiles); ++i) {
base::FilePath::StringType file_name;
bool ok = GetGeneratedFilename(false,
kGeneratedFiles[i].disposition,
@@ -244,7 +242,7 @@ TEST_F(SavePackageTest, MAYBE_TestLongSafePureFilename) {
const base::FilePath::StringType ext(FPL_HTML_EXTENSION);
base::FilePath::StringType filename =
#if defined(OS_WIN)
- base::ASCIIToWide(long_file_name);
+ base::ASCIIToUTF16(long_file_name);
#else
long_file_name;
#endif
@@ -282,7 +280,7 @@ static const struct {
#define MAYBE_TestEnsureHtmlExtension TestEnsureHtmlExtension
#endif
TEST_F(SavePackageTest, MAYBE_TestEnsureHtmlExtension) {
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExtensionTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kExtensionTestCases); ++i) {
base::FilePath original = base::FilePath(kExtensionTestCases[i].page_title);
base::FilePath expected =
base::FilePath(kExtensionTestCases[i].expected_name);
@@ -327,7 +325,7 @@ TEST_F(SavePackageTest, MAYBE_TestEnsureMimeExtension) {
{ FPL("filename.abc"), FPL("filename.abc"), "unknown/unknown" },
{ FPL("filename"), FPL("filename"), "unknown/unknown" },
};
- for (uint32 i = 0; i < ARRAYSIZE_UNSAFE(kExtensionTests); ++i) {
+ for (uint32 i = 0; i < arraysize(kExtensionTests); ++i) {
base::FilePath original = base::FilePath(kExtensionTests[i].page_title);
base::FilePath expected = base::FilePath(kExtensionTests[i].expected_name);
std::string mime_type(kExtensionTests[i].contents_mime_type);
@@ -416,8 +414,8 @@ static const base::FilePath::CharType* kTestDir =
// GetUrlToBeSaved method should return correct url to be saved.
TEST_F(SavePackageTest, TestGetUrlToBeSaved) {
base::FilePath file_name(FILE_PATH_LITERAL("a.htm"));
- GURL url = URLRequestMockHTTPJob::GetMockUrl(
- base::FilePath(kTestDir).Append(file_name));
+ GURL url = net::URLRequestMockHTTPJob::GetMockUrl(
+ base::FilePath(kTestDir).Append(file_name));
NavigateAndCommit(url);
EXPECT_EQ(url, GetUrlToBeSaved());
}
@@ -428,10 +426,12 @@ TEST_F(SavePackageTest, TestGetUrlToBeSaved) {
// when user types view-source:http://www.google.com
TEST_F(SavePackageTest, TestGetUrlToBeSavedViewSource) {
base::FilePath file_name(FILE_PATH_LITERAL("a.htm"));
- GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl(
- base::FilePath(kTestDir).Append(file_name));
- GURL actual_url = URLRequestMockHTTPJob::GetMockUrl(
- base::FilePath(kTestDir).Append(file_name));
+ GURL mock_url = net::URLRequestMockHTTPJob::GetMockUrl(
+ base::FilePath(kTestDir).Append(file_name));
+ GURL view_source_url =
+ GURL(kViewSourceScheme + std::string(":") + mock_url.spec());
+ GURL actual_url = net::URLRequestMockHTTPJob::GetMockUrl(
+ base::FilePath(kTestDir).Append(file_name));
NavigateAndCommit(view_source_url);
EXPECT_EQ(actual_url, GetUrlToBeSaved());
EXPECT_EQ(view_source_url, contents()->GetLastCommittedURL());
diff --git a/chromium/content/browser/file_descriptor_info_impl.cc b/chromium/content/browser/file_descriptor_info_impl.cc
new file mode 100644
index 00000000000..c1f055bc76d
--- /dev/null
+++ b/chromium/content/browser/file_descriptor_info_impl.cc
@@ -0,0 +1,69 @@
+// 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/file_descriptor_info_impl.h"
+
+namespace content {
+
+// static
+scoped_ptr<FileDescriptorInfo> FileDescriptorInfoImpl::Create() {
+ return scoped_ptr<FileDescriptorInfo>(new FileDescriptorInfoImpl());
+}
+
+FileDescriptorInfoImpl::FileDescriptorInfoImpl() {
+}
+
+FileDescriptorInfoImpl::~FileDescriptorInfoImpl() {
+}
+
+void FileDescriptorInfoImpl::Share(int id, base::PlatformFile fd) {
+ AddToMapping(id, fd);
+}
+
+void FileDescriptorInfoImpl::Transfer(int id, base::ScopedFD fd) {
+ AddToMapping(id, fd.get());
+ owned_descriptors_.push_back(new base::ScopedFD(fd.Pass()));
+}
+
+base::PlatformFile FileDescriptorInfoImpl::GetFDAt(size_t i) const {
+ return mapping_[i].first;
+}
+
+int FileDescriptorInfoImpl::GetIDAt(size_t i) const {
+ return mapping_[i].second;
+}
+
+size_t FileDescriptorInfoImpl::GetMappingSize() const {
+ return mapping_.size();
+}
+
+bool FileDescriptorInfoImpl::HasID(int id) const {
+ for (unsigned i = 0; i < mapping_.size(); ++i) {
+ if (mapping_[i].second == id)
+ return true;
+ }
+
+ return false;
+}
+
+void FileDescriptorInfoImpl::AddToMapping(int id, base::PlatformFile fd) {
+ DCHECK(!HasID(id));
+ mapping_.push_back(std::make_pair(fd, id));
+}
+
+const base::FileHandleMappingVector& FileDescriptorInfoImpl::GetMapping()
+ const {
+ return mapping_;
+}
+
+base::FileHandleMappingVector
+FileDescriptorInfoImpl::GetMappingWithIDAdjustment(int delta) const {
+ base::FileHandleMappingVector result = mapping_;
+ // Adding delta to each ID.
+ for (unsigned i = 0; i < mapping_.size(); ++i)
+ result[i].second += delta;
+ return result;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/file_descriptor_info_impl.h b/chromium/content/browser/file_descriptor_info_impl.h
new file mode 100644
index 00000000000..78d746e22d4
--- /dev/null
+++ b/chromium/content/browser/file_descriptor_info_impl.h
@@ -0,0 +1,39 @@
+// 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_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
+#define CONTENT_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/file_descriptor_info.h"
+
+namespace content {
+
+class FileDescriptorInfoImpl : public FileDescriptorInfo {
+ public:
+ CONTENT_EXPORT static scoped_ptr<FileDescriptorInfo> Create();
+
+ ~FileDescriptorInfoImpl() override;
+ void Share(int id, base::PlatformFile fd) override;
+ void Transfer(int id, base::ScopedFD fd) override;
+ const base::FileHandleMappingVector& GetMapping() const override;
+ base::FileHandleMappingVector GetMappingWithIDAdjustment(
+ int delta) const override;
+ base::PlatformFile GetFDAt(size_t i) const override;
+ int GetIDAt(size_t i) const override;
+ size_t GetMappingSize() const override;
+
+ private:
+ FileDescriptorInfoImpl();
+
+ void AddToMapping(int id, base::PlatformFile fd);
+ bool HasID(int id) const;
+ base::FileHandleMappingVector mapping_;
+ ScopedVector<base::ScopedFD> owned_descriptors_;
+};
+}
+
+#endif // CONTENT_PUBLIC_BROWSER_FILE_DESCRIPTOR_INFO_IMPL_H_
diff --git a/chromium/content/browser/file_descriptor_info_impl_unittest.cc b/chromium/content/browser/file_descriptor_info_impl_unittest.cc
new file mode 100644
index 00000000000..9724a7cff64
--- /dev/null
+++ b/chromium/content/browser/file_descriptor_info_impl_unittest.cc
@@ -0,0 +1,86 @@
+// 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/file_descriptor_info_impl.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/posix/eintr_wrapper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Get a safe file descriptor for test purposes.
+// TODO(morrita) Merge with things in file_descriptor_set_posix_unittest.cc
+int GetSafeFd() {
+ return open("/dev/null", O_RDONLY);
+}
+
+// Returns true if fd was already closed. Closes fd if not closed.
+// TODO(morrita) Merge with things in file_descriptor_set_posix_unittest.cc
+bool VerifyClosed(int fd) {
+ const int duped = dup(fd);
+ if (duped != -1) {
+ EXPECT_NE(IGNORE_EINTR(close(duped)), -1);
+ EXPECT_NE(IGNORE_EINTR(close(fd)), -1);
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+namespace content {
+
+typedef testing::Test FileDescriptorInfoTest;
+
+TEST_F(FileDescriptorInfoTest, Transfer) {
+ int testingId = 42;
+ scoped_ptr<FileDescriptorInfo> target(FileDescriptorInfoImpl::Create());
+ base::ScopedFD fd(GetSafeFd());
+
+ int raw_fd = fd.get();
+ target->Transfer(testingId, fd.Pass());
+ ASSERT_EQ(1U, target->GetMappingSize());
+ ASSERT_EQ(target->GetFDAt(0), raw_fd);
+ ASSERT_EQ(target->GetIDAt(0), testingId);
+
+ target.reset();
+
+ ASSERT_TRUE(VerifyClosed(raw_fd));
+}
+
+TEST_F(FileDescriptorInfoTest, Share) {
+ int testingId = 42;
+ scoped_ptr<FileDescriptorInfo> target(FileDescriptorInfoImpl::Create());
+ base::ScopedFD fd(GetSafeFd());
+
+ int raw_fd = fd.get();
+ target->Share(testingId, fd.get());
+ ASSERT_EQ(1U, target->GetMappingSize());
+ ASSERT_EQ(target->GetFDAt(0), raw_fd);
+ ASSERT_EQ(target->GetIDAt(0), testingId);
+
+ target.reset();
+
+ ASSERT_TRUE(!VerifyClosed(fd.release()));
+}
+
+TEST_F(FileDescriptorInfoTest, GetMappingWithIDAdjustment) {
+ int testingId1 = 42;
+ int testingId2 = 43;
+ scoped_ptr<FileDescriptorInfo> target(FileDescriptorInfoImpl::Create());
+
+ target->Transfer(testingId1, base::ScopedFD(GetSafeFd()));
+ target->Transfer(testingId2, base::ScopedFD(GetSafeFd()));
+
+ base::FileHandleMappingVector mapping =
+ target->GetMappingWithIDAdjustment(100);
+ ASSERT_EQ(mapping[0].second, 142);
+ ASSERT_EQ(mapping[1].second, 143);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/fileapi/OWNERS b/chromium/content/browser/fileapi/OWNERS
index f7cc33cc7c2..43601cc9435 100644
--- a/chromium/content/browser/fileapi/OWNERS
+++ b/chromium/content/browser/fileapi/OWNERS
@@ -1,4 +1,5 @@
-ericu@chromium.org
kinuko@chromium.org
michaeln@chromium.org
jianli@chromium.org
+tzik@chromium.org
+nhiroki@chromium.org
diff --git a/chromium/content/browser/fileapi/blob_storage_context_unittest.cc b/chromium/content/browser/fileapi/blob_storage_context_unittest.cc
index 823679e585c..6ac1832894c 100644
--- a/chromium/content/browser/fileapi/blob_storage_context_unittest.cc
+++ b/chromium/content/browser/fileapi/blob_storage_context_unittest.cc
@@ -9,11 +9,11 @@
#include "base/run_loop.h"
#include "base/time/time.h"
#include "content/browser/fileapi/blob_storage_host.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-using webkit_blob::BlobDataHandle;
+using storage::BlobDataHandle;
namespace content {
diff --git a/chromium/content/browser/fileapi/blob_storage_host.cc b/chromium/content/browser/fileapi/blob_storage_host.cc
index cc51dbb37a7..87e675ce5d1 100644
--- a/chromium/content/browser/fileapi/blob_storage_host.cc
+++ b/chromium/content/browser/fileapi/blob_storage_host.cc
@@ -6,12 +6,12 @@
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
#include "url/gurl.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-using webkit_blob::BlobStorageContext;
-using webkit_blob::BlobData;
+using storage::BlobStorageContext;
+using storage::BlobData;
namespace content {
diff --git a/chromium/content/browser/fileapi/blob_storage_host.h b/chromium/content/browser/fileapi/blob_storage_host.h
index 5d10d204dce..3544f398b7d 100644
--- a/chromium/content/browser/fileapi/blob_storage_host.h
+++ b/chromium/content/browser/fileapi/blob_storage_host.h
@@ -12,18 +12,18 @@
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
-#include "webkit/common/blob/blob_data.h"
+#include "storage/common/blob/blob_data.h"
class GURL;
-namespace webkit_blob {
+namespace storage {
class BlobDataHandle;
class BlobStorageHost;
class BlobStorageContext;
}
-using webkit_blob::BlobStorageContext;
-using webkit_blob::BlobData;
+using storage::BlobStorageContext;
+using storage::BlobData;
namespace content {
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 5ce43121433..79824772be6 100644
--- a/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc
+++ b/chromium/content/browser/fileapi/blob_url_request_job_unittest.cc
@@ -4,8 +4,8 @@
#include "base/basictypes.h"
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -22,15 +22,15 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job_factory_impl.h"
+#include "storage/browser/blob/blob_url_request_job.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/common/blob/blob_data.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/blob/blob_url_request_job.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/common/blob/blob_data.h"
-using webkit_blob::BlobData;
-using webkit_blob::BlobURLRequestJob;
+using storage::BlobData;
+using storage::BlobURLRequestJob;
namespace content {
@@ -47,8 +47,8 @@ const char kTestContentType[] = "foo/bar";
const char kTestContentDisposition[] = "attachment; filename=foo.txt";
const char kFileSystemURLOrigin[] = "http://remote";
-const fileapi::FileSystemType kFileSystemType =
- fileapi::kFileSystemTypeTemporary;
+const storage::FileSystemType kFileSystemType =
+ storage::kFileSystemTypeTemporary;
} // namespace
@@ -61,9 +61,9 @@ class BlobURLRequestJobTest : public testing::Test {
MockProtocolHandler(BlobURLRequestJobTest* test) : test_(test) {}
// net::URLRequestJobFactory::ProtocolHandler override.
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
return new BlobURLRequestJob(request,
network_delegate,
test_->blob_data_.get(),
@@ -79,7 +79,7 @@ class BlobURLRequestJobTest : public testing::Test {
: blob_data_(new BlobData()),
expected_status_code_(0) {}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
temp_file1_ = temp_dir_.path().AppendASCII("BlobFile1.dat");
@@ -103,8 +103,7 @@ class BlobURLRequestJobTest : public testing::Test {
url_request_context_.set_job_factory(&url_request_job_factory_);
}
- virtual void TearDown() {
- }
+ void TearDown() override {}
void SetUpFileSystem() {
// Prepare file system.
@@ -114,7 +113,7 @@ class BlobURLRequestJobTest : public testing::Test {
file_system_context_->OpenFileSystem(
GURL(kFileSystemURLOrigin),
kFileSystemType,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&BlobURLRequestJobTest::OnValidateFileSystem,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
@@ -140,7 +139,7 @@ class BlobURLRequestJobTest : public testing::Test {
void WriteFileSystemFile(const std::string& filename,
const char* buf, int buf_size,
base::Time* modification_time) {
- fileapi::FileSystemURL url =
+ storage::FileSystemURL url =
file_system_context_->CreateCrackedFileSystemURL(
GURL(kFileSystemURLOrigin),
kFileSystemType,
@@ -148,12 +147,12 @@ class BlobURLRequestJobTest : public testing::Test {
ASSERT_EQ(base::File::FILE_OK,
content::AsyncFileTestHelper::CreateFileWithData(
- file_system_context_, url, buf, buf_size));
+ file_system_context_.get(), url, buf, buf_size));
base::File::Info file_info;
ASSERT_EQ(base::File::FILE_OK,
content::AsyncFileTestHelper::GetMetadata(
- file_system_context_, url, &file_info));
+ file_system_context_.get(), url, &file_info));
if (modification_time)
*modification_time = file_info.last_modified;
}
@@ -243,7 +242,7 @@ class BlobURLRequestJobTest : public testing::Test {
base::Time temp_file_system_file_modification_time2_;
base::MessageLoopForIO message_loop_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
scoped_refptr<BlobData> blob_data_;
net::URLRequestJobFactoryImpl url_request_job_factory_;
net::URLRequestContext url_request_context_;
@@ -260,7 +259,7 @@ TEST_F(BlobURLRequestJobTest, TestGetSimpleDataRequest) {
}
TEST_F(BlobURLRequestJobTest, TestGetSimpleFileRequest) {
- blob_data_->AppendFile(temp_file1_, 0, -1, base::Time());
+ blob_data_->AppendFile(temp_file1_, 0, kuint64max, base::Time());
TestSuccessNonrangeRequest(kTestFileData1, arraysize(kTestFileData1) - 1);
}
@@ -274,14 +273,14 @@ TEST_F(BlobURLRequestJobTest, TestGetLargeFileRequest) {
ASSERT_EQ(static_cast<int>(large_data.size()),
base::WriteFile(large_temp_file, large_data.data(),
large_data.size()));
- blob_data_->AppendFile(large_temp_file, 0, -1, base::Time());
+ blob_data_->AppendFile(large_temp_file, 0, kuint64max, base::Time());
TestSuccessNonrangeRequest(large_data, large_data.size());
}
TEST_F(BlobURLRequestJobTest, TestGetNonExistentFileRequest) {
base::FilePath non_existent_file =
temp_file1_.InsertBeforeExtension(FILE_PATH_LITERAL("-na"));
- blob_data_->AppendFile(non_existent_file, 0, -1, base::Time());
+ blob_data_->AppendFile(non_existent_file, 0, kuint64max, base::Time());
TestErrorRequest(404);
}
@@ -300,7 +299,7 @@ TEST_F(BlobURLRequestJobTest, TestGetSlicedFileRequest) {
TEST_F(BlobURLRequestJobTest, TestGetSimpleFileSystemFileRequest) {
SetUpFileSystem();
- blob_data_->AppendFileSystemFile(temp_file_system_file1_, 0, -1,
+ blob_data_->AppendFileSystemFile(temp_file_system_file1_, 0, kuint64max,
base::Time());
TestSuccessNonrangeRequest(kTestFileSystemFileData1,
arraysize(kTestFileSystemFileData1) - 1);
@@ -316,7 +315,7 @@ TEST_F(BlobURLRequestJobTest, TestGetLargeFileSystemFileRequest) {
const char kFilename[] = "LargeBlob.dat";
WriteFileSystemFile(kFilename, large_data.data(), large_data.size(), NULL);
- blob_data_->AppendFileSystemFile(GetFileSystemURL(kFilename), 0, -1,
+ blob_data_->AppendFileSystemFile(GetFileSystemURL(kFilename), 0, kuint64max,
base::Time());
TestSuccessNonrangeRequest(large_data, large_data.size());
}
@@ -324,7 +323,8 @@ TEST_F(BlobURLRequestJobTest, TestGetLargeFileSystemFileRequest) {
TEST_F(BlobURLRequestJobTest, TestGetNonExistentFileSystemFileRequest) {
SetUpFileSystem();
GURL non_existent_file = GetFileSystemURL("non-existent.dat");
- blob_data_->AppendFileSystemFile(non_existent_file, 0, -1, base::Time());
+ blob_data_->AppendFileSystemFile(non_existent_file, 0, kuint64max,
+ base::Time());
TestErrorRequest(404);
}
diff --git a/chromium/content/browser/fileapi/browser_file_system_helper.cc b/chromium/content/browser/fileapi/browser_file_system_helper.cc
index d89d6cab25b..b3221612116 100644
--- a/chromium/content/browser/fileapi/browser_file_system_helper.cc
+++ b/chromium/content/browser/fileapi/browser_file_system_helper.cc
@@ -17,20 +17,20 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
+#include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/file_permission_policy.h"
+#include "storage/browser/fileapi/file_system_backend.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/browser/fileapi/file_system_options.h"
+#include "storage/browser/quota/quota_manager.h"
#include "url/url_constants.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
-#include "webkit/browser/fileapi/file_permission_policy.h"
-#include "webkit/browser/fileapi/file_system_backend.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-#include "webkit/browser/fileapi/file_system_options.h"
-#include "webkit/browser/quota/quota_manager.h"
namespace content {
namespace {
-using fileapi::FileSystemOptions;
+using storage::FileSystemOptions;
FileSystemOptions CreateBrowserFileSystemOptions(bool is_incognito) {
FileSystemOptions::ProfileMode profile_mode =
@@ -48,12 +48,11 @@ FileSystemOptions CreateBrowserFileSystemOptions(bool is_incognito) {
} // namespace
-scoped_refptr<fileapi::FileSystemContext> CreateFileSystemContext(
+scoped_refptr<storage::FileSystemContext> CreateFileSystemContext(
BrowserContext* browser_context,
const base::FilePath& profile_path,
bool is_incognito,
- quota::QuotaManagerProxy* quota_manager_proxy) {
-
+ storage::QuotaManagerProxy* quota_manager_proxy) {
base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
scoped_refptr<base::SequencedTaskRunner> file_task_runner =
pool->GetSequencedTaskRunnerWithShutdownBehavior(
@@ -61,20 +60,20 @@ scoped_refptr<fileapi::FileSystemContext> CreateFileSystemContext(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
// Setting up additional filesystem backends.
- ScopedVector<fileapi::FileSystemBackend> additional_backends;
+ ScopedVector<storage::FileSystemBackend> additional_backends;
GetContentClient()->browser()->GetAdditionalFileSystemBackends(
browser_context,
profile_path,
&additional_backends);
// Set up the auto mount handlers for url requests.
- std::vector<fileapi::URLRequestAutoMountHandler>
+ std::vector<storage::URLRequestAutoMountHandler>
url_request_auto_mount_handlers;
GetContentClient()->browser()->GetURLRequestAutoMountHandlers(
&url_request_auto_mount_handlers);
- scoped_refptr<fileapi::FileSystemContext> file_system_context =
- new fileapi::FileSystemContext(
+ scoped_refptr<storage::FileSystemContext> file_system_context =
+ new storage::FileSystemContext(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(),
file_task_runner.get(),
BrowserContext::GetMountPoints(browser_context),
@@ -85,28 +84,27 @@ scoped_refptr<fileapi::FileSystemContext> CreateFileSystemContext(
profile_path,
CreateBrowserFileSystemOptions(is_incognito));
- std::vector<fileapi::FileSystemType> types;
+ std::vector<storage::FileSystemType> types;
file_system_context->GetFileSystemTypes(&types);
for (size_t i = 0; i < types.size(); ++i) {
- ChildProcessSecurityPolicyImpl::GetInstance()->
- RegisterFileSystemPermissionPolicy(
+ ChildProcessSecurityPolicyImpl::GetInstance()
+ ->RegisterFileSystemPermissionPolicy(
types[i],
- fileapi::FileSystemContext::GetPermissionPolicy(types[i]));
+ storage::FileSystemContext::GetPermissionPolicy(types[i]));
}
return file_system_context;
}
-bool FileSystemURLIsValid(
- fileapi::FileSystemContext* context,
- const fileapi::FileSystemURL& url) {
+bool FileSystemURLIsValid(storage::FileSystemContext* context,
+ const storage::FileSystemURL& url) {
if (!url.is_valid())
return false;
return context->GetFileSystemBackend(url.type()) != NULL;
}
-void SyncGetPlatformPath(fileapi::FileSystemContext* context,
+void SyncGetPlatformPath(storage::FileSystemContext* context,
int process_id,
const GURL& path,
base::FilePath* platform_path) {
@@ -114,7 +112,7 @@ void SyncGetPlatformPath(fileapi::FileSystemContext* context,
RunsTasksOnCurrentThread());
DCHECK(platform_path);
*platform_path = base::FilePath();
- fileapi::FileSystemURL url(context->CrackURL(path));
+ storage::FileSystemURL url(context->CrackURL(path));
if (!FileSystemURLIsValid(context, url))
return;
diff --git a/chromium/content/browser/fileapi/browser_file_system_helper.h b/chromium/content/browser/fileapi/browser_file_system_helper.h
index ad44ced5064..de63da54435 100644
--- a/chromium/content/browser/fileapi/browser_file_system_helper.h
+++ b/chromium/content/browser/fileapi/browser_file_system_helper.h
@@ -7,9 +7,9 @@
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
-#include "webkit/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_context.h"
-namespace fileapi {
+namespace storage {
class ExternalMountPoints;
class FileSystemContext;
class FileSystemURL;
@@ -21,20 +21,19 @@ class BrowserContext;
// Helper method that returns FileSystemContext constructed for
// the browser process.
-CONTENT_EXPORT scoped_refptr<fileapi::FileSystemContext>
-CreateFileSystemContext(
- BrowserContext* browser_context,
- const base::FilePath& profile_path,
- bool is_incognito,
- quota::QuotaManagerProxy* quota_manager_proxy);
+CONTENT_EXPORT scoped_refptr<storage::FileSystemContext>
+ CreateFileSystemContext(BrowserContext* browser_context,
+ const base::FilePath& profile_path,
+ bool is_incognito,
+ storage::QuotaManagerProxy* quota_manager_proxy);
// Verifies that |url| is valid and has a registered backend in |context|.
-CONTENT_EXPORT bool FileSystemURLIsValid(fileapi::FileSystemContext* context,
- const fileapi::FileSystemURL& url);
+CONTENT_EXPORT bool FileSystemURLIsValid(storage::FileSystemContext* context,
+ const storage::FileSystemURL& url);
// Get the platform path from a file system URL. This needs to be called
// on the FILE thread.
-CONTENT_EXPORT void SyncGetPlatformPath(fileapi::FileSystemContext* context,
+CONTENT_EXPORT void SyncGetPlatformPath(storage::FileSystemContext* context,
int process_id,
const GURL& path,
base::FilePath* platform_path);
diff --git a/chromium/content/browser/fileapi/chrome_blob_storage_context.cc b/chromium/content/browser/fileapi/chrome_blob_storage_context.cc
index fce0bed9066..f085242f689 100644
--- a/chromium/content/browser/fileapi/chrome_blob_storage_context.cc
+++ b/chromium/content/browser/fileapi/chrome_blob_storage_context.cc
@@ -9,36 +9,34 @@
#include "content/public/browser/blob_handle.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
using base::UserDataAdapter;
-using webkit_blob::BlobStorageContext;
+using storage::BlobStorageContext;
namespace content {
namespace {
+const char kBlobStorageContextKeyName[] = "content_blob_storage_context";
+
class BlobHandleImpl : public BlobHandle {
public:
- BlobHandleImpl(scoped_ptr<webkit_blob::BlobDataHandle> handle)
+ explicit BlobHandleImpl(scoped_ptr<storage::BlobDataHandle> handle)
: handle_(handle.Pass()) {
}
- virtual ~BlobHandleImpl() {}
+ ~BlobHandleImpl() override {}
- virtual std::string GetUUID() OVERRIDE {
- return handle_->uuid();
- }
+ std::string GetUUID() override { return handle_->uuid(); }
private:
- scoped_ptr<webkit_blob::BlobDataHandle> handle_;
+ scoped_ptr<storage::BlobDataHandle> handle_;
};
} // namespace
-static const char* kBlobStorageContextKeyName = "content_blob_storage_context";
-
ChromeBlobStorageContext::ChromeBlobStorageContext() {}
ChromeBlobStorageContext* ChromeBlobStorageContext::GetFor(
@@ -71,11 +69,10 @@ scoped_ptr<BlobHandle> ChromeBlobStorageContext::CreateMemoryBackedBlob(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
std::string uuid(base::GenerateGUID());
- scoped_refptr<webkit_blob::BlobData> blob_data =
- new webkit_blob::BlobData(uuid);
+ scoped_refptr<storage::BlobData> blob_data = new storage::BlobData(uuid);
blob_data->AppendData(data, length);
- scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle =
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle =
context_->AddFinishedBlob(blob_data.get());
if (!blob_data_handle)
return scoped_ptr<BlobHandle>();
diff --git a/chromium/content/browser/fileapi/chrome_blob_storage_context.h b/chromium/content/browser/fileapi/chrome_blob_storage_context.h
index 1dccd99faf0..8d8a5f226b4 100644
--- a/chromium/content/browser/fileapi/chrome_blob_storage_context.h
+++ b/chromium/content/browser/fileapi/chrome_blob_storage_context.h
@@ -10,7 +10,7 @@
#include "base/sequenced_task_runner_helpers.h"
#include "content/common/content_export.h"
-namespace webkit_blob {
+namespace storage {
class BlobStorageContext;
}
@@ -37,9 +37,7 @@ class CONTENT_EXPORT ChromeBlobStorageContext
void InitializeOnIOThread();
- webkit_blob::BlobStorageContext* context() const {
- return context_.get();
- }
+ storage::BlobStorageContext* context() const { return context_.get(); }
// Returns a NULL scoped_ptr on failure.
scoped_ptr<BlobHandle> CreateMemoryBackedBlob(const char* data,
@@ -56,7 +54,7 @@ class CONTENT_EXPORT ChromeBlobStorageContext
void DeleteOnCorrectThread() const;
- scoped_ptr<webkit_blob::BlobStorageContext> context_;
+ scoped_ptr<storage::BlobStorageContext> context_;
};
struct ChromeBlobStorageContextDeleter {
diff --git a/chromium/content/browser/fileapi/copy_or_move_file_validator_unittest.cc b/chromium/content/browser/fileapi/copy_or_move_file_validator_unittest.cc
index eaff4d38f54..ea2ba898940 100644
--- a/chromium/content/browser/fileapi/copy_or_move_file_validator_unittest.cc
+++ b/chromium/content/browser/fileapi/copy_or_move_file_validator_unittest.cc
@@ -11,28 +11,28 @@
#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/test_file_system_backend.h"
#include "content/public/test/test_file_system_context.h"
+#include "storage/browser/fileapi/copy_or_move_file_validator.h"
+#include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/file_system_backend.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/common/blob/shareable_file_reference.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
-#include "webkit/browser/fileapi/file_system_backend.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/common/blob/shareable_file_reference.h"
-#include "webkit/common/fileapi/file_system_util.h"
using content::AsyncFileTestHelper;
-using fileapi::CopyOrMoveFileValidator;
-using fileapi::CopyOrMoveFileValidatorFactory;
-using fileapi::FileSystemURL;
+using storage::CopyOrMoveFileValidator;
+using storage::CopyOrMoveFileValidatorFactory;
+using storage::FileSystemURL;
namespace content {
namespace {
-const fileapi::FileSystemType kNoValidatorType =
- fileapi::kFileSystemTypeTemporary;
-const fileapi::FileSystemType kWithValidatorType = fileapi::kFileSystemTypeTest;
+const storage::FileSystemType kNoValidatorType =
+ storage::kFileSystemTypeTemporary;
+const storage::FileSystemType kWithValidatorType = storage::kFileSystemTypeTest;
void ExpectOk(const GURL& origin_url,
const std::string& name,
@@ -43,8 +43,8 @@ void ExpectOk(const GURL& origin_url,
class CopyOrMoveFileValidatorTestHelper {
public:
CopyOrMoveFileValidatorTestHelper(const GURL& origin,
- fileapi::FileSystemType src_type,
- fileapi::FileSystemType dest_type)
+ storage::FileSystemType src_type,
+ storage::FileSystemType dest_type)
: origin_(origin), src_type_(src_type), dest_type_(dest_type) {}
~CopyOrMoveFileValidatorTestHelper() {
@@ -59,17 +59,17 @@ class CopyOrMoveFileValidatorTestHelper {
file_system_context_ = CreateFileSystemContextForTesting(NULL, base_dir);
// Set up TestFileSystemBackend to require CopyOrMoveFileValidator.
- fileapi::FileSystemBackend* test_file_system_backend =
+ storage::FileSystemBackend* test_file_system_backend =
file_system_context_->GetFileSystemBackend(kWithValidatorType);
static_cast<TestFileSystemBackend*>(test_file_system_backend)->
set_require_copy_or_move_validator(true);
// Sets up source.
- fileapi::FileSystemBackend* src_file_system_backend =
+ storage::FileSystemBackend* src_file_system_backend =
file_system_context_->GetFileSystemBackend(src_type_);
src_file_system_backend->ResolveURL(
FileSystemURL::CreateForTest(origin_, src_type_, base::FilePath()),
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&ExpectOk));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(base::File::FILE_OK, CreateDirectory(SourceURL("")));
@@ -93,7 +93,7 @@ class CopyOrMoveFileValidatorTestHelper {
}
void SetMediaCopyOrMoveFileValidatorFactory(
- scoped_ptr<fileapi::CopyOrMoveFileValidatorFactory> factory) {
+ scoped_ptr<storage::CopyOrMoveFileValidatorFactory> factory) {
TestFileSystemBackend* backend = static_cast<TestFileSystemBackend*>(
file_system_context_->GetFileSystemBackend(kWithValidatorType));
backend->InitializeCopyOrMoveFileValidatorFactory(factory.Pass());
@@ -167,13 +167,13 @@ class CopyOrMoveFileValidatorTestHelper {
const GURL origin_;
- const fileapi::FileSystemType src_type_;
- const fileapi::FileSystemType dest_type_;
+ const storage::FileSystemType src_type_;
+ const storage::FileSystemType dest_type_;
std::string src_fsid_;
std::string dest_fsid_;
base::MessageLoop message_loop_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
FileSystemURL copy_src_;
FileSystemURL copy_dest_;
@@ -191,17 +191,17 @@ enum Validity {
};
class TestCopyOrMoveFileValidatorFactory
- : public fileapi::CopyOrMoveFileValidatorFactory {
+ : public storage::CopyOrMoveFileValidatorFactory {
public:
// A factory that creates validators that accept everything or nothing.
// TODO(gbillock): switch args to enum or something
explicit TestCopyOrMoveFileValidatorFactory(Validity validity)
: validity_(validity) {}
- virtual ~TestCopyOrMoveFileValidatorFactory() {}
+ ~TestCopyOrMoveFileValidatorFactory() override {}
- virtual fileapi::CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
+ storage::CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
const FileSystemURL& /*src_url*/,
- const base::FilePath& /*platform_path*/) OVERRIDE {
+ const base::FilePath& /*platform_path*/) override {
return new TestCopyOrMoveFileValidator(validity_);
}
@@ -216,18 +216,18 @@ class TestCopyOrMoveFileValidatorFactory
base::File::FILE_OK :
base::File::FILE_ERROR_SECURITY) {
}
- virtual ~TestCopyOrMoveFileValidator() {}
+ ~TestCopyOrMoveFileValidator() override {}
- virtual void StartPreWriteValidation(
- const ResultCallback& result_callback) OVERRIDE {
+ void StartPreWriteValidation(
+ const ResultCallback& result_callback) override {
// Post the result since a real validator must do work asynchronously.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(result_callback, result_));
}
- virtual void StartPostWriteValidation(
+ void StartPostWriteValidation(
const base::FilePath& dest_platform_path,
- const ResultCallback& result_callback) OVERRIDE {
+ const ResultCallback& result_callback) override {
// Post the result since a real validator must do work asynchronously.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(result_callback, write_result_));
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 f2c00fcf9df..a50d4a054a6 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
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -18,27 +18,27 @@
#include "content/public/test/test_file_system_backend.h"
#include "content/public/test/test_file_system_context.h"
#include "content/test/fileapi_test_file_set.h"
+#include "storage/browser/blob/file_stream_reader.h"
+#include "storage/browser/fileapi/copy_or_move_file_validator.h"
+#include "storage/browser/fileapi/copy_or_move_operation_delegate.h"
+#include "storage/browser/fileapi/file_stream_writer.h"
+#include "storage/browser/fileapi/file_system_backend.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/blob/file_stream_reader.h"
-#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
-#include "webkit/browser/fileapi/copy_or_move_operation_delegate.h"
-#include "webkit/browser/fileapi/file_stream_writer.h"
-#include "webkit/browser/fileapi/file_system_backend.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/common/fileapi/file_system_util.h"
using content::AsyncFileTestHelper;
-using fileapi::CopyOrMoveOperationDelegate;
-using fileapi::FileStreamWriter;
-using fileapi::FileSystemOperation;
-using fileapi::FileSystemURL;
+using storage::CopyOrMoveOperationDelegate;
+using storage::FileStreamWriter;
+using storage::FileSystemOperation;
+using storage::FileSystemURL;
namespace content {
-typedef fileapi::FileSystemOperation::FileEntryList FileEntryList;
+typedef storage::FileSystemOperation::FileEntryList FileEntryList;
namespace {
@@ -48,21 +48,21 @@ void ExpectOk(const GURL& origin_url,
ASSERT_EQ(base::File::FILE_OK, error);
}
-class TestValidatorFactory : public fileapi::CopyOrMoveFileValidatorFactory {
+class TestValidatorFactory : public storage::CopyOrMoveFileValidatorFactory {
public:
// A factory that creates validators that accept everything or nothing.
TestValidatorFactory() {}
- virtual ~TestValidatorFactory() {}
+ ~TestValidatorFactory() override {}
- virtual fileapi::CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
+ storage::CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator(
const FileSystemURL& /*src_url*/,
- const base::FilePath& /*platform_path*/) OVERRIDE {
+ const base::FilePath& /*platform_path*/) override {
// Move arg management to TestValidator?
return new TestValidator(true, true, std::string("2"));
}
private:
- class TestValidator : public fileapi::CopyOrMoveFileValidator {
+ class TestValidator : public storage::CopyOrMoveFileValidator {
public:
explicit TestValidator(bool pre_copy_valid,
bool post_copy_valid,
@@ -73,18 +73,18 @@ class TestValidatorFactory : public fileapi::CopyOrMoveFileValidatorFactory {
base::File::FILE_ERROR_SECURITY),
reject_string_(reject_string) {
}
- virtual ~TestValidator() {}
+ ~TestValidator() override {}
- virtual void StartPreWriteValidation(
- const ResultCallback& result_callback) OVERRIDE {
+ void StartPreWriteValidation(
+ const ResultCallback& result_callback) override {
// Post the result since a real validator must do work asynchronously.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(result_callback, result_));
}
- virtual void StartPostWriteValidation(
+ void StartPostWriteValidation(
const base::FilePath& dest_platform_path,
- const ResultCallback& result_callback) OVERRIDE {
+ const ResultCallback& result_callback) override {
base::File::Error result = write_result_;
std::string unsafe = dest_platform_path.BaseName().AsUTF8Unsafe();
if (unsafe.find(reject_string_) != std::string::npos) {
@@ -106,14 +106,14 @@ class TestValidatorFactory : public fileapi::CopyOrMoveFileValidatorFactory {
// Records CopyProgressCallback invocations.
struct ProgressRecord {
- fileapi::FileSystemOperation::CopyProgressType type;
+ storage::FileSystemOperation::CopyProgressType type;
FileSystemURL source_url;
FileSystemURL dest_url;
int64 size;
};
void RecordProgressCallback(std::vector<ProgressRecord>* records,
- fileapi::FileSystemOperation::CopyProgressType type,
+ storage::FileSystemOperation::CopyProgressType type,
const FileSystemURL& source_url,
const FileSystemURL& dest_url,
int64 size) {
@@ -165,8 +165,8 @@ class ScopedThreadStopper {
class CopyOrMoveOperationTestHelper {
public:
CopyOrMoveOperationTestHelper(const GURL& origin,
- fileapi::FileSystemType src_type,
- fileapi::FileSystemType dest_type)
+ storage::FileSystemType src_type,
+ storage::FileSystemType dest_type)
: origin_(origin), src_type_(src_type), dest_type_(dest_type) {}
~CopyOrMoveOperationTestHelper() {
@@ -201,17 +201,17 @@ class CopyOrMoveOperationTestHelper {
CreateFileSystemContextForTesting(quota_manager_proxy_.get(), base_dir);
// Prepare the origin's root directory.
- fileapi::FileSystemBackend* backend =
+ storage::FileSystemBackend* backend =
file_system_context_->GetFileSystemBackend(src_type_);
backend->ResolveURL(
FileSystemURL::CreateForTest(origin_, src_type_, base::FilePath()),
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&ExpectOk));
backend = file_system_context_->GetFileSystemBackend(dest_type_);
- if (dest_type_ == fileapi::kFileSystemTypeTest) {
+ if (dest_type_ == storage::kFileSystemTypeTest) {
TestFileSystemBackend* test_backend =
static_cast<TestFileSystemBackend*>(backend);
- scoped_ptr<fileapi::CopyOrMoveFileValidatorFactory> factory(
+ scoped_ptr<storage::CopyOrMoveFileValidatorFactory> factory(
new TestValidatorFactory);
test_backend->set_require_copy_or_move_validator(
require_copy_or_move_validator);
@@ -220,18 +220,18 @@ class CopyOrMoveOperationTestHelper {
}
backend->ResolveURL(
FileSystemURL::CreateForTest(origin_, dest_type_, base::FilePath()),
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&ExpectOk));
base::RunLoop().RunUntilIdle();
// Grant relatively big quota initially.
quota_manager_->SetQuota(
origin_,
- fileapi::FileSystemTypeToQuotaStorageType(src_type_),
+ storage::FileSystemTypeToQuotaStorageType(src_type_),
1024 * 1024);
quota_manager_->SetQuota(
origin_,
- fileapi::FileSystemTypeToQuotaStorageType(dest_type_),
+ storage::FileSystemTypeToQuotaStorageType(dest_type_),
1024 * 1024);
}
@@ -373,23 +373,23 @@ class CopyOrMoveOperationTestHelper {
}
private:
- void GetUsageAndQuota(fileapi::FileSystemType type,
+ void GetUsageAndQuota(storage::FileSystemType type,
int64* usage,
int64* quota) {
- quota::QuotaStatusCode status = AsyncFileTestHelper::GetUsageAndQuota(
+ storage::QuotaStatusCode status = AsyncFileTestHelper::GetUsageAndQuota(
quota_manager_.get(), origin_, type, usage, quota);
- ASSERT_EQ(quota::kQuotaStatusOk, status);
+ ASSERT_EQ(storage::kQuotaStatusOk, status);
}
private:
base::ScopedTempDir base_;
const GURL origin_;
- const fileapi::FileSystemType src_type_;
- const fileapi::FileSystemType dest_type_;
+ const storage::FileSystemType src_type_;
+ const storage::FileSystemType dest_type_;
base::MessageLoopForIO message_loop_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
scoped_refptr<MockQuotaManager> quota_manager_;
@@ -398,8 +398,8 @@ class CopyOrMoveOperationTestHelper {
TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFile) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypePersistent);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypePersistent);
helper.SetUp();
FileSystemURL src = helper.SourceURL("a");
@@ -427,8 +427,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFile) {
TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleFile) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypePersistent);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypePersistent);
helper.SetUp();
FileSystemURL src = helper.SourceURL("a");
@@ -456,8 +456,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleFile) {
TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleDirectory) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypePersistent);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypePersistent);
helper.SetUp();
FileSystemURL src = helper.SourceURL("a");
@@ -485,8 +485,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleDirectory) {
TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleDirectory) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypePersistent);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypePersistent);
helper.SetUp();
FileSystemURL src = helper.SourceURL("a");
@@ -514,8 +514,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, MoveSingleDirectory) {
TEST(LocalFileSystemCopyOrMoveOperationTest, CopyDirectory) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypePersistent);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypePersistent);
helper.SetUp();
FileSystemURL src = helper.SourceURL("a");
@@ -554,8 +554,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopyDirectory) {
TEST(LocalFileSystemCopyOrMoveOperationTest, MoveDirectory) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypePersistent);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypePersistent);
helper.SetUp();
FileSystemURL src = helper.SourceURL("a");
@@ -592,8 +592,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, MoveDirectory) {
TEST(LocalFileSystemCopyOrMoveOperationTest,
MoveDirectoryFailPostWriteValidation) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypeTest);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypeTest);
helper.SetUp();
FileSystemURL src = helper.SourceURL("a");
@@ -625,8 +625,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest,
TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFileNoValidator) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypeTest);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypeTest);
helper.SetUpNoValidator();
FileSystemURL src = helper.SourceURL("a");
@@ -643,8 +643,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, CopySingleFileNoValidator) {
TEST(LocalFileSystemCopyOrMoveOperationTest, ProgressCallback) {
CopyOrMoveOperationTestHelper helper(GURL("http://foo"),
- fileapi::kFileSystemTypeTemporary,
- fileapi::kFileSystemTypePersistent);
+ storage::kFileSystemTypeTemporary,
+ storage::kFileSystemTypePersistent);
helper.SetUp();
FileSystemURL src = helper.SourceURL("a");
@@ -730,8 +730,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper) {
scoped_refptr<base::MessageLoopProxy> task_runner =
file_thread.message_loop_proxy();
- scoped_ptr<webkit_blob::FileStreamReader> reader(
- webkit_blob::FileStreamReader::CreateForLocalFile(
+ scoped_ptr<storage::FileStreamReader> reader(
+ storage::FileStreamReader::CreateForLocalFile(
task_runner.get(), source_path, 0, base::Time()));
scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
@@ -786,8 +786,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelperWithFlush) {
scoped_refptr<base::MessageLoopProxy> task_runner =
file_thread.message_loop_proxy();
- scoped_ptr<webkit_blob::FileStreamReader> reader(
- webkit_blob::FileStreamReader::CreateForLocalFile(
+ scoped_ptr<storage::FileStreamReader> reader(
+ storage::FileStreamReader::CreateForLocalFile(
task_runner.get(), source_path, 0, base::Time()));
scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
@@ -837,8 +837,8 @@ TEST(LocalFileSystemCopyOrMoveOperationTest, StreamCopyHelper_Cancel) {
scoped_refptr<base::MessageLoopProxy> task_runner =
file_thread.message_loop_proxy();
- scoped_ptr<webkit_blob::FileStreamReader> reader(
- webkit_blob::FileStreamReader::CreateForLocalFile(
+ scoped_ptr<storage::FileStreamReader> reader(
+ storage::FileStreamReader::CreateForLocalFile(
task_runner.get(), source_path, 0, base::Time()));
scoped_ptr<FileStreamWriter> writer(FileStreamWriter::CreateForLocalFile(
diff --git a/chromium/content/browser/fileapi/dragged_file_util_unittest.cc b/chromium/content/browser/fileapi/dragged_file_util_unittest.cc
index 6bd6e100253..98b2ceec421 100644
--- a/chromium/content/browser/fileapi/dragged_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/dragged_file_util_unittest.cc
@@ -8,8 +8,8 @@
#include <string>
#include <vector>
-#include "base/file_util.h"
#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
@@ -18,19 +18,19 @@
#include "content/public/test/async_file_test_helper.h"
#include "content/public/test/test_file_system_context.h"
#include "content/test/fileapi_test_file_set.h"
+#include "storage/browser/fileapi/dragged_file_util.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/browser/fileapi/local_file_util.h"
+#include "storage/browser/fileapi/native_file_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/dragged_file_util.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/browser/fileapi/local_file_util.h"
-#include "webkit/browser/fileapi/native_file_util.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemContext;
-using fileapi::FileSystemOperationContext;
-using fileapi::FileSystemType;
-using fileapi::FileSystemURL;
+using storage::FileSystemContext;
+using storage::FileSystemOperationContext;
+using storage::FileSystemType;
+using storage::FileSystemURL;
namespace content {
@@ -97,10 +97,10 @@ class DraggedFileUtilTest : public testing::Test {
public:
DraggedFileUtilTest() {}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
ASSERT_TRUE(partition_dir_.CreateUniqueTempDir());
- file_util_.reset(new fileapi::DraggedFileUtil());
+ file_util_.reset(new storage::DraggedFileUtil());
// Register the files/directories of RegularTestCases (with random
// root paths) as dropped files.
@@ -113,13 +113,13 @@ class DraggedFileUtilTest : public testing::Test {
isolated_context()->AddReference(filesystem_id_);
}
- virtual void TearDown() {
+ void TearDown() override {
isolated_context()->RemoveReference(filesystem_id_);
}
protected:
- fileapi::IsolatedContext* isolated_context() const {
- return fileapi::IsolatedContext::GetInstance();
+ storage::IsolatedContext* isolated_context() const {
+ return storage::IsolatedContext::GetInstance();
}
const base::FilePath& root_path() const {
return data_dir_.path();
@@ -127,7 +127,7 @@ class DraggedFileUtilTest : public testing::Test {
FileSystemContext* file_system_context() const {
return file_system_context_.get();
}
- fileapi::FileSystemFileUtil* file_util() const { return file_util_.get(); }
+ storage::FileSystemFileUtil* file_util() const { return file_util_.get(); }
std::string filesystem_id() const { return filesystem_id_; }
base::FilePath GetTestCasePlatformPath(
@@ -148,14 +148,14 @@ class DraggedFileUtilTest : public testing::Test {
filesystem_id()).Append(path);
return file_system_context_->CreateCrackedFileSystemURL(
GURL("http://example.com"),
- fileapi::kFileSystemTypeIsolated,
+ storage::kFileSystemTypeIsolated,
virtual_path);
}
FileSystemURL GetOtherFileSystemURL(const base::FilePath& path) const {
return file_system_context()->CreateCrackedFileSystemURL(
GURL("http://example.com"),
- fileapi::kFileSystemTypeTemporary,
+ storage::kFileSystemTypeTemporary,
base::FilePath().AppendASCII("dest").Append(path));
}
@@ -247,9 +247,9 @@ class DraggedFileUtilTest : public testing::Test {
}
}
- scoped_ptr<fileapi::FileSystemOperationContext> GetOperationContext() {
- return make_scoped_ptr(
- new fileapi::FileSystemOperationContext(file_system_context())).Pass();
+ scoped_ptr<storage::FileSystemOperationContext> GetOperationContext() {
+ return make_scoped_ptr(new storage::FileSystemOperationContext(
+ file_system_context())).Pass();
}
@@ -257,7 +257,7 @@ class DraggedFileUtilTest : public testing::Test {
void SimulateDropFiles() {
size_t root_path_index = 0;
- fileapi::IsolatedContext::FileInfoSet toplevels;
+ storage::IsolatedContext::FileInfoSet toplevels;
for (size_t i = 0; i < kRegularFileSystemTestCaseSize; ++i) {
const FileSystemTestCaseRecord& test_case =
kRegularFileSystemTestCases[i];
@@ -286,7 +286,7 @@ class DraggedFileUtilTest : public testing::Test {
std::string filesystem_id_;
scoped_refptr<FileSystemContext> file_system_context_;
std::map<base::FilePath, base::FilePath> toplevel_root_map_;
- scoped_ptr<fileapi::DraggedFileUtil> file_util_;
+ scoped_ptr<storage::DraggedFileUtil> file_util_;
DISALLOW_COPY_AND_ASSIGN(DraggedFileUtilTest);
};
@@ -361,7 +361,7 @@ TEST_F(DraggedFileUtilTest, ReadDirectoryTest) {
<< ": " << test_case.path);
// Read entries in the directory to construct the expected results map.
- typedef std::map<base::FilePath::StringType, fileapi::DirectoryEntry>
+ typedef std::map<base::FilePath::StringType, storage::DirectoryEntry>
EntryMap;
EntryMap expected_entry_map;
@@ -372,7 +372,7 @@ TEST_F(DraggedFileUtilTest, ReadDirectoryTest) {
base::FilePath current;
while (!(current = file_enum.Next()).empty()) {
base::FileEnumerator::FileInfo file_info = file_enum.GetInfo();
- fileapi::DirectoryEntry entry;
+ storage::DirectoryEntry entry;
entry.is_directory = file_info.IsDirectory();
entry.name = current.BaseName().value();
entry.size = file_info.GetSize();
@@ -399,7 +399,7 @@ TEST_F(DraggedFileUtilTest, ReadDirectoryTest) {
EXPECT_EQ(expected_entry_map.size(), entries.size());
for (size_t i = 0; i < entries.size(); ++i) {
- const fileapi::DirectoryEntry& entry = entries[i];
+ const storage::DirectoryEntry& entry = entries[i];
EntryMap::iterator found = expected_entry_map.find(entry.name);
EXPECT_TRUE(found != expected_entry_map.end());
EXPECT_EQ(found->second.name, entry.name);
diff --git a/chromium/content/browser/fileapi/external_mount_points_unittest.cc b/chromium/content/browser/fileapi/external_mount_points_unittest.cc
index fa0d1f5bbc2..447eb7348a7 100644
--- a/chromium/content/browser/fileapi/external_mount_points_unittest.cc
+++ b/chromium/content/browser/fileapi/external_mount_points_unittest.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 "webkit/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/external_mount_points.h"
#include <string>
#include "base/files/file_path.h"
+#include "storage/browser/fileapi/file_system_url.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/file_system_url.h"
#define FPL FILE_PATH_LITERAL
@@ -18,13 +18,13 @@
#define DRIVE
#endif
-using fileapi::FileSystemURL;
+using storage::FileSystemURL;
namespace content {
TEST(ExternalMountPointsTest, AddMountPoint) {
- scoped_refptr<fileapi::ExternalMountPoints> mount_points(
- fileapi::ExternalMountPoints::CreateRefCounted());
+ scoped_refptr<storage::ExternalMountPoints> mount_points(
+ storage::ExternalMountPoints::CreateRefCounted());
struct TestCase {
// The mount point's name.
@@ -106,19 +106,19 @@ TEST(ExternalMountPointsTest, AddMountPoint) {
};
// Test adding mount points.
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
- EXPECT_EQ(kTestCases[i].success,
- mount_points->RegisterFileSystem(
- kTestCases[i].name,
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
- base::FilePath(kTestCases[i].path)))
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ EXPECT_EQ(
+ kTestCases[i].success,
+ mount_points->RegisterFileSystem(kTestCases[i].name,
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
+ base::FilePath(kTestCases[i].path)))
<< "Adding mount point: " << kTestCases[i].name << " with path "
<< kTestCases[i].path;
}
// Test that final mount point presence state is as expected.
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
base::FilePath found_path;
EXPECT_EQ(kTestCases[i].registered_path != NULL,
mount_points->GetRegisteredPath(kTestCases[i].name, &found_path))
@@ -132,35 +132,35 @@ TEST(ExternalMountPointsTest, AddMountPoint) {
}
TEST(ExternalMountPointsTest, GetVirtualPath) {
- scoped_refptr<fileapi::ExternalMountPoints> mount_points(
- fileapi::ExternalMountPoints::CreateRefCounted());
+ scoped_refptr<storage::ExternalMountPoints> mount_points(
+ storage::ExternalMountPoints::CreateRefCounted());
mount_points->RegisterFileSystem("c",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/a/b/c")));
// Note that "/a/b/c" < "/a/b/c(1)" < "/a/b/c/".
mount_points->RegisterFileSystem("c(1)",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/a/b/c(1)")));
mount_points->RegisterFileSystem("x",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/z/y/x")));
mount_points->RegisterFileSystem("o",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/m/n/o")));
// A mount point whose name does not match its path base name.
mount_points->RegisterFileSystem("mount",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/root/foo")));
// A mount point with an empty path.
mount_points->RegisterFileSystem("empty_path",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
base::FilePath());
struct TestCase {
@@ -214,7 +214,7 @@ TEST(ExternalMountPointsTest, GetVirtualPath) {
#endif
};
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
// Initialize virtual path with a value.
base::FilePath virtual_path(DRIVE FPL("/mount"));
base::FilePath local_path(kTestCases[i].local_path);
@@ -234,57 +234,57 @@ TEST(ExternalMountPointsTest, GetVirtualPath) {
}
TEST(ExternalMountPointsTest, HandlesFileSystemMountType) {
- scoped_refptr<fileapi::ExternalMountPoints> mount_points(
- fileapi::ExternalMountPoints::CreateRefCounted());
+ scoped_refptr<storage::ExternalMountPoints> mount_points(
+ storage::ExternalMountPoints::CreateRefCounted());
const GURL test_origin("http://chromium.org");
const base::FilePath test_path(FPL("/mount"));
// Should handle External File System.
EXPECT_TRUE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeExternal));
+ storage::kFileSystemTypeExternal));
// Shouldn't handle the rest.
EXPECT_FALSE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeIsolated));
- EXPECT_FALSE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeTemporary));
+ storage::kFileSystemTypeIsolated));
EXPECT_FALSE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypePersistent));
+ storage::kFileSystemTypeTemporary));
EXPECT_FALSE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeTest));
+ storage::kFileSystemTypePersistent));
+ EXPECT_FALSE(
+ mount_points->HandlesFileSystemMountType(storage::kFileSystemTypeTest));
// Not even if it's external subtype.
EXPECT_FALSE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeNativeLocal));
- EXPECT_FALSE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeRestrictedNativeLocal));
+ storage::kFileSystemTypeNativeLocal));
EXPECT_FALSE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeDrive));
+ storage::kFileSystemTypeRestrictedNativeLocal));
+ EXPECT_FALSE(
+ mount_points->HandlesFileSystemMountType(storage::kFileSystemTypeDrive));
EXPECT_FALSE(mount_points->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeSyncable));
+ storage::kFileSystemTypeSyncable));
}
TEST(ExternalMountPointsTest, CreateCrackedFileSystemURL) {
- scoped_refptr<fileapi::ExternalMountPoints> mount_points(
- fileapi::ExternalMountPoints::CreateRefCounted());
+ scoped_refptr<storage::ExternalMountPoints> mount_points(
+ storage::ExternalMountPoints::CreateRefCounted());
const GURL kTestOrigin("http://chromium.org");
mount_points->RegisterFileSystem("c",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/a/b/c")));
mount_points->RegisterFileSystem("c(1)",
- fileapi::kFileSystemTypeDrive,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeDrive,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/a/b/c(1)")));
mount_points->RegisterFileSystem("empty_path",
- fileapi::kFileSystemTypeSyncable,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeSyncable,
+ storage::FileSystemMountOption(),
base::FilePath());
mount_points->RegisterFileSystem("mount",
- fileapi::kFileSystemTypeDrive,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeDrive,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/root")));
// Try cracking invalid GURL.
@@ -293,69 +293,62 @@ TEST(ExternalMountPointsTest, CreateCrackedFileSystemURL) {
// Try cracking isolated path.
FileSystemURL isolated = mount_points->CreateCrackedFileSystemURL(
- kTestOrigin, fileapi::kFileSystemTypeIsolated, base::FilePath(FPL("c")));
+ kTestOrigin, storage::kFileSystemTypeIsolated, base::FilePath(FPL("c")));
EXPECT_FALSE(isolated.is_valid());
// Try native local which is not cracked.
FileSystemURL native_local = mount_points->CreateCrackedFileSystemURL(
kTestOrigin,
- fileapi::kFileSystemTypeNativeLocal,
+ storage::kFileSystemTypeNativeLocal,
base::FilePath(FPL("c")));
EXPECT_FALSE(native_local.is_valid());
struct TestCase {
const base::FilePath::CharType* const path;
bool expect_valid;
- fileapi::FileSystemType expect_type;
+ storage::FileSystemType expect_type;
const base::FilePath::CharType* const expect_path;
const char* const expect_fs_id;
};
const TestCase kTestCases[] = {
- { FPL("c/d/e"),
- true, fileapi::kFileSystemTypeNativeLocal, DRIVE FPL("/a/b/c/d/e"), "c" },
- { FPL("c(1)/d/e"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/a/b/c(1)/d/e"), "c(1)" },
- { FPL("c(1)"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/a/b/c(1)"), "c(1)" },
- { FPL("empty_path/a"),
- true, fileapi::kFileSystemTypeSyncable, FPL("a"), "empty_path" },
- { FPL("empty_path"),
- true, fileapi::kFileSystemTypeSyncable, FPL(""), "empty_path" },
- { FPL("mount/a/b"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/root/a/b"), "mount" },
- { FPL("mount"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/root"), "mount" },
- { FPL("cc"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL(""),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL(".."),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
+ {FPL("c/d/e"), true, storage::kFileSystemTypeNativeLocal,
+ DRIVE FPL("/a/b/c/d/e"), "c"},
+ {FPL("c(1)/d/e"), true, storage::kFileSystemTypeDrive,
+ DRIVE FPL("/a/b/c(1)/d/e"), "c(1)"},
+ {FPL("c(1)"), true, storage::kFileSystemTypeDrive, DRIVE FPL("/a/b/c(1)"),
+ "c(1)"},
+ {FPL("empty_path/a"), true, storage::kFileSystemTypeSyncable, FPL("a"),
+ "empty_path"},
+ {FPL("empty_path"), true, storage::kFileSystemTypeSyncable, FPL(""),
+ "empty_path"},
+ {FPL("mount/a/b"), true, storage::kFileSystemTypeDrive,
+ DRIVE FPL("/root/a/b"), "mount"},
+ {FPL("mount"), true, storage::kFileSystemTypeDrive, DRIVE FPL("/root"),
+ "mount"},
+ {FPL("cc"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL(""), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL(".."), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
// Absolte paths.
- { FPL("/c/d/e"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL("/c(1)/d/e"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL("/empty_path"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
+ {FPL("/c/d/e"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL("/c(1)/d/e"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL("/empty_path"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
// PAth references parent.
- { FPL("c/d/../e"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL("/empty_path/a/../b"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
+ {FPL("c/d/../e"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL("/empty_path/a/../b"), false, storage::kFileSystemTypeUnknown, FPL(""),
+ ""},
#if defined(FILE_PATH_USES_WIN_SEPARATORS)
- { FPL("c/d\\e"),
- true, fileapi::kFileSystemTypeNativeLocal, DRIVE FPL("/a/b/c/d/e"), "c" },
- { FPL("mount\\a\\b"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/root/a/b"), "mount" },
+ {FPL("c/d\\e"), true, storage::kFileSystemTypeNativeLocal,
+ DRIVE FPL("/a/b/c/d/e"), "c"},
+ {FPL("mount\\a\\b"), true, storage::kFileSystemTypeDrive,
+ DRIVE FPL("/root/a/b"), "mount"},
#endif
};
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
FileSystemURL cracked = mount_points->CreateCrackedFileSystemURL(
kTestOrigin,
- fileapi::kFileSystemTypeExternal,
+ storage::kFileSystemTypeExternal,
base::FilePath(kTestCases[i].path));
EXPECT_EQ(kTestCases[i].expect_valid, cracked.is_valid())
@@ -376,89 +369,82 @@ TEST(ExternalMountPointsTest, CreateCrackedFileSystemURL) {
<< "Test case index: " << i;
EXPECT_EQ(kTestCases[i].expect_fs_id, cracked.filesystem_id())
<< "Test case index: " << i;
- EXPECT_EQ(fileapi::kFileSystemTypeExternal, cracked.mount_type())
+ EXPECT_EQ(storage::kFileSystemTypeExternal, cracked.mount_type())
<< "Test case index: " << i;
}
}
TEST(ExternalMountPointsTest, CrackVirtualPath) {
- scoped_refptr<fileapi::ExternalMountPoints> mount_points(
- fileapi::ExternalMountPoints::CreateRefCounted());
+ scoped_refptr<storage::ExternalMountPoints> mount_points(
+ storage::ExternalMountPoints::CreateRefCounted());
const GURL kTestOrigin("http://chromium.org");
mount_points->RegisterFileSystem("c",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/a/b/c")));
mount_points->RegisterFileSystem("c(1)",
- fileapi::kFileSystemTypeDrive,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeDrive,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/a/b/c(1)")));
mount_points->RegisterFileSystem("empty_path",
- fileapi::kFileSystemTypeSyncable,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeSyncable,
+ storage::FileSystemMountOption(),
base::FilePath());
mount_points->RegisterFileSystem("mount",
- fileapi::kFileSystemTypeDrive,
- fileapi::FileSystemMountOption(),
+ storage::kFileSystemTypeDrive,
+ storage::FileSystemMountOption(),
base::FilePath(DRIVE FPL("/root")));
struct TestCase {
const base::FilePath::CharType* const path;
bool expect_valid;
- fileapi::FileSystemType expect_type;
+ storage::FileSystemType expect_type;
const base::FilePath::CharType* const expect_path;
const char* const expect_name;
};
const TestCase kTestCases[] = {
- { FPL("c/d/e"),
- true, fileapi::kFileSystemTypeNativeLocal, DRIVE FPL("/a/b/c/d/e"), "c" },
- { FPL("c(1)/d/e"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/a/b/c(1)/d/e"), "c(1)" },
- { FPL("c(1)"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/a/b/c(1)"), "c(1)" },
- { FPL("empty_path/a"),
- true, fileapi::kFileSystemTypeSyncable, FPL("a"), "empty_path" },
- { FPL("empty_path"),
- true, fileapi::kFileSystemTypeSyncable, FPL(""), "empty_path" },
- { FPL("mount/a/b"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/root/a/b"), "mount" },
- { FPL("mount"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/root"), "mount" },
- { FPL("cc"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL(""),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL(".."),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
+ {FPL("c/d/e"), true, storage::kFileSystemTypeNativeLocal,
+ DRIVE FPL("/a/b/c/d/e"), "c"},
+ {FPL("c(1)/d/e"), true, storage::kFileSystemTypeDrive,
+ DRIVE FPL("/a/b/c(1)/d/e"), "c(1)"},
+ {FPL("c(1)"), true, storage::kFileSystemTypeDrive, DRIVE FPL("/a/b/c(1)"),
+ "c(1)"},
+ {FPL("empty_path/a"), true, storage::kFileSystemTypeSyncable, FPL("a"),
+ "empty_path"},
+ {FPL("empty_path"), true, storage::kFileSystemTypeSyncable, FPL(""),
+ "empty_path"},
+ {FPL("mount/a/b"), true, storage::kFileSystemTypeDrive,
+ DRIVE FPL("/root/a/b"), "mount"},
+ {FPL("mount"), true, storage::kFileSystemTypeDrive, DRIVE FPL("/root"),
+ "mount"},
+ {FPL("cc"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL(""), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL(".."), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
// Absolte paths.
- { FPL("/c/d/e"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL("/c(1)/d/e"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL("/empty_path"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
+ {FPL("/c/d/e"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL("/c(1)/d/e"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL("/empty_path"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
// PAth references parent.
- { FPL("c/d/../e"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
- { FPL("/empty_path/a/../b"),
- false, fileapi::kFileSystemTypeUnknown, FPL(""), "" },
+ {FPL("c/d/../e"), false, storage::kFileSystemTypeUnknown, FPL(""), ""},
+ {FPL("/empty_path/a/../b"), false, storage::kFileSystemTypeUnknown, FPL(""),
+ ""},
#if defined(FILE_PATH_USES_WIN_SEPARATORS)
- { FPL("c/d\\e"),
- true, fileapi::kFileSystemTypeNativeLocal, DRIVE FPL("/a/b/c/d/e"), "c" },
- { FPL("mount\\a\\b"),
- true, fileapi::kFileSystemTypeDrive, DRIVE FPL("/root/a/b"), "mount" },
+ {FPL("c/d\\e"), true, storage::kFileSystemTypeNativeLocal,
+ DRIVE FPL("/a/b/c/d/e"), "c"},
+ {FPL("mount\\a\\b"), true, storage::kFileSystemTypeDrive,
+ DRIVE FPL("/root/a/b"), "mount"},
#endif
};
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
std::string cracked_name;
- fileapi::FileSystemType cracked_type;
+ storage::FileSystemType cracked_type;
std::string cracked_id;
base::FilePath cracked_path;
- fileapi::FileSystemMountOption cracked_option;
+ storage::FileSystemMountOption cracked_option;
EXPECT_EQ(kTestCases[i].expect_valid,
mount_points->CrackVirtualPath(base::FilePath(kTestCases[i].path),
&cracked_name, &cracked_type, &cracked_id, &cracked_path,
@@ -482,33 +468,33 @@ TEST(ExternalMountPointsTest, CrackVirtualPath) {
}
TEST(ExternalMountPointsTest, MountOption) {
- scoped_refptr<fileapi::ExternalMountPoints> mount_points(
- fileapi::ExternalMountPoints::CreateRefCounted());
+ scoped_refptr<storage::ExternalMountPoints> mount_points(
+ storage::ExternalMountPoints::CreateRefCounted());
mount_points->RegisterFileSystem(
"nosync",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(fileapi::COPY_SYNC_OPTION_NO_SYNC),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(storage::COPY_SYNC_OPTION_NO_SYNC),
base::FilePath(DRIVE FPL("/nosync")));
mount_points->RegisterFileSystem(
"sync",
- fileapi::kFileSystemTypeNativeLocal,
- fileapi::FileSystemMountOption(fileapi::COPY_SYNC_OPTION_SYNC),
+ storage::kFileSystemTypeNativeLocal,
+ storage::FileSystemMountOption(storage::COPY_SYNC_OPTION_SYNC),
base::FilePath(DRIVE FPL("/sync")));
std::string name;
- fileapi::FileSystemType type;
+ storage::FileSystemType type;
std::string cracked_id;
- fileapi::FileSystemMountOption option;
+ storage::FileSystemMountOption option;
base::FilePath path;
EXPECT_TRUE(mount_points->CrackVirtualPath(
base::FilePath(FPL("nosync/file")), &name, &type, &cracked_id, &path,
&option));
- EXPECT_EQ(fileapi::COPY_SYNC_OPTION_NO_SYNC, option.copy_sync_option());
+ EXPECT_EQ(storage::COPY_SYNC_OPTION_NO_SYNC, option.copy_sync_option());
EXPECT_TRUE(mount_points->CrackVirtualPath(
base::FilePath(FPL("sync/file")), &name, &type, &cracked_id, &path,
&option));
- EXPECT_EQ(fileapi::COPY_SYNC_OPTION_SYNC, option.copy_sync_option());
+ EXPECT_EQ(storage::COPY_SYNC_OPTION_SYNC, option.copy_sync_option());
}
} // namespace content
diff --git a/chromium/content/browser/fileapi/file_system_browsertest.cc b/chromium/content/browser/fileapi/file_system_browsertest.cc
index 51fc4164dab..804f04e9fd9 100644
--- a/chromium/content/browser/fileapi/file_system_browsertest.cc
+++ b/chromium/content/browser/fileapi/file_system_browsertest.cc
@@ -16,9 +16,9 @@
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
-#include "webkit/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_manager.h"
-using quota::QuotaManager;
+using storage::QuotaManager;
namespace content {
@@ -51,7 +51,7 @@ class FileSystemBrowserTest : public ContentBrowserTest {
class FileSystemBrowserTestWithLowQuota : public FileSystemBrowserTest {
public:
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
const int kInitialQuotaKilobytes = 5000;
const int kTemporaryStorageQuotaMaxSize =
kInitialQuotaKilobytes * 1024 * QuotaManager::kPerHostTemporaryPortion;
@@ -70,7 +70,7 @@ class FileSystemBrowserTestWithLowQuota : public FileSystemBrowserTest {
return;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- qm->SetTemporaryGlobalOverrideQuota(bytes, quota::QuotaCallback());
+ qm->SetTemporaryGlobalOverrideQuota(bytes, storage::QuotaCallback());
// Don't return until the quota has been set.
scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB).get()));
diff --git a/chromium/content/browser/fileapi/file_system_context_unittest.cc b/chromium/content/browser/fileapi/file_system_context_unittest.cc
index e746a6a3ad3..454a8f385e6 100644
--- a/chromium/content/browser/fileapi/file_system_context_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_context_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 "webkit/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_context.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
@@ -10,10 +10,10 @@
#include "content/browser/quota/mock_quota_manager.h"
#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/test_file_system_options.h"
+#include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/file_system_backend.h"
+#include "storage/browser/fileapi/isolated_context.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
-#include "webkit/browser/fileapi/file_system_backend.h"
-#include "webkit/browser/fileapi/isolated_context.h"
#define FPL(x) FILE_PATH_LITERAL(x)
@@ -23,12 +23,12 @@
#define DRIVE
#endif
-using fileapi::ExternalMountPoints;
-using fileapi::FileSystemBackend;
-using fileapi::FileSystemContext;
-using fileapi::FileSystemMountOption;
-using fileapi::FileSystemURL;
-using fileapi::IsolatedContext;
+using storage::ExternalMountPoints;
+using storage::FileSystemBackend;
+using storage::FileSystemContext;
+using storage::FileSystemMountOption;
+using storage::FileSystemURL;
+using storage::IsolatedContext;
namespace content {
@@ -49,7 +49,7 @@ class FileSystemContextTest : public testing::Test {
public:
FileSystemContextTest() {}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
storage_policy_ = new MockSpecialStoragePolicy();
@@ -64,7 +64,7 @@ class FileSystemContextTest : public testing::Test {
protected:
FileSystemContext* CreateFileSystemContextForTest(
- fileapi::ExternalMountPoints* external_mount_points) {
+ storage::ExternalMountPoints* external_mount_points) {
return new FileSystemContext(
base::MessageLoopProxy::current().get(),
base::MessageLoopProxy::current().get(),
@@ -72,7 +72,7 @@ class FileSystemContextTest : public testing::Test {
storage_policy_.get(),
mock_quota_manager_->proxy(),
ScopedVector<FileSystemBackend>(),
- std::vector<fileapi::URLRequestAutoMountHandler>(),
+ std::vector<storage::URLRequestAutoMountHandler>(),
data_dir_.path(),
CreateAllowFileAccessOptions());
}
@@ -80,8 +80,8 @@ class FileSystemContextTest : public testing::Test {
// Verifies a *valid* filesystem url has expected values.
void ExpectFileSystemURLMatches(const FileSystemURL& url,
const GURL& expect_origin,
- fileapi::FileSystemType expect_mount_type,
- fileapi::FileSystemType expect_type,
+ storage::FileSystemType expect_mount_type,
+ storage::FileSystemType expect_type,
const base::FilePath& expect_path,
const base::FilePath& expect_virtual_path,
const std::string& expect_filesystem_id) {
@@ -98,7 +98,7 @@ class FileSystemContextTest : public testing::Test {
private:
base::ScopedTempDir data_dir_;
base::MessageLoop message_loop_;
- scoped_refptr<quota::SpecialStoragePolicy> storage_policy_;
+ scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
scoped_refptr<MockQuotaManager> mock_quota_manager_;
};
@@ -113,14 +113,14 @@ TEST_F(FileSystemContextTest, NullExternalMountPoints) {
std::string isolated_name = "root";
std::string isolated_id =
IsolatedContext::GetInstance()->RegisterFileSystemForPath(
- fileapi::kFileSystemTypeNativeLocal,
+ storage::kFileSystemTypeNativeLocal,
std::string(),
base::FilePath(DRIVE FPL("/test/isolated/root")),
&isolated_name);
// Register system external mount point.
ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
"system",
- fileapi::kFileSystemTypeNativeLocal,
+ storage::kFileSystemTypeNativeLocal,
FileSystemMountOption(),
base::FilePath(DRIVE FPL("/test/sys/"))));
@@ -130,12 +130,13 @@ TEST_F(FileSystemContextTest, NullExternalMountPoints) {
ExpectFileSystemURLMatches(
cracked_isolated,
GURL(kTestOrigin),
- fileapi::kFileSystemTypeIsolated,
- fileapi::kFileSystemTypeNativeLocal,
- base::FilePath(
- DRIVE FPL("/test/isolated/root/file")).NormalizePathSeparators(),
- base::FilePath::FromUTF8Unsafe(isolated_id).Append(FPL("root/file")).
- NormalizePathSeparators(),
+ storage::kFileSystemTypeIsolated,
+ storage::kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/isolated/root/file"))
+ .NormalizePathSeparators(),
+ base::FilePath::FromUTF8Unsafe(isolated_id)
+ .Append(FPL("root/file"))
+ .NormalizePathSeparators(),
isolated_id);
FileSystemURL cracked_external = file_system_context->CrackURL(
@@ -144,14 +145,13 @@ TEST_F(FileSystemContextTest, NullExternalMountPoints) {
ExpectFileSystemURLMatches(
cracked_external,
GURL(kTestOrigin),
- fileapi::kFileSystemTypeExternal,
- fileapi::kFileSystemTypeNativeLocal,
- base::FilePath(
- DRIVE FPL("/test/sys/root/file")).NormalizePathSeparators(),
+ storage::kFileSystemTypeExternal,
+ storage::kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/sys/root/file"))
+ .NormalizePathSeparators(),
base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
"system");
-
IsolatedContext::GetInstance()->RevokeFileSystem(isolated_id);
ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
}
@@ -164,7 +164,7 @@ TEST_F(FileSystemContextTest, FileSystemContextKeepsMountPointsAlive) {
// Register system external mount point.
ASSERT_TRUE(mount_points->RegisterFileSystem(
"system",
- fileapi::kFileSystemTypeNativeLocal,
+ storage::kFileSystemTypeNativeLocal,
FileSystemMountOption(),
base::FilePath(DRIVE FPL("/test/sys/"))));
@@ -182,10 +182,10 @@ TEST_F(FileSystemContextTest, FileSystemContextKeepsMountPointsAlive) {
ExpectFileSystemURLMatches(
cracked_external,
GURL(kTestOrigin),
- fileapi::kFileSystemTypeExternal,
- fileapi::kFileSystemTypeNativeLocal,
- base::FilePath(
- DRIVE FPL("/test/sys/root/file")).NormalizePathSeparators(),
+ storage::kFileSystemTypeExternal,
+ storage::kFileSystemTypeNativeLocal,
+ base::FilePath(DRIVE FPL("/test/sys/root/file"))
+ .NormalizePathSeparators(),
base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
"system");
@@ -203,35 +203,35 @@ TEST_F(FileSystemContextTest, CrackFileSystemURL) {
std::string isolated_file_system_name = "root";
const std::string kIsolatedFileSystemID =
IsolatedContext::GetInstance()->RegisterFileSystemForPath(
- fileapi::kFileSystemTypeNativeLocal,
+ storage::kFileSystemTypeNativeLocal,
std::string(),
base::FilePath(DRIVE FPL("/test/isolated/root")),
&isolated_file_system_name);
// Register system external mount point.
ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
"system",
- fileapi::kFileSystemTypeDrive,
+ storage::kFileSystemTypeDrive,
FileSystemMountOption(),
base::FilePath(DRIVE FPL("/test/sys/"))));
ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
"ext",
- fileapi::kFileSystemTypeNativeLocal,
+ storage::kFileSystemTypeNativeLocal,
FileSystemMountOption(),
base::FilePath(DRIVE FPL("/test/ext"))));
// Register a system external mount point with the same name/id as the
// registered isolated mount point.
ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
kIsolatedFileSystemID,
- fileapi::kFileSystemTypeRestrictedNativeLocal,
+ storage::kFileSystemTypeRestrictedNativeLocal,
FileSystemMountOption(),
base::FilePath(DRIVE FPL("/test/system/isolated"))));
// Add a mount points with the same name as a system mount point to
// FileSystemContext's external mount points.
ASSERT_TRUE(external_mount_points->RegisterFileSystem(
"ext",
- fileapi::kFileSystemTypeNativeLocal,
- FileSystemMountOption(),
- base::FilePath(DRIVE FPL("/test/local/ext/"))));
+ storage::kFileSystemTypeNativeLocal,
+ FileSystemMountOption(),
+ base::FilePath(DRIVE FPL("/test/local/ext/"))));
const GURL kTestOrigin = GURL("http://chromium.org/");
const base::FilePath kVirtualPathNoRoot = base::FilePath(FPL("root/file"));
@@ -243,8 +243,8 @@ TEST_F(FileSystemContextTest, CrackFileSystemURL) {
// Expected test results.
bool expect_is_valid;
- fileapi::FileSystemType expect_mount_type;
- fileapi::FileSystemType expect_type;
+ storage::FileSystemType expect_mount_type;
+ storage::FileSystemType expect_type;
const base::FilePath::CharType* expect_path;
std::string expect_filesystem_id;
};
@@ -252,63 +252,45 @@ TEST_F(FileSystemContextTest, CrackFileSystemURL) {
const TestCase kTestCases[] = {
// Following should not be handled by the url crackers:
{
- "pers_mount", "persistent", true /* is_valid */,
- fileapi::kFileSystemTypePersistent, fileapi::kFileSystemTypePersistent,
- FPL("pers_mount/root/file"),
- std::string() /* filesystem id */
+ "pers_mount", "persistent", true /* is_valid */,
+ storage::kFileSystemTypePersistent, storage::kFileSystemTypePersistent,
+ FPL("pers_mount/root/file"), std::string() /* filesystem id */
},
{
- "temp_mount", "temporary", true /* is_valid */,
- fileapi::kFileSystemTypeTemporary, fileapi::kFileSystemTypeTemporary,
- FPL("temp_mount/root/file"),
- std::string() /* filesystem id */
+ "temp_mount", "temporary", true /* is_valid */,
+ storage::kFileSystemTypeTemporary, storage::kFileSystemTypeTemporary,
+ FPL("temp_mount/root/file"), std::string() /* filesystem id */
},
// Should be cracked by isolated mount points:
- {
- kIsolatedFileSystemID, "isolated", true /* is_valid */,
- fileapi::kFileSystemTypeIsolated, fileapi::kFileSystemTypeNativeLocal,
- DRIVE FPL("/test/isolated/root/file"),
- kIsolatedFileSystemID
- },
+ {kIsolatedFileSystemID, "isolated", true /* is_valid */,
+ storage::kFileSystemTypeIsolated, storage::kFileSystemTypeNativeLocal,
+ DRIVE FPL("/test/isolated/root/file"), kIsolatedFileSystemID},
// Should be cracked by system mount points:
- {
- "system", "external", true /* is_valid */,
- fileapi::kFileSystemTypeExternal, fileapi::kFileSystemTypeDrive,
- DRIVE FPL("/test/sys/root/file"),
- "system"
- },
- {
- kIsolatedFileSystemID, "external", true /* is_valid */,
- fileapi::kFileSystemTypeExternal,
- fileapi::kFileSystemTypeRestrictedNativeLocal,
- DRIVE FPL("/test/system/isolated/root/file"),
- kIsolatedFileSystemID
- },
+ {"system", "external", true /* is_valid */,
+ storage::kFileSystemTypeExternal, storage::kFileSystemTypeDrive,
+ DRIVE FPL("/test/sys/root/file"), "system"},
+ {kIsolatedFileSystemID, "external", true /* is_valid */,
+ storage::kFileSystemTypeExternal,
+ storage::kFileSystemTypeRestrictedNativeLocal,
+ DRIVE FPL("/test/system/isolated/root/file"), kIsolatedFileSystemID},
// Should be cracked by FileSystemContext's ExternalMountPoints.
- {
- "ext", "external", true /* is_valid */,
- fileapi::kFileSystemTypeExternal, fileapi::kFileSystemTypeNativeLocal,
- DRIVE FPL("/test/local/ext/root/file"),
- "ext"
- },
+ {"ext", "external", true /* is_valid */, storage::kFileSystemTypeExternal,
+ storage::kFileSystemTypeNativeLocal,
+ DRIVE FPL("/test/local/ext/root/file"), "ext"},
// Test for invalid filesystem url (made invalid by adding invalid
// filesystem type).
- {
- "sytem", "external", false /* is_valid */,
- // The rest of values will be ignored.
- fileapi::kFileSystemTypeUnknown, fileapi::kFileSystemTypeUnknown,
- FPL(""), std::string()
- },
+ {"sytem", "external", false /* is_valid */,
+ // The rest of values will be ignored.
+ storage::kFileSystemTypeUnknown, storage::kFileSystemTypeUnknown,
+ FPL(""), std::string()},
// Test for URL with non-existing filesystem id.
- {
- "invalid", "external", false /* is_valid */,
- // The rest of values will be ignored.
- fileapi::kFileSystemTypeUnknown, fileapi::kFileSystemTypeUnknown,
- FPL(""), std::string()
- },
+ {"invalid", "external", false /* is_valid */,
+ // The rest of values will be ignored.
+ storage::kFileSystemTypeUnknown, storage::kFileSystemTypeUnknown,
+ FPL(""), std::string()},
};
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
const base::FilePath virtual_path =
base::FilePath::FromUTF8Unsafe(
kTestCases[i].root).Append(kVirtualPathNoRoot);
@@ -351,31 +333,32 @@ TEST_F(FileSystemContextTest, CanServeURLRequest) {
// A request for a sandbox mount point should be served.
FileSystemURL cracked_url =
context->CrackURL(CreateRawFileSystemURL("persistent", "pers_mount"));
- EXPECT_EQ(fileapi::kFileSystemTypePersistent, cracked_url.mount_type());
+ EXPECT_EQ(storage::kFileSystemTypePersistent, cracked_url.mount_type());
EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
// A request for an isolated mount point should NOT be served.
std::string isolated_fs_name = "root";
std::string isolated_fs_id =
IsolatedContext::GetInstance()->RegisterFileSystemForPath(
- fileapi::kFileSystemTypeNativeLocal,
+ storage::kFileSystemTypeNativeLocal,
std::string(),
base::FilePath(DRIVE FPL("/test/isolated/root")),
&isolated_fs_name);
cracked_url = context->CrackURL(
CreateRawFileSystemURL("isolated", isolated_fs_id));
- EXPECT_EQ(fileapi::kFileSystemTypeIsolated, cracked_url.mount_type());
+ EXPECT_EQ(storage::kFileSystemTypeIsolated, cracked_url.mount_type());
EXPECT_FALSE(context->CanServeURLRequest(cracked_url));
// A request for an external mount point should be served.
const std::string kExternalMountName = "ext_mount";
ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
- kExternalMountName, fileapi::kFileSystemTypeDrive,
+ kExternalMountName,
+ storage::kFileSystemTypeDrive,
FileSystemMountOption(),
base::FilePath()));
cracked_url = context->CrackURL(
CreateRawFileSystemURL("external", kExternalMountName));
- EXPECT_EQ(fileapi::kFileSystemTypeExternal, cracked_url.mount_type());
+ EXPECT_EQ(storage::kFileSystemTypeExternal, cracked_url.mount_type());
EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
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 8741cff294b..e496954c229 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
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/file_system_dir_url_request_job.h"
+#include "storage/browser/fileapi/file_system_dir_url_request_job.h"
#include <string>
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/format_macros.h"
#include "base/memory/scoped_vector.h"
@@ -26,17 +26,17 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_test_util.h"
+#include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_file_util.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/file_system_url.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/icu/source/i18n/unicode/regex.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-using fileapi::FileSystemContext;
-using fileapi::FileSystemOperationContext;
-using fileapi::FileSystemURL;
+using storage::FileSystemContext;
+using storage::FileSystemOperationContext;
+using storage::FileSystemURL;
namespace content {
namespace {
@@ -50,7 +50,7 @@ const char kValidExternalMountPoint[] = "mnt_name";
// "automount", but will only succeed for the mount point "mnt_name".
bool TestAutoMountForURLRequest(
const net::URLRequest* /*url_request*/,
- const fileapi::FileSystemURL& filesystem_url,
+ const storage::FileSystemURL& filesystem_url,
const std::string& storage_domain,
const base::Callback<void(base::File::Error result)>& callback) {
if (storage_domain != "automount")
@@ -61,9 +61,11 @@ bool TestAutoMountForURLRequest(
std::string mount_point = base::FilePath(components[0]).AsUTF8Unsafe();
if (mount_point == kValidExternalMountPoint) {
- fileapi::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
- kValidExternalMountPoint, fileapi::kFileSystemTypeTest,
- fileapi::FileSystemMountOption(), base::FilePath());
+ storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+ kValidExternalMountPoint,
+ storage::kFileSystemTypeTest,
+ storage::FileSystemMountOption(),
+ base::FilePath());
callback.Run(base::File::FILE_OK);
} else {
callback.Run(base::File::FILE_ERROR_NOT_FOUND);
@@ -78,23 +80,34 @@ class FileSystemDirURLRequestJobFactory : public net::URLRequestJobFactory {
: storage_domain_(storage_domain), file_system_context_(context) {
}
- virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+ net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
- return new fileapi::FileSystemDirURLRequestJob(
+ net::NetworkDelegate* network_delegate) const override {
+ return new storage::FileSystemDirURLRequestJob(
request, network_delegate, storage_domain_, file_system_context_);
}
- virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
- return true;
+ net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const override {
+ return nullptr;
+ }
+
+ net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return nullptr;
}
- virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
+ bool IsHandledProtocol(const std::string& scheme) const override {
return true;
}
- virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
+ bool IsHandledURL(const GURL& url) const override { return true; }
+
+ bool IsSafeRedirectTarget(const GURL& location) const override {
return false;
}
@@ -112,7 +125,7 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
: weak_factory_(this) {
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
special_storage_policy_ = new MockSpecialStoragePolicy;
@@ -120,14 +133,15 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
NULL, temp_dir_.path());
file_system_context_->OpenFileSystem(
- GURL("http://remote/"), fileapi::kFileSystemTypeTemporary,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ GURL("http://remote/"),
+ storage::kFileSystemTypeTemporary,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&FileSystemDirURLRequestJobTest::OnOpenFileSystem,
weak_factory_.GetWeakPtr()));
base::RunLoop().RunUntilIdle();
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// NOTE: order matters, request must die before delegate
request_.reset(NULL);
delegate_.reset(NULL);
@@ -137,11 +151,11 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
*mnt_point = temp_dir_.path().AppendASCII("auto_mount_dir");
ASSERT_TRUE(base::CreateDirectory(*mnt_point));
- ScopedVector<fileapi::FileSystemBackend> additional_providers;
+ ScopedVector<storage::FileSystemBackend> additional_providers;
additional_providers.push_back(new TestFileSystemBackend(
base::MessageLoopProxy::current().get(), *mnt_point));
- std::vector<fileapi::URLRequestAutoMountHandler> handlers;
+ std::vector<storage::URLRequestAutoMountHandler> handlers;
handlers.push_back(base::Bind(&TestAutoMountForURLRequest));
file_system_context_ = CreateFileSystemContextWithAutoMountersForTesting(
@@ -185,9 +199,7 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
FileSystemURL CreateURL(const base::FilePath& file_path) {
return file_system_context_->CreateCrackedFileSystemURL(
- GURL("http://remote"),
- fileapi::kFileSystemTypeTemporary,
- file_path);
+ GURL("http://remote"), storage::kFileSystemTypeTemporary, file_path);
}
FileSystemOperationContext* NewOperationContext() {
@@ -268,7 +280,7 @@ class FileSystemDirURLRequestJobTest : public testing::Test {
return GURL(kFileSystemURLPrefix + path);
}
- fileapi::FileSystemFileUtil* file_util() {
+ storage::FileSystemFileUtil* file_util() {
return file_system_context_->sandbox_delegate()->sync_file_util();
}
@@ -406,7 +418,7 @@ TEST_F(FileSystemDirURLRequestJobTest, AutoMountDirectoryListing) {
VerifyListingEntry(listing_entries[1], "foo", "foo", true, -1);
ASSERT_TRUE(
- fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+ storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
kValidExternalMountPoint));
}
@@ -420,7 +432,7 @@ TEST_F(FileSystemDirURLRequestJobTest, AutoMountInvalidRoot) {
EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
ASSERT_FALSE(
- fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+ storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
"invalid"));
}
@@ -434,7 +446,7 @@ TEST_F(FileSystemDirURLRequestJobTest, AutoMountNoHandler) {
EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
ASSERT_FALSE(
- fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+ storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
kValidExternalMountPoint));
}
diff --git a/chromium/content/browser/fileapi/file_system_file_stream_reader_unittest.cc b/chromium/content/browser/fileapi/file_system_file_stream_reader_unittest.cc
index fe1d25e5ddf..5e13f15c288 100644
--- a/chromium/content/browser/fileapi/file_system_file_stream_reader_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_file_stream_reader_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 "webkit/browser/fileapi/file_system_file_stream_reader.h"
+#include "storage/browser/fileapi/file_system_file_stream_reader.h"
#include <limits>
#include <string>
@@ -15,16 +15,16 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
+#include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_file_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemContext;
-using fileapi::FileSystemFileStreamReader;
-using fileapi::FileSystemType;
-using fileapi::FileSystemURL;
+using storage::FileSystemContext;
+using storage::FileSystemFileStreamReader;
+using storage::FileSystemType;
+using storage::FileSystemURL;
namespace content {
@@ -35,7 +35,7 @@ const char kTestFileName[] = "test.dat";
const char kTestData[] = "0123456789";
const int kTestDataSize = arraysize(kTestData) - 1;
-void ReadFromReader(fileapi::FileSystemFileStreamReader* reader,
+void ReadFromReader(storage::FileSystemFileStreamReader* reader,
std::string* data,
size_t size,
int* result) {
@@ -67,15 +67,16 @@ class FileSystemFileStreamReaderTest : public testing::Test {
public:
FileSystemFileStreamReaderTest() {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_system_context_ = CreateFileSystemContextForTesting(
NULL, temp_dir_.path());
file_system_context_->OpenFileSystem(
- GURL(kURLOrigin), fileapi::kFileSystemTypeTemporary,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ GURL(kURLOrigin),
+ storage::kFileSystemTypeTemporary,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&OnOpenFileSystem));
base::RunLoop().RunUntilIdle();
@@ -83,12 +84,10 @@ class FileSystemFileStreamReaderTest : public testing::Test {
&test_file_modification_time_);
}
- virtual void TearDown() OVERRIDE {
- base::RunLoop().RunUntilIdle();
- }
+ void TearDown() override { base::RunLoop().RunUntilIdle(); }
protected:
- fileapi::FileSystemFileStreamReader* CreateFileReader(
+ storage::FileSystemFileStreamReader* CreateFileReader(
const std::string& file_name,
int64 initial_offset,
const base::Time& expected_modification_time) {
@@ -110,12 +109,12 @@ class FileSystemFileStreamReaderTest : public testing::Test {
ASSERT_EQ(base::File::FILE_OK,
content::AsyncFileTestHelper::CreateFileWithData(
- file_system_context_, url, buf, buf_size));
+ file_system_context_.get(), url, buf, buf_size));
base::File::Info file_info;
ASSERT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::GetMetadata(
- file_system_context_, url, &file_info));
+ file_system_context_.get(), url, &file_info));
if (modification_time)
*modification_time = file_info.last_modified;
}
@@ -130,7 +129,7 @@ class FileSystemFileStreamReaderTest : public testing::Test {
FileSystemURL GetFileSystemURL(const std::string& file_name) {
return file_system_context_->CreateCrackedFileSystemURL(
GURL(kURLOrigin),
- fileapi::kFileSystemTypeTemporary,
+ storage::kFileSystemTypeTemporary,
base::FilePath().AppendASCII(file_name));
}
diff --git a/chromium/content/browser/fileapi/file_system_operation_impl_unittest.cc b/chromium/content/browser/fileapi/file_system_operation_impl_unittest.cc
index 2f8e82ec094..23a8c2d679b 100644
--- a/chromium/content/browser/fileapi/file_system_operation_impl_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_operation_impl_unittest.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/file_system_operation_impl.h"
+#include "storage/browser/fileapi/file_system_operation_impl.h"
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -13,58 +13,47 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "content/browser/fileapi/mock_file_change_observer.h"
+#include "content/browser/fileapi/mock_file_update_observer.h"
#include "content/browser/quota/mock_quota_manager.h"
#include "content/browser/quota/mock_quota_manager_proxy.h"
#include "content/public/test/async_file_test_helper.h"
#include "content/public/test/sandbox_file_system_test_helper.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_file_util.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/browser/fileapi/sandbox_file_system_backend.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/blob/shareable_file_reference.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-#include "webkit/browser/fileapi/sandbox_file_system_backend.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-#include "webkit/common/blob/shareable_file_reference.h"
-#include "webkit/common/fileapi/file_system_util.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemOperation;
-using fileapi::FileSystemOperationContext;
-using fileapi::FileSystemOperationRunner;
-using fileapi::FileSystemURL;
-using quota::QuotaManager;
-using quota::QuotaManagerProxy;
-using webkit_blob::ShareableFileReference;
+using storage::FileSystemOperation;
+using storage::FileSystemOperationContext;
+using storage::FileSystemOperationRunner;
+using storage::FileSystemURL;
+using storage::QuotaManager;
+using storage::QuotaManagerProxy;
+using storage::ShareableFileReference;
namespace content {
-namespace {
-
-const int kFileOperationStatusNotSet = 1;
-
-void AssertFileErrorEq(const tracked_objects::Location& from_here,
- base::File::Error expected,
- base::File::Error actual) {
- ASSERT_EQ(expected, actual) << from_here.ToString();
-}
-
-} // namespace
-
// Test class for FileSystemOperationImpl.
class FileSystemOperationImplTest
: public testing::Test {
public:
- FileSystemOperationImplTest()
- : status_(kFileOperationStatusNotSet),
- weak_factory_(this) {}
+ FileSystemOperationImplTest() : weak_factory_(this) {}
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
EXPECT_TRUE(base_.CreateUniqueTempDir());
- change_observers_ = fileapi::MockFileChangeObserver::CreateList(
- &change_observer_);
+ change_observers_ =
+ storage::MockFileChangeObserver::CreateList(&change_observer_);
+ update_observers_ =
+ storage::MockFileUpdateObserver::CreateList(&update_observer_);
base::FilePath base_dir = base_.path().AppendASCII("filesystem");
quota_manager_ =
@@ -77,9 +66,11 @@ class FileSystemOperationImplTest
quota_manager(), base::MessageLoopProxy::current().get());
sandbox_file_system_.SetUp(base_dir, quota_manager_proxy_.get());
sandbox_file_system_.AddFileChangeObserver(&change_observer_);
+ sandbox_file_system_.AddFileUpdateObserver(&update_observer_);
+ update_observer_.Disable();
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// Let the client go away before dropping a ref of the quota manager proxy.
quota_manager_proxy()->SimulateQuotaManagerDestroyed();
quota_manager_ = NULL;
@@ -91,10 +82,9 @@ class FileSystemOperationImplTest
return sandbox_file_system_.operation_runner();
}
- int status() const { return status_; }
const base::File::Info& info() const { return info_; }
const base::FilePath& path() const { return path_; }
- const std::vector<fileapi::DirectoryEntry>& entries() const {
+ const std::vector<storage::DirectoryEntry>& entries() const {
return entries_;
}
@@ -111,11 +101,11 @@ class FileSystemOperationImplTest
quota_manager_proxy_.get());
}
- fileapi::FileSystemFileUtil* file_util() {
+ storage::FileSystemFileUtil* file_util() {
return sandbox_file_system_.file_util();
}
- fileapi::MockFileChangeObserver* change_observer() {
+ storage::MockFileChangeObserver* change_observer() {
return &change_observer_;
}
@@ -172,54 +162,80 @@ class FileSystemOperationImplTest
}
// Callbacks for recording test results.
- FileSystemOperation::StatusCallback RecordStatusCallback() {
+ FileSystemOperation::StatusCallback RecordStatusCallback(
+ const base::Closure& closure,
+ base::File::Error* status) {
return base::Bind(&FileSystemOperationImplTest::DidFinish,
- weak_factory_.GetWeakPtr());
+ weak_factory_.GetWeakPtr(),
+ closure,
+ status);
}
- FileSystemOperation::ReadDirectoryCallback
- RecordReadDirectoryCallback() {
+ FileSystemOperation::ReadDirectoryCallback RecordReadDirectoryCallback(
+ const base::Closure& closure,
+ base::File::Error* status) {
return base::Bind(&FileSystemOperationImplTest::DidReadDirectory,
- weak_factory_.GetWeakPtr());
+ weak_factory_.GetWeakPtr(),
+ closure,
+ status);
}
- FileSystemOperation::GetMetadataCallback RecordMetadataCallback() {
+ FileSystemOperation::GetMetadataCallback RecordMetadataCallback(
+ const base::Closure& closure,
+ base::File::Error* status) {
return base::Bind(&FileSystemOperationImplTest::DidGetMetadata,
- weak_factory_.GetWeakPtr());
+ weak_factory_.GetWeakPtr(),
+ closure,
+ status);
}
- FileSystemOperation::SnapshotFileCallback RecordSnapshotFileCallback() {
+ FileSystemOperation::SnapshotFileCallback RecordSnapshotFileCallback(
+ const base::Closure& closure,
+ base::File::Error* status) {
return base::Bind(&FileSystemOperationImplTest::DidCreateSnapshotFile,
- weak_factory_.GetWeakPtr());
+ weak_factory_.GetWeakPtr(),
+ closure,
+ status);
}
- void DidFinish(base::File::Error status) {
- status_ = status;
+ void DidFinish(const base::Closure& closure,
+ base::File::Error* status,
+ base::File::Error actual) {
+ *status = actual;
+ closure.Run();
}
- void DidReadDirectory(
- base::File::Error status,
- const std::vector<fileapi::DirectoryEntry>& entries,
- bool /* has_more */) {
+ void DidReadDirectory(const base::Closure& closure,
+ base::File::Error* status,
+ base::File::Error actual,
+ const std::vector<storage::DirectoryEntry>& entries,
+ bool /* has_more */) {
entries_ = entries;
- status_ = status;
+ *status = actual;
+ closure.Run();
}
- void DidGetMetadata(base::File::Error status,
+ void DidGetMetadata(const base::Closure& closure,
+ base::File::Error* status,
+ base::File::Error actual,
const base::File::Info& info) {
info_ = info;
- status_ = status;
+ *status = actual;
+ closure.Run();
}
void DidCreateSnapshotFile(
- base::File::Error status,
+ const base::Closure& closure,
+ base::File::Error* status,
+ base::File::Error actual,
const base::File::Info& info,
const base::FilePath& platform_path,
const scoped_refptr<ShareableFileReference>& shareable_file_ref) {
info_ = info;
path_ = platform_path;
- status_ = status;
+ *status = actual;
shareable_file_ref_ = shareable_file_ref;
+ closure.Run();
}
int64 GetDataSizeOnDisk() {
@@ -228,14 +244,14 @@ class FileSystemOperationImplTest
}
void GetUsageAndQuota(int64* usage, int64* quota) {
- quota::QuotaStatusCode status =
+ storage::QuotaStatusCode status =
AsyncFileTestHelper::GetUsageAndQuota(quota_manager_.get(),
sandbox_file_system_.origin(),
sandbox_file_system_.type(),
usage,
quota);
base::RunLoop().RunUntilIdle();
- ASSERT_EQ(quota::kQuotaStatusOk, status);
+ ASSERT_EQ(storage::kQuotaStatusOk, status);
}
int64 ComputePathCost(const FileSystemURL& url) {
@@ -244,10 +260,8 @@ class FileSystemOperationImplTest
AsyncFileTestHelper::CreateFile(
sandbox_file_system_.file_system_context(), url);
- operation_runner()->Remove(url, false /* recursive */,
- base::Bind(&AssertFileErrorEq, FROM_HERE,
- base::File::FILE_OK));
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(base::File::FILE_OK, Remove(url, false /* recursive */));
+
change_observer()->ResetCount();
int64 total_usage;
@@ -277,8 +291,175 @@ class FileSystemOperationImplTest
quota + quota_delta);
}
+ base::File::Error Move(
+ const FileSystemURL& src,
+ const FileSystemURL& dest,
+ storage::FileSystemOperation::CopyOrMoveOption option) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->Move(
+ src,
+ dest,
+ option,
+ RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error Copy(
+ const FileSystemURL& src,
+ const FileSystemURL& dest,
+ storage::FileSystemOperation::CopyOrMoveOption option) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->Copy(
+ src,
+ dest,
+ option,
+ FileSystemOperationRunner::CopyProgressCallback(),
+ RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error CopyInForeignFile(const base::FilePath& src,
+ const FileSystemURL& dest) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->CopyInForeignFile(
+ src, dest, RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error Truncate(const FileSystemURL& url, int size) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->Truncate(
+ url, size, RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error CreateFile(const FileSystemURL& url, bool exclusive) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->CreateFile(
+ url, exclusive, RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error Remove(const FileSystemURL& url, bool recursive) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->Remove(
+ url, recursive, RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error CreateDirectory(const FileSystemURL& url,
+ bool exclusive,
+ bool recursive) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->CreateDirectory(
+ url,
+ exclusive,
+ recursive,
+ RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error GetMetadata(const FileSystemURL& url) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->GetMetadata(
+ url, RecordMetadataCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error ReadDirectory(const FileSystemURL& url) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->ReadDirectory(
+ url, RecordReadDirectoryCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error CreateSnapshotFile(const FileSystemURL& url) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->CreateSnapshotFile(
+ url, RecordSnapshotFileCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error FileExists(const FileSystemURL& url) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->FileExists(
+ url, RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error DirectoryExists(const FileSystemURL& url) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->DirectoryExists(
+ url, RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
+ base::File::Error TouchFile(const FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time) {
+ base::File::Error status;
+ base::RunLoop run_loop;
+ update_observer_.Enable();
+ operation_runner()->TouchFile(
+ url,
+ last_access_time,
+ last_modified_time,
+ RecordStatusCallback(run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ update_observer_.Disable();
+ return status;
+ }
+
private:
- base::MessageLoop message_loop_;
+ base::MessageLoopForIO message_loop_;
scoped_refptr<QuotaManager> quota_manager_;
scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
@@ -288,14 +469,15 @@ class FileSystemOperationImplTest
SandboxFileSystemTestHelper sandbox_file_system_;
// For post-operation status.
- int status_;
base::File::Info info_;
base::FilePath path_;
- std::vector<fileapi::DirectoryEntry> entries_;
+ std::vector<storage::DirectoryEntry> entries_;
scoped_refptr<ShareableFileReference> shareable_file_ref_;
- fileapi::MockFileChangeObserver change_observer_;
- fileapi::ChangeObserverList change_observers_;
+ storage::MockFileChangeObserver change_observer_;
+ storage::ChangeObserverList change_observers_;
+ storage::MockFileUpdateObserver update_observer_;
+ storage::UpdateObserverList update_observers_;
base::WeakPtrFactory<FileSystemOperationImplTest> weak_factory_;
@@ -304,11 +486,9 @@ class FileSystemOperationImplTest
TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcDoesntExist) {
change_observer()->ResetCount();
- operation_runner()->Move(URLForPath("a"), URLForPath("b"),
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
+ EXPECT_EQ(
+ base::File::FILE_ERROR_NOT_FOUND,
+ Move(URLForPath("a"), URLForPath("b"), FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -316,11 +496,8 @@ TEST_F(FileSystemOperationImplTest, TestMoveFailureContainsPath) {
FileSystemURL src_dir(CreateDirectory("src"));
FileSystemURL dest_dir(CreateDirectory("src/dest"));
- operation_runner()->Move(src_dir, dest_dir,
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION,
+ Move(src_dir, dest_dir, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -330,11 +507,8 @@ TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcDirExistsDestFile) {
FileSystemURL dest_dir(CreateDirectory("dest"));
FileSystemURL dest_file(CreateFile("dest/file"));
- operation_runner()->Move(src_dir, dest_file,
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION,
+ Move(src_dir, dest_file, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -345,11 +519,8 @@ TEST_F(FileSystemOperationImplTest,
FileSystemURL dest_dir(CreateDirectory("dest"));
FileSystemURL dest_file(CreateFile("dest/file"));
- operation_runner()->Move(src_dir, dest_dir,
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY,
+ Move(src_dir, dest_dir, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -359,22 +530,18 @@ TEST_F(FileSystemOperationImplTest, TestMoveFailureSrcFileExistsDestDir) {
FileSystemURL src_file(CreateFile("src/file"));
FileSystemURL dest_dir(CreateDirectory("dest"));
- operation_runner()->Move(src_file, dest_dir,
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION,
+ Move(src_file, dest_dir, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(FileSystemOperationImplTest, TestMoveFailureDestParentDoesntExist) {
// Dest. parent path does not exist.
FileSystemURL src_dir(CreateDirectory("src"));
- operation_runner()->Move(src_dir, URLForPath("nonexistent/deset"),
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
+ Move(src_dir,
+ URLForPath("nonexistent/deset"),
+ FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -382,11 +549,8 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndOverwrite) {
FileSystemURL src_file(CreateFile("src"));
FileSystemURL dest_file(CreateFile("dest"));
- operation_runner()->Move(src_file, dest_file,
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ Move(src_file, dest_file, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(FileExists("dest"));
EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
@@ -399,11 +563,9 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndOverwrite) {
TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcFileAndNew) {
FileSystemURL src_file(CreateFile("src"));
- operation_runner()->Move(src_file, URLForPath("new"),
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(
+ base::File::FILE_OK,
+ Move(src_file, URLForPath("new"), FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(FileExists("new"));
EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
@@ -415,11 +577,8 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirAndOverwrite) {
FileSystemURL src_dir(CreateDirectory("src"));
FileSystemURL dest_dir(CreateDirectory("dest"));
- operation_runner()->Move(src_dir, dest_dir,
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ Move(src_dir, dest_dir, FileSystemOperation::OPTION_NONE));
EXPECT_FALSE(DirectoryExists("src"));
EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
@@ -435,11 +594,9 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirAndNew) {
FileSystemURL src_dir(CreateDirectory("src"));
FileSystemURL dest_dir(CreateDirectory("dest"));
- operation_runner()->Move(src_dir, URLForPath("dest/new"),
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(
+ base::File::FILE_OK,
+ Move(src_dir, URLForPath("dest/new"), FileSystemOperation::OPTION_NONE));
EXPECT_FALSE(DirectoryExists("src"));
EXPECT_TRUE(DirectoryExists("dest/new"));
@@ -455,11 +612,8 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSrcDirRecursive) {
FileSystemURL dest_dir(CreateDirectory("dest"));
- operation_runner()->Move(src_dir, dest_dir,
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ Move(src_dir, dest_dir, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(DirectoryExists("dest/dir"));
EXPECT_TRUE(FileExists("dest/dir/sub"));
@@ -475,11 +629,8 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSamePath) {
CreateDirectory("src/dir");
CreateFile("src/dir/sub");
- operation_runner()->Move(src_dir, src_dir,
- FileSystemOperation::OPTION_NONE,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ Move(src_dir, src_dir, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(DirectoryExists("src/dir"));
EXPECT_TRUE(FileExists("src/dir/sub"));
@@ -491,12 +642,9 @@ TEST_F(FileSystemOperationImplTest, TestMoveSuccessSamePath) {
}
TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcDoesntExist) {
- operation_runner()->Copy(URLForPath("a"), URLForPath("b"),
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
+ EXPECT_EQ(
+ base::File::FILE_ERROR_NOT_FOUND,
+ Copy(URLForPath("a"), URLForPath("b"), FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -504,12 +652,8 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureContainsPath) {
FileSystemURL src_dir(CreateDirectory("src"));
FileSystemURL dest_dir(CreateDirectory("src/dir"));
- operation_runner()->Copy(src_dir, dest_dir,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION,
+ Copy(src_dir, dest_dir, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -519,12 +663,8 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcDirExistsDestFile) {
FileSystemURL dest_dir(CreateDirectory("dest"));
FileSystemURL dest_file(CreateFile("dest/file"));
- operation_runner()->Copy(src_dir, dest_file,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION,
+ Copy(src_dir, dest_file, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -535,12 +675,8 @@ TEST_F(FileSystemOperationImplTest,
FileSystemURL dest_dir(CreateDirectory("dest"));
FileSystemURL dest_file(CreateFile("dest/file"));
- operation_runner()->Copy(src_dir, dest_dir,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY,
+ Copy(src_dir, dest_dir, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -549,12 +685,8 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureSrcFileExistsDestDir) {
FileSystemURL src_file(CreateFile("src"));
FileSystemURL dest_dir(CreateDirectory("dest"));
- operation_runner()->Copy(src_file, dest_dir,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION,
+ Copy(src_file, dest_dir, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -562,12 +694,10 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureDestParentDoesntExist) {
// Dest. parent path does not exist.
FileSystemURL src_dir(CreateDirectory("src"));
- operation_runner()->Copy(src_dir, URLForPath("nonexistent/dest"),
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
+ Copy(src_dir,
+ URLForPath("nonexistent/dest"),
+ FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -575,9 +705,7 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureByQuota) {
FileSystemURL src_dir(CreateDirectory("src"));
FileSystemURL src_file(CreateFile("src/file"));
FileSystemURL dest_dir(CreateDirectory("dest"));
- operation_runner()->Truncate(src_file, 6, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, Truncate(src_file, 6));
EXPECT_EQ(6, GetFileSize("src/file"));
FileSystemURL dest_file(URLForPath("dest/file"));
@@ -585,12 +713,8 @@ TEST_F(FileSystemOperationImplTest, TestCopyFailureByQuota) {
GrantQuotaForCurrentUsage();
AddQuota(6 + dest_path_cost - 1);
- operation_runner()->Copy(src_file, dest_file,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE,
+ Copy(src_file, dest_file, FileSystemOperation::OPTION_NONE));
EXPECT_FALSE(FileExists("dest/file"));
}
@@ -598,32 +722,27 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcFileAndOverwrite) {
FileSystemURL src_file(CreateFile("src"));
FileSystemURL dest_file(CreateFile("dest"));
- operation_runner()->Copy(src_file, dest_file,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ Copy(src_file, dest_file, FileSystemOperation::OPTION_NONE));
+
EXPECT_TRUE(FileExists("dest"));
- EXPECT_EQ(2, quota_manager_proxy()->notify_storage_accessed_count());
+ EXPECT_EQ(4, quota_manager_proxy()->notify_storage_accessed_count());
+ EXPECT_EQ(2, change_observer()->get_and_reset_modify_file_count());
- EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcFileAndNew) {
FileSystemURL src_file(CreateFile("src"));
- operation_runner()->Copy(src_file, URLForPath("new"),
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(
+ base::File::FILE_OK,
+ Copy(src_file, URLForPath("new"), FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(FileExists("new"));
- EXPECT_EQ(2, quota_manager_proxy()->notify_storage_accessed_count());
+ EXPECT_EQ(4, quota_manager_proxy()->notify_storage_accessed_count());
- EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -631,20 +750,16 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirAndOverwrite) {
FileSystemURL src_dir(CreateDirectory("src"));
FileSystemURL dest_dir(CreateDirectory("dest"));
- operation_runner()->Copy(src_dir, dest_dir,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ Copy(src_dir, dest_dir, FileSystemOperation::OPTION_NONE));
// Make sure we've overwritten but not copied the source under the |dest_dir|.
EXPECT_TRUE(DirectoryExists("dest"));
EXPECT_FALSE(DirectoryExists("dest/src"));
EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 3);
- EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -652,12 +767,8 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirAndNew) {
FileSystemURL src_dir(CreateDirectory("src"));
FileSystemURL dest_dir_new(URLForPath("dest"));
- operation_runner()->Copy(src_dir, dest_dir_new,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ Copy(src_dir, dest_dir_new, FileSystemOperation::OPTION_NONE));
EXPECT_TRUE(DirectoryExists("dest"));
EXPECT_GE(quota_manager_proxy()->notify_storage_accessed_count(), 2);
@@ -672,13 +783,9 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirRecursive) {
FileSystemURL dest_dir(CreateDirectory("dest"));
- operation_runner()->Copy(src_dir, dest_dir,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(base::File::FILE_OK,
+ Copy(src_dir, dest_dir, FileSystemOperation::OPTION_NONE));
- EXPECT_EQ(base::File::FILE_OK, status());
EXPECT_TRUE(DirectoryExists("dest/dir"));
EXPECT_TRUE(FileExists("dest/dir/sub"));
@@ -687,7 +794,8 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSrcDirRecursive) {
EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
- EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -696,13 +804,9 @@ TEST_F(FileSystemOperationImplTest, TestCopySuccessSamePath) {
CreateDirectory("src/dir");
CreateFile("src/dir/sub");
- operation_runner()->Copy(src_dir, src_dir,
- FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(base::File::FILE_OK,
+ Copy(src_dir, src_dir, FileSystemOperation::OPTION_NONE));
- EXPECT_EQ(base::File::FILE_OK, status());
EXPECT_TRUE(DirectoryExists("src/dir"));
EXPECT_TRUE(FileExists("src/dir/sub"));
@@ -716,7 +820,7 @@ TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileSuccess) {
base::FilePath src_local_disk_file_path;
base::CreateTemporaryFile(&src_local_disk_file_path);
const char test_data[] = "foo";
- int data_size = ARRAYSIZE_UNSAFE(test_data);
+ int data_size = arraysize(test_data);
base::WriteFile(src_local_disk_file_path, test_data, data_size);
FileSystemURL dest_dir(CreateDirectory("dest"));
@@ -725,13 +829,11 @@ TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileSuccess) {
GetUsageAndQuota(&before_usage, NULL);
// Check that the file copied and corresponding usage increased.
- operation_runner()->CopyInForeignFile(src_local_disk_file_path,
- URLForPath("dest/file"),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(
+ base::File::FILE_OK,
+ CopyInForeignFile(src_local_disk_file_path, URLForPath("dest/file")));
EXPECT_EQ(1, change_observer()->create_file_count());
- EXPECT_EQ(base::File::FILE_OK, status());
EXPECT_TRUE(FileExists("dest/file"));
int64 after_usage;
GetUsageAndQuota(&after_usage, NULL);
@@ -749,37 +851,30 @@ TEST_F(FileSystemOperationImplTest, TestCopyInForeignFileFailureByQuota) {
base::FilePath src_local_disk_file_path;
base::CreateTemporaryFile(&src_local_disk_file_path);
const char test_data[] = "foo";
- base::WriteFile(src_local_disk_file_path, test_data,
- ARRAYSIZE_UNSAFE(test_data));
+ base::WriteFile(src_local_disk_file_path, test_data, arraysize(test_data));
FileSystemURL dest_dir(CreateDirectory("dest"));
GrantQuotaForCurrentUsage();
- operation_runner()->CopyInForeignFile(src_local_disk_file_path,
- URLForPath("dest/file"),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(
+ base::File::FILE_ERROR_NO_SPACE,
+ CopyInForeignFile(src_local_disk_file_path, URLForPath("dest/file")));
EXPECT_FALSE(FileExists("dest/file"));
EXPECT_EQ(0, change_observer()->create_file_count());
- EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, status());
}
TEST_F(FileSystemOperationImplTest, TestCreateFileFailure) {
// Already existing file and exclusive true.
FileSystemURL file(CreateFile("file"));
- operation_runner()->CreateFile(file, true, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_EXISTS, status());
+ EXPECT_EQ(base::File::FILE_ERROR_EXISTS, CreateFile(file, true));
EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileExists) {
// Already existing file and exclusive false.
FileSystemURL file(CreateFile("file"));
- operation_runner()->CreateFile(file, false, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, CreateFile(file, false));
EXPECT_TRUE(FileExists("file"));
// The file was already there; did nothing.
@@ -788,98 +883,70 @@ TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileExists) {
TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessExclusive) {
// File doesn't exist but exclusive is true.
- operation_runner()->CreateFile(URLForPath("new"), true,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, CreateFile(URLForPath("new"), true));
EXPECT_TRUE(FileExists("new"));
EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
}
TEST_F(FileSystemOperationImplTest, TestCreateFileSuccessFileDoesntExist) {
// Non existing file.
- operation_runner()->CreateFile(URLForPath("nonexistent"), false,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, CreateFile(URLForPath("nonexistent"), false));
EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
}
TEST_F(FileSystemOperationImplTest,
TestCreateDirFailureDestParentDoesntExist) {
// Dest. parent path does not exist.
- operation_runner()->CreateDirectory(
- URLForPath("nonexistent/dir"), false, false,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
+ CreateDirectory(URLForPath("nonexistent/dir"), false, false));
EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(FileSystemOperationImplTest, TestCreateDirFailureDirExists) {
// Exclusive and dir existing at path.
FileSystemURL dir(CreateDirectory("dir"));
- operation_runner()->CreateDirectory(dir, true, false,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_EXISTS, status());
+ EXPECT_EQ(base::File::FILE_ERROR_EXISTS, CreateDirectory(dir, true, false));
EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(FileSystemOperationImplTest, TestCreateDirFailureFileExists) {
// Exclusive true and file existing at path.
FileSystemURL file(CreateFile("file"));
- operation_runner()->CreateDirectory(file, true, false,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_EXISTS, status());
+ EXPECT_EQ(base::File::FILE_ERROR_EXISTS, CreateDirectory(file, true, false));
EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(FileSystemOperationImplTest, TestCreateDirSuccess) {
// Dir exists and exclusive is false.
FileSystemURL dir(CreateDirectory("dir"));
- operation_runner()->CreateDirectory(dir, false, false,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, CreateDirectory(dir, false, false));
EXPECT_TRUE(change_observer()->HasNoChange());
// Dir doesn't exist.
- operation_runner()->CreateDirectory(URLForPath("new"), false, false,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ CreateDirectory(URLForPath("new"), false, false));
EXPECT_TRUE(DirectoryExists("new"));
EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
}
TEST_F(FileSystemOperationImplTest, TestCreateDirSuccessExclusive) {
// Dir doesn't exist.
- operation_runner()->CreateDirectory(URLForPath("new"), true, false,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ CreateDirectory(URLForPath("new"), true, false));
EXPECT_TRUE(DirectoryExists("new"));
EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataFailure) {
- operation_runner()->GetMetadata(URLForPath("nonexistent"),
- RecordMetadataCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
-
- operation_runner()->FileExists(URLForPath("nonexistent"),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
-
- operation_runner()->DirectoryExists(URLForPath("nonexistent"),
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
+ GetMetadata(URLForPath("nonexistent")));
+
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
+ FileExists(URLForPath("nonexistent")));
+
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
+ DirectoryExists(URLForPath("nonexistent")));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -888,25 +955,17 @@ TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataSuccess) {
FileSystemURL file(CreateFile("dir/file"));
int read_access = 0;
- operation_runner()->DirectoryExists(dir, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, DirectoryExists(dir));
++read_access;
- operation_runner()->GetMetadata(dir, RecordMetadataCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, GetMetadata(dir));
EXPECT_TRUE(info().is_directory);
++read_access;
- operation_runner()->FileExists(file, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, FileExists(file));
++read_access;
- operation_runner()->GetMetadata(file, RecordMetadataCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, GetMetadata(file));
EXPECT_FALSE(info().is_directory);
++read_access;
@@ -917,28 +976,20 @@ TEST_F(FileSystemOperationImplTest, TestExistsAndMetadataSuccess) {
TEST_F(FileSystemOperationImplTest, TestTypeMismatchErrors) {
FileSystemURL dir(CreateDirectory("dir"));
- operation_runner()->FileExists(dir, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_A_FILE, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_A_FILE, FileExists(dir));
FileSystemURL file(CreateFile("file"));
- operation_runner()->DirectoryExists(file, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, DirectoryExists(file));
}
TEST_F(FileSystemOperationImplTest, TestReadDirFailure) {
// Path doesn't exist
- operation_runner()->ReadDirectory(URLForPath("nonexistent"),
- RecordReadDirectoryCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
+ ReadDirectory(URLForPath("nonexistent")));
// File exists.
FileSystemURL file(CreateFile("file"));
- operation_runner()->ReadDirectory(file, RecordReadDirectoryCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY, ReadDirectory(file));
EXPECT_TRUE(change_observer()->HasNoChange());
}
@@ -951,9 +1002,7 @@ TEST_F(FileSystemOperationImplTest, TestReadDirSuccess) {
FileSystemURL child_dir(CreateDirectory("dir/child_dir"));
FileSystemURL child_file(CreateFile("dir/child_file"));
- operation_runner()->ReadDirectory(parent_dir, RecordReadDirectoryCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, ReadDirectory(parent_dir));
EXPECT_EQ(2u, entries().size());
for (size_t i = 0; i < entries().size(); ++i) {
@@ -968,10 +1017,8 @@ TEST_F(FileSystemOperationImplTest, TestReadDirSuccess) {
TEST_F(FileSystemOperationImplTest, TestRemoveFailure) {
// Path doesn't exist.
- operation_runner()->Remove(URLForPath("nonexistent"), false /* recursive */,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
+ Remove(URLForPath("nonexistent"), false /* recursive */));
// It's an error to try to remove a non-empty directory if recursive flag
// is false.
@@ -983,20 +1030,15 @@ TEST_F(FileSystemOperationImplTest, TestRemoveFailure) {
FileSystemURL child_dir(CreateDirectory("dir/child_dir"));
FileSystemURL child_file(CreateFile("dir/child_file"));
- operation_runner()->Remove(parent_dir, false /* recursive */,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_EMPTY,
+ Remove(parent_dir, false /* recursive */));
EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(FileSystemOperationImplTest, TestRemoveSuccess) {
FileSystemURL empty_dir(CreateDirectory("empty_dir"));
EXPECT_TRUE(DirectoryExists("empty_dir"));
- operation_runner()->Remove(empty_dir, false /* recursive */,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, Remove(empty_dir, false /* recursive */));
EXPECT_FALSE(DirectoryExists("empty_dir"));
EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
@@ -1019,10 +1061,7 @@ TEST_F(FileSystemOperationImplTest, TestRemoveSuccessRecursive) {
for (int i = 0; i < 8; ++i)
CreateFile(base::StringPrintf("dir/child_dir/file-%d", i));
- operation_runner()->Remove(parent_dir, true /* recursive */,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, Remove(parent_dir, true /* recursive */));
EXPECT_FALSE(DirectoryExists("parent_dir"));
EXPECT_EQ(2, change_observer()->get_and_reset_remove_directory_count());
@@ -1040,17 +1079,13 @@ TEST_F(FileSystemOperationImplTest, TestTruncate) {
base::WriteFile(platform_path, test_data, data_size));
// Check that its length is the size of the data written.
- operation_runner()->GetMetadata(file, RecordMetadataCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, GetMetadata(file));
EXPECT_FALSE(info().is_directory);
EXPECT_EQ(data_size, info().size);
// Extend the file by truncating it.
int length = 17;
- operation_runner()->Truncate(file, length, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, Truncate(file, length));
EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
EXPECT_TRUE(change_observer()->HasNoChange());
@@ -1069,9 +1104,7 @@ TEST_F(FileSystemOperationImplTest, TestTruncate) {
// Shorten the file by truncating it.
length = 3;
- operation_runner()->Truncate(file, length, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, Truncate(file, length));
EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
EXPECT_TRUE(change_observer()->HasNoChange());
@@ -1094,17 +1127,13 @@ TEST_F(FileSystemOperationImplTest, TestTruncateFailureByQuota) {
GrantQuotaForCurrentUsage();
AddQuota(10);
- operation_runner()->Truncate(file, 10, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, Truncate(file, 10));
EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
EXPECT_TRUE(change_observer()->HasNoChange());
EXPECT_EQ(10, GetFileSize("dir/file"));
- operation_runner()->Truncate(file, 11, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, status());
+ EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, Truncate(file, 11));
EXPECT_TRUE(change_observer()->HasNoChange());
EXPECT_EQ(10, GetFileSize("dir/file"));
@@ -1127,10 +1156,8 @@ TEST_F(FileSystemOperationImplTest, TestTouchFile) {
ASSERT_NE(last_modified, new_modified_time);
ASSERT_NE(last_accessed, new_accessed_time);
- operation_runner()->TouchFile(file, new_accessed_time, new_modified_time,
- RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK,
+ TouchFile(file, new_accessed_time, new_modified_time));
EXPECT_TRUE(change_observer()->HasNoChange());
EXPECT_TRUE(base::GetFileInfo(platform_path, &info));
@@ -1145,19 +1172,15 @@ TEST_F(FileSystemOperationImplTest, TestCreateSnapshotFile) {
FileSystemURL dir(CreateDirectory("dir"));
// Create a file for the testing.
- operation_runner()->DirectoryExists(dir, RecordStatusCallback());
+ EXPECT_EQ(base::File::FILE_OK, DirectoryExists(dir));
FileSystemURL file(CreateFile("dir/file"));
- operation_runner()->FileExists(file, RecordStatusCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, FileExists(file));
// See if we can get a 'snapshot' file info for the file.
// Since FileSystemOperationImpl assumes the file exists in the local
// directory it should just returns the same metadata and platform_path
// as the file itself.
- operation_runner()->CreateSnapshotFile(file, RecordSnapshotFileCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(base::File::FILE_OK, status());
+ EXPECT_EQ(base::File::FILE_OK, CreateSnapshotFile(file));
EXPECT_FALSE(info().is_directory);
EXPECT_EQ(PlatformPath("dir/file"), path());
EXPECT_TRUE(change_observer()->HasNoChange());
@@ -1182,28 +1205,17 @@ TEST_F(FileSystemOperationImplTest,
int total_path_cost = GetUsage();
EXPECT_EQ(0, GetDataSizeOnDisk());
- operation_runner()->Truncate(
- child_file1, 5000,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- operation_runner()->Truncate(
- child_file2, 400,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- operation_runner()->Truncate(
- grandchild_file1, 30,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- operation_runner()->Truncate(
- grandchild_file2, 2,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(base::File::FILE_OK, Truncate(child_file1, 5000));
+ EXPECT_EQ(base::File::FILE_OK, Truncate(child_file2, 400));
+ EXPECT_EQ(base::File::FILE_OK, Truncate(grandchild_file1, 30));
+ EXPECT_EQ(base::File::FILE_OK, Truncate(grandchild_file2, 2));
const int64 all_file_size = 5000 + 400 + 30 + 2;
EXPECT_EQ(all_file_size, GetDataSizeOnDisk());
EXPECT_EQ(all_file_size + total_path_cost, GetUsage());
- operation_runner()->Move(
- src, dest, FileSystemOperation::OPTION_NONE,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(base::File::FILE_OK,
+ Move(src, dest, FileSystemOperation::OPTION_NONE));
EXPECT_FALSE(DirectoryExists("src/dir"));
EXPECT_FALSE(FileExists("src/dir/file2"));
@@ -1235,19 +1247,10 @@ TEST_F(FileSystemOperationImplTest,
EXPECT_EQ(0, GetDataSizeOnDisk());
- operation_runner()->Truncate(
- child_file1, 8000,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- operation_runner()->Truncate(
- child_file2, 700,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- operation_runner()->Truncate(
- grandchild_file1, 60,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- operation_runner()->Truncate(
- grandchild_file2, 5,
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(base::File::FILE_OK, Truncate(child_file1, 8000));
+ EXPECT_EQ(base::File::FILE_OK, Truncate(child_file2, 700));
+ EXPECT_EQ(base::File::FILE_OK, Truncate(grandchild_file1, 60));
+ EXPECT_EQ(base::File::FILE_OK, Truncate(grandchild_file2, 5));
const int64 child_file_size = 8000 + 700;
const int64 grandchild_file_size = 60 + 5;
@@ -1258,12 +1261,8 @@ TEST_F(FileSystemOperationImplTest,
EXPECT_EQ(all_file_size, GetDataSizeOnDisk());
EXPECT_EQ(expected_usage, usage);
- // Copy src to dest1.
- operation_runner()->Copy(
- src, dest1, FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(base::File::FILE_OK,
+ Copy(src, dest1, FileSystemOperation::OPTION_NONE));
expected_usage += all_file_size + child_path_cost + grandchild_path_cost;
EXPECT_TRUE(DirectoryExists("src/dir"));
@@ -1274,12 +1273,8 @@ TEST_F(FileSystemOperationImplTest,
EXPECT_EQ(2 * all_file_size, GetDataSizeOnDisk());
EXPECT_EQ(expected_usage, GetUsage());
- // Copy src/dir to dest2.
- operation_runner()->Copy(
- child_dir, dest2, FileSystemOperation::OPTION_NONE,
- FileSystemOperationRunner::CopyProgressCallback(),
- base::Bind(&AssertFileErrorEq, FROM_HERE, base::File::FILE_OK));
- base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(base::File::FILE_OK,
+ Copy(child_dir, dest2, FileSystemOperation::OPTION_NONE));
expected_usage += grandchild_file_size + grandchild_path_cost;
usage = GetUsage();
@@ -1288,4 +1283,15 @@ TEST_F(FileSystemOperationImplTest,
EXPECT_EQ(expected_usage, usage);
}
+TEST_F(FileSystemOperationImplTest,
+ TestCopySuccessSrcFileWithDifferentFileSize) {
+ FileSystemURL src_file(CreateFile("src"));
+ FileSystemURL dest_file(CreateFile("dest"));
+
+ EXPECT_EQ(base::File::FILE_OK, Truncate(dest_file, 6));
+ EXPECT_EQ(base::File::FILE_OK,
+ Copy(src_file, dest_file, FileSystemOperation::OPTION_NONE));
+ EXPECT_EQ(0, GetFileSize("dest"));
+}
+
} // namespace content
diff --git a/chromium/content/browser/fileapi/file_system_operation_impl_write_unittest.cc b/chromium/content/browser/fileapi/file_system_operation_impl_write_unittest.cc
index 47b0e2d122b..9d3c181fdce 100644
--- a/chromium/content/browser/fileapi/file_system_operation_impl_write_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_operation_impl_write_unittest.cc
@@ -18,21 +18,21 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory_impl.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_url_request_job.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_file_util.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/browser/fileapi/local_file_util.h"
+#include "storage/common/blob/blob_data.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/blob/blob_url_request_job.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-#include "webkit/browser/fileapi/local_file_util.h"
-#include "webkit/common/blob/blob_data.h"
-#include "webkit/common/fileapi/file_system_util.h"
-
-using fileapi::FileSystemOperation;
-using fileapi::FileSystemOperationRunner;
-using fileapi::FileSystemURL;
+
+using storage::FileSystemOperation;
+using storage::FileSystemOperationRunner;
+using storage::FileSystemURL;
using content::MockBlobURLRequestContext;
using content::ScopedTextBlob;
@@ -41,7 +41,7 @@ namespace content {
namespace {
const GURL kOrigin("http://example.com");
-const fileapi::FileSystemType kFileSystemType = fileapi::kFileSystemTypeTest;
+const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
void AssertStatusEq(base::File::Error expected,
base::File::Error actual) {
@@ -59,11 +59,11 @@ class FileSystemOperationImplWriteTest
bytes_written_(0),
complete_(false),
weak_factory_(this) {
- change_observers_ = fileapi::MockFileChangeObserver::CreateList(
- &change_observer_);
+ change_observers_ =
+ storage::MockFileChangeObserver::CreateList(&change_observer_);
}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(dir_.CreateUniqueTempDir());
quota_manager_ =
@@ -88,7 +88,7 @@ class FileSystemOperationImplWriteTest
->AddFileChangeObserver(change_observer());
}
- virtual void TearDown() {
+ void TearDown() override {
quota_manager_ = NULL;
file_system_context_ = NULL;
base::RunLoop().RunUntilIdle();
@@ -105,11 +105,11 @@ class FileSystemOperationImplWriteTest
bool complete() const { return complete_; }
protected:
- const fileapi::ChangeObserverList& change_observers() const {
+ const storage::ChangeObserverList& change_observers() const {
return change_observers_;
}
- fileapi::MockFileChangeObserver* change_observer() {
+ storage::MockFileChangeObserver* change_observer() {
return &change_observer_;
}
@@ -152,7 +152,7 @@ class FileSystemOperationImplWriteTest
return *url_request_context_;
}
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
scoped_refptr<MockQuotaManager> quota_manager_;
base::MessageLoopForIO loop_;
@@ -168,8 +168,8 @@ class FileSystemOperationImplWriteTest
scoped_ptr<MockBlobURLRequestContext> url_request_context_;
- fileapi::MockFileChangeObserver change_observer_;
- fileapi::ChangeObserverList change_observers_;
+ storage::MockFileChangeObserver change_observer_;
+ storage::ChangeObserverList change_observers_;
base::WeakPtrFactory<FileSystemOperationImplWriteTest> weak_factory_;
@@ -209,7 +209,7 @@ TEST_F(FileSystemOperationImplWriteTest, TestWriteZero) {
TEST_F(FileSystemOperationImplWriteTest, TestWriteInvalidBlobUrl) {
- scoped_ptr<webkit_blob::BlobDataHandle> null_handle;
+ scoped_ptr<storage::BlobDataHandle> null_handle;
file_system_context_->operation_runner()->Write(
&url_request_context(), URLForPath(virtual_path_),
null_handle.Pass(), 0, RecordWriteCallback());
diff --git a/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc b/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc
index af5f8e74ba9..12ba010a318 100644
--- a/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_operation_runner_unittest.cc
@@ -7,14 +7,14 @@
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "content/public/test/test_file_system_context.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-using fileapi::FileSystemContext;
-using fileapi::FileSystemOperationRunner;
-using fileapi::FileSystemType;
-using fileapi::FileSystemURL;
+using storage::FileSystemContext;
+using storage::FileSystemOperationRunner;
+using storage::FileSystemType;
+using storage::FileSystemURL;
namespace content {
@@ -40,23 +40,24 @@ void GetCancelStatus(bool* operation_done,
class FileSystemOperationRunnerTest : public testing::Test {
protected:
FileSystemOperationRunnerTest() {}
- virtual ~FileSystemOperationRunnerTest() {}
+ ~FileSystemOperationRunnerTest() override {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(base_.CreateUniqueTempDir());
base::FilePath base_dir = base_.path();
file_system_context_ =
CreateFileSystemContextForTesting(NULL, base_dir);
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
file_system_context_ = NULL;
base::RunLoop().RunUntilIdle();
}
FileSystemURL URL(const std::string& path) {
return file_system_context_->CreateCrackedFileSystemURL(
- GURL("http://example.com"), fileapi::kFileSystemTypeTemporary,
+ GURL("http://example.com"),
+ storage::kFileSystemTypeTemporary,
base::FilePath::FromUTF8Unsafe(path));
}
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 65eaf57d164..747c6626d6e 100644
--- a/chromium/content/browser/fileapi/file_system_quota_client_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_quota_client_unittest.cc
@@ -4,25 +4,25 @@
#include "base/basictypes.h"
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "content/public/test/async_file_test_helper.h"
#include "content/public/test/test_file_system_context.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_quota_client.h"
+#include "storage/browser/fileapi/file_system_usage_cache.h"
+#include "storage/browser/fileapi/obfuscated_file_util.h"
+#include "storage/common/fileapi/file_system_types.h"
+#include "storage/common/fileapi/file_system_util.h"
+#include "storage/common/quota/quota_types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_quota_client.h"
-#include "webkit/browser/fileapi/file_system_usage_cache.h"
-#include "webkit/browser/fileapi/obfuscated_file_util.h"
-#include "webkit/common/fileapi/file_system_types.h"
-#include "webkit/common/fileapi/file_system_util.h"
-#include "webkit/common/quota/quota_types.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemQuotaClient;
-using fileapi::FileSystemURL;
+using storage::FileSystemQuotaClient;
+using storage::FileSystemURL;
namespace content {
namespace {
@@ -32,8 +32,8 @@ const char kDummyURL2[] = "http://www.example.com";
const char kDummyURL3[] = "http://www.bleh";
// Declared to shorten the variable names.
-const quota::StorageType kTemporary = quota::kStorageTypeTemporary;
-const quota::StorageType kPersistent = quota::kStorageTypePersistent;
+const storage::StorageType kTemporary = storage::kStorageTypeTemporary;
+const storage::StorageType kPersistent = storage::kStorageTypePersistent;
} // namespace
@@ -42,10 +42,9 @@ class FileSystemQuotaClientTest : public testing::Test {
FileSystemQuotaClientTest()
: weak_factory_(this),
additional_callback_count_(0),
- deletion_status_(quota::kQuotaStatusUnknown) {
- }
+ deletion_status_(storage::kQuotaStatusUnknown) {}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
file_system_context_ = CreateFileSystemContextForTesting(
NULL, data_dir_.path());
@@ -56,7 +55,7 @@ class FileSystemQuotaClientTest : public testing::Test {
const char* name;
int64 size;
const char* origin_url;
- quota::StorageType type;
+ storage::StorageType type;
};
protected:
@@ -66,7 +65,7 @@ class FileSystemQuotaClientTest : public testing::Test {
void GetOriginUsageAsync(FileSystemQuotaClient* quota_client,
const std::string& origin_url,
- quota::StorageType type) {
+ storage::StorageType type) {
quota_client->GetOriginUsage(
GURL(origin_url), type,
base::Bind(&FileSystemQuotaClientTest::OnGetUsage,
@@ -75,15 +74,14 @@ class FileSystemQuotaClientTest : public testing::Test {
int64 GetOriginUsage(FileSystemQuotaClient* quota_client,
const std::string& origin_url,
- quota::StorageType type) {
+ storage::StorageType type) {
GetOriginUsageAsync(quota_client, origin_url, type);
base::RunLoop().RunUntilIdle();
return usage_;
}
- const std::set<GURL>& GetOriginsForType(
- FileSystemQuotaClient* quota_client,
- quota::StorageType type) {
+ const std::set<GURL>& GetOriginsForType(FileSystemQuotaClient* quota_client,
+ storage::StorageType type) {
origins_.clear();
quota_client->GetOriginsForType(
type,
@@ -93,10 +91,9 @@ class FileSystemQuotaClientTest : public testing::Test {
return origins_;
}
- const std::set<GURL>& GetOriginsForHost(
- FileSystemQuotaClient* quota_client,
- quota::StorageType type,
- const std::string& host) {
+ const std::set<GURL>& GetOriginsForHost(FileSystemQuotaClient* quota_client,
+ storage::StorageType type,
+ const std::string& host) {
origins_.clear();
quota_client->GetOriginsForHost(
type, host,
@@ -106,10 +103,9 @@ class FileSystemQuotaClientTest : public testing::Test {
return origins_;
}
- void RunAdditionalOriginUsageTask(
- FileSystemQuotaClient* quota_client,
- const std::string& origin_url,
- quota::StorageType type) {
+ void RunAdditionalOriginUsageTask(FileSystemQuotaClient* quota_client,
+ const std::string& origin_url,
+ storage::StorageType type) {
quota_client->GetOriginUsage(
GURL(origin_url), type,
base::Bind(&FileSystemQuotaClientTest::OnGetAdditionalUsage,
@@ -118,36 +114,36 @@ class FileSystemQuotaClientTest : public testing::Test {
bool CreateFileSystemDirectory(const base::FilePath& file_path,
const std::string& origin_url,
- quota::StorageType storage_type) {
- fileapi::FileSystemType type =
- fileapi::QuotaStorageTypeToFileSystemType(storage_type);
+ storage::StorageType storage_type) {
+ storage::FileSystemType type =
+ storage::QuotaStorageTypeToFileSystemType(storage_type);
FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
GURL(origin_url), type, file_path);
base::File::Error result =
- AsyncFileTestHelper::CreateDirectory(file_system_context_, url);
+ AsyncFileTestHelper::CreateDirectory(file_system_context_.get(), url);
return result == base::File::FILE_OK;
}
bool CreateFileSystemFile(const base::FilePath& file_path,
int64 file_size,
const std::string& origin_url,
- quota::StorageType storage_type) {
+ storage::StorageType storage_type) {
if (file_path.empty())
return false;
- fileapi::FileSystemType type =
- fileapi::QuotaStorageTypeToFileSystemType(storage_type);
+ storage::FileSystemType type =
+ storage::QuotaStorageTypeToFileSystemType(storage_type);
FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
GURL(origin_url), type, file_path);
base::File::Error result =
- AsyncFileTestHelper::CreateFile(file_system_context_, url);
+ AsyncFileTestHelper::CreateFile(file_system_context_.get(), url);
if (result != base::File::FILE_OK)
return false;
result = AsyncFileTestHelper::TruncateFile(
- file_system_context_, url, file_size);
+ file_system_context_.get(), url, file_size);
return result == base::File::FILE_OK;
}
@@ -182,15 +178,15 @@ class FileSystemQuotaClientTest : public testing::Test {
int64 ComputeFilePathsCostForOriginAndType(const TestFile* files,
int num_files,
const std::string& origin_url,
- quota::StorageType type) {
+ storage::StorageType type) {
int64 file_paths_cost = 0;
for (int i = 0; i < num_files; i++) {
if (files[i].type == type &&
GURL(files[i].origin_url) == GURL(origin_url)) {
base::FilePath path = base::FilePath().AppendASCII(files[i].name);
if (!path.empty()) {
- file_paths_cost += fileapi::ObfuscatedFileUtil::ComputeFilePathCost(
- path);
+ file_paths_cost +=
+ storage::ObfuscatedFileUtil::ComputeFilePathCost(path);
}
}
}
@@ -199,8 +195,8 @@ class FileSystemQuotaClientTest : public testing::Test {
void DeleteOriginData(FileSystemQuotaClient* quota_client,
const std::string& origin,
- quota::StorageType type) {
- deletion_status_ = quota::kQuotaStatusUnknown;
+ storage::StorageType type) {
+ deletion_status_ = storage::kQuotaStatusUnknown;
quota_client->DeleteOriginData(
GURL(origin), type,
base::Bind(&FileSystemQuotaClientTest::OnDeleteOrigin,
@@ -208,7 +204,7 @@ class FileSystemQuotaClientTest : public testing::Test {
}
int64 usage() const { return usage_; }
- quota::QuotaStatusCode status() { return deletion_status_; }
+ storage::QuotaStatusCode status() { return deletion_status_; }
int additional_callback_count() const { return additional_callback_count_; }
void set_additional_callback_count(int count) {
additional_callback_count_ = count;
@@ -227,18 +223,18 @@ class FileSystemQuotaClientTest : public testing::Test {
++additional_callback_count_;
}
- void OnDeleteOrigin(quota::QuotaStatusCode status) {
+ void OnDeleteOrigin(storage::QuotaStatusCode status) {
deletion_status_ = status;
}
base::ScopedTempDir data_dir_;
base::MessageLoop message_loop_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
base::WeakPtrFactory<FileSystemQuotaClientTest> weak_factory_;
int64 usage_;
int additional_callback_count_;
std::set<GURL> origins_;
- quota::QuotaStatusCode deletion_status_;
+ storage::QuotaStatusCode deletion_status_;
DISALLOW_COPY_AND_ASSIGN(FileSystemQuotaClientTest);
};
@@ -254,7 +250,7 @@ TEST_F(FileSystemQuotaClientTest, NoFileTest) {
const TestFile kFiles[] = {
{true, NULL, 0, kDummyURL1, kTemporary},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
for (int i = 0; i < 2; i++) {
EXPECT_EQ(0, GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary));
@@ -267,9 +263,9 @@ TEST_F(FileSystemQuotaClientTest, OneFileTest) {
{true, NULL, 0, kDummyURL1, kTemporary},
{false, "foo", 4921, kDummyURL1, kTemporary},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
const int64 file_paths_cost = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL1, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL1, kTemporary);
for (int i = 0; i < 2; i++) {
EXPECT_EQ(4921 + file_paths_cost,
@@ -284,9 +280,9 @@ TEST_F(FileSystemQuotaClientTest, TwoFilesTest) {
{false, "foo", 10310, kDummyURL1, kTemporary},
{false, "bar", 41, kDummyURL1, kTemporary},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
const int64 file_paths_cost = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL1, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL1, kTemporary);
for (int i = 0; i < 2; i++) {
EXPECT_EQ(10310 + 41 + file_paths_cost,
@@ -302,9 +298,9 @@ TEST_F(FileSystemQuotaClientTest, EmptyFilesTest) {
{false, "bar", 0, kDummyURL1, kTemporary},
{false, "baz", 0, kDummyURL1, kTemporary},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
const int64 file_paths_cost = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL1, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL1, kTemporary);
for (int i = 0; i < 2; i++) {
EXPECT_EQ(file_paths_cost,
@@ -320,9 +316,9 @@ TEST_F(FileSystemQuotaClientTest, SubDirectoryTest) {
{false, "dirtest/foo", 11921, kDummyURL1, kTemporary},
{false, "bar", 4814, kDummyURL1, kTemporary},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
const int64 file_paths_cost = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL1, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL1, kTemporary);
for (int i = 0; i < 2; i++) {
EXPECT_EQ(11921 + 4814 + file_paths_cost,
@@ -342,11 +338,11 @@ TEST_F(FileSystemQuotaClientTest, MultiTypeTest) {
{false, "dirtest/foo", 193, kDummyURL1, kPersistent},
{false, "bar", 9, kDummyURL1, kPersistent},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
const int64 file_paths_cost_temporary = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL1, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL1, kTemporary);
const int64 file_paths_cost_persistent = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL1, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL1, kTemporary);
for (int i = 0; i < 2; i++) {
EXPECT_EQ(133 + 14 + file_paths_cost_temporary,
@@ -376,16 +372,16 @@ TEST_F(FileSystemQuotaClientTest, MultiDomainTest) {
{false, "dom/fan", 2013, kDummyURL2, kPersistent},
{false, "baz", 18, kDummyURL2, kPersistent},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
const int64 file_paths_cost_temporary1 = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL1, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL1, kTemporary);
const int64 file_paths_cost_persistent1 =
- ComputeFilePathsCostForOriginAndType(kFiles, ARRAYSIZE_UNSAFE(kFiles),
+ ComputeFilePathsCostForOriginAndType(kFiles, arraysize(kFiles),
kDummyURL1, kPersistent);
const int64 file_paths_cost_temporary2 = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL2, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL2, kTemporary);
const int64 file_paths_cost_persistent2 =
- ComputeFilePathsCostForOriginAndType(kFiles, ARRAYSIZE_UNSAFE(kFiles),
+ ComputeFilePathsCostForOriginAndType(kFiles, arraysize(kFiles),
kDummyURL2, kPersistent);
for (int i = 0; i < 2; i++) {
@@ -407,9 +403,9 @@ TEST_F(FileSystemQuotaClientTest, GetUsage_MultipleTasks) {
{false, "foo", 11, kDummyURL1, kTemporary},
{false, "bar", 22, kDummyURL1, kTemporary},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
const int64 file_paths_cost = ComputeFilePathsCostForOriginAndType(
- kFiles, ARRAYSIZE_UNSAFE(kFiles), kDummyURL1, kTemporary);
+ kFiles, arraysize(kFiles), kDummyURL1, kTemporary);
// Dispatching three GetUsage tasks.
set_additional_callback_count(0);
@@ -437,7 +433,7 @@ TEST_F(FileSystemQuotaClientTest, GetOriginsForType) {
{true, NULL, 0, kDummyURL2, kTemporary},
{true, NULL, 0, kDummyURL3, kPersistent},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
std::set<GURL> origins = GetOriginsForType(quota_client.get(), kTemporary);
EXPECT_EQ(2U, origins.size());
@@ -460,7 +456,7 @@ TEST_F(FileSystemQuotaClientTest, GetOriginsForHost) {
{true, NULL, 0, kURL4, kTemporary},
{true, NULL, 0, kURL5, kPersistent},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
std::set<GURL> origins = GetOriginsForHost(
quota_client.get(), kTemporary, "foo.com");
@@ -478,7 +474,7 @@ TEST_F(FileSystemQuotaClientTest, IncognitoTest) {
{true, NULL, 0, kDummyURL1, kTemporary},
{false, "foo", 10, kDummyURL1, kTemporary},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
// Having files in the usual directory wouldn't affect the result
// queried in incognito mode.
@@ -509,34 +505,34 @@ TEST_F(FileSystemQuotaClientTest, DeleteOriginTest) {
{true, NULL, 0, "https://bar.com/", kTemporary},
{false, "g", 64, "https://bar.com/", kTemporary},
};
- InitializeOriginFiles(quota_client.get(), kFiles, ARRAYSIZE_UNSAFE(kFiles));
+ InitializeOriginFiles(quota_client.get(), kFiles, arraysize(kFiles));
const int64 file_paths_cost_temporary_foo_https =
- ComputeFilePathsCostForOriginAndType(kFiles, ARRAYSIZE_UNSAFE(kFiles),
+ ComputeFilePathsCostForOriginAndType(kFiles, arraysize(kFiles),
"https://foo.com/", kTemporary);
const int64 file_paths_cost_persistent_foo =
- ComputeFilePathsCostForOriginAndType(kFiles, ARRAYSIZE_UNSAFE(kFiles),
+ ComputeFilePathsCostForOriginAndType(kFiles, arraysize(kFiles),
"http://foo.com/", kPersistent);
const int64 file_paths_cost_temporary_bar =
- ComputeFilePathsCostForOriginAndType(kFiles, ARRAYSIZE_UNSAFE(kFiles),
+ ComputeFilePathsCostForOriginAndType(kFiles, arraysize(kFiles),
"http://bar.com/", kTemporary);
const int64 file_paths_cost_temporary_bar_https =
- ComputeFilePathsCostForOriginAndType(kFiles, ARRAYSIZE_UNSAFE(kFiles),
+ ComputeFilePathsCostForOriginAndType(kFiles, arraysize(kFiles),
"https://bar.com/", kTemporary);
const int64 file_paths_cost_persistent_bar_https =
- ComputeFilePathsCostForOriginAndType(kFiles, ARRAYSIZE_UNSAFE(kFiles),
+ ComputeFilePathsCostForOriginAndType(kFiles, arraysize(kFiles),
"https://bar.com/", kPersistent);
DeleteOriginData(quota_client.get(), "http://foo.com/", kTemporary);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(quota::kQuotaStatusOk, status());
+ EXPECT_EQ(storage::kQuotaStatusOk, status());
DeleteOriginData(quota_client.get(), "http://bar.com/", kPersistent);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(quota::kQuotaStatusOk, status());
+ EXPECT_EQ(storage::kQuotaStatusOk, status());
DeleteOriginData(quota_client.get(), "http://buz.com/", kTemporary);
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(quota::kQuotaStatusOk, status());
+ EXPECT_EQ(storage::kQuotaStatusOk, status());
EXPECT_EQ(0, GetOriginUsage(
quota_client.get(), "http://foo.com/", kTemporary));
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 4f3d0abde39..4dcba3baac6 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
@@ -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 "webkit/browser/fileapi/file_system_url_request_job.h"
+#include "storage/browser/fileapi/file_system_url_request_job.h"
#include <string>
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/format_macros.h"
#include "base/memory/scoped_vector.h"
@@ -33,15 +33,15 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_test_util.h"
+#include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_file_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemContext;
-using fileapi::FileSystemURL;
-using fileapi::FileSystemURLRequestJob;
+using storage::FileSystemContext;
+using storage::FileSystemURL;
+using storage::FileSystemURLRequestJob;
namespace content {
namespace {
@@ -60,7 +60,7 @@ const char kValidExternalMountPoint[] = "mnt_name";
// "automount", but will only succeed for the mount point "mnt_name".
bool TestAutoMountForURLRequest(
const net::URLRequest* /*url_request*/,
- const fileapi::FileSystemURL& filesystem_url,
+ const storage::FileSystemURL& filesystem_url,
const std::string& storage_domain,
const base::Callback<void(base::File::Error result)>& callback) {
if (storage_domain != "automount")
@@ -70,9 +70,11 @@ bool TestAutoMountForURLRequest(
std::string mount_point = base::FilePath(components[0]).AsUTF8Unsafe();
if (mount_point == kValidExternalMountPoint) {
- fileapi::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
- kValidExternalMountPoint, fileapi::kFileSystemTypeTest,
- fileapi::FileSystemMountOption(), base::FilePath());
+ storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
+ kValidExternalMountPoint,
+ storage::kFileSystemTypeTest,
+ storage::FileSystemMountOption(),
+ base::FilePath());
callback.Run(base::File::FILE_OK);
} else {
callback.Run(base::File::FILE_ERROR_NOT_FOUND);
@@ -87,23 +89,34 @@ class FileSystemURLRequestJobFactory : public net::URLRequestJobFactory {
: storage_domain_(storage_domain), file_system_context_(context) {
}
- virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+ net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
- return new fileapi::FileSystemURLRequestJob(
+ net::NetworkDelegate* network_delegate) const override {
+ return new storage::FileSystemURLRequestJob(
request, network_delegate, storage_domain_, file_system_context_);
}
- virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
- return true;
+ net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const override {
+ return nullptr;
+ }
+
+ net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return nullptr;
}
- virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
+ bool IsHandledProtocol(const std::string& scheme) const override {
return true;
}
- virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
+ bool IsHandledURL(const GURL& url) const override { return true; }
+
+ bool IsSafeRedirectTarget(const GURL& location) const override {
return false;
}
@@ -119,7 +132,7 @@ class FileSystemURLRequestJobTest : public testing::Test {
FileSystemURLRequestJobTest() : weak_factory_(this) {
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
// We use the main thread so that we can get the root path synchronously.
@@ -128,14 +141,15 @@ class FileSystemURLRequestJobTest : public testing::Test {
CreateFileSystemContextForTesting(NULL, temp_dir_.path());
file_system_context_->OpenFileSystem(
- GURL("http://remote/"), fileapi::kFileSystemTypeTemporary,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ GURL("http://remote/"),
+ storage::kFileSystemTypeTemporary,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&FileSystemURLRequestJobTest::OnOpenFileSystem,
weak_factory_.GetWeakPtr()));
base::RunLoop().RunUntilIdle();
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// FileReader posts a task to close the file in destructor.
base::RunLoop().RunUntilIdle();
}
@@ -144,11 +158,11 @@ class FileSystemURLRequestJobTest : public testing::Test {
base::FilePath mnt_point = temp_dir_.path().AppendASCII("auto_mount_dir");
ASSERT_TRUE(base::CreateDirectory(mnt_point));
- ScopedVector<fileapi::FileSystemBackend> additional_providers;
+ ScopedVector<storage::FileSystemBackend> additional_providers;
additional_providers.push_back(new TestFileSystemBackend(
base::MessageLoopProxy::current().get(), mnt_point));
- std::vector<fileapi::URLRequestAutoMountHandler> handlers;
+ std::vector<storage::URLRequestAutoMountHandler> handlers;
handlers.push_back(base::Bind(&TestAutoMountForURLRequest));
file_system_context_ = CreateFileSystemContextWithAutoMountersForTesting(
@@ -210,21 +224,22 @@ class FileSystemURLRequestJobTest : public testing::Test {
void CreateDirectory(const base::StringPiece& dir_name) {
FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
GURL("http://remote"),
- fileapi::kFileSystemTypeTemporary,
+ storage::kFileSystemTypeTemporary,
base::FilePath().AppendASCII(dir_name));
- ASSERT_EQ(base::File::FILE_OK, AsyncFileTestHelper::CreateDirectory(
- file_system_context_, url));
+ ASSERT_EQ(
+ base::File::FILE_OK,
+ AsyncFileTestHelper::CreateDirectory(file_system_context_.get(), url));
}
void WriteFile(const base::StringPiece& file_name,
const char* buf, int buf_size) {
FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
GURL("http://remote"),
- fileapi::kFileSystemTypeTemporary,
+ storage::kFileSystemTypeTemporary,
base::FilePath().AppendASCII(file_name));
ASSERT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::CreateFileWithData(
- file_system_context_, url, buf, buf_size));
+ file_system_context_.get(), url, buf, buf_size));
}
GURL CreateFileSystemURL(const std::string& path) {
@@ -235,7 +250,7 @@ class FileSystemURLRequestJobTest : public testing::Test {
base::MessageLoopForIO message_loop_;
base::ScopedTempDir temp_dir_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
base::WeakPtrFactory<FileSystemURLRequestJobTest> weak_factory_;
net::URLRequestContext empty_context_;
@@ -430,7 +445,7 @@ TEST_F(FileSystemURLRequestJobTest, AutoMountFileTest) {
EXPECT_EQ("no-cache", cache_control);
ASSERT_TRUE(
- fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+ storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
kValidExternalMountPoint));
}
@@ -443,7 +458,7 @@ TEST_F(FileSystemURLRequestJobTest, AutoMountInvalidRoot) {
EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
ASSERT_FALSE(
- fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+ storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
"invalid"));
}
@@ -456,7 +471,7 @@ TEST_F(FileSystemURLRequestJobTest, AutoMountNoHandler) {
EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
ASSERT_FALSE(
- fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
+ storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
kValidExternalMountPoint));
}
diff --git a/chromium/content/browser/fileapi/file_system_url_unittest.cc b/chromium/content/browser/fileapi/file_system_url_unittest.cc
index 4aa23dd8ab4..e4dd5e2b3f5 100644
--- a/chromium/content/browser/fileapi/file_system_url_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_url_unittest.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 "webkit/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/file_system_url.h"
#include "base/files/file_path.h"
+#include "storage/common/fileapi/file_system_types.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/common/fileapi/file_system_types.h"
-#include "webkit/common/fileapi/file_system_util.h"
#define FPL FILE_PATH_LITERAL
@@ -18,12 +18,12 @@
#define DRIVE FPL("/a/")
#endif
-using fileapi::FileSystemURL;
-using fileapi::kFileSystemTypeExternal;
-using fileapi::kFileSystemTypeIsolated;
-using fileapi::kFileSystemTypePersistent;
-using fileapi::kFileSystemTypeTemporary;
-using fileapi::VirtualPath;
+using storage::FileSystemURL;
+using storage::kFileSystemTypeExternal;
+using storage::kFileSystemTypeIsolated;
+using storage::kFileSystemTypePersistent;
+using storage::kFileSystemTypeTemporary;
+using storage::VirtualPath;
namespace content {
diff --git a/chromium/content/browser/fileapi/file_system_usage_cache_unittest.cc b/chromium/content/browser/fileapi/file_system_usage_cache_unittest.cc
index 0a54b891075..13f1d659d30 100644
--- a/chromium/content/browser/fileapi/file_system_usage_cache_unittest.cc
+++ b/chromium/content/browser/fileapi/file_system_usage_cache_unittest.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/file_system_usage_cache.h"
+#include "storage/browser/fileapi/file_system_usage_cache.h"
#include "base/basictypes.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
-using fileapi::FileSystemUsageCache;
+using storage::FileSystemUsageCache;
namespace content {
@@ -19,9 +19,7 @@ class FileSystemUsageCacheTest : public testing::Test {
FileSystemUsageCacheTest()
: usage_cache_(base::MessageLoopProxy::current().get()) {}
- virtual void SetUp() {
- ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
- }
+ void SetUp() override { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); }
protected:
base::FilePath GetUsageFilePath() {
diff --git a/chromium/content/browser/fileapi/file_writer_delegate_unittest.cc b/chromium/content/browser/fileapi/file_writer_delegate_unittest.cc
index ccbc4a563df..d907843695a 100644
--- a/chromium/content/browser/fileapi/file_writer_delegate_unittest.cc
+++ b/chromium/content/browser/fileapi/file_writer_delegate_unittest.cc
@@ -20,26 +20,26 @@
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory.h"
#include "net/url_request/url_request_status.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_quota_util.h"
+#include "storage/browser/fileapi/file_writer_delegate.h"
+#include "storage/browser/fileapi/sandbox_file_stream_writer.h"
#include "testing/platform_test.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_quota_util.h"
-#include "webkit/browser/fileapi/file_writer_delegate.h"
-#include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemURL;
-using fileapi::FileWriterDelegate;
+using storage::FileSystemURL;
+using storage::FileWriterDelegate;
namespace content {
namespace {
const GURL kOrigin("http://example.com");
-const fileapi::FileSystemType kFileSystemType = fileapi::kFileSystemTypeTest;
+const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
const char kData[] = "The quick brown fox jumps over the lazy dog.\n";
-const int kDataSize = ARRAYSIZE_UNSAFE(kData) - 1;
+const int kDataSize = arraysize(kData) - 1;
class Result {
public:
@@ -84,8 +84,8 @@ class FileWriterDelegateTest : public PlatformTest {
FileWriterDelegateTest() {}
protected:
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
+ void SetUp() override;
+ void TearDown() override;
int64 usage() {
return file_system_context_->GetQuotaUtil(kFileSystemType)
@@ -103,7 +103,7 @@ class FileWriterDelegateTest : public PlatformTest {
base::File::Info file_info;
EXPECT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::GetMetadata(
- file_system_context_, url, &file_info));
+ file_system_context_.get(), url, &file_info));
return file_info.size;
}
@@ -116,16 +116,15 @@ class FileWriterDelegateTest : public PlatformTest {
const char* test_file_path,
int64 offset,
int64 allowed_growth) {
- fileapi::SandboxFileStreamWriter* writer =
- new fileapi::SandboxFileStreamWriter(
+ storage::SandboxFileStreamWriter* writer =
+ new storage::SandboxFileStreamWriter(
file_system_context_.get(),
GetFileSystemURL(test_file_path),
offset,
*file_system_context_->GetUpdateObservers(kFileSystemType));
writer->set_default_quota(allowed_growth);
- return new FileWriterDelegate(
- scoped_ptr<fileapi::FileStreamWriter>(writer),
- FileWriterDelegate::FLUSH_ON_COMPLETION);
+ return new FileWriterDelegate(scoped_ptr<storage::FileStreamWriter>(writer),
+ FileWriterDelegate::FLUSH_ON_COMPLETION);
}
FileWriterDelegate::DelegateWriteCallback GetWriteCallback(Result* result) {
@@ -147,7 +146,7 @@ class FileWriterDelegateTest : public PlatformTest {
// This should be alive until the very end of this instance.
base::MessageLoopForIO loop_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
net::URLRequestContext empty_context_;
scoped_ptr<FileWriterDelegate> file_writer_delegate_;
@@ -176,15 +175,13 @@ class FileWriterDelegateTestJob : public net::URLRequestJob {
cursor_(0) {
}
- virtual void Start() OVERRIDE {
+ void Start() override {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
}
- virtual bool ReadRawData(net::IOBuffer* buf,
- int buf_size,
- int *bytes_read) OVERRIDE {
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override {
if (remaining_bytes_ < buf_size)
buf_size = static_cast<int>(remaining_bytes_);
@@ -197,12 +194,10 @@ class FileWriterDelegateTestJob : public net::URLRequestJob {
return true;
}
- virtual int GetResponseCode() const OVERRIDE {
- return 200;
- }
+ int GetResponseCode() const override { return 200; }
protected:
- virtual ~FileWriterDelegateTestJob() {}
+ ~FileWriterDelegateTestJob() override {}
private:
std::string content_;
@@ -216,23 +211,36 @@ class BlobURLRequestJobFactory : public net::URLRequestJobFactory {
: content_data_(content_data) {
}
- virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+ net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
return new FileWriterDelegateTestJob(
request, network_delegate, *content_data_);
}
- virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
+ net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const override {
+ return nullptr;
+ }
+
+ net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return nullptr;
+ }
+
+ bool IsHandledProtocol(const std::string& scheme) const override {
return scheme == "blob";
}
- virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
+ bool IsHandledURL(const GURL& url) const override {
return url.SchemeIs("blob");
}
- virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
+ bool IsSafeRedirectTarget(const GURL& location) const override {
return true;
}
@@ -250,8 +258,8 @@ void FileWriterDelegateTest::SetUp() {
file_system_context_ = CreateFileSystemContextForTesting(
NULL, dir_.path());
ASSERT_EQ(base::File::FILE_OK,
- AsyncFileTestHelper::CreateFile(
- file_system_context_, GetFileSystemURL("test")));
+ AsyncFileTestHelper::CreateFile(file_system_context_.get(),
+ GetFileSystemURL("test")));
job_factory_.reset(new BlobURLRequestJobFactory(&content_));
empty_context_.set_job_factory(job_factory_.get());
}
@@ -348,8 +356,8 @@ TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) {
scoped_ptr<net::URLRequest> request2;
ASSERT_EQ(base::File::FILE_OK,
- AsyncFileTestHelper::CreateFile(
- file_system_context_, GetFileSystemURL("test2")));
+ AsyncFileTestHelper::CreateFile(file_system_context_.get(),
+ GetFileSystemURL("test2")));
const GURL kBlobURL("blob:nolimitconcurrent");
const GURL kBlobURL2("blob:nolimitconcurrent2");
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter.cc b/chromium/content/browser/fileapi/fileapi_message_filter.cc
index 2eb601a7c6d..3fe4199272a 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter.cc
+++ b/chromium/content/browser/fileapi/fileapi_message_filter.cc
@@ -27,25 +27,25 @@
#include "net/base/mime_util.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/fileapi/file_observers.h"
+#include "storage/browser/fileapi/file_permission_policy.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/common/blob/blob_data.h"
+#include "storage/common/blob/shareable_file_reference.h"
+#include "storage/common/fileapi/directory_entry.h"
+#include "storage/common/fileapi/file_system_info.h"
+#include "storage/common/fileapi/file_system_types.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "url/gurl.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/fileapi/file_observers.h"
-#include "webkit/browser/fileapi/file_permission_policy.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/common/blob/blob_data.h"
-#include "webkit/common/blob/shareable_file_reference.h"
-#include "webkit/common/fileapi/directory_entry.h"
-#include "webkit/common/fileapi/file_system_info.h"
-#include "webkit/common/fileapi/file_system_types.h"
-#include "webkit/common/fileapi/file_system_util.h"
-
-using fileapi::FileSystemFileUtil;
-using fileapi::FileSystemBackend;
-using fileapi::FileSystemOperation;
-using fileapi::FileSystemURL;
-using webkit_blob::BlobData;
-using webkit_blob::BlobStorageContext;
+
+using storage::FileSystemFileUtil;
+using storage::FileSystemBackend;
+using storage::FileSystemOperation;
+using storage::FileSystemURL;
+using storage::BlobData;
+using storage::BlobStorageContext;
namespace content {
@@ -66,11 +66,11 @@ void RevokeFilePermission(int child_id, const base::FilePath& path) {
FileAPIMessageFilter::FileAPIMessageFilter(
int process_id,
net::URLRequestContextGetter* request_context_getter,
- fileapi::FileSystemContext* file_system_context,
+ storage::FileSystemContext* file_system_context,
ChromeBlobStorageContext* blob_storage_context,
StreamContext* stream_context)
- : BrowserMessageFilter(
- kFilteredMessageClasses, arraysize(kFilteredMessageClasses)),
+ : BrowserMessageFilter(kFilteredMessageClasses,
+ arraysize(kFilteredMessageClasses)),
process_id_(process_id),
context_(file_system_context),
security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
@@ -87,11 +87,11 @@ FileAPIMessageFilter::FileAPIMessageFilter(
FileAPIMessageFilter::FileAPIMessageFilter(
int process_id,
net::URLRequestContext* request_context,
- fileapi::FileSystemContext* file_system_context,
+ storage::FileSystemContext* file_system_context,
ChromeBlobStorageContext* blob_storage_context,
StreamContext* stream_context)
- : BrowserMessageFilter(
- kFilteredMessageClasses, arraysize(kFilteredMessageClasses)),
+ : BrowserMessageFilter(kFilteredMessageClasses,
+ arraysize(kFilteredMessageClasses)),
process_id_(process_id),
context_(file_system_context),
security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
@@ -203,15 +203,15 @@ void FileAPIMessageFilter::BadMessageReceived() {
void FileAPIMessageFilter::OnOpenFileSystem(int request_id,
const GURL& origin_url,
- fileapi::FileSystemType type) {
+ storage::FileSystemType type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (type == fileapi::kFileSystemTypeTemporary) {
+ if (type == storage::kFileSystemTypeTemporary) {
RecordAction(base::UserMetricsAction("OpenFileSystemTemporary"));
- } else if (type == fileapi::kFileSystemTypePersistent) {
+ } else if (type == storage::kFileSystemTypePersistent) {
RecordAction(base::UserMetricsAction("OpenFileSystemPersistent"));
}
- fileapi::OpenFileSystemMode mode =
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT;
+ storage::OpenFileSystemMode mode =
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT;
context_->OpenFileSystem(origin_url, type, mode, base::Bind(
&FileAPIMessageFilter::DidOpenFileSystem, this, request_id));
}
@@ -233,10 +233,9 @@ void FileAPIMessageFilter::OnResolveURL(
&FileAPIMessageFilter::DidResolveURL, this, request_id));
}
-void FileAPIMessageFilter::OnDeleteFileSystem(
- int request_id,
- const GURL& origin_url,
- fileapi::FileSystemType type) {
+void FileAPIMessageFilter::OnDeleteFileSystem(int request_id,
+ const GURL& origin_url,
+ storage::FileSystemType type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
context_->DeleteFileSystem(origin_url, type, base::Bind(
&FileAPIMessageFilter::DidDeleteFileSystem, this, request_id));
@@ -260,8 +259,9 @@ void FileAPIMessageFilter::OnMove(
}
operations_[request_id] = operation_runner()->Move(
- src_url, dest_url,
- fileapi::FileSystemOperation::OPTION_NONE,
+ src_url,
+ dest_url,
+ storage::FileSystemOperation::OPTION_NONE,
base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
}
@@ -282,9 +282,10 @@ void FileAPIMessageFilter::OnCopy(
}
operations_[request_id] = operation_runner()->Copy(
- src_url, dest_url,
- fileapi::FileSystemOperation::OPTION_NONE,
- fileapi::FileSystemOperationRunner::CopyProgressCallback(),
+ src_url,
+ dest_url,
+ storage::FileSystemOperation::OPTION_NONE,
+ storage::FileSystemOperationRunner::CopyProgressCallback(),
base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id));
}
@@ -406,7 +407,7 @@ void FileAPIMessageFilter::OnWrite(
return;
}
- scoped_ptr<webkit_blob::BlobDataHandle> blob =
+ scoped_ptr<storage::BlobDataHandle> blob =
blob_storage_context_->context()->GetBlobDataFromUUID(blob_uuid);
operations_[request_id] = operation_runner()->Write(
@@ -671,7 +672,7 @@ void FileAPIMessageFilter::OnCloneStream(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// Abort if there's no Stream instance for |src_url| (source Stream which
// we're going to make |url| point to) in the registry.
- if (!GetStreamForURL(src_url))
+ if (!GetStreamForURL(src_url).get())
return;
stream_context_->registry()->CloneStream(url, src_url);
@@ -726,7 +727,7 @@ void FileAPIMessageFilter::DidGetMetadataForStreaming(
void FileAPIMessageFilter::DidReadDirectory(
int request_id,
base::File::Error result,
- const std::vector<fileapi::DirectoryEntry>& entries,
+ const std::vector<storage::DirectoryEntry>& entries,
bool has_more) {
if (result == base::File::FILE_OK) {
if (!entries.empty() || !has_more)
@@ -771,19 +772,21 @@ void FileAPIMessageFilter::DidOpenFileSystem(int request_id,
void FileAPIMessageFilter::DidResolveURL(
int request_id,
base::File::Error result,
- const fileapi::FileSystemInfo& info,
+ const storage::FileSystemInfo& info,
const base::FilePath& file_path,
- fileapi::FileSystemContext::ResolvedEntryType type) {
+ storage::FileSystemContext::ResolvedEntryType type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (result == base::File::FILE_OK &&
- type == fileapi::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND)
+ type == storage::FileSystemContext::RESOLVED_ENTRY_NOT_FOUND)
result = base::File::FILE_ERROR_NOT_FOUND;
if (result == base::File::FILE_OK) {
DCHECK(info.root_url.is_valid());
Send(new FileSystemMsg_DidResolveURL(
- request_id, info, file_path,
- type == fileapi::FileSystemContext::RESOLVED_ENTRY_DIRECTORY));
+ request_id,
+ info,
+ file_path,
+ type == storage::FileSystemContext::RESOLVED_ENTRY_DIRECTORY));
} else {
Send(new FileSystemMsg_DidFail(request_id, result));
}
@@ -803,11 +806,11 @@ void FileAPIMessageFilter::DidDeleteFileSystem(
void FileAPIMessageFilter::DidCreateSnapshot(
int request_id,
- const fileapi::FileSystemURL& url,
+ const storage::FileSystemURL& url,
base::File::Error result,
const base::File::Info& info,
const base::FilePath& platform_path,
- const scoped_refptr<webkit_blob::ShareableFileReference>& /* unused */) {
+ const scoped_refptr<storage::ShareableFileReference>& /* unused */) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
operations_.erase(request_id);
@@ -816,8 +819,8 @@ void FileAPIMessageFilter::DidCreateSnapshot(
return;
}
- scoped_refptr<webkit_blob::ShareableFileReference> file_ref =
- webkit_blob::ShareableFileReference::Get(platform_path);
+ scoped_refptr<storage::ShareableFileReference> file_ref =
+ storage::ShareableFileReference::Get(platform_path);
if (!security_policy_->CanReadFile(process_id_, platform_path)) {
// Give per-file read permission to the snapshot file if it hasn't it yet.
// In order for the renderer to be able to read the file via File object,
@@ -831,9 +834,9 @@ void FileAPIMessageFilter::DidCreateSnapshot(
// is dropped.
if (!file_ref.get()) {
// Create a reference for temporary permission handling.
- file_ref = webkit_blob::ShareableFileReference::GetOrCreate(
+ file_ref = storage::ShareableFileReference::GetOrCreate(
platform_path,
- webkit_blob::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
+ storage::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE,
context_->default_file_task_runner());
}
file_ref->AddFinalReleaseCallback(
@@ -851,7 +854,8 @@ void FileAPIMessageFilter::DidCreateSnapshot(
}
bool FileAPIMessageFilter::ValidateFileSystemURL(
- int request_id, const fileapi::FileSystemURL& url) {
+ int request_id,
+ const storage::FileSystemURL& url) {
if (!FileSystemURLIsValid(context_, url)) {
Send(new FileSystemMsg_DidFail(request_id,
base::File::FILE_ERROR_INVALID_URL));
@@ -861,7 +865,7 @@ bool FileAPIMessageFilter::ValidateFileSystemURL(
// Deny access to files in PluginPrivate FileSystem from JavaScript.
// TODO(nhiroki): Move this filter somewhere else since this is not for
// validation.
- if (url.type() == fileapi::kFileSystemTypePluginPrivate) {
+ if (url.type() == storage::kFileSystemTypePluginPrivate) {
Send(new FileSystemMsg_DidFail(request_id,
base::File::FILE_ERROR_SECURITY));
return false;
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter.h b/chromium/content/browser/fileapi/fileapi_message_filter.h
index 7a98b1483c9..297213d722d 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter.h
+++ b/chromium/content/browser/fileapi/fileapi_message_filter.h
@@ -18,11 +18,11 @@
#include "content/browser/streams/stream_context.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-#include "webkit/common/blob/blob_data.h"
-#include "webkit/common/fileapi/file_system_types.h"
-#include "webkit/common/quota/quota_types.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/common/blob/blob_data.h"
+#include "storage/common/fileapi/file_system_types.h"
+#include "storage/common/quota/quota_types.h"
class GURL;
@@ -31,7 +31,7 @@ class FilePath;
class Time;
}
-namespace fileapi {
+namespace storage {
class FileSystemURL;
class FileSystemOperationRunner;
struct DirectoryEntry;
@@ -47,7 +47,7 @@ namespace content {
class BlobStorageHost;
}
-namespace webkit_blob {
+namespace storage {
class ShareableFileReference;
}
@@ -60,43 +60,41 @@ class ChromeBlobStorageContext;
class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
public:
// Used by the renderer process host on the UI thread.
- FileAPIMessageFilter(
- int process_id,
- net::URLRequestContextGetter* request_context_getter,
- fileapi::FileSystemContext* file_system_context,
- ChromeBlobStorageContext* blob_storage_context,
- StreamContext* stream_context);
+ FileAPIMessageFilter(int process_id,
+ net::URLRequestContextGetter* request_context_getter,
+ storage::FileSystemContext* file_system_context,
+ ChromeBlobStorageContext* blob_storage_context,
+ StreamContext* stream_context);
// Used by the worker process host on the IO thread.
- FileAPIMessageFilter(
- int process_id,
- net::URLRequestContext* request_context,
- fileapi::FileSystemContext* file_system_context,
- ChromeBlobStorageContext* blob_storage_context,
- StreamContext* stream_context);
+ FileAPIMessageFilter(int process_id,
+ net::URLRequestContext* request_context,
+ storage::FileSystemContext* file_system_context,
+ ChromeBlobStorageContext* blob_storage_context,
+ StreamContext* stream_context);
// BrowserMessageFilter implementation.
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
- virtual void OnChannelClosing() OVERRIDE;
- virtual base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& message) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelConnected(int32 peer_pid) override;
+ void OnChannelClosing() override;
+ base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
protected:
- virtual ~FileAPIMessageFilter();
+ ~FileAPIMessageFilter() override;
- virtual void BadMessageReceived() OVERRIDE;
+ void BadMessageReceived() override;
private:
- typedef fileapi::FileSystemOperationRunner::OperationID OperationID;
+ typedef storage::FileSystemOperationRunner::OperationID OperationID;
void OnOpenFileSystem(int request_id,
const GURL& origin_url,
- fileapi::FileSystemType type);
+ storage::FileSystemType type);
void OnResolveURL(int request_id,
const GURL& filesystem_url);
void OnDeleteFileSystem(int request_id,
const GURL& origin_url,
- fileapi::FileSystemType type);
+ storage::FileSystemType type);
void OnMove(int request_id,
const GURL& src_path,
const GURL& dest_path);
@@ -132,7 +130,7 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
void OnStartBuildingBlob(const std::string& uuid);
void OnAppendBlobDataItemToBlob(const std::string& uuid,
- const webkit_blob::BlobData::Item& item);
+ const storage::BlobData::Item& item);
void OnAppendSharedMemoryToBlob(const std::string& uuid,
base::SharedMemoryHandle handle,
size_t buffer_size);
@@ -152,8 +150,8 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
//
// TODO(tyoshino): Set |content_type| to the stream.
void OnStartBuildingStream(const GURL& url, const std::string& content_type);
- void OnAppendBlobDataItemToStream(
- const GURL& url, const webkit_blob::BlobData::Item& item);
+ void OnAppendBlobDataItemToStream(const GURL& url,
+ const storage::BlobData::Item& item);
void OnAppendSharedMemoryToStream(
const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size);
void OnFinishBuildingStream(const GURL& url);
@@ -171,7 +169,7 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
const base::File::Info& info);
void DidReadDirectory(int request_id,
base::File::Error result,
- const std::vector<fileapi::DirectoryEntry>& entries,
+ const std::vector<storage::DirectoryEntry>& entries,
bool has_more);
void DidWrite(int request_id,
base::File::Error result,
@@ -183,34 +181,34 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
base::File::Error result);
void DidResolveURL(int request_id,
base::File::Error result,
- const fileapi::FileSystemInfo& info,
+ const storage::FileSystemInfo& info,
const base::FilePath& file_path,
- fileapi::FileSystemContext::ResolvedEntryType type);
+ storage::FileSystemContext::ResolvedEntryType type);
void DidDeleteFileSystem(int request_id,
base::File::Error result);
void DidCreateSnapshot(
int request_id,
- const fileapi::FileSystemURL& url,
+ const storage::FileSystemURL& url,
base::File::Error result,
const base::File::Info& info,
const base::FilePath& platform_path,
- const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref);
+ const scoped_refptr<storage::ShareableFileReference>& file_ref);
// Sends a FileSystemMsg_DidFail and returns false if |url| is invalid.
- bool ValidateFileSystemURL(int request_id, const fileapi::FileSystemURL& url);
+ bool ValidateFileSystemURL(int request_id, const storage::FileSystemURL& url);
// Retrieves the Stream object for |url| from |stream_context_|. Returns unset
// scoped_refptr when there's no Stream instance for the given |url|
// registered with stream_context_->registry().
scoped_refptr<Stream> GetStreamForURL(const GURL& url);
- fileapi::FileSystemOperationRunner* operation_runner() {
+ storage::FileSystemOperationRunner* operation_runner() {
return operation_runner_.get();
}
int process_id_;
- fileapi::FileSystemContext* context_;
+ storage::FileSystemContext* context_;
ChildProcessSecurityPolicyImpl* security_policy_;
// Keeps map from request_id to OperationID for ongoing operations.
@@ -226,7 +224,7 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
scoped_refptr<StreamContext> stream_context_;
- scoped_ptr<fileapi::FileSystemOperationRunner> operation_runner_;
+ scoped_ptr<storage::FileSystemOperationRunner> operation_runner_;
// Keeps track of blobs used in this process and cleans up
// when the renderer process dies.
@@ -238,7 +236,7 @@ class CONTENT_EXPORT FileAPIMessageFilter : public BrowserMessageFilter {
// Used to keep snapshot files alive while a DidCreateSnapshot
// is being sent to the renderer.
- std::map<int, scoped_refptr<webkit_blob::ShareableFileReference> >
+ std::map<int, scoped_refptr<storage::ShareableFileReference> >
in_transit_snapshot_files_;
DISALLOW_COPY_AND_ASSIGN(FileAPIMessageFilter);
diff --git a/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc b/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
index 3a4c47e93eb..b3a66595420 100644
--- a/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
+++ b/chromium/content/browser/fileapi/fileapi_message_filter_unittest.cc
@@ -10,7 +10,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
-#include "base/process/process.h"
+#include "base/process/process_handle.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/streams/stream_registry.h"
@@ -23,10 +23,10 @@
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_file_system_context.h"
#include "net/base/io_buffer.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/common/blob/blob_data.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/common/blob/blob_data.h"
namespace content {
@@ -48,17 +48,17 @@ class FileAPIMessageFilterTest : public testing::Test {
}
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
file_system_context_ =
CreateFileSystemContextForTesting(NULL, base::FilePath());
- std::vector<fileapi::FileSystemType> types;
+ std::vector<storage::FileSystemType> types;
file_system_context_->GetFileSystemTypes(&types);
for (size_t i = 0; i < types.size(); ++i) {
- ChildProcessSecurityPolicyImpl::GetInstance()->
- RegisterFileSystemPermissionPolicy(
+ ChildProcessSecurityPolicyImpl::GetInstance()
+ ->RegisterFileSystemPermissionPolicy(
types[i],
- fileapi::FileSystemContext::GetPermissionPolicy(types[i]));
+ storage::FileSystemContext::GetPermissionPolicy(types[i]));
}
stream_context_ = StreamContext::GetFor(&browser_context_);
@@ -79,7 +79,7 @@ class FileAPIMessageFilterTest : public testing::Test {
TestBrowserThread io_browser_thread_;
TestBrowserContext browser_context_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
StreamContext* stream_context_;
ChromeBlobStorageContext* blob_storage_context_;
@@ -197,7 +197,7 @@ TEST_F(FileAPIMessageFilterTest, BuildNonEmptyStream) {
StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
EXPECT_TRUE(filter_->OnMessageReceived(start_message));
- webkit_blob::BlobData::Item item;
+ storage::BlobData::Item item;
const std::string kFakeData = "foobarbaz";
item.SetToBytes(kFakeData.data(), kFakeData.size());
StreamHostMsg_AppendBlobDataItem append_message(kUrl, item);
@@ -236,7 +236,7 @@ TEST_F(FileAPIMessageFilterTest, BuildStreamWithSharedMemory) {
// OnAppendSharedMemoryToStream passes the peer process's handle to
// SharedMemory's constructor. If it's incorrect, DuplicateHandle won't work
// correctly.
- filter_->set_peer_pid_for_testing(base::Process::Current().pid());
+ filter_->set_peer_pid_for_testing(base::GetCurrentProcId());
StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
EXPECT_TRUE(filter_->OnMessageReceived(start_message));
diff --git a/chromium/content/browser/fileapi/isolated_context_unittest.cc b/chromium/content/browser/fileapi/isolated_context_unittest.cc
index be5cc8e1c00..72969344505 100644
--- a/chromium/content/browser/fileapi/isolated_context_unittest.cc
+++ b/chromium/content/browser/fileapi/isolated_context_unittest.cc
@@ -6,9 +6,9 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/isolated_context.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/isolated_context.h"
#define FPL(x) FILE_PATH_LITERAL(x)
@@ -18,12 +18,12 @@
#define DRIVE
#endif
-using fileapi::FileSystemMountOption;
-using fileapi::FileSystemURL;
-using fileapi::IsolatedContext;
-using fileapi::kFileSystemTypeDragged;
-using fileapi::kFileSystemTypeIsolated;
-using fileapi::kFileSystemTypeNativeLocal;
+using storage::FileSystemMountOption;
+using storage::FileSystemURL;
+using storage::IsolatedContext;
+using storage::kFileSystemTypeDragged;
+using storage::kFileSystemTypeIsolated;
+using storage::kFileSystemTypeNativeLocal;
namespace content {
@@ -55,7 +55,7 @@ class IsolatedContextTest : public testing::Test {
fileset_.insert(kTestPaths[i].NormalizePathSeparators());
}
- virtual void SetUp() {
+ void SetUp() override {
IsolatedContext::FileInfoSet files;
for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
std::string name;
@@ -68,7 +68,7 @@ class IsolatedContextTest : public testing::Test {
ASSERT_FALSE(id_.empty());
}
- virtual void TearDown() {
+ void TearDown() override {
IsolatedContext::GetInstance()->RemoveReference(id_);
}
@@ -103,7 +103,7 @@ TEST_F(IsolatedContextTest, RegisterAndRevokeTest) {
std::string cracked_id;
base::FilePath cracked_path;
std::string cracked_inner_id;
- fileapi::FileSystemType cracked_type;
+ storage::FileSystemType cracked_type;
FileSystemMountOption cracked_option;
ASSERT_TRUE(isolated_context()->CrackVirtualPath(
virtual_path, &cracked_id, &cracked_type, &cracked_inner_id,
@@ -195,7 +195,7 @@ TEST_F(IsolatedContextTest, CrackWithRelativePaths) {
};
for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
- for (size_t j = 0; j < ARRAYSIZE_UNSAFE(relatives); ++j) {
+ for (size_t j = 0; j < arraysize(relatives); ++j) {
SCOPED_TRACE(testing::Message() << "Testing "
<< kTestPaths[i].value() << " " << relatives[j].path);
base::FilePath virtual_path =
@@ -203,7 +203,7 @@ TEST_F(IsolatedContextTest, CrackWithRelativePaths) {
names_[i]).Append(relatives[j].path);
std::string cracked_id;
base::FilePath cracked_path;
- fileapi::FileSystemType cracked_type;
+ storage::FileSystemType cracked_type;
std::string cracked_inner_id;
FileSystemMountOption cracked_option;
if (!relatives[j].valid) {
@@ -245,7 +245,7 @@ TEST_F(IsolatedContextTest, CrackURLWithRelativePaths) {
};
for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
- for (size_t j = 0; j < ARRAYSIZE_UNSAFE(relatives); ++j) {
+ for (size_t j = 0; j < arraysize(relatives); ++j) {
SCOPED_TRACE(testing::Message() << "Testing "
<< kTestPaths[i].value() << " " << relatives[j].path);
base::FilePath virtual_path =
@@ -299,35 +299,36 @@ TEST_F(IsolatedContextTest, CanHandleURL) {
// Should handle isolated file system.
EXPECT_TRUE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeIsolated));
+ storage::kFileSystemTypeIsolated));
// Shouldn't handle the rest.
EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeExternal));
+ storage::kFileSystemTypeExternal));
EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeTemporary));
+ storage::kFileSystemTypeTemporary));
EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypePersistent));
+ storage::kFileSystemTypePersistent));
EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeTest));
+ storage::kFileSystemTypeTest));
// Not even if it's isolated subtype.
EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeNativeLocal));
+ storage::kFileSystemTypeNativeLocal));
EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeDragged));
+ storage::kFileSystemTypeDragged));
EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeNativeMedia));
+ storage::kFileSystemTypeNativeMedia));
EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
- fileapi::kFileSystemTypeDeviceMedia));
+ storage::kFileSystemTypeDeviceMedia));
}
TEST_F(IsolatedContextTest, VirtualFileSystemTests) {
// Should be able to register empty and non-absolute paths
std::string empty_fsid = isolated_context()->RegisterFileSystemForVirtualPath(
- fileapi::kFileSystemTypeIsolated, "_", base::FilePath());
+ storage::kFileSystemTypeIsolated, "_", base::FilePath());
std::string relative_fsid =
isolated_context()->RegisterFileSystemForVirtualPath(
- fileapi::kFileSystemTypeIsolated, "_",
+ storage::kFileSystemTypeIsolated,
+ "_",
base::FilePath(FPL("relpath")));
ASSERT_FALSE(empty_fsid.empty());
ASSERT_FALSE(relative_fsid.empty());
@@ -336,7 +337,7 @@ TEST_F(IsolatedContextTest, VirtualFileSystemTests) {
base::FilePath database_root = base::FilePath(DRIVE FPL("/database_path"));
std::string database_fsid =
isolated_context()->RegisterFileSystemForVirtualPath(
- fileapi::kFileSystemTypeIsolated, "_", database_root);
+ storage::kFileSystemTypeIsolated, "_", database_root);
base::FilePath test_virtual_path =
base::FilePath().AppendASCII("virtualdir").AppendASCII("virtualfile.txt");
diff --git a/chromium/content/browser/fileapi/local_file_stream_reader_unittest.cc b/chromium/content/browser/fileapi/local_file_stream_reader_unittest.cc
index c9547ed770c..461aa606c6c 100644
--- a/chromium/content/browser/fileapi/local_file_stream_reader_unittest.cc
+++ b/chromium/content/browser/fileapi/local_file_stream_reader_unittest.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 "webkit/browser/blob/local_file_stream_reader.h"
+#include "storage/browser/blob/local_file_stream_reader.h"
#include <string>
-#include "base/file_util.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/memory/scoped_ptr.h"
#include "base/run_loop.h"
@@ -18,7 +18,7 @@
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
-using webkit_blob::LocalFileStreamReader;
+using storage::LocalFileStreamReader;
namespace content {
@@ -64,7 +64,7 @@ class LocalFileStreamReaderTest : public testing::Test {
LocalFileStreamReaderTest()
: file_thread_("FileUtilProxyTestFileThread") {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(file_thread_.Start());
ASSERT_TRUE(dir_.CreateUniqueTempDir());
@@ -74,7 +74,7 @@ class LocalFileStreamReaderTest : public testing::Test {
test_file_modification_time_ = info.last_modified;
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// Give another chance for deleted streams to perform Close.
base::RunLoop().RunUntilIdle();
file_thread_.Stop();
diff --git a/chromium/content/browser/fileapi/local_file_stream_writer_unittest.cc b/chromium/content/browser/fileapi/local_file_stream_writer_unittest.cc
index 97e5e1ecc1a..48f5560ff8b 100644
--- a/chromium/content/browser/fileapi/local_file_stream_writer_unittest.cc
+++ b/chromium/content/browser/fileapi/local_file_stream_writer_unittest.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/local_file_stream_writer.h"
+#include "storage/browser/fileapi/local_file_stream_writer.h"
#include <string>
#include "base/callback.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -18,8 +18,8 @@
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
-using fileapi::FileStreamWriter;
-using fileapi::LocalFileStreamWriter;
+using storage::FileStreamWriter;
+using storage::LocalFileStreamWriter;
namespace content {
@@ -28,12 +28,12 @@ class LocalFileStreamWriterTest : public testing::Test {
LocalFileStreamWriterTest()
: file_thread_("FileUtilProxyTestFileThread") {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(file_thread_.Start());
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// Give another chance for deleted streams to perform Close.
base::RunLoop().RunUntilIdle();
file_thread_.Stop();
diff --git a/chromium/content/browser/fileapi/local_file_util_unittest.cc b/chromium/content/browser/fileapi/local_file_util_unittest.cc
index a20b18d3bff..bf2f2f874a3 100644
--- a/chromium/content/browser/fileapi/local_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/local_file_util_unittest.cc
@@ -4,9 +4,9 @@
#include <string>
-#include "base/file_util.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/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
@@ -14,28 +14,28 @@
#include "base/strings/utf_string_conversions.h"
#include "content/public/test/async_file_test_helper.h"
#include "content/public/test/test_file_system_context.h"
+#include "storage/browser/fileapi/async_file_util_adapter.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_file_util.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/local_file_util.h"
+#include "storage/browser/fileapi/native_file_util.h"
+#include "storage/common/fileapi/file_system_types.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/async_file_util_adapter.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/local_file_util.h"
-#include "webkit/browser/fileapi/native_file_util.h"
-#include "webkit/common/fileapi/file_system_types.h"
using content::AsyncFileTestHelper;
-using fileapi::AsyncFileUtilAdapter;
-using fileapi::FileSystemContext;
-using fileapi::FileSystemOperationContext;
-using fileapi::FileSystemURL;
-using fileapi::LocalFileUtil;
+using storage::AsyncFileUtilAdapter;
+using storage::FileSystemContext;
+using storage::FileSystemOperationContext;
+using storage::FileSystemURL;
+using storage::LocalFileUtil;
namespace content {
namespace {
const GURL kOrigin("http://foo/");
-const fileapi::FileSystemType kFileSystemType = fileapi::kFileSystemTypeTest;
+const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
} // namespace
@@ -43,13 +43,13 @@ class LocalFileUtilTest : public testing::Test {
public:
LocalFileUtilTest() {}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
file_system_context_ = CreateFileSystemContextForTesting(
NULL, data_dir_.path());
}
- virtual void TearDown() {
+ void TearDown() override {
file_system_context_ = NULL;
base::RunLoop().RunUntilIdle();
}
diff --git a/chromium/content/browser/fileapi/mock_file_change_observer.cc b/chromium/content/browser/fileapi/mock_file_change_observer.cc
index c37f175d953..f6a86e964a0 100644
--- a/chromium/content/browser/fileapi/mock_file_change_observer.cc
+++ b/chromium/content/browser/fileapi/mock_file_change_observer.cc
@@ -4,7 +4,7 @@
#include "content/browser/fileapi/mock_file_change_observer.h"
-namespace fileapi {
+namespace storage {
MockFileChangeObserver::MockFileChangeObserver()
: create_file_count_(0),
@@ -48,4 +48,4 @@ void MockFileChangeObserver::OnRemoveDirectory(const FileSystemURL& url) {
remove_directory_count_++;
}
-} // namespace fileapi
+} // namespace storage
diff --git a/chromium/content/browser/fileapi/mock_file_change_observer.h b/chromium/content/browser/fileapi/mock_file_change_observer.h
index 4c1bcb2d1a4..3465a7a1f5d 100644
--- a/chromium/content/browser/fileapi/mock_file_change_observer.h
+++ b/chromium/content/browser/fileapi/mock_file_change_observer.h
@@ -7,29 +7,29 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "webkit/browser/fileapi/file_observers.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
+#include "storage/browser/fileapi/file_observers.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/task_runner_bound_observer_list.h"
-namespace fileapi {
+namespace storage {
// Mock file change observer.
class MockFileChangeObserver : public FileChangeObserver {
public:
MockFileChangeObserver();
- virtual ~MockFileChangeObserver();
+ ~MockFileChangeObserver() override;
// Creates a ChangeObserverList which only contains given |observer|.
static ChangeObserverList CreateList(MockFileChangeObserver* observer);
// FileChangeObserver overrides.
- virtual void OnCreateFile(const FileSystemURL& url) OVERRIDE;
- virtual void OnCreateFileFrom(const FileSystemURL& url,
- const FileSystemURL& src) OVERRIDE;
- virtual void OnRemoveFile(const FileSystemURL& url) OVERRIDE;
- virtual void OnModifyFile(const FileSystemURL& url) OVERRIDE;
- virtual void OnCreateDirectory(const FileSystemURL& url) OVERRIDE;
- virtual void OnRemoveDirectory(const FileSystemURL& url) OVERRIDE;
+ void OnCreateFile(const FileSystemURL& url) override;
+ void OnCreateFileFrom(const FileSystemURL& url,
+ const FileSystemURL& src) override;
+ void OnRemoveFile(const FileSystemURL& url) override;
+ void OnModifyFile(const FileSystemURL& url) override;
+ void OnCreateDirectory(const FileSystemURL& url) override;
+ void OnRemoveDirectory(const FileSystemURL& url) override;
void ResetCount() {
create_file_count_ = 0;
@@ -98,6 +98,6 @@ class MockFileChangeObserver : public FileChangeObserver {
DISALLOW_COPY_AND_ASSIGN(MockFileChangeObserver);
};
-} // namespace fileapi
+} // namespace storage
#endif // WEBKIT_BROWSER_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
diff --git a/chromium/content/browser/fileapi/mock_file_update_observer.cc b/chromium/content/browser/fileapi/mock_file_update_observer.cc
new file mode 100644
index 00000000000..2951d3ec77e
--- /dev/null
+++ b/chromium/content/browser/fileapi/mock_file_update_observer.cc
@@ -0,0 +1,42 @@
+// 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 "base/thread_task_runner_handle.h"
+#include "content/browser/fileapi/mock_file_update_observer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace storage {
+
+MockFileUpdateObserver::MockFileUpdateObserver() : is_ready_(false) {
+}
+
+MockFileUpdateObserver::~MockFileUpdateObserver() {
+}
+
+// static
+UpdateObserverList MockFileUpdateObserver::CreateList(
+ MockFileUpdateObserver* observer) {
+ UpdateObserverList list;
+ return list.AddObserver(observer, base::ThreadTaskRunnerHandle::Get().get());
+}
+
+void MockFileUpdateObserver::OnStartUpdate(const FileSystemURL& url) {
+ if (is_ready_)
+ ++start_update_count_[url];
+}
+
+void MockFileUpdateObserver::OnUpdate(const FileSystemURL& url, int64 delta) {
+ if (!is_ready_)
+ return;
+ int start = start_update_count_[url];
+ int end = end_update_count_[url];
+ EXPECT_LT(0, start - end);
+}
+
+void MockFileUpdateObserver::OnEndUpdate(const FileSystemURL& url) {
+ if (is_ready_)
+ ++end_update_count_[url];
+}
+
+} // namespace storage
diff --git a/chromium/content/browser/fileapi/mock_file_update_observer.h b/chromium/content/browser/fileapi/mock_file_update_observer.h
new file mode 100644
index 00000000000..78aef9fae25
--- /dev/null
+++ b/chromium/content/browser/fileapi/mock_file_update_observer.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBKIT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
+#define WEBKIT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "storage/browser/fileapi/file_observers.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/task_runner_bound_observer_list.h"
+
+namespace storage {
+
+// Mock file change observer.
+class MockFileUpdateObserver : public FileUpdateObserver {
+ public:
+ MockFileUpdateObserver();
+ ~MockFileUpdateObserver() override;
+
+ // Creates a ChangeObserverList which only contains given |observer|.
+ static UpdateObserverList CreateList(MockFileUpdateObserver* observer);
+
+ // FileUpdateObserver overrides.
+ void OnStartUpdate(const FileSystemURL& url) override;
+ void OnUpdate(const FileSystemURL& url, int64 delta) override;
+ void OnEndUpdate(const FileSystemURL& url) override;
+
+ void Enable() { is_ready_ = true; }
+
+ void Disable() {
+ start_update_count_.clear();
+ end_update_count_.clear();
+ is_ready_ = false;
+ }
+
+ private:
+ std::map<FileSystemURL, int, FileSystemURL::Comparator> start_update_count_;
+ std::map<FileSystemURL, int, FileSystemURL::Comparator> end_update_count_;
+ bool is_ready_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockFileUpdateObserver);
+};
+
+} // namespace storage
+
+#endif // WEBKIT_BROWSER_FILEAPI_MOCK_FILE_UPDATE_OBSERVER_H_
diff --git a/chromium/content/browser/fileapi/mock_url_request_delegate.h b/chromium/content/browser/fileapi/mock_url_request_delegate.h
index 137b11426e8..a628f6ea5a4 100644
--- a/chromium/content/browser/fileapi/mock_url_request_delegate.h
+++ b/chromium/content/browser/fileapi/mock_url_request_delegate.h
@@ -17,11 +17,10 @@ namespace content {
class MockURLRequestDelegate : public net::URLRequest::Delegate {
public:
MockURLRequestDelegate();
- virtual ~MockURLRequestDelegate();
+ ~MockURLRequestDelegate() override;
- virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
- virtual void OnReadCompleted(net::URLRequest* request,
- int bytes_read) OVERRIDE;
+ void OnResponseStarted(net::URLRequest* request) override;
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
const std::string& response_data() const { return response_data_; }
private:
diff --git a/chromium/content/browser/fileapi/native_file_util_unittest.cc b/chromium/content/browser/fileapi/native_file_util_unittest.cc
index e20914d6610..85aadb672f7 100644
--- a/chromium/content/browser/fileapi/native_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/native_file_util_unittest.cc
@@ -4,16 +4,16 @@
#include <set>
-#include "base/file_util.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 "storage/browser/fileapi/native_file_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/native_file_util.h"
-using fileapi::FileSystemFileUtil;
-using fileapi::FileSystemOperation;
-using fileapi::NativeFileUtil;
+using storage::FileSystemFileUtil;
+using storage::FileSystemOperation;
+using storage::NativeFileUtil;
namespace content {
@@ -21,9 +21,7 @@ class NativeFileUtilTest : public testing::Test {
public:
NativeFileUtilTest() {}
- virtual void SetUp() {
- ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
- }
+ void SetUp() override { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); }
protected:
base::FilePath Path() {
diff --git a/chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc b/chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc
index 089cef8d73d..cef39901405 100644
--- a/chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -7,9 +7,9 @@
#include <vector>
#include "base/bind.h"
-#include "base/file_util.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/memory/scoped_ptr.h"
#include "base/run_loop.h"
@@ -19,31 +19,31 @@
#include "content/public/test/sandbox_file_system_test_helper.h"
#include "content/public/test/test_file_system_context.h"
#include "content/test/fileapi_test_file_set.h"
+#include "storage/browser/fileapi/external_mount_points.h"
+#include "storage/browser/fileapi/file_system_backend.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/file_system_usage_cache.h"
+#include "storage/browser/fileapi/obfuscated_file_util.h"
+#include "storage/browser/fileapi/sandbox_directory_database.h"
+#include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
+#include "storage/browser/fileapi/sandbox_isolated_origin_database.h"
+#include "storage/browser/fileapi/sandbox_origin_database.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/common/database/database_identifier.h"
+#include "storage/common/quota/quota_types.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/external_mount_points.h"
-#include "webkit/browser/fileapi/file_system_backend.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/file_system_usage_cache.h"
-#include "webkit/browser/fileapi/obfuscated_file_util.h"
-#include "webkit/browser/fileapi/sandbox_directory_database.h"
-#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
-#include "webkit/browser/fileapi/sandbox_isolated_origin_database.h"
-#include "webkit/browser/fileapi/sandbox_origin_database.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/common/database/database_identifier.h"
-#include "webkit/common/quota/quota_types.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemContext;
-using fileapi::FileSystemOperation;
-using fileapi::FileSystemOperationContext;
-using fileapi::FileSystemURL;
-using fileapi::ObfuscatedFileUtil;
-using fileapi::SandboxDirectoryDatabase;
-using fileapi::SandboxIsolatedOriginDatabase;
-using fileapi::kFileSystemTypeTemporary;
-using fileapi::kFileSystemTypePersistent;
+using storage::FileSystemContext;
+using storage::FileSystemOperation;
+using storage::FileSystemOperationContext;
+using storage::FileSystemURL;
+using storage::ObfuscatedFileUtil;
+using storage::SandboxDirectoryDatabase;
+using storage::SandboxIsolatedOriginDatabase;
+using storage::kFileSystemTypeTemporary;
+using storage::kFileSystemTypePersistent;
namespace content {
@@ -121,16 +121,17 @@ FileSystemURL FileSystemURLAppendUTF8(
FileSystemURL FileSystemURLDirName(const FileSystemURL& url) {
return FileSystemURL::CreateForTest(
- url.origin(), url.mount_type(),
- fileapi::VirtualPath::DirName(url.virtual_path()));
+ url.origin(),
+ url.mount_type(),
+ storage::VirtualPath::DirName(url.virtual_path()));
}
-std::string GetTypeString(fileapi::FileSystemType type) {
- return fileapi::SandboxFileSystemBackendDelegate::GetTypeString(type);
+std::string GetTypeString(storage::FileSystemType type) {
+ return storage::SandboxFileSystemBackendDelegate::GetTypeString(type);
}
bool HasFileSystemType(ObfuscatedFileUtil::AbstractOriginEnumerator* enumerator,
- fileapi::FileSystemType type) {
+ storage::FileSystemType type) {
return enumerator->HasTypeDirectory(GetTypeString(type));
}
@@ -144,24 +145,23 @@ class ObfuscatedFileUtilTest : public testing::Test {
public:
ObfuscatedFileUtilTest()
: origin_(GURL("http://www.example.com")),
- type_(fileapi::kFileSystemTypeTemporary),
+ type_(storage::kFileSystemTypeTemporary),
weak_factory_(this),
sandbox_file_system_(origin_, type_),
- quota_status_(quota::kQuotaStatusUnknown),
- usage_(-1) {
- }
+ quota_status_(storage::kQuotaStatusUnknown),
+ usage_(-1) {}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
storage_policy_ = new MockSpecialStoragePolicy();
quota_manager_ =
- new quota::QuotaManager(false /* is_incognito */,
- data_dir_.path(),
- base::MessageLoopProxy::current().get(),
- base::MessageLoopProxy::current().get(),
- storage_policy_.get());
+ new storage::QuotaManager(false /* is_incognito */,
+ data_dir_.path(),
+ base::MessageLoopProxy::current().get(),
+ base::MessageLoopProxy::current().get(),
+ storage_policy_.get());
// Every time we create a new sandbox_file_system helper,
// it creates another context, which creates another path manager,
@@ -173,11 +173,11 @@ class ObfuscatedFileUtilTest : public testing::Test {
sandbox_file_system_.SetUp(file_system_context_.get());
- change_observers_ = fileapi::MockFileChangeObserver::CreateList(
- &change_observer_);
+ change_observers_ =
+ storage::MockFileChangeObserver::CreateList(&change_observer_);
}
- virtual void TearDown() {
+ void TearDown() override {
quota_manager_ = NULL;
sandbox_file_system_.TearDown();
}
@@ -208,11 +208,11 @@ class ObfuscatedFileUtilTest : public testing::Test {
return context;
}
- const fileapi::ChangeObserverList& change_observers() const {
+ const storage::ChangeObserverList& change_observers() const {
return change_observers_;
}
- fileapi::MockFileChangeObserver* change_observer() {
+ storage::MockFileChangeObserver* change_observer() {
return &change_observer_;
}
@@ -220,8 +220,8 @@ class ObfuscatedFileUtilTest : public testing::Test {
// and obfuscated_file_util_.
// Use this for tests which need to run in multiple origins; we need a test
// helper per origin.
- SandboxFileSystemTestHelper* NewFileSystem(
- const GURL& origin, fileapi::FileSystemType type) {
+ SandboxFileSystemTestHelper* NewFileSystem(const GURL& origin,
+ storage::FileSystemType type) {
SandboxFileSystemTestHelper* file_system =
new SandboxFileSystemTestHelper(origin, type);
@@ -230,7 +230,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
}
scoped_ptr<ObfuscatedFileUtil> CreateObfuscatedFileUtil(
- quota::SpecialStoragePolicy* storage_policy) {
+ storage::SpecialStoragePolicy* storage_policy) {
return scoped_ptr<ObfuscatedFileUtil>(
ObfuscatedFileUtil::CreateForTesting(
storage_policy, data_dir_path(), NULL,
@@ -249,9 +249,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
return origin_;
}
- fileapi::FileSystemType type() const {
- return type_;
- }
+ storage::FileSystemType type() const { return type_; }
std::string type_string() const {
return GetTypeString(type_);
@@ -270,7 +268,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
sandbox_file_system_.type(),
&usage_,
&quota);
- EXPECT_EQ(quota::kQuotaStatusOk, quota_status_);
+ EXPECT_EQ(storage::kQuotaStatusOk, quota_status_);
}
void RevokeUsageCache() {
@@ -303,7 +301,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
}
int64 usage() const { return usage_; }
- fileapi::FileSystemUsageCache* usage_cache() {
+ storage::FileSystemUsageCache* usage_cache() {
return sandbox_file_system_.usage_cache();
}
@@ -440,7 +438,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
std::set<base::FilePath::StringType>* files,
std::set<base::FilePath::StringType>* directories) {
scoped_ptr<FileSystemOperationContext> context;
- std::vector<fileapi::DirectoryEntry> entries;
+ std::vector<storage::DirectoryEntry> entries;
EXPECT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::ReadDirectory(file_system_context(),
root_url, &entries));
@@ -482,17 +480,17 @@ class ObfuscatedFileUtilTest : public testing::Test {
FillTestDirectory(root_url, &files, &directories);
scoped_ptr<FileSystemOperationContext> context;
- std::vector<fileapi::DirectoryEntry> entries;
+ std::vector<storage::DirectoryEntry> entries;
context.reset(NewContext(NULL));
EXPECT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::ReadDirectory(
file_system_context(), root_url, &entries));
- std::vector<fileapi::DirectoryEntry>::iterator entry_iter;
+ std::vector<storage::DirectoryEntry>::iterator entry_iter;
EXPECT_EQ(files.size() + directories.size(), entries.size());
EXPECT_TRUE(change_observer()->HasNoChange());
for (entry_iter = entries.begin(); entry_iter != entries.end();
++entry_iter) {
- const fileapi::DirectoryEntry& entry = *entry_iter;
+ const storage::DirectoryEntry& entry = *entry_iter;
std::set<base::FilePath::StringType>::iterator iter =
files.find(entry.name);
if (iter != files.end()) {
@@ -711,8 +709,8 @@ class ObfuscatedFileUtilTest : public testing::Test {
ASSERT_TRUE(db != NULL);
// Destory it.
- ASSERT_TRUE(file_util->DestroyDirectoryDatabase(
- url.origin(), GetTypeString(url.type())));
+ file_util->DestroyDirectoryDatabase(
+ url.origin(), GetTypeString(url.type()));
ASSERT_TRUE(file_util->directories_.empty());
}
@@ -745,8 +743,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
// Initialize the directory with one origin using
// SandboxIsolatedOriginDatabase.
{
- std::string origin_string =
- webkit_database::GetIdentifierFromOrigin(origin_);
+ std::string origin_string = storage::GetIdentifierFromOrigin(origin_);
SandboxIsolatedOriginDatabase database_old(
origin_string, data_dir_path(),
base::FilePath(
@@ -799,18 +796,18 @@ class ObfuscatedFileUtilTest : public testing::Test {
protected:
base::ScopedTempDir data_dir_;
- base::MessageLoop message_loop_;
+ base::MessageLoopForIO message_loop_;
scoped_refptr<MockSpecialStoragePolicy> storage_policy_;
- scoped_refptr<quota::QuotaManager> quota_manager_;
+ scoped_refptr<storage::QuotaManager> quota_manager_;
scoped_refptr<FileSystemContext> file_system_context_;
GURL origin_;
- fileapi::FileSystemType type_;
+ storage::FileSystemType type_;
base::WeakPtrFactory<ObfuscatedFileUtilTest> weak_factory_;
SandboxFileSystemTestHelper sandbox_file_system_;
- quota::QuotaStatusCode quota_status_;
+ storage::QuotaStatusCode quota_status_;
int64 usage_;
- fileapi::MockFileChangeObserver change_observer_;
- fileapi::ChangeObserverList change_observers_;
+ storage::MockFileChangeObserver change_observer_;
+ storage::ChangeObserverList change_observers_;
private:
DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilTest);
@@ -1217,7 +1214,7 @@ TEST_F(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) {
ofu()->EnsureFileExists(context.get(), url, &created));
ASSERT_TRUE(created);
- std::vector<fileapi::DirectoryEntry> entries;
+ std::vector<storage::DirectoryEntry> entries;
EXPECT_EQ(base::File::FILE_ERROR_NOT_A_DIRECTORY,
AsyncFileTestHelper::ReadDirectory(file_system_context(), url,
&entries));
@@ -1787,7 +1784,7 @@ TEST_F(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) {
const FileSystemURL empty_path = CreateURL(base::FilePath());
scoped_ptr<FileSystemOperationContext> context;
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kPath); ++i) {
+ for (size_t i = 0; i < arraysize(kPath); ++i) {
bool created = false;
context.reset(NewContext(NULL));
EXPECT_EQ(base::File::FILE_OK,
@@ -1795,7 +1792,7 @@ TEST_F(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) {
EXPECT_TRUE(created);
}
- std::vector<fileapi::DirectoryEntry> entries;
+ std::vector<storage::DirectoryEntry> entries;
EXPECT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::ReadDirectory(
file_system_context(), empty_path, &entries));
@@ -1810,7 +1807,7 @@ TEST_F(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) {
EXPECT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::ReadDirectory(
file_system_context(), empty_path, &entries));
- EXPECT_EQ(ARRAYSIZE_UNSAFE(kPath) - 1, entries.size());
+ EXPECT_EQ(arraysize(kPath) - 1, entries.size());
}
TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) {
@@ -2040,7 +2037,7 @@ TEST_F(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) {
base::Time()));
context.reset(NewContext(NULL));
- scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator> file_enum(
+ scoped_ptr<storage::FileSystemFileUtil::AbstractFileEnumerator> file_enum(
ofu()->CreateFileEnumerator(context.get(), dir, false));
int count = 0;
@@ -2190,7 +2187,6 @@ TEST_F(ObfuscatedFileUtilTest, TestQuotaOnMoveFile) {
from_file, from_file_size));
ASSERT_EQ(expected_total_file_size, ComputeTotalFileSize());
- int64 to_file_size ALLOW_UNUSED = from_file_size;
from_file_size = 0;
ASSERT_EQ(base::File::FILE_OK,
ofu()->CopyOrMoveFile(
@@ -2453,4 +2449,123 @@ TEST_F(ObfuscatedFileUtilTest, CreateDirectory_NotADirectoryInRecursive) {
true /* recursive */));
}
+TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) {
+ const GURL origin1("http://www.example.com:12");
+ const GURL origin2("http://www.example.com:1234");
+
+ // Create origin directories.
+ scoped_ptr<SandboxFileSystemTestHelper> fs1(
+ NewFileSystem(origin1, kFileSystemTypeTemporary));
+ scoped_ptr<SandboxFileSystemTestHelper> fs2(
+ NewFileSystem(origin1, kFileSystemTypePersistent));
+ scoped_ptr<SandboxFileSystemTestHelper> fs3(
+ NewFileSystem(origin2, kFileSystemTypeTemporary));
+ scoped_ptr<SandboxFileSystemTestHelper> fs4(
+ NewFileSystem(origin2, kFileSystemTypePersistent));
+
+ // Make sure directories for origin1 exist.
+ base::File::Error error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypeTemporary), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypePersistent), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ // Make sure directories for origin2 exist.
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin2, GetTypeString(kFileSystemTypeTemporary), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin2, GetTypeString(kFileSystemTypePersistent), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ // Delete a directory for origin1's persistent filesystem.
+ ofu()->DeleteDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypePersistent));
+
+ // The directory for origin1's temporary filesystem should not be removed.
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypeTemporary), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ // The directory for origin1's persistent filesystem should be removed.
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypePersistent), false, &error);
+ ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error);
+
+ // The directories for origin2 should not be removed.
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin2, GetTypeString(kFileSystemTypeTemporary), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin2, GetTypeString(kFileSystemTypePersistent), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+}
+
+TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) {
+ const GURL origin1("http://www.example.com:12");
+ const GURL origin2("http://www.example.com:1234");
+
+ // Create origin directories.
+ scoped_ptr<SandboxFileSystemTestHelper> fs1(
+ NewFileSystem(origin1, kFileSystemTypeTemporary));
+ scoped_ptr<SandboxFileSystemTestHelper> fs2(
+ NewFileSystem(origin1, kFileSystemTypePersistent));
+ scoped_ptr<SandboxFileSystemTestHelper> fs3(
+ NewFileSystem(origin2, kFileSystemTypeTemporary));
+ scoped_ptr<SandboxFileSystemTestHelper> fs4(
+ NewFileSystem(origin2, kFileSystemTypePersistent));
+
+ // Make sure directories for origin1 exist.
+ base::File::Error error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypeTemporary), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypePersistent), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ // Make sure directories for origin2 exist.
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin2, GetTypeString(kFileSystemTypeTemporary), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin2, GetTypeString(kFileSystemTypePersistent), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ // Delete all directories for origin1.
+ ofu()->DeleteDirectoryForOriginAndType(origin1, std::string());
+
+ // The directories for origin1 should be removed.
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypeTemporary), false, &error);
+ ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error);
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin1, GetTypeString(kFileSystemTypePersistent), false, &error);
+ ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND, error);
+
+ // The directories for origin2 should not be removed.
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin2, GetTypeString(kFileSystemTypeTemporary), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+ error = base::File::FILE_ERROR_FAILED;
+ ofu()->GetDirectoryForOriginAndType(
+ origin2, GetTypeString(kFileSystemTypePersistent), false, &error);
+ ASSERT_EQ(base::File::FILE_OK, error);
+}
+
} // namespace content
diff --git a/chromium/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc b/chromium/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
index 08fb9e0fbc7..ef88fed2f83 100644
--- a/chromium/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
+++ b/chromium/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "base/basictypes.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
@@ -12,26 +12,27 @@
#include "content/public/test/async_file_test_helper.h"
#include "content/public/test/test_file_system_context.h"
#include "content/public/test/test_file_system_options.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/browser/fileapi/obfuscated_file_util.h"
+#include "storage/browser/fileapi/plugin_private_file_system_backend.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/browser/fileapi/obfuscated_file_util.h"
-#include "webkit/browser/fileapi/plugin_private_file_system_backend.h"
-#include "webkit/common/fileapi/file_system_util.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemContext;
-using fileapi::FileSystemURL;
-using fileapi::IsolatedContext;
+using storage::FileSystemContext;
+using storage::FileSystemURL;
+using storage::IsolatedContext;
namespace content {
namespace {
-const GURL kOrigin("http://www.example.com");
+const GURL kOrigin1("http://www.example.com");
+const GURL kOrigin2("https://www.example.com");
const std::string kPlugin1("plugin1");
const std::string kPlugin2("plugin2");
-const fileapi::FileSystemType kType = fileapi::kFileSystemTypePluginPrivate;
+const storage::FileSystemType kType = storage::kFileSystemTypePluginPrivate;
const std::string kRootName = "pluginprivate";
void DidOpenFileSystem(base::File::Error* error_out,
@@ -48,7 +49,7 @@ std::string RegisterFileSystem() {
class PluginPrivateFileSystemBackendTest : public testing::Test {
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
context_ = CreateFileSystemContextForTesting(
NULL /* quota_manager_proxy */,
@@ -63,7 +64,7 @@ class PluginPrivateFileSystemBackendTest : public testing::Test {
root.virtual_path().AppendASCII(relative));
}
- fileapi::PluginPrivateFileSystemBackend* backend() const {
+ storage::PluginPrivateFileSystemBackend* backend() const {
return context_->plugin_private_backend();
}
@@ -72,15 +73,20 @@ class PluginPrivateFileSystemBackendTest : public testing::Test {
base::ScopedTempDir data_dir_;
base::MessageLoop message_loop_;
scoped_refptr<FileSystemContext> context_;
- std::string filesystem_id_;
};
+// TODO(kinuko,nhiroki): There are a lot of duplicate code in these tests. Write
+// helper functions to simplify the tests.
+
TEST_F(PluginPrivateFileSystemBackendTest, OpenFileSystemBasic) {
const std::string filesystem_id1 = RegisterFileSystem();
base::File::Error error = base::File::FILE_ERROR_FAILED;
backend()->OpenPrivateFileSystem(
- kOrigin, kType, filesystem_id1, kPlugin1,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ kOrigin1,
+ kType,
+ filesystem_id1,
+ kPlugin1,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&DidOpenFileSystem, &error));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(base::File::FILE_OK, error);
@@ -89,15 +95,17 @@ TEST_F(PluginPrivateFileSystemBackendTest, OpenFileSystemBasic) {
const std::string filesystem_id2 = RegisterFileSystem();
error = base::File::FILE_ERROR_FAILED;
backend()->OpenPrivateFileSystem(
- kOrigin, kType, filesystem_id2, kPlugin1,
- fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
+ kOrigin1,
+ kType,
+ filesystem_id2,
+ kPlugin1,
+ storage::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
base::Bind(&DidOpenFileSystem, &error));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(base::File::FILE_OK, error);
- const GURL root_url(
- fileapi::GetIsolatedFileSystemRootURIString(
- kOrigin, filesystem_id1, kRootName));
+ const GURL root_url(storage::GetIsolatedFileSystemRootURIString(
+ kOrigin1, filesystem_id1, kRootName));
FileSystemURL file = CreateURL(root_url, "foo");
base::FilePath platform_path;
EXPECT_EQ(base::File::FILE_OK,
@@ -114,8 +122,11 @@ TEST_F(PluginPrivateFileSystemBackendTest, PluginIsolation) {
const std::string filesystem_id1 = RegisterFileSystem();
base::File::Error error = base::File::FILE_ERROR_FAILED;
backend()->OpenPrivateFileSystem(
- kOrigin, kType, filesystem_id1, kPlugin1,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ kOrigin1,
+ kType,
+ filesystem_id1,
+ kPlugin1,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&DidOpenFileSystem, &error));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(base::File::FILE_OK, error);
@@ -123,33 +134,157 @@ TEST_F(PluginPrivateFileSystemBackendTest, PluginIsolation) {
const std::string filesystem_id2 = RegisterFileSystem();
error = base::File::FILE_ERROR_FAILED;
backend()->OpenPrivateFileSystem(
- kOrigin, kType, filesystem_id2, kPlugin2,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ kOrigin1,
+ kType,
+ filesystem_id2,
+ kPlugin2,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&DidOpenFileSystem, &error));
base::RunLoop().RunUntilIdle();
ASSERT_EQ(base::File::FILE_OK, error);
// Create 'foo' in kPlugin1.
- const GURL root_url1(
- fileapi::GetIsolatedFileSystemRootURIString(
- kOrigin, filesystem_id1, kRootName));
+ const GURL root_url1(storage::GetIsolatedFileSystemRootURIString(
+ kOrigin1, filesystem_id1, kRootName));
FileSystemURL file1 = CreateURL(root_url1, "foo");
- base::FilePath platform_path;
EXPECT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::CreateFile(context_.get(), file1));
EXPECT_TRUE(AsyncFileTestHelper::FileExists(
context_.get(), file1, AsyncFileTestHelper::kDontCheckSize));
// See the same path is not available in kPlugin2.
- const GURL root_url2(
- fileapi::GetIsolatedFileSystemRootURIString(
- kOrigin, filesystem_id2, kRootName));
+ const GURL root_url2(storage::GetIsolatedFileSystemRootURIString(
+ kOrigin1, filesystem_id2, kRootName));
FileSystemURL file2 = CreateURL(root_url2, "foo");
EXPECT_FALSE(AsyncFileTestHelper::FileExists(
context_.get(), file2, AsyncFileTestHelper::kDontCheckSize));
}
-// TODO(kinuko,nhiroki): also test if DeleteOriginDataOnFileThread
-// works fine when there's multiple plugin partitions.
+TEST_F(PluginPrivateFileSystemBackendTest, OriginIsolation) {
+ // Open filesystem for kOrigin1 and kOrigin2.
+ const std::string filesystem_id1 = RegisterFileSystem();
+ base::File::Error error = base::File::FILE_ERROR_FAILED;
+ backend()->OpenPrivateFileSystem(
+ kOrigin1,
+ kType,
+ filesystem_id1,
+ kPlugin1,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ base::Bind(&DidOpenFileSystem, &error));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ const std::string filesystem_id2 = RegisterFileSystem();
+ error = base::File::FILE_ERROR_FAILED;
+ backend()->OpenPrivateFileSystem(
+ kOrigin2,
+ kType,
+ filesystem_id2,
+ kPlugin1,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ base::Bind(&DidOpenFileSystem, &error));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ // Create 'foo' in kOrigin1.
+ const GURL root_url1(storage::GetIsolatedFileSystemRootURIString(
+ kOrigin1, filesystem_id1, kRootName));
+ FileSystemURL file1 = CreateURL(root_url1, "foo");
+ EXPECT_EQ(base::File::FILE_OK,
+ AsyncFileTestHelper::CreateFile(context_.get(), file1));
+ EXPECT_TRUE(AsyncFileTestHelper::FileExists(
+ context_.get(), file1, AsyncFileTestHelper::kDontCheckSize));
+
+ // See the same path is not available in kOrigin2.
+ const GURL root_url2(storage::GetIsolatedFileSystemRootURIString(
+ kOrigin2, filesystem_id2, kRootName));
+ FileSystemURL file2 = CreateURL(root_url2, "foo");
+ EXPECT_FALSE(AsyncFileTestHelper::FileExists(
+ context_.get(), file2, AsyncFileTestHelper::kDontCheckSize));
+}
+
+TEST_F(PluginPrivateFileSystemBackendTest, DeleteOriginDirectory) {
+ // Open filesystem for kOrigin1 and kOrigin2.
+ const std::string filesystem_id1 = RegisterFileSystem();
+ base::File::Error error = base::File::FILE_ERROR_FAILED;
+ backend()->OpenPrivateFileSystem(
+ kOrigin1,
+ kType,
+ filesystem_id1,
+ kPlugin1,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ base::Bind(&DidOpenFileSystem, &error));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ const std::string filesystem_id2 = RegisterFileSystem();
+ error = base::File::FILE_ERROR_FAILED;
+ backend()->OpenPrivateFileSystem(
+ kOrigin2,
+ kType,
+ filesystem_id2,
+ kPlugin1,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ base::Bind(&DidOpenFileSystem, &error));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ // Create 'foo' in kOrigin1.
+ const GURL root_url1(storage::GetIsolatedFileSystemRootURIString(
+ kOrigin1, filesystem_id1, kRootName));
+ FileSystemURL file1 = CreateURL(root_url1, "foo");
+ EXPECT_EQ(base::File::FILE_OK,
+ AsyncFileTestHelper::CreateFile(context_.get(), file1));
+ EXPECT_TRUE(AsyncFileTestHelper::FileExists(
+ context_.get(), file1, AsyncFileTestHelper::kDontCheckSize));
+
+ // Create 'foo' in kOrigin2.
+ const GURL root_url2(storage::GetIsolatedFileSystemRootURIString(
+ kOrigin2, filesystem_id2, kRootName));
+ FileSystemURL file2 = CreateURL(root_url2, "foo");
+ EXPECT_EQ(base::File::FILE_OK,
+ AsyncFileTestHelper::CreateFile(context_.get(), file2));
+ EXPECT_TRUE(AsyncFileTestHelper::FileExists(
+ context_.get(), file2, AsyncFileTestHelper::kDontCheckSize));
+
+ // Delete data for kOrigin1.
+ error = backend()->DeleteOriginDataOnFileTaskRunner(
+ context_.get(), NULL, kOrigin1, kType);
+ EXPECT_EQ(base::File::FILE_OK, error);
+
+ // Confirm 'foo' in kOrigin1 is deleted.
+ EXPECT_FALSE(AsyncFileTestHelper::FileExists(
+ context_.get(), file1, AsyncFileTestHelper::kDontCheckSize));
+
+ // Confirm 'foo' in kOrigin2 is NOT deleted.
+ EXPECT_TRUE(AsyncFileTestHelper::FileExists(
+ context_.get(), file2, AsyncFileTestHelper::kDontCheckSize));
+
+ // Re-open filesystem for kOrigin1.
+ const std::string filesystem_id3 = RegisterFileSystem();
+ error = base::File::FILE_ERROR_FAILED;
+ backend()->OpenPrivateFileSystem(
+ kOrigin1,
+ kType,
+ filesystem_id3,
+ kPlugin1,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ base::Bind(&DidOpenFileSystem, &error));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(base::File::FILE_OK, error);
+
+ // Re-create 'foo' in kOrigin1.
+ const GURL root_url3(storage::GetIsolatedFileSystemRootURIString(
+ kOrigin1, filesystem_id3, kRootName));
+ FileSystemURL file3 = CreateURL(root_url3, "foo");
+ EXPECT_EQ(base::File::FILE_OK,
+ AsyncFileTestHelper::CreateFile(context_.get(), file3));
+ EXPECT_TRUE(AsyncFileTestHelper::FileExists(
+ context_.get(), file3, AsyncFileTestHelper::kDontCheckSize));
+
+ // Confirm 'foo' in kOrigin1 is re-created.
+ EXPECT_TRUE(AsyncFileTestHelper::FileExists(
+ context_.get(), file3, AsyncFileTestHelper::kDontCheckSize));
+}
} // namespace content
diff --git a/chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc b/chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc
index a96a21213a2..38853844628 100644
--- a/chromium/content/browser/fileapi/recursive_operation_delegate_unittest.cc
+++ b/chromium/content/browser/fileapi/recursive_operation_delegate_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 "webkit/browser/fileapi/recursive_operation_delegate.h"
+#include "storage/browser/fileapi/recursive_operation_delegate.h"
#include <vector>
@@ -14,19 +14,19 @@
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "content/public/test/sandbox_file_system_test_helper.h"
+#include "storage/browser/fileapi/file_system_file_util.h"
+#include "storage/browser/fileapi/file_system_operation.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
-#include "webkit/browser/fileapi/file_system_operation.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-using fileapi::FileSystemContext;
-using fileapi::FileSystemOperationContext;
-using fileapi::FileSystemURL;
+using storage::FileSystemContext;
+using storage::FileSystemOperationContext;
+using storage::FileSystemURL;
namespace content {
namespace {
-class LoggingRecursiveOperation : public fileapi::RecursiveOperationDelegate {
+class LoggingRecursiveOperation : public storage::RecursiveOperationDelegate {
public:
struct LogEntry {
enum Type {
@@ -41,26 +41,21 @@ class LoggingRecursiveOperation : public fileapi::RecursiveOperationDelegate {
LoggingRecursiveOperation(FileSystemContext* file_system_context,
const FileSystemURL& root,
const StatusCallback& callback)
- : fileapi::RecursiveOperationDelegate(file_system_context),
+ : storage::RecursiveOperationDelegate(file_system_context),
root_(root),
callback_(callback),
- weak_factory_(this) {
- }
- virtual ~LoggingRecursiveOperation() {}
+ weak_factory_(this) {}
+ ~LoggingRecursiveOperation() override {}
const std::vector<LogEntry>& log_entries() const { return log_entries_; }
// RecursiveOperationDelegate overrides.
- virtual void Run() OVERRIDE {
- NOTREACHED();
- }
+ void Run() override { NOTREACHED(); }
- virtual void RunRecursively() OVERRIDE {
- StartRecursiveOperation(root_, callback_);
- }
+ void RunRecursively() override { StartRecursiveOperation(root_, callback_); }
- virtual void ProcessFile(const FileSystemURL& url,
- const StatusCallback& callback) OVERRIDE {
+ void ProcessFile(const FileSystemURL& url,
+ const StatusCallback& callback) override {
RecordLogEntry(LogEntry::PROCESS_FILE, url);
operation_runner()->GetMetadata(
url,
@@ -68,14 +63,14 @@ class LoggingRecursiveOperation : public fileapi::RecursiveOperationDelegate {
weak_factory_.GetWeakPtr(), callback));
}
- virtual void ProcessDirectory(const FileSystemURL& url,
- const StatusCallback& callback) OVERRIDE {
+ void ProcessDirectory(const FileSystemURL& url,
+ const StatusCallback& callback) override {
RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url);
callback.Run(base::File::FILE_OK);
}
- virtual void PostProcessDirectory(const FileSystemURL& url,
- const StatusCallback& callback) OVERRIDE {
+ void PostProcessDirectory(const FileSystemURL& url,
+ const StatusCallback& callback) override {
RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY, url);
callback.Run(base::File::FILE_OK);
}
@@ -117,7 +112,7 @@ void ReportStatus(base::File::Error* out_error,
// To test the Cancel() during operation, calls Cancel() of |operation|
// after |counter| times message posting.
-void CallCancelLater(fileapi::RecursiveOperationDelegate* operation,
+void CallCancelLater(storage::RecursiveOperationDelegate* operation,
int counter) {
if (counter > 0) {
base::MessageLoopProxy::current()->PostTask(
@@ -133,14 +128,12 @@ void CallCancelLater(fileapi::RecursiveOperationDelegate* operation,
class RecursiveOperationDelegateTest : public testing::Test {
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
EXPECT_TRUE(base_.CreateUniqueTempDir());
sandbox_file_system_.SetUp(base_.path().AppendASCII("filesystem"));
}
- virtual void TearDown() OVERRIDE {
- sandbox_file_system_.TearDown();
- }
+ void TearDown() override { sandbox_file_system_.TearDown(); }
scoped_ptr<FileSystemOperationContext> NewContext() {
FileSystemOperationContext* context =
@@ -150,7 +143,7 @@ class RecursiveOperationDelegateTest : public testing::Test {
return make_scoped_ptr(context);
}
- fileapi::FileSystemFileUtil* file_util() {
+ storage::FileSystemFileUtil* file_util() {
return sandbox_file_system_.file_util();
}
diff --git a/chromium/content/browser/fileapi/sandbox_database_test_helper.cc b/chromium/content/browser/fileapi/sandbox_database_test_helper.cc
index 3e295679590..205b653e370 100644
--- a/chromium/content/browser/fileapi/sandbox_database_test_helper.cc
+++ b/chromium/content/browser/fileapi/sandbox_database_test_helper.cc
@@ -8,14 +8,14 @@
#include <functional>
#include <vector>
-#include "base/file_util.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
#include "base/stl_util.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/common/fileapi/file_system_util.h"
-using fileapi::FilePathToString;
+using storage::FilePathToString;
namespace content {
diff --git a/chromium/content/browser/fileapi/sandbox_directory_database_unittest.cc b/chromium/content/browser/fileapi/sandbox_directory_database_unittest.cc
index 6bc3c5669fa..dcb74a272c2 100644
--- a/chromium/content/browser/fileapi/sandbox_directory_database_unittest.cc
+++ b/chromium/content/browser/fileapi/sandbox_directory_database_unittest.cc
@@ -2,26 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/sandbox_directory_database.h"
+#include "storage/browser/fileapi/sandbox_directory_database.h"
#include <math.h>
#include <limits>
-#include "base/file_util.h"
#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "content/browser/fileapi/sandbox_database_test_helper.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
-#include "webkit/common/fileapi/file_system_util.h"
#define FPL(x) FILE_PATH_LITERAL(x)
-using fileapi::FilePathToString;
-using fileapi::SandboxDirectoryDatabase;
+using storage::FilePathToString;
+using storage::SandboxDirectoryDatabase;
namespace content {
diff --git a/chromium/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc b/chromium/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
index 935f6ce2fe4..1b5b19b122c 100644
--- a/chromium/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
+++ b/chromium/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
+#include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
#include "base/basictypes.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "content/public/test/test_file_system_options.h"
+#include "storage/browser/fileapi/file_system_url.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-using fileapi::FileSystemURL;
+using storage::FileSystemURL;
namespace content {
@@ -23,8 +23,9 @@ namespace {
FileSystemURL CreateFileSystemURL(const char* path) {
const GURL kOrigin("http://foo/");
- return fileapi::FileSystemURL::CreateForTest(
- kOrigin, fileapi::kFileSystemTypeTemporary,
+ return storage::FileSystemURL::CreateForTest(
+ kOrigin,
+ storage::kFileSystemTypeTemporary,
base::FilePath::FromUTF8Unsafe(path));
}
@@ -32,9 +33,9 @@ FileSystemURL CreateFileSystemURL(const char* path) {
class SandboxFileSystemBackendDelegateTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
- delegate_.reset(new fileapi::SandboxFileSystemBackendDelegate(
+ delegate_.reset(new storage::SandboxFileSystemBackendDelegate(
NULL /* quota_manager_proxy */,
base::MessageLoopProxy::current().get(),
data_dir_.path(),
@@ -48,7 +49,7 @@ class SandboxFileSystemBackendDelegateTest : public testing::Test {
base::ScopedTempDir data_dir_;
base::MessageLoop message_loop_;
- scoped_ptr<fileapi::SandboxFileSystemBackendDelegate> delegate_;
+ scoped_ptr<storage::SandboxFileSystemBackendDelegate> delegate_;
};
TEST_F(SandboxFileSystemBackendDelegateTest, IsAccessValid) {
@@ -60,9 +61,9 @@ TEST_F(SandboxFileSystemBackendDelegateTest, IsAccessValid) {
// Access from non-allowed scheme should be disallowed.
EXPECT_FALSE(IsAccessValid(
- FileSystemURL::CreateForTest(
- GURL("unknown://bar"), fileapi::kFileSystemTypeTemporary,
- base::FilePath::FromUTF8Unsafe("foo"))));
+ FileSystemURL::CreateForTest(GURL("unknown://bar"),
+ storage::kFileSystemTypeTemporary,
+ base::FilePath::FromUTF8Unsafe("foo"))));
// Access with restricted name should be disallowed.
EXPECT_FALSE(IsAccessValid(CreateFileSystemURL(".")));
diff --git a/chromium/content/browser/fileapi/sandbox_file_system_backend_unittest.cc b/chromium/content/browser/fileapi/sandbox_file_system_backend_unittest.cc
index eda34612be8..efa7259fd44 100644
--- a/chromium/content/browser/fileapi/sandbox_file_system_backend_unittest.cc
+++ b/chromium/content/browser/fileapi/sandbox_file_system_backend_unittest.cc
@@ -2,27 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/sandbox_file_system_backend.h"
+#include "storage/browser/fileapi/sandbox_file_system_backend.h"
#include <set>
#include "base/basictypes.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "content/public/test/test_file_system_options.h"
+#include "storage/browser/fileapi/file_system_backend.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_backend.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
-#include "webkit/common/fileapi/file_system_util.h"
-using fileapi::FileSystemURL;
-using fileapi::SandboxFileSystemBackend;
-using fileapi::SandboxFileSystemBackendDelegate;
+using storage::FileSystemURL;
+using storage::SandboxFileSystemBackend;
+using storage::SandboxFileSystemBackendDelegate;
// PS stands for path separator.
#if defined(FILE_PATH_USES_WIN_SEPARATORS)
@@ -36,38 +36,28 @@ namespace content {
namespace {
const struct RootPathTest {
- fileapi::FileSystemType type;
+ storage::FileSystemType type;
const char* origin_url;
const char* expected_path;
} kRootPathTestCases[] = {
- { fileapi::kFileSystemTypeTemporary, "http://foo:1/",
- "000" PS "t" },
- { fileapi::kFileSystemTypePersistent, "http://foo:1/",
- "000" PS "p" },
- { fileapi::kFileSystemTypeTemporary, "http://bar.com/",
- "001" PS "t" },
- { fileapi::kFileSystemTypePersistent, "http://bar.com/",
- "001" PS "p" },
- { fileapi::kFileSystemTypeTemporary, "https://foo:2/",
- "002" PS "t" },
- { fileapi::kFileSystemTypePersistent, "https://foo:2/",
- "002" PS "p" },
- { fileapi::kFileSystemTypeTemporary, "https://bar.com/",
- "003" PS "t" },
- { fileapi::kFileSystemTypePersistent, "https://bar.com/",
- "003" PS "p" },
+ {storage::kFileSystemTypeTemporary, "http://foo:1/", "000" PS "t"},
+ {storage::kFileSystemTypePersistent, "http://foo:1/", "000" PS "p"},
+ {storage::kFileSystemTypeTemporary, "http://bar.com/", "001" PS "t"},
+ {storage::kFileSystemTypePersistent, "http://bar.com/", "001" PS "p"},
+ {storage::kFileSystemTypeTemporary, "https://foo:2/", "002" PS "t"},
+ {storage::kFileSystemTypePersistent, "https://foo:2/", "002" PS "p"},
+ {storage::kFileSystemTypeTemporary, "https://bar.com/", "003" PS "t"},
+ {storage::kFileSystemTypePersistent, "https://bar.com/", "003" PS "p"},
};
const struct RootPathFileURITest {
- fileapi::FileSystemType type;
+ storage::FileSystemType type;
const char* origin_url;
const char* expected_path;
const char* virtual_path;
} kRootPathFileURITestCases[] = {
- { fileapi::kFileSystemTypeTemporary, "file:///",
- "000" PS "t", NULL },
- { fileapi::kFileSystemTypePersistent, "file:///",
- "000" PS "p", NULL },
+ {storage::kFileSystemTypeTemporary, "file:///", "000" PS "t", NULL},
+ {storage::kFileSystemTypePersistent, "file:///", "000" PS "p", NULL},
};
void DidOpenFileSystem(base::File::Error* error_out,
@@ -81,12 +71,12 @@ void DidOpenFileSystem(base::File::Error* error_out,
class SandboxFileSystemBackendTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
SetUpNewDelegate(CreateAllowFileAccessOptions());
}
- void SetUpNewDelegate(const fileapi::FileSystemOptions& options) {
+ void SetUpNewDelegate(const storage::FileSystemOptions& options) {
delegate_.reset(new SandboxFileSystemBackendDelegate(
NULL /* quota_manager_proxy */,
base::MessageLoopProxy::current().get(),
@@ -95,18 +85,18 @@ class SandboxFileSystemBackendTest : public testing::Test {
options));
}
- void SetUpNewBackend(const fileapi::FileSystemOptions& options) {
+ void SetUpNewBackend(const storage::FileSystemOptions& options) {
SetUpNewDelegate(options);
backend_.reset(new SandboxFileSystemBackend(delegate_.get()));
}
- fileapi::SandboxFileSystemBackendDelegate::OriginEnumerator*
+ storage::SandboxFileSystemBackendDelegate::OriginEnumerator*
CreateOriginEnumerator() const {
return backend_->CreateOriginEnumerator();
}
void CreateOriginTypeDirectory(const GURL& origin,
- fileapi::FileSystemType type) {
+ storage::FileSystemType type) {
base::FilePath target = delegate_->
GetBaseDirectoryForOriginAndType(origin, type, true);
ASSERT_TRUE(!target.empty());
@@ -114,8 +104,8 @@ class SandboxFileSystemBackendTest : public testing::Test {
}
bool GetRootPath(const GURL& origin_url,
- fileapi::FileSystemType type,
- fileapi::OpenFileSystemMode mode,
+ storage::FileSystemType type,
+ storage::OpenFileSystemMode mode,
base::FilePath* root_path) {
base::File::Error error = base::File::FILE_OK;
backend_->ResolveURL(
@@ -140,8 +130,8 @@ class SandboxFileSystemBackendTest : public testing::Test {
base::ScopedTempDir data_dir_;
base::MessageLoop message_loop_;
- scoped_ptr<fileapi::SandboxFileSystemBackendDelegate> delegate_;
- scoped_ptr<fileapi::SandboxFileSystemBackend> backend_;
+ scoped_ptr<storage::SandboxFileSystemBackendDelegate> delegate_;
+ scoped_ptr<storage::SandboxFileSystemBackend> backend_;
};
TEST_F(SandboxFileSystemBackendTest, Empty) {
@@ -165,17 +155,17 @@ TEST_F(SandboxFileSystemBackendTest, EnumerateOrigins) {
"http://www.foo.com:8080/",
"http://www.foo.com:80/",
};
- size_t temporary_size = ARRAYSIZE_UNSAFE(temporary_origins);
- size_t persistent_size = ARRAYSIZE_UNSAFE(persistent_origins);
+ size_t temporary_size = arraysize(temporary_origins);
+ size_t persistent_size = arraysize(persistent_origins);
std::set<GURL> temporary_set, persistent_set;
for (size_t i = 0; i < temporary_size; ++i) {
CreateOriginTypeDirectory(GURL(temporary_origins[i]),
- fileapi::kFileSystemTypeTemporary);
+ storage::kFileSystemTypeTemporary);
temporary_set.insert(GURL(temporary_origins[i]));
}
for (size_t i = 0; i < persistent_size; ++i) {
CreateOriginTypeDirectory(GURL(persistent_origins[i]),
- fileapi::kFileSystemTypePersistent);
+ storage::kFileSystemTypePersistent);
persistent_set.insert(GURL(persistent_origins[i]));
}
@@ -186,11 +176,11 @@ TEST_F(SandboxFileSystemBackendTest, EnumerateOrigins) {
GURL current;
while (!(current = enumerator->Next()).is_empty()) {
SCOPED_TRACE(testing::Message() << "EnumerateOrigin " << current.spec());
- if (enumerator->HasFileSystemType(fileapi::kFileSystemTypeTemporary)) {
+ if (enumerator->HasFileSystemType(storage::kFileSystemTypeTemporary)) {
ASSERT_TRUE(temporary_set.find(current) != temporary_set.end());
++temporary_actual_size;
}
- if (enumerator->HasFileSystemType(fileapi::kFileSystemTypePersistent)) {
+ if (enumerator->HasFileSystemType(storage::kFileSystemTypePersistent)) {
ASSERT_TRUE(persistent_set.find(current) != persistent_set.end());
++persistent_actual_size;
}
@@ -201,19 +191,18 @@ TEST_F(SandboxFileSystemBackendTest, EnumerateOrigins) {
}
TEST_F(SandboxFileSystemBackendTest, GetRootPathCreateAndExamine) {
- std::vector<base::FilePath> returned_root_path(
- ARRAYSIZE_UNSAFE(kRootPathTestCases));
+ std::vector<base::FilePath> returned_root_path(arraysize(kRootPathTestCases));
SetUpNewBackend(CreateAllowFileAccessOptions());
// Create a new root directory.
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kRootPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPath (create) #" << i << " "
<< kRootPathTestCases[i].expected_path);
base::FilePath root_path;
EXPECT_TRUE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
kRootPathTestCases[i].type,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
&root_path));
base::FilePath expected = file_system_path().AppendASCII(
@@ -226,14 +215,14 @@ TEST_F(SandboxFileSystemBackendTest, GetRootPathCreateAndExamine) {
// Get the root directory with create=false and see if we get the
// same directory.
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kRootPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPath (get) #" << i << " "
<< kRootPathTestCases[i].expected_path);
base::FilePath root_path;
EXPECT_TRUE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
kRootPathTestCases[i].type,
- fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
&root_path));
ASSERT_TRUE(returned_root_path.size() > i);
EXPECT_EQ(returned_root_path[i].value(), root_path.value());
@@ -242,21 +231,22 @@ TEST_F(SandboxFileSystemBackendTest, GetRootPathCreateAndExamine) {
TEST_F(SandboxFileSystemBackendTest,
GetRootPathCreateAndExamineWithNewBackend) {
- std::vector<base::FilePath> returned_root_path(
- ARRAYSIZE_UNSAFE(kRootPathTestCases));
+ std::vector<base::FilePath> returned_root_path(arraysize(kRootPathTestCases));
SetUpNewBackend(CreateAllowFileAccessOptions());
GURL origin_url("http://foo.com:1/");
base::FilePath root_path1;
- EXPECT_TRUE(GetRootPath(origin_url, fileapi::kFileSystemTypeTemporary,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ EXPECT_TRUE(GetRootPath(origin_url,
+ storage::kFileSystemTypeTemporary,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
&root_path1));
SetUpNewBackend(CreateDisallowFileAccessOptions());
base::FilePath root_path2;
- EXPECT_TRUE(GetRootPath(origin_url, fileapi::kFileSystemTypeTemporary,
- fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
+ EXPECT_TRUE(GetRootPath(origin_url,
+ storage::kFileSystemTypeTemporary,
+ storage::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
&root_path2));
EXPECT_EQ(root_path1.value(), root_path2.value());
@@ -266,12 +256,12 @@ TEST_F(SandboxFileSystemBackendTest, GetRootPathGetWithoutCreate) {
SetUpNewBackend(CreateDisallowFileAccessOptions());
// Try to get a root directory without creating.
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kRootPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPath (create=false) #" << i << " "
<< kRootPathTestCases[i].expected_path);
EXPECT_FALSE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
kRootPathTestCases[i].type,
- fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
NULL));
}
}
@@ -280,39 +270,37 @@ TEST_F(SandboxFileSystemBackendTest, GetRootPathInIncognito) {
SetUpNewBackend(CreateIncognitoFileSystemOptions());
// Try to get a root directory.
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kRootPathTestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPath (incognito) #" << i << " "
<< kRootPathTestCases[i].expected_path);
- EXPECT_FALSE(
- GetRootPath(GURL(kRootPathTestCases[i].origin_url),
- kRootPathTestCases[i].type,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
- NULL));
+ EXPECT_FALSE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
+ kRootPathTestCases[i].type,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ NULL));
}
}
TEST_F(SandboxFileSystemBackendTest, GetRootPathFileURI) {
SetUpNewBackend(CreateDisallowFileAccessOptions());
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathFileURITestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kRootPathFileURITestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPathFileURI (disallow) #"
<< i << " " << kRootPathFileURITestCases[i].expected_path);
- EXPECT_FALSE(
- GetRootPath(GURL(kRootPathFileURITestCases[i].origin_url),
- kRootPathFileURITestCases[i].type,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
- NULL));
+ EXPECT_FALSE(GetRootPath(GURL(kRootPathFileURITestCases[i].origin_url),
+ kRootPathFileURITestCases[i].type,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ NULL));
}
}
TEST_F(SandboxFileSystemBackendTest, GetRootPathFileURIWithAllowFlag) {
SetUpNewBackend(CreateAllowFileAccessOptions());
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathFileURITestCases); ++i) {
+ for (size_t i = 0; i < arraysize(kRootPathFileURITestCases); ++i) {
SCOPED_TRACE(testing::Message() << "RootPathFileURI (allow) #"
<< i << " " << kRootPathFileURITestCases[i].expected_path);
base::FilePath root_path;
EXPECT_TRUE(GetRootPath(GURL(kRootPathFileURITestCases[i].origin_url),
kRootPathFileURITestCases[i].type,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
&root_path));
base::FilePath expected = file_system_path().AppendASCII(
kRootPathFileURITestCases[i].expected_path);
diff --git a/chromium/content/browser/fileapi/sandbox_isolated_origin_database_unittest.cc b/chromium/content/browser/fileapi/sandbox_isolated_origin_database_unittest.cc
index fbf6a5eb25d..5f7f55f8005 100644
--- a/chromium/content/browser/fileapi/sandbox_isolated_origin_database_unittest.cc
+++ b/chromium/content/browser/fileapi/sandbox_isolated_origin_database_unittest.cc
@@ -3,13 +3,13 @@
// found in the LICENSE file.
#include "base/basictypes.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "storage/browser/fileapi/sandbox_isolated_origin_database.h"
+#include "storage/browser/fileapi/sandbox_origin_database.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/sandbox_isolated_origin_database.h"
-#include "webkit/browser/fileapi/sandbox_origin_database.h"
-using fileapi::SandboxIsolatedOriginDatabase;
+using storage::SandboxIsolatedOriginDatabase;
namespace content {
diff --git a/chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc b/chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc
index cda5b77d9a8..44dad2032d7 100644
--- a/chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc
+++ b/chromium/content/browser/fileapi/sandbox_origin_database_unittest.cc
@@ -8,19 +8,19 @@
#include <string>
#include <vector>
-#include "base/file_util.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/stl_util.h"
#include "content/browser/fileapi/sandbox_database_test_helper.h"
+#include "storage/browser/fileapi/sandbox_origin_database.h"
+#include "storage/common/fileapi/file_system_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/leveldatabase/src/db/filename.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
-#include "webkit/browser/fileapi/sandbox_origin_database.h"
-#include "webkit/common/fileapi/file_system_util.h"
-using fileapi::SandboxOriginDatabase;
+using storage::SandboxOriginDatabase;
namespace content {
diff --git a/chromium/content/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc b/chromium/content/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc
index e81dc7d18a0..0fb01153a57 100644
--- a/chromium/content/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc
+++ b/chromium/content/browser/fileapi/sandbox_prioritized_origin_database_unittest.cc
@@ -3,15 +3,15 @@
// found in the LICENSE file.
#include "base/basictypes.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "storage/browser/fileapi/sandbox_origin_database.h"
+#include "storage/browser/fileapi/sandbox_prioritized_origin_database.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/sandbox_origin_database.h"
-#include "webkit/browser/fileapi/sandbox_prioritized_origin_database.h"
-using fileapi::SandboxOriginDatabase;
-using fileapi::SandboxOriginDatabaseInterface;
-using fileapi::SandboxPrioritizedOriginDatabase;
+using storage::SandboxOriginDatabase;
+using storage::SandboxOriginDatabaseInterface;
+using storage::SandboxPrioritizedOriginDatabase;
namespace content {
diff --git a/chromium/content/browser/fileapi/timed_task_helper_unittest.cc b/chromium/content/browser/fileapi/timed_task_helper_unittest.cc
index 59e465c98c5..5a6ac8df0e5 100644
--- a/chromium/content/browser/fileapi/timed_task_helper_unittest.cc
+++ b/chromium/content/browser/fileapi/timed_task_helper_unittest.cc
@@ -9,10 +9,10 @@
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "base/time/time.h"
+#include "storage/browser/fileapi/timed_task_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/timed_task_helper.h"
-using fileapi::TimedTaskHelper;
+using storage::TimedTaskHelper;
namespace content {
diff --git a/chromium/content/browser/fileapi/transient_file_util_unittest.cc b/chromium/content/browser/fileapi/transient_file_util_unittest.cc
index 96df84f4fcf..faf20caa4c5 100644
--- a/chromium/content/browser/fileapi/transient_file_util_unittest.cc
+++ b/chromium/content/browser/fileapi/transient_file_util_unittest.cc
@@ -3,37 +3,37 @@
// found in the LICENSE file.
#include "base/basictypes.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "content/public/test/test_file_system_context.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/browser/fileapi/transient_file_util.h"
+#include "storage/common/blob/scoped_file.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/browser/fileapi/transient_file_util.h"
-#include "webkit/common/blob/scoped_file.h"
-using fileapi::FileSystemURL;
+using storage::FileSystemURL;
namespace content {
class TransientFileUtilTest : public testing::Test {
public:
TransientFileUtilTest() {}
- virtual ~TransientFileUtilTest() {}
+ ~TransientFileUtilTest() override {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
file_system_context_ = CreateFileSystemContextForTesting(
NULL, base::FilePath(FILE_PATH_LITERAL("dummy")));
- transient_file_util_.reset(new fileapi::TransientFileUtil);
+ transient_file_util_.reset(new storage::TransientFileUtil);
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
file_system_context_ = NULL;
base::RunLoop().RunUntilIdle();
}
@@ -42,11 +42,11 @@ class TransientFileUtilTest : public testing::Test {
FileSystemURL* file_url,
base::FilePath* file_path) {
EXPECT_TRUE(base::CreateTemporaryFileInDir(data_dir_.path(), file_path));
- fileapi::IsolatedContext* isolated_context =
- fileapi::IsolatedContext::GetInstance();
+ storage::IsolatedContext* isolated_context =
+ storage::IsolatedContext::GetInstance();
std::string name = "tmp";
std::string fsid = isolated_context->RegisterFileSystemForPath(
- fileapi::kFileSystemTypeForTransientFile,
+ storage::kFileSystemTypeForTransientFile,
std::string(),
*file_path,
&name);
@@ -54,25 +54,23 @@ class TransientFileUtilTest : public testing::Test {
base::FilePath virtual_path = isolated_context->CreateVirtualRootPath(
fsid).AppendASCII(name);
*file_url = file_system_context_->CreateCrackedFileSystemURL(
- GURL("http://foo"),
- fileapi::kFileSystemTypeIsolated,
- virtual_path);
+ GURL("http://foo"), storage::kFileSystemTypeIsolated, virtual_path);
}
- scoped_ptr<fileapi::FileSystemOperationContext> NewOperationContext() {
+ scoped_ptr<storage::FileSystemOperationContext> NewOperationContext() {
return make_scoped_ptr(
- new fileapi::FileSystemOperationContext(file_system_context_.get()));
+ new storage::FileSystemOperationContext(file_system_context_.get()));
}
- fileapi::FileSystemFileUtil* file_util() {
+ storage::FileSystemFileUtil* file_util() {
return transient_file_util_.get();
}
private:
base::MessageLoop message_loop_;
base::ScopedTempDir data_dir_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
- scoped_ptr<fileapi::TransientFileUtil> transient_file_util_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
+ scoped_ptr<storage::TransientFileUtil> transient_file_util_;
DISALLOW_COPY_AND_ASSIGN(TransientFileUtilTest);
};
@@ -94,12 +92,8 @@ TEST_F(TransientFileUtilTest, TransientFile) {
// Create a snapshot file.
{
- webkit_blob::ScopedFile scoped_file =
- file_util()->CreateSnapshotFile(NewOperationContext().get(),
- temp_url,
- &error,
- &file_info,
- &path);
+ storage::ScopedFile scoped_file = file_util()->CreateSnapshotFile(
+ NewOperationContext().get(), temp_url, &error, &file_info, &path);
ASSERT_EQ(base::File::FILE_OK, error);
ASSERT_EQ(temp_path, path);
ASSERT_FALSE(file_info.is_directory);
diff --git a/chromium/content/browser/fileapi/upload_file_system_file_element_reader.cc b/chromium/content/browser/fileapi/upload_file_system_file_element_reader.cc
index 9e6a288758e..a6a99ca0c75 100644
--- a/chromium/content/browser/fileapi/upload_file_system_file_element_reader.cc
+++ b/chromium/content/browser/fileapi/upload_file_system_file_element_reader.cc
@@ -5,17 +5,19 @@
#include "content/browser/fileapi/upload_file_system_file_element_reader.h"
#include <algorithm>
+#include <limits>
#include "base/bind.h"
+#include "base/numerics/safe_conversions.h"
#include "net/base/net_errors.h"
-#include "webkit/browser/blob/file_stream_reader.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_url.h"
+#include "storage/browser/blob/file_stream_reader.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_url.h"
namespace content {
UploadFileSystemFileElementReader::UploadFileSystemFileElementReader(
- fileapi::FileSystemContext* file_system_context,
+ storage::FileSystemContext* file_system_context,
const GURL& url,
uint64 range_offset,
uint64 range_length,
@@ -41,11 +43,13 @@ int UploadFileSystemFileElementReader::Init(
position_ = 0;
// Initialize the stream reader and the length.
- stream_reader_ =
- file_system_context_->CreateFileStreamReader(
- file_system_context_->CrackURL(url_),
- range_offset_,
- expected_modification_time_);
+ stream_reader_ = file_system_context_->CreateFileStreamReader(
+ file_system_context_->CrackURL(url_),
+ range_offset_,
+ range_length_ == std::numeric_limits<uint64>::max()
+ ? storage::kMaximumLength
+ : base::checked_cast<int64>(range_length_),
+ expected_modification_time_);
DCHECK(stream_reader_);
const int64 result = stream_reader_->GetLength(
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 1b33489d1b2..bc2a6f7a71a 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
@@ -11,11 +11,11 @@
#include "net/base/upload_element_reader.h"
#include "url/gurl.h"
-namespace webkit_blob {
+namespace storage {
class FileStreamReader;
}
-namespace fileapi {
+namespace storage {
class FileSystemContext;
}
@@ -26,32 +26,32 @@ class CONTENT_EXPORT UploadFileSystemFileElementReader :
NON_EXPORTED_BASE(public net::UploadElementReader) {
public:
UploadFileSystemFileElementReader(
- fileapi::FileSystemContext* file_system_context,
+ storage::FileSystemContext* file_system_context,
const GURL& url,
uint64 range_offset,
uint64 range_length,
const base::Time& expected_modification_time);
- virtual ~UploadFileSystemFileElementReader();
+ ~UploadFileSystemFileElementReader() override;
// UploadElementReader overrides:
- virtual int Init(const net::CompletionCallback& callback) OVERRIDE;
- virtual uint64 GetContentLength() const OVERRIDE;
- virtual uint64 BytesRemaining() const OVERRIDE;
- virtual int Read(net::IOBuffer* buf,
- int buf_length,
- const net::CompletionCallback& callback) OVERRIDE;
+ int Init(const net::CompletionCallback& callback) override;
+ uint64 GetContentLength() const override;
+ uint64 BytesRemaining() const override;
+ int Read(net::IOBuffer* buf,
+ int buf_length,
+ const net::CompletionCallback& callback) override;
private:
void OnGetLength(const net::CompletionCallback& callback, int64 result);
void OnRead(const net::CompletionCallback& callback, int result);
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
const GURL url_;
const uint64 range_offset_;
const uint64 range_length_;
const base::Time expected_modification_time_;
- scoped_ptr<webkit_blob::FileStreamReader> stream_reader_;
+ scoped_ptr<storage::FileStreamReader> stream_reader_;
uint64 stream_length_;
uint64 position_;
diff --git a/chromium/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc b/chromium/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
index 641b96852ca..7e16a725039 100644
--- a/chromium/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
+++ b/chromium/content/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
@@ -11,24 +11,24 @@
#include "content/public/test/test_file_system_context.h"
#include "net/base/io_buffer.h"
#include "net/base/test_completion_callback.h"
+#include "storage/browser/fileapi/file_system_backend.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_context.h"
+#include "storage/browser/fileapi/file_system_url.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/file_system_backend.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/file_system_url.h"
using content::AsyncFileTestHelper;
-using fileapi::FileSystemContext;
-using fileapi::FileSystemType;
-using fileapi::FileSystemURL;
+using storage::FileSystemContext;
+using storage::FileSystemType;
+using storage::FileSystemURL;
namespace content {
namespace {
const char kFileSystemURLOrigin[] = "http://remote";
-const fileapi::FileSystemType kFileSystemType =
- fileapi::kFileSystemTypeTemporary;
+const storage::FileSystemType kFileSystemType =
+ storage::kFileSystemTypeTemporary;
} // namespace
@@ -36,7 +36,7 @@ class UploadFileSystemFileElementReaderTest : public testing::Test {
public:
UploadFileSystemFileElementReaderTest() {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_system_context_ = CreateFileSystemContextForTesting(
@@ -45,7 +45,7 @@ class UploadFileSystemFileElementReaderTest : public testing::Test {
file_system_context_->OpenFileSystem(
GURL(kFileSystemURLOrigin),
kFileSystemType,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&UploadFileSystemFileElementReaderTest::OnOpenFileSystem,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
@@ -74,7 +74,7 @@ class UploadFileSystemFileElementReaderTest : public testing::Test {
EXPECT_FALSE(reader_->IsInMemory());
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
reader_.reset();
base::RunLoop().RunUntilIdle();
}
@@ -88,7 +88,7 @@ class UploadFileSystemFileElementReaderTest : public testing::Test {
const char* buf,
int buf_size,
base::Time* modification_time) {
- fileapi::FileSystemURL url =
+ storage::FileSystemURL url =
file_system_context_->CreateCrackedFileSystemURL(
GURL(kFileSystemURLOrigin),
kFileSystemType,
@@ -96,12 +96,12 @@ class UploadFileSystemFileElementReaderTest : public testing::Test {
ASSERT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::CreateFileWithData(
- file_system_context_, url, buf, buf_size));
+ file_system_context_.get(), url, buf, buf_size));
base::File::Info file_info;
ASSERT_EQ(base::File::FILE_OK,
AsyncFileTestHelper::GetMetadata(
- file_system_context_, url, &file_info));
+ file_system_context_.get(), url, &file_info));
*modification_time = file_info.last_modified;
}
diff --git a/chromium/content/browser/frame_host/OWNERS b/chromium/content/browser/frame_host/OWNERS
deleted file mode 100644
index df8aeac9541..00000000000
--- a/chromium/content/browser/frame_host/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-nasko@chromium.org
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 7701f63d7ea..43efd017fe1 100644
--- a/chromium/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/chromium/content/browser/frame_host/cross_process_frame_connector.cc
@@ -30,7 +30,6 @@ bool CrossProcessFrameConnector::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(CrossProcessFrameConnector, msg)
- IPC_MESSAGE_HANDLER(FrameHostMsg_BuffersSwappedACK, OnBuffersSwappedACK)
IPC_MESSAGE_HANDLER(FrameHostMsg_CompositorFrameSwappedACK,
OnCompositorFrameSwappedACK)
IPC_MESSAGE_HANDLER(FrameHostMsg_ReclaimCompositorResources,
@@ -65,20 +64,6 @@ void CrossProcessFrameConnector::RenderProcessGone() {
frame_proxy_in_parent_renderer_->GetRoutingID()));
}
-void CrossProcessFrameConnector::ChildFrameBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& gpu_params,
- int gpu_host_id) {
-
- FrameMsg_BuffersSwapped_Params params;
- params.size = gpu_params.size;
- params.mailbox = gpu_params.mailbox;
- params.gpu_route_id = gpu_params.route_id;
- params.gpu_host_id = gpu_host_id;
-
- frame_proxy_in_parent_renderer_->Send(new FrameMsg_BuffersSwapped(
- frame_proxy_in_parent_renderer_->GetRoutingID(), params));
-}
-
void CrossProcessFrameConnector::ChildFrameCompositorFrameSwapped(
uint32 output_surface_id,
int host_id,
@@ -93,18 +78,6 @@ void CrossProcessFrameConnector::ChildFrameCompositorFrameSwapped(
frame_proxy_in_parent_renderer_->GetRoutingID(), params));
}
-void CrossProcessFrameConnector::OnBuffersSwappedACK(
- const FrameHostMsg_BuffersSwappedACK_Params& params) {
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.mailbox = params.mailbox;
- ack_params.sync_point = params.sync_point;
- RenderWidgetHostImpl::AcknowledgeBufferPresent(params.gpu_route_id,
- params.gpu_host_id,
- ack_params);
-
- // TODO(kenrb): Special case stuff for Win + Mac.
-}
-
void CrossProcessFrameConnector::OnCompositorFrameSwappedACK(
const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
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 82452243f5b..dffeba2675d 100644
--- a/chromium/content/browser/frame_host/cross_process_frame_connector.h
+++ b/chromium/content/browser/frame_host/cross_process_frame_connector.h
@@ -16,10 +16,8 @@ namespace IPC {
class Message;
}
-struct FrameHostMsg_BuffersSwappedACK_Params;
struct FrameHostMsg_CompositorFrameSwappedACK_Params;
struct FrameHostMsg_ReclaimCompositorResources_Params;
-struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
namespace content {
class RenderFrameProxyHost;
@@ -78,13 +76,6 @@ class CrossProcessFrameConnector {
void RenderProcessGone();
- // 'Platform' functionality exposed to RenderWidgetHostViewChildFrame.
- // These methods can forward messages to the child frame proxy in the parent
- // frame's renderer or attempt to handle them within the browser process.
- void ChildFrameBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id);
-
void ChildFrameCompositorFrameSwapped(uint32 output_surface_id,
int host_id,
int route_id,
@@ -94,8 +85,6 @@ class CrossProcessFrameConnector {
private:
// Handlers for messages received from the parent frame.
- void OnBuffersSwappedACK(
- const FrameHostMsg_BuffersSwappedACK_Params& params);
void OnCompositorFrameSwappedACK(
const FrameHostMsg_CompositorFrameSwappedACK_Params& params);
void OnReclaimCompositorResources(
diff --git a/chromium/content/browser/frame_host/cross_site_transferring_request.h b/chromium/content/browser/frame_host/cross_site_transferring_request.h
index a78684be77b..0d696a3d69a 100644
--- a/chromium/content/browser/frame_host/cross_site_transferring_request.h
+++ b/chromium/content/browser/frame_host/cross_site_transferring_request.h
@@ -26,6 +26,8 @@ class CONTENT_EXPORT CrossSiteTransferringRequest {
// control of it.
void ReleaseRequest();
+ GlobalRequestID request_id() const { return global_request_id_; }
+
private:
// No need for a weak pointer here - nothing should have ownership of the
// cross site request until after |this| is deleted, or ReleaseRequest is
diff --git a/chromium/content/browser/frame_host/debug_urls.cc b/chromium/content/browser/frame_host/debug_urls.cc
index ae454ae64a7..0b2ca863388 100644
--- a/chromium/content/browser/frame_host/debug_urls.cc
+++ b/chromium/content/browser/frame_host/debug_urls.cc
@@ -6,17 +6,22 @@
#include <vector>
+#include "base/command_line.h"
#include "base/debug/asan_invalid_access.h"
#include "base/debug/profiler.h"
#include "base/strings/utf_string_conversions.h"
+#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
-#include "content/browser/ppapi_plugin_process_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/url_constants.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "url/gurl.h"
+#if defined(ENABLE_PLUGINS)
+#include "content/browser/ppapi_plugin_process_host.h"
+#endif
+
namespace content {
namespace {
@@ -105,18 +110,22 @@ bool HandleAsanDebugURL(const GURL& url) {
} // namespace
-bool HandleDebugURL(const GURL& url, PageTransition transition) {
- // Ensure that the user explicitly navigated to this URL.
- if (!(transition & PAGE_TRANSITION_FROM_ADDRESS_BAR))
- return false;
+bool HandleDebugURL(const GURL& url, ui::PageTransition transition) {
+ // Ensure that the user explicitly navigated to this URL, unless
+ // kEnableGpuBenchmarking is enabled by Telemetry.
+ bool is_telemetry_navigation =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ cc::switches::kEnableGpuBenchmarking) &&
+ (transition & ui::PAGE_TRANSITION_TYPED);
- // NOTE: when you add handling of any URLs to this function, also
- // update IsDebugURL, below.
+ if (!(transition & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) &&
+ !is_telemetry_navigation)
+ return false;
if (IsAsanDebugURL(url))
return HandleAsanDebugURL(url);
- if (url.host() == kChromeUIBrowserCrashHost) {
+ if (url == GURL(kChromeUIBrowserCrashURL)) {
// Induce an intentional crash in the browser process.
CHECK(false);
return true;
@@ -153,19 +162,6 @@ bool HandleDebugURL(const GURL& url, PageTransition transition) {
return false;
}
-bool IsDebugURL(const GURL& url) {
- // NOTE: when you add any URLs to this list, also update
- // HandleDebugURL, above.
- return IsRendererDebugURL(url) || IsAsanDebugURL(url) ||
- (url.is_valid() &&
- (url.host() == kChromeUIBrowserCrashHost ||
- url == GURL(kChromeUIGpuCleanURL) ||
- url == GURL(kChromeUIGpuCrashURL) ||
- url == GURL(kChromeUIGpuHangURL) ||
- url == GURL(kChromeUIPpapiFlashCrashURL) ||
- url == GURL(kChromeUIPpapiFlashHangURL)));
-}
-
bool IsRendererDebugURL(const GURL& url) {
if (!url.is_valid())
return false;
diff --git a/chromium/content/browser/frame_host/debug_urls.h b/chromium/content/browser/frame_host/debug_urls.h
index 2c871948ef2..413cd0f3387 100644
--- a/chromium/content/browser/frame_host/debug_urls.h
+++ b/chromium/content/browser/frame_host/debug_urls.h
@@ -5,7 +5,7 @@
#ifndef CONTENT_BROWSER_FRAME_HOST_DEBUG_URLS_H_
#define CONTENT_BROWSER_FRAME_HOST_DEBUG_URLS_H_
-#include "content/public/common/page_transition_types.h"
+#include "ui/base/page_transition_types.h"
class GURL;
@@ -13,12 +13,7 @@ namespace content {
// Checks if the given url is a url used for debugging purposes, and if so
// handles it and returns true.
-bool HandleDebugURL(const GURL& url, PageTransition transition);
-
-// Returns whether this given url is a debugging url. It is a superset
-// of IsRendererDebugURL, below, and debugging urls that are handled
-// in the browser process.
-bool IsDebugURL(const GURL& url);
+bool HandleDebugURL(const GURL& url, ui::PageTransition transition);
// Returns whether the given url is either a debugging url handled in the
// renderer process, such as one that crashes or hangs the renderer, or a
diff --git a/chromium/content/browser/frame_host/frame_accessibility.cc b/chromium/content/browser/frame_host/frame_accessibility.cc
new file mode 100644
index 00000000000..aa2c32667bf
--- /dev/null
+++ b/chromium/content/browser/frame_host/frame_accessibility.cc
@@ -0,0 +1,179 @@
+// 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/frame_host/frame_accessibility.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_delegate.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/public/browser/browser_context.h"
+
+namespace content {
+
+// static
+FrameAccessibility* FrameAccessibility::GetInstance() {
+ return Singleton<FrameAccessibility>::get();
+}
+
+FrameAccessibility::ChildFrameMapping::ChildFrameMapping()
+ : parent_frame_host(NULL),
+ accessibility_node_id(0),
+ child_frame_tree_node_id(0),
+ browser_plugin_instance_id(0) {}
+
+FrameAccessibility::FrameAccessibility() {}
+
+FrameAccessibility::~FrameAccessibility() {}
+
+void FrameAccessibility::AddChildFrame(
+ RenderFrameHostImpl* parent_frame_host,
+ int accessibility_node_id,
+ int64 child_frame_tree_node_id) {
+ for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin();
+ iter != mappings_.end();
+ ++iter) {
+ // TODO(dmazzoni): the renderer should keep track of these mappings
+ // and clear an existing mapping before setting a new one, that would
+ // be safer than just updating existing mappings. http://crbug.com/413464
+ if (iter->parent_frame_host == parent_frame_host &&
+ (iter->accessibility_node_id == accessibility_node_id ||
+ iter->child_frame_tree_node_id == child_frame_tree_node_id)) {
+ iter->accessibility_node_id = accessibility_node_id;
+ iter->child_frame_tree_node_id = child_frame_tree_node_id;
+ return;
+ }
+ }
+
+ ChildFrameMapping new_mapping;
+ new_mapping.parent_frame_host = parent_frame_host;
+ new_mapping.accessibility_node_id = accessibility_node_id;
+ new_mapping.child_frame_tree_node_id = child_frame_tree_node_id;
+ mappings_.push_back(new_mapping);
+}
+
+void FrameAccessibility::AddGuestWebContents(
+ RenderFrameHostImpl* parent_frame_host,
+ int accessibility_node_id,
+ int browser_plugin_instance_id) {
+ for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin();
+ iter != mappings_.end();
+ ++iter) {
+ // TODO(dmazzoni): the renderer should keep track of these mappings
+ // and clear an existing mapping before setting a new one, that would
+ // be safer than just updating existing mappings. http://crbug.com/413464
+ if (iter->parent_frame_host == parent_frame_host &&
+ (iter->accessibility_node_id == accessibility_node_id ||
+ iter->browser_plugin_instance_id == browser_plugin_instance_id)) {
+ iter->accessibility_node_id = accessibility_node_id;
+ iter->browser_plugin_instance_id = browser_plugin_instance_id;
+ return;
+ }
+ }
+
+ ChildFrameMapping new_mapping;
+ new_mapping.parent_frame_host = parent_frame_host;
+ new_mapping.accessibility_node_id = accessibility_node_id;
+ new_mapping.browser_plugin_instance_id = browser_plugin_instance_id;
+ mappings_.push_back(new_mapping);
+}
+
+void FrameAccessibility::OnRenderFrameHostDestroyed(
+ RenderFrameHostImpl* render_frame_host) {
+ // Since the order doesn't matter, the fastest way to remove all items
+ // with this render_frame_host is to iterate over the vector backwards,
+ // swapping each one with the back element if we need to delete it.
+ int initial_len = static_cast<int>(mappings_.size());
+ for (int i = initial_len - 1; i >= 0; i--) {
+ if (mappings_[i].parent_frame_host == render_frame_host) {
+ mappings_[i] = mappings_.back();
+ mappings_.pop_back();
+ }
+ }
+}
+
+RenderFrameHostImpl* FrameAccessibility::GetChild(
+ RenderFrameHostImpl* parent_frame_host,
+ int accessibility_node_id) {
+ for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin();
+ iter != mappings_.end();
+ ++iter) {
+ if (iter->parent_frame_host != parent_frame_host ||
+ iter->accessibility_node_id != accessibility_node_id) {
+ continue;
+ }
+
+ if (iter->child_frame_tree_node_id) {
+ FrameTreeNode* child_node =
+ FrameTree::GloballyFindByID(iter->child_frame_tree_node_id);
+ if (!child_node)
+ return NULL;
+
+ // We should have gotten a node in the same frame tree.
+ if (child_node->frame_tree() !=
+ parent_frame_host->frame_tree_node()->frame_tree()) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return child_node->current_frame_host();
+ }
+
+ if (iter->browser_plugin_instance_id) {
+ RenderFrameHost* guest =
+ parent_frame_host->delegate()->GetGuestByInstanceID(
+ iter->browser_plugin_instance_id);
+ if (guest)
+ return static_cast<RenderFrameHostImpl*>(guest);
+ }
+ }
+
+ return NULL;
+}
+
+bool FrameAccessibility::GetParent(
+ RenderFrameHostImpl* child_frame_host,
+ RenderFrameHostImpl** out_parent_frame_host,
+ int* out_accessibility_node_id) {
+ for (std::vector<ChildFrameMapping>::iterator iter = mappings_.begin();
+ iter != mappings_.end();
+ ++iter) {
+ if (iter->child_frame_tree_node_id) {
+ FrameTreeNode* child_node =
+ FrameTree::GloballyFindByID(iter->child_frame_tree_node_id);
+ if (child_node &&
+ child_node->current_frame_host() == child_frame_host) {
+ // We should have gotten a node in the same frame tree.
+ if (child_node->frame_tree() !=
+ iter->parent_frame_host->frame_tree_node()->frame_tree()) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (out_parent_frame_host)
+ *out_parent_frame_host = iter->parent_frame_host;
+ if (out_accessibility_node_id)
+ *out_accessibility_node_id = iter->accessibility_node_id;
+ return true;
+ }
+ }
+
+ if (iter->browser_plugin_instance_id) {
+ RenderFrameHost* guest =
+ iter->parent_frame_host->delegate()->GetGuestByInstanceID(
+ iter->browser_plugin_instance_id);
+ if (guest == child_frame_host) {
+ if (out_parent_frame_host)
+ *out_parent_frame_host = iter->parent_frame_host;
+ if (out_accessibility_node_id)
+ *out_accessibility_node_id = iter->accessibility_node_id;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/frame_host/frame_accessibility.h b/chromium/content/browser/frame_host/frame_accessibility.h
new file mode 100644
index 00000000000..253ba19b054
--- /dev/null
+++ b/chromium/content/browser/frame_host/frame_accessibility.h
@@ -0,0 +1,79 @@
+// 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_FRAME_HOST_FRAME_ACCESSIBILITY_H_
+#define CONTENT_BROWSER_FRAME_HOST_FRAME_ACCESSIBILITY_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/singleton.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class RenderFrameHostImpl;
+
+// This singleton class maintains the mappings necessary to link child frames
+// and guest frames into a single tree for accessibility. This class is only
+// used if accessibility is enabled.
+class CONTENT_EXPORT FrameAccessibility {
+ public:
+ static FrameAccessibility* GetInstance();
+
+ // Add a mapping between an accessibility node of |parent_frame_host|
+ // and the child frame with the given frame tree node id, in the same
+ // frame tree.
+ void AddChildFrame(RenderFrameHostImpl* parent_frame_host,
+ int accessibility_node_id,
+ int64 child_frame_tree_node_id);
+
+ // Add a mapping between an accessibility node of |parent_frame_host|
+ // and the main frame of the guest Webcontents with the given
+ // browser plugin instance id.
+ void AddGuestWebContents(RenderFrameHostImpl* parent_frame_host,
+ int accessibility_node_id,
+ int browser_plugin_instance_id);
+
+ // This is called when a RenderFrameHostImpl is deleted, so invalid
+ // mappings can be removed from this data structure.
+ void OnRenderFrameHostDestroyed(RenderFrameHostImpl* render_frame_host);
+
+ // Given a parent RenderFrameHostImpl and an accessibility node id, look up
+ // a child frame or guest frame that was previously associated with this
+ // frame and node id. If a mapping exists, return the resulting frame if
+ // it's valid. If it doesn't resolve to a valid RenderFrameHostImpl,
+ // returns NULL.
+ RenderFrameHostImpl* GetChild(RenderFrameHostImpl* parent_frame_host,
+ int accessibility_node_id);
+
+ // Given a RenderFrameHostImpl, check the mapping table to see if it's
+ // the child of a node in some other frame. If so, return true and
+ // set the parent frame and accessibility node id in the parent frame,
+ // otherwise return false.
+ bool GetParent(RenderFrameHostImpl* child_frame_host,
+ RenderFrameHostImpl** out_parent_frame_host,
+ int* out_accessibility_node_id);
+
+ private:
+ FrameAccessibility();
+ virtual ~FrameAccessibility();
+
+ struct ChildFrameMapping {
+ ChildFrameMapping();
+
+ RenderFrameHostImpl* parent_frame_host;
+ int accessibility_node_id;
+ int64 child_frame_tree_node_id;
+ int browser_plugin_instance_id;
+ };
+
+ std::vector<ChildFrameMapping> mappings_;
+
+ friend struct DefaultSingletonTraits<FrameAccessibility>;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FRAME_HOST_FRAME_ACCESSIBILITY_H_
diff --git a/chromium/content/browser/frame_host/frame_tree.cc b/chromium/content/browser/frame_host/frame_tree.cc
index 1accb0e9d1b..b1ccf6f9c79 100644
--- a/chromium/content/browser/frame_host/frame_tree.cc
+++ b/chromium/content/browser/frame_host/frame_tree.cc
@@ -8,18 +8,30 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.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_factory.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/frame_host/render_frame_proxy_host.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/public/browser/browser_thread.h"
namespace content {
namespace {
+
+// This is a global map between frame_tree_node_ids and pointer to
+// FrameTreeNodes.
+typedef base::hash_map<int64, FrameTreeNode*> FrameTreeNodeIDMap;
+
+base::LazyInstance<FrameTreeNodeIDMap> g_frame_tree_node_id_map =
+ LAZY_INSTANCE_INITIALIZER;
+
// Used with FrameTree::ForEach() to search for the FrameTreeNode
-// corresponding to |frame_tree_node_id|.
+// corresponding to |frame_tree_node_id| whithin a specific FrameTree.
bool FrameTreeNodeForId(int64 frame_tree_node_id,
FrameTreeNode** out_node,
FrameTreeNode* node) {
@@ -31,26 +43,27 @@ bool FrameTreeNodeForId(int64 frame_tree_node_id,
return true;
}
-bool FrameTreeNodeForRoutingId(int routing_id,
- int process_id,
- FrameTreeNode** out_node,
- FrameTreeNode* node) {
- // TODO(creis): Look through the swapped out RFHs as well.
- if (node->current_frame_host()->GetProcess()->GetID() == process_id &&
- node->current_frame_host()->GetRoutingID() == routing_id) {
- *out_node = node;
- // Terminate iteration once the node has been found.
- return false;
- }
- return true;
-}
-
// Iterate over the FrameTree to reset any node affected by the loss of the
// given RenderViewHost's process.
bool ResetNodesForNewProcess(RenderViewHost* render_view_host,
FrameTreeNode* node) {
- if (render_view_host == node->current_frame_host()->render_view_host())
+ if (render_view_host == node->current_frame_host()->render_view_host()) {
+ // Ensure that if the frame host is reused for a new RenderFrame, it will
+ // set up the Mojo connection with that frame.
+ node->current_frame_host()->InvalidateMojoConnection();
node->ResetForNewProcess();
+ }
+ 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;
}
@@ -73,9 +86,22 @@ FrameTree::FrameTree(Navigator* navigator,
manager_delegate,
std::string())),
focused_frame_tree_node_id_(-1) {
+ std::pair<FrameTreeNodeIDMap::iterator, bool> result =
+ g_frame_tree_node_id_map.Get().insert(
+ std::make_pair(root_->frame_tree_node_id(), root_.get()));
+ CHECK(result.second);
}
FrameTree::~FrameTree() {
+ g_frame_tree_node_id_map.Get().erase(root_->frame_tree_node_id());
+}
+
+// static
+FrameTreeNode* FrameTree::GloballyFindByID(int64 frame_tree_node_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ FrameTreeNodeIDMap* nodes = g_frame_tree_node_id_map.Pointer();
+ FrameTreeNodeIDMap::iterator it = nodes->find(frame_tree_node_id);
+ return it == nodes->end() ? NULL : it->second;
}
FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
@@ -85,20 +111,42 @@ FrameTreeNode* FrameTree::FindByID(int64 frame_tree_node_id) {
}
FrameTreeNode* FrameTree::FindByRoutingID(int routing_id, int process_id) {
- FrameTreeNode* node = NULL;
- ForEach(
- base::Bind(&FrameTreeNodeForRoutingId, routing_id, process_id, &node));
- return node;
+ RenderFrameHostImpl* render_frame_host =
+ RenderFrameHostImpl::FromID(process_id, routing_id);
+ if (render_frame_host) {
+ FrameTreeNode* result = render_frame_host->frame_tree_node();
+ if (this == result->frame_tree())
+ return result;
+ }
+
+ RenderFrameProxyHost* render_frame_proxy_host =
+ RenderFrameProxyHost::FromID(process_id, routing_id);
+ if (render_frame_proxy_host) {
+ FrameTreeNode* result = render_frame_proxy_host->frame_tree_node();
+ if (this == result->frame_tree())
+ return result;
+ }
+
+ return NULL;
}
void FrameTree::ForEach(
const base::Callback<bool(FrameTreeNode*)>& on_node) const {
+ ForEach(on_node, NULL);
+}
+
+void FrameTree::ForEach(
+ const base::Callback<bool(FrameTreeNode*)>& on_node,
+ FrameTreeNode* skip_this_subtree) const {
std::queue<FrameTreeNode*> queue;
queue.push(root_.get());
while (!queue.empty()) {
FrameTreeNode* node = queue.front();
queue.pop();
+ if (skip_this_subtree == node)
+ continue;
+
if (!on_node.Run(node))
break;
@@ -108,14 +156,26 @@ void FrameTree::ForEach(
}
RenderFrameHostImpl* FrameTree::AddFrame(FrameTreeNode* parent,
+ int process_id,
int new_routing_id,
const std::string& frame_name) {
+ // A child frame always starts with an initial empty document, which means
+ // it is in the same SiteInstance as the parent frame. Ensure that the process
+ // which requested a child frame to be added is the same as the process of the
+ // parent node.
+ if (parent->current_frame_host()->GetProcess()->GetID() != process_id)
+ return nullptr;
+
scoped_ptr<FrameTreeNode> node(new FrameTreeNode(
this, parent->navigator(), render_frame_delegate_, render_view_delegate_,
render_widget_delegate_, manager_delegate_, frame_name));
+ std::pair<FrameTreeNodeIDMap::iterator, bool> result =
+ g_frame_tree_node_id_map.Get().insert(
+ std::make_pair(node->frame_tree_node_id(), node.get()));
+ CHECK(result.second);
FrameTreeNode* node_ptr = node.get();
// AddChild is what creates the RenderFrameHost.
- parent->AddChild(node.Pass(), new_routing_id);
+ parent->AddChild(node.Pass(), process_id, new_routing_id);
return node_ptr->current_frame_host();
}
@@ -129,14 +189,38 @@ void FrameTree::RemoveFrame(FrameTreeNode* child) {
// Notify observers of the frame removal.
RenderFrameHostImpl* render_frame_host = child->current_frame_host();
if (!on_frame_removed_.is_null()) {
- on_frame_removed_.Run(
- render_frame_host->render_view_host(),
- render_frame_host->GetRoutingID());
+ on_frame_removed_.Run(render_frame_host);
}
-
+ g_frame_tree_node_id_map.Get().erase(child->frame_tree_node_id());
parent->RemoveChild(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.
+ if (!source->IsMainFrame()) {
+ RenderViewHostImpl* render_view_host =
+ source->frame_tree()->GetRenderViewHost(site_instance);
+ if (!render_view_host) {
+ root()->render_manager()->CreateRenderFrame(site_instance,
+ MSG_ROUTING_NONE,
+ true,
+ false,
+ true);
+ }
+ }
+
+ 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);
+}
+
void FrameTree::ResetForMainFrameSwap() {
root_->ResetForNewProcess();
focused_frame_tree_node_id_ = -1;
@@ -165,29 +249,33 @@ void FrameTree::SetFocusedFrame(FrameTreeNode* node) {
}
void FrameTree::SetFrameRemoveListener(
- const base::Callback<void(RenderViewHostImpl*, int)>& on_frame_removed) {
+ const base::Callback<void(RenderFrameHost*)>& on_frame_removed) {
on_frame_removed_ = on_frame_removed;
}
-RenderViewHostImpl* FrameTree::CreateRenderViewHostForMainFrame(
- SiteInstance* site_instance,
- int routing_id,
- int main_frame_routing_id,
- bool swapped_out,
- bool hidden) {
+RenderViewHostImpl* FrameTree::CreateRenderViewHost(SiteInstance* site_instance,
+ int routing_id,
+ int main_frame_routing_id,
+ bool swapped_out,
+ bool hidden) {
DCHECK(main_frame_routing_id != MSG_ROUTING_NONE);
RenderViewHostMap::iterator iter =
render_view_host_map_.find(site_instance->GetId());
if (iter != render_view_host_map_.end()) {
- // If a RenderViewHost is pending shutdown for this |site_instance|, put it
- // in the map of RenderViewHosts pending shutdown. Otherwise there should
- // not be a RenderViewHost for the SiteInstance.
- CHECK_EQ(RenderViewHostImpl::STATE_PENDING_SHUTDOWN,
- iter->second->rvh_state());
- render_view_host_pending_shutdown_map_.insert(
- std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
- iter->second));
- render_view_host_map_.erase(iter);
+ // If a RenderViewHost's main frame is pending deletion for this
+ // |site_instance|, put it in the map of RenderViewHosts pending shutdown.
+ // Otherwise return the existing RenderViewHost for the SiteInstance.
+ RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
+ iter->second->GetMainFrame());
+ if (main_frame->frame_tree_node()->render_manager()->IsPendingDeletion(
+ main_frame)) {
+ render_view_host_pending_shutdown_map_.insert(
+ std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
+ iter->second));
+ render_view_host_map_.erase(iter);
+ } else {
+ return iter->second;
+ }
}
RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
RenderViewHostFactory::Create(site_instance,
@@ -202,8 +290,7 @@ RenderViewHostImpl* FrameTree::CreateRenderViewHostForMainFrame(
return rvh;
}
-RenderViewHostImpl* FrameTree::GetRenderViewHostForSubFrame(
- SiteInstance* site_instance) {
+RenderViewHostImpl* FrameTree::GetRenderViewHost(SiteInstance* site_instance) {
RenderViewHostMap::iterator iter =
render_view_host_map_.find(site_instance->GetId());
// TODO(creis): Mirror the frame tree so this check can't fail.
diff --git a/chromium/content/browser/frame_host/frame_tree.h b/chromium/content/browser/frame_host/frame_tree.h
index c7fdc4eaf7a..b312265fe4e 100644
--- a/chromium/content/browser/frame_host/frame_tree.h
+++ b/chromium/content/browser/frame_host/frame_tree.h
@@ -50,9 +50,13 @@ class CONTENT_EXPORT FrameTree {
RenderFrameHostManager::Delegate* manager_delegate);
~FrameTree();
+ // Returns the FrameTreeNode with the given |frame_tree_node_id|.
+ static FrameTreeNode* GloballyFindByID(int64 frame_tree_node_id);
+
FrameTreeNode* root() const { return root_.get(); }
- // Returns the FrameTreeNode with the given |frame_tree_node_id|.
+ // Returns the FrameTreeNode with the given |frame_tree_node_id| if it is part
+ // of this FrameTree.
FrameTreeNode* FindByID(int64 frame_tree_node_id);
// Returns the FrameTreeNode with the given renderer-specific |routing_id|.
@@ -67,10 +71,19 @@ class CONTENT_EXPORT FrameTree {
// Frame tree manipulation routines.
RenderFrameHostImpl* AddFrame(FrameTreeNode* parent,
+ int process_id,
int new_routing_id,
const std::string& frame_name);
void RemoveFrame(FrameTreeNode* child);
+ // This method walks the entire frame tree and creates a RenderFrameProxyHost
+ // for the given |site_instance| in each node except the |source| one --
+ // the source will have a RenderFrameHost. It assumes that no frame tree
+ // nodes already have RenderFrameProxyHost for the given |site_instance|.
+ void CreateProxiesForSiteInstance(
+ FrameTreeNode* source,
+ SiteInstance* site_instance);
+
// Clears process specific-state after a main frame process swap.
// This destroys most of the frame tree but retains the root node so that
// navigation state may be kept on it between process swaps. Used to
@@ -97,24 +110,22 @@ class CONTENT_EXPORT FrameTree {
// Allows a client to listen for frame removal. The listener should expect
// to receive the RenderViewHostImpl containing the frame and the renderer-
// specific frame routing ID of the removed frame.
- // TODO(creis): These parameters will later change to be the RenderFrameHost.
void SetFrameRemoveListener(
- const base::Callback<void(RenderViewHostImpl*, int)>& on_frame_removed);
+ const base::Callback<void(RenderFrameHost*)>& on_frame_removed);
- // Creates a RenderViewHost for a new main frame RenderFrameHost in the given
+ // Creates a RenderViewHost for a new RenderFrameHost in the given
// |site_instance|. The RenderViewHost will have its Shutdown method called
// when all of the RenderFrameHosts using it are deleted.
- RenderViewHostImpl* CreateRenderViewHostForMainFrame(
- SiteInstance* site_instance,
- int routing_id,
- int main_frame_routing_id,
- bool swapped_out,
- bool hidden);
-
- // Returns the existing RenderViewHost for a new subframe RenderFrameHost.
+ RenderViewHostImpl* CreateRenderViewHost(SiteInstance* site_instance,
+ int routing_id,
+ int main_frame_routing_id,
+ bool swapped_out,
+ bool hidden);
+
+ // Returns the existing RenderViewHost for a new RenderFrameHost.
// There should always be such a RenderViewHost, because the main frame
// RenderFrameHost for each SiteInstance should be created before subframes.
- RenderViewHostImpl* GetRenderViewHostForSubFrame(SiteInstance* site_instance);
+ RenderViewHostImpl* GetRenderViewHost(SiteInstance* site_instance);
// Keeps track of which RenderFrameHosts are using each RenderViewHost. When
// the number drops to zero, we call Shutdown on the RenderViewHost.
@@ -125,6 +136,11 @@ class CONTENT_EXPORT FrameTree {
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;
+
// These delegates are installed into all the RenderViewHosts and
// RenderFrameHosts that we create.
RenderFrameHostDelegate* render_frame_delegate_;
@@ -153,7 +169,7 @@ class CONTENT_EXPORT FrameTree {
int64 focused_frame_tree_node_id_;
- base::Callback<void(RenderViewHostImpl*, int)> on_frame_removed_;
+ base::Callback<void(RenderFrameHost*)> on_frame_removed_;
DISALLOW_COPY_AND_ASSIGN(FrameTree);
};
diff --git a/chromium/content/browser/frame_host/frame_tree_browsertest.cc b/chromium/content/browser/frame_host/frame_tree_browsertest.cc
index bc5f1cb04ff..9f16066cd38 100644
--- a/chromium/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/chromium/content/browser/frame_host/frame_tree_browsertest.cc
@@ -2,12 +2,14 @@
// 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/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/renderer_host/render_view_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/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"
@@ -15,6 +17,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"
namespace content {
@@ -102,6 +105,13 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
NavigateToURL(shell(),
test_server()->GetURL("files/frame_tree/top.html"));
+ // Ensure the view and frame are live.
+ RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
+ EXPECT_TRUE(rvh->IsRenderViewLive());
+ EXPECT_TRUE(rfh->IsRenderFrameLive());
+
// Crash the renderer so that it doesn't send any FrameDetached messages.
RenderProcessHostWatcher crash_observer(
shell()->web_contents(),
@@ -114,11 +124,19 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
FrameTreeNode* root = wc->GetFrameTree()->root();
EXPECT_EQ(0UL, root->child_count());
+ // Ensure the view and frame aren't live anymore.
+ EXPECT_FALSE(rvh->IsRenderViewLive());
+ EXPECT_FALSE(rfh->IsRenderFrameLive());
+
// Navigate to a new URL.
GURL url(test_server()->GetURL("files/title1.html"));
NavigateToURL(shell(), url);
EXPECT_EQ(0UL, root->child_count());
EXPECT_EQ(url, root->current_url());
+
+ // Ensure the view and frame are live again.
+ EXPECT_TRUE(rvh->IsRenderViewLive());
+ EXPECT_TRUE(rfh->IsRenderFrameLive());
}
// Test that we can navigate away if the previous renderer doesn't clean up its
@@ -155,4 +173,108 @@ IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, NavigateWithLeftoverFrames) {
EXPECT_EQ(0UL, root->child_count());
}
+// Ensure that IsRenderFrameLive is true for main frames and same-site iframes.
+IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+ GURL main_url(test_server()->GetURL("files/frame_tree/top.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();
+
+ // The root and subframe should each have a live RenderFrame.
+ EXPECT_TRUE(
+ root->current_frame_host()->render_view_host()->IsRenderViewLive());
+ EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
+ EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
+
+ // Load a same-site page into iframe and it should still be live.
+ GURL http_url(test_server()->GetURL("files/title1.html"));
+ NavigateFrameToURL(root->child_at(0), http_url);
+ EXPECT_TRUE(
+ root->current_frame_host()->render_view_host()->IsRenderViewLive());
+ EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
+ EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
+}
+
+class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
+ public:
+ CrossProcessFrameTreeBrowserTest() {}
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(switches::kSitePerProcess);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CrossProcessFrameTreeBrowserTest);
+};
+
+// Ensure that we can complete a cross-process subframe navigation.
+#if defined(OS_ANDROID)
+#define MAYBE_CreateCrossProcessSubframeProxies DISABLED_CreateCrossProcessSubframeProxies
+#else
+#define MAYBE_CreateCrossProcessSubframeProxies CreateCrossProcessSubframeProxies
+#endif
+IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
+ MAYBE_CreateCrossProcessSubframeProxies) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+ GURL main_url(test_server()->GetURL("files/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();
+
+ // There should not be a proxy for the root's own SiteInstance.
+ SiteInstance* root_instance = root->current_frame_host()->GetSiteInstance();
+ EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
+
+ // Load same-site page into iframe.
+ GURL http_url(test_server()->GetURL("files/title1.html"));
+ NavigateFrameToURL(root->child_at(0), http_url);
+
+ // These must stay in scope with replace_host.
+ GURL::Replacements replace_host;
+ std::string foo_com("foo.com");
+
+ // Load cross-site page into iframe.
+ GURL cross_site_url(test_server()->GetURL("files/title2.html"));
+ replace_host.SetHostStr(foo_com);
+ cross_site_url = cross_site_url.ReplaceComponents(replace_host);
+ NavigateFrameToURL(root->child_at(0), cross_site_url);
+
+ // Ensure that we have created a new process for the subframe.
+ ASSERT_EQ(2U, root->child_count());
+ FrameTreeNode* child = root->child_at(0);
+ SiteInstance* child_instance = child->current_frame_host()->GetSiteInstance();
+ RenderViewHost* rvh = child->current_frame_host()->render_view_host();
+ RenderProcessHost* rph = child->current_frame_host()->GetProcess();
+
+ EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(), child_instance);
+ EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
+
+ // Ensure that the root node has a proxy for the child node's SiteInstance.
+ EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(child_instance));
+
+ // Also ensure that the child has a proxy for the root node's SiteInstance.
+ EXPECT_TRUE(child->render_manager()->GetRenderFrameProxyHost(root_instance));
+
+ // The nodes should not have proxies for their own SiteInstance.
+ EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
+ EXPECT_FALSE(
+ child->render_manager()->GetRenderFrameProxyHost(child_instance));
+
+ // Ensure that the RenderViews and RenderFrames are all live.
+ EXPECT_TRUE(
+ root->current_frame_host()->render_view_host()->IsRenderViewLive());
+ EXPECT_TRUE(
+ child->current_frame_host()->render_view_host()->IsRenderViewLive());
+ EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
+ EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/frame_tree_node.cc b/chromium/content/browser/frame_host/frame_tree_node.cc
index ebc542e56e3..41be622302e 100644
--- a/chromium/content/browser/frame_host/frame_tree_node.cc
+++ b/chromium/content/browser/frame_host/frame_tree_node.cc
@@ -6,11 +6,13 @@
#include <queue>
+#include "base/command_line.h"
#include "base/stl_util.h"
#include "content/browser/frame_host/frame_tree.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/public/common/content_switches.h"
namespace content {
@@ -35,6 +37,10 @@ FrameTreeNode::FrameTreeNode(FrameTree* frame_tree,
parent_(NULL) {}
FrameTreeNode::~FrameTreeNode() {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ navigator_->CancelNavigation(this);
+ }
}
bool FrameTreeNode::IsMainFrame() const {
@@ -42,7 +48,11 @@ bool FrameTreeNode::IsMainFrame() const {
}
void FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child,
+ int process_id,
int frame_routing_id) {
+ // Child frame must always be created in the same process as the parent.
+ CHECK_EQ(process_id, render_manager_.current_host()->GetProcess()->GetID());
+
// Initialize the RenderFrameHost for the new node. We always create child
// frames in the same SiteInstance as the current frame, and they can swap to
// a different one if they navigate away.
@@ -76,6 +86,9 @@ void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
void FrameTreeNode::ResetForNewProcess() {
current_url_ = GURL();
+ // The RenderFrame no longer exists and will need to be created again.
+ current_frame_host()->set_render_frame_created(false);
+
// The children may not have been cleared if a cross-process navigation
// commits before the old process cleans everything up. Make sure the child
// nodes get deleted before swapping to a new process.
diff --git a/chromium/content/browser/frame_host/frame_tree_node.h b/chromium/content/browser/frame_host/frame_tree_node.h
index 3b5e6acb6b3..5974fd29bf5 100644
--- a/chromium/content/browser/frame_host/frame_tree_node.h
+++ b/chromium/content/browser/frame_host/frame_tree_node.h
@@ -41,7 +41,9 @@ class CONTENT_EXPORT FrameTreeNode {
bool IsMainFrame() const;
- void AddChild(scoped_ptr<FrameTreeNode> child, int frame_routing_id);
+ void AddChild(scoped_ptr<FrameTreeNode> child,
+ int process_id,
+ int frame_routing_id);
void RemoveChild(FrameTreeNode* child);
// Clears process specific-state in this node to prepare for a new process.
diff --git a/chromium/content/browser/frame_host/frame_tree_unittest.cc b/chromium/content/browser/frame_host/frame_tree_unittest.cc
index a894061f32c..bb705c7f881 100644
--- a/chromium/content/browser/frame_host/frame_tree_unittest.cc
+++ b/chromium/content/browser/frame_host/frame_tree_unittest.cc
@@ -16,11 +16,13 @@
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/test_render_frame_host.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 {
+
namespace {
// Appends a description of the structure of the frame tree to |result|.
@@ -49,7 +51,7 @@ class TreeWalkingWebContentsLogger : public WebContentsObserver {
explicit TreeWalkingWebContentsLogger(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
- virtual ~TreeWalkingWebContentsLogger() {
+ ~TreeWalkingWebContentsLogger() override {
EXPECT_EQ("", log_) << "Activity logged that was not expected";
}
@@ -61,15 +63,22 @@ class TreeWalkingWebContentsLogger : public WebContentsObserver {
}
// content::WebContentsObserver implementation.
- virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE {
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
LogWhatHappened("RenderFrameCreated", render_frame_host);
}
- virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
+ void RenderFrameHostChanged(RenderFrameHost* old_host,
+ RenderFrameHost* new_host) override {
+ if (old_host)
+ LogWhatHappened("RenderFrameChanged(old)", old_host);
+ LogWhatHappened("RenderFrameChanged(new)", new_host);
+ }
+
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override {
LogWhatHappened("RenderFrameDeleted", render_frame_host);
}
- virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE {
+ void RenderProcessGone(base::TerminationStatus status) override {
LogWhatHappened("RenderProcessGone");
}
@@ -94,6 +103,8 @@ class TreeWalkingWebContentsLogger : public WebContentsObserver {
DISALLOW_COPY_AND_ASSIGN(TreeWalkingWebContentsLogger);
};
+} // namespace
+
class FrameTreeTest : public RenderViewHostImplTestHarness {
protected:
// Prints a FrameTree, for easy assertions of the tree hierarchy.
@@ -115,17 +126,18 @@ TEST_F(FrameTreeTest, Shape) {
std::string no_children_node("no children node");
std::string deep_subtree("node with deep subtree");
+ int process_id = root->current_frame_host()->GetProcess()->GetID();
ASSERT_EQ("1: []", GetTreeState(frame_tree));
// Simulate attaching a series of frames to build the frame tree.
- frame_tree->AddFrame(root, 14, std::string());
- frame_tree->AddFrame(root, 15, std::string());
- frame_tree->AddFrame(root, 16, std::string());
+ frame_tree->AddFrame(root, process_id, 14, std::string());
+ frame_tree->AddFrame(root, process_id, 15, std::string());
+ frame_tree->AddFrame(root, process_id, 16, std::string());
- frame_tree->AddFrame(root->child_at(0), 244, std::string());
- frame_tree->AddFrame(root->child_at(1), 255, no_children_node);
- frame_tree->AddFrame(root->child_at(0), 245, std::string());
+ frame_tree->AddFrame(root->child_at(0), process_id, 244, std::string());
+ frame_tree->AddFrame(root->child_at(1), process_id, 255, no_children_node);
+ frame_tree->AddFrame(root->child_at(0), process_id, 245, std::string());
ASSERT_EQ("1: [14: [244: [], 245: []], "
"15: [255 'no children node': []], "
@@ -133,18 +145,19 @@ TEST_F(FrameTreeTest, Shape) {
GetTreeState(frame_tree));
FrameTreeNode* child_16 = root->child_at(2);
- frame_tree->AddFrame(child_16, 264, std::string());
- frame_tree->AddFrame(child_16, 265, std::string());
- frame_tree->AddFrame(child_16, 266, std::string());
- frame_tree->AddFrame(child_16, 267, deep_subtree);
- frame_tree->AddFrame(child_16, 268, std::string());
+ frame_tree->AddFrame(child_16, process_id, 264, std::string());
+ frame_tree->AddFrame(child_16, process_id, 265, std::string());
+ frame_tree->AddFrame(child_16, process_id, 266, std::string());
+ frame_tree->AddFrame(child_16, process_id, 267, deep_subtree);
+ frame_tree->AddFrame(child_16, process_id, 268, std::string());
FrameTreeNode* child_267 = child_16->child_at(3);
- frame_tree->AddFrame(child_267, 365, std::string());
- frame_tree->AddFrame(child_267->child_at(0), 455, std::string());
- frame_tree->AddFrame(child_267->child_at(0)->child_at(0), 555, std::string());
- frame_tree->AddFrame(child_267->child_at(0)->child_at(0)->child_at(0), 655,
+ frame_tree->AddFrame(child_267, process_id, 365, std::string());
+ frame_tree->AddFrame(child_267->child_at(0), process_id, 455, std::string());
+ frame_tree->AddFrame(child_267->child_at(0)->child_at(0), process_id, 555,
std::string());
+ frame_tree->AddFrame(child_267->child_at(0)->child_at(0)->child_at(0),
+ process_id, 655, std::string());
// Now that's it's fully built, verify the tree structure is as expected.
ASSERT_EQ("1: [14: [244: [], 245: []], "
@@ -186,6 +199,8 @@ TEST_F(FrameTreeTest, ObserverWalksTreeDuringFrameCreation) {
FrameTree* frame_tree = contents()->GetFrameTree();
FrameTreeNode* root = frame_tree->root();
+ EXPECT_EQ("", activity.GetLog());
+
// Simulate attaching a series of frames to build the frame tree.
main_test_rfh()->OnCreateChildFrame(14, std::string());
EXPECT_EQ("RenderFrameCreated(14) -> 1: [14: []]", activity.GetLog());
@@ -217,5 +232,18 @@ TEST_F(FrameTreeTest, ObserverWalksTreeAfterCrash) {
activity.GetLog());
}
-} // namespace
+// Ensure that frames are not added to the tree, if the process passed in
+// is different than the process of the parent node.
+TEST_F(FrameTreeTest, FailAddFrameWithWrongProcessId) {
+ FrameTree* frame_tree = contents()->GetFrameTree();
+ FrameTreeNode* root = frame_tree->root();
+ int process_id = root->current_frame_host()->GetProcess()->GetID();
+
+ ASSERT_EQ("1: []", GetTreeState(frame_tree));
+
+ // Simulate attaching a frame from mismatched process id.
+ ASSERT_FALSE(frame_tree->AddFrame(root, process_id + 1, 1, std::string()));
+ ASSERT_EQ("1: []", GetTreeState(frame_tree));
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.cc b/chromium/content/browser/frame_host/interstitial_page_impl.cc
index a4ea2997bf7..72fd2043faf 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl.cc
+++ b/chromium/content/browser/frame_host/interstitial_page_impl.cc
@@ -40,9 +40,9 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/bindings_policy.h"
-#include "content/public/common/page_transition_types.h"
#include "net/base/escape.h"
#include "net/url_request/url_request_context_getter.h"
+#include "ui/base/page_transition_types.h"
using blink::WebDragOperation;
using blink::WebDragOperationsMask;
@@ -78,23 +78,24 @@ class InterstitialPageImpl::InterstitialPageRVHDelegateView
// RenderViewHostDelegateView implementation:
#if defined(OS_MACOSX) || defined(OS_ANDROID)
- virtual void ShowPopupMenu(const gfx::Rect& bounds,
- int item_height,
- double item_font_size,
- int selected_item,
- const std::vector<MenuItem>& items,
- bool right_aligned,
- bool allow_multiple_selection) OVERRIDE;
- virtual void HidePopupMenu() OVERRIDE;
+ void ShowPopupMenu(RenderFrameHost* render_frame_host,
+ const gfx::Rect& bounds,
+ int item_height,
+ double item_font_size,
+ int selected_item,
+ const std::vector<MenuItem>& items,
+ bool right_aligned,
+ bool allow_multiple_selection) override;
+ void HidePopupMenu() override;
#endif
- virtual void StartDragging(const DropData& drop_data,
- WebDragOperationsMask operations_allowed,
- const gfx::ImageSkia& image,
- const gfx::Vector2d& image_offset,
- const DragEventSourceInfo& event_info) OVERRIDE;
- virtual void UpdateDragCursor(WebDragOperation operation) OVERRIDE;
- virtual void GotFocus() OVERRIDE;
- virtual void TakeFocus(bool reverse) OVERRIDE;
+ void StartDragging(const DropData& drop_data,
+ WebDragOperationsMask operations_allowed,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const DragEventSourceInfo& event_info) override;
+ void UpdateDragCursor(WebDragOperation operation) override;
+ void GotFocus() override;
+ void TakeFocus(bool reverse) override;
virtual void OnFindReply(int request_id,
int number_of_matches,
const gfx::Rect& selection_rect,
@@ -148,7 +149,7 @@ InterstitialPageImpl::InterstitialPageImpl(
bool new_navigation,
const GURL& url,
InterstitialPageDelegate* delegate)
- : WebContentsObserver(web_contents),
+ : underlying_content_observer_(web_contents, this),
web_contents_(web_contents),
controller_(static_cast<NavigationControllerImpl*>(
&web_contents->GetController())),
@@ -243,13 +244,13 @@ void InterstitialPageImpl::Show() {
}
DCHECK(!render_view_host_);
- render_view_host_ = static_cast<RenderViewHostImpl*>(CreateRenderViewHost());
+ render_view_host_ = CreateRenderViewHost();
render_view_host_->AttachToFrameTree();
CreateWebContentsView();
std::string data_url = "data:text/html;charset=utf-8," +
net::EscapePath(delegate_->GetHTMLContents());
- render_view_host_->NavigateToURL(GURL(data_url));
+ frame_tree_.root()->current_frame_host()->NavigateToURL(GURL(data_url));
notification_registrar_.Add(this, NOTIFICATION_NAV_ENTRY_PENDING,
Source<NavigationController>(controller_));
@@ -351,32 +352,13 @@ void InterstitialPageImpl::Observe(
}
}
-void InterstitialPageImpl::NavigationEntryCommitted(
- const LoadCommittedDetails& load_details) {
- OnNavigatingAwayOrTabClosing();
-}
-
-void InterstitialPageImpl::WebContentsDestroyed() {
- OnNavigatingAwayOrTabClosing();
-}
-
-bool InterstitialPageImpl::OnMessageReceived(
- const IPC::Message& message,
- RenderFrameHost* render_frame_host) {
- return OnMessageReceived(message);
-}
-
bool InterstitialPageImpl::OnMessageReceived(RenderFrameHost* render_frame_host,
const IPC::Message& message) {
- return OnMessageReceived(message);
-}
-
-bool InterstitialPageImpl::OnMessageReceived(RenderViewHost* render_view_host,
- const IPC::Message& message) {
- return OnMessageReceived(message);
-}
-
-bool InterstitialPageImpl::OnMessageReceived(const IPC::Message& message) {
+ if (render_frame_host->GetRenderViewHost() != render_view_host_) {
+ DCHECK(!render_view_host_)
+ << "We expect an interstitial page to have only a single RVH";
+ return false;
+ }
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(InterstitialPageImpl, message)
@@ -388,6 +370,11 @@ bool InterstitialPageImpl::OnMessageReceived(const IPC::Message& message) {
return handled;
}
+bool InterstitialPageImpl::OnMessageReceived(RenderViewHost* render_view_host,
+ const IPC::Message& message) {
+ return false;
+}
+
void InterstitialPageImpl::RenderFrameCreated(
RenderFrameHost* render_frame_host) {
// Note this is only for subframes in the interstitial, the notification for
@@ -432,6 +419,13 @@ void InterstitialPageImpl::UpdateTitle(
controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE);
}
+AccessibilityMode InterstitialPageImpl::GetAccessibilityMode() const {
+ if (web_contents_)
+ return static_cast<WebContentsImpl*>(web_contents_)->GetAccessibilityMode();
+ else
+ return AccessibilityModeOff;
+}
+
RenderViewHostDelegateView* InterstitialPageImpl::GetDelegateView() {
return rvh_delegate_view_.get();
}
@@ -462,8 +456,8 @@ void InterstitialPageImpl::DidNavigate(
DontProceed();
return;
}
- if (PageTransitionCoreTypeIs(params.transition,
- PAGE_TRANSITION_AUTO_SUBFRAME)) {
+ if (ui::PageTransitionCoreTypeIs(params.transition,
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME)) {
// No need to handle navigate message from iframe in the interstitial page.
return;
}
@@ -502,11 +496,11 @@ RendererPreferences InterstitialPageImpl::GetRendererPrefs(
return renderer_preferences_;
}
-WebPreferences InterstitialPageImpl::GetWebkitPrefs() {
+WebPreferences InterstitialPageImpl::ComputeWebkitPrefs() {
if (!enabled())
return WebPreferences();
- return render_view_host_->GetWebkitPrefs(url_);
+ return render_view_host_->ComputeWebkitPrefs(url_);
}
void InterstitialPageImpl::RenderWidgetDeleted(
@@ -533,7 +527,11 @@ void InterstitialPageImpl::HandleKeyboardEvent(
#if defined(OS_WIN)
gfx::NativeViewAccessible
InterstitialPageImpl::GetParentNativeViewAccessible() {
- return render_widget_host_delegate_->GetParentNativeViewAccessible();
+ if (web_contents_) {
+ WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents_);
+ return wci->GetParentNativeViewAccessible();
+ }
+ return NULL;
}
#endif
@@ -541,7 +539,7 @@ WebContents* InterstitialPageImpl::web_contents() const {
return web_contents_;
}
-RenderViewHost* InterstitialPageImpl::CreateRenderViewHost() {
+RenderViewHostImpl* InterstitialPageImpl::CreateRenderViewHost() {
if (!enabled())
return NULL;
@@ -569,7 +567,7 @@ WebContentsView* InterstitialPageImpl::CreateWebContentsView() {
WebContentsView* wcv =
static_cast<WebContentsImpl*>(web_contents())->GetView();
RenderWidgetHostViewBase* view =
- wcv->CreateViewForWidget(render_view_host_);
+ wcv->CreateViewForWidget(render_view_host_, false);
render_view_host_->SetView(view);
render_view_host_->AllowBindings(BINDINGS_POLICY_DOM_AUTOMATION);
@@ -852,6 +850,7 @@ InterstitialPageImpl::InterstitialPageRVHDelegateView::
#if defined(OS_MACOSX) || defined(OS_ANDROID)
void InterstitialPageImpl::InterstitialPageRVHDelegateView::ShowPopupMenu(
+ RenderFrameHost* render_frame_host,
const gfx::Rect& bounds,
int item_height,
double item_font_size,
@@ -905,4 +904,19 @@ void InterstitialPageImpl::InterstitialPageRVHDelegateView::OnFindReply(
int active_match_ordinal, bool final_update) {
}
+InterstitialPageImpl::UnderlyingContentObserver::UnderlyingContentObserver(
+ WebContents* web_contents,
+ InterstitialPageImpl* interstitial)
+ : WebContentsObserver(web_contents), interstitial_(interstitial) {
+}
+
+void InterstitialPageImpl::UnderlyingContentObserver::NavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) {
+ interstitial_->OnNavigatingAwayOrTabClosing();
+}
+
+void InterstitialPageImpl::UnderlyingContentObserver::WebContentsDestroyed() {
+ interstitial_->OnNavigatingAwayOrTabClosing();
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/interstitial_page_impl.h b/chromium/content/browser/frame_host/interstitial_page_impl.h
index 8068fd34e01..9f6ce8445aa 100644
--- a/chromium/content/browser/frame_host/interstitial_page_impl.h
+++ b/chromium/content/browser/frame_host/interstitial_page_impl.h
@@ -37,7 +37,6 @@ enum ResourceRequestAction {
class CONTENT_EXPORT InterstitialPageImpl
: public NON_EXPORTED_BASE(InterstitialPage),
public NotificationObserver,
- public WebContentsObserver,
public NON_EXPORTED_BASE(RenderFrameHostDelegate),
public RenderViewHostDelegate,
public RenderWidgetHostDelegate,
@@ -55,18 +54,18 @@ class CONTENT_EXPORT InterstitialPageImpl
bool new_navigation,
const GURL& url,
InterstitialPageDelegate* delegate);
- virtual ~InterstitialPageImpl();
+ ~InterstitialPageImpl() override;
// InterstitialPage implementation:
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual void DontProceed() OVERRIDE;
- virtual void Proceed() OVERRIDE;
- virtual RenderViewHost* GetRenderViewHostForTesting() const OVERRIDE;
- virtual InterstitialPageDelegate* GetDelegateForTesting() OVERRIDE;
- virtual void DontCreateViewForTesting() OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void Focus() OVERRIDE;
+ void Show() override;
+ void Hide() override;
+ void DontProceed() override;
+ void Proceed() override;
+ RenderViewHost* GetRenderViewHostForTesting() const override;
+ InterstitialPageDelegate* GetDelegateForTesting() override;
+ void DontCreateViewForTesting() override;
+ void SetSize(const gfx::Size& size) override;
+ void Focus() override;
// Allows the user to navigate away by disabling the interstitial, canceling
// the pending request, and unblocking the hidden renderer. The interstitial
@@ -99,83 +98,67 @@ class CONTENT_EXPORT InterstitialPageImpl
protected:
// NotificationObserver method:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
-
- // WebContentsObserver implementation:
- virtual bool OnMessageReceived(const IPC::Message& message,
- RenderFrameHost* render_frame_host) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void WebContentsDestroyed() OVERRIDE;
- virtual void NavigationEntryCommitted(
- const LoadCommittedDetails& load_details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
// RenderFrameHostDelegate implementation:
- virtual bool OnMessageReceived(RenderFrameHost* render_frame_host,
- const IPC::Message& message) OVERRIDE;
- virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void UpdateTitle(RenderFrameHost* render_frame_host,
- int32 page_id,
- const base::string16& title,
- base::i18n::TextDirection title_direction) OVERRIDE;
+ bool OnMessageReceived(RenderFrameHost* render_frame_host,
+ const IPC::Message& message) override;
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
+ void UpdateTitle(RenderFrameHost* render_frame_host,
+ int32 page_id,
+ const base::string16& title,
+ base::i18n::TextDirection title_direction) override;
+ AccessibilityMode GetAccessibilityMode() const override;
// RenderViewHostDelegate implementation:
- virtual RenderViewHostDelegateView* GetDelegateView() OVERRIDE;
- virtual bool OnMessageReceived(RenderViewHost* render_view_host,
- const IPC::Message& message) OVERRIDE;
- virtual const GURL& GetMainFrameLastCommittedURL() const OVERRIDE;
- virtual void RenderViewTerminated(RenderViewHost* render_view_host,
- base::TerminationStatus status,
- int error_code) OVERRIDE;
- virtual RendererPreferences GetRendererPrefs(
- BrowserContext* browser_context) const OVERRIDE;
- virtual WebPreferences GetWebkitPrefs() OVERRIDE;
- virtual gfx::Rect GetRootWindowResizerRect() const OVERRIDE;
- virtual void CreateNewWindow(
+ RenderViewHostDelegateView* GetDelegateView() override;
+ bool OnMessageReceived(RenderViewHost* render_view_host,
+ const IPC::Message& message) override;
+ const GURL& GetMainFrameLastCommittedURL() const override;
+ void RenderViewTerminated(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code) override;
+ RendererPreferences GetRendererPrefs(
+ BrowserContext* browser_context) const override;
+ WebPreferences ComputeWebkitPrefs() override;
+ gfx::Rect GetRootWindowResizerRect() const override;
+ void CreateNewWindow(
int render_process_id,
int route_id,
int main_frame_route_id,
const ViewHostMsg_CreateWindow_Params& params,
- SessionStorageNamespace* session_storage_namespace) OVERRIDE;
- virtual void CreateNewWidget(int render_process_id,
- int route_id,
- blink::WebPopupType popup_type) OVERRIDE;
- virtual void CreateNewFullscreenWidget(int render_process_id,
- int route_id) OVERRIDE;
- virtual void ShowCreatedWindow(int route_id,
- WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
- bool user_gesture) OVERRIDE;
- virtual void ShowCreatedWidget(int route_id,
- const gfx::Rect& initial_pos) OVERRIDE;
- virtual void ShowCreatedFullscreenWidget(int route_id) OVERRIDE;
-
- virtual SessionStorageNamespace* GetSessionStorageNamespace(
- SiteInstance* instance) OVERRIDE;
-
- virtual FrameTree* GetFrameTree() OVERRIDE;
+ SessionStorageNamespace* session_storage_namespace) override;
+ void CreateNewWidget(int render_process_id,
+ int route_id,
+ blink::WebPopupType popup_type) override;
+ void CreateNewFullscreenWidget(int render_process_id, int route_id) override;
+ void ShowCreatedWindow(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) override;
+ void ShowCreatedWidget(int route_id, const gfx::Rect& initial_pos) override;
+ void ShowCreatedFullscreenWidget(int route_id) override;
+
+ SessionStorageNamespace* GetSessionStorageNamespace(
+ SiteInstance* instance) override;
+
+ FrameTree* GetFrameTree() override;
// RenderWidgetHostDelegate implementation:
- virtual void RenderWidgetDeleted(
- RenderWidgetHostImpl* render_widget_host) OVERRIDE;
- virtual bool PreHandleKeyboardEvent(
- const NativeWebKeyboardEvent& event,
- bool* is_keyboard_shortcut) OVERRIDE;
- virtual void HandleKeyboardEvent(
- const NativeWebKeyboardEvent& event) OVERRIDE;
+ void RenderWidgetDeleted(RenderWidgetHostImpl* render_widget_host) override;
+ bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) override;
+ void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) override;
#if defined(OS_WIN)
- virtual gfx::NativeViewAccessible GetParentNativeViewAccessible() OVERRIDE;
+ virtual gfx::NativeViewAccessible GetParentNativeViewAccessible() override;
#endif
bool enabled() const { return enabled_; }
WebContents* web_contents() const;
const GURL& url() const { return url_; }
- // Creates the RenderViewHost containing the interstitial content.
- // Overriden in unit tests.
- virtual RenderViewHost* CreateRenderViewHost();
-
// Creates the WebContentsView that shows the interstitial RVH.
// Overriden in unit tests.
virtual WebContentsView* CreateWebContentsView();
@@ -185,6 +168,27 @@ class CONTENT_EXPORT InterstitialPageImpl
private:
class InterstitialPageRVHDelegateView;
+ class UnderlyingContentObserver : public WebContentsObserver {
+ public:
+ UnderlyingContentObserver(WebContents* web_contents,
+ InterstitialPageImpl* interstitial);
+
+ // WebContentsObserver implementation:
+ void WebContentsDestroyed() override;
+ void NavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) override;
+
+ // This observer does not override OnMessageReceived or otherwise handle
+ // messages from the underlying content, because the interstitial should not
+ // care about them. Messages from the interstitial page (which has its own
+ // FrameTree) arrive through the RenderFrameHostDelegate interface, not
+ // WebContentsObserver.
+
+ private:
+ InterstitialPageImpl* const interstitial_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnderlyingContentObserver);
+ };
// Disable the interstitial:
// - if it is not yet showing, then it won't be shown.
@@ -205,6 +209,12 @@ class CONTENT_EXPORT InterstitialPageImpl
void OnDomOperationResponse(const std::string& json_string,
int automation_id);
+ // Creates the RenderViewHost containing the interstitial content.
+ RenderViewHostImpl* CreateRenderViewHost();
+
+ // Watches the underlying WebContents for reasons to cancel the interstitial.
+ UnderlyingContentObserver underlying_content_observer_;
+
// The contents in which we are displayed. This is valid until Hide is
// called, at which point it will be set to NULL because the WebContents
// itself may be deleted.
@@ -281,10 +291,10 @@ class CONTENT_EXPORT InterstitialPageImpl
scoped_ptr<InterstitialPageDelegate> delegate_;
- base::WeakPtrFactory<InterstitialPageImpl> weak_ptr_factory_;
-
scoped_refptr<SessionStorageNamespace> session_storage_namespace_;
+ base::WeakPtrFactory<InterstitialPageImpl> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(InterstitialPageImpl);
};
diff --git a/chromium/content/browser/frame_host/interstitial_page_navigator_impl.h b/chromium/content/browser/frame_host/interstitial_page_navigator_impl.h
index 707754661e0..2f9661440c0 100644
--- a/chromium/content/browser/frame_host/interstitial_page_navigator_impl.h
+++ b/chromium/content/browser/frame_host/interstitial_page_navigator_impl.h
@@ -22,14 +22,13 @@ class CONTENT_EXPORT InterstitialPageNavigatorImpl : public Navigator {
InterstitialPageImpl* interstitial,
NavigationControllerImpl* navigation_controller);
- virtual NavigationController* GetController() OVERRIDE;
- virtual void DidNavigate(
- RenderFrameHostImpl* render_frame_host,
- const FrameHostMsg_DidCommitProvisionalLoad_Params&
- input_params) OVERRIDE;
+ NavigationController* GetController() override;
+ void DidNavigate(RenderFrameHostImpl* render_frame_host,
+ const FrameHostMsg_DidCommitProvisionalLoad_Params&
+ input_params) override;
private:
- virtual ~InterstitialPageNavigatorImpl() {}
+ ~InterstitialPageNavigatorImpl() override {}
// The InterstitialPage with which this navigator object is associated.
// Non owned pointer.
diff --git a/chromium/content/browser/frame_host/navigation_controller_android.cc b/chromium/content/browser/frame_host/navigation_controller_android.cc
index 536e17dd3ec..52ef78ee5d1 100644
--- a/chromium/content/browser/frame_host/navigation_controller_android.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_android.cc
@@ -5,10 +5,64 @@
#include "content/browser/frame_host/navigation_controller_android.h"
#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/ssl_host_state_delegate.h"
#include "jni/NavigationControllerImpl_jni.h"
+#include "ui/gfx/android/java_bitmap.h"
using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+namespace {
+
+// static
+static base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationEntry(
+ JNIEnv* env,
+ content::NavigationEntry* entry,
+ int index) {
+ DCHECK(entry);
+
+ // Get the details of the current entry
+ ScopedJavaLocalRef<jstring> j_url(
+ ConvertUTF8ToJavaString(env, entry->GetURL().spec()));
+ ScopedJavaLocalRef<jstring> j_virtual_url(
+ ConvertUTF8ToJavaString(env, entry->GetVirtualURL().spec()));
+ ScopedJavaLocalRef<jstring> j_original_url(
+ ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec()));
+ ScopedJavaLocalRef<jstring> j_title(
+ ConvertUTF16ToJavaString(env, entry->GetTitle()));
+ ScopedJavaLocalRef<jobject> j_bitmap;
+ const content::FaviconStatus& status = entry->GetFavicon();
+ if (status.valid && status.image.ToSkBitmap()->getSize() > 0)
+ j_bitmap = gfx::ConvertToJavaBitmap(status.image.ToSkBitmap());
+
+ return content::Java_NavigationControllerImpl_createNavigationEntry(
+ env,
+ index,
+ j_url.obj(),
+ j_virtual_url.obj(),
+ j_original_url.obj(),
+ j_title.obj(),
+ j_bitmap.obj());
+}
+
+static void AddNavigationEntryToHistory(JNIEnv* env,
+ jobject history,
+ content::NavigationEntry* entry,
+ int index) {
+ content::Java_NavigationControllerImpl_addToNavigationHistory(
+ env,
+ history,
+ CreateJavaNavigationEntry(env, entry, index).obj());
+}
+
+} // namespace
namespace content {
@@ -64,10 +118,208 @@ void NavigationControllerAndroid::GoToOffset(JNIEnv* env,
navigation_controller_->GoToOffset(offset);
}
+void NavigationControllerAndroid::LoadIfNecessary(JNIEnv* env, jobject obj) {
+ navigation_controller_->LoadIfNecessary();
+}
+
+void NavigationControllerAndroid::ContinuePendingReload(JNIEnv* env,
+ jobject obj) {
+ navigation_controller_->ContinuePendingReload();
+}
+
+void NavigationControllerAndroid::Reload(JNIEnv* env,
+ jobject obj,
+ jboolean check_for_repost) {
+ navigation_controller_->Reload(check_for_repost);
+}
+
+void NavigationControllerAndroid::ReloadIgnoringCache(
+ JNIEnv* env,
+ jobject obj,
+ jboolean check_for_repost) {
+ navigation_controller_->ReloadIgnoringCache(check_for_repost);
+}
+
+void NavigationControllerAndroid::RequestRestoreLoad(JNIEnv* env, jobject obj) {
+ navigation_controller_->SetNeedsReload();
+}
+
+void NavigationControllerAndroid::CancelPendingReload(JNIEnv* env,
+ jobject obj) {
+ navigation_controller_->CancelPendingReload();
+}
+
void NavigationControllerAndroid::GoToNavigationIndex(JNIEnv* env,
jobject obj,
jint index) {
navigation_controller_->GoToIndex(index);
}
+void NavigationControllerAndroid::LoadUrl(JNIEnv* env,
+ jobject obj,
+ jstring url,
+ jint load_url_type,
+ jint transition_type,
+ jstring j_referrer_url,
+ jint referrer_policy,
+ jint ua_override_option,
+ jstring extra_headers,
+ jbyteArray post_data,
+ jstring base_url_for_data_url,
+ jstring virtual_url_for_data_url,
+ jboolean can_load_local_resources,
+ jboolean is_renderer_initiated) {
+ DCHECK(url);
+ NavigationController::LoadURLParams params(
+ GURL(ConvertJavaStringToUTF8(env, url)));
+
+ params.load_type =
+ static_cast<NavigationController::LoadURLType>(load_url_type);
+ params.transition_type = ui::PageTransitionFromInt(transition_type);
+ params.override_user_agent =
+ static_cast<NavigationController::UserAgentOverrideOption>(
+ ua_override_option);
+ params.can_load_local_resources = can_load_local_resources;
+ params.is_renderer_initiated = is_renderer_initiated;
+
+ if (extra_headers)
+ params.extra_headers = ConvertJavaStringToUTF8(env, extra_headers);
+
+ if (post_data) {
+ std::vector<uint8> http_body_vector;
+ base::android::JavaByteArrayToByteVector(env, post_data, &http_body_vector);
+ params.browser_initiated_post_data =
+ base::RefCountedBytes::TakeVector(&http_body_vector);
+ }
+
+ if (base_url_for_data_url) {
+ params.base_url_for_data_url =
+ GURL(ConvertJavaStringToUTF8(env, base_url_for_data_url));
+ }
+
+ if (virtual_url_for_data_url) {
+ params.virtual_url_for_data_url =
+ GURL(ConvertJavaStringToUTF8(env, virtual_url_for_data_url));
+ }
+
+ if (j_referrer_url) {
+ params.referrer = content::Referrer(
+ GURL(ConvertJavaStringToUTF8(env, j_referrer_url)),
+ static_cast<blink::WebReferrerPolicy>(referrer_policy));
+ }
+
+ navigation_controller_->LoadURLWithParams(params);
+}
+
+void NavigationControllerAndroid::ClearHistory(JNIEnv* env, jobject obj) {
+ // TODO(creis): Do callers of this need to know if it fails?
+ if (navigation_controller_->CanPruneAllButLastCommitted())
+ navigation_controller_->PruneAllButLastCommitted();
+}
+
+jint NavigationControllerAndroid::GetNavigationHistory(JNIEnv* env,
+ jobject obj,
+ jobject history) {
+ // Iterate through navigation entries to populate the list
+ int count = navigation_controller_->GetEntryCount();
+ for (int i = 0; i < count; ++i) {
+ AddNavigationEntryToHistory(
+ env, history, navigation_controller_->GetEntryAtIndex(i), i);
+ }
+
+ return navigation_controller_->GetCurrentEntryIndex();
+}
+
+void NavigationControllerAndroid::GetDirectedNavigationHistory(
+ JNIEnv* env,
+ jobject obj,
+ jobject history,
+ jboolean is_forward,
+ jint max_entries) {
+ // Iterate through navigation entries to populate the list
+ int count = navigation_controller_->GetEntryCount();
+ int num_added = 0;
+ int increment_value = is_forward ? 1 : -1;
+ for (int i = navigation_controller_->GetCurrentEntryIndex() + increment_value;
+ i >= 0 && i < count;
+ i += increment_value) {
+ if (num_added >= max_entries)
+ break;
+
+ AddNavigationEntryToHistory(
+ env, history, navigation_controller_->GetEntryAtIndex(i), i);
+ num_added++;
+ }
+}
+
+ScopedJavaLocalRef<jstring>
+NavigationControllerAndroid::GetOriginalUrlForVisibleNavigationEntry(
+ JNIEnv* env,
+ jobject obj) {
+ NavigationEntry* entry = navigation_controller_->GetVisibleEntry();
+ if (entry == NULL)
+ return ScopedJavaLocalRef<jstring>(env, NULL);
+ return ConvertUTF8ToJavaString(env, entry->GetOriginalRequestURL().spec());
+}
+
+void NavigationControllerAndroid::ClearSslPreferences(JNIEnv* env,
+ jobject obj) {
+ content::SSLHostStateDelegate* delegate =
+ navigation_controller_->GetBrowserContext()->GetSSLHostStateDelegate();
+ if (delegate)
+ delegate->Clear();
+}
+
+bool NavigationControllerAndroid::GetUseDesktopUserAgent(JNIEnv* env,
+ jobject obj) {
+ NavigationEntry* entry = navigation_controller_->GetVisibleEntry();
+ return entry && entry->GetIsOverridingUserAgent();
+}
+
+void NavigationControllerAndroid::SetUseDesktopUserAgent(
+ JNIEnv* env,
+ jobject obj,
+ jboolean enabled,
+ jboolean reload_on_state_change) {
+ if (GetUseDesktopUserAgent(env, obj) == enabled)
+ return;
+
+ // Make sure the navigation entry actually exists.
+ NavigationEntry* entry = navigation_controller_->GetVisibleEntry();
+ if (!entry)
+ return;
+
+ // Set the flag in the NavigationEntry.
+ entry->SetIsOverridingUserAgent(enabled);
+
+ // Send the override to the renderer.
+ if (reload_on_state_change) {
+ // Reloading the page will send the override down as part of the
+ // navigation IPC message.
+ navigation_controller_->ReloadOriginalRequestURL(false);
+ }
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+NavigationControllerAndroid::GetPendingEntry(JNIEnv* env, jobject obj) {
+ content::NavigationEntry* entry = navigation_controller_->GetPendingEntry();
+
+ if (!entry)
+ return base::android::ScopedJavaLocalRef<jobject>();
+
+ return CreateJavaNavigationEntry(
+ env, entry, navigation_controller_->GetPendingEntryIndex());
+}
+
+jint NavigationControllerAndroid::GetLastCommittedEntryIndex(JNIEnv* env,
+ jobject obj) {
+ return navigation_controller_->GetLastCommittedEntryIndex();
+}
+
+jboolean NavigationControllerAndroid::RemoveEntryAtIndex(JNIEnv* env,
+ jobject obj,
+ jint index) {
+ return navigation_controller_->RemoveEntryAtIndex(index);
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_controller_android.h b/chromium/content/browser/frame_host/navigation_controller_android.h
index e0c96a63a0c..9b9a8c67062 100644
--- a/chromium/content/browser/frame_host/navigation_controller_android.h
+++ b/chromium/content/browser/frame_host/navigation_controller_android.h
@@ -39,7 +39,46 @@ class CONTENT_EXPORT NavigationControllerAndroid {
void GoBack(JNIEnv* env, jobject obj);
void GoForward(JNIEnv* env, jobject obj);
void GoToOffset(JNIEnv* env, jobject obj, jint offset);
+ void LoadIfNecessary(JNIEnv* env, jobject obj);
+ void ContinuePendingReload(JNIEnv* env, jobject obj);
+ void Reload(JNIEnv* env, jobject obj, jboolean check_for_repost);
+ void ReloadIgnoringCache(JNIEnv* env, jobject obj, jboolean check_for_repost);
+ void RequestRestoreLoad(JNIEnv* env, jobject obj);
+ void CancelPendingReload(JNIEnv* env, jobject obj);
void GoToNavigationIndex(JNIEnv* env, jobject obj, jint index);
+ void LoadUrl(JNIEnv* env,
+ jobject obj,
+ jstring url,
+ jint load_url_type,
+ jint transition_type,
+ jstring j_referrer_url,
+ jint referrer_policy,
+ jint ua_override_option,
+ jstring extra_headers,
+ jbyteArray post_data,
+ jstring base_url_for_data_url,
+ jstring virtual_url_for_data_url,
+ jboolean can_load_local_resources,
+ jboolean is_renderer_initiated);
+ void ClearSslPreferences(JNIEnv* env, jobject /* obj */);
+ bool GetUseDesktopUserAgent(JNIEnv* env, jobject /* obj */);
+ void SetUseDesktopUserAgent(JNIEnv* env,
+ jobject /* obj */,
+ jboolean state,
+ jboolean reload_on_state_change);
+ base::android::ScopedJavaLocalRef<jobject> GetPendingEntry(JNIEnv* env,
+ jobject /* obj */);
+ int GetNavigationHistory(JNIEnv* env, jobject obj, jobject history);
+ void GetDirectedNavigationHistory(JNIEnv* env,
+ jobject obj,
+ jobject history,
+ jboolean is_forward,
+ jint max_entries);
+ base::android::ScopedJavaLocalRef<jstring>
+ GetOriginalUrlForVisibleNavigationEntry(JNIEnv* env, jobject obj);
+ void ClearHistory(JNIEnv* env, jobject obj);
+ int GetLastCommittedEntryIndex(JNIEnv* env, jobject obj);
+ jboolean RemoveEntryAtIndex(JNIEnv* env, jobject obj, jint index);
private:
NavigationController* navigation_controller_;
diff --git a/chromium/content/browser/frame_host/navigation_controller_delegate.h b/chromium/content/browser/frame_host/navigation_controller_delegate.h
index 49dfc60bef0..52567ef3c62 100644
--- a/chromium/content/browser/frame_host/navigation_controller_delegate.h
+++ b/chromium/content/browser/frame_host/navigation_controller_delegate.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_DELEGATE_H_
#include <string>
+#include "content/public/browser/invalidate_type.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_details.h"
@@ -34,7 +35,7 @@ class NavigationControllerDelegate {
virtual RenderViewHost* GetRenderViewHost() const = 0;
virtual InterstitialPage* GetInterstitialPage() const = 0;
virtual const std::string& GetContentsMimeType() const = 0;
- virtual void NotifyNavigationStateChanged(unsigned changed_flags) = 0;
+ virtual void NotifyNavigationStateChanged(InvalidateTypes changed_flags) = 0;
virtual void Stop() = 0;
virtual SiteInstance* GetPendingSiteInstance() const = 0;
virtual int32 GetMaxPageID() = 0;
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl.cc b/chromium/content/browser/frame_host/navigation_controller_impl.cc
index 6d1c597d760..4be5a3ce4a0 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl.cc
@@ -46,8 +46,6 @@
namespace content {
namespace {
-const int kInvalidateAll = 0xFFFFFFFF;
-
// Invoked when entries have been pruned, or removed. For example, if the
// current entries are [google, digg, yahoo], with the current entry google,
// and the user types in cnet, then digg and yahoo are pruned.
@@ -97,31 +95,44 @@ void ConfigureEntriesForRestore(
for (size_t i = 0; i < entries->size(); ++i) {
// Use a transition type of reload so that we don't incorrectly increase
// the typed count.
- (*entries)[i]->SetTransitionType(PAGE_TRANSITION_RELOAD);
+ (*entries)[i]->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
(*entries)[i]->set_restore_type(ControllerRestoreTypeToEntryType(type));
// NOTE(darin): This code is only needed for backwards compat.
SetPageStateIfEmpty((*entries)[i].get());
}
}
-// See NavigationController::IsURLInPageNavigation for how this works and why.
+// There are two general cases where a navigation is in page:
+// 1. A fragment navigation, in which the url is kept the same except for the
+// reference fragment.
+// 2. A history API navigation (pushState and replaceState). This case is
+// always in-page, but the urls are not guaranteed to match excluding the
+// fragment. The relevant spec allows pushState/replaceState to any URL on
+// the same origin.
+// However, due to reloads, even identical urls are *not* guaranteed to be
+// in-page navigations, we have to trust the renderer almost entirely.
+// The one thing we do know is that cross-origin navigations will *never* be
+// in-page. Therefore, trust the renderer if the URLs are on the same origin,
+// and assume the renderer is malicious if a cross-origin navigation claims to
+// be in-page.
bool AreURLsInPageNavigation(const GURL& existing_url,
const GURL& new_url,
bool renderer_says_in_page,
- NavigationType navigation_type) {
- if (existing_url.GetOrigin() == new_url.GetOrigin())
- return renderer_says_in_page;
-
- if (!new_url.has_ref()) {
- // When going back from the ref URL to the non ref one the navigation type
- // is IN_PAGE.
- return navigation_type == NAVIGATION_TYPE_IN_PAGE;
- }
-
- url::Replacements<char> replacements;
- replacements.ClearRef();
- return existing_url.ReplaceComponents(replacements) ==
- new_url.ReplaceComponents(replacements);
+ RenderFrameHost* rfh) {
+ WebPreferences prefs = rfh->GetRenderViewHost()->GetWebkitPreferences();
+ bool is_same_origin = existing_url.is_empty() ||
+ // TODO(japhet): We should only permit navigations
+ // originating from about:blank to be in-page if the
+ // about:blank is the first document that frame loaded.
+ // We don't have sufficient information to identify
+ // that case at the moment, so always allow about:blank
+ // for now.
+ existing_url == GURL(url::kAboutBlankURL) ||
+ existing_url.GetOrigin() == new_url.GetOrigin() ||
+ !prefs.web_security_enabled;
+ if (!is_same_origin && renderer_says_in_page)
+ rfh->GetProcess()->ReceivedBadMessage();
+ return is_same_origin && renderer_says_in_page;
}
// Determines whether or not we should be carrying over a user agent override
@@ -134,7 +145,7 @@ bool ShouldKeepOverride(const NavigationEntry* last_entry) {
// NavigationControllerImpl ----------------------------------------------------
-const size_t kMaxEntryCountForTestingNotSet = -1;
+const size_t kMaxEntryCountForTestingNotSet = static_cast<size_t>(-1);
// static
size_t NavigationControllerImpl::max_entry_count_for_testing_ =
@@ -148,7 +159,7 @@ static bool g_check_for_repost = true;
NavigationEntry* NavigationController::CreateNavigationEntry(
const GURL& url,
const Referrer& referrer,
- PageTransition transition,
+ ui::PageTransition transition,
bool is_renderer_initiated,
const std::string& extra_headers,
BrowserContext* browser_context) {
@@ -277,7 +288,7 @@ void NavigationControllerImpl::ReloadInternal(bool check_for_repost,
return;
LoadURL(transient_entry->GetURL(),
Referrer(),
- PAGE_TRANSITION_RELOAD,
+ ui::PAGE_TRANSITION_RELOAD,
transient_entry->extra_headers());
return;
}
@@ -365,7 +376,7 @@ void NavigationControllerImpl::ReloadInternal(bool check_for_repost,
// See Chromium issue 96041.
pending_entry_->SetTitle(base::string16());
- pending_entry_->SetTransitionType(PAGE_TRANSITION_RELOAD);
+ pending_entry_->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
}
NavigateToPendingEntry(reload_type);
@@ -541,9 +552,9 @@ void NavigationControllerImpl::GoBack() {
pending_entry_index_ = current_index - 1;
entries_[pending_entry_index_]->SetTransitionType(
- PageTransitionFromInt(
+ ui::PageTransitionFromInt(
entries_[pending_entry_index_]->GetTransitionType() |
- PAGE_TRANSITION_FORWARD_BACK));
+ ui::PAGE_TRANSITION_FORWARD_BACK));
NavigateToPendingEntry(NO_RELOAD);
}
@@ -567,9 +578,9 @@ void NavigationControllerImpl::GoForward() {
pending_entry_index_++;
entries_[pending_entry_index_]->SetTransitionType(
- PageTransitionFromInt(
+ ui::PageTransitionFromInt(
entries_[pending_entry_index_]->GetTransitionType() |
- PAGE_TRANSITION_FORWARD_BACK));
+ ui::PAGE_TRANSITION_FORWARD_BACK));
NavigateToPendingEntry(NO_RELOAD);
}
@@ -594,9 +605,9 @@ void NavigationControllerImpl::GoToIndex(int index) {
pending_entry_index_ = index;
entries_[pending_entry_index_]->SetTransitionType(
- PageTransitionFromInt(
+ ui::PageTransitionFromInt(
entries_[pending_entry_index_]->GetTransitionType() |
- PAGE_TRANSITION_FORWARD_BACK));
+ ui::PAGE_TRANSITION_FORWARD_BACK));
NavigateToPendingEntry(NO_RELOAD);
}
@@ -628,7 +639,7 @@ void NavigationControllerImpl::UpdateVirtualURLToURL(
void NavigationControllerImpl::LoadURL(
const GURL& url,
const Referrer& referrer,
- PageTransition transition,
+ ui::PageTransition transition,
const std::string& extra_headers) {
LoadURLParams params(url);
params.referrer = referrer;
@@ -638,9 +649,16 @@ void NavigationControllerImpl::LoadURL(
}
void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
- TRACE_EVENT0("browser", "NavigationControllerImpl::LoadURLWithParams");
- if (HandleDebugURL(params.url, params.transition_type))
- return;
+ TRACE_EVENT1("browser,navigation",
+ "NavigationControllerImpl::LoadURLWithParams",
+ "url", params.url.possibly_invalid_spec());
+ if (HandleDebugURL(params.url, params.transition_type)) {
+ // If Telemetry is running, allow the URL load to proceed as if it's
+ // unhandled, otherwise Telemetry can't tell if Navigation completed.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ cc::switches::kEnableGpuBenchmarking))
+ return;
+ }
// Any renderer-side debug URLs or javascript: URLs should be ignored if the
// renderer process is not live, unless it is the initial navigation of the
@@ -766,8 +784,8 @@ bool NavigationControllerImpl::RendererDidNavigate(
details->type = ClassifyNavigation(rfh, params);
// is_in_page must be computed before the entry gets committed.
- details->is_in_page = IsURLInPageNavigation(
- params.url, params.was_within_same_page, details->type);
+ details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(),
+ params.url, params.was_within_same_page, rfh);
switch (details->type) {
case NAVIGATION_TYPE_NEW_PAGE:
@@ -842,7 +860,7 @@ bool NavigationControllerImpl::RendererDidNavigate(
// The active entry's SiteInstance should match our SiteInstance.
// TODO(creis): This check won't pass for subframes until we create entries
// for subframe navigations.
- if (PageTransitionIsMainFrame(params.transition))
+ if (ui::PageTransitionIsMainFrame(params.transition))
CHECK(active_entry->site_instance() == rfh->GetSiteInstance());
// Remember the bindings the renderer process has at this point, so that
@@ -853,7 +871,7 @@ bool NavigationControllerImpl::RendererDidNavigate(
// Now prep the rest of the details for the notification and broadcast.
details->entry = active_entry;
details->is_main_frame =
- PageTransitionIsMainFrame(params.transition);
+ ui::PageTransitionIsMainFrame(params.transition);
details->serialized_security_info = params.security_info;
details->http_status_code = params.http_status_code;
NotifyNavigationEntryCommitted(details);
@@ -865,6 +883,15 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
RenderFrameHost* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const {
if (params.page_id == -1) {
+ // TODO(nasko, creis): An out-of-process child frame has no way of
+ // knowing the page_id of its parent, so it is passing back -1. The
+ // semantics here should be re-evaluated during session history refactor
+ // (see http://crbug.com/236848). For now, we assume this means the
+ // child frame loaded and proceed. Note that this may do the wrong thing
+ // for cross-process AUTO_SUBFRAME navigations.
+ if (rfh->IsCrossProcessSubframe())
+ return NAVIGATION_TYPE_NEW_SUBFRAME;
+
// The renderer generates the page IDs, and so if it gives us the invalid
// page ID (-1) we know it didn't actually navigate. This happens in a few
// cases:
@@ -891,7 +918,7 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
// Greater page IDs than we've ever seen before are new pages. We may or may
// not have a pending entry for the page, and this may or may not be the
// main frame.
- if (PageTransitionIsMainFrame(params.transition))
+ if (ui::PageTransitionIsMainFrame(params.transition))
return NAVIGATION_TYPE_NEW_PAGE;
// When this is a new subframe navigation, we should have a committed page
@@ -956,7 +983,7 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
}
NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
- if (!PageTransitionIsMainFrame(params.transition)) {
+ if (!ui::PageTransitionIsMainFrame(params.transition)) {
// All manual subframes would get new IDs and were handled above, so we
// know this is auto. Since the current page was found in the navigation
// entry list, we're guaranteed to have a last committed entry.
@@ -986,8 +1013,7 @@ NavigationType NavigationControllerImpl::ClassifyNavigation(
// navigations that don't actually navigate, but it can happen when there is
// an encoding override (it always sends a navigation request).
if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
- params.was_within_same_page,
- NAVIGATION_TYPE_UNKNOWN)) {
+ params.was_within_same_page, rfh)) {
return NAVIGATION_TYPE_IN_PAGE;
}
@@ -1023,18 +1049,8 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
// update the virtual URL when replaceState is called after a pushState.
GURL url = params.url;
bool needs_update = false;
- // We call RewriteURLIfNecessary twice: once when page navigation
- // begins in CreateNavigationEntry, and once here when it commits.
- // With the kEnableGpuBenchmarking flag, the rewriting includes
- // handling debug URLs which cause an action to occur, and thus we
- // should not rewrite them a second time.
- bool skip_rewrite =
- IsDebugURL(url) && base::CommandLine::ForCurrentProcess()->HasSwitch(
- cc::switches::kEnableGpuBenchmarking);
- if (!skip_rewrite) {
- BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
- &url, browser_context_, &needs_update);
- }
+ BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
+ &url, browser_context_, &needs_update);
new_entry->set_update_virtual_url_with_url(needs_update);
// When navigating to a new page, give the browser URL handler a chance to
@@ -1044,6 +1060,8 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
update_virtual_url = needs_update;
}
+ if (params.url_is_unreachable)
+ new_entry->set_page_type(PAGE_TYPE_ERROR);
new_entry->SetURL(params.url);
if (update_virtual_url)
UpdateVirtualURLToURL(new_entry, params.url);
@@ -1059,9 +1077,11 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
// history.pushState() is classified as a navigation to a new page, but
// sets was_within_same_page to true. In this case, we already have the
- // title available, so set it immediately.
- if (params.was_within_same_page && GetLastCommittedEntry())
+ // title and favicon available, so set them immediately.
+ if (params.was_within_same_page && GetLastCommittedEntry()) {
new_entry->SetTitle(GetLastCommittedEntry()->GetTitle());
+ new_entry->GetFavicon() = GetLastCommittedEntry()->GetFavicon();
+ }
DCHECK(!params.history_list_was_cleared || !replace_entry);
// The browser requested to clear the session history when it initiated the
@@ -1080,7 +1100,7 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage(
RenderFrameHost* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
// We should only get here for main frame navigations.
- DCHECK(PageTransitionIsMainFrame(params.transition));
+ DCHECK(ui::PageTransitionIsMainFrame(params.transition));
// This is a back/forward navigation. The existing page for the ID is
// guaranteed to exist by ClassifyNavigation, and we just need to update it
@@ -1099,7 +1119,7 @@ void NavigationControllerImpl::RendererDidNavigateToExistingPage(
// The redirected to page should not inherit the favicon from the previous
// page.
- if (PageTransitionIsRedirect(params.transition))
+ if (ui::PageTransitionIsRedirect(params.transition))
entry->GetFavicon() = FaviconStatus();
// The site instance will normally be the same except during session restore,
@@ -1160,7 +1180,7 @@ void NavigationControllerImpl::RendererDidNavigateInPage(
RenderFrameHost* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
bool* did_replace_entry) {
- DCHECK(PageTransitionIsMainFrame(params.transition)) <<
+ DCHECK(ui::PageTransitionIsMainFrame(params.transition)) <<
"WebKit should only tell us about in-page navs for the main frame.";
// We're guaranteed to have an entry for this one.
NavigationEntryImpl* existing_entry = GetEntryWithPageID(
@@ -1191,8 +1211,8 @@ void NavigationControllerImpl::RendererDidNavigateInPage(
void NavigationControllerImpl::RendererDidNavigateNewSubframe(
RenderFrameHost* rfh,
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
- if (PageTransitionCoreTypeIs(params.transition,
- PAGE_TRANSITION_AUTO_SUBFRAME)) {
+ if (ui::PageTransitionCoreTypeIs(params.transition,
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME)) {
// This is not user-initiated. Ignore.
DiscardNonCommittedEntriesInternal();
return;
@@ -1253,10 +1273,10 @@ int NavigationControllerImpl::GetIndexOfEntry(
bool NavigationControllerImpl::IsURLInPageNavigation(
const GURL& url,
bool renderer_says_in_page,
- NavigationType navigation_type) const {
+ RenderFrameHost* rfh) const {
NavigationEntry* last_committed = GetLastCommittedEntry();
return last_committed && AreURLsInPageNavigation(
- last_committed->GetURL(), url, renderer_says_in_page, navigation_type);
+ last_committed->GetURL(), url, renderer_says_in_page, rfh);
}
void NavigationControllerImpl::CopyStateFrom(
@@ -1509,7 +1529,7 @@ void NavigationControllerImpl::DiscardNonCommittedEntries() {
// If there was a transient entry, invalidate everything so the new active
// entry state is shown.
if (transient) {
- delegate_->NotifyNavigationStateChanged(kInvalidateAll);
+ delegate_->NotifyNavigationStateChanged(INVALIDATE_TYPE_ALL);
}
}
@@ -1523,7 +1543,7 @@ int NavigationControllerImpl::GetPendingEntryIndex() const {
void NavigationControllerImpl::InsertOrReplaceEntry(NavigationEntryImpl* entry,
bool replace) {
- DCHECK(entry->GetTransitionType() != PAGE_TRANSITION_AUTO_SUBFRAME);
+ DCHECK(entry->GetTransitionType() != ui::PAGE_TRANSITION_AUTO_SUBFRAME);
// Copy the pending entry's unique ID to the committed entry.
// I don't know if pending_entry_index_ can be other than -1 here.
@@ -1588,7 +1608,7 @@ void NavigationControllerImpl::NavigateToPendingEntry(ReloadType reload_type) {
(entries_[pending_entry_index_]->restore_type() ==
NavigationEntryImpl::RESTORE_NONE) &&
(entries_[pending_entry_index_]->GetTransitionType() &
- PAGE_TRANSITION_FORWARD_BACK)) {
+ ui::PAGE_TRANSITION_FORWARD_BACK)) {
delegate_->Stop();
// If an interstitial page is showing, we want to close it to get back
@@ -1643,7 +1663,7 @@ void NavigationControllerImpl::NotifyNavigationEntryCommitted(
// when it wants to draw. See http://crbug.com/11157
ssl_manager_.DidCommitProvisionalLoad(*details);
- delegate_->NotifyNavigationStateChanged(kInvalidateAll);
+ delegate_->NotifyNavigationStateChanged(INVALIDATE_TYPE_ALL);
delegate_->NotifyNavigationEntryCommitted(*details);
// TODO(avi): Remove. http://crbug.com/170921
@@ -1752,7 +1772,7 @@ void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) {
entries_.begin() + index, linked_ptr<NavigationEntryImpl>(
NavigationEntryImpl::FromNavigationEntry(entry)));
transient_entry_index_ = index;
- delegate_->NotifyNavigationStateChanged(kInvalidateAll);
+ delegate_->NotifyNavigationStateChanged(INVALIDATE_TYPE_ALL);
}
void NavigationControllerImpl::InsertEntriesFrom(
diff --git a/chromium/content/browser/frame_host/navigation_controller_impl.h b/chromium/content/browser/frame_host/navigation_controller_impl.h
index 7a06ba663b6..a646646f35f 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl.h
+++ b/chromium/content/browser/frame_host/navigation_controller_impl.h
@@ -31,68 +31,63 @@ class CONTENT_EXPORT NavigationControllerImpl
NavigationControllerImpl(
NavigationControllerDelegate* delegate,
BrowserContext* browser_context);
- virtual ~NavigationControllerImpl();
+ ~NavigationControllerImpl() override;
// NavigationController implementation:
- virtual WebContents* GetWebContents() const OVERRIDE;
- virtual BrowserContext* GetBrowserContext() const OVERRIDE;
- virtual void SetBrowserContext(
- BrowserContext* browser_context) OVERRIDE;
- virtual void Restore(
- int selected_navigation,
- RestoreType type,
- std::vector<NavigationEntry*>* entries) OVERRIDE;
- virtual NavigationEntry* GetActiveEntry() const OVERRIDE;
- virtual NavigationEntry* GetVisibleEntry() const OVERRIDE;
- virtual int GetCurrentEntryIndex() const OVERRIDE;
- virtual NavigationEntry* GetLastCommittedEntry() const OVERRIDE;
- virtual int GetLastCommittedEntryIndex() const OVERRIDE;
- virtual bool CanViewSource() const OVERRIDE;
- virtual int GetEntryCount() const OVERRIDE;
- virtual NavigationEntry* GetEntryAtIndex(int index) const OVERRIDE;
- virtual NavigationEntry* GetEntryAtOffset(int offset) const OVERRIDE;
- virtual void DiscardNonCommittedEntries() OVERRIDE;
- virtual NavigationEntry* GetPendingEntry() const OVERRIDE;
- virtual int GetPendingEntryIndex() const OVERRIDE;
- virtual NavigationEntry* GetTransientEntry() const OVERRIDE;
- virtual void SetTransientEntry(NavigationEntry* entry) OVERRIDE;
- virtual void LoadURL(const GURL& url,
- const Referrer& referrer,
- PageTransition type,
- const std::string& extra_headers) OVERRIDE;
- virtual void LoadURLWithParams(const LoadURLParams& params) OVERRIDE;
- virtual void LoadIfNecessary() OVERRIDE;
- virtual bool CanGoBack() const OVERRIDE;
- virtual bool CanGoForward() const OVERRIDE;
- virtual bool CanGoToOffset(int offset) const OVERRIDE;
- virtual void GoBack() OVERRIDE;
- virtual void GoForward() OVERRIDE;
- virtual void GoToIndex(int index) OVERRIDE;
- virtual void GoToOffset(int offset) OVERRIDE;
- virtual bool RemoveEntryAtIndex(int index) OVERRIDE;
- virtual const SessionStorageNamespaceMap&
- GetSessionStorageNamespaceMap() const OVERRIDE;
- virtual SessionStorageNamespace*
- GetDefaultSessionStorageNamespace() OVERRIDE;
- virtual void SetMaxRestoredPageID(int32 max_id) OVERRIDE;
- virtual int32 GetMaxRestoredPageID() const OVERRIDE;
- virtual bool NeedsReload() const OVERRIDE;
- virtual void SetNeedsReload() OVERRIDE;
- virtual void CancelPendingReload() OVERRIDE;
- virtual void ContinuePendingReload() OVERRIDE;
- virtual bool IsInitialNavigation() const OVERRIDE;
- virtual void Reload(bool check_for_repost) OVERRIDE;
- virtual void ReloadIgnoringCache(bool check_for_repost) OVERRIDE;
- virtual void ReloadOriginalRequestURL(bool check_for_repost) OVERRIDE;
- virtual void NotifyEntryChanged(const NavigationEntry* entry,
- int index) OVERRIDE;
- virtual void CopyStateFrom(
- const NavigationController& source) OVERRIDE;
- virtual void CopyStateFromAndPrune(NavigationController* source,
- bool replace_entry) OVERRIDE;
- virtual bool CanPruneAllButLastCommitted() OVERRIDE;
- virtual void PruneAllButLastCommitted() OVERRIDE;
- virtual void ClearAllScreenshots() OVERRIDE;
+ WebContents* GetWebContents() const override;
+ BrowserContext* GetBrowserContext() const override;
+ void SetBrowserContext(BrowserContext* browser_context) override;
+ void Restore(int selected_navigation,
+ RestoreType type,
+ std::vector<NavigationEntry*>* entries) override;
+ NavigationEntry* GetActiveEntry() const override;
+ NavigationEntry* GetVisibleEntry() const override;
+ int GetCurrentEntryIndex() const override;
+ NavigationEntry* GetLastCommittedEntry() const override;
+ int GetLastCommittedEntryIndex() const override;
+ bool CanViewSource() const override;
+ int GetEntryCount() const override;
+ NavigationEntry* GetEntryAtIndex(int index) const override;
+ NavigationEntry* GetEntryAtOffset(int offset) const override;
+ void DiscardNonCommittedEntries() override;
+ NavigationEntry* GetPendingEntry() const override;
+ int GetPendingEntryIndex() const override;
+ NavigationEntry* GetTransientEntry() const override;
+ void SetTransientEntry(NavigationEntry* entry) override;
+ void LoadURL(const GURL& url,
+ const Referrer& referrer,
+ ui::PageTransition type,
+ const std::string& extra_headers) override;
+ void LoadURLWithParams(const LoadURLParams& params) override;
+ void LoadIfNecessary() override;
+ bool CanGoBack() const override;
+ bool CanGoForward() const override;
+ bool CanGoToOffset(int offset) const override;
+ void GoBack() override;
+ void GoForward() override;
+ void GoToIndex(int index) override;
+ void GoToOffset(int offset) override;
+ bool RemoveEntryAtIndex(int index) override;
+ const SessionStorageNamespaceMap& GetSessionStorageNamespaceMap()
+ const override;
+ SessionStorageNamespace* GetDefaultSessionStorageNamespace() override;
+ void SetMaxRestoredPageID(int32 max_id) override;
+ int32 GetMaxRestoredPageID() const override;
+ bool NeedsReload() const override;
+ void SetNeedsReload() override;
+ void CancelPendingReload() override;
+ void ContinuePendingReload() override;
+ bool IsInitialNavigation() const override;
+ void Reload(bool check_for_repost) override;
+ void ReloadIgnoringCache(bool check_for_repost) override;
+ void ReloadOriginalRequestURL(bool check_for_repost) override;
+ void NotifyEntryChanged(const NavigationEntry* entry, int index) override;
+ void CopyStateFrom(const NavigationController& source) override;
+ void CopyStateFromAndPrune(NavigationController* source,
+ bool replace_entry) override;
+ bool CanPruneAllButLastCommitted() override;
+ void PruneAllButLastCommitted() override;
+ void ClearAllScreenshots() override;
// Whether this is the initial navigation in an unmodified new tab. In this
// case, we know there is no content displayed in the page.
@@ -167,7 +162,7 @@ class CONTENT_EXPORT NavigationControllerImpl
bool IsURLInPageNavigation(
const GURL& url,
bool renderer_says_in_page,
- NavigationType navigation_type) const;
+ RenderFrameHost* rfh) const;
// Sets the SessionStorageNamespace for the given |partition_id|. This is
// used during initialization of a new NavigationController to allow
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 956288c33d9..ae7ad90f1e4 100644
--- a/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -4,9 +4,8 @@
#include "base/basictypes.h"
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/memory/scoped_ptr.h"
-#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -31,6 +30,7 @@
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_notification_tracker.h"
#include "content/public/test/test_utils.h"
+#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"
@@ -44,8 +44,7 @@ namespace {
// Creates an image with a 1x1 SkBitmap of the specified |color|.
gfx::Image CreateImage(SkColor color) {
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(color);
return gfx::Image::CreateFrom1xBitmap(bitmap);
}
@@ -74,13 +73,12 @@ class MockScreenshotManager : public content::NavigationEntryScreenshotManager {
encoding_screenshot_in_progress_(false) {
}
- virtual ~MockScreenshotManager() {
- }
+ ~MockScreenshotManager() override {}
void TakeScreenshotFor(content::NavigationEntryImpl* entry) {
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- bitmap.allocPixels();
+ bitmap.allocPixels(SkImageInfo::Make(
+ 1, 1, kAlpha_8_SkColorType, kPremul_SkAlphaType));
bitmap.eraseARGB(0, 0, 0, 0);
encoding_screenshot_in_progress_ = true;
OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
@@ -100,12 +98,10 @@ class MockScreenshotManager : public content::NavigationEntryScreenshotManager {
private:
// Overridden from content::NavigationEntryScreenshotManager:
- virtual void TakeScreenshotImpl(
- content::RenderViewHost* host,
- content::NavigationEntryImpl* entry) OVERRIDE {
- }
+ void TakeScreenshotImpl(content::RenderViewHost* host,
+ content::NavigationEntryImpl* entry) override {}
- virtual void OnScreenshotSet(content::NavigationEntryImpl* entry) OVERRIDE {
+ void OnScreenshotSet(content::NavigationEntryImpl* entry) override {
encoding_screenshot_in_progress_ = false;
NavigationEntryScreenshotManager::OnScreenshotSet(entry);
if (message_loop_runner_.get())
@@ -188,7 +184,7 @@ class NavigationControllerTest
NavigationControllerTest() : navigation_entry_committed_counter_(0) {
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
WebContents* web_contents = RenderViewHostImplTestHarness::web_contents();
ASSERT_TRUE(web_contents); // The WebContents should be created by now.
@@ -196,14 +192,14 @@ class NavigationControllerTest
}
// WebContentsObserver:
- virtual void DidStartNavigationToPendingEntry(
+ void DidStartNavigationToPendingEntry(
const GURL& url,
- NavigationController::ReloadType reload_type) OVERRIDE {
+ NavigationController::ReloadType reload_type) override {
navigated_url_ = url;
}
- virtual void NavigationEntryCommitted(
- const LoadCommittedDetails& load_details) OVERRIDE {
+ void NavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) override {
navigation_entry_committed_counter_++;
}
@@ -247,12 +243,12 @@ class TestWebContentsDelegate : public WebContentsDelegate {
}
// Keep track of whether the tab has notified us of a navigation state change.
- virtual void NavigationStateChanged(const WebContents* source,
- unsigned changed_flags) OVERRIDE {
+ void NavigationStateChanged(const WebContents* source,
+ InvalidateTypes changed_flags) override {
navigation_state_change_count_++;
}
- virtual void ShowRepostFormWarningDialog(WebContents* source) OVERRIDE {
+ void ShowRepostFormWarningDialog(WebContents* source) override {
repost_form_warning_count_++;
}
@@ -354,7 +350,8 @@ TEST_F(NavigationControllerTest, LoadURL) {
const GURL url1("http://foo1");
const GURL url2("http://foo2");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Creating a pending notification should not have issued any of the
// notifications we're listening for.
EXPECT_EQ(0U, notifications.size());
@@ -398,7 +395,8 @@ TEST_F(NavigationControllerTest, LoadURL) {
EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
// Load another...
- controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// The load should now be pending.
EXPECT_EQ(controller.GetEntryCount(), 1);
@@ -416,9 +414,8 @@ TEST_F(NavigationControllerTest, LoadURL) {
// Simulate the beforeunload ack for the cross-site transition, and then the
// commit.
- test_rvh()->SendBeforeUnloadACK(true);
- static_cast<TestRenderViewHost*>(
- contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ contents()->GetPendingMainFrame()->SendNavigate(1, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -456,18 +453,20 @@ TEST_F(NavigationControllerTest, LoadURLSameTime) {
const GURL url1("http://foo1");
const GURL url2("http://foo2");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
// Load another...
- controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Simulate the beforeunload ack for the cross-site transition, and then the
// commit.
- test_rvh()->SendBeforeUnloadACK(true);
+ main_test_rfh()->SendBeforeUnloadACK(true);
main_test_rfh()->SendNavigate(1, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -503,8 +502,8 @@ void CheckNavigationEntryMatchLoadParams(
load_params.override_user_agent);
EXPECT_EQ(should_override, entry->GetIsOverridingUserAgent());
}
- EXPECT_EQ(load_params.browser_initiated_post_data,
- entry->GetBrowserInitiatedPostData());
+ EXPECT_EQ(load_params.browser_initiated_post_data.get(),
+ entry->GetBrowserInitiatedPostData());
EXPECT_EQ(load_params.transferred_global_request_id,
entry->transferred_global_request_id());
}
@@ -515,7 +514,7 @@ TEST_F(NavigationControllerTest, LoadURLWithParams) {
NavigationController::LoadURLParams load_params(GURL("http://foo"));
load_params.referrer =
Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault);
- load_params.transition_type = PAGE_TRANSITION_GENERATED;
+ load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
load_params.extra_headers = "content-type: text/plain";
load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
load_params.is_renderer_initiated = true;
@@ -556,7 +555,7 @@ TEST_F(NavigationControllerTest, LoadURLWithExtraParams_HttpPost) {
NavigationControllerImpl& controller = controller_impl();
NavigationController::LoadURLParams load_params(GURL("https://posturl"));
- load_params.transition_type = PAGE_TRANSITION_TYPED;
+ load_params.transition_type = ui::PAGE_TRANSITION_TYPED;
load_params.load_type =
NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
@@ -589,7 +588,8 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage) {
const GURL url1("http://foo1");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
main_test_rfh()->SendNavigate(0, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -599,7 +599,8 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage) {
const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
EXPECT_FALSE(timestamp.is_null());
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
main_test_rfh()->SendNavigate(0, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -631,11 +632,12 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage_DifferentMethod) {
const GURL url1("http://foo1");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.url = url1;
- params.transition = PAGE_TRANSITION_TYPED;
+ params.transition = ui::PAGE_TRANSITION_TYPED;
params.is_post = true;
params.post_id = 123;
params.page_state = PageState::CreateForTesting(url1, false, 0, 0);
@@ -647,7 +649,8 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage_DifferentMethod) {
EXPECT_TRUE(entry->GetHasPostData());
EXPECT_EQ(entry->GetPostID(), 123);
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url1);
// We should not have produced a new session history entry.
@@ -667,7 +670,8 @@ TEST_F(NavigationControllerTest, LoadURL_Discarded) {
const GURL url1("http://foo1");
const GURL url2("http://foo2");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
main_test_rfh()->SendNavigate(0, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -677,7 +681,8 @@ TEST_F(NavigationControllerTest, LoadURL_Discarded) {
const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
EXPECT_FALSE(timestamp.is_null());
- controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
controller.DiscardNonCommittedEntries();
EXPECT_EQ(0U, notifications.size());
@@ -705,7 +710,7 @@ TEST_F(NavigationControllerTest, LoadURL_NoPending) {
// First make an existing committed entry.
const GURL kExistingURL1("http://eh");
controller.LoadURL(
- kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -735,7 +740,7 @@ TEST_F(NavigationControllerTest, LoadURL_NewPending) {
// First make an existing committed entry.
const GURL kExistingURL1("http://eh");
controller.LoadURL(
- kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -743,14 +748,13 @@ TEST_F(NavigationControllerTest, LoadURL_NewPending) {
// Make a pending entry to somewhere new.
const GURL kExistingURL2("http://bee");
controller.LoadURL(
- kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
// After the beforeunload but before it commits, do a new navigation.
- test_rvh()->SendBeforeUnloadACK(true);
+ main_test_rfh()->SendBeforeUnloadACK(true);
const GURL kNewURL("http://see");
- static_cast<TestRenderViewHost*>(
- contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL);
+ contents()->GetPendingMainFrame()->SendNavigate(3, kNewURL);
// There should no longer be any pending entry, and the third navigation we
// just made should be committed.
@@ -772,14 +776,14 @@ TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
// First make some history.
const GURL kExistingURL1("http://foo/eh");
controller.LoadURL(
- kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
const GURL kExistingURL2("http://foo/bee");
controller.LoadURL(
- kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(1, kExistingURL2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -816,9 +820,9 @@ TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
// First make some history, starting with a privileged URL.
const GURL kExistingURL1("http://privileged");
controller.LoadURL(
- kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Pretend it has bindings so we can tell if we incorrectly copy it.
- test_rvh()->AllowBindings(2);
+ main_test_rfh()->GetRenderViewHost()->AllowBindings(2);
main_test_rfh()->SendNavigate(0, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -826,18 +830,17 @@ TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
// Navigate cross-process to a second URL.
const GURL kExistingURL2("http://foo/eh");
controller.LoadURL(
- kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- test_rvh()->SendBeforeUnloadACK(true);
- TestRenderViewHost* foo_rvh = static_cast<TestRenderViewHost*>(
- contents()->GetPendingRenderViewHost());
- foo_rvh->SendNavigate(1, kExistingURL2);
+ kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ main_test_rfh()->SendBeforeUnloadACK(true);
+ TestRenderFrameHost* foo_rfh = contents()->GetPendingMainFrame();
+ foo_rfh->SendNavigate(1, kExistingURL2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
// Now make a pending back/forward navigation to a privileged entry.
// The zeroth entry should be pending.
controller.GoBack();
- foo_rvh->SendBeforeUnloadACK(true);
+ foo_rfh->SendBeforeUnloadACK(true);
EXPECT_EQ(0U, notifications.size());
EXPECT_EQ(0, controller.GetPendingEntryIndex());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
@@ -847,7 +850,7 @@ TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
// Before that commits, do a new navigation.
const GURL kNewURL("http://foo/bee");
LoadCommittedDetails details;
- foo_rvh->SendNavigate(3, kNewURL);
+ foo_rfh->SendNavigate(3, kNewURL);
// There should no longer be any pending entry, and the third navigation we
// just made should be committed.
@@ -871,14 +874,14 @@ TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
// First make some history.
const GURL kExistingURL1("http://foo/eh");
controller.LoadURL(
- kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kExistingURL1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, kExistingURL1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
const GURL kExistingURL2("http://foo/bee");
controller.LoadURL(
- kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kExistingURL2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(1, kExistingURL2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -886,7 +889,7 @@ TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
// Now make a pending new navigation.
const GURL kNewURL("http://foo/see");
controller.LoadURL(
- kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kNewURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
@@ -922,7 +925,7 @@ TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
// Now make a pending new navigation.
const GURL kNewURL("http://eh");
controller.LoadURL(
- kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kNewURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_TRUE(controller.GetPendingEntry());
@@ -959,7 +962,7 @@ TEST_F(NavigationControllerTest, LoadURL_AbortDoesntCancelPending) {
// Start with a pending new navigation.
const GURL kNewURL("http://eh");
controller.LoadURL(
- kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kNewURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_TRUE(controller.GetPendingEntry());
@@ -1005,8 +1008,8 @@ TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
// First make an existing committed entry.
const GURL kExistingURL("http://foo/eh");
controller.LoadURL(kExistingURL, content::Referrer(),
- content::PAGE_TRANSITION_TYPED, std::string());
- main_test_rfh()->SendNavigate(0, kExistingURL);
+ ui::PAGE_TRANSITION_TYPED, std::string());
+ main_test_rfh()->SendNavigate(1, kExistingURL);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1018,7 +1021,7 @@ TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
// Now make a pending new navigation, initiated by the renderer.
const GURL kNewURL("http://foo/bee");
NavigationController::LoadURLParams load_url_params(kNewURL);
- load_url_params.transition_type = PAGE_TRANSITION_TYPED;
+ load_url_params.transition_type = ui::PAGE_TRANSITION_TYPED;
load_url_params.is_renderer_initiated = true;
controller.LoadURLWithParams(load_url_params);
EXPECT_EQ(0U, notifications.size());
@@ -1030,13 +1033,8 @@ TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
// The visible entry should be the last committed URL, not the pending one.
EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
- // Now the navigation redirects.
+ // Now the navigation redirects. (There is no corresponding message here.)
const GURL kRedirectURL("http://foo/see");
- main_test_rfh()->OnMessageReceived(
- FrameHostMsg_DidRedirectProvisionalLoad(0, // routing_id
- -1, // pending page_id
- kNewURL, // old url
- kRedirectURL)); // new url
// We don't want to change the NavigationEntry's url, in case it cancels.
// Prevents regression of http://crbug.com/77786.
@@ -1079,39 +1077,35 @@ TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
const GURL url2("http://foo2");
// Navigate to a first, unprivileged URL.
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(NavigationEntryImpl::kInvalidBindings,
NavigationEntryImpl::FromNavigationEntry(
controller.GetPendingEntry())->bindings());
// Commit.
- TestRenderViewHost* orig_rvh = static_cast<TestRenderViewHost*>(test_rvh());
- orig_rvh->SendNavigate(0, url1);
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
+ orig_rfh->SendNavigate(0, url1);
EXPECT_EQ(controller.GetEntryCount(), 1);
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
controller.GetLastCommittedEntry())->bindings());
- // Manually increase the number of active views in the SiteInstance
- // that orig_rvh belongs to, to prevent it from being destroyed when
- // it gets swapped out, so that we can reuse orig_rvh when the
+ // Manually increase the number of active frames in the SiteInstance
+ // that orig_rfh belongs to, to prevent it from being destroyed when
+ // it gets swapped out, so that we can reuse orig_rfh when the
// controller goes back.
- static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
- increment_active_view_count();
+ orig_rfh->GetSiteInstance()->increment_active_frame_count();
// Navigate to a second URL, simulate the beforeunload ack for the cross-site
- // transition, run the unload handler, and set bindings on the pending
- // RenderViewHost to simulate a privileged url.
- controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- orig_rvh->SendBeforeUnloadACK(true);
- contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
- contents()->GetRenderManagerForTesting()->pending_frame_host(),
- GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
- url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
- TestRenderViewHost* new_rvh =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
- new_rvh->AllowBindings(1);
- new_rvh->SendNavigate(1, url2);
+ // transition, and set bindings on the pending RenderViewHost to simulate a
+ // privileged url.
+ controller.LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ orig_rfh->SendBeforeUnloadACK(true);
+ TestRenderFrameHost* new_rfh = contents()->GetPendingMainFrame();
+ new_rfh->GetRenderViewHost()->AllowBindings(1);
+ new_rfh->SendNavigate(1, url2);
// The second load should be committed, and bindings should be remembered.
EXPECT_EQ(controller.GetEntryCount(), 2);
@@ -1122,12 +1116,8 @@ TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
// Going back, the first entry should still appear unprivileged.
controller.GoBack();
- new_rvh->SendBeforeUnloadACK(true);
- contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
- contents()->GetRenderManagerForTesting()->pending_frame_host(),
- GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
- url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
- orig_rvh->SendNavigate(0, url1);
+ new_rfh->SendBeforeUnloadACK(true);
+ orig_rfh->SendNavigate(0, url1);
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
controller.GetLastCommittedEntry())->bindings());
@@ -1140,7 +1130,8 @@ TEST_F(NavigationControllerTest, Reload) {
const GURL url1("http://foo1");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
main_test_rfh()->SendNavigate(0, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
@@ -1193,7 +1184,8 @@ TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
const GURL url1("http://foo1");
const GURL url2("http://foo2");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1222,7 +1214,8 @@ TEST_F(NavigationControllerTest, ReloadWithGuest) {
NavigationControllerImpl& controller = controller_impl();
const GURL url1("http://foo1");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url1);
ASSERT_TRUE(controller.GetVisibleEntry());
@@ -1257,7 +1250,7 @@ TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
// Load up the original URL, but get redirected.
controller.LoadURL(
- original_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ original_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
main_test_rfh()->SendNavigateWithOriginalRequestURL(
0, final_url, original_url);
@@ -1312,7 +1305,8 @@ TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
NavigationControllerImpl& controller = controller_impl();
const GURL url1("http://foo1");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Set up some sample values.
const unsigned char* raw_data =
@@ -1358,7 +1352,8 @@ TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
TEST_F(NavigationControllerTest, RedirectsAreNotResetByCommit) {
NavigationControllerImpl& controller = controller_impl();
const GURL url1("http://foo1");
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Set up some redirect values.
std::vector<GURL> redirects;
@@ -1449,12 +1444,13 @@ TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
const GURL url3("http://foo/3");
controller.LoadURL(
- url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(1, url2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -1501,13 +1497,14 @@ TEST_F(NavigationControllerTest, Back_NewPending) {
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
- // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
+ // controller.LoadURL(kUrl2, ui::PAGE_TRANSITION_TYPED);
main_test_rfh()->SendNavigate(1, kUrl2);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
// Now start a new pending navigation and go back before it commits.
- controller.LoadURL(kUrl3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ kUrl3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(-1, controller.GetPendingEntryIndex());
EXPECT_EQ(kUrl3, controller.GetPendingEntry()->GetURL());
controller.GoBack();
@@ -1690,7 +1687,8 @@ TEST_F(NavigationControllerTest, Redirect) {
const GURL url2("http://foo2"); // Redirection target
// First request
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(0U, notifications.size());
main_test_rfh()->SendNavigate(0, url2);
@@ -1698,7 +1696,8 @@ TEST_F(NavigationControllerTest, Redirect) {
navigation_entry_committed_counter_ = 0;
// Second request
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_TRUE(controller.GetPendingEntry());
EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
@@ -1707,7 +1706,7 @@ TEST_F(NavigationControllerTest, Redirect) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.url = url2;
- params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
+ params.transition = ui::PAGE_TRANSITION_SERVER_REDIRECT;
params.redirects.push_back(GURL("http://foo1"));
params.redirects.push_back(GURL("http://foo2"));
params.should_update_history = false;
@@ -1747,7 +1746,8 @@ TEST_F(NavigationControllerTest, PostThenRedirect) {
const GURL url2("http://foo2"); // Redirection target
// First request as POST
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
controller.GetVisibleEntry()->SetHasPostData(true);
EXPECT_EQ(0U, notifications.size());
@@ -1756,7 +1756,8 @@ TEST_F(NavigationControllerTest, PostThenRedirect) {
navigation_entry_committed_counter_ = 0;
// Second request
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_TRUE(controller.GetPendingEntry());
EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
@@ -1765,7 +1766,7 @@ TEST_F(NavigationControllerTest, PostThenRedirect) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.url = url2;
- params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
+ params.transition = ui::PAGE_TRANSITION_SERVER_REDIRECT;
params.redirects.push_back(GURL("http://foo1"));
params.redirects.push_back(GURL("http://foo2"));
params.should_update_history = false;
@@ -1804,7 +1805,8 @@ TEST_F(NavigationControllerTest, ImmediateRedirect) {
const GURL url2("http://foo2"); // Redirection target
// First request
- controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_TRUE(controller.GetPendingEntry());
EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
@@ -1813,7 +1815,7 @@ TEST_F(NavigationControllerTest, ImmediateRedirect) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.url = url2;
- params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
+ params.transition = ui::PAGE_TRANSITION_SERVER_REDIRECT;
params.redirects.push_back(GURL("http://foo1"));
params.redirects.push_back(GURL("http://foo2"));
params.should_update_history = false;
@@ -1857,7 +1859,7 @@ TEST_F(NavigationControllerTest, NewSubframe) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
params.url = url2;
- params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
+ params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
@@ -1894,7 +1896,7 @@ TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
params.url = url;
- params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureAuto;
params.is_post = false;
@@ -1922,7 +1924,7 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.url = url2;
- params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
@@ -1955,7 +1957,7 @@ TEST_F(NavigationControllerTest, BackSubframe) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
params.url = url2;
- params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
+ params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
@@ -2049,7 +2051,7 @@ TEST_F(NavigationControllerTest, InPage) {
FrameHostMsg_DidCommitProvisionalLoad_Params self_params;
self_params.page_id = 0;
self_params.url = url1;
- self_params.transition = PAGE_TRANSITION_LINK;
+ self_params.transition = ui::PAGE_TRANSITION_LINK;
self_params.should_update_history = false;
self_params.gesture = NavigationGestureUser;
self_params.is_post = false;
@@ -2070,7 +2072,7 @@ TEST_F(NavigationControllerTest, InPage) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
params.url = url2;
- params.transition = PAGE_TRANSITION_LINK;
+ params.transition = ui::PAGE_TRANSITION_LINK;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
@@ -2158,7 +2160,7 @@ TEST_F(NavigationControllerTest, InPage_Replace) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0; // Same page_id
params.url = url2;
- params.transition = PAGE_TRANSITION_LINK;
+ params.transition = ui::PAGE_TRANSITION_LINK;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
@@ -2209,7 +2211,7 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1; // Same page_id
params.url = url;
- params.transition = PAGE_TRANSITION_LINK;
+ params.transition = ui::PAGE_TRANSITION_LINK;
params.redirects.push_back(url);
params.should_update_history = true;
params.gesture = NavigationGestureUnknown;
@@ -2234,7 +2236,7 @@ TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 2; // New page_id
params.url = url;
- params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
+ params.transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
params.redirects.push_back(GURL("http://foo2/#a"));
params.redirects.push_back(url);
params.should_update_history = true;
@@ -2272,7 +2274,7 @@ TEST_F(NavigationControllerTest, PushStateWithoutPreviousEntry)
params.url = url;
params.page_state = PageState::CreateFromURL(url);
params.was_within_same_page = true;
- test_rvh()->SendNavigateWithParams(&params);
+ contents()->GetMainFrame()->SendNavigateWithParams(&params);
// We pass if we don't crash.
}
@@ -2286,9 +2288,9 @@ class PrunedListener : public NotificationObserver {
Source<NavigationController>(controller));
}
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE {
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override {
if (type == NOTIFICATION_NAV_LIST_PRUNED) {
notification_count_++;
details_ = *(Details<PrunedDetails>(details).ptr());
@@ -2320,7 +2322,7 @@ TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
for (url_index = 0; url_index < kMaxEntryCount; url_index++) {
GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
controller.LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(url_index, url);
}
@@ -2332,7 +2334,7 @@ TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
// Navigate some more.
GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
controller.LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(url_index, url);
url_index++;
@@ -2350,7 +2352,7 @@ TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
for (int i = 0; i < 3; i++) {
url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index));
controller.LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(url_index, url);
url_index++;
}
@@ -2369,7 +2371,7 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
GURL url("http://foo");
std::vector<NavigationEntry*> entries;
NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
- url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
+ url, Referrer(), ui::PAGE_TRANSITION_RELOAD, false, std::string(),
browser_context());
entry->SetPageID(0);
entry->SetTitle(base::ASCIIToUTF16("Title"));
@@ -2415,7 +2417,7 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.url = url;
- params.transition = PAGE_TRANSITION_LINK;
+ params.transition = ui::PAGE_TRANSITION_LINK;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
@@ -2449,7 +2451,7 @@ TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
GURL url("http://foo");
std::vector<NavigationEntry*> entries;
NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
- url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
+ url, Referrer(), ui::PAGE_TRANSITION_RELOAD, false, std::string(),
browser_context());
entry->SetPageID(0);
entry->SetTitle(base::ASCIIToUTF16("Title"));
@@ -2498,7 +2500,7 @@ TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.url = url;
- params.transition = PAGE_TRANSITION_LINK;
+ params.transition = ui::PAGE_TRANSITION_LINK;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
@@ -2526,13 +2528,13 @@ TEST_F(NavigationControllerTest, Interstitial) {
// First navigate somewhere normal.
const GURL url1("http://foo");
controller.LoadURL(
- url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url1);
// Now navigate somewhere with an interstitial.
const GURL url2("http://bar");
controller.LoadURL(
- url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
set_page_type(PAGE_TYPE_INTERSTITIAL);
@@ -2557,19 +2559,19 @@ TEST_F(NavigationControllerTest, RemoveEntry) {
const GURL default_url("http://foo/default");
controller.LoadURL(
- url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url1);
controller.LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(1, url2);
controller.LoadURL(
- url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(2, url3);
controller.LoadURL(
- url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(3, url4);
controller.LoadURL(
- url5, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url5, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(4, url5);
// Try to remove the last entry. Will fail because it is the current entry.
@@ -2605,6 +2607,45 @@ TEST_F(NavigationControllerTest, RemoveEntry) {
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
}
+TEST_F(NavigationControllerTest, RemoveEntryWithPending) {
+ NavigationControllerImpl& controller = controller_impl();
+ const GURL url1("http://foo/1");
+ const GURL url2("http://foo/2");
+ const GURL url3("http://foo/3");
+ const GURL default_url("http://foo/default");
+
+ controller.LoadURL(
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ main_test_rfh()->SendNavigate(0, url1);
+ controller.LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ main_test_rfh()->SendNavigate(1, url2);
+ controller.LoadURL(
+ url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ main_test_rfh()->SendNavigate(2, url3);
+
+ // Go back, but don't commit yet. Check that we can't delete the current
+ // and pending entries.
+ controller.GoBack();
+ EXPECT_FALSE(controller.RemoveEntryAtIndex(2));
+ EXPECT_FALSE(controller.RemoveEntryAtIndex(1));
+
+ // Remove the first entry, while there is a pending entry. This is expected
+ // to discard the pending entry.
+ EXPECT_TRUE(controller.RemoveEntryAtIndex(0));
+ EXPECT_FALSE(controller.GetPendingEntry());
+ EXPECT_EQ(-1, controller.GetPendingEntryIndex());
+
+ // We should update the last committed entry index.
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+
+ // Now commit and ensure we land on the right entry.
+ main_test_rfh()->SendNavigate(1, url2);
+ EXPECT_EQ(2, controller.GetEntryCount());
+ EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
+ EXPECT_FALSE(controller.GetPendingEntry());
+}
+
// Tests the transient entry, making sure it goes away with all navigations.
TEST_F(NavigationControllerTest, TransientEntry) {
NavigationControllerImpl& controller = controller_impl();
@@ -2620,10 +2661,10 @@ TEST_F(NavigationControllerTest, TransientEntry) {
const GURL transient_url("http://foo/transient");
controller.LoadURL(
- url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url0);
controller.LoadURL(
- url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(1, url1);
notifications.Reset();
@@ -2649,7 +2690,7 @@ TEST_F(NavigationControllerTest, TransientEntry) {
// Navigate.
controller.LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(2, url2);
// We should have navigated, transient entry should be gone.
@@ -2668,7 +2709,7 @@ TEST_F(NavigationControllerTest, TransientEntry) {
// Initiate a navigation, add a transient then commit navigation.
controller.LoadURL(
- url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
transient_entry = new NavigationEntryImpl;
transient_entry->SetURL(transient_url);
controller.SetTransientEntry(transient_entry);
@@ -2760,10 +2801,10 @@ TEST_F(NavigationControllerTest, ReloadTransient) {
// Load |url0|, and start a pending navigation to |url1|.
controller.LoadURL(
- url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
main_test_rfh()->SendNavigate(0, url0);
controller.LoadURL(
- url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// A transient entry is added, interrupting the navigation.
NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
@@ -2803,7 +2844,7 @@ TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
// We create pending entries for renderer-initiated navigations so that we
// can show them in new tabs when it is safe.
- navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url1);
+ navigator->DidStartProvisionalLoad(main_test_rfh(), url1, false);
// Simulate what happens if a BrowserURLHandler rewrites the URL, causing
// the virtual URL to differ from the URL.
@@ -2817,7 +2858,7 @@ TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
is_renderer_initiated());
// If the user clicks another link, we should replace the pending entry.
- navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url2);
+ navigator->DidStartProvisionalLoad(main_test_rfh(), url2, false);
EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
EXPECT_EQ(url2, controller.GetPendingEntry()->GetVirtualURL());
@@ -2827,18 +2868,18 @@ TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetVirtualURL());
// We should not replace the pending entry for an error URL.
- navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url1);
+ navigator->DidStartProvisionalLoad(main_test_rfh(), url1, false);
EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
- navigator->DidStartProvisionalLoad(
- main_test_rfh(), -1, GURL(kUnreachableWebDataURL));
+ navigator->DidStartProvisionalLoad(main_test_rfh(),
+ GURL(kUnreachableWebDataURL), false);
EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
// We should remember if the pending entry will replace the current one.
// http://crbug.com/308444.
- navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url1);
+ navigator->DidStartProvisionalLoad(main_test_rfh(), url1, false);
NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
set_should_replace_entry(true);
- navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url2);
+ navigator->DidStartProvisionalLoad(main_test_rfh(), url2, false);
EXPECT_TRUE(
NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
should_replace_entry());
@@ -2862,7 +2903,8 @@ TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) {
// For typed navigations (browser-initiated), both pending and visible entries
// should update before commit.
- controller.LoadURL(url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller.LoadURL(
+ url0, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(url0, controller.GetPendingEntry()->GetURL());
EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
main_test_rfh()->SendNavigate(0, url0);
@@ -2905,7 +2947,7 @@ TEST_F(NavigationControllerTest, ShowRendererURLInNewTabUntilModified) {
// we show the pending entry's URL as long as the about:blank page is not
// modified.
NavigationController::LoadURLParams load_url_params(url);
- load_url_params.transition_type = PAGE_TRANSITION_LINK;
+ load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
load_url_params.is_renderer_initiated = true;
controller.LoadURLWithParams(load_url_params);
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
@@ -2945,7 +2987,7 @@ TEST_F(NavigationControllerTest, ShowBrowserURLAfterFailUntilModified) {
// modified. This is possible in cases that the user types a URL into a popup
// tab created with a slow URL.
NavigationController::LoadURLParams load_url_params(url);
- load_url_params.transition_type = PAGE_TRANSITION_TYPED;
+ load_url_params.transition_type = ui::PAGE_TRANSITION_TYPED;
load_url_params.is_renderer_initiated = false;
controller.LoadURLWithParams(load_url_params);
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
@@ -2996,7 +3038,7 @@ TEST_F(NavigationControllerTest, ShowRendererURLAfterFailUntilModified) {
// we show the pending entry's URL as long as the about:blank page is not
// modified.
NavigationController::LoadURLParams load_url_params(url);
- load_url_params.transition_type = PAGE_TRANSITION_LINK;
+ load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
load_url_params.is_renderer_initiated = true;
controller.LoadURLWithParams(load_url_params);
EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
@@ -3043,7 +3085,7 @@ TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
// we show the pending entry's URL as long as the about:blank page is not
// modified.
NavigationController::LoadURLParams load_url_params(url1);
- load_url_params.transition_type = PAGE_TRANSITION_LINK;
+ load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
load_url_params.is_renderer_initiated = true;
controller.LoadURLWithParams(load_url_params);
EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
@@ -3056,7 +3098,7 @@ TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
// Simulate a commit and then starting a new pending navigation.
main_test_rfh()->SendNavigate(0, url1);
NavigationController::LoadURLParams load_url2_params(url2);
- load_url2_params.transition_type = PAGE_TRANSITION_LINK;
+ load_url2_params.transition_type = ui::PAGE_TRANSITION_LINK;
load_url2_params.is_renderer_initiated = true;
controller.LoadURLWithParams(load_url2_params);
@@ -3074,54 +3116,71 @@ TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
// regression for bug 1126349.
TEST_F(NavigationControllerTest, IsInPageNavigation) {
NavigationControllerImpl& controller = controller_impl();
- // Navigate to URL with no refs.
const GURL url("http://www.google.com/home.html");
+
+ // If the renderer claims it performed an in-page navigation from
+ // about:blank, trust the renderer.
+ // This can happen when an iframe is created and populated via
+ // document.write(), then tries to perform a fragment navigation.
+ // TODO(japhet): We should only trust the renderer if the about:blank
+ // was the first document in the given frame, but we don't have enough
+ // information to identify that case currently.
+ const GURL blank_url(url::kAboutBlankURL);
+ main_test_rfh()->SendNavigate(0, blank_url);
+ EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
+ main_test_rfh()));
+
+ // Navigate to URL with no refs.
main_test_rfh()->SendNavigate(0, url);
// Reloading the page is not an in-page navigation.
EXPECT_FALSE(controller.IsURLInPageNavigation(url, false,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
const GURL other_url("http://www.google.com/add.html");
EXPECT_FALSE(controller.IsURLInPageNavigation(other_url, false,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
const GURL url_with_ref("http://www.google.com/home.html#my_ref");
EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
// Navigate to URL with refs.
main_test_rfh()->SendNavigate(1, url_with_ref);
// Reloading the page is not an in-page navigation.
EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref, false,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
EXPECT_FALSE(controller.IsURLInPageNavigation(url, false,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
EXPECT_FALSE(controller.IsURLInPageNavigation(other_url, false,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref, true,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
// Going to the same url again will be considered in-page
// if the renderer says it is even if the navigation type isn't IN_PAGE.
EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
// Going back to the non ref url will be considered in-page if the navigation
// type is IN_PAGE.
EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
- NAVIGATION_TYPE_IN_PAGE));
+ main_test_rfh()));
// If the renderer says this is a same-origin in-page navigation, believe it.
// This is the pushState/replaceState case.
EXPECT_TRUE(controller.IsURLInPageNavigation(other_url, true,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
// Don't believe the renderer if it claims a cross-origin navigation is
// in-page.
const GURL different_origin_url("http://www.example.com");
+ MockRenderProcessHost* rph =
+ static_cast<MockRenderProcessHost*>(main_test_rfh()->GetProcess());
+ EXPECT_EQ(0, rph->bad_msg_count());
EXPECT_FALSE(controller.IsURLInPageNavigation(different_origin_url, true,
- NAVIGATION_TYPE_UNKNOWN));
+ main_test_rfh()));
+ EXPECT_EQ(1, rph->bad_msg_count());
}
// Some pages can have subframes with the same base URL (minus the reference) as
@@ -3143,7 +3202,7 @@ TEST_F(NavigationControllerTest, SameSubframe) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 0;
params.url = subframe;
- params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureAuto;
params.is_post = false;
@@ -3251,7 +3310,7 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
// Now start a pending load to a totally different page, but don't commit it.
const GURL url2("http://bar/");
controller.LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Send a subframe update from the first page, as if one had just
// automatically loaded. Auto subframes don't increment the page ID.
@@ -3259,7 +3318,7 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = controller.GetLastCommittedEntry()->GetPageID();
params.url = url1_sub;
- params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureAuto;
params.is_post = false;
@@ -3522,7 +3581,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) {
NavigationControllerImpl& other_controller = other_contents->GetController();
other_contents->NavigateAndCommit(url3);
other_controller.LoadURL(
- url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url4, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
other_contents->ExpectSetHistoryLengthAndPrune(
GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
other_controller.GetEntryAtIndex(0)->GetPageID());
@@ -3566,7 +3625,7 @@ TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) {
other_contents->NavigateAndCommit(url2a);
// Simulate a client redirect, which has the same page ID as entry 2a.
other_controller.LoadURL(
- url2b, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ url2b, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
other_controller.GetPendingEntry()->SetPageID(
other_controller.GetLastCommittedEntry()->GetPageID());
@@ -3802,7 +3861,7 @@ TEST_F(NavigationControllerTest, CopyRestoredStateAndNavigate) {
std::vector<NavigationEntry*> entries;
for (size_t i = 0; i < arraysize(kRestoredUrls); ++i) {
NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
- kRestoredUrls[i], Referrer(), PAGE_TRANSITION_RELOAD, false,
+ kRestoredUrls[i], Referrer(), ui::PAGE_TRANSITION_RELOAD, false,
std::string(), browser_context());
entry->SetPageID(static_cast<int>(i));
entries.push_back(entry);
@@ -3871,7 +3930,7 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
ASSERT_TRUE(message != NULL);
Tuple1<FrameMsg_Navigate_Params> nav_params;
FrameMsg_Navigate::Read(message, &nav_params);
- EXPECT_EQ(url1, nav_params.a.url);
+ EXPECT_EQ(url1, nav_params.a.common_params.url);
process()->sink().ClearMessages();
// Now test history.forward()
@@ -3883,7 +3942,7 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
message = process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
ASSERT_TRUE(message != NULL);
FrameMsg_Navigate::Read(message, &nav_params);
- EXPECT_EQ(url3, nav_params.a.url);
+ EXPECT_EQ(url3, nav_params.a.common_params.url);
process()->sink().ClearMessages();
controller.DiscardNonCommittedEntries();
@@ -3971,7 +4030,7 @@ TEST_F(NavigationControllerTest, PruneAllButLastCommittedForPendingNotInList) {
// Create a pending entry that is not in the entry list.
controller.LoadURL(
- url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_TRUE(controller.GetPendingEntry());
EXPECT_EQ(2, controller.GetEntryCount());
@@ -4038,7 +4097,7 @@ TEST_F(NavigationControllerTest, IsInitialNavigation) {
// After starting a new navigation, it stays false.
const GURL url2("http://foo2");
controller.LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
}
// Check that the favicon is not reused across a client redirect.
@@ -4071,7 +4130,7 @@ TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) {
main_test_rfh()->SendNavigateWithTransition(
0, // same page ID.
kPageWithoutFavicon,
- PAGE_TRANSITION_CLIENT_REDIRECT);
+ ui::PAGE_TRANSITION_CLIENT_REDIRECT);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -4113,7 +4172,7 @@ TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
main_test_rfh()->SendNavigateWithTransition(
0,
kUrl1,
- PAGE_TRANSITION_FORWARD_BACK);
+ ui::PAGE_TRANSITION_FORWARD_BACK);
EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0;
@@ -4220,14 +4279,17 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
}
}
-TEST_F(NavigationControllerTest, PushStateUpdatesTitle) {
-
- // Navigate
- test_rvh()->SendNavigate(1, GURL("http://foo"));
+TEST_F(NavigationControllerTest, PushStateUpdatesTitleAndFavicon) {
+ // Navigate.
+ contents()->GetMainFrame()->SendNavigate(1, GURL("http://foo"));
- // Set title
+ // Set title and favicon.
base::string16 title(base::ASCIIToUTF16("Title"));
+ FaviconStatus favicon;
+ favicon.valid = true;
+ favicon.url = GURL("http://foo/favicon.ico");
controller().GetLastCommittedEntry()->SetTitle(title);
+ controller().GetLastCommittedEntry()->GetFavicon() = favicon;
// history.pushState() is called.
FrameHostMsg_DidCommitProvisionalLoad_Params params;
@@ -4236,12 +4298,16 @@ TEST_F(NavigationControllerTest, PushStateUpdatesTitle) {
params.url = url;
params.page_state = PageState::CreateFromURL(url);
params.was_within_same_page = true;
- test_rvh()->SendNavigateWithParams(&params);
+ contents()->GetMainFrame()->SendNavigateWithParams(&params);
// The title should immediately be visible on the new NavigationEntry.
base::string16 new_title =
controller().GetLastCommittedEntry()->GetTitleForDisplay(std::string());
EXPECT_EQ(title, new_title);
+ FaviconStatus new_favicon =
+ controller().GetLastCommittedEntry()->GetFavicon();
+ EXPECT_EQ(favicon.valid, new_favicon.valid);
+ EXPECT_EQ(favicon.url, new_favicon.url);
}
// Test that the navigation controller clears its session history when a
@@ -4277,8 +4343,8 @@ TEST_F(NavigationControllerTest, ClearHistoryList) {
ASSERT_TRUE(entry);
EXPECT_TRUE(entry->should_clear_history_list());
- // Assume that the RV correctly cleared its history and commit the navigation.
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost())->
+ // Assume that the RF correctly cleared its history and commit the navigation.
+ contents()->GetPendingMainFrame()->
set_simulate_history_list_was_cleared(true);
contents()->CommitPendingNavigation();
@@ -4303,25 +4369,25 @@ TEST_F(NavigationControllerTest, PostThenReplaceStateThenReload) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
params.url = url;
- params.transition = PAGE_TRANSITION_FORM_SUBMIT;
+ params.transition = ui::PAGE_TRANSITION_FORM_SUBMIT;
params.gesture = NavigationGestureUser;
params.page_state = PageState::CreateFromURL(url);
params.was_within_same_page = false;
params.is_post = true;
params.post_id = 2;
- test_rvh()->SendNavigateWithParams(&params);
+ contents()->GetMainFrame()->SendNavigateWithParams(&params);
// history.replaceState() is called.
GURL replace_url("http://foo#foo");
params.page_id = 1;
params.url = replace_url;
- params.transition = PAGE_TRANSITION_LINK;
+ params.transition = ui::PAGE_TRANSITION_LINK;
params.gesture = NavigationGestureUser;
params.page_state = PageState::CreateFromURL(replace_url);
params.was_within_same_page = true;
params.is_post = false;
params.post_id = -1;
- test_rvh()->SendNavigateWithParams(&params);
+ contents()->GetMainFrame()->SendNavigateWithParams(&params);
// Now reload. replaceState overrides the POST, so we should not show a
// repost warning dialog.
diff --git a/chromium/content/browser/frame_host/navigation_entry_impl.cc b/chromium/content/browser/frame_host/navigation_entry_impl.cc
index b021d5eda18..7105608f774 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_impl.cc
@@ -43,7 +43,7 @@ NavigationEntryImpl::NavigationEntryImpl()
page_type_(PAGE_TYPE_NORMAL),
update_virtual_url_with_url_(false),
page_id_(-1),
- transition_type_(PAGE_TRANSITION_LINK),
+ transition_type_(ui::PAGE_TRANSITION_LINK),
has_post_data_(false),
post_id_(-1),
restore_type_(RESTORE_NONE),
@@ -61,7 +61,7 @@ NavigationEntryImpl::NavigationEntryImpl(SiteInstanceImpl* instance,
const GURL& url,
const Referrer& referrer,
const base::string16& title,
- PageTransition transition_type,
+ ui::PageTransition transition_type,
bool is_renderer_initiated)
: unique_id_(GetUniqueIDInConstructor()),
site_instance_(instance),
@@ -202,11 +202,11 @@ bool NavigationEntryImpl::IsViewSourceMode() const {
}
void NavigationEntryImpl::SetTransitionType(
- PageTransition transition_type) {
+ ui::PageTransition transition_type) {
transition_type_ = transition_type;
}
-PageTransition NavigationEntryImpl::GetTransitionType() const {
+ui::PageTransition NavigationEntryImpl::GetTransitionType() const {
return transition_type_;
}
diff --git a/chromium/content/browser/frame_host/navigation_entry_impl.h b/chromium/content/browser/frame_host/navigation_entry_impl.h
index 613f45edb42..37de18213cb 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl.h
+++ b/chromium/content/browser/frame_host/navigation_entry_impl.h
@@ -30,65 +30,63 @@ class CONTENT_EXPORT NavigationEntryImpl
const GURL& url,
const Referrer& referrer,
const base::string16& title,
- PageTransition transition_type,
+ ui::PageTransition transition_type,
bool is_renderer_initiated);
- virtual ~NavigationEntryImpl();
+ ~NavigationEntryImpl() override;
// NavigationEntry implementation:
- virtual int GetUniqueID() const OVERRIDE;
- virtual PageType GetPageType() const OVERRIDE;
- virtual void SetURL(const GURL& url) OVERRIDE;
- virtual const GURL& GetURL() const OVERRIDE;
- virtual void SetBaseURLForDataURL(const GURL& url) OVERRIDE;
- virtual const GURL& GetBaseURLForDataURL() const OVERRIDE;
- virtual void SetReferrer(const Referrer& referrer) OVERRIDE;
- virtual const Referrer& GetReferrer() const OVERRIDE;
- virtual void SetVirtualURL(const GURL& url) OVERRIDE;
- virtual const GURL& GetVirtualURL() const OVERRIDE;
- virtual void SetTitle(const base::string16& title) OVERRIDE;
- virtual const base::string16& GetTitle() const OVERRIDE;
- virtual void SetPageState(const PageState& state) OVERRIDE;
- virtual const PageState& GetPageState() const OVERRIDE;
- virtual void SetPageID(int page_id) OVERRIDE;
- virtual int32 GetPageID() const OVERRIDE;
- virtual const base::string16& GetTitleForDisplay(
- const std::string& languages) const OVERRIDE;
- virtual bool IsViewSourceMode() const OVERRIDE;
- virtual void SetTransitionType(PageTransition transition_type) OVERRIDE;
- virtual PageTransition GetTransitionType() const OVERRIDE;
- virtual const GURL& GetUserTypedURL() const OVERRIDE;
- virtual void SetHasPostData(bool has_post_data) OVERRIDE;
- virtual bool GetHasPostData() const OVERRIDE;
- virtual void SetPostID(int64 post_id) OVERRIDE;
- virtual int64 GetPostID() const OVERRIDE;
- virtual void SetBrowserInitiatedPostData(
- const base::RefCountedMemory* data) OVERRIDE;
- virtual const base::RefCountedMemory*
- GetBrowserInitiatedPostData() const OVERRIDE;
- virtual const FaviconStatus& GetFavicon() const OVERRIDE;
- virtual FaviconStatus& GetFavicon() OVERRIDE;
- virtual const SSLStatus& GetSSL() const OVERRIDE;
- virtual SSLStatus& GetSSL() OVERRIDE;
- virtual void SetOriginalRequestURL(const GURL& original_url) OVERRIDE;
- virtual const GURL& GetOriginalRequestURL() const OVERRIDE;
- virtual void SetIsOverridingUserAgent(bool override) OVERRIDE;
- virtual bool GetIsOverridingUserAgent() const OVERRIDE;
- virtual void SetTimestamp(base::Time timestamp) OVERRIDE;
- virtual base::Time GetTimestamp() const OVERRIDE;
- virtual void SetCanLoadLocalResources(bool allow) OVERRIDE;
- virtual bool GetCanLoadLocalResources() const OVERRIDE;
- virtual void SetFrameToNavigate(const std::string& frame_name) OVERRIDE;
- virtual const std::string& GetFrameToNavigate() const OVERRIDE;
- virtual void SetExtraData(const std::string& key,
- const base::string16& data) OVERRIDE;
- virtual bool GetExtraData(const std::string& key,
- base::string16* data) const OVERRIDE;
- virtual void ClearExtraData(const std::string& key) OVERRIDE;
- virtual void SetHttpStatusCode(int http_status_code) OVERRIDE;
- virtual int GetHttpStatusCode() const OVERRIDE;
- virtual void SetRedirectChain(const std::vector<GURL>& redirects) OVERRIDE;
- virtual const std::vector<GURL>& GetRedirectChain() const OVERRIDE;
- virtual bool IsRestored() const OVERRIDE;
+ int GetUniqueID() const override;
+ PageType GetPageType() const override;
+ void SetURL(const GURL& url) override;
+ const GURL& GetURL() const override;
+ void SetBaseURLForDataURL(const GURL& url) override;
+ const GURL& GetBaseURLForDataURL() const override;
+ void SetReferrer(const Referrer& referrer) override;
+ const Referrer& GetReferrer() const override;
+ void SetVirtualURL(const GURL& url) override;
+ const GURL& GetVirtualURL() const override;
+ void SetTitle(const base::string16& title) override;
+ const base::string16& GetTitle() const override;
+ void SetPageState(const PageState& state) override;
+ const PageState& GetPageState() const override;
+ void SetPageID(int page_id) override;
+ int32 GetPageID() const override;
+ const base::string16& GetTitleForDisplay(
+ const std::string& languages) const override;
+ bool IsViewSourceMode() const override;
+ void SetTransitionType(ui::PageTransition transition_type) override;
+ ui::PageTransition GetTransitionType() const override;
+ const GURL& GetUserTypedURL() const override;
+ void SetHasPostData(bool has_post_data) override;
+ bool GetHasPostData() const override;
+ void SetPostID(int64 post_id) override;
+ int64 GetPostID() const override;
+ void SetBrowserInitiatedPostData(const base::RefCountedMemory* data) override;
+ const base::RefCountedMemory* GetBrowserInitiatedPostData() const override;
+ const FaviconStatus& GetFavicon() const override;
+ FaviconStatus& GetFavicon() override;
+ const SSLStatus& GetSSL() const override;
+ SSLStatus& GetSSL() override;
+ void SetOriginalRequestURL(const GURL& original_url) override;
+ const GURL& GetOriginalRequestURL() const override;
+ void SetIsOverridingUserAgent(bool override) override;
+ bool GetIsOverridingUserAgent() const override;
+ void SetTimestamp(base::Time timestamp) override;
+ base::Time GetTimestamp() const override;
+ void SetCanLoadLocalResources(bool allow) override;
+ bool GetCanLoadLocalResources() const override;
+ void SetFrameToNavigate(const std::string& frame_name) override;
+ const std::string& GetFrameToNavigate() const override;
+ void SetExtraData(const std::string& key,
+ const base::string16& data) override;
+ bool GetExtraData(const std::string& key,
+ base::string16* data) const override;
+ void ClearExtraData(const std::string& key) override;
+ void SetHttpStatusCode(int http_status_code) override;
+ int GetHttpStatusCode() const override;
+ void SetRedirectChain(const std::vector<GURL>& redirects) override;
+ const std::vector<GURL>& GetRedirectChain() const override;
+ bool IsRestored() const override;
// Once a navigation entry is committed, we should no longer track several
// pieces of non-persisted state, as documented on the members below.
@@ -241,7 +239,7 @@ class CONTENT_EXPORT NavigationEntryImpl
PageState page_state_;
int32 page_id_;
SSLStatus ssl_;
- PageTransition transition_type_;
+ ui::PageTransition transition_type_;
GURL user_typed_url_;
bool has_post_data_;
int64 post_id_;
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 79768019179..663386a1316 100644
--- a/chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_impl_unittest.cc
@@ -20,7 +20,7 @@ class NavigationEntryTest : public testing::Test {
NavigationEntryTest() : instance_(NULL) {
}
- virtual void SetUp() {
+ void SetUp() override {
entry1_.reset(new NavigationEntryImpl);
#if !defined(OS_IOS)
@@ -31,12 +31,11 @@ class NavigationEntryTest : public testing::Test {
GURL("test:url"),
Referrer(GURL("from"), blink::WebReferrerPolicyDefault),
ASCIIToUTF16("title"),
- PAGE_TRANSITION_TYPED,
+ ui::PAGE_TRANSITION_TYPED,
false));
}
- virtual void TearDown() {
- }
+ void TearDown() override {}
protected:
scoped_ptr<NavigationEntryImpl> entry1_;
@@ -156,10 +155,10 @@ TEST_F(NavigationEntryTest, NavigationEntryAccessors) {
EXPECT_EQ(2, entry2_->GetPageID());
// Transition type
- EXPECT_EQ(PAGE_TRANSITION_LINK, entry1_->GetTransitionType());
- EXPECT_EQ(PAGE_TRANSITION_TYPED, entry2_->GetTransitionType());
- entry2_->SetTransitionType(PAGE_TRANSITION_RELOAD);
- EXPECT_EQ(PAGE_TRANSITION_RELOAD, entry2_->GetTransitionType());
+ EXPECT_EQ(ui::PAGE_TRANSITION_LINK, entry1_->GetTransitionType());
+ EXPECT_EQ(ui::PAGE_TRANSITION_TYPED, entry2_->GetTransitionType());
+ entry2_->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
+ EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD, entry2_->GetTransitionType());
// Is renderer initiated
EXPECT_FALSE(entry1_->is_renderer_initiated());
diff --git a/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc b/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc
index 1e476827703..162cfb79043 100644
--- a/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc
+++ b/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.cc
@@ -13,9 +13,6 @@
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/common/content_switches.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/effects/SkLumaColorFilter.h"
#include "ui/gfx/codec/png_codec.h"
namespace {
@@ -27,7 +24,7 @@ const int kMinScreenshotIntervalMS = 1000;
namespace content {
-// Converts SkBitmap to grayscale and encodes to PNG data in a worker thread.
+// Encodes the A8 SkBitmap to grayscale PNG in a worker thread.
class ScreenshotData : public base::RefCountedThreadSafe<ScreenshotData> {
public:
ScreenshotData() {
@@ -52,22 +49,10 @@ class ScreenshotData : public base::RefCountedThreadSafe<ScreenshotData> {
}
void EncodeOnWorker(const SkBitmap& bitmap) {
+ DCHECK_EQ(bitmap.colorType(), kAlpha_8_SkColorType);
+ // Encode the A8 bitmap to grayscale PNG treating alpha as color intensity.
std::vector<unsigned char> data;
- // Paint |bitmap| to a kA8_Config SkBitmap
- SkBitmap a8Bitmap;
- a8Bitmap.setConfig(SkBitmap::kA8_Config,
- bitmap.width(),
- bitmap.height(),
- 0);
- a8Bitmap.allocPixels();
- SkCanvas canvas(a8Bitmap);
- SkPaint paint;
- SkColorFilter* filter = SkLumaColorFilter::Create();
- paint.setColorFilter(filter);
- filter->unref();
- canvas.drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
- // Encode the a8Bitmap to grayscale PNG treating alpha as color intensity
- if (gfx::PNGCodec::EncodeA8SkBitmap(a8Bitmap, &data))
+ if (gfx::PNGCodec::EncodeA8SkBitmap(bitmap, &data))
data_ = new base::RefCountedBytes(data);
}
@@ -79,15 +64,16 @@ class ScreenshotData : public base::RefCountedThreadSafe<ScreenshotData> {
NavigationEntryScreenshotManager::NavigationEntryScreenshotManager(
NavigationControllerImpl* owner)
: owner_(owner),
- screenshot_factory_(this),
- min_screenshot_interval_ms_(kMinScreenshotIntervalMS) {
+ min_screenshot_interval_ms_(kMinScreenshotIntervalMS),
+ screenshot_factory_(this) {
+
}
NavigationEntryScreenshotManager::~NavigationEntryScreenshotManager() {
}
void NavigationEntryScreenshotManager::TakeScreenshot() {
- static bool overscroll_enabled = CommandLine::ForCurrentProcess()->
+ static bool overscroll_enabled = base::CommandLine::ForCurrentProcess()->
GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
if (!overscroll_enabled)
return;
@@ -134,14 +120,13 @@ void NavigationEntryScreenshotManager::TakeScreenshotImpl(
NavigationEntryImpl* entry) {
DCHECK(host && host->GetView());
DCHECK(entry);
- SkBitmap::Config preferred_format = host->PreferredReadbackFormat();
host->CopyFromBackingStore(
gfx::Rect(),
host->GetView()->GetViewBounds().size(),
base::Bind(&NavigationEntryScreenshotManager::OnScreenshotTaken,
screenshot_factory_.GetWeakPtr(),
entry->GetUniqueID()),
- preferred_format);
+ kAlpha_8_SkColorType);
}
void NavigationEntryScreenshotManager::SetMinScreenshotIntervalMS(
diff --git a/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.h b/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.h
index 072d6fd4a7f..21c78f18e62 100644
--- a/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.h
+++ b/chromium/content/browser/frame_host/navigation_entry_screenshot_manager.h
@@ -74,14 +74,14 @@ class CONTENT_EXPORT NavigationEntryScreenshotManager {
// The navigation controller that owns this screenshot-manager.
NavigationControllerImpl* owner_;
+ base::Time last_screenshot_time_;
+ int min_screenshot_interval_ms_;
+
// Taking a screenshot and encoding them can be async. So use a weakptr for
// the callback to make sure that the screenshot/encoding completion callback
// does not trigger on a destroyed NavigationEntryScreenshotManager.
base::WeakPtrFactory<NavigationEntryScreenshotManager> screenshot_factory_;
- base::Time last_screenshot_time_;
- int min_screenshot_interval_ms_;
-
DISALLOW_COPY_AND_ASSIGN(NavigationEntryScreenshotManager);
};
diff --git a/chromium/content/browser/frame_host/navigation_request.cc b/chromium/content/browser/frame_host/navigation_request.cc
new file mode 100644
index 00000000000..57f5479727c
--- /dev/null
+++ b/chromium/content/browser/frame_host/navigation_request.cc
@@ -0,0 +1,67 @@
+// 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/frame_host/navigation_request.h"
+
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/navigation_request_info.h"
+#include "content/browser/frame_host/navigator.h"
+#include "content/browser/loader/navigation_url_loader.h"
+#include "content/common/resource_request_body.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/stream_handle.h"
+#include "net/url_request/redirect_info.h"
+
+namespace content {
+
+NavigationRequest::NavigationRequest(
+ FrameTreeNode* frame_tree_node,
+ const CommonNavigationParams& common_params,
+ const CommitNavigationParams& commit_params)
+ : frame_tree_node_(frame_tree_node),
+ common_params_(common_params),
+ commit_params_(commit_params) {
+}
+
+NavigationRequest::~NavigationRequest() {
+}
+
+void NavigationRequest::BeginNavigation(
+ scoped_ptr<NavigationRequestInfo> info,
+ scoped_refptr<ResourceRequestBody> request_body) {
+ DCHECK(!loader_);
+ loader_ = NavigationURLLoader::Create(
+ frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
+ frame_tree_node_->frame_tree_node_id(), common_params_, info.Pass(),
+ request_body.get(), this);
+
+ // TODO(davidben): Fire (and add as necessary) observer methods such as
+ // DidStartProvisionalLoadForFrame for the navigation.
+}
+
+void NavigationRequest::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ const scoped_refptr<ResourceResponse>& response) {
+ // TODO(davidben): Track other changes from redirects. These are important
+ // for, e.g., reloads.
+ common_params_.url = redirect_info.new_url;
+
+ // TODO(davidben): This where prerender and navigation_interceptor should be
+ // integrated. For now, just always follow all redirects.
+ loader_->FollowRedirect();
+}
+
+void NavigationRequest::OnResponseStarted(
+ const scoped_refptr<ResourceResponse>& response,
+ scoped_ptr<StreamHandle> body) {
+ frame_tree_node_->navigator()->CommitNavigation(frame_tree_node_,
+ response.get(), body.Pass());
+}
+
+void NavigationRequest::OnRequestFailed(int net_error) {
+ // TODO(davidben): Network failures should display a network error page.
+ NOTIMPLEMENTED();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_request.h b/chromium/content/browser/frame_host/navigation_request.h
new file mode 100644
index 00000000000..eb537211374
--- /dev/null
+++ b/chromium/content/browser/frame_host/navigation_request.h
@@ -0,0 +1,74 @@
+// 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_FRAME_HOST_NAVIGATION_REQUEST_H_
+#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_REQUEST_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/loader/navigation_url_loader_delegate.h"
+#include "content/common/content_export.h"
+#include "content/common/navigation_params.h"
+
+namespace content {
+
+class FrameTreeNode;
+class NavigationURLLoader;
+class ResourceRequestBody;
+struct NavigationRequestInfo;
+
+// PlzNavigate
+// A UI thread object that owns a navigation request until it commits. It
+// ensures the UI thread can start a navigation request in the
+// ResourceDispatcherHost (that lives on the IO thread).
+// TODO(clamy): Describe the interactions between the UI and IO thread during
+// the navigation following its refactoring.
+class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate {
+ public:
+ NavigationRequest(FrameTreeNode* frame_tree_node,
+ const CommonNavigationParams& common_params,
+ const CommitNavigationParams& commit_params);
+
+ ~NavigationRequest() override;
+
+ // Called on the UI thread by the RenderFrameHostManager which owns the
+ // NavigationRequest. Takes ownership of |info|. After calling this function,
+ // |body| can no longer be manipulated on the UI thread.
+ void BeginNavigation(scoped_ptr<NavigationRequestInfo> info,
+ scoped_refptr<ResourceRequestBody> body);
+
+ CommonNavigationParams& common_params() { return common_params_; }
+
+ const CommitNavigationParams& commit_params() const { return commit_params_; }
+
+ NavigationURLLoader* loader_for_testing() const { return loader_.get(); }
+
+ private:
+ // NavigationURLLoaderDelegate implementation.
+ void OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ const scoped_refptr<ResourceResponse>& response) override;
+ void OnResponseStarted(const scoped_refptr<ResourceResponse>& response,
+ scoped_ptr<StreamHandle> body) override;
+ void OnRequestFailed(int net_error) override;
+
+ FrameTreeNode* frame_tree_node_;
+
+ // Initialized on creation of the NavigationRequest. Sent to the renderer when
+ // the navigation is ready to commit.
+ // Note: When the navigation is ready to commit, the url in |common_params|
+ // will be set to the final navigation url, obtained after following all
+ // redirects.
+ CommonNavigationParams common_params_;
+ const CommitNavigationParams commit_params_;
+
+ scoped_ptr<NavigationURLLoader> loader_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationRequest);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_REQUEST_H_
diff --git a/chromium/content/browser/frame_host/navigation_request_info.cc b/chromium/content/browser/frame_host/navigation_request_info.cc
new file mode 100644
index 00000000000..91568ad36df
--- /dev/null
+++ b/chromium/content/browser/frame_host/navigation_request_info.cc
@@ -0,0 +1,18 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/frame_host/navigation_request_info.h"
+
+#include "content/common/resource_request_body.h"
+
+namespace content {
+
+NavigationRequestInfo::NavigationRequestInfo(
+ const FrameHostMsg_BeginNavigation_Params& params)
+ : navigation_params(params),
+ is_main_frame(true),
+ parent_is_main_frame(false) {
+}
+
+} // namespace content
diff --git a/chromium/content/browser/frame_host/navigation_request_info.h b/chromium/content/browser/frame_host/navigation_request_info.h
new file mode 100644
index 00000000000..70bb78729dd
--- /dev/null
+++ b/chromium/content/browser/frame_host/navigation_request_info.h
@@ -0,0 +1,40 @@
+// 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_FRAME_HOST_NAVIGATION_REQUEST_INFO_H_
+#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_REQUEST_INFO_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "content/common/content_export.h"
+#include "content/common/frame_messages.h"
+#include "content/public/common/referrer.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// A struct to hold the parameters needed to start a navigation request in
+// ResourceDispatcherHost. It is initialized on the UI thread, and then passed
+// to the IO thread by a NavigationRequest object.
+struct CONTENT_EXPORT NavigationRequestInfo {
+ explicit NavigationRequestInfo(
+ const FrameHostMsg_BeginNavigation_Params& params);
+
+ const FrameHostMsg_BeginNavigation_Params navigation_params;
+
+ // ---------------------------------------------------------------------------
+ // The following parameters should be filled in by RenderFrameHostManager
+ // before the navigation request is sent to the ResourceDispatcherHost.
+
+ // Usually the URL of the document in the top-level window, which may be
+ // checked by the third-party cookie blocking policy.
+ GURL first_party_for_cookies;
+ bool is_main_frame;
+ bool parent_is_main_frame;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_REQUEST_INFO_H_
diff --git a/chromium/content/browser/frame_host/navigator.cc b/chromium/content/browser/frame_host/navigator.cc
index 3d5eb8f906b..3f5d6cb5f99 100644
--- a/chromium/content/browser/frame_host/navigator.cc
+++ b/chromium/content/browser/frame_host/navigator.cc
@@ -5,6 +5,7 @@
#include "content/browser/frame_host/navigator.h"
#include "base/time/time.h"
+#include "content/public/browser/stream_handle.h"
namespace content {
@@ -22,4 +23,9 @@ base::TimeTicks Navigator::GetCurrentLoadStart() {
return base::TimeTicks::Now();
}
+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 a64edeb717b..5063faf20e5 100644
--- a/chromium/content/browser/frame_host/navigator.h
+++ b/chromium/content/browser/frame_host/navigator.h
@@ -6,11 +6,13 @@
#define CONTENT_BROWSER_FRAME_HOST_NAVIGATOR_H_
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_controller.h"
#include "ui/base/window_open_disposition.h"
class GURL;
+struct FrameHostMsg_BeginNavigation_Params;
struct FrameHostMsg_DidCommitProvisionalLoad_Params;
struct FrameHostMsg_DidFailProvisionalLoadWithError_Params;
@@ -20,10 +22,15 @@ class TimeTicks;
namespace content {
+class FrameTreeNode;
class NavigationControllerImpl;
class NavigationEntryImpl;
+class NavigationRequest;
class NavigatorDelegate;
class RenderFrameHostImpl;
+class StreamHandle;
+struct CommonNavigationParams;
+struct ResourceResponse;
// Implementations of this interface are responsible for performing navigations
// in a node of the FrameTree. Its lifetime is bound to all FrameTreeNode
@@ -37,13 +44,12 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
// Returns the NavigationController associated with this Navigator.
virtual NavigationController* GetController();
-
// Notifications coming from the RenderFrameHosts ----------------------------
// The RenderFrameHostImpl started a provisional load.
virtual void DidStartProvisionalLoad(RenderFrameHostImpl* render_frame_host,
- int parent_routing_id,
- const GURL& url) {};
+ const GURL& url,
+ bool is_transition_navigation) {};
// The RenderFrameHostImpl has failed a provisional load.
virtual void DidFailProvisionalLoadWithError(
@@ -57,17 +63,6 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
int error_code,
const base::string16& error_description) {}
- // The RenderFrameHostImpl processed a redirect during a provisional load.
- //
- // TODO(creis): Remove this method and have the pre-rendering code listen to
- // WebContentsObserver::DidGetRedirectForResourceRequest instead.
- // See http://crbug.com/78512.
- virtual void DidRedirectProvisionalLoad(
- RenderFrameHostImpl* render_frame_host,
- int32 page_id,
- const GURL& source_url,
- const GURL& target_url) {}
-
// The RenderFrameHostImpl has committed a navigation.
virtual void DidNavigate(
RenderFrameHostImpl* render_frame_host,
@@ -113,12 +108,45 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> {
const GURL& url,
const std::vector<GURL>& redirect_chain,
const Referrer& referrer,
- PageTransition page_transition,
+ ui::PageTransition page_transition,
WindowOpenDisposition disposition,
const GlobalRequestID& transferred_global_request_id,
bool should_replace_current_entry,
bool user_gesture) {}
+ // PlzNavigate: Used to start a navigation. OnBeginNavigation is called
+ // directly by RequestNavigation when there is no live renderer. Otherwise, it
+ // is called following a BeginNavigation IPC from the renderer (which in
+ // browser-initiated navigation also happens after RequestNavigation has been
+ // called).
+ virtual void OnBeginNavigation(
+ FrameTreeNode* frame_tree_node,
+ const FrameHostMsg_BeginNavigation_Params& params,
+ const CommonNavigationParams& common_params) {}
+
+ // 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
+ // Cancel a NavigationRequest for |frame_tree_node|. Called when
+ // |frame_tree_node| is destroyed.
+ virtual void CancelNavigation(FrameTreeNode* frame_tree_node) {}
+
+ // Called when the first resource request for a given navigation is executed
+ // so that it can be tracked into an histogram.
+ virtual void LogResourceRequestTime(
+ base::TimeTicks timestamp, const GURL& url) {};
+
+ // Called to record the time it took to execute the before unload hook for the
+ // current navigation.
+ virtual void LogBeforeUnloadTime(
+ const base::TimeTicks& renderer_before_unload_start_time,
+ const base::TimeTicks& renderer_before_unload_end_time) {}
+
protected:
friend class base::RefCounted<Navigator>;
virtual ~Navigator() {}
diff --git a/chromium/content/browser/frame_host/navigator_delegate.h b/chromium/content/browser/frame_host/navigator_delegate.h
index 0835fe04a49..80ed2135223 100644
--- a/chromium/content/browser/frame_host/navigator_delegate.h
+++ b/chromium/content/browser/frame_host/navigator_delegate.h
@@ -8,7 +8,7 @@
#include "base/strings/string16.h"
#include "content/public/browser/invalidate_type.h"
#include "content/public/browser/navigation_controller.h"
-#include "content/public/common/page_transition_types.h"
+#include "ui/base/page_transition_types.h"
#include "ui/base/window_open_disposition.h"
class GURL;
@@ -29,11 +29,14 @@ class CONTENT_EXPORT NavigatorDelegate {
// represented by |render_frame_host|.
virtual void DidStartProvisionalLoad(
RenderFrameHostImpl* render_frame_host,
- int parent_routing_id,
const GURL& validated_url,
bool is_error_page,
bool is_iframe_srcdoc) {}
+ // The |render_frame_host| started a transition-flagged navigation.
+ virtual void DidStartNavigationTransition(
+ RenderFrameHostImpl* render_frame_host) {}
+
// A provisional load in |render_frame_host| failed.
virtual void DidFailProvisionalLoadWithError(
RenderFrameHostImpl* render_frame_host,
@@ -46,23 +49,15 @@ class CONTENT_EXPORT NavigatorDelegate {
int error_code,
const base::string16& error_description) {}
- // A redirect was processed in |render_frame_host| during a provisional load.
- virtual void DidRedirectProvisionalLoad(
- RenderFrameHostImpl* render_frame_host,
- const GURL& validated_target_url) {}
-
// A navigation was committed in |render_frame_host|.
virtual void DidCommitProvisionalLoad(
RenderFrameHostImpl* render_frame_host,
- const base::string16& frame_unique_name,
- bool is_main_frame,
const GURL& url,
- PageTransition transition_type) {}
+ ui::PageTransition transition_type) {}
// Handles post-navigation tasks in navigation BEFORE the entry has been
// committed to the NavigationController.
- virtual void DidNavigateMainFramePreCommit(
- const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {}
+ virtual void DidNavigateMainFramePreCommit(bool navigation_is_within_page) {}
// Handles post-navigation tasks in navigation AFTER the entry has been
// committed to the NavigationController. Note that the NavigationEntry is
diff --git a/chromium/content/browser/frame_host/navigator_impl.cc b/chromium/content/browser/frame_host/navigator_impl.cc
index e12df2ac420..e3b56215d4d 100644
--- a/chromium/content/browser/frame_host/navigator_impl.cc
+++ b/chromium/content/browser/frame_host/navigator_impl.cc
@@ -5,17 +5,21 @@
#include "content/browser/frame_host/navigator_impl.h"
#include "base/command_line.h"
+#include "base/metrics/histogram.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/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/frame_host/navigation_request.h"
+#include "content/browser/frame_host/navigation_request_info.h"
#include "content/browser/frame_host/navigator_delegate.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/browser/webui/web_ui_impl.h"
-#include "content/common/frame_messages.h"
+#include "content/common/navigation_params.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
@@ -25,11 +29,16 @@
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/stream_handle.h"
+#include "content/public/browser/user_metrics.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/resource_response.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
namespace content {
@@ -61,13 +70,89 @@ FrameMsg_Navigate_Type::Value GetNavigationType(
return FrameMsg_Navigate_Type::NORMAL;
}
+// PlzNavigate
+// Returns the net load flags to use based on the navigation type.
+// TODO(clamy): unify the code with what is happening on the renderer side.
+int LoadFlagFromNavigationType(FrameMsg_Navigate_Type::Value navigation_type) {
+ int load_flags = net::LOAD_NORMAL;
+ switch (navigation_type) {
+ case FrameMsg_Navigate_Type::RELOAD:
+ case FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL:
+ load_flags |= net::LOAD_VALIDATE_CACHE;
+ break;
+ case FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE:
+ load_flags |= net::LOAD_BYPASS_CACHE;
+ break;
+ case FrameMsg_Navigate_Type::RESTORE:
+ load_flags |= net::LOAD_PREFERRING_CACHE;
+ break;
+ case FrameMsg_Navigate_Type::RESTORE_WITH_POST:
+ load_flags |= net::LOAD_ONLY_FROM_CACHE;
+ break;
+ case FrameMsg_Navigate_Type::NORMAL:
+ default:
+ break;
+ }
+ return load_flags;
+}
+
+// PlzNavigate
+// Generates a default FrameHostMsg_BeginNavigation_Params to be used when there
+// is no live renderer.
+FrameHostMsg_BeginNavigation_Params MakeDefaultBeginNavigation(
+ const RequestNavigationParams& request_params,
+ FrameMsg_Navigate_Type::Value navigation_type) {
+ FrameHostMsg_BeginNavigation_Params begin_navigation_params;
+ begin_navigation_params.method = request_params.is_post ? "POST" : "GET";
+ begin_navigation_params.load_flags =
+ LoadFlagFromNavigationType(navigation_type);
+
+ // TODO(clamy): Post data from the browser should be put in the request body.
+ // Headers should be filled in as well.
+
+ begin_navigation_params.has_user_gesture = false;
+ return begin_navigation_params;
+}
+
+RenderFrameHostManager* GetRenderManager(RenderFrameHostImpl* rfh) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return rfh->frame_tree_node()->render_manager();
+
+ return rfh->frame_tree_node()->frame_tree()->root()->render_manager();
+}
+
void MakeNavigateParams(const NavigationEntryImpl& entry,
- const NavigationControllerImpl& controller,
+ NavigationControllerImpl* controller,
NavigationController::ReloadType reload_type,
+ base::TimeTicks navigation_start,
FrameMsg_Navigate_Params* params) {
+ params->common_params = CommonNavigationParams(
+ entry.GetURL(), entry.GetReferrer(), entry.GetTransitionType(),
+ GetNavigationType(controller->GetBrowserContext(), entry, reload_type),
+ !entry.IsViewSourceMode());
+ params->request_params = RequestNavigationParams(
+ entry.GetHasPostData(),
+ entry.extra_headers(),
+ entry.GetBrowserInitiatedPostData());
+ params->commit_params = CommitNavigationParams(
+ entry.GetPageState(), entry.GetIsOverridingUserAgent(), navigation_start);
+ if (!entry.GetBaseURLForDataURL().is_empty()) {
+ params->base_url_for_data_url = entry.GetBaseURLForDataURL();
+ params->history_url_for_data_url = entry.GetVirtualURL();
+ }
+ params->should_replace_current_entry = entry.should_replace_entry();
+ // This is used by the old performance infrastructure to set up DocumentState
+ // associated with the RenderView.
+ // TODO(ppi): make it go away.
+ params->request_time = base::Time::Now();
+ params->transferred_request_child_id =
+ entry.transferred_global_request_id().child_id;
+ params->transferred_request_request_id =
+ entry.transferred_global_request_id().request_id;
+
params->page_id = entry.GetPageID();
params->should_clear_history_list = entry.should_clear_history_list();
- params->should_replace_current_entry = entry.should_replace_entry();
if (entry.should_clear_history_list()) {
// Set the history list related parameters to the same values a
// NavigationController would return before its first navigation. This will
@@ -76,41 +161,14 @@ void MakeNavigateParams(const NavigationEntryImpl& entry,
params->current_history_list_offset = -1;
params->current_history_list_length = 0;
} else {
- params->pending_history_list_offset = controller.GetIndexOfEntry(&entry);
+ params->pending_history_list_offset = controller->GetIndexOfEntry(&entry);
params->current_history_list_offset =
- controller.GetLastCommittedEntryIndex();
- params->current_history_list_length = controller.GetEntryCount();
+ controller->GetLastCommittedEntryIndex();
+ params->current_history_list_length = controller->GetEntryCount();
}
- params->url = entry.GetURL();
- if (!entry.GetBaseURLForDataURL().is_empty()) {
- params->base_url_for_data_url = entry.GetBaseURLForDataURL();
- params->history_url_for_data_url = entry.GetVirtualURL();
- }
- params->referrer = entry.GetReferrer();
- params->transition = entry.GetTransitionType();
- params->page_state = entry.GetPageState();
- params->navigation_type =
- GetNavigationType(controller.GetBrowserContext(), entry, reload_type);
- params->request_time = base::Time::Now();
- params->extra_headers = entry.extra_headers();
- params->transferred_request_child_id =
- entry.transferred_global_request_id().child_id;
- params->transferred_request_request_id =
- entry.transferred_global_request_id().request_id;
- params->is_overriding_user_agent = entry.GetIsOverridingUserAgent();
- // Avoid downloading when in view-source mode.
- params->allow_download = !entry.IsViewSourceMode();
- params->is_post = entry.GetHasPostData();
- if (entry.GetBrowserInitiatedPostData()) {
- params->browser_initiated_post_data.assign(
- entry.GetBrowserInitiatedPostData()->front(),
- entry.GetBrowserInitiatedPostData()->front() +
- entry.GetBrowserInitiatedPostData()->size());
- }
-
// Set the redirect chain to the navigation's redirects, unless we are
// returning to a completed navigation (whose previous redirects don't apply).
- if (PageTransitionIsNewNavigation(params->transition)) {
+ if (ui::PageTransitionIsNewNavigation(params->common_params.transition)) {
params->redirects = entry.GetRedirectChain();
} else {
params->redirects.clear();
@@ -120,15 +178,25 @@ void MakeNavigateParams(const NavigationEntryImpl& entry,
params->frame_to_navigate = entry.GetFrameToNavigate();
}
-RenderFrameHostManager* GetRenderManager(RenderFrameHostImpl* rfh) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
- return rfh->frame_tree_node()->render_manager();
-
- return rfh->frame_tree_node()->frame_tree()->root()->render_manager();
-}
-
} // namespace
+struct NavigatorImpl::NavigationMetricsData {
+ NavigationMetricsData(base::TimeTicks start_time,
+ GURL url,
+ NavigationEntryImpl::RestoreType restore_type)
+ : start_time_(start_time), url_(url) {
+ is_restoring_from_last_session_ =
+ (restore_type ==
+ NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY ||
+ restore_type == NavigationEntryImpl::RESTORE_LAST_SESSION_CRASHED);
+ }
+
+ base::TimeTicks start_time_;
+ GURL url_;
+ bool is_restoring_from_last_session_;
+ base::TimeTicks url_job_start_time_;
+ base::TimeDelta before_unload_delay_;
+};
NavigatorImpl::NavigatorImpl(
NavigationControllerImpl* navigation_controller,
@@ -137,14 +205,16 @@ NavigatorImpl::NavigatorImpl(
delegate_(delegate) {
}
+NavigatorImpl::~NavigatorImpl() {}
+
NavigationController* NavigatorImpl::GetController() {
return controller_;
}
void NavigatorImpl::DidStartProvisionalLoad(
RenderFrameHostImpl* render_frame_host,
- int parent_routing_id,
- const GURL& url) {
+ const GURL& url,
+ bool is_transition_navigation) {
bool is_error_page = (url.spec() == kUnreachableWebDataURL);
bool is_iframe_srcdoc = (url.spec() == kAboutSrcDocURL);
GURL validated_url(url);
@@ -166,7 +236,7 @@ void NavigatorImpl::DidStartProvisionalLoad(
NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
controller_->CreateNavigationEntry(validated_url,
content::Referrer(),
- content::PAGE_TRANSITION_LINK,
+ ui::PAGE_TRANSITION_LINK,
true /* is_renderer_initiated */,
std::string(),
controller_->GetBrowserContext()));
@@ -185,13 +255,15 @@ void NavigatorImpl::DidStartProvisionalLoad(
if (delegate_)
delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL);
}
+
+ if (delegate_ && is_transition_navigation)
+ delegate_->DidStartNavigationTransition(render_frame_host);
}
if (delegate_) {
// Notify the observer about the start of the provisional load.
delegate_->DidStartProvisionalLoad(
- render_frame_host, parent_routing_id,
- validated_url, is_error_page, is_iframe_srcdoc);
+ render_frame_host, validated_url, is_error_page, is_iframe_srcdoc);
}
}
@@ -281,40 +353,11 @@ void NavigatorImpl::DidFailLoadWithError(
}
}
-void NavigatorImpl::DidRedirectProvisionalLoad(
- RenderFrameHostImpl* render_frame_host,
- int32 page_id,
- const GURL& source_url,
- const GURL& target_url) {
- // TODO(creis): Remove this method and have the pre-rendering code listen to
- // WebContentsObserver::DidGetRedirectForResourceRequest instead.
- // See http://crbug.com/78512.
- GURL validated_source_url(source_url);
- GURL validated_target_url(target_url);
- RenderProcessHost* render_process_host = render_frame_host->GetProcess();
- render_process_host->FilterURL(false, &validated_source_url);
- render_process_host->FilterURL(false, &validated_target_url);
- NavigationEntry* entry;
- if (page_id == -1) {
- entry = controller_->GetPendingEntry();
- } else {
- entry = controller_->GetEntryWithPageID(
- render_frame_host->GetSiteInstance(), page_id);
- }
- if (!entry || entry->GetURL() != validated_source_url)
- return;
-
- if (delegate_) {
- delegate_->DidRedirectProvisionalLoad(
- render_frame_host, validated_target_url);
- }
-}
-
bool NavigatorImpl::NavigateToEntry(
RenderFrameHostImpl* render_frame_host,
const NavigationEntryImpl& entry,
NavigationController::ReloadType reload_type) {
- TRACE_EVENT0("browser", "NavigatorImpl::NavigateToEntry");
+ TRACE_EVENT0("browser,navigation", "NavigatorImpl::NavigateToEntry");
// The renderer will reject IPC messages with URLs longer than
// this limit, so don't attempt to navigate with a longer URL.
@@ -324,8 +367,26 @@ bool NavigatorImpl::NavigateToEntry(
return false;
}
+ // This will be used to set the Navigation Timing API navigationStart
+ // parameter for browser navigations in new tabs (intents, tabs opened through
+ // "Open link in new tab"). We need to keep it above RFHM::Navigate() call to
+ // capture the time needed for the RenderFrameHost initialization.
+ base::TimeTicks navigation_start = base::TimeTicks::Now();
+
RenderFrameHostManager* manager =
render_frame_host->frame_tree_node()->render_manager();
+
+ // PlzNavigate: the RenderFrameHosts are no longer asked to navigate.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ navigation_data_.reset(new NavigationMetricsData(
+ navigation_start, entry.GetURL(), entry.restore_type()));
+ return RequestNavigation(render_frame_host->frame_tree_node(),
+ entry,
+ reload_type,
+ navigation_start);
+ }
+
RenderFrameHostImpl* dest_render_frame_host = manager->Navigate(entry);
if (!dest_render_frame_host)
return false; // Unable to create the desired RenderFrameHost.
@@ -335,29 +396,38 @@ bool NavigatorImpl::NavigateToEntry(
// For security, we should never send non-Web-UI URLs to a Web UI renderer.
// Double check that here.
- int enabled_bindings =
- dest_render_frame_host->render_view_host()->GetEnabledBindings();
- bool is_allowed_in_web_ui_renderer =
- WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
- controller_->GetBrowserContext(), entry.GetURL());
- 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(entry.GetURL());
- CHECK(0);
- }
+ CheckWebUIRendererDoesNotDisplayNormalURL(
+ dest_render_frame_host, entry.GetURL());
// Notify observers that we will navigate in this RenderFrame.
if (delegate_)
delegate_->AboutToNavigateRenderFrame(dest_render_frame_host);
- // Used for page load time metrics.
- current_load_start_ = base::TimeTicks::Now();
+ // Create the navigation parameters.
+ // TODO(vitalybuka): Move this before AboutToNavigateRenderFrame once
+ // http://crbug.com/408684 is fixed.
+ FrameMsg_Navigate_Params navigate_params;
+ MakeNavigateParams(
+ entry, controller_, reload_type, navigation_start, &navigate_params);
// Navigate in the desired RenderFrameHost.
- FrameMsg_Navigate_Params navigate_params;
- MakeNavigateParams(entry, *controller_, reload_type, &navigate_params);
- dest_render_frame_host->Navigate(navigate_params);
+ // 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 =
+ navigate_params.transferred_request_child_id != -1 &&
+ navigate_params.transferred_request_child_id ==
+ dest_render_frame_host->GetProcess()->GetID();
+ if (!is_transfer_to_same) {
+ navigation_data_.reset(new NavigationMetricsData(
+ navigation_start, entry.GetURL(), entry.restore_type()));
+ dest_render_frame_host->Navigate(navigate_params);
+ } else {
+ // No need to navigate again. Just resume the deferred request.
+ dest_render_frame_host->GetProcess()->ResumeDeferredNavigation(
+ GlobalRequestID(navigate_params.transferred_request_child_id,
+ navigate_params.transferred_request_request_id));
+ }
// Make sure no code called via RFH::Navigate clears the pending entry.
CHECK_EQ(controller_->GetPendingEntry(), &entry);
@@ -374,7 +444,7 @@ bool NavigatorImpl::NavigateToEntry(
// Notify observers about navigation.
if (delegate_) {
- delegate_->DidStartNavigationToPendingEntry(render_frame_host,
+ delegate_->DidStartNavigationToPendingEntry(dest_render_frame_host,
entry.GetURL(),
reload_type);
}
@@ -391,17 +461,22 @@ bool NavigatorImpl::NavigateToPendingEntry(
reload_type);
}
-base::TimeTicks NavigatorImpl::GetCurrentLoadStart() {
- return current_load_start_;
-}
-
void NavigatorImpl::DidNavigate(
RenderFrameHostImpl* render_frame_host,
const FrameHostMsg_DidCommitProvisionalLoad_Params& input_params) {
+ // PlzNavigate
+ // The navigation request has been committed so the browser process doesn't
+ // need to care about it anymore.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ navigation_request_map_.erase(
+ render_frame_host->frame_tree_node()->frame_tree_node_id());
+ }
+
FrameHostMsg_DidCommitProvisionalLoad_Params params(input_params);
FrameTree* frame_tree = render_frame_host->frame_tree_node()->frame_tree();
- bool use_site_per_process =
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess);
+ bool use_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess);
if (use_site_per_process) {
// TODO(creis): Until we mirror the frame tree in the subframe's process,
@@ -414,11 +489,11 @@ void NavigatorImpl::DidNavigate(
pending_entry &&
pending_entry->frame_tree_node_id() ==
render_frame_host->frame_tree_node()->frame_tree_node_id()) {
- params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
+ params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
}
}
- if (PageTransitionIsMainFrame(params.transition)) {
+ if (ui::PageTransitionIsMainFrame(params.transition)) {
if (delegate_) {
// When overscroll navigation gesture is enabled, a screenshot of the page
// in its current state is taken so that it can be used during the
@@ -436,7 +511,9 @@ void NavigatorImpl::DidNavigate(
}
// Run tasks that must execute just before the commit.
- delegate_->DidNavigateMainFramePreCommit(params);
+ bool is_navigation_within_page = controller_->IsURLInPageNavigation(
+ params.url, params.was_within_same_page, render_frame_host);
+ delegate_->DidNavigateMainFramePreCommit(is_navigation_within_page);
}
if (!use_site_per_process)
@@ -472,7 +549,7 @@ void NavigatorImpl::DidNavigate(
// TODO(nasko): Verify the correctness of the above comment, since some of the
// code doesn't exist anymore. Also, move this code in the
// PageTransitionIsMainFrame code block above.
- if (PageTransitionIsMainFrame(params.transition) && delegate_)
+ if (ui::PageTransitionIsMainFrame(params.transition) && delegate_)
delegate_->SetMainFrameMimeType(params.contents_mime_type);
LoadCommittedDetails details;
@@ -488,25 +565,20 @@ void NavigatorImpl::DidNavigate(
// different from the NAV_ENTRY_COMMITTED notification which doesn't include
// the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations.
if (details.type != NAVIGATION_TYPE_NAV_IGNORE && delegate_) {
- // For AUTO_SUBFRAME navigations, an event for the main frame is generated
- // that is not recorded in the navigation history. For the purpose of
- // tracking navigation events, we treat this event as a sub frame navigation
- // event.
- bool is_main_frame = did_navigate ? details.is_main_frame : false;
- PageTransition transition_type = params.transition;
+ DCHECK_EQ(!render_frame_host->GetParent(),
+ did_navigate ? details.is_main_frame : false);
+ ui::PageTransition transition_type = params.transition;
// Whether or not a page transition was triggered by going backward or
// forward in the history is only stored in the navigation controller's
// entry list.
if (did_navigate &&
(controller_->GetLastCommittedEntry()->GetTransitionType() &
- PAGE_TRANSITION_FORWARD_BACK)) {
- transition_type = PageTransitionFromInt(
- params.transition | PAGE_TRANSITION_FORWARD_BACK);
+ ui::PAGE_TRANSITION_FORWARD_BACK)) {
+ transition_type = ui::PageTransitionFromInt(
+ params.transition | ui::PAGE_TRANSITION_FORWARD_BACK);
}
delegate_->DidCommitProvisionalLoad(render_frame_host,
- params.frame_unique_name,
- is_main_frame,
params.url,
transition_type);
}
@@ -519,6 +591,10 @@ void NavigatorImpl::DidNavigate(
// DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if
// necessary, please).
+ // TODO(carlosk): Move this out when PlzNavigate implementation properly calls
+ // the observer methods.
+ RecordNavigationMetrics(details, params, site_instance);
+
// Run post-commit tasks.
if (delegate_) {
if (details.is_main_frame)
@@ -550,9 +626,10 @@ void NavigatorImpl::RequestOpenURL(
SiteInstance* current_site_instance =
GetRenderManager(render_frame_host)->current_frame_host()->
GetSiteInstance();
- // If this came from a swapped out RenderViewHost, we only allow the request
+ // If this came from a swapped out RenderFrameHost, we only allow the request
// if we are still in the same BrowsingInstance.
- if (render_frame_host->render_view_host()->IsSwappedOut() &&
+ // TODO(creis): Move this to RenderFrameProxyHost::OpenURL.
+ if (render_frame_host->is_swapped_out() &&
!render_frame_host->GetSiteInstance()->IsRelatedSiteInstance(
current_site_instance)) {
return;
@@ -563,10 +640,15 @@ void NavigatorImpl::RequestOpenURL(
// TODO(creis): Pass the redirect_chain into this method to support client
// redirects. http://crbug.com/311721.
std::vector<GURL> redirect_chain;
- RequestTransferURL(
- render_frame_host, url, redirect_chain, referrer, PAGE_TRANSITION_LINK,
- disposition, GlobalRequestID(),
- should_replace_current_entry, user_gesture);
+ RequestTransferURL(render_frame_host,
+ url,
+ redirect_chain,
+ referrer,
+ ui::PAGE_TRANSITION_LINK,
+ disposition,
+ GlobalRequestID(),
+ should_replace_current_entry,
+ user_gesture);
}
void NavigatorImpl::RequestTransferURL(
@@ -574,7 +656,7 @@ void NavigatorImpl::RequestTransferURL(
const GURL& url,
const std::vector<GURL>& redirect_chain,
const Referrer& referrer,
- PageTransition page_transition,
+ ui::PageTransition page_transition,
WindowOpenDisposition disposition,
const GlobalRequestID& transferred_global_request_id,
bool should_replace_current_entry,
@@ -589,7 +671,8 @@ void NavigatorImpl::RequestTransferURL(
}
int64 frame_tree_node_id = -1;
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
frame_tree_node_id =
render_frame_host->frame_tree_node()->frame_tree_node_id();
}
@@ -607,7 +690,8 @@ void NavigatorImpl::RequestTransferURL(
// link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for
// automatically generated suggestions). We don't override other types
// like TYPED because they have different implications (e.g., autocomplete).
- if (PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_LINK))
+ if (ui::PageTransitionCoreTypeIs(
+ params.transition, ui::PAGE_TRANSITION_LINK))
params.transition =
GetRenderManager(render_frame_host)->web_ui()->
GetLinkTransitionType();
@@ -626,4 +710,216 @@ void NavigatorImpl::RequestTransferURL(
delegate_->RequestOpenURL(render_frame_host, params);
}
+// PlzNavigate
+void NavigatorImpl::OnBeginNavigation(
+ FrameTreeNode* frame_tree_node,
+ const FrameHostMsg_BeginNavigation_Params& params,
+ const CommonNavigationParams& common_params) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ DCHECK(frame_tree_node);
+
+ // TODO(clamy): In case of a renderer initiated navigation create a new
+ // NavigationRequest.
+ NavigationRequest* navigation_request =
+ navigation_request_map_.get(frame_tree_node->frame_tree_node_id());
+ DCHECK(navigation_request);
+
+ // Update the referrer with the one received from the renderer.
+ navigation_request->common_params().referrer = common_params.referrer;
+
+ scoped_ptr<NavigationRequestInfo> info(new NavigationRequestInfo(params));
+
+ info->first_party_for_cookies =
+ frame_tree_node->IsMainFrame()
+ ? navigation_request->common_params().url
+ : frame_tree_node->frame_tree()->root()->current_url();
+ info->is_main_frame = frame_tree_node->IsMainFrame();
+ info->parent_is_main_frame = !frame_tree_node->parent() ?
+ false : frame_tree_node->parent()->IsMainFrame();
+
+ // TODO(clamy): Inform the RenderFrameHostManager that a navigation is about
+ // to begin, so that it can speculatively spawn a new renderer if needed.
+
+ navigation_request->BeginNavigation(info.Pass(), params.request_body);
+}
+
+// PlzNavigate
+void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node,
+ ResourceResponse* response,
+ scoped_ptr<StreamHandle> body) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+
+ // HTTP 204 (No Content) and HTTP 205 (Reset Content) responses should not
+ // commit; they leave the frame showing the previous page.
+ if (response->head.headers.get() &&
+ (response->head.headers->response_code() == 204 ||
+ response->head.headers->response_code() == 205)) {
+ CancelNavigation(frame_tree_node);
+ return;
+ }
+
+ NavigationRequest* navigation_request =
+ navigation_request_map_.get(frame_tree_node->frame_tree_node_id());
+ DCHECK(navigation_request);
+
+ // Select an appropriate renderer to commit the navigation.
+ RenderFrameHostImpl* render_frame_host =
+ frame_tree_node->render_manager()->GetFrameHostForNavigation(
+ navigation_request->common_params().url,
+ navigation_request->common_params().transition);
+ CheckWebUIRendererDoesNotDisplayNormalURL(
+ render_frame_host, navigation_request->common_params().url);
+
+ render_frame_host->CommitNavigation(response, body.Pass(),
+ navigation_request->common_params(),
+ navigation_request->commit_params());
+}
+
+// PlzNavigate
+void NavigatorImpl::CancelNavigation(FrameTreeNode* frame_tree_node) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ navigation_request_map_.erase(frame_tree_node->frame_tree_node_id());
+}
+
+void NavigatorImpl::LogResourceRequestTime(
+ base::TimeTicks timestamp, const GURL& url) {
+ if (navigation_data_ && navigation_data_->url_ == url) {
+ navigation_data_->url_job_start_time_ = timestamp;
+ UMA_HISTOGRAM_TIMES(
+ "Navigation.TimeToURLJobStart",
+ navigation_data_->url_job_start_time_ - navigation_data_->start_time_);
+ }
+}
+
+void NavigatorImpl::LogBeforeUnloadTime(
+ const base::TimeTicks& renderer_before_unload_start_time,
+ const base::TimeTicks& renderer_before_unload_end_time) {
+ // Only stores the beforeunload delay if we're tracking a browser initiated
+ // navigation and it happened later than the navigation request.
+ if (navigation_data_ &&
+ renderer_before_unload_start_time > navigation_data_->start_time_) {
+ navigation_data_->before_unload_delay_ =
+ renderer_before_unload_end_time - renderer_before_unload_start_time;
+ }
+}
+
+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
+bool NavigatorImpl::RequestNavigation(
+ FrameTreeNode* frame_tree_node,
+ const NavigationEntryImpl& entry,
+ NavigationController::ReloadType reload_type,
+ base::TimeTicks navigation_start) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ DCHECK(frame_tree_node);
+ int64 frame_tree_node_id = frame_tree_node->frame_tree_node_id();
+ FrameMsg_Navigate_Type::Value navigation_type =
+ GetNavigationType(controller_->GetBrowserContext(), entry, reload_type);
+ scoped_ptr<NavigationRequest> navigation_request(new NavigationRequest(
+ frame_tree_node,
+ CommonNavigationParams(entry.GetURL(),
+ entry.GetReferrer(),
+ entry.GetTransitionType(),
+ navigation_type,
+ !entry.IsViewSourceMode()),
+ CommitNavigationParams(entry.GetPageState(),
+ entry.GetIsOverridingUserAgent(),
+ navigation_start)));
+ RequestNavigationParams request_params(entry.GetHasPostData(),
+ entry.extra_headers(),
+ entry.GetBrowserInitiatedPostData());
+ // TODO(clamy): Check if navigations are blocked and if so store the
+ // parameters.
+
+ // If there is an ongoing request, replace it.
+ navigation_request_map_.set(frame_tree_node_id, navigation_request.Pass());
+
+ if (frame_tree_node->current_frame_host()->IsRenderFrameLive()) {
+ frame_tree_node->current_frame_host()->Send(new FrameMsg_RequestNavigation(
+ frame_tree_node->current_frame_host()->GetRoutingID(),
+ navigation_request_map_.get(frame_tree_node_id)->common_params(),
+ request_params));
+ return true;
+ }
+
+ // The navigation request is sent directly to the IO thread.
+ OnBeginNavigation(
+ frame_tree_node,
+ MakeDefaultBeginNavigation(request_params, navigation_type),
+ navigation_request_map_.get(frame_tree_node_id)->common_params());
+ return true;
+}
+
+void NavigatorImpl::RecordNavigationMetrics(
+ const LoadCommittedDetails& details,
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
+ SiteInstance* site_instance) {
+ DCHECK(site_instance->HasProcess());
+
+ if (!details.is_in_page)
+ RecordAction(base::UserMetricsAction("FrameLoad"));
+
+ if (!details.is_main_frame || !navigation_data_ ||
+ navigation_data_->url_ != params.original_request_url) {
+ return;
+ }
+
+ base::TimeDelta time_to_commit =
+ base::TimeTicks::Now() - navigation_data_->start_time_;
+ UMA_HISTOGRAM_TIMES("Navigation.TimeToCommit", time_to_commit);
+
+ time_to_commit -= navigation_data_->before_unload_delay_;
+ base::TimeDelta time_to_network = navigation_data_->url_job_start_time_ -
+ navigation_data_->start_time_ -
+ navigation_data_->before_unload_delay_;
+ if (navigation_data_->is_restoring_from_last_session_) {
+ UMA_HISTOGRAM_TIMES(
+ "Navigation.TimeToCommit_SessionRestored_BeforeUnloadDiscounted",
+ time_to_commit);
+ UMA_HISTOGRAM_TIMES(
+ "Navigation.TimeToURLJobStart_SessionRestored_BeforeUnloadDiscounted",
+ time_to_network);
+ navigation_data_.reset();
+ return;
+ }
+ bool navigation_created_new_renderer_process =
+ site_instance->GetProcess()->GetInitTimeForNavigationMetrics() >
+ navigation_data_->start_time_;
+ if (navigation_created_new_renderer_process) {
+ UMA_HISTOGRAM_TIMES(
+ "Navigation.TimeToCommit_NewRenderer_BeforeUnloadDiscounted",
+ time_to_commit);
+ UMA_HISTOGRAM_TIMES(
+ "Navigation.TimeToURLJobStart_NewRenderer_BeforeUnloadDiscounted",
+ time_to_network);
+ } else {
+ UMA_HISTOGRAM_TIMES(
+ "Navigation.TimeToCommit_ExistingRenderer_BeforeUnloadDiscounted",
+ time_to_commit);
+ UMA_HISTOGRAM_TIMES(
+ "Navigation.TimeToURLJobStart_ExistingRenderer_BeforeUnloadDiscounted",
+ time_to_network);
+ }
+ navigation_data_.reset();
+}
+
} // namespace content
diff --git a/chromium/content/browser/frame_host/navigator_impl.h b/chromium/content/browser/frame_host/navigator_impl.h
index 1aa9a609c09..e142b3fd1ff 100644
--- a/chromium/content/browser/frame_host/navigator_impl.h
+++ b/chromium/content/browser/frame_host/navigator_impl.h
@@ -5,16 +5,28 @@
#ifndef CONTENT_BROWSER_FRAME_HOST_NAVIGATOR_IMPL_H_
#define CONTENT_BROWSER_FRAME_HOST_NAVIGATOR_IMPL_H_
+#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "base/tuple.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+class GURL;
+struct FrameMsg_Navigate_Params;
namespace content {
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.
@@ -24,51 +36,58 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
NavigatorDelegate* delegate);
// Navigator implementation.
- virtual NavigationController* GetController() OVERRIDE;
- virtual void DidStartProvisionalLoad(RenderFrameHostImpl* render_frame_host,
- int parent_routing_id,
- const GURL& url) OVERRIDE;
- virtual void DidFailProvisionalLoadWithError(
+ NavigationController* GetController() override;
+ void DidStartProvisionalLoad(RenderFrameHostImpl* render_frame_host,
+ const GURL& url,
+ bool is_transition_navigation) override;
+ void DidFailProvisionalLoadWithError(
RenderFrameHostImpl* render_frame_host,
const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params)
- OVERRIDE;
- virtual void DidFailLoadWithError(
- RenderFrameHostImpl* render_frame_host,
- const GURL& url,
- int error_code,
- const base::string16& error_description) OVERRIDE;
- virtual void DidRedirectProvisionalLoad(
- RenderFrameHostImpl* render_frame_host,
- int32 page_id,
- const GURL& source_url,
- const GURL& target_url) OVERRIDE;
- virtual void DidNavigate(
- RenderFrameHostImpl* render_frame_host,
- const FrameHostMsg_DidCommitProvisionalLoad_Params&
- input_params) OVERRIDE;
- virtual bool NavigateToPendingEntry(
- RenderFrameHostImpl* render_frame_host,
- NavigationController::ReloadType reload_type) OVERRIDE;
- virtual base::TimeTicks GetCurrentLoadStart() OVERRIDE;
- virtual void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
- const GURL& url,
- const Referrer& referrer,
- WindowOpenDisposition disposition,
- bool should_replace_current_entry,
- bool user_gesture) OVERRIDE;
- virtual void RequestTransferURL(
+ override;
+ void DidFailLoadWithError(RenderFrameHostImpl* render_frame_host,
+ const GURL& url,
+ int error_code,
+ const base::string16& error_description) override;
+ void DidNavigate(RenderFrameHostImpl* render_frame_host,
+ const FrameHostMsg_DidCommitProvisionalLoad_Params&
+ input_params) override;
+ bool NavigateToPendingEntry(
RenderFrameHostImpl* render_frame_host,
- const GURL& url,
- const std::vector<GURL>& redirect_chain,
- const Referrer& referrer,
- PageTransition page_transition,
- WindowOpenDisposition disposition,
- const GlobalRequestID& transferred_global_request_id,
- bool should_replace_current_entry,
- bool user_gesture) OVERRIDE;
+ NavigationController::ReloadType reload_type) override;
+ void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
+ const GURL& url,
+ const Referrer& referrer,
+ WindowOpenDisposition disposition,
+ bool should_replace_current_entry,
+ bool user_gesture) override;
+ void RequestTransferURL(RenderFrameHostImpl* render_frame_host,
+ const GURL& url,
+ const std::vector<GURL>& redirect_chain,
+ const Referrer& referrer,
+ ui::PageTransition page_transition,
+ WindowOpenDisposition disposition,
+ const GlobalRequestID& transferred_global_request_id,
+ bool should_replace_current_entry,
+ bool user_gesture) override;
+ void OnBeginNavigation(FrameTreeNode* frame_tree_node,
+ const FrameHostMsg_BeginNavigation_Params& params,
+ const CommonNavigationParams& common_params) override;
+ void CommitNavigation(FrameTreeNode* frame_tree_node,
+ ResourceResponse* response,
+ scoped_ptr<StreamHandle> body) override;
+ void LogResourceRequestTime(base::TimeTicks timestamp,
+ const GURL& url) override;
+ void LogBeforeUnloadTime(
+ const base::TimeTicks& renderer_before_unload_start_time,
+ const base::TimeTicks& renderer_before_unload_end_time) override;
+ void CancelNavigation(FrameTreeNode* frame_tree_node) override;
private:
- virtual ~NavigatorImpl() {}
+ // Holds data used to track browser side navigation metrics.
+ struct NavigationMetricsData;
+
+ friend class NavigatorTest;
+ ~NavigatorImpl() override;
// Navigates to the given entry, which must be the pending entry. Private
// because all callers should use NavigateToPendingEntry.
@@ -79,6 +98,23 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
bool ShouldAssignSiteForURL(const GURL& url);
+ void CheckWebUIRendererDoesNotDisplayNormalURL(
+ RenderFrameHostImpl* render_frame_host,
+ const GURL& url);
+
+ // PlzNavigate: sends a RequestNavigation IPC to the renderer to ask it to
+ // navigate. If no live renderer is present, then the navigation request will
+ // be sent directly to the ResourceDispatcherHost.
+ bool RequestNavigation(FrameTreeNode* frame_tree_node,
+ const NavigationEntryImpl& entry,
+ NavigationController::ReloadType reload_type,
+ base::TimeTicks navigation_start);
+
+ void RecordNavigationMetrics(
+ const LoadCommittedDetails& details,
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
+ SiteInstance* site_instance);
+
// The NavigationController that will keep track of session history for all
// RenderFrameHost objects using this NavigatorImpl.
// TODO(nasko): Move ownership of the NavigationController from
@@ -89,8 +125,12 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator {
// events. Can be NULL in tests.
NavigatorDelegate* delegate_;
- // System time at which the current load was started.
- base::TimeTicks current_load_start_;
+ scoped_ptr<NavigatorImpl::NavigationMetricsData> navigation_data_;
+
+ // PlzNavigate: used to track the various ongoing NavigationRequests in the
+ // different FrameTreeNodes, based on the frame_tree_node_id.
+ typedef base::ScopedPtrHashMap<int64, NavigationRequest> NavigationRequestMap;
+ NavigationRequestMap navigation_request_map_;
DISALLOW_COPY_AND_ASSIGN(NavigatorImpl);
};
diff --git a/chromium/content/browser/frame_host/navigator_impl_unittest.cc b/chromium/content/browser/frame_host/navigator_impl_unittest.cc
new file mode 100644
index 00000000000..37a0f243d6d
--- /dev/null
+++ b/chromium/content/browser/frame_host/navigator_impl_unittest.cc
@@ -0,0 +1,480 @@
+// 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 "base/command_line.h"
+#include "base/guid.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/test/histogram_tester.h"
+#include "base/time/time.h"
+#include "content/browser/frame_host/navigation_controller_impl.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/frame_host/navigation_request.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/frame_host/render_frame_host_manager.h"
+#include "content/browser/loader/navigation_url_loader.h"
+#include "content/browser/loader/navigation_url_loader_delegate.h"
+#include "content/browser/loader/navigation_url_loader_factory.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/browser/streams/stream.h"
+#include "content/browser/streams/stream_registry.h"
+#include "content/common/navigation_params.h"
+#include "content/public/browser/stream_handle.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/url_utils.h"
+#include "content/test/test_render_frame_host.h"
+#include "content/test/test_web_contents.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/redirect_info.h"
+#include "ui/base/page_transition_types.h"
+#include "url/url_constants.h"
+
+namespace content {
+
+namespace {
+
+class TestNavigationURLLoader
+ : public NavigationURLLoader,
+ public base::SupportsWeakPtr<TestNavigationURLLoader> {
+ public:
+ TestNavigationURLLoader(const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ NavigationURLLoaderDelegate* delegate)
+ : common_params_(common_params),
+ request_info_(request_info.Pass()),
+ delegate_(delegate),
+ redirect_count_(0) {
+ }
+
+ // NavigationURLLoader implementation.
+ void FollowRedirect() override { redirect_count_++; }
+
+ const CommonNavigationParams& common_params() const { return common_params_; }
+ NavigationRequestInfo* request_info() const { return request_info_.get(); }
+
+ void CallOnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ const scoped_refptr<ResourceResponse>& response) {
+ delegate_->OnRequestRedirected(redirect_info, response);
+ }
+
+ void CallOnResponseStarted(
+ const scoped_refptr<ResourceResponse>& response,
+ scoped_ptr<StreamHandle> body) {
+ delegate_->OnResponseStarted(response, body.Pass());
+ }
+
+ int redirect_count() { return redirect_count_; }
+
+ private:
+ CommonNavigationParams common_params_;
+ scoped_ptr<NavigationRequestInfo> request_info_;
+ NavigationURLLoaderDelegate* delegate_;
+ int redirect_count_;
+};
+
+class TestNavigationURLLoaderFactory : public NavigationURLLoaderFactory {
+ public:
+ // NavigationURLLoaderFactory implementation.
+ scoped_ptr<NavigationURLLoader> CreateLoader(
+ BrowserContext* browser_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ ResourceRequestBody* request_body,
+ NavigationURLLoaderDelegate* delegate) override {
+ return scoped_ptr<NavigationURLLoader>(new TestNavigationURLLoader(
+ common_params, request_info.Pass(), delegate));
+ }
+};
+
+} // namespace
+
+class NavigatorTest : public RenderViewHostImplTestHarness {
+ public:
+ NavigatorTest() : stream_registry_(new StreamRegistry) {}
+
+ void SetUp() override {
+ RenderViewHostImplTestHarness::SetUp();
+ loader_factory_.reset(new TestNavigationURLLoaderFactory);
+ NavigationURLLoader::SetFactoryForTesting(loader_factory_.get());
+ }
+
+ void TearDown() override {
+ NavigationURLLoader::SetFactoryForTesting(nullptr);
+ loader_factory_.reset();
+ RenderViewHostImplTestHarness::TearDown();
+ }
+
+ NavigationRequest* GetNavigationRequestForFrameTreeNode(
+ FrameTreeNode* frame_tree_node) const {
+ NavigatorImpl* navigator =
+ static_cast<NavigatorImpl*>(frame_tree_node->navigator());
+ return navigator->navigation_request_map_.get(
+ frame_tree_node->frame_tree_node_id());
+ }
+
+ TestNavigationURLLoader* GetLoaderForNavigationRequest(
+ NavigationRequest* request) const {
+ return static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
+ }
+
+ void EnableBrowserSideNavigation() {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableBrowserSideNavigation);
+ }
+
+ void SendRequestNavigation(FrameTreeNode* node,
+ const GURL& url) {
+ SendRequestNavigationWithParameters(
+ node, url, Referrer(), ui::PAGE_TRANSITION_LINK,
+ NavigationController::NO_RELOAD);
+ }
+
+ void SendRequestNavigationWithParameters(
+ FrameTreeNode* node,
+ const GURL& url,
+ const Referrer& referrer,
+ ui::PageTransition transition_type,
+ NavigationController::ReloadType reload_type) {
+ scoped_ptr<NavigationEntryImpl> entry(
+ NavigationEntryImpl::FromNavigationEntry(
+ NavigationController::CreateNavigationEntry(
+ url,
+ referrer,
+ transition_type,
+ false,
+ std::string(),
+ controller().GetBrowserContext())));
+ static_cast<NavigatorImpl*>(node->navigator())->RequestNavigation(
+ node, *entry, reload_type, base::TimeTicks::Now());
+ }
+
+ scoped_ptr<StreamHandle> MakeEmptyStream() {
+ GURL url(std::string(url::kBlobScheme) + "://" + base::GenerateGUID());
+ scoped_refptr<Stream> stream(new Stream(stream_registry_.get(), NULL, url));
+ stream->Finalize();
+ return stream->CreateHandle();
+ }
+
+ private:
+ scoped_ptr<StreamRegistry> stream_registry_;
+ scoped_ptr<TestNavigationURLLoaderFactory> loader_factory_;
+};
+
+// PlzNavigate: Test that a proper NavigationRequest is created by
+// BeginNavigation.
+// Note that all PlzNavigate methods on the browser side require the use of the
+// flag kEnableBrowserSideNavigation.
+TEST_F(NavigatorTest, BrowserSideNavigationBeginNavigation) {
+ const GURL kUrl1("http://www.google.com/");
+ const GURL kUrl2("http://www.chromium.org/");
+ const GURL kUrl3("http://www.gmail.com/");
+
+ contents()->NavigateAndCommit(kUrl1);
+
+ EnableBrowserSideNavigation();
+
+ // Add a subframe.
+ FrameTreeNode* root = contents()->GetFrameTree()->root();
+ TestRenderFrameHost* subframe_rfh = static_cast<TestRenderFrameHost*>(
+ contents()->GetFrameTree()->AddFrame(
+ root, root->current_frame_host()->GetProcess()->GetID(), 14,
+ "Child"));
+ EXPECT_TRUE(subframe_rfh);
+
+ FrameTreeNode* subframe_node = subframe_rfh->frame_tree_node();
+ SendRequestNavigation(subframe_rfh->frame_tree_node(), kUrl2);
+ // There is no previous renderer in the subframe, so BeginNavigation is
+ // handled already.
+ NavigationRequest* subframe_request =
+ GetNavigationRequestForFrameTreeNode(subframe_node);
+ TestNavigationURLLoader* subframe_loader =
+ GetLoaderForNavigationRequest(subframe_request);
+ ASSERT_TRUE(subframe_request);
+ EXPECT_EQ(kUrl2, subframe_request->common_params().url);
+ EXPECT_EQ(kUrl2, subframe_loader->common_params().url);
+ // First party for cookies url should be that of the main frame.
+ EXPECT_EQ(kUrl1, subframe_loader->request_info()->first_party_for_cookies);
+ EXPECT_FALSE(subframe_loader->request_info()->is_main_frame);
+ EXPECT_TRUE(subframe_loader->request_info()->parent_is_main_frame);
+
+ SendRequestNavigation(root, kUrl3);
+ // Simulate a BeginNavigation IPC on the main frame.
+ contents()->GetMainFrame()->SendBeginNavigationWithURL(kUrl3);
+ NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(root);
+ TestNavigationURLLoader* main_loader =
+ GetLoaderForNavigationRequest(main_request);
+ ASSERT_TRUE(main_request);
+ EXPECT_EQ(kUrl3, main_request->common_params().url);
+ EXPECT_EQ(kUrl3, main_loader->common_params().url);
+ EXPECT_EQ(kUrl3, main_loader->request_info()->first_party_for_cookies);
+ EXPECT_TRUE(main_loader->request_info()->is_main_frame);
+ EXPECT_FALSE(main_loader->request_info()->parent_is_main_frame);
+}
+
+// PlzNavigate: Test that RequestNavigation creates a NavigationRequest and that
+// RenderFrameHost is not modified when the navigation commits.
+TEST_F(NavigatorTest, BrowserSideNavigationRequestNavigationNoLiveRenderer) {
+ const GURL kUrl("http://www.google.com/");
+
+ EnableBrowserSideNavigation();
+ EXPECT_FALSE(main_test_rfh()->render_view_host()->IsRenderViewLive());
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ SendRequestNavigation(node, kUrl);
+ NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(node);
+ // A NavigationRequest should have been generated.
+ EXPECT_TRUE(main_request != NULL);
+ RenderFrameHostImpl* rfh = main_test_rfh();
+
+ // Now return the response without any redirects. This will cause the
+ // navigation to commit at the same URL.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted(
+ response, MakeEmptyStream());
+ main_request = GetNavigationRequestForFrameTreeNode(node);
+
+ // The main RFH should not have been changed, and the renderer should have
+ // been initialized.
+ EXPECT_EQ(rfh, main_test_rfh());
+ EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
+ EXPECT_TRUE(main_test_rfh()->render_view_host()->IsRenderViewLive());
+}
+
+// PlzNavigate: Test that commiting an HTTP 204 or HTTP 205 response cancels the
+// navigation.
+TEST_F(NavigatorTest, BrowserSideNavigationNoContent) {
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.google.com/");
+
+ // Load a URL.
+ contents()->NavigateAndCommit(kUrl1);
+ RenderFrameHostImpl* rfh = main_test_rfh();
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh->rfh_state());
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+ EnableBrowserSideNavigation();
+
+ // Navigate to a different site.
+ SendRequestNavigation(node, kUrl2);
+ main_test_rfh()->SendBeginNavigationWithURL(kUrl2);
+ NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(node);
+ ASSERT_TRUE(main_request);
+
+ // Commit an HTTP 204 response.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ const char kNoContentHeaders[] = "HTTP/1.1 204 No Content\0\0";
+ response->head.headers = new net::HttpResponseHeaders(
+ std::string(kNoContentHeaders, arraysize(kNoContentHeaders)));
+ GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted(
+ response, MakeEmptyStream());
+
+ // There should be no pending RenderFrameHost; the navigation was aborted.
+ EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node));
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
+
+ // Now, repeat the test with 205 Reset Content.
+
+ // Navigate to a different site again.
+ SendRequestNavigation(node, kUrl2);
+ main_test_rfh()->SendBeginNavigationWithURL(kUrl2);
+ main_request = GetNavigationRequestForFrameTreeNode(node);
+ ASSERT_TRUE(main_request);
+
+ // Commit an HTTP 205 response.
+ response = new ResourceResponse;
+ const char kResetContentHeaders[] = "HTTP/1.1 205 Reset Content\0\0";
+ response->head.headers = new net::HttpResponseHeaders(
+ std::string(kResetContentHeaders, arraysize(kResetContentHeaders)));
+ GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted(
+ response, MakeEmptyStream());
+
+ // There should be no pending RenderFrameHost; the navigation was aborted.
+ EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node));
+ EXPECT_FALSE(node->render_manager()->pending_frame_host());
+}
+
+// PlzNavigate: Test that a new RenderFrameHost is created when doing a cross
+// site navigation.
+TEST_F(NavigatorTest, BrowserSideNavigationCrossSiteNavigation) {
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.google.com/");
+
+ contents()->NavigateAndCommit(kUrl1);
+ RenderFrameHostImpl* rfh = main_test_rfh();
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh->rfh_state());
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+ EnableBrowserSideNavigation();
+
+ // Navigate to a different site.
+ SendRequestNavigation(node, kUrl2);
+ main_test_rfh()->SendBeginNavigationWithURL(kUrl2);
+ NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(node);
+ ASSERT_TRUE(main_request);
+
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted(
+ response, MakeEmptyStream());
+ RenderFrameHostImpl* pending_rfh =
+ node->render_manager()->pending_frame_host();
+ ASSERT_TRUE(pending_rfh);
+ EXPECT_NE(pending_rfh, rfh);
+ EXPECT_TRUE(pending_rfh->IsRenderFrameLive());
+ EXPECT_TRUE(pending_rfh->render_view_host()->IsRenderViewLive());
+}
+
+// PlzNavigate: Test that redirects are followed.
+TEST_F(NavigatorTest, BrowserSideNavigationRedirectCrossSite) {
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.google.com/");
+
+ contents()->NavigateAndCommit(kUrl1);
+ RenderFrameHostImpl* rfh = main_test_rfh();
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh->rfh_state());
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+ EnableBrowserSideNavigation();
+
+ // Navigate to a URL on the same site.
+ SendRequestNavigation(node, kUrl1);
+ main_test_rfh()->SendBeginNavigationWithURL(kUrl1);
+ NavigationRequest* main_request = GetNavigationRequestForFrameTreeNode(node);
+ ASSERT_TRUE(main_request);
+
+ // It then redirects to another site.
+ net::RedirectInfo redirect_info;
+ redirect_info.status_code = 302;
+ redirect_info.new_method = "GET";
+ redirect_info.new_url = kUrl2;
+ redirect_info.new_first_party_for_cookies = kUrl2;
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(main_request)->CallOnRequestRedirected(
+ redirect_info, response);
+
+ // The redirect should have been followed.
+ EXPECT_EQ(1, GetLoaderForNavigationRequest(main_request)->redirect_count());
+
+ // Then it commits.
+ response = new ResourceResponse;
+ GetLoaderForNavigationRequest(main_request)->CallOnResponseStarted(
+ response, MakeEmptyStream());
+ RenderFrameHostImpl* pending_rfh =
+ node->render_manager()->pending_frame_host();
+ ASSERT_TRUE(pending_rfh);
+ EXPECT_NE(pending_rfh, rfh);
+ EXPECT_TRUE(pending_rfh->IsRenderFrameLive());
+ EXPECT_TRUE(pending_rfh->render_view_host()->IsRenderViewLive());
+}
+
+// PlzNavigate: Test that a navigation is cancelled if another request has been
+// issued in the meantime.
+TEST_F(NavigatorTest, BrowserSideNavigationReplacePendingNavigation) {
+ const GURL kUrl0("http://www.wikipedia.org/");
+ const GURL kUrl0_site = SiteInstance::GetSiteForURL(browser_context(), kUrl0);
+ const GURL kUrl1("http://www.chromium.org/");
+ const GURL kUrl2("http://www.google.com/");
+ const GURL kUrl2_site = SiteInstance::GetSiteForURL(browser_context(), kUrl2);
+
+ // Initialization.
+ contents()->NavigateAndCommit(kUrl0);
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ EnableBrowserSideNavigation();
+ EXPECT_EQ(kUrl0_site, main_test_rfh()->GetSiteInstance()->GetSiteURL());
+
+ // Request navigation to the 1st URL.
+ SendRequestNavigation(node, kUrl1);
+ main_test_rfh()->SendBeginNavigationWithURL(kUrl1);
+ NavigationRequest* request1 = GetNavigationRequestForFrameTreeNode(node);
+ ASSERT_TRUE(request1);
+ EXPECT_EQ(kUrl1, request1->common_params().url);
+ base::WeakPtr<TestNavigationURLLoader> loader1 =
+ GetLoaderForNavigationRequest(request1)->AsWeakPtr();
+
+ // Request navigation to the 2nd URL; the NavigationRequest must have been
+ // replaced by a new one with a different URL.
+ SendRequestNavigation(node, kUrl2);
+ main_test_rfh()->SendBeginNavigationWithURL(kUrl2);
+ NavigationRequest* request2 = GetNavigationRequestForFrameTreeNode(node);
+ ASSERT_TRUE(request2);
+ EXPECT_EQ(kUrl2, request2->common_params().url);
+
+ // Confirm that the first loader got destroyed.
+ EXPECT_FALSE(loader1);
+
+ // Confirm that the commit corresponds to the new request.
+ scoped_refptr<ResourceResponse> response(new ResourceResponse);
+ GetLoaderForNavigationRequest(request2)->CallOnResponseStarted(
+ response, MakeEmptyStream());
+ RenderFrameHostImpl* pending_rfh =
+ node->render_manager()->pending_frame_host();
+ ASSERT_TRUE(pending_rfh);
+ EXPECT_EQ(kUrl2_site, pending_rfh->GetSiteInstance()->GetSiteURL());
+}
+
+// PlzNavigate: Tests that the navigation histograms are correctly tracked both
+// when PlzNavigate is enabled and disabled, and also ignores in-tab renderer
+// initiated navigation for the non-enabled case.
+// Note: the related histogram, Navigation.TimeToURLJobStart, cannot be tracked
+// by this test as the IO thread is not running.
+TEST_F(NavigatorTest, BrowserSideNavigationHistogramTest) {
+ const GURL kUrl0("http://www.google.com/");
+ const GURL kUrl1("http://www.chromium.org/");
+ base::HistogramTester histo_tester;
+
+ // Performs a "normal" non-PlzNavigate navigation
+ contents()->NavigateAndCommit(kUrl0);
+ histo_tester.ExpectTotalCount("Navigation.TimeToCommit", 1);
+
+ // Performs an in-tab renderer initiated navigation
+ int32 new_page_id = 1 + contents()->GetMaxPageIDForSiteInstance(
+ main_test_rfh()->GetSiteInstance());
+ main_test_rfh()->SendNavigate(new_page_id, kUrl0);
+ histo_tester.ExpectTotalCount("Navigation.TimeToCommit", 1);
+
+ // Performs a PlzNavigate navigation
+ EnableBrowserSideNavigation();
+ contents()->NavigateAndCommit(kUrl1);
+ histo_tester.ExpectTotalCount("Navigation.TimeToCommit", 2);
+}
+
+// PlzNavigate: Test that a reload navigation is properly signaled to the
+// renderer when the navigation can commit.
+TEST_F(NavigatorTest, BrowserSideNavigationReload) {
+ const GURL kUrl("http://www.google.com/");
+ contents()->NavigateAndCommit(kUrl);
+
+ EnableBrowserSideNavigation();
+ FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+ SendRequestNavigationWithParameters(
+ node, kUrl, Referrer(), ui::PAGE_TRANSITION_LINK,
+ NavigationController::RELOAD);
+ contents()->GetMainFrame()->SendBeginNavigationWithURL(kUrl);
+ // A NavigationRequest should have been generated.
+ NavigationRequest* main_request =
+ GetNavigationRequestForFrameTreeNode(node);
+ ASSERT_TRUE(main_request != NULL);
+ EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD,
+ main_request->common_params().navigation_type);
+ int page_id = contents()->GetMaxPageIDForSiteInstance(
+ main_test_rfh()->GetSiteInstance()) + 1;
+ main_test_rfh()->SendNavigate(page_id, kUrl);
+
+ // Now do a shift+reload.
+ SendRequestNavigationWithParameters(
+ node, kUrl, Referrer(), ui::PAGE_TRANSITION_LINK,
+ NavigationController::RELOAD_IGNORING_CACHE);
+ contents()->GetMainFrame()->SendBeginNavigationWithURL(kUrl);
+ // A NavigationRequest should have been generated.
+ main_request = GetNavigationRequestForFrameTreeNode(node);
+ ASSERT_TRUE(main_request != NULL);
+ EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE,
+ main_request->common_params().navigation_type);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/popup_menu_helper_mac.h b/chromium/content/browser/frame_host/popup_menu_helper_mac.h
index 8a6f3176c7e..e92aa10340f 100644
--- a/chromium/content/browser/renderer_host/popup_menu_helper_mac.h
+++ b/chromium/content/browser/frame_host/popup_menu_helper_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_RENDERER_HOST_POPUP_MENU_HELPER_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_POPUP_MENU_HELPER_MAC_H_
+#ifndef CONTENT_BROWSER_FRAME_HOST_POPUP_MENU_HELPER_MAC_H_
+#define CONTENT_BROWSER_FRAME_HOST_POPUP_MENU_HELPER_MAC_H_
#include <vector>
@@ -20,21 +20,21 @@ class WebMenuRunner;
#endif
namespace content {
-class RenderViewHost;
-class RenderViewHostImpl;
+
+class RenderFrameHost;
+class RenderFrameHostImpl;
class RenderWidgetHostViewMac;
struct MenuItem;
class PopupMenuHelper : public NotificationObserver {
public:
- // Creates a PopupMenuHelper that will notify |render_view_host| when a user
+ // Creates a PopupMenuHelper that will notify |render_frame_host| when a user
// selects or cancels the popup.
- explicit PopupMenuHelper(RenderViewHost* render_view_host);
+ explicit PopupMenuHelper(RenderFrameHost* render_frame_host);
void Hide();
- // Shows the popup menu and notifies the RenderViewHost of the selection/
- // cancel.
- // This call is blocking.
+ // Shows the popup menu and notifies the RenderFrameHost of the selection/
+ // cancellation. This call is blocking.
void ShowPopupMenu(const gfx::Rect& bounds,
int item_height,
double item_font_size,
@@ -50,12 +50,12 @@ class PopupMenuHelper : public NotificationObserver {
virtual RenderWidgetHostViewMac* GetRenderWidgetHostView() const;
// NotificationObserver implementation:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
NotificationRegistrar notification_registrar_;
- RenderViewHostImpl* render_view_host_;
+ RenderFrameHostImpl* render_frame_host_;
WebMenuRunner* menu_runner_;
bool popup_was_hidden_;
@@ -64,4 +64,4 @@ class PopupMenuHelper : public NotificationObserver {
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_POPUP_MENU_HELPER_MAC_H_
+#endif // CONTENT_BROWSER_FRAME_HOST_POPUP_MENU_HELPER_MAC_H_
diff --git a/chromium/content/browser/renderer_host/popup_menu_helper_mac.mm b/chromium/content/browser/frame_host/popup_menu_helper_mac.mm
index 1fb28bae96b..eac8f7c3b7a 100644
--- a/chromium/content/browser/renderer_host/popup_menu_helper_mac.mm
+++ b/chromium/content/browser/frame_host/popup_menu_helper_mac.mm
@@ -4,11 +4,12 @@
#import <Carbon/Carbon.h>
-#include "content/browser/renderer_host/popup_menu_helper_mac.h"
+#include "content/browser/frame_host/popup_menu_helper_mac.h"
#include "base/mac/scoped_nsobject.h"
#import "base/mac/scoped_sending_event.h"
#include "base/message_loop/message_loop.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
#include "content/browser/renderer_host/webmenurunner_mac.h"
@@ -24,13 +25,13 @@ bool g_allow_showing_popup_menus = true;
} // namespace
-PopupMenuHelper::PopupMenuHelper(RenderViewHost* render_view_host)
- : render_view_host_(static_cast<RenderViewHostImpl*>(render_view_host)),
+PopupMenuHelper::PopupMenuHelper(RenderFrameHost* render_frame_host)
+ : render_frame_host_(static_cast<RenderFrameHostImpl*>(render_frame_host)),
menu_runner_(nil),
popup_was_hidden_(false) {
notification_registrar_.Add(
this, NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
- Source<RenderWidgetHost>(render_view_host));
+ Source<RenderWidgetHost>(render_frame_host->GetRenderViewHost()));
}
void PopupMenuHelper::ShowPopupMenu(
@@ -79,8 +80,8 @@ void PopupMenuHelper::ShowPopupMenu(
initialIndex:selected_item];
}
- if (!render_view_host_) {
- // Bad news, the RenderViewHost got deleted while we were off running the
+ if (!render_frame_host_) {
+ // Bad news, the RenderFrameHost got deleted while we were off running the
// menu. Nothing to do.
[menu_runner_ release];
menu_runner_ = nil;
@@ -89,10 +90,10 @@ void PopupMenuHelper::ShowPopupMenu(
if (!popup_was_hidden_) {
if ([menu_runner_ menuItemWasChosen]) {
- render_view_host_->DidSelectPopupMenuItem(
+ render_frame_host_->DidSelectPopupMenuItem(
[menu_runner_ indexOfSelectedItem]);
} else {
- render_view_host_->DidCancelPopupMenu();
+ render_frame_host_->DidCancelPopupMenu();
}
}
[menu_runner_ release];
@@ -111,15 +112,17 @@ void PopupMenuHelper::DontShowPopupMenuForTesting() {
}
RenderWidgetHostViewMac* PopupMenuHelper::GetRenderWidgetHostView() const {
- return static_cast<RenderWidgetHostViewMac*>(render_view_host_->GetView());
+ return static_cast<RenderWidgetHostViewMac*>(
+ render_frame_host_->GetRenderViewHost()->GetView());
}
void PopupMenuHelper::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK(type == NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED);
- DCHECK(Source<RenderWidgetHost>(source).ptr() == render_view_host_);
- render_view_host_ = NULL;
+ DCHECK_EQ(Source<RenderWidgetHost>(source).ptr(),
+ render_frame_host_->GetRenderViewHost());
+ render_frame_host_ = NULL;
}
} // namespace content
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 8e424ead131..a83715dece8 100644
--- a/chromium/content/browser/frame_host/render_frame_host_delegate.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_delegate.cc
@@ -4,8 +4,10 @@
#include <stddef.h>
+#include "base/callback.h"
#include "base/strings/string16.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
+#include "ui/gfx/native_widget_types.h"
#include "url/gurl.h"
namespace content {
@@ -20,6 +22,10 @@ const GURL& RenderFrameHostDelegate::GetMainFrameLastCommittedURL() const {
return GURL::EmptyGURL();
}
+bool RenderFrameHostDelegate::WillHandleDeferAfterResponseStarted() {
+ return false;
+}
+
bool RenderFrameHostDelegate::AddMessageToConsole(
int32 level, const base::string16& message, int32 line_no,
const base::string16& source_id) {
@@ -30,4 +36,43 @@ WebContents* RenderFrameHostDelegate::GetAsWebContents() {
return NULL;
}
+void RenderFrameHostDelegate::RequestMediaAccessPermission(
+ const MediaStreamRequest& request,
+ const MediaResponseCallback& callback) {
+ LOG(ERROR) << "RenderFrameHostDelegate::RequestMediaAccessPermission: "
+ << "Not supported.";
+ callback.Run(MediaStreamDevices(),
+ MEDIA_DEVICE_NOT_SUPPORTED,
+ scoped_ptr<MediaStreamUI>());
+}
+
+bool RenderFrameHostDelegate::CheckMediaAccessPermission(
+ const GURL& security_origin,
+ MediaStreamType type) {
+ LOG(ERROR) << "RenderFrameHostDelegate::CheckMediaAccessPermission: "
+ << "Not supported.";
+ return false;
+}
+
+AccessibilityMode RenderFrameHostDelegate::GetAccessibilityMode() const {
+ return AccessibilityModeOff;
+}
+
+RenderFrameHost* RenderFrameHostDelegate::GetGuestByInstanceID(
+ int browser_plugin_instance_id) {
+ return NULL;
+}
+
+GeolocationServiceContext*
+RenderFrameHostDelegate::GetGeolocationServiceContext() {
+ return NULL;
+}
+
+#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 b4db5d4c9c9..6c22d94abf2 100644
--- a/chromium/content/browser/frame_host/render_frame_host_delegate.h
+++ b/chromium/content/browser/frame_host/render_frame_host_delegate.h
@@ -5,10 +5,19 @@
#ifndef CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_DELEGATE_H_
#define CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_DELEGATE_H_
+#include <vector>
+
#include "base/basictypes.h"
#include "base/i18n/rtl.h"
#include "content/common/content_export.h"
+#include "content/common/frame_message_enums.h"
#include "content/public/common/javascript_message_type.h"
+#include "content/public/common/media_stream_request.h"
+#include "net/http/http_response_headers.h"
+
+#if defined(OS_WIN)
+#include "ui/gfx/native_widget_types.h"
+#endif
class GURL;
@@ -17,9 +26,12 @@ class Message;
}
namespace content {
+class GeolocationServiceContext;
class RenderFrameHost;
class WebContents;
+struct AXEventNotificationDetails;
struct ContextMenuParams;
+struct TransitionLayerData;
// An interface implemented by an object interested in knowing about the state
// of the RenderFrameHost.
@@ -55,6 +67,14 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
// The RenderFrameHost has been swapped out.
virtual void SwappedOut(RenderFrameHost* render_frame_host) {}
+ // Notification that the navigation on the main frame is blocked waiting
+ // for transition to occur.
+ virtual void DidDeferAfterResponseStarted(
+ const TransitionLayerData& transition_data) {}
+
+ // Used to query whether the navigation transition will be handled.
+ virtual bool WillHandleDeferAfterResponseStarted();
+
// Notification that a worker process has crashed.
virtual void WorkerCrashed(RenderFrameHost* render_frame_host) {}
@@ -104,6 +124,38 @@ class CONTENT_EXPORT RenderFrameHostDelegate {
// not a WebContents, returns NULL.
virtual WebContents* GetAsWebContents();
+ // The render frame has requested access to media devices listed in
+ // |request|, and the client should grant or deny that permission by
+ // calling |callback|.
+ virtual void RequestMediaAccessPermission(
+ const MediaStreamRequest& request,
+ const MediaResponseCallback& callback);
+
+ // Checks if we have permission to access the microphone or camera. Note that
+ // this does not query the user. |type| must be MEDIA_DEVICE_AUDIO_CAPTURE
+ // or MEDIA_DEVICE_VIDEO_CAPTURE.
+ virtual bool CheckMediaAccessPermission(const GURL& security_origin,
+ MediaStreamType type);
+
+ // Get the accessibility mode for the WebContents that owns this frame.
+ virtual AccessibilityMode GetAccessibilityMode() const;
+
+ // Invoked when an accessibility event is received from the renderer.
+ virtual void AccessibilityEventReceived(
+ const std::vector<AXEventNotificationDetails>& details) {}
+
+ // Find a guest RenderFrameHost by its browser plugin instance id.
+ virtual RenderFrameHost* GetGuestByInstanceID(
+ int browser_plugin_instance_id);
+
+ // Gets the GeolocationServiceContext associated with this delegate.
+ virtual GeolocationServiceContext* GetGeolocationServiceContext();
+
+#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_impl.cc b/chromium/content/browser/frame_host/render_frame_host_impl.cc
index 397fd915ea4..b7941077c5e 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.cc
@@ -5,43 +5,76 @@
#include "content/browser/frame_host/render_frame_host_impl.h"
#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"
#include "base/metrics/user_metrics_action.h"
+#include "base/time/time.h"
+#include "content/browser/accessibility/accessibility_mode_helper.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/frame_host/cross_process_frame_connector.h"
#include "content/browser/frame_host/cross_site_transferring_request.h"
+#include "content/browser/frame_host/frame_accessibility.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_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/renderer_host/input/input_router.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"
+#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/browser/renderer_host/render_view_host_impl.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/transition_request_manager.h"
+#include "content/common/accessibility_messages.h"
#include "content/common/desktop_notification_messages.h"
#include "content/common/frame_messages.h"
#include "content/common/input_messages.h"
#include "content/common/inter_process_time_ticks_converter.h"
+#include "content/common/navigation_params.h"
+#include "content/common/platform_notification_messages.h"
+#include "content/common/push_messaging_messages.h"
+#include "content/common/render_frame_setup.mojom.h"
#include "content/common/swapped_out_messages.h"
+#include "content/public/browser/ax_event_notification_details.h"
+#include "content/public/browser/browser_accessibility_state.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/desktop_notification_delegate.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/stream_handle.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
+#include "ui/accessibility/ax_tree.h"
#include "url/gurl.h"
+#if defined(OS_MACOSX)
+#include "content/browser/frame_host/popup_menu_helper_mac.h"
+#endif
+
using base::TimeDelta;
namespace content {
namespace {
+// The next value to use for the accessibility reset token.
+int g_next_accessibility_reset_token = 1;
+
// The (process id, routing id) pair that identifies one RenderFrame.
typedef std::pair<int32, int32> RenderFrameHostID;
typedef base::hash_map<RenderFrameHostID, RenderFrameHostImpl*>
@@ -57,9 +90,9 @@ class DesktopNotificationDelegateImpl : public DesktopNotificationDelegate {
render_frame_id_(render_frame_host->GetRoutingID()),
notification_id_(notification_id) {}
- virtual ~DesktopNotificationDelegateImpl() {}
+ ~DesktopNotificationDelegateImpl() override {}
- virtual void NotificationDisplayed() OVERRIDE {
+ void NotificationDisplayed() override {
RenderFrameHost* rfh =
RenderFrameHost::FromID(render_process_id_, render_frame_id_);
if (!rfh)
@@ -69,18 +102,7 @@ class DesktopNotificationDelegateImpl : public DesktopNotificationDelegate {
rfh->GetRoutingID(), notification_id_));
}
- virtual void NotificationError() OVERRIDE {
- RenderFrameHost* rfh =
- RenderFrameHost::FromID(render_process_id_, render_frame_id_);
- if (!rfh)
- return;
-
- rfh->Send(new DesktopNotificationMsg_PostError(
- rfh->GetRoutingID(), notification_id_));
- delete this;
- }
-
- virtual void NotificationClosed(bool by_user) OVERRIDE {
+ void NotificationClosed(bool by_user) override {
RenderFrameHost* rfh =
RenderFrameHost::FromID(render_process_id_, render_frame_id_);
if (!rfh)
@@ -90,10 +112,9 @@ class DesktopNotificationDelegateImpl : public DesktopNotificationDelegate {
rfh->GetRoutingID(), notification_id_, by_user));
static_cast<RenderFrameHostImpl*>(rfh)->NotificationClosed(
notification_id_);
- delete this;
}
- virtual void NotificationClick() OVERRIDE {
+ void NotificationClick() override {
RenderFrameHost* rfh =
RenderFrameHost::FromID(render_process_id_, render_frame_id_);
if (!rfh)
@@ -125,14 +146,20 @@ 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);
}
// static
-RenderFrameHostImpl* RenderFrameHostImpl::FromID(
- int process_id, int routing_id) {
+RenderFrameHostImpl* RenderFrameHostImpl::FromID(int process_id,
+ int routing_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RoutingIDFrameMap* frames = g_routing_id_frame_map.Pointer();
RoutingIDFrameMap::iterator it = frames->find(
@@ -140,13 +167,12 @@ RenderFrameHostImpl* RenderFrameHostImpl::FromID(
return it == frames->end() ? NULL : it->second;
}
-RenderFrameHostImpl::RenderFrameHostImpl(
- RenderViewHostImpl* render_view_host,
- RenderFrameHostDelegate* delegate,
- FrameTree* frame_tree,
- FrameTreeNode* frame_tree_node,
- int routing_id,
- bool is_swapped_out)
+RenderFrameHostImpl::RenderFrameHostImpl(RenderViewHostImpl* render_view_host,
+ RenderFrameHostDelegate* delegate,
+ FrameTree* frame_tree,
+ FrameTreeNode* frame_tree_node,
+ int routing_id,
+ bool is_swapped_out)
: render_view_host_(render_view_host),
delegate_(delegate),
cross_process_frame_connector_(NULL),
@@ -154,22 +180,47 @@ RenderFrameHostImpl::RenderFrameHostImpl(
frame_tree_(frame_tree),
frame_tree_node_(frame_tree_node),
routing_id_(routing_id),
- is_swapped_out_(is_swapped_out),
+ render_frame_created_(false),
+ navigations_suspended_(false),
+ is_waiting_for_beforeunload_ack_(false),
+ unload_ack_is_for_cross_site_transition_(false),
+ accessibility_reset_token_(0),
+ accessibility_reset_count_(0),
+ no_create_browser_accessibility_manager_for_testing_(false),
weak_ptr_factory_(this) {
frame_tree_->RegisterRenderFrameHost(this);
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()->increment_active_frame_count();
+ }
+
+ SetUpMojoIfNeeded();
+ swapout_event_monitor_timeout_.reset(new TimeoutMonitor(base::Bind(
+ &RenderFrameHostImpl::OnSwappedOut, weak_ptr_factory_.GetWeakPtr())));
}
RenderFrameHostImpl::~RenderFrameHostImpl() {
GetProcess()->RemoveRoute(routing_id_);
g_routing_id_frame_map.Get().erase(
RenderFrameHostID(GetProcess()->GetID(), routing_id_));
+
if (delegate_)
delegate_->RenderFrameDeleted(this);
+ FrameAccessibility::GetInstance()->OnRenderFrameHostDestroyed(this);
+
+ // If this was swapped out, it already decremented the active frame count of
+ // the SiteInstance it belongs to.
+ if (IsRFHStateActive(rfh_state_))
+ GetSiteInstance()->decrement_active_frame_count();
+
// Notify the FrameTree that this RFH is going away, allowing it to shut down
// the corresponding RenderViewHost if it is no longer needed.
frame_tree_->UnregisterRenderFrameHost(this);
@@ -179,7 +230,7 @@ int RenderFrameHostImpl::GetRoutingID() {
return routing_id_;
}
-SiteInstance* RenderFrameHostImpl::GetSiteInstance() {
+SiteInstanceImpl* RenderFrameHostImpl::GetSiteInstance() {
return render_view_host_->GetSiteInstance();
}
@@ -237,17 +288,31 @@ void RenderFrameHostImpl::ExecuteJavaScript(
javascript_callbacks_.insert(std::make_pair(key, callback));
}
+void RenderFrameHostImpl::ExecuteJavaScriptForTests(
+ const base::string16& javascript) {
+ Send(new FrameMsg_JavaScriptExecuteRequestForTests(routing_id_,
+ javascript,
+ 0, false));
+}
+
RenderViewHost* RenderFrameHostImpl::GetRenderViewHost() {
return render_view_host_;
}
+ServiceRegistry* RenderFrameHostImpl::GetServiceRegistry() {
+ return service_registry_.get();
+}
+
bool RenderFrameHostImpl::Send(IPC::Message* message) {
if (IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart) {
return render_view_host_->input_router()->SendInput(
make_scoped_ptr(message));
}
- if (render_view_host_->IsSwappedOut()) {
+ // Route IPCs through the RenderFrameProxyHost when in swapped out state.
+ // Note: For subframes in --site-per-process mode, we don't use swapped out
+ // RenderFrameHosts.
+ if (frame_tree_node_->IsMainFrame() && is_swapped_out()) {
DCHECK(render_frame_proxy_host_);
return render_frame_proxy_host_->Send(message);
}
@@ -256,12 +321,9 @@ bool RenderFrameHostImpl::Send(IPC::Message* message) {
}
bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
- // Filter out most IPC messages if this renderer is swapped out.
+ // Filter out most IPC messages if this frame is swapped out.
// We still want to handle certain ACKs to keep our state consistent.
- // TODO(nasko): Only check RenderViewHost state, as this object's own state
- // isn't yet properly updated. Transition this check once the swapped out
- // state is correct in RenderFrameHost itself.
- if (render_view_host_->IsSwappedOut()) {
+ 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
@@ -294,12 +356,10 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
OnDidStartProvisionalLoadForFrame)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailProvisionalLoadWithError,
OnDidFailProvisionalLoadWithError)
- IPC_MESSAGE_HANDLER(FrameHostMsg_DidRedirectProvisionalLoad,
- OnDidRedirectProvisionalLoad)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailLoadWithError,
OnDidFailLoadWithError)
IPC_MESSAGE_HANDLER_GENERIC(FrameHostMsg_DidCommitProvisionalLoad,
- OnNavigate(msg))
+ OnDidCommitProvisionalLoad(msg))
IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
IPC_MESSAGE_HANDLER(FrameHostMsg_DocumentOnLoadCompleted,
OnDocumentOnLoadCompleted)
@@ -315,21 +375,225 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(FrameHostMsg_DidAccessInitialDocument,
OnDidAccessInitialDocument)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisownOpener, OnDidDisownOpener)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidAssignPageId, OnDidAssignPageId)
IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateTitle, OnUpdateTitle)
IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateEncoding, OnUpdateEncoding)
- IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_RequestPermission,
- OnRequestDesktopNotificationPermission)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_BeginNavigation,
+ OnBeginNavigation)
+ IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_RequestPermission,
+ OnRequestPlatformNotificationPermission)
IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_Show,
OnShowDesktopNotification)
IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_Cancel,
OnCancelDesktopNotification)
IPC_MESSAGE_HANDLER(FrameHostMsg_TextSurroundingSelectionResponse,
OnTextSurroundingSelectionResponse)
+ IPC_MESSAGE_HANDLER(AccessibilityHostMsg_Events, OnAccessibilityEvents)
+ IPC_MESSAGE_HANDLER(AccessibilityHostMsg_LocationChanges,
+ OnAccessibilityLocationChanges)
+ IPC_MESSAGE_HANDLER(AccessibilityHostMsg_FindInPageResult,
+ OnAccessibilityFindInPageResult)
+ IPC_MESSAGE_HANDLER(PushMessagingHostMsg_RequestPermission,
+ OnRequestPushPermission)
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_HidePopup, OnHidePopup)
+#endif
IPC_END_MESSAGE_MAP()
+ // No further actions here, since we may have been deleted.
return handled;
}
+void RenderFrameHostImpl::AccessibilitySetFocus(int object_id) {
+ Send(new AccessibilityMsg_SetFocus(routing_id_, object_id));
+}
+
+void RenderFrameHostImpl::AccessibilityDoDefaultAction(int object_id) {
+ Send(new AccessibilityMsg_DoDefaultAction(routing_id_, object_id));
+}
+
+void RenderFrameHostImpl::AccessibilityShowMenu(
+ const gfx::Point& global_point) {
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ render_view_host_->GetView());
+ if (view)
+ view->AccessibilityShowMenu(global_point);
+}
+
+void RenderFrameHostImpl::AccessibilityScrollToMakeVisible(
+ int acc_obj_id, const gfx::Rect& subfocus) {
+ Send(new AccessibilityMsg_ScrollToMakeVisible(
+ routing_id_, acc_obj_id, subfocus));
+}
+
+void RenderFrameHostImpl::AccessibilityScrollToPoint(
+ int acc_obj_id, const gfx::Point& point) {
+ Send(new AccessibilityMsg_ScrollToPoint(
+ routing_id_, acc_obj_id, point));
+}
+
+void RenderFrameHostImpl::AccessibilitySetTextSelection(
+ int object_id, int start_offset, int end_offset) {
+ Send(new AccessibilityMsg_SetTextSelection(
+ routing_id_, object_id, start_offset, end_offset));
+}
+
+void RenderFrameHostImpl::AccessibilitySetValue(
+ int object_id, const base::string16& value) {
+ Send(new AccessibilityMsg_SetValue(routing_id_, object_id, value));
+}
+
+bool RenderFrameHostImpl::AccessibilityViewHasFocus() const {
+ RenderWidgetHostView* view = render_view_host_->GetView();
+ if (view)
+ return view->HasFocus();
+ return false;
+}
+
+gfx::Rect RenderFrameHostImpl::AccessibilityGetViewBounds() const {
+ RenderWidgetHostView* view = render_view_host_->GetView();
+ if (view)
+ return view->GetViewBounds();
+ return gfx::Rect();
+}
+
+gfx::Point RenderFrameHostImpl::AccessibilityOriginInScreen(
+ const gfx::Rect& bounds) const {
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ render_view_host_->GetView());
+ if (view)
+ return view->AccessibilityOriginInScreen(bounds);
+ return gfx::Point();
+}
+
+void RenderFrameHostImpl::AccessibilityHitTest(const gfx::Point& point) {
+ Send(new AccessibilityMsg_HitTest(routing_id_, point));
+}
+
+void RenderFrameHostImpl::AccessibilitySetAccessibilityFocus(int acc_obj_id) {
+ Send(new AccessibilityMsg_SetAccessibilityFocus(routing_id_, acc_obj_id));
+}
+
+void RenderFrameHostImpl::AccessibilityFatalError() {
+ browser_accessibility_manager_.reset(NULL);
+ if (accessibility_reset_token_)
+ return;
+
+ accessibility_reset_count_++;
+ if (accessibility_reset_count_ >= kMaxAccessibilityResets) {
+ Send(new AccessibilityMsg_FatalError(routing_id_));
+ } else {
+ accessibility_reset_token_ = g_next_accessibility_reset_token++;
+ UMA_HISTOGRAM_COUNTS("Accessibility.FrameResetCount", 1);
+ Send(new AccessibilityMsg_Reset(routing_id_, accessibility_reset_token_));
+ }
+}
+
+gfx::AcceleratedWidget
+ RenderFrameHostImpl::AccessibilityGetAcceleratedWidget() {
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ render_view_host_->GetView());
+ if (view)
+ return view->AccessibilityGetAcceleratedWidget();
+ return gfx::kNullAcceleratedWidget;
+}
+
+gfx::NativeViewAccessible
+ RenderFrameHostImpl::AccessibilityGetNativeViewAccessible() {
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ render_view_host_->GetView());
+ if (view)
+ return view->AccessibilityGetNativeViewAccessible();
+ return NULL;
+}
+
+BrowserAccessibilityManager* RenderFrameHostImpl::AccessibilityGetChildFrame(
+ int accessibility_node_id) {
+ RenderFrameHostImpl* child_frame =
+ FrameAccessibility::GetInstance()->GetChild(this, accessibility_node_id);
+ if (!child_frame)
+ return NULL;
+
+ // Return NULL if this isn't an out-of-process iframe. Same-process iframes
+ // are already part of the accessibility tree.
+ if (child_frame->GetProcess()->GetID() == GetProcess()->GetID())
+ return NULL;
+
+ // As a sanity check, make sure the frame we're going to return belongs
+ // to the same BrowserContext.
+ if (GetSiteInstance()->GetBrowserContext() !=
+ child_frame->GetSiteInstance()->GetBrowserContext()) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ return child_frame->GetOrCreateBrowserAccessibilityManager();
+}
+
+BrowserAccessibility* RenderFrameHostImpl::AccessibilityGetParentFrame() {
+ RenderFrameHostImpl* parent_frame = NULL;
+ int parent_node_id = 0;
+ if (!FrameAccessibility::GetInstance()->GetParent(
+ this, &parent_frame, &parent_node_id)) {
+ return NULL;
+ }
+
+ // As a sanity check, make sure the frame we're going to return belongs
+ // to the same BrowserContext.
+ if (GetSiteInstance()->GetBrowserContext() !=
+ parent_frame->GetSiteInstance()->GetBrowserContext()) {
+ NOTREACHED();
+ return NULL;
+ }
+
+ BrowserAccessibilityManager* manager =
+ parent_frame->browser_accessibility_manager();
+ if (!manager)
+ return NULL;
+
+ return manager->GetFromID(parent_node_id);
+}
+
+bool RenderFrameHostImpl::CreateRenderFrame(int parent_routing_id,
+ int proxy_routing_id) {
+ TRACE_EVENT0("navigation", "RenderFrameHostImpl::CreateRenderFrame");
+ DCHECK(!IsRenderFrameLive()) << "Creating frame twice";
+
+ // The process may (if we're sharing a process with another host that already
+ // initialized it) or may not (we have our own process or the old process
+ // crashed) have been initialized. Calling Init multiple times will be
+ // ignored, so this is safe.
+ if (!GetProcess()->Init())
+ return false;
+
+ DCHECK(GetProcess()->HasConnection());
+
+ Send(new FrameMsg_NewFrame(routing_id_, parent_routing_id, proxy_routing_id));
+
+ // The renderer now has a RenderFrame for this RenderFrameHost. Note that
+ // this path is only used for out-of-process iframes. Main frame RenderFrames
+ // are created with their RenderView, and same-site iframes are created at the
+ // time of OnCreateChildFrame.
+ set_render_frame_created(true);
+
+ return true;
+}
+
+bool RenderFrameHostImpl::IsRenderFrameLive() {
+ // RenderFrames are created for main frames at the same time as RenderViews,
+ // so we rely on IsRenderViewLive. For subframes, we keep track of each
+ // RenderFrame individually with render_frame_created_.
+ bool is_live = !GetParent() ?
+ render_view_host_->IsRenderViewLive() :
+ GetProcess()->HasConnection() && render_frame_created_;
+
+ // Sanity check: the RenderView should always be live if the RenderFrame is.
+ DCHECK(!is_live || render_view_host_->IsRenderViewLive());
+
+ return is_live;
+}
+
void RenderFrameHostImpl::Init() {
GetProcess()->ResumeRequestsForView(routing_id_);
}
@@ -354,8 +618,22 @@ void RenderFrameHostImpl::OnAddMessageToConsole(
void RenderFrameHostImpl::OnCreateChildFrame(int new_routing_id,
const std::string& frame_name) {
+ // 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)
+ return;
+
RenderFrameHostImpl* new_frame = frame_tree_->AddFrame(
- frame_tree_node_, new_routing_id, frame_name);
+ frame_tree_node_, GetProcess()->GetID(), new_routing_id, frame_name);
+ if (!new_frame)
+ return;
+
+ // We know that the RenderFrame has been created in this case, immediately
+ // after the CreateChildFrame IPC was sent.
+ new_frame->set_render_frame_created(true);
+
if (delegate_)
delegate_->RenderFrameCreated(new_frame);
}
@@ -373,6 +651,8 @@ void RenderFrameHostImpl::OnOpenURL(
GURL validated_url(params.url);
GetProcess()->FilterURL(false, &validated_url);
+ TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnOpenURL",
+ "url", validated_url.possibly_invalid_spec());
frame_tree_node_->navigator()->RequestOpenURL(
this, validated_url, params.referrer, params.disposition,
params.should_replace_current_entry, params.user_gesture);
@@ -385,10 +665,10 @@ void RenderFrameHostImpl::OnDocumentOnLoadCompleted() {
}
void RenderFrameHostImpl::OnDidStartProvisionalLoadForFrame(
- int parent_routing_id,
- const GURL& url) {
+ const GURL& url,
+ bool is_transition_navigation) {
frame_tree_node_->navigator()->DidStartProvisionalLoad(
- this, parent_routing_id, url);
+ this, url, is_transition_navigation);
}
void RenderFrameHostImpl::OnDidFailProvisionalLoadWithError(
@@ -407,14 +687,6 @@ void RenderFrameHostImpl::OnDidFailLoadWithError(
this, validated_url, error_code, error_description);
}
-void RenderFrameHostImpl::OnDidRedirectProvisionalLoad(
- int32 page_id,
- const GURL& source_url,
- const GURL& target_url) {
- frame_tree_node_->navigator()->DidRedirectProvisionalLoad(
- this, page_id, source_url, target_url);
-}
-
// Called when the renderer navigates. For every frame loaded, we'll get this
// notification containing parameters identifying the navigation.
//
@@ -423,7 +695,7 @@ void RenderFrameHostImpl::OnDidRedirectProvisionalLoad(
// level frame. If the user explicitly requests a subframe navigation, we will
// get a new page_id because we need to create a new navigation entry for that
// action.
-void RenderFrameHostImpl::OnNavigate(const IPC::Message& msg) {
+void RenderFrameHostImpl::OnDidCommitProvisionalLoad(const IPC::Message& msg) {
// Read the parameters out of the IPC message directly to avoid making another
// copy when we filter the URLs.
PickleIterator iter(msg);
@@ -431,18 +703,20 @@ void RenderFrameHostImpl::OnNavigate(const IPC::Message& msg) {
if (!IPC::ParamTraits<FrameHostMsg_DidCommitProvisionalLoad_Params>::
Read(&msg, &iter, &validated_params))
return;
+ TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDidCommitProvisionalLoad",
+ "url", validated_params.url.possibly_invalid_spec());
// If we're waiting for a cross-site beforeunload ack from this renderer and
// we receive a Navigate message from the main frame, then the renderer was
- // navigating already and sent it before hearing the ViewMsg_Stop message.
+ // navigating already and sent it before hearing the FrameMsg_Stop message.
// We do not want to cancel the pending navigation in this case, since the
// old page will soon be stopped. Instead, treat this as a beforeunload ack
// to allow the pending navigation to continue.
- if (render_view_host_->is_waiting_for_beforeunload_ack_ &&
- render_view_host_->unload_ack_is_for_cross_site_transition_ &&
- PageTransitionIsMainFrame(validated_params.transition)) {
- OnBeforeUnloadACK(true, send_before_unload_start_time_,
- base::TimeTicks::Now());
+ if (is_waiting_for_beforeunload_ack_ &&
+ unload_ack_is_for_cross_site_transition_ &&
+ ui::PageTransitionIsMainFrame(validated_params.transition)) {
+ base::TimeTicks approx_renderer_start_time = send_before_unload_start_time_;
+ OnBeforeUnloadACK(true, approx_renderer_start_time, base::TimeTicks::Now());
return;
}
@@ -451,7 +725,7 @@ void RenderFrameHostImpl::OnNavigate(const IPC::Message& msg) {
// unload request. It will either respond to the unload request soon or our
// timer will expire. Either way, we should ignore this message, because we
// have already committed to closing this renderer.
- if (render_view_host_->IsWaitingForUnloadACK())
+ if (IsWaitingForUnloadACK())
return;
RenderProcessHost* process = GetProcess();
@@ -490,6 +764,7 @@ void RenderFrameHostImpl::OnNavigate(const IPC::Message& msg) {
return;
}
+ accessibility_reset_count_ = 0;
frame_tree_node()->navigator()->DidNavigate(this, validated_params);
}
@@ -506,7 +781,7 @@ void RenderFrameHostImpl::OnCrossSiteResponse(
scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
const std::vector<GURL>& transfer_url_chain,
const Referrer& referrer,
- PageTransition page_transition,
+ ui::PageTransition page_transition,
bool should_replace_current_entry) {
frame_tree_node_->render_manager()->OnCrossSiteResponse(
this, global_request_id, cross_site_transferring_request.Pass(),
@@ -514,84 +789,124 @@ void RenderFrameHostImpl::OnCrossSiteResponse(
should_replace_current_entry);
}
-void RenderFrameHostImpl::SwapOut(RenderFrameProxyHost* proxy) {
- // TODO(creis): Move swapped out state to RFH. Until then, only update it
- // when swapping out the main frame.
- if (!GetParent()) {
- // If this RenderViewHost is not in the default state, it must have already
- // gone through this, therefore just return.
- if (render_view_host_->rvh_state_ != RenderViewHostImpl::STATE_DEFAULT)
- return;
+void RenderFrameHostImpl::OnDeferredAfterResponseStarted(
+ const GlobalRequestID& global_request_id,
+ const TransitionLayerData& transition_data) {
+ frame_tree_node_->render_manager()->OnDeferredAfterResponseStarted(
+ global_request_id, this);
+
+ if (GetParent() || !delegate_->WillHandleDeferAfterResponseStarted())
+ frame_tree_node_->render_manager()->ResumeResponseDeferredAtStart();
+ else
+ delegate_->DidDeferAfterResponseStarted(transition_data);
+}
- render_view_host_->SetState(
- RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK);
- render_view_host_->unload_event_monitor_timeout_->Start(
- base::TimeDelta::FromMilliseconds(
- RenderViewHostImpl::kUnloadTimeoutMS));
+void RenderFrameHostImpl::SwapOut(RenderFrameProxyHost* proxy) {
+ // The end of this event is in OnSwapOutACK when the RenderFrame has completed
+ // the operation and sends back an IPC message.
+ // The trace event may not end properly if the ACK times out. We expect this
+ // 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
+ // gone through this, therefore just return.
+ if (rfh_state_ != RenderFrameHostImpl::STATE_DEFAULT) {
+ NOTREACHED() << "RFH should be in default state when calling SwapOut.";
+ return;
}
- set_render_frame_proxy_host(proxy);
+ SetState(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT);
+ swapout_event_monitor_timeout_->Start(
+ base::TimeDelta::FromMilliseconds(RenderViewHostImpl::kUnloadTimeoutMS));
+
+ // There may be no proxy if there are no active views in the process.
+ int proxy_routing_id = MSG_ROUTING_NONE;
+ if (proxy) {
+ set_render_frame_proxy_host(proxy);
+ proxy_routing_id = proxy->GetRoutingID();
+ }
- if (render_view_host_->IsRenderViewLive())
- Send(new FrameMsg_SwapOut(routing_id_, proxy->GetRoutingID()));
+ if (IsRenderFrameLive())
+ Send(new FrameMsg_SwapOut(routing_id_, proxy_routing_id));
if (!GetParent())
delegate_->SwappedOut(this);
-
- // Allow the navigation to proceed.
- frame_tree_node_->render_manager()->SwappedOut(this);
}
void RenderFrameHostImpl::OnBeforeUnloadACK(
bool proceed,
const base::TimeTicks& renderer_before_unload_start_time,
const base::TimeTicks& renderer_before_unload_end_time) {
- // TODO(creis): Support properly beforeunload on subframes. For now just
- // pretend that the handler ran and allowed the navigation to proceed.
- if (GetParent()) {
- render_view_host_->is_waiting_for_beforeunload_ack_ = false;
- frame_tree_node_->render_manager()->OnBeforeUnloadACK(
- render_view_host_->unload_ack_is_for_cross_site_transition_, proceed,
- renderer_before_unload_end_time);
- return;
- }
-
+ TRACE_EVENT_ASYNC_END0(
+ "navigation", "RenderFrameHostImpl::BeforeUnload", this);
+ DCHECK(!GetParent());
render_view_host_->decrement_in_flight_event_count();
render_view_host_->StopHangMonitorTimeout();
// If this renderer navigated while the beforeunload request was in flight, we
- // may have cleared this state in OnNavigate, in which case we can ignore
- // this message.
+ // may have cleared this state in OnDidCommitProvisionalLoad, in which case we
+ // can ignore this message.
// However renderer might also be swapped out but we still want to proceed
// with navigation, otherwise it would block future navigations. This can
// happen when pending cross-site navigation is canceled by a second one just
- // before OnNavigate while current RVH is waiting for commit but second
- // navigation is started from the beginning.
- if (!render_view_host_->is_waiting_for_beforeunload_ack_) {
+ // before OnDidCommitProvisionalLoad while current RVH is waiting for commit
+ // but second navigation is started from the beginning.
+ if (!is_waiting_for_beforeunload_ack_) {
return;
}
+ DCHECK(!send_before_unload_start_time_.is_null());
- render_view_host_->is_waiting_for_beforeunload_ack_ = false;
-
- base::TimeTicks before_unload_end_time;
- if (!send_before_unload_start_time_.is_null() &&
- !renderer_before_unload_start_time.is_null() &&
+ // Sets a default value for before_unload_end_time so that the browser
+ // survives a hacked renderer.
+ base::TimeTicks before_unload_end_time = renderer_before_unload_end_time;
+ if (!renderer_before_unload_start_time.is_null() &&
!renderer_before_unload_end_time.is_null()) {
// When passing TimeTicks across process boundaries, we need to compensate
// for any skew between the processes. Here we are converting the
// renderer's notion of before_unload_end_time to TimeTicks in the browser
// process. See comments in inter_process_time_ticks_converter.h for more.
+ base::TimeTicks receive_before_unload_ack_time = base::TimeTicks::Now();
InterProcessTimeTicksConverter converter(
LocalTimeTicks::FromTimeTicks(send_before_unload_start_time_),
- LocalTimeTicks::FromTimeTicks(base::TimeTicks::Now()),
+ LocalTimeTicks::FromTimeTicks(receive_before_unload_ack_time),
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time),
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
LocalTimeTicks browser_before_unload_end_time =
converter.ToLocalTimeTicks(
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
before_unload_end_time = browser_before_unload_end_time.ToTimeTicks();
+
+ // Collect UMA on the inter-process skew.
+ bool is_skew_additive = false;
+ if (converter.IsSkewAdditiveForMetrics()) {
+ is_skew_additive = true;
+ base::TimeDelta skew = converter.GetSkewForMetrics();
+ if (skew >= base::TimeDelta()) {
+ UMA_HISTOGRAM_TIMES(
+ "InterProcessTimeTicks.BrowserBehind_RendererToBrowser", skew);
+ } else {
+ UMA_HISTOGRAM_TIMES(
+ "InterProcessTimeTicks.BrowserAhead_RendererToBrowser", -skew);
+ }
+ }
+ UMA_HISTOGRAM_BOOLEAN(
+ "InterProcessTimeTicks.IsSkewAdditive_RendererToBrowser",
+ is_skew_additive);
+
+ base::TimeDelta on_before_unload_overhead_time =
+ (receive_before_unload_ack_time - send_before_unload_start_time_) -
+ (renderer_before_unload_end_time - renderer_before_unload_start_time);
+ UMA_HISTOGRAM_TIMES("Navigation.OnBeforeUnloadOverheadTime",
+ on_before_unload_overhead_time);
+
+ frame_tree_node_->navigator()->LogBeforeUnloadTime(
+ renderer_before_unload_start_time, renderer_before_unload_end_time);
}
+ // Resets beforeunload waiting state.
+ is_waiting_for_beforeunload_ack_ = false;
+ send_before_unload_start_time_ = base::TimeTicks();
+
frame_tree_node_->render_manager()->OnBeforeUnloadACK(
- render_view_host_->unload_ack_is_for_cross_site_transition_, proceed,
+ unload_ack_is_for_cross_site_transition_, proceed,
before_unload_end_time);
// If canceled, notify the delegate to cancel its pending navigation entry.
@@ -599,17 +914,30 @@ void RenderFrameHostImpl::OnBeforeUnloadACK(
render_view_host_->GetDelegate()->DidCancelLoading();
}
+bool RenderFrameHostImpl::IsWaitingForUnloadACK() const {
+ return render_view_host_->is_waiting_for_close_ack_ ||
+ rfh_state_ == STATE_PENDING_SWAP_OUT;
+}
+
void RenderFrameHostImpl::OnSwapOutACK() {
- OnSwappedOut(false);
+ OnSwappedOut();
}
-void RenderFrameHostImpl::OnSwappedOut(bool timed_out) {
- // For now, we only need to update the RVH state machine for top-level swaps.
- // Subframe swaps (in --site-per-process) can just continue via RFHM.
- if (!GetParent())
- render_view_host_->OnSwappedOut(timed_out);
- else
- frame_tree_node_->render_manager()->SwappedOut(this);
+void RenderFrameHostImpl::OnSwappedOut() {
+ // Ignore spurious swap out ack.
+ if (rfh_state_ != STATE_PENDING_SWAP_OUT)
+ return;
+
+ TRACE_EVENT_ASYNC_END0("navigation", "RenderFrameHostImpl::SwapOut", this);
+ swapout_event_monitor_timeout_->Stop();
+
+ if (frame_tree_node_->render_manager()->DeleteFromPendingList(this)) {
+ // We are now deleted.
+ return;
+ }
+
+ // If this RFH wasn't pending deletion, then it is now swapped out.
+ SetState(RenderFrameHostImpl::STATE_SWAPPED_OUT);
}
void RenderFrameHostImpl::OnContextMenu(const ContextMenuParams& params) {
@@ -666,38 +994,54 @@ void RenderFrameHostImpl::OnRunBeforeUnloadConfirm(
const base::string16& message,
bool is_reload,
IPC::Message* reply_msg) {
- // While a JS before unload dialog is showing, tabs in the same process
+ // While a JS beforeunload dialog is showing, tabs in the same process
// shouldn't process input events.
GetProcess()->SetIgnoreInputEvents(true);
render_view_host_->StopHangMonitorTimeout();
delegate_->RunBeforeUnloadConfirm(this, message, is_reload, reply_msg);
}
-void RenderFrameHostImpl::OnRequestDesktopNotificationPermission(
- const GURL& source_origin, int callback_context) {
- base::Closure done_callback = base::Bind(
- &RenderFrameHostImpl::DesktopNotificationPermissionRequestDone,
- weak_ptr_factory_.GetWeakPtr(), callback_context);
- GetContentClient()->browser()->RequestDesktopNotificationPermission(
- source_origin, this, done_callback);
+void RenderFrameHostImpl::OnRequestPlatformNotificationPermission(
+ const GURL& origin, int request_id) {
+ base::Callback<void(bool)> done_callback = base::Bind(
+ &RenderFrameHostImpl::PlatformNotificationPermissionRequestDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ request_id);
+
+ if (!delegate()->GetAsWebContents())
+ return;
+
+ // TODO(peter): plumb user_gesture and bridge_id.
+ GetContentClient()->browser()->RequestPermission(
+ content::PERMISSION_NOTIFICATIONS,
+ delegate()->GetAsWebContents(),
+ routing_id_,
+ origin,
+ true, // user_gesture,
+ done_callback);
}
void RenderFrameHostImpl::OnShowDesktopNotification(
int notification_id,
const ShowDesktopNotificationHostMsgParams& params) {
+ scoped_ptr<DesktopNotificationDelegateImpl> delegate(
+ new DesktopNotificationDelegateImpl(this, notification_id));
+
base::Closure cancel_callback;
GetContentClient()->browser()->ShowDesktopNotification(
- params, this,
- new DesktopNotificationDelegateImpl(this, notification_id),
+ params,
+ GetSiteInstance()->GetBrowserContext(),
+ GetProcess()->GetID(),
+ delegate.Pass(),
&cancel_callback);
+
cancel_notification_callbacks_[notification_id] = cancel_callback;
}
void RenderFrameHostImpl::OnCancelDesktopNotification(int notification_id) {
- if (!cancel_notification_callbacks_.count(notification_id)) {
- NOTREACHED();
+ if (!cancel_notification_callbacks_.count(notification_id))
return;
- }
+
cancel_notification_callbacks_[notification_id].Run();
cancel_notification_callbacks_.erase(notification_id);
}
@@ -720,8 +1064,13 @@ void RenderFrameHostImpl::OnDidDisownOpener() {
delegate_->DidDisownOpener(this);
}
+void RenderFrameHostImpl::OnDidAssignPageId(int32 page_id) {
+ // Update the RVH's current page ID so that future IPCs from the renderer
+ // correspond to the new page.
+ render_view_host_->page_id_ = page_id;
+}
+
void RenderFrameHostImpl::OnUpdateTitle(
- int32 page_id,
const base::string16& title,
blink::WebTextDirection title_direction) {
// This message is only sent for top-level frames. TODO(avi): when frame tree
@@ -731,7 +1080,7 @@ void RenderFrameHostImpl::OnUpdateTitle(
return;
}
- delegate_->UpdateTitle(this, page_id, title,
+ delegate_->UpdateTitle(this, render_view_host_->page_id_, title,
WebTextDirectionToChromeTextDirection(
title_direction));
}
@@ -742,8 +1091,221 @@ void RenderFrameHostImpl::OnUpdateEncoding(const std::string& encoding_name) {
delegate_->UpdateEncoding(this, encoding_name);
}
-void RenderFrameHostImpl::SetPendingShutdown(const base::Closure& on_swap_out) {
- render_view_host_->SetPendingShutdown(on_swap_out);
+void RenderFrameHostImpl::OnBeginNavigation(
+ const FrameHostMsg_BeginNavigation_Params& params,
+ const CommonNavigationParams& common_params) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ frame_tree_node()->navigator()->OnBeginNavigation(
+ frame_tree_node(), params, common_params);
+}
+
+void RenderFrameHostImpl::OnAccessibilityEvents(
+ const std::vector<AccessibilityHostMsg_EventParams>& params,
+ int reset_token) {
+ // Don't process this IPC if either we're waiting on a reset and this
+ // IPC doesn't have the matching token ID, or if we're not waiting on a
+ // reset but this message includes a reset token.
+ if (accessibility_reset_token_ != reset_token) {
+ Send(new AccessibilityMsg_Events_ACK(routing_id_));
+ return;
+ }
+ accessibility_reset_token_ = 0;
+
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ render_view_host_->GetView());
+
+ AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
+ if ((accessibility_mode != AccessibilityModeOff) && view &&
+ RenderFrameHostImpl::IsRFHStateActive(rfh_state())) {
+ if (accessibility_mode & AccessibilityModeFlagPlatform) {
+ GetOrCreateBrowserAccessibilityManager();
+ if (browser_accessibility_manager_)
+ browser_accessibility_manager_->OnAccessibilityEvents(params);
+ }
+
+ if (browser_accessibility_manager_) {
+ // Get the frame routing ids from out-of-process iframes and
+ // browser plugin instance ids from guests and update the mappings in
+ // FrameAccessibility.
+ for (size_t i = 0; i < params.size(); ++i) {
+ const AccessibilityHostMsg_EventParams& param = params[i];
+ UpdateCrossProcessIframeAccessibility(
+ param.node_to_frame_routing_id_map);
+ UpdateGuestFrameAccessibility(
+ param.node_to_browser_plugin_instance_id_map);
+ }
+ }
+
+ // Send the updates to the automation extension API.
+ std::vector<AXEventNotificationDetails> details;
+ details.reserve(params.size());
+ for (size_t i = 0; i < params.size(); ++i) {
+ const AccessibilityHostMsg_EventParams& param = params[i];
+ AXEventNotificationDetails detail(param.update.node_id_to_clear,
+ param.update.nodes,
+ param.event_type,
+ param.id,
+ GetProcess()->GetID(),
+ routing_id_);
+ details.push_back(detail);
+ }
+
+ delegate_->AccessibilityEventReceived(details);
+ }
+
+ // Always send an ACK or the renderer can be in a bad state.
+ Send(new AccessibilityMsg_Events_ACK(routing_id_));
+
+ // The rest of this code is just for testing; bail out if we're not
+ // in that mode.
+ if (accessibility_testing_callback_.is_null())
+ return;
+
+ for (size_t i = 0; i < params.size(); i++) {
+ const AccessibilityHostMsg_EventParams& param = params[i];
+ if (static_cast<int>(param.event_type) < 0)
+ continue;
+
+ if (!ax_tree_for_testing_) {
+ if (browser_accessibility_manager_) {
+ ax_tree_for_testing_.reset(new ui::AXTree(
+ browser_accessibility_manager_->SnapshotAXTreeForTesting()));
+ } else {
+ ax_tree_for_testing_.reset(new ui::AXTree());
+ CHECK(ax_tree_for_testing_->Unserialize(param.update))
+ << ax_tree_for_testing_->error();
+ }
+ } else {
+ CHECK(ax_tree_for_testing_->Unserialize(param.update))
+ << ax_tree_for_testing_->error();
+ }
+ accessibility_testing_callback_.Run(param.event_type, param.id);
+ }
+}
+
+void RenderFrameHostImpl::OnAccessibilityLocationChanges(
+ const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
+ if (accessibility_reset_token_)
+ return;
+
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ render_view_host_->GetView());
+ if (view && RenderFrameHostImpl::IsRFHStateActive(rfh_state())) {
+ AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
+ if (accessibility_mode & AccessibilityModeFlagPlatform) {
+ BrowserAccessibilityManager* manager =
+ GetOrCreateBrowserAccessibilityManager();
+ if (manager)
+ manager->OnLocationChanges(params);
+ }
+ // TODO(aboxhall): send location change events to web contents observers too
+ }
+}
+
+void RenderFrameHostImpl::OnAccessibilityFindInPageResult(
+ const AccessibilityHostMsg_FindInPageResultParams& params) {
+ AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
+ if (accessibility_mode & AccessibilityModeFlagPlatform) {
+ BrowserAccessibilityManager* manager =
+ GetOrCreateBrowserAccessibilityManager();
+ if (manager) {
+ manager->OnFindInPageResult(
+ params.request_id, params.match_index, params.start_id,
+ params.start_offset, params.end_id, params.end_offset);
+ }
+ }
+}
+
+void RenderFrameHostImpl::OnRequestPushPermission(int request_id,
+ bool user_gesture) {
+ if (!delegate()->GetAsWebContents())
+ return;
+
+ GetContentClient()->browser()->RequestPermission(
+ PERMISSION_PUSH_MESSAGING,
+ delegate()->GetAsWebContents(),
+ routing_id_,
+ GetLastCommittedURL().GetOrigin(),
+ user_gesture,
+ base::Bind(&RenderFrameHostImpl::PushPermissionRequestDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ request_id));
+}
+
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+void RenderFrameHostImpl::OnShowPopup(
+ const FrameHostMsg_ShowPopup_Params& params) {
+ 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,
+ params.allow_multiple_selection);
+ }
+}
+
+void RenderFrameHostImpl::OnHidePopup() {
+ RenderViewHostDelegateView* view =
+ render_view_host_->delegate_->GetDelegateView();
+ if (view)
+ view->HidePopupMenu();
+}
+#endif
+
+void RenderFrameHostImpl::RegisterMojoServices() {
+ GeolocationServiceContext* geolocation_service_context =
+ delegate_ ? delegate_->GetGeolocationServiceContext() : NULL;
+ if (geolocation_service_context) {
+ // TODO(creis): Bind process ID here so that GeolocationServiceImpl
+ // can perform permissions checks once site isolation is complete.
+ // crbug.com/426384
+ GetServiceRegistry()->AddService<GeolocationService>(
+ base::Bind(&GeolocationServiceContext::CreateService,
+ base::Unretained(geolocation_service_context),
+ base::Bind(&RenderFrameHostImpl::DidUseGeolocationPermission,
+ base::Unretained(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());
+
+ // 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()->increment_active_frame_count();
+ else if (IsRFHStateActive(rfh_state_) && !IsRFHStateActive(rfh_state))
+ GetSiteInstance()->decrement_active_frame_count();
+
+ // The active and swapped out 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) {
+ is_waiting_for_beforeunload_ack_ = false;
+ send_before_unload_start_time_ = base::TimeTicks();
+ render_view_host_->is_waiting_for_close_ack_ = false;
+ }
+ rfh_state_ = rfh_state;
}
bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
@@ -756,13 +1318,13 @@ bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
}
void RenderFrameHostImpl::Navigate(const FrameMsg_Navigate_Params& params) {
- TRACE_EVENT0("frame_host", "RenderFrameHostImpl::Navigate");
+ TRACE_EVENT0("navigation", "RenderFrameHostImpl::Navigate");
// Browser plugin guests are not allowed to navigate outside web-safe schemes,
// so do not grant them the ability to request additional URLs.
if (!GetProcess()->IsIsolatedGuest()) {
ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
- GetProcess()->GetID(), params.url);
- if (params.url.SchemeIs(url::kDataScheme) &&
+ GetProcess()->GetID(), params.common_params.url);
+ if (params.common_params.url.SchemeIs(url::kDataScheme) &&
params.base_url_for_data_url.SchemeIs(url::kFileScheme)) {
// If 'data:' is used, and we have a 'file:' base url, grant access to
// local files.
@@ -773,18 +1335,17 @@ void RenderFrameHostImpl::Navigate(const FrameMsg_Navigate_Params& params) {
// Only send the message if we aren't suspended at the start of a cross-site
// request.
- if (render_view_host_->navigations_suspended_) {
+ if (navigations_suspended_) {
// Shouldn't be possible to have a second navigation while suspended, since
// navigations will only be suspended during a cross-site request. If a
// second navigation occurs, RenderFrameHostManager will cancel this pending
// RFH and create a new pending RFH.
- DCHECK(!render_view_host_->suspended_nav_params_.get());
- render_view_host_->suspended_nav_params_.reset(
- new FrameMsg_Navigate_Params(params));
+ DCHECK(!suspended_nav_params_.get());
+ suspended_nav_params_.reset(new FrameMsg_Navigate_Params(params));
} else {
// Get back to a clean state, in case we start a new navigation without
- // completing a RVH swap or unload handler.
- render_view_host_->SetState(RenderViewHostImpl::STATE_DEFAULT);
+ // completing a RFH swap or unload handler.
+ SetState(RenderFrameHostImpl::STATE_DEFAULT);
Send(new FrameMsg_Navigate(routing_id_, params));
}
@@ -800,53 +1361,60 @@ void RenderFrameHostImpl::Navigate(const FrameMsg_Navigate_Params& params) {
//
// Blink doesn't send throb notifications for JavaScript URLs, so we
// don't want to either.
- if (!params.url.SchemeIs(url::kJavaScriptScheme))
+ if (!params.common_params.url.SchemeIs(url::kJavaScriptScheme))
delegate_->DidStartLoading(this, true);
}
void RenderFrameHostImpl::NavigateToURL(const GURL& url) {
FrameMsg_Navigate_Params params;
+ params.common_params.url = url;
+ params.common_params.transition = ui::PAGE_TRANSITION_LINK;
+ params.common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+ params.commit_params.browser_navigation_start = base::TimeTicks::Now();
params.page_id = -1;
params.pending_history_list_offset = -1;
params.current_history_list_offset = -1;
params.current_history_list_length = 0;
- params.url = url;
- params.transition = PAGE_TRANSITION_LINK;
- params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
Navigate(params);
}
+void RenderFrameHostImpl::OpenURL(const FrameHostMsg_OpenURL_Params& params) {
+ OnOpenURL(params);
+}
+
+void RenderFrameHostImpl::Stop() {
+ Send(new FrameMsg_Stop(routing_id_));
+}
+
void RenderFrameHostImpl::DispatchBeforeUnload(bool for_cross_site_transition) {
- // TODO(creis): Support subframes.
- if (!render_view_host_->IsRenderViewLive() || GetParent()) {
+ // TODO(creis): Support beforeunload on subframes. For now just pretend that
+ // the handler ran and allowed the navigation to proceed.
+ if (GetParent() || !IsRenderFrameLive()) {
// We don't have a live renderer, so just skip running beforeunload.
- render_view_host_->is_waiting_for_beforeunload_ack_ = true;
- render_view_host_->unload_ack_is_for_cross_site_transition_ =
- for_cross_site_transition;
- base::TimeTicks now = base::TimeTicks::Now();
- OnBeforeUnloadACK(true, now, now);
+ frame_tree_node_->render_manager()->OnBeforeUnloadACK(
+ for_cross_site_transition, true, base::TimeTicks::Now());
return;
}
+ TRACE_EVENT_ASYNC_BEGIN0(
+ "navigation", "RenderFrameHostImpl::BeforeUnload", this);
// This may be called more than once (if the user clicks the tab close button
// several times, or if she clicks the tab close button then the browser close
// button), and we only send the message once.
- if (render_view_host_->is_waiting_for_beforeunload_ack_) {
+ if (is_waiting_for_beforeunload_ack_) {
// Some of our close messages could be for the tab, others for cross-site
// transitions. We always want to think it's for closing the tab if any
// of the messages were, since otherwise it might be impossible to close
// (if there was a cross-site "close" request pending when the user clicked
// the close button). We want to keep the "for cross site" flag only if
// both the old and the new ones are also for cross site.
- render_view_host_->unload_ack_is_for_cross_site_transition_ =
- render_view_host_->unload_ack_is_for_cross_site_transition_ &&
- for_cross_site_transition;
+ unload_ack_is_for_cross_site_transition_ =
+ unload_ack_is_for_cross_site_transition_ && for_cross_site_transition;
} else {
// Start the hang monitor in case the renderer hangs in the beforeunload
// handler.
- render_view_host_->is_waiting_for_beforeunload_ack_ = true;
- render_view_host_->unload_ack_is_for_cross_site_transition_ =
- for_cross_site_transition;
+ is_waiting_for_beforeunload_ack_ = true;
+ unload_ack_is_for_cross_site_transition_ = for_cross_site_transition;
// Increment the in-flight event count, to ensure that input events won't
// cancel the timeout timer.
render_view_host_->increment_in_flight_event_count();
@@ -857,9 +1425,13 @@ void RenderFrameHostImpl::DispatchBeforeUnload(bool for_cross_site_transition) {
}
}
+void RenderFrameHostImpl::DisownOpener() {
+ Send(new FrameMsg_DisownOpener(GetRoutingID()));
+}
+
void RenderFrameHostImpl::ExtendSelectionAndDelete(size_t before,
size_t after) {
- Send(new FrameMsg_ExtendSelectionAndDelete(routing_id_, before, after));
+ Send(new InputMsg_ExtendSelectionAndDelete(routing_id_, before, after));
}
void RenderFrameHostImpl::JavaScriptDialogClosed(
@@ -868,8 +1440,7 @@ void RenderFrameHostImpl::JavaScriptDialogClosed(
const base::string16& user_input,
bool dialog_was_suppressed) {
GetProcess()->SetIgnoreInputEvents(false);
- bool is_waiting = render_view_host_->is_waiting_for_beforeunload_ack() ||
- render_view_host_->IsWaitingForUnloadACK();
+ bool is_waiting = is_waiting_for_beforeunload_ack_ || IsWaitingForUnloadACK();
// If we are executing as part of (before)unload event handling, we don't
// want to use the regular hung_renderer_delay_ms_ if the user has agreed to
@@ -892,20 +1463,249 @@ void RenderFrameHostImpl::JavaScriptDialogClosed(
// This must be done after sending the reply since RenderView can't close
// correctly while waiting for a response.
if (is_waiting && dialog_was_suppressed)
- render_view_host_->delegate_->RendererUnresponsive(
- render_view_host_,
- render_view_host_->is_waiting_for_beforeunload_ack(),
- render_view_host_->IsWaitingForUnloadACK());
+ render_view_host_->delegate_->RendererUnresponsive(render_view_host_);
}
void RenderFrameHostImpl::NotificationClosed(int notification_id) {
cancel_notification_callbacks_.erase(notification_id);
}
-void RenderFrameHostImpl::DesktopNotificationPermissionRequestDone(
- int callback_context) {
- Send(new DesktopNotificationMsg_PermissionRequestDone(
- routing_id_, callback_context));
+// PlzNavigate
+void RenderFrameHostImpl::CommitNavigation(
+ ResourceResponse* response,
+ scoped_ptr<StreamHandle> body,
+ const CommonNavigationParams& common_params,
+ const CommitNavigationParams& commit_params) {
+ // TODO(clamy): Check if we have to add security checks for the browser plugin
+ // guests.
+
+ Send(new FrameMsg_CommitNavigation(
+ routing_id_, response->head, body->GetURL(),
+ common_params, commit_params));
+ // TODO(clamy): Check if we should start the throbber for non javascript urls
+ // here.
+
+ // TODO(clamy): Release the stream handle once the renderer has finished
+ // reading it.
+ stream_handle_ = body.Pass();
+}
+
+void RenderFrameHostImpl::SetUpMojoIfNeeded() {
+ if (service_registry_.get())
+ return;
+
+ service_registry_.reset(new ServiceRegistryImpl());
+ if (!GetProcess()->GetServiceRegistry())
+ return;
+
+ RegisterMojoServices();
+ RenderFrameSetupPtr setup;
+ GetProcess()->GetServiceRegistry()->ConnectToRemoteService(&setup);
+ mojo::ServiceProviderPtr service_provider;
+ setup->GetServiceProviderForFrame(routing_id_,
+ mojo::GetProxy(&service_provider));
+ service_registry_->BindRemoteServiceProvider(
+ service_provider.PassMessagePipe());
+
+#if defined(OS_ANDROID)
+ service_registry_android_.reset(
+ new ServiceRegistryAndroid(service_registry_.get()));
+#endif
+}
+
+void RenderFrameHostImpl::InvalidateMojoConnection() {
+#if defined(OS_ANDROID)
+ // The Android-specific service registry has a reference to
+ // |service_registry_| and thus must be torn down first.
+ service_registry_android_.reset();
+#endif
+
+ service_registry_.reset();
+}
+
+void RenderFrameHostImpl::PlatformNotificationPermissionRequestDone(
+ int request_id,
+ bool granted) {
+ blink::WebNotificationPermission permission =
+ granted ? blink::WebNotificationPermissionAllowed
+ : blink::WebNotificationPermissionDenied;
+
+ Send(new PlatformNotificationMsg_PermissionRequestComplete(
+ routing_id_, request_id, permission));
+}
+
+void RenderFrameHostImpl::PushPermissionRequestDone(int request_id,
+ bool allowed) {
+ Send(new PushMessagingMsg_RequestPermissionResponse(routing_id_, request_id));
+}
+
+void RenderFrameHostImpl::UpdateCrossProcessIframeAccessibility(
+ const std::map<int32, int>& node_to_frame_routing_id_map) {
+ for (const auto& iter : node_to_frame_routing_id_map) {
+ // This is the id of the accessibility node that has a child frame.
+ int32 node_id = iter.first;
+ // The routing id from either a RenderFrame or a RenderFrameProxy.
+ int frame_routing_id = iter.second;
+
+ FrameTree* frame_tree = frame_tree_node()->frame_tree();
+ FrameTreeNode* child_frame_tree_node = frame_tree->FindByRoutingID(
+ GetProcess()->GetID(), frame_routing_id);
+ if (child_frame_tree_node) {
+ FrameAccessibility::GetInstance()->AddChildFrame(
+ this, node_id, child_frame_tree_node->frame_tree_node_id());
+ }
+ }
+}
+
+void RenderFrameHostImpl::UpdateGuestFrameAccessibility(
+ const std::map<int32, int>& node_to_browser_plugin_instance_id_map) {
+ for (const auto& iter : node_to_browser_plugin_instance_id_map) {
+ // This is the id of the accessibility node that hosts a plugin.
+ int32 node_id = iter.first;
+ // The id of the browser plugin.
+ int browser_plugin_instance_id = iter.second;
+ FrameAccessibility::GetInstance()->AddGuestWebContents(
+ this, node_id, browser_plugin_instance_id);
+ }
+}
+
+void RenderFrameHostImpl::SetAccessibilityMode(AccessibilityMode mode) {
+ Send(new FrameMsg_SetAccessibilityMode(routing_id_, mode));
+}
+
+void RenderFrameHostImpl::SetAccessibilityCallbackForTesting(
+ const base::Callback<void(ui::AXEvent, int)>& callback) {
+ accessibility_testing_callback_ = callback;
+}
+
+const ui::AXTree* RenderFrameHostImpl::GetAXTreeForTesting() {
+ return ax_tree_for_testing_.get();
+}
+
+BrowserAccessibilityManager*
+ RenderFrameHostImpl::GetOrCreateBrowserAccessibilityManager() {
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ render_view_host_->GetView());
+ if (view &&
+ !browser_accessibility_manager_ &&
+ !no_create_browser_accessibility_manager_for_testing_) {
+ browser_accessibility_manager_.reset(
+ view->CreateBrowserAccessibilityManager(this));
+ if (browser_accessibility_manager_)
+ UMA_HISTOGRAM_COUNTS("Accessibility.FrameEnabledCount", 1);
+ else
+ UMA_HISTOGRAM_COUNTS("Accessibility.FrameDidNotEnableCount", 1);
+ }
+ return browser_accessibility_manager_.get();
+}
+
+void RenderFrameHostImpl::ActivateFindInPageResultForAccessibility(
+ int request_id) {
+ AccessibilityMode accessibility_mode = delegate_->GetAccessibilityMode();
+ if (accessibility_mode & AccessibilityModeFlagPlatform) {
+ BrowserAccessibilityManager* manager =
+ GetOrCreateBrowserAccessibilityManager();
+ if (manager)
+ manager->ActivateFindInPageResult(request_id);
+ }
+}
+
+#if defined(OS_WIN)
+
+void RenderFrameHostImpl::SetParentNativeViewAccessible(
+ gfx::NativeViewAccessible accessible_parent) {
+ RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
+ render_view_host_->GetView());
+ if (view)
+ view->SetParentNativeViewAccessible(accessible_parent);
+}
+
+gfx::NativeViewAccessible
+RenderFrameHostImpl::GetParentNativeViewAccessible() const {
+ return delegate_->GetParentNativeViewAccessible();
+}
+
+#elif defined(OS_MACOSX)
+
+void RenderFrameHostImpl::DidSelectPopupMenuItem(int selected_index) {
+ Send(new FrameMsg_SelectPopupMenuItem(routing_id_, selected_index));
+}
+
+void RenderFrameHostImpl::DidCancelPopupMenu() {
+ Send(new FrameMsg_SelectPopupMenuItem(routing_id_, -1));
+}
+
+#elif defined(OS_ANDROID)
+
+void RenderFrameHostImpl::DidSelectPopupMenuItems(
+ const std::vector<int>& selected_indices) {
+ Send(new FrameMsg_SelectPopupMenuItems(routing_id_, false, selected_indices));
+}
+
+void RenderFrameHostImpl::DidCancelPopupMenu() {
+ Send(new FrameMsg_SelectPopupMenuItems(
+ routing_id_, true, std::vector<int>()));
+}
+
+#endif
+
+void RenderFrameHostImpl::ClearPendingTransitionRequestData() {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &TransitionRequestManager::ClearPendingTransitionRequestData,
+ base::Unretained(TransitionRequestManager::GetInstance()),
+ GetProcess()->GetID(),
+ routing_id_));
+}
+
+void RenderFrameHostImpl::SetNavigationsSuspended(
+ bool suspend,
+ const base::TimeTicks& proceed_time) {
+ // This should only be called to toggle the state.
+ DCHECK(navigations_suspended_ != suspend);
+
+ navigations_suspended_ = suspend;
+ if (navigations_suspended_) {
+ TRACE_EVENT_ASYNC_BEGIN0("navigation",
+ "RenderFrameHostImpl navigation suspended", this);
+ } else {
+ TRACE_EVENT_ASYNC_END0("navigation",
+ "RenderFrameHostImpl navigation suspended", this);
+ }
+
+ 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);
+
+ DCHECK(!proceed_time.is_null());
+ suspended_nav_params_->commit_params.browser_navigation_start =
+ proceed_time;
+ Send(new FrameMsg_Navigate(routing_id_, *suspended_nav_params_));
+ suspended_nav_params_.reset();
+ }
+}
+
+void RenderFrameHostImpl::CancelSuspendedNavigations() {
+ // Clear any state if a pending navigation is canceled or preempted.
+ if (suspended_nav_params_)
+ suspended_nav_params_.reset();
+
+ TRACE_EVENT_ASYNC_END0("navigation",
+ "RenderFrameHostImpl navigation suspended", this);
+ navigations_suspended_ = false;
+}
+
+void RenderFrameHostImpl::DidUseGeolocationPermission() {
+ RenderFrameHost* top_frame = frame_tree_node()->frame_tree()->GetMainFrame();
+ GetContentClient()->browser()->RegisterPermissionUsage(
+ PERMISSION_GEOLOCATION,
+ delegate_->GetAsWebContents(),
+ GetLastCommittedURL().GetOrigin(),
+ top_frame->GetLastCommittedURL().GetOrigin());
}
} // 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 854a14fb39e..b1c470312f4 100644
--- a/chromium/content/browser/frame_host/render_frame_host_impl.h
+++ b/chromium/content/browser/frame_host/render_frame_host_impl.h
@@ -10,19 +10,37 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/common/accessibility_mode_enums.h"
#include "content/common/content_export.h"
+#include "content/common/mojo/service_registry_impl.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/javascript_message_type.h"
-#include "content/public/common/page_transition_types.h"
+#include "net/http/http_response_headers.h"
#include "third_party/WebKit/public/web/WebTextDirection.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/base/page_transition_types.h"
+
+#if defined(OS_ANDROID)
+#include "content/browser/mojo/service_registry_android.h"
+#endif
class GURL;
+struct AccessibilityHostMsg_EventParams;
+struct AccessibilityHostMsg_FindInPageResultParams;
+struct AccessibilityHostMsg_LocationChangeParams;
struct FrameHostMsg_DidFailProvisionalLoadWithError_Params;
struct FrameHostMsg_OpenURL_Params;
+struct FrameHostMsg_BeginNavigation_Params;
struct FrameMsg_Navigate_Params;
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+struct FrameHostMsg_ShowPopup_Params;
+#endif
namespace base {
class FilePath;
@@ -40,40 +58,118 @@ class RenderFrameProxyHost;
class RenderProcessHost;
class RenderViewHostImpl;
class RenderWidgetHostImpl;
+class StreamHandle;
+class TimeoutMonitor;
+struct CommitNavigationParams;
+struct CommonNavigationParams;
struct ContextMenuParams;
struct GlobalRequestID;
struct Referrer;
+struct ResourceResponse;
struct ShowDesktopNotificationHostMsgParams;
+struct TransitionLayerData;
-class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
+class CONTENT_EXPORT RenderFrameHostImpl
+ : public RenderFrameHost,
+ public BrowserAccessibilityDelegate {
public:
+ // 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.
+ static const int kMaxAccessibilityResets = 5;
+
static RenderFrameHostImpl* FromID(int process_id, int routing_id);
- virtual ~RenderFrameHostImpl();
+ ~RenderFrameHostImpl() override;
// RenderFrameHost
- virtual int GetRoutingID() OVERRIDE;
- virtual SiteInstance* GetSiteInstance() OVERRIDE;
- virtual RenderProcessHost* GetProcess() OVERRIDE;
- virtual RenderFrameHost* GetParent() OVERRIDE;
- virtual const std::string& GetFrameName() OVERRIDE;
- virtual bool IsCrossProcessSubframe() OVERRIDE;
- virtual GURL GetLastCommittedURL() OVERRIDE;
- virtual gfx::NativeView GetNativeView() OVERRIDE;
- virtual void ExecuteJavaScript(
- const base::string16& javascript) OVERRIDE;
- virtual void ExecuteJavaScript(
- const base::string16& javascript,
- const JavaScriptResultCallback& callback) OVERRIDE;
- virtual RenderViewHost* GetRenderViewHost() OVERRIDE;
+ int GetRoutingID() override;
+ SiteInstanceImpl* GetSiteInstance() override;
+ RenderProcessHost* GetProcess() override;
+ RenderFrameHost* GetParent() override;
+ const std::string& GetFrameName() override;
+ bool IsCrossProcessSubframe() override;
+ GURL GetLastCommittedURL() override;
+ gfx::NativeView GetNativeView() override;
+ void ExecuteJavaScript(const base::string16& javascript) override;
+ void ExecuteJavaScript(const base::string16& javascript,
+ const JavaScriptResultCallback& callback) override;
+ void ExecuteJavaScriptForTests(const base::string16& javascript) override;
+ RenderViewHost* GetRenderViewHost() override;
+ ServiceRegistry* GetServiceRegistry() override;
+ void ActivateFindInPageResultForAccessibility(int request_id) override;
// IPC::Sender
- virtual bool Send(IPC::Message* msg) OVERRIDE;
+ bool Send(IPC::Message* msg) override;
// IPC::Listener
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+
+ // BrowserAccessibilityDelegate
+ void AccessibilitySetFocus(int acc_obj_id) override;
+ void AccessibilityDoDefaultAction(int acc_obj_id) override;
+ void AccessibilityShowMenu(const gfx::Point& global_point) override;
+ void AccessibilityScrollToMakeVisible(int acc_obj_id,
+ const gfx::Rect& subfocus) override;
+ void AccessibilityScrollToPoint(int acc_obj_id,
+ const gfx::Point& point) override;
+ void AccessibilitySetTextSelection(int acc_obj_id,
+ int start_offset,
+ int end_offset) override;
+ void AccessibilitySetValue(int acc_obj_id, const base::string16& value)
+ override;
+ bool AccessibilityViewHasFocus() const override;
+ gfx::Rect AccessibilityGetViewBounds() const override;
+ gfx::Point AccessibilityOriginInScreen(
+ const gfx::Rect& bounds) const 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;
+ BrowserAccessibilityManager* AccessibilityGetChildFrame(
+ int accessibility_node_id) override;
+ BrowserAccessibility* AccessibilityGetParentFrame() override;
+
+ // Creates a RenderFrame in the renderer process. Only called for
+ // cross-process subframe navigations in --site-per-process.
+ bool CreateRenderFrame(int parent_routing_id, int proxy_routing_id);
+
+ // Returns whether the RenderFrame in the renderer process has been created
+ // and still has a connection. This is valid for all frames.
+ bool IsRenderFrameLive();
+
+ // Tracks whether the RenderFrame for this RenderFrameHost has been created in
+ // the renderer process. This is currently only used for subframes.
+ // TODO(creis): Use this for main frames as well when RVH goes away.
+ void set_render_frame_created(bool created) {
+ render_frame_created_ = created;
+ }
+ // Called for renderer-created windows to resume requests from this frame,
+ // after they are blocked in RenderWidgetHelper::CreateNewWindow.
void Init();
+
int routing_id() const { return routing_id_; }
void OnCreateChildFrame(int new_routing_id,
const std::string& frame_name);
@@ -115,26 +211,41 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
const std::vector<GURL>& transfer_url_chain,
const Referrer& referrer,
- PageTransition page_transition,
+ ui::PageTransition page_transition,
bool should_replace_current_entry);
+ // Called on the current RenderFrameHost when the network response is first
+ // receieved.
+ void OnDeferredAfterResponseStarted(
+ const GlobalRequestID& global_request_id,
+ const TransitionLayerData& transition_data);
+
// Tells the renderer that this RenderFrame is being swapped out for one in a
- // different renderer process. It should run its unload handler, move to
- // a blank document and create a RenderFrameProxy to replace the RenderFrame.
- // The renderer should preserve the Proxy object until it exits, in case we
- // come back. The renderer can exit if it has no other active RenderFrames,
- // but not until WasSwappedOut is called (when it is no longer visible).
+ // different renderer process. It should run its unload handler and move to
+ // a blank document. If |proxy| is not null, it should also create a
+ // RenderFrameProxy to replace the RenderFrame. The renderer should preserve
+ // the RenderFrameProxy object until it exits, in case we come back. The
+ // renderer can exit if it has no other active RenderFrames, but not until
+ // WasSwappedOut is called.
void SwapOut(RenderFrameProxyHost* proxy);
- void OnSwappedOut(bool timed_out);
- bool is_swapped_out() { return is_swapped_out_; }
- void set_swapped_out(bool is_swapped_out) {
- is_swapped_out_ = is_swapped_out;
+ bool is_waiting_for_beforeunload_ack() const {
+ return is_waiting_for_beforeunload_ack_;
}
- // Sets the RVH for |this| as pending shutdown. |on_swap_out| will be called
- // when the SwapOutACK is received.
- void SetPendingShutdown(const base::Closure& on_swap_out);
+ // Whether the RFH is waiting for an unload ACK from the renderer.
+ bool IsWaitingForUnloadACK() const;
+
+ // Called when either the SwapOut request has been acknowledged or has timed
+ // 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_; }
// Sends the given navigation message. Use this rather than sending it
// yourself since this does the internal bookkeeping described below. This
@@ -148,11 +259,47 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
// Load the specified URL; this is a shortcut for Navigate().
void NavigateToURL(const GURL& url);
+ // Treat this prospective navigation as thought it originated from the
+ // frame. Used, e.g., for a navigation request that originated from
+ // a RemoteFrame.
+ void OpenURL(const FrameHostMsg_OpenURL_Params& params);
+
+ // Stop the load in progress.
+ void Stop();
+
+ // Returns whether navigation messages are currently suspended for this
+ // RenderFrameHost. Only true during a cross-site navigation, while waiting
+ // for the onbeforeunload handler.
+ bool are_navigations_suspended() const { return navigations_suspended_; }
+
+ // Suspends (or unsuspends) any navigation messages from being sent from this
+ // RenderFrameHost. This is called when a pending RenderFrameHost is created
+ // for a cross-site navigation, because we must suspend any navigations until
+ // we hear back from the old renderer's onbeforeunload handler. Note that it
+ // is important that only one navigation event happen after calling this
+ // method with |suspend| equal to true. If |suspend| is false and there is a
+ // suspended_nav_message_, this will send the message. This function should
+ // only be called to toggle the state; callers should check
+ // are_navigations_suspended() first. If |suspend| is false, the time that the
+ // user decided the navigation should proceed should be passed as
+ // |proceed_time|.
+ void SetNavigationsSuspended(bool suspend,
+ const base::TimeTicks& proceed_time);
+
+ // Clears any suspended navigation state after a cross-site navigation is
+ // canceled or suspended. This is important if we later return to this
+ // RenderFrameHost.
+ void CancelSuspendedNavigations();
+
// Runs the beforeunload handler for this frame. |for_cross_site_transition|
// indicates whether this call is for the current frame during a cross-process
// navigation. False means we're closing the entire tab.
void DispatchBeforeUnload(bool for_cross_site_transition);
+ // Set the frame's opener to null in the renderer process in response to an
+ // action in another renderer process.
+ void DisownOpener();
+
// Deletes the current selection plus the specified number of characters
// before and after the selection or caret.
void ExtendSelectionAndDelete(size_t before, size_t after);
@@ -167,6 +314,67 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
// Called when an HTML5 notification is closed.
void NotificationClosed(int notification_id);
+ // Clears any outstanding transition request. This is called when we hear the
+ // response or commit.
+ void ClearPendingTransitionRequestData();
+
+ // Send a message to the renderer process to change the accessibility mode.
+ void SetAccessibilityMode(AccessibilityMode AccessibilityMode);
+
+ // Turn on accessibility testing. The given callback will be run
+ // every time an accessibility notification is received from the
+ // renderer process, and the accessibility tree it sent can be
+ // retrieved using GetAXTreeForTesting().
+ void SetAccessibilityCallbackForTesting(
+ const base::Callback<void(ui::AXEvent, int)>& callback);
+
+ // Returns a snapshot of the accessibility tree received from the
+ // renderer as of the last time an accessibility notification was
+ // received.
+ const ui::AXTree* GetAXTreeForTesting();
+
+ // Access the BrowserAccessibilityManager if it already exists.
+ BrowserAccessibilityManager* browser_accessibility_manager() const {
+ return browser_accessibility_manager_.get();
+ }
+
+ // If accessibility is enabled, get the BrowserAccessibilityManager for
+ // this frame, or create one if it doesn't exist yet, otherwise return
+ // NULL.
+ BrowserAccessibilityManager* GetOrCreateBrowserAccessibilityManager();
+
+ void set_no_create_browser_accessibility_manager_for_testing(bool flag) {
+ 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)
+ // Select popup menu related methods (for external popup menus).
+ void DidSelectPopupMenuItem(int selected_index);
+ void DidCancelPopupMenu();
+#elif defined(OS_ANDROID)
+ void DidSelectPopupMenuItems(const std::vector<int>& selected_indices);
+ void DidCancelPopupMenu();
+#endif
+
+ // PlzNavigate: Indicates that a navigation is ready to commit and can be
+ // handled by this RenderFrame.
+ void CommitNavigation(ResourceResponse* response,
+ scoped_ptr<StreamHandle> body,
+ const CommonNavigationParams& common_params,
+ const CommitNavigationParams& commit_params);
+
+ // Sets up the Mojo connection between this instance and its associated render
+ // frame if it has not yet been set up.
+ void SetUpMojoIfNeeded();
+
+ // Tears down the browser-side state relating to the Mojo connection between
+ // this instance and its associated render frame.
+ void InvalidateMojoConnection();
+
protected:
friend class RenderFrameHostFactory;
@@ -184,6 +392,8 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
friend class TestRenderFrameHost;
friend class TestRenderViewHost;
+ FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, CrashSubframe);
+
// IPC Message handlers.
void OnAddMessageToConsole(int32 level,
const base::string16& message,
@@ -193,18 +403,15 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
void OnFrameFocused();
void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
void OnDocumentOnLoadCompleted();
- void OnDidStartProvisionalLoadForFrame(int parent_routing_id,
- const GURL& url);
+ void OnDidStartProvisionalLoadForFrame(const GURL& url,
+ bool is_transition_navigation);
void OnDidFailProvisionalLoadWithError(
const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params);
void OnDidFailLoadWithError(
const GURL& url,
int error_code,
const base::string16& error_description);
- void OnDidRedirectProvisionalLoad(int32 page_id,
- const GURL& source_url,
- const GURL& target_url);
- void OnNavigate(const IPC::Message& msg);
+ void OnDidCommitProvisionalLoad(const IPC::Message& msg);
void OnBeforeUnloadACK(
bool proceed,
const base::TimeTicks& renderer_before_unload_start_time,
@@ -221,8 +428,8 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
const base::string16& message,
bool is_reload,
IPC::Message* reply_msg);
- void OnRequestDesktopNotificationPermission(const GURL& origin,
- int callback_id);
+ void OnRequestPlatformNotificationPermission(const GURL& origin,
+ int request_id);
void OnShowDesktopNotification(
int notification_id,
const ShowDesktopNotificationHostMsgParams& params);
@@ -232,17 +439,56 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
size_t end_offset);
void OnDidAccessInitialDocument();
void OnDidDisownOpener();
- void OnUpdateTitle(int32 page_id,
- const base::string16& title,
+ void OnDidAssignPageId(int32 page_id);
+ void OnUpdateTitle(const base::string16& title,
blink::WebTextDirection title_direction);
void OnUpdateEncoding(const std::string& encoding);
+ void OnBeginNavigation(const FrameHostMsg_BeginNavigation_Params& params,
+ const CommonNavigationParams& common_params);
+ void OnAccessibilityEvents(
+ const std::vector<AccessibilityHostMsg_EventParams>& params,
+ int reset_token);
+ void OnAccessibilityLocationChanges(
+ const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
+ void OnAccessibilityFindInPageResult(
+ const AccessibilityHostMsg_FindInPageResultParams& params);
+ void OnRequestPushPermission(int request_id, bool user_gesture);
+
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+ void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params);
+ void OnHidePopup();
+#endif
+
+ // 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);
// 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);
- void DesktopNotificationPermissionRequestDone(int callback_context);
+ void PlatformNotificationPermissionRequestDone(int request_id, bool granted);
+
+ void PushPermissionRequestDone(int request_id, bool allowed);
+
+ // Update the the singleton FrameAccessibility instance with a map
+ // from accessibility node id to the frame routing id of a cross-process
+ // iframe.
+ void UpdateCrossProcessIframeAccessibility(
+ const std::map<int32, int>& node_to_frame_routing_id_map);
+
+ // Update the the singleton FrameAccessibility instance with a map
+ // from accessibility node id to the browser plugin instance id of a
+ // guest WebContents.
+ void UpdateGuestFrameAccessibility(
+ const std::map<int32, int>& node_to_browser_plugin_instance_id_map);
+
+ // Informs the content client that geolocation permissions were used.
+ void DidUseGeolocationPermission();
// For now, RenderFrameHosts indirectly keep RenderViewHosts alive via a
// refcount that calls Shutdown when it reaches zero. This allows each
@@ -288,11 +534,82 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost {
std::map<int, base::Closure> cancel_notification_callbacks_;
int routing_id_;
- bool is_swapped_out_;
+
+ // The current state of this RenderFrameHost.
+ RenderFrameHostImplState rfh_state_;
+
+ // Tracks whether the RenderFrame for this RenderFrameHost has been created in
+ // the renderer process. Currently only used for subframes.
+ // TODO(creis): Use this for main frames as well when RVH goes away.
+ bool render_frame_created_;
+
+ // Whether we should buffer outgoing Navigate messages rather than sending
+ // them. This will be true when a RenderFrameHost is created for a cross-site
+ // request, until we hear back from the onbeforeunload handler of the old
+ // RenderFrameHost.
+ bool navigations_suspended_;
+
+ // We only buffer the params for a suspended navigation while this RFH is the
+ // pending RenderFrameHost of a RenderFrameHostManager. There will only ever
+ // be one suspended navigation, because RenderFrameHostManager will destroy
+ // the pending RenderFrameHost and create a new one if a second navigation
+ // occurs.
+ scoped_ptr<FrameMsg_Navigate_Params> suspended_nav_params_;
// When the last BeforeUnload message was sent.
base::TimeTicks send_before_unload_start_time_;
+ // Set to true when there is a pending FrameMsg_ShouldClose message. This
+ // ensures we don't spam the renderer with multiple beforeunload requests.
+ // When either this value or IsWaitingForUnloadACK is true, the value of
+ // unload_ack_is_for_cross_site_transition_ indicates whether this is for a
+ // cross-site transition or a tab close attempt.
+ // TODO(clamy): Remove this boolean and add one more state to the state
+ // machine.
+ bool is_waiting_for_beforeunload_ack_;
+
+ // Valid only when is_waiting_for_beforeunload_ack_ or
+ // IsWaitingForUnloadACK is true. This tells us if the unload request
+ // is for closing the entire tab ( = false), or only this RenderFrameHost in
+ // the case of a cross-site transition ( = true).
+ bool unload_ack_is_for_cross_site_transition_;
+
+ // Used to swap out or shut down this RFH when the unload event is taking too
+ // long to execute, depending on the number of active frames in the
+ // SiteInstance.
+ scoped_ptr<TimeoutMonitor> swapout_event_monitor_timeout_;
+
+ scoped_ptr<ServiceRegistryImpl> service_registry_;
+
+#if defined(OS_ANDROID)
+ scoped_ptr<ServiceRegistryAndroid> service_registry_android_;
+#endif
+
+ // The object managing the accessibility tree for this frame.
+ scoped_ptr<BrowserAccessibilityManager> browser_accessibility_manager_;
+
+ // This is nonzero if we sent an accessibility reset to the renderer and
+ // we're waiting for an IPC containing this reset token (sequentially
+ // assigned) and a complete replacement accessibility tree.
+ int accessibility_reset_token_;
+
+ // A count of the number of times we needed to reset accessibility, so
+ // we don't keep trying to reset forever.
+ int accessibility_reset_count_;
+
+ // Callback when an event is received, for testing.
+ base::Callback<void(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
+ // already exists it will still be used.
+ bool no_create_browser_accessibility_manager_for_testing_;
+
+ // PlzNavigate: Owns the stream used in navigations to store the body of the
+ // response once it has started.
+ scoped_ptr<StreamHandle> stream_handle_;
+
+ // NOTE: This must be the last member.
base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderFrameHostImpl);
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 fc36df203e8..49b9495e32d 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager.cc
+++ b/chromium/content/browser/frame_host/render_frame_host_manager.cc
@@ -27,6 +27,7 @@
#include "content/browser/site_instance_impl.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/browser/webui/web_ui_impl.h"
+#include "content/common/frame_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/notification_service.h"
@@ -36,29 +37,12 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/referrer.h"
#include "content/public/common/url_constants.h"
namespace content {
-RenderFrameHostManager::PendingNavigationParams::PendingNavigationParams(
- const GlobalRequestID& global_request_id,
- scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
- const std::vector<GURL>& transfer_url_chain,
- Referrer referrer,
- PageTransition page_transition,
- int render_frame_id,
- bool should_replace_current_entry)
- : global_request_id(global_request_id),
- cross_site_transferring_request(cross_site_transferring_request.Pass()),
- transfer_url_chain(transfer_url_chain),
- referrer(referrer),
- page_transition(page_transition),
- render_frame_id(render_frame_id),
- should_replace_current_entry(should_replace_current_entry) {
-}
-
-RenderFrameHostManager::PendingNavigationParams::~PendingNavigationParams() {}
-
+// static
bool RenderFrameHostManager::ClearRFHsPendingShutdown(FrameTreeNode* node) {
node->render_manager()->pending_delete_hosts_.clear();
return true;
@@ -152,9 +136,10 @@ RenderFrameProxyHost* RenderFrameHostManager::GetProxyToParent() {
return iter->second;
}
-void RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
+void RenderFrameHostManager::SetPendingWebUI(const GURL& url,
+ int bindings) {
pending_web_ui_.reset(
- delegate_->CreateWebUIForRenderManager(entry.GetURL()));
+ delegate_->CreateWebUIForRenderManager(url));
pending_and_current_web_ui_.reset();
// If we have assigned (zero or more) bindings to this NavigationEntry in the
@@ -162,8 +147,8 @@ void RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
// before. If so, note it and don't give it any bindings, to avoid a
// potential privilege escalation.
if (pending_web_ui_.get() &&
- entry.bindings() != NavigationEntryImpl::kInvalidBindings &&
- pending_web_ui_->GetBindings() != entry.bindings()) {
+ bindings != NavigationEntryImpl::kInvalidBindings &&
+ pending_web_ui_->GetBindings() != bindings) {
RecordAction(
base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
pending_web_ui_.reset();
@@ -172,9 +157,17 @@ void RenderFrameHostManager::SetPendingWebUI(const NavigationEntryImpl& entry) {
RenderFrameHostImpl* RenderFrameHostManager::Navigate(
const NavigationEntryImpl& entry) {
- TRACE_EVENT0("browser", "RenderFrameHostManager:Navigate");
+ TRACE_EVENT1("navigation", "RenderFrameHostManager:Navigate",
+ "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
// Create a pending RenderFrameHost to use for the navigation.
- RenderFrameHostImpl* dest_render_frame_host = UpdateStateForNavigate(entry);
+ RenderFrameHostImpl* dest_render_frame_host = UpdateStateForNavigate(
+ entry.GetURL(),
+ entry.site_instance(),
+ entry.GetTransitionType(),
+ entry.restore_type() != NavigationEntryImpl::RESTORE_NONE,
+ entry.IsViewSourceMode(),
+ entry.transferred_global_request_id(),
+ entry.bindings());
if (!dest_render_frame_host)
return NULL; // We weren't able to create a pending render frame host.
@@ -182,7 +175,7 @@ RenderFrameHostImpl* RenderFrameHostManager::Navigate(
// that we don't show a sad tab while the dest_render_frame_host fetches
// its first page. (Bug 1145340)
if (dest_render_frame_host != render_frame_host_ &&
- !render_frame_host_->render_view_host()->IsRenderViewLive()) {
+ !render_frame_host_->IsRenderFrameLive()) {
// Note: we don't call InitRenderView here because we are navigating away
// soon anyway, and we don't have the NavigationEntry for this host.
delegate_->CreateRenderViewForRenderManager(
@@ -192,7 +185,16 @@ RenderFrameHostImpl* RenderFrameHostManager::Navigate(
// If the renderer crashed, then try to create a new one to satisfy this
// navigation request.
- if (!dest_render_frame_host->render_view_host()->IsRenderViewLive()) {
+ if (!dest_render_frame_host->IsRenderFrameLive()) {
+ // Instruct the destination render frame host to set up a Mojo connection
+ // with the new render frame if necessary. Note that this call needs to
+ // occur before initializing the RenderView; the flow of creating the
+ // RenderView can cause browser-side code to execute that expects the this
+ // RFH's ServiceRegistry to be initialized (e.g., if the site is a WebUI
+ // site that is handled via Mojo, then Mojo WebUI code in //chrome will
+ // add a service to this RFH's ServiceRegistry).
+ dest_render_frame_host->SetUpMojoIfNeeded();
+
// Recreate the opener chain.
int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
dest_render_frame_host->GetSiteInstance());
@@ -208,35 +210,34 @@ RenderFrameHostImpl* RenderFrameHostManager::Navigate(
if (dest_render_frame_host != render_frame_host_ &&
dest_render_frame_host->render_view_host()->GetView()) {
dest_render_frame_host->render_view_host()->GetView()->Hide();
- } else if (frame_tree_node_->IsMainFrame()) {
- // This is our primary renderer, notify here as we won't be calling
- // CommitPending (which does the notify). We only do this for top-level
- // frames.
+ } else {
+ // Notify here as we won't be calling CommitPending (which does the
+ // notify).
delegate_->NotifySwappedFromRenderManager(
- NULL, render_frame_host_->render_view_host());
+ NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame());
}
}
// If entry includes the request ID of a request that is being transferred,
// the destination render frame will take ownership, so release ownership of
// the request.
- if (pending_nav_params_ &&
- pending_nav_params_->global_request_id ==
+ if (cross_site_transferring_request_.get() &&
+ cross_site_transferring_request_->request_id() ==
entry.transferred_global_request_id()) {
- pending_nav_params_->cross_site_transferring_request->ReleaseRequest();
+ cross_site_transferring_request_->ReleaseRequest();
}
return dest_render_frame_host;
}
void RenderFrameHostManager::Stop() {
- render_frame_host_->render_view_host()->Stop();
+ render_frame_host_->Stop();
// If we are cross-navigating, we should stop the pending renderers. This
// will lead to a DidFailProvisionalLoad, which will properly destroy them.
if (cross_navigation_pending_) {
- pending_render_frame_host_->render_view_host()->Send(new ViewMsg_Stop(
- pending_render_frame_host_->render_view_host()->GetRoutingID()));
+ pending_render_frame_host_->Send(new FrameMsg_Stop(
+ pending_render_frame_host_->GetRoutingID()));
}
}
@@ -247,34 +248,35 @@ void RenderFrameHostManager::SetIsLoading(bool is_loading) {
}
bool RenderFrameHostManager::ShouldCloseTabOnUnresponsiveRenderer() {
- if (!cross_navigation_pending_)
+ // If we're waiting for a close ACK, then the tab should close whether there's
+ // a navigation in progress or not. Unfortunately, we also need to check for
+ // cases that we arrive here with no navigation in progress, since there are
+ // some tab closure paths that don't set is_waiting_for_close_ack to true.
+ // TODO(creis): Clean this up in http://crbug.com/418266.
+ if (!cross_navigation_pending_ ||
+ render_frame_host_->render_view_host()->is_waiting_for_close_ack())
return true;
// We should always have a pending RFH when there's a cross-process navigation
// in progress. Sanity check this for http://crbug.com/276333.
CHECK(pending_render_frame_host_);
- // If the tab becomes unresponsive during {before}unload while doing a
+ // Unload handlers run in the background, so we should never get an
+ // unresponsiveness warning for them.
+ CHECK(!render_frame_host_->IsWaitingForUnloadACK());
+
+ // If the tab becomes unresponsive during beforeunload while doing a
// cross-site navigation, proceed with the navigation. (This assumes that
// the pending RenderFrameHost is still responsive.)
- if (render_frame_host_->render_view_host()->IsWaitingForUnloadACK()) {
- // The request has been started and paused while we're waiting for the
- // unload handler to finish. We'll pretend that it did. The pending
- // renderer will then be swapped in as part of the usual DidNavigate logic.
- // (If the unload handler later finishes, this call will be ignored because
- // the pending_nav_params_ state will already be cleaned up.)
- current_host()->OnSwappedOut(true);
- } else if (render_frame_host_->render_view_host()->
- is_waiting_for_beforeunload_ack()) {
+ if (render_frame_host_->is_waiting_for_beforeunload_ack()) {
// Haven't gotten around to starting the request, because we're still
// waiting for the beforeunload handler to finish. We'll pretend that it
// did finish, to let the navigation proceed. Note that there's a danger
// that the beforeunload handler will later finish and possibly return
// false (meaning the navigation should not proceed), but we'll ignore it
// in this case because it took too long.
- if (pending_render_frame_host_->render_view_host()->
- are_navigations_suspended()) {
- pending_render_frame_host_->render_view_host()->SetNavigationsSuspended(
+ if (pending_render_frame_host_->are_navigations_suspended()) {
+ pending_render_frame_host_->SetNavigationsSuspended(
false, base::TimeTicks::Now());
}
}
@@ -297,10 +299,9 @@ void RenderFrameHostManager::OnBeforeUnloadACK(
// already made by ShouldCloseTabOnUnresponsiveRenderer. In that case, it
// is ok to do nothing here.
if (pending_render_frame_host_ &&
- pending_render_frame_host_->render_view_host()->
- are_navigations_suspended()) {
- pending_render_frame_host_->render_view_host()->
- SetNavigationsSuspended(false, proceed_time);
+ pending_render_frame_host_->are_navigations_suspended()) {
+ pending_render_frame_host_->SetNavigationsSuspended(false,
+ proceed_time);
}
} else {
// Current page says to cancel.
@@ -334,87 +335,86 @@ void RenderFrameHostManager::OnCrossSiteResponse(
scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
const std::vector<GURL>& transfer_url_chain,
const Referrer& referrer,
- PageTransition page_transition,
+ ui::PageTransition page_transition,
bool should_replace_current_entry) {
- // This should be called either when the pending RFH is ready to commit or
- // when we realize that the current RFH's request requires a transfer.
+ // We should only get here for transfer navigations. Most cross-process
+ // navigations can just continue and wait to run the unload handler (by
+ // swapping out) when the new navigation commits.
+ CHECK(cross_site_transferring_request.get());
+
+ // A transfer should only have come from our pending or current RFH.
+ // 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_ ||
pending_render_frame_host == render_frame_host_);
- // TODO(creis): Eventually we will want to check all navigation responses
- // here, but currently we pass information for a transfer if
- // ShouldSwapProcessesForRedirect returned true in the network stack.
- // In that case, we should set up a transfer after the unload handler runs.
- // If |cross_site_transferring_request| is NULL, we will just run the unload
- // handler and resume.
- pending_nav_params_.reset(new PendingNavigationParams(
- global_request_id, cross_site_transferring_request.Pass(),
- transfer_url_chain, referrer, page_transition,
- pending_render_frame_host->GetRoutingID(),
- should_replace_current_entry));
-
- // Run the unload handler of the current page.
- SwapOutOldPage();
+ // Store the transferring request so that we can release it if the transfer
+ // navigation matches.
+ cross_site_transferring_request_ = cross_site_transferring_request.Pass();
+
+ // 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);
+
+ // Treat the last URL in the chain as the destination and the remainder as
+ // the redirect chain.
+ CHECK(transfer_url_chain.size());
+ GURL transfer_url = transfer_url_chain.back();
+ std::vector<GURL> rest_of_chain = transfer_url_chain;
+ rest_of_chain.pop_back();
+
+ // We don't know whether the original request had |user_action| set to true.
+ // However, since we force the navigation to be in the current tab, it
+ // doesn't matter.
+ pending_render_frame_host->frame_tree_node()->navigator()->RequestTransferURL(
+ pending_render_frame_host,
+ transfer_url,
+ rest_of_chain,
+ referrer,
+ page_transition,
+ CURRENT_TAB,
+ global_request_id,
+ should_replace_current_entry,
+ true);
+
+ // The transferring request was only needed during the RequestTransferURL
+ // call, so it is safe to clear at this point.
+ cross_site_transferring_request_.reset();
}
-void RenderFrameHostManager::SwappedOut(
- RenderFrameHostImpl* render_frame_host) {
- // Make sure this is from our current RFH, and that we have a pending
- // navigation from OnCrossSiteResponse. (There may be no pending navigation
- // for data URLs that don't make network requests, for example.) If not,
- // just return early and ignore.
- if (render_frame_host != render_frame_host_ || !pending_nav_params_.get()) {
- pending_nav_params_.reset();
- return;
- }
+void RenderFrameHostManager::OnDeferredAfterResponseStarted(
+ const GlobalRequestID& global_request_id,
+ RenderFrameHostImpl* pending_render_frame_host) {
+ DCHECK(!response_started_id_.get());
- // Now that the unload handler has run, we need to either initiate the
- // pending transfer (if there is one) or resume the paused response (if not).
- // TODO(creis): The blank swapped out page is visible during this time, but
- // we can shorten this by delivering the response directly, rather than
- // forcing an identical request to be made.
- if (pending_nav_params_->cross_site_transferring_request) {
- // 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_nav_params_->render_frame_id);
- int process_id = pending_render_frame_host_ ?
- pending_render_frame_host_->GetProcess()->GetID() :
- render_frame_host_->GetProcess()->GetID();
- DCHECK_EQ(process_id, pending_nav_params_->global_request_id.child_id);
-
- // Treat the last URL in the chain as the destination and the remainder as
- // the redirect chain.
- CHECK(pending_nav_params_->transfer_url_chain.size());
- GURL transfer_url = pending_nav_params_->transfer_url_chain.back();
- pending_nav_params_->transfer_url_chain.pop_back();
-
- // We don't know whether the original request had |user_action| set to true.
- // However, since we force the navigation to be in the current tab, it
- // doesn't matter.
- render_frame_host->frame_tree_node()->navigator()->RequestTransferURL(
- render_frame_host,
- transfer_url,
- pending_nav_params_->transfer_url_chain,
- pending_nav_params_->referrer,
- pending_nav_params_->page_transition,
- CURRENT_TAB,
- pending_nav_params_->global_request_id,
- pending_nav_params_->should_replace_current_entry,
- true);
- } else if (pending_render_frame_host_) {
- RenderProcessHostImpl* pending_process =
- static_cast<RenderProcessHostImpl*>(
- pending_render_frame_host_->GetProcess());
- pending_process->ResumeDeferredNavigation(
- pending_nav_params_->global_request_id);
- }
- pending_nav_params_.reset();
+ response_started_id_.reset(new GlobalRequestID(global_request_id));
+}
+
+void RenderFrameHostManager::ResumeResponseDeferredAtStart() {
+ DCHECK(response_started_id_.get());
+
+ RenderProcessHostImpl* process =
+ static_cast<RenderProcessHostImpl*>(render_frame_host_->GetProcess());
+ process->ResumeResponseDeferredAtStart(*response_started_id_);
+
+ render_frame_host_->ClearPendingTransitionRequestData();
+
+ response_started_id_.reset();
+}
+
+void RenderFrameHostManager::ClearNavigationTransitionData() {
+ render_frame_host_->ClearPendingTransitionRequestData();
}
void RenderFrameHostManager::DidNavigateFrame(
@@ -433,17 +433,6 @@ void RenderFrameHostManager::DidNavigateFrame(
if (render_frame_host == pending_render_frame_host_) {
// The pending cross-site navigation completed, so show the renderer.
- // If it committed without sending network requests (e.g., data URLs),
- // then we still need to swap out the old RFH first and run its unload
- // handler, only if it hasn't happened yet. OK for that to happen in the
- // background.
- if (pending_render_frame_host_->render_view_host()->
- HasPendingCrossSiteRequest() &&
- pending_render_frame_host_->render_view_host()->rvh_state() ==
- RenderViewHostImpl::STATE_DEFAULT) {
- SwapOutOldPage();
- }
-
CommitPending();
cross_navigation_pending_ = false;
} else if (render_frame_host == render_frame_host_) {
@@ -457,15 +446,24 @@ void RenderFrameHostManager::DidNavigateFrame(
}
}
-// TODO(creis): Take in RenderFrameHost instead, since frames can have openers.
-void RenderFrameHostManager::DidDisownOpener(RenderViewHost* render_view_host) {
- // Notify all swapped out hosts, including the pending RVH.
+void RenderFrameHostManager::DidDisownOpener(
+ RenderFrameHost* render_frame_host) {
+ // Notify all RenderFrameHosts but the one that notified us. This is necessary
+ // in case a process swap has occurred while the message was in flight.
for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
iter != proxy_hosts_.end();
++iter) {
DCHECK_NE(iter->second->GetSiteInstance(),
current_frame_host()->GetSiteInstance());
- iter->second->GetRenderViewHost()->DisownOpener();
+ iter->second->DisownOpener();
+ }
+
+ if (render_frame_host_.get() != render_frame_host)
+ render_frame_host_->DisownOpener();
+
+ if (pending_render_frame_host_ &&
+ pending_render_frame_host_.get() != render_frame_host) {
+ pending_render_frame_host_->DisownOpener();
}
}
@@ -490,64 +488,144 @@ void RenderFrameHostManager::RendererProcessClosing(
}
}
-void RenderFrameHostManager::SwapOutOldPage() {
- // Should only see this while we have a pending renderer or transfer.
- CHECK(cross_navigation_pending_ || pending_nav_params_.get());
+void RenderFrameHostManager::SwapOutOldFrame(
+ scoped_ptr<RenderFrameHostImpl> old_render_frame_host) {
+ TRACE_EVENT1("navigation", "RenderFrameHostManager::SwapOutOldFrame",
+ "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
// 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.
- render_frame_host_->render_view_host()->SuppressDialogsUntilSwapOut();
+ old_render_frame_host->render_view_host()->SuppressDialogsUntilSwapOut();
// Now close any modal dialogs that would prevent us from swapping out. This
// must be done separately from SwapOut, so that the PageGroupLoadDeferrer is
// no longer on the stack when we send the SwapOut message.
delegate_->CancelModalDialogsForRenderManager();
- // Create the RenderFrameProxyHost that will replace the
- // RenderFrameHost which is swapping out. If one exists, ensure it is deleted
- // from the map and not leaked.
- RenderFrameProxyHostMap::iterator iter = proxy_hosts_.find(
- render_frame_host_->GetSiteInstance()->GetId());
- if (iter != proxy_hosts_.end()) {
- delete iter->second;
- proxy_hosts_.erase(iter);
+ // If the old RFH is not live, just return as there is no further work to do.
+ // It will be deleted and there will be no proxy created.
+ int32 old_site_instance_id =
+ old_render_frame_host->GetSiteInstance()->GetId();
+ if (!old_render_frame_host->IsRenderFrameLive()) {
+ ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id);
+ return;
+ }
+
+ // If there are no active frames besides this one, we can delete the old
+ // RenderFrameHost once it runs its unload handler, without replacing it with
+ // a proxy.
+ size_t active_frame_count =
+ old_render_frame_host->GetSiteInstance()->active_frame_count();
+ if (active_frame_count <= 1) {
+ // Tell the old RenderFrameHost to swap out, with no proxy to replace it.
+ old_render_frame_host->SwapOut(NULL);
+ MoveToPendingDeleteHosts(old_render_frame_host.Pass());
+
+ // Also clear out any proxies from this SiteInstance, in case this was the
+ // last one keeping other proxies alive.
+ ShutdownRenderFrameProxyHostsInSiteInstance(old_site_instance_id);
+
+ return;
}
+ // Otherwise there are active views and we need a proxy for the old RFH.
+ // (There should not be one yet.)
+ CHECK(!GetRenderFrameProxyHost(old_render_frame_host->GetSiteInstance()));
RenderFrameProxyHost* proxy = new RenderFrameProxyHost(
- render_frame_host_->GetSiteInstance(), frame_tree_node_);
- proxy_hosts_[render_frame_host_->GetSiteInstance()->GetId()] = proxy;
-
- // Tell the old frame it is being swapped out. This will fire the unload
- // handler in the background (without firing the beforeunload handler a second
- // time). When the navigation completes, we will send a message to the
- // ResourceDispatcherHost, allowing the pending RVH's response to resume.
- render_frame_host_->SwapOut(proxy);
-
- // ResourceDispatcherHost has told us to run the onunload handler, which
- // means it is not a download or unsafe page, and we are going to perform the
- // navigation. Thus, we no longer need to remember that the RenderFrameHost
- // is part of a pending cross-site request.
- if (pending_render_frame_host_) {
- pending_render_frame_host_->render_view_host()->
- SetHasPendingCrossSiteRequest(false);
+ old_render_frame_host->GetSiteInstance(), frame_tree_node_);
+ CHECK(proxy_hosts_.insert(std::make_pair(old_site_instance_id, proxy)).second)
+ << "Inserting a duplicate item.";
+
+ // Tell the old RenderFrameHost to swap out and be replaced by the proxy.
+ old_render_frame_host->SwapOut(proxy);
+
+ bool is_main_frame = frame_tree_node_->IsMainFrame();
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
+ !is_main_frame) {
+ // In --site-per-process, subframes 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(old_render_frame_host.Pass());
+ } else {
+ // We shouldn't get here for subframes, since we only swap subframes when
+ // --site-per-process is used.
+ DCHECK(is_main_frame);
+
+ // The old RenderFrameHost will stay alive inside the proxy so that existing
+ // JavaScript window references to it stay valid.
+ proxy->TakeFrameHostOwnership(old_render_frame_host.Pass());
}
}
-void RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance(
- int32 site_instance_id,
- RenderFrameHostImpl* rfh) {
- RFHPendingDeleteMap::iterator iter =
- pending_delete_hosts_.find(site_instance_id);
- if (iter != pending_delete_hosts_.end() && iter->second.get() == rfh)
- pending_delete_hosts_.erase(site_instance_id);
+void RenderFrameHostManager::MoveToPendingDeleteHosts(
+ scoped_ptr<RenderFrameHostImpl> render_frame_host) {
+ // |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()));
+}
+
+bool RenderFrameHostManager::IsPendingDeletion(
+ RenderFrameHostImpl* render_frame_host) {
+ for (const auto& rfh : pending_delete_hosts_) {
+ if (rfh == render_frame_host)
+ return true;
+ }
+ return false;
+}
+
+bool RenderFrameHostManager::DeleteFromPendingList(
+ RenderFrameHostImpl* render_frame_host) {
+ for (RFHPendingDeleteList::iterator iter = pending_delete_hosts_.begin();
+ iter != pending_delete_hosts_.end();
+ iter++) {
+ if (*iter == render_frame_host) {
+ pending_delete_hosts_.erase(iter);
+ return true;
+ }
+ }
+ return false;
}
void RenderFrameHostManager::ResetProxyHosts() {
STLDeleteValues(&proxy_hosts_);
}
+// PlzNavigate
+RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
+ const GURL& url,
+ ui::PageTransition transition) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+ // TODO(clamy): When we handle renderer initiated navigations, make sure not
+ // to use a different process for subframes if --site-per-process is not
+ // enabled.
+
+ // Pick the right RenderFrameHost to commit the navigation.
+ // TODO(clamy): Replace the default values by the right ones.
+ RenderFrameHostImpl* render_frame_host = UpdateStateForNavigate(
+ url, NULL, transition, false, false, GlobalRequestID(),
+ NavigationEntryImpl::kInvalidBindings);
+
+ // If the renderer that needs to navigate is not live (it was just created or
+ // it crashed), initialize it.
+ if (!render_frame_host->render_view_host()->IsRenderViewLive()) {
+ // Recreate the opener chain.
+ int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
+ render_frame_host->GetSiteInstance());
+ if (!InitRenderView(render_frame_host->render_view_host(),
+ opener_route_id,
+ MSG_ROUTING_NONE,
+ frame_tree_node_->IsMainFrame())) {
+ return NULL;
+ }
+ }
+ return render_frame_host;
+}
+
void RenderFrameHostManager::Observe(
int type,
const NotificationSource& source,
@@ -564,6 +642,7 @@ void RenderFrameHostManager::Observe(
}
}
+// static
bool RenderFrameHostManager::ClearProxiesInSiteInstance(
int32 site_instance_id,
FrameTreeNode* node) {
@@ -571,26 +650,15 @@ bool RenderFrameHostManager::ClearProxiesInSiteInstance(
node->render_manager()->proxy_hosts_.find(site_instance_id);
if (iter != node->render_manager()->proxy_hosts_.end()) {
RenderFrameProxyHost* proxy = iter->second;
- // If the RVH is pending swap out, it needs to switch state to
- // pending shutdown. Otherwise it is deleted.
- if (proxy->GetRenderViewHost()->rvh_state() ==
- RenderViewHostImpl::STATE_PENDING_SWAP_OUT) {
+ // Delete the proxy. If it is for a main frame (and thus the RFH is stored
+ // in the proxy) and it was still pending swap out, move the RFH to the
+ // pending deletion list first.
+ if (node->IsMainFrame() &&
+ proxy->render_frame_host()->rfh_state() ==
+ RenderFrameHostImpl::STATE_PENDING_SWAP_OUT) {
scoped_ptr<RenderFrameHostImpl> swapped_out_rfh =
proxy->PassFrameHostOwnership();
-
- swapped_out_rfh->SetPendingShutdown(base::Bind(
- &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
- node->render_manager()->weak_factory_.GetWeakPtr(),
- site_instance_id,
- swapped_out_rfh.get()));
- RFHPendingDeleteMap::iterator pending_delete_iter =
- node->render_manager()->pending_delete_hosts_.find(site_instance_id);
- if (pending_delete_iter ==
- node->render_manager()->pending_delete_hosts_.end() ||
- pending_delete_iter->second.get() != swapped_out_rfh) {
- node->render_manager()->pending_delete_hosts_[site_instance_id] =
- linked_ptr<RenderFrameHostImpl>(swapped_out_rfh.release());
- }
+ node->render_manager()->MoveToPendingDeleteHosts(swapped_out_rfh.Pass());
}
delete proxy;
node->render_manager()->proxy_hosts_.erase(site_instance_id);
@@ -610,62 +678,55 @@ bool RenderFrameHostManager::ShouldTransitionCrossSite() {
}
bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
- const NavigationEntry* current_entry,
- const NavigationEntryImpl* new_entry) const {
- DCHECK(new_entry);
-
+ const GURL& current_effective_url,
+ bool current_is_view_source_mode,
+ SiteInstance* new_site_instance,
+ const GURL& new_effective_url,
+ bool new_is_view_source_mode) const {
// If new_entry already has a SiteInstance, assume it is correct. We only
// need to force a swap if it is in a different BrowsingInstance.
- if (new_entry->site_instance()) {
- return !new_entry->site_instance()->IsRelatedSiteInstance(
+ if (new_site_instance) {
+ return !new_site_instance->IsRelatedSiteInstance(
render_frame_host_->GetSiteInstance());
}
// Check for reasons to swap processes even if we are in a process model that
// doesn't usually swap (e.g., process-per-tab). Any time we return true,
// the new_entry will be rendered in a new SiteInstance AND BrowsingInstance.
-
- // We use the effective URL here, since that's what is used in the
- // SiteInstance's site and when we later call IsSameWebSite. If there is no
- // current_entry, check the current SiteInstance's site, which might already
- // be committed to a Web UI URL (such as the NTP).
BrowserContext* browser_context =
delegate_->GetControllerForRenderManager().GetBrowserContext();
- const GURL& current_url = (current_entry) ?
- SiteInstanceImpl::GetEffectiveURL(browser_context,
- current_entry->GetURL()) :
- render_frame_host_->GetSiteInstance()->GetSiteURL();
- const GURL& new_url = SiteInstanceImpl::GetEffectiveURL(browser_context,
- new_entry->GetURL());
// Don't force a new BrowsingInstance for debug URLs that are handled in the
// renderer process, like javascript: or chrome://crash.
- if (IsRendererDebugURL(new_url))
+ if (IsRendererDebugURL(new_effective_url))
return false;
// For security, we should transition between processes when one is a Web UI
// page and one isn't.
- if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
- browser_context, current_url)) {
+ if (ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
+ render_frame_host_->GetProcess()->GetID()) ||
+ WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
+ browser_context, current_effective_url)) {
// If so, force a swap if destination is not an acceptable URL for Web UI.
// Here, data URLs are never allowed.
if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
- browser_context, new_url)) {
+ browser_context, new_effective_url)) {
return true;
}
} else {
// Force a swap if it's a Web UI URL.
if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
- browser_context, new_url)) {
+ browser_context, new_effective_url)) {
return true;
}
}
- // Check with the content client as well. Important to pass current_url here,
- // which uses the SiteInstance's site if there is no current_entry.
+ // Check with the content client as well. Important to pass
+ // current_effective_url here, which uses the SiteInstance's site if there is
+ // no current_entry.
if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation(
render_frame_host_->GetSiteInstance(),
- current_url, new_url)) {
+ current_effective_url, new_effective_url)) {
return true;
}
@@ -673,8 +734,7 @@ bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
// without screwing up the session history sometimes (when navigating between
// "view-source:http://foo.com/" and "http://foo.com/", Blink doesn't treat
// it as a new navigation). So require a BrowsingInstance switch.
- if (current_entry &&
- current_entry->IsViewSourceMode() != new_entry->IsViewSourceMode())
+ if (current_is_view_source_mode != new_is_view_source_mode)
return true;
return false;
@@ -682,34 +742,90 @@ bool RenderFrameHostManager::ShouldSwapBrowsingInstancesForNavigation(
bool RenderFrameHostManager::ShouldReuseWebUI(
const NavigationEntry* current_entry,
- const NavigationEntryImpl* new_entry) const {
+ const GURL& new_url) const {
NavigationControllerImpl& controller =
delegate_->GetControllerForRenderManager();
return current_entry && web_ui_.get() &&
(WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
controller.GetBrowserContext(), current_entry->GetURL()) ==
WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
- controller.GetBrowserContext(), new_entry->GetURL()));
+ controller.GetBrowserContext(), new_url));
+}
+
+SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation(
+ const GURL& dest_url,
+ SiteInstance* dest_instance,
+ ui::PageTransition dest_transition,
+ bool dest_is_restore,
+ bool dest_is_view_source_mode) {
+ SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
+ SiteInstance* new_instance = current_instance;
+
+ // We do not currently swap processes for navigations in webview tag guests.
+ if (current_instance->GetSiteURL().SchemeIs(kGuestScheme))
+ return current_instance;
+
+ // Determine if we need a new BrowsingInstance for this entry. If true, this
+ // implies that it will get a new SiteInstance (and likely process), and that
+ // other tabs in the current BrowsingInstance will be unable to script it.
+ // This is used for cases that require a process swap even in the
+ // process-per-tab model, such as WebUI pages.
+ // TODO(clamy): Remove the dependency on the current entry.
+ const NavigationEntry* current_entry =
+ delegate_->GetLastCommittedNavigationEntryForRenderManager();
+ BrowserContext* browser_context =
+ delegate_->GetControllerForRenderManager().GetBrowserContext();
+ const GURL& current_effective_url = current_entry ?
+ SiteInstanceImpl::GetEffectiveURL(browser_context,
+ current_entry->GetURL()) :
+ render_frame_host_->GetSiteInstance()->GetSiteURL();
+ bool current_is_view_source_mode = current_entry ?
+ current_entry->IsViewSourceMode() : dest_is_view_source_mode;
+ bool force_swap = ShouldSwapBrowsingInstancesForNavigation(
+ current_effective_url,
+ current_is_view_source_mode,
+ dest_instance,
+ SiteInstanceImpl::GetEffectiveURL(browser_context, dest_url),
+ dest_is_view_source_mode);
+ if (ShouldTransitionCrossSite() || force_swap) {
+ new_instance = GetSiteInstanceForURL(
+ dest_url,
+ dest_instance,
+ dest_transition,
+ dest_is_restore,
+ dest_is_view_source_mode,
+ current_instance,
+ force_swap);
+ }
+
+ // If force_swap is true, we must use a different SiteInstance. 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;
}
-SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
- const NavigationEntryImpl& entry,
+SiteInstance* RenderFrameHostManager::GetSiteInstanceForURL(
+ const GURL& dest_url,
+ SiteInstance* dest_instance,
+ ui::PageTransition dest_transition,
+ bool dest_is_restore,
+ bool dest_is_view_source_mode,
SiteInstance* current_instance,
bool force_browsing_instance_swap) {
- // Determine which SiteInstance to use for navigating to |entry|.
- const GURL& dest_url = entry.GetURL();
NavigationControllerImpl& controller =
delegate_->GetControllerForRenderManager();
BrowserContext* browser_context = controller.GetBrowserContext();
// If the entry has an instance already we should use it.
- if (entry.site_instance()) {
+ if (dest_instance) {
// If we are forcing a swap, this should be in a different BrowsingInstance.
if (force_browsing_instance_swap) {
- CHECK(!entry.site_instance()->IsRelatedSiteInstance(
+ CHECK(!dest_instance->IsRelatedSiteInstance(
render_frame_host_->GetSiteInstance()));
}
- return entry.site_instance();
+ return dest_instance;
}
// If a swap is required, we need to force the SiteInstance AND
@@ -728,8 +844,8 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
// RenderViews in response to a link click.
//
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
- PageTransitionCoreTypeIs(entry.GetTransitionType(),
- PAGE_TRANSITION_GENERATED)) {
+ ui::PageTransitionCoreTypeIs(
+ dest_transition, ui::PAGE_TRANSITION_GENERATED)) {
return current_instance;
}
@@ -771,7 +887,7 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
// 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 (entry.IsViewSourceMode())
+ if (dest_is_view_source_mode)
return SiteInstance::CreateForURL(browser_context, dest_url);
// If we are navigating from a blank SiteInstance to a WebUI, make sure we
@@ -789,8 +905,16 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
// In the case of session restore, as it loads all the pages immediately
// we need to set the site first, otherwise after a restore none of the
// pages would share renderers in process-per-site.
- if (entry.restore_type() != NavigationEntryImpl::RESTORE_NONE)
+ //
+ // The embedder can request some urls never to be assigned to SiteInstance
+ // through the ShouldAssignSiteForURL() content client method, so that
+ // renderers created for particular chrome urls (e.g. the chrome-native://
+ // scheme) can be reused for subsequent navigations in the same WebContents.
+ // See http://crbug.com/386542.
+ if (dest_is_restore &&
+ GetContentClient()->browser()->ShouldAssignSiteForURL(dest_url)) {
current_site_instance->SetSite(dest_url);
+ }
return current_site_instance;
}
@@ -811,18 +935,6 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
// compare against the last non-interstitial entry.
current_entry = controller.GetEntryAtOffset(-1);
}
- // 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.)
- const GURL& current_url = (current_entry) ? current_entry->GetURL() :
- current_instance->GetSiteURL();
// View-source URLs must use a new SiteInstance and BrowsingInstance.
// We don't need a swap when going from view-source to a debug URL like
@@ -830,7 +942,7 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
// TODO(creis): Refactor this method so this duplicated code isn't needed.
// See http://crbug.com/123007.
if (current_entry &&
- current_entry->IsViewSourceMode() != entry.IsViewSourceMode() &&
+ current_entry->IsViewSourceMode() != dest_is_view_source_mode &&
!IsRendererDebugURL(dest_url)) {
return SiteInstance::CreateForURL(browser_context, dest_url);
}
@@ -838,6 +950,8 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
// 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, current_entry);
if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
!current_site_instance->HasWrongProcessForURL(dest_url)) {
return current_instance;
@@ -851,6 +965,63 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
return current_instance->GetRelatedSiteInstance(dest_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() &&
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
+ 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();
+}
+
+void RenderFrameHostManager::CreateRenderFrameHostForNewSiteInstance(
+ SiteInstance* old_instance,
+ SiteInstance* new_instance,
+ bool is_main_frame) {
+ // Ensure that we have created RFHs for the new RFH's opener chain if
+ // we are staying in the same BrowsingInstance. This allows the new RFH
+ // to send cross-process script calls to its opener(s).
+ int opener_route_id = MSG_ROUTING_NONE;
+ if (new_instance->IsRelatedSiteInstance(old_instance)) {
+ opener_route_id =
+ delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ // Ensure that the frame tree has RenderFrameProxyHosts for the new
+ // SiteInstance in all nodes except the current one.
+ frame_tree_node_->frame_tree()->CreateProxiesForSiteInstance(
+ frame_tree_node_, new_instance);
+ }
+ }
+
+ // Create a non-swapped-out RFH with the given opener.
+ int route_id = CreateRenderFrame(
+ new_instance, opener_route_id, false, is_main_frame,
+ delegate_->IsHidden());
+ if (route_id == MSG_ROUTING_NONE) {
+ pending_render_frame_host_.reset();
+ return;
+ }
+}
+
scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
SiteInstance* site_instance,
int view_routing_id,
@@ -864,20 +1035,12 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
FrameTree* frame_tree = frame_tree_node_->frame_tree();
RenderViewHostImpl* render_view_host = NULL;
if (frame_tree_node_->IsMainFrame()) {
- render_view_host = frame_tree->CreateRenderViewHostForMainFrame(
+ render_view_host = frame_tree->CreateRenderViewHost(
site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
} else {
- render_view_host = frame_tree->GetRenderViewHostForSubFrame(site_instance);
-
- // If we haven't found a RVH for a subframe RFH, it's because we currently
- // do not create top-level RFHs for pending subframe navigations. Create
- // the RVH here for now.
- // TODO(creis): Mirror the frame tree so this check isn't necessary.
- if (!render_view_host) {
- render_view_host = frame_tree->CreateRenderViewHostForMainFrame(
- site_instance, view_routing_id, frame_routing_id, swapped_out,
- hidden);
- }
+ render_view_host = frame_tree->GetRenderViewHost(site_instance);
+
+ CHECK(render_view_host);
}
// TODO(creis): Pass hidden to RFH.
@@ -891,14 +1054,20 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
return render_frame_host.Pass();
}
-int RenderFrameHostManager::CreateRenderFrame(
- SiteInstance* instance,
- int opener_route_id,
- bool swapped_out,
- bool hidden) {
+int RenderFrameHostManager::CreateRenderFrame(SiteInstance* instance,
+ int opener_route_id,
+ bool swapped_out,
+ bool for_main_frame_navigation,
+ bool hidden) {
CHECK(instance);
DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
+ // TODO(nasko): Remove the following CHECK once cross-site navigation no
+ // longer relies on swapped out RFH for the top-level frame.
+ if (!frame_tree_node_->IsMainFrame()) {
+ CHECK(!swapped_out);
+ }
+
scoped_ptr<RenderFrameHostImpl> new_render_frame_host;
RenderFrameHostImpl* frame_to_announce = NULL;
int routing_id = MSG_ROUTING_NONE;
@@ -909,10 +1078,10 @@ int RenderFrameHostManager::CreateRenderFrame(
// 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 swapped out hosts if it commits.
+ // remove it from the list of proxy hosts below if it will be active.
RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
- if (proxy) {
+ if (proxy && proxy->render_frame_host()) {
routing_id = proxy->GetRenderViewHost()->GetRoutingID();
// Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost.
// Prevent the process from exiting while we're trying to use it.
@@ -953,16 +1122,24 @@ int RenderFrameHostManager::CreateRenderFrame(
proxy = new RenderFrameProxyHost(
new_render_frame_host->GetSiteInstance(), frame_tree_node_);
proxy_hosts_[instance->GetId()] = proxy;
- proxy->TakeFrameHostOwnership(new_render_frame_host.Pass());
proxy_routing_id = proxy->GetRoutingID();
+ if (frame_tree_node_->IsMainFrame())
+ proxy->TakeFrameHostOwnership(new_render_frame_host.Pass());
}
- bool success = InitRenderView(
- render_view_host, opener_route_id, proxy_routing_id,
- frame_tree_node_->IsMainFrame());
- if (success && frame_tree_node_->IsMainFrame()) {
- // Don't show the main frame's view until we get a DidNavigate from it.
- render_view_host->GetView()->Hide();
+ bool success = InitRenderView(render_view_host,
+ opener_route_id,
+ proxy_routing_id,
+ for_main_frame_navigation);
+ if (success) {
+ if (frame_tree_node_->IsMainFrame()) {
+ // Don't show the main frame's view until we get a DidNavigate from it.
+ render_view_host->GetView()->Hide();
+ } else if (!swapped_out) {
+ // Init the RFH, so a RenderFrame is created in the renderer.
+ DCHECK(new_render_frame_host.get());
+ success = InitRenderFrame(new_render_frame_host.get());
+ }
} else if (!swapped_out && pending_render_frame_host_) {
CancelPending();
}
@@ -981,10 +1158,27 @@ int RenderFrameHostManager::CreateRenderFrame(
return routing_id;
}
-bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host,
- int opener_route_id,
- int proxy_routing_id,
- bool for_main_frame) {
+int RenderFrameHostManager::CreateRenderFrameProxy(SiteInstance* instance) {
+ // A RenderFrameProxyHost should never be created in the same SiteInstance as
+ // the current RFH.
+ CHECK(instance);
+ CHECK_NE(instance, render_frame_host_->GetSiteInstance());
+
+ RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
+ if (proxy)
+ return proxy->GetRoutingID();
+
+ proxy = new RenderFrameProxyHost(instance, frame_tree_node_);
+ proxy_hosts_[instance->GetId()] = proxy;
+ proxy->InitRenderFrameProxy();
+ return proxy->GetRoutingID();
+}
+
+bool RenderFrameHostManager::InitRenderView(
+ RenderViewHostImpl* render_view_host,
+ int opener_route_id,
+ int proxy_routing_id,
+ bool for_main_frame_navigation) {
// We may have initialized this RenderViewHost for another RenderFrameHost.
if (render_view_host->IsRenderViewLive())
return true;
@@ -997,32 +1191,70 @@ bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host,
} else {
// Ensure that we don't create an unprivileged RenderView in a WebUI-enabled
// process unless it's swapped out.
- RenderViewHostImpl* rvh_impl =
- static_cast<RenderViewHostImpl*>(render_view_host);
- if (!rvh_impl->IsSwappedOut()) {
+ if (render_view_host->is_active()) {
CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
render_view_host->GetProcess()->GetID()));
}
}
- return delegate_->CreateRenderViewForRenderManager(
- render_view_host, opener_route_id, proxy_routing_id, for_main_frame);
+ return delegate_->CreateRenderViewForRenderManager(render_view_host,
+ opener_route_id,
+ proxy_routing_id,
+ for_main_frame_navigation);
+}
+
+bool RenderFrameHostManager::InitRenderFrame(
+ RenderFrameHostImpl* render_frame_host) {
+ if (render_frame_host->IsRenderFrameLive())
+ return true;
+
+ int parent_routing_id = MSG_ROUTING_NONE;
+ int proxy_routing_id = MSG_ROUTING_NONE;
+ if (frame_tree_node_->parent()) {
+ parent_routing_id = frame_tree_node_->parent()->render_manager()->
+ GetRoutingIdForSiteInstance(render_frame_host->GetSiteInstance());
+ CHECK_NE(parent_routing_id, MSG_ROUTING_NONE);
+ }
+ // Check whether there is an existing proxy for this frame in this
+ // SiteInstance. If there is, the new RenderFrame needs to be able to find
+ // the proxy it is replacing, so that it can fully initialize itself.
+ // NOTE: This is the only time that a RenderFrameProxyHost can be in the same
+ // SiteInstance as its RenderFrameHost. This is only the case until the
+ // RenderFrameHost commits, at which point it will replace and delete the
+ // RenderFrameProxyHost.
+ RenderFrameProxyHost* existing_proxy =
+ GetRenderFrameProxyHost(render_frame_host->GetSiteInstance());
+ if (existing_proxy) {
+ proxy_routing_id = existing_proxy->GetRoutingID();
+ CHECK_NE(proxy_routing_id, MSG_ROUTING_NONE);
+ }
+ return delegate_->CreateRenderFrameForRenderManager(render_frame_host,
+ parent_routing_id,
+ proxy_routing_id);
+}
+
+int RenderFrameHostManager::GetRoutingIdForSiteInstance(
+ SiteInstance* site_instance) {
+ if (render_frame_host_->GetSiteInstance() == site_instance)
+ return render_frame_host_->GetRoutingID();
+
+ RenderFrameProxyHostMap::iterator iter =
+ proxy_hosts_.find(site_instance->GetId());
+ if (iter != proxy_hosts_.end())
+ return iter->second->GetRoutingID();
+
+ return MSG_ROUTING_NONE;
}
void RenderFrameHostManager::CommitPending() {
+ TRACE_EVENT1("navigation", "RenderFrameHostManager::CommitPending",
+ "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
// First check whether we're going to want to focus the location bar after
// this commit. We do this now because the navigation hasn't formally
// committed yet, so if we've already cleared |pending_web_ui_| the call chain
// this triggers won't be able to figure out what's going on.
bool will_focus_location_bar = delegate_->FocusLocationBarByDefault();
- // We expect SwapOutOldPage to have canceled any modal dialogs and told the
- // renderer to suppress any further dialogs until it is swapped out. However,
- // crash reports indicate that it's still possible for modal dialogs to exist
- // at this point, which poses a risk if we delete their RenderViewHost below.
- // Cancel them again to be safe. http://crbug.com/324320.
- delegate_->CancelModalDialogsForRenderManager();
-
// Next commit the Web UI, if any. Either replace |web_ui_| with
// |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or
// leave |web_ui_| as is if reusing it.
@@ -1051,8 +1283,6 @@ void RenderFrameHostManager::CommitPending() {
render_frame_host_->render_view_host()->GetView() &&
render_frame_host_->render_view_host()->GetView()->HasFocus();
- // TODO(creis): As long as show/hide are on RVH, we don't want to do them for
- // subframe navigations or they'll interfere with the top-level page.
bool is_main_frame = frame_tree_node_->IsMainFrame();
// Swap in the pending frame and make it active. Also ensure the FrameTree
@@ -1065,33 +1295,27 @@ void RenderFrameHostManager::CommitPending() {
// The process will no longer try to exit, so we can decrement the count.
render_frame_host_->GetProcess()->RemovePendingView();
- // If the view is gone, then this RenderViewHost died while it was hidden.
- // We ignored the RenderProcessGone call at the time, so we should send it now
- // to make sure the sad tab shows up, etc.
- if (!render_frame_host_->render_view_host()->GetView()) {
+ // Show the new view (or a sad tab) if necessary.
+ bool new_rfh_has_view = !!render_frame_host_->render_view_host()->GetView();
+ if (!delegate_->IsHidden() && new_rfh_has_view) {
+ // In most cases, we need to show the new view.
+ render_frame_host_->render_view_host()->GetView()->Show();
+ }
+ if (!new_rfh_has_view) {
+ // If the view is gone, then this RenderViewHost died while it was hidden.
+ // We ignored the RenderProcessGone call at the time, so we should send it
+ // now to make sure the sad tab shows up, etc.
+ DCHECK(!render_frame_host_->IsRenderFrameLive());
+ DCHECK(!render_frame_host_->render_view_host()->IsRenderViewLive());
delegate_->RenderProcessGoneFromRenderManager(
render_frame_host_->render_view_host());
- } else if (!delegate_->IsHidden()) {
- render_frame_host_->render_view_host()->GetView()->Show();
}
- // If the old view is live and top-level, hide it now that the new one is
- // visible.
- int32 old_site_instance_id =
- old_render_frame_host->GetSiteInstance()->GetId();
- if (old_render_frame_host->render_view_host()->GetView()) {
- if (is_main_frame) {
- old_render_frame_host->render_view_host()->GetView()->Hide();
- old_render_frame_host->render_view_host()->WasSwappedOut(base::Bind(
- &RenderFrameHostManager::ClearPendingShutdownRFHForSiteInstance,
- weak_factory_.GetWeakPtr(),
- old_site_instance_id,
- old_render_frame_host.get()));
- } else {
- // TODO(creis): We'll need to set this back to false if we navigate back.
- old_render_frame_host->set_swapped_out(true);
- }
- }
+ // For top-level frames, also hide the old RenderViewHost's view.
+ // TODO(creis): As long as show/hide are on RVH, we don't want to hide on
+ // subframe navigations or we will interfere with the top-level frame.
+ if (is_main_frame && old_render_frame_host->render_view_host()->GetView())
+ old_render_frame_host->render_view_host()->GetView()->Hide();
// Make sure the size is up to date. (Fix for bug 1079768.)
delegate_->UpdateRenderViewSizeForRenderManager();
@@ -1105,82 +1329,47 @@ void RenderFrameHostManager::CommitPending() {
// Notify that we've swapped RenderFrameHosts. We do this before shutting down
// the RFH so that we can clean up RendererResources related to the RFH first.
- // TODO(creis): Only do this on top-level RFHs for now, and later update it to
- // pass the RFHs.
- if (is_main_frame) {
- delegate_->NotifySwappedFromRenderManager(
- old_render_frame_host->render_view_host(),
- render_frame_host_->render_view_host());
- }
-
- // If the old RFH is not live, just return as there is no work to do.
- if (!old_render_frame_host->render_view_host()->IsRenderViewLive()) {
- return;
- }
+ delegate_->NotifySwappedFromRenderManager(
+ old_render_frame_host.get(), render_frame_host_.get(), is_main_frame);
+
+ // 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 RHFs are not kept alive inside
+ // the proxy.
+ SwapOutOldFrame(old_render_frame_host.Pass());
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
+ !is_main_frame) {
+ // 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
+ // belongs to the parent frame's SiteInstance.
+ // Note: We do this after swapping out the old RFH because that may create
+ // the proxy we're looking for.
+ RenderFrameProxyHost* proxy_to_parent = GetProxyToParent();
+ if (proxy_to_parent) {
+ proxy_to_parent->SetChildRWHView(
+ render_frame_host_->render_view_host()->GetView());
+ }
- // If the old RFH is live, we are swapping it out and should keep track of
- // it in case we navigate back to it, or it is waiting for the unload event
- // to execute in the background.
- // TODO(creis): Swap out the subframe in --site-per-process.
- if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
- DCHECK(old_render_frame_host->is_swapped_out() ||
- !RenderViewHostImpl::IsRVHStateActive(
- old_render_frame_host->render_view_host()->rvh_state()));
-
- // If the RenderViewHost backing the RenderFrameHost is pending shutdown,
- // the RenderFrameHost should be put in the map of RenderFrameHosts pending
- // shutdown. Otherwise, it is stored in the map of proxy hosts.
- if (old_render_frame_host->render_view_host()->rvh_state() ==
- RenderViewHostImpl::STATE_PENDING_SHUTDOWN) {
- // The proxy for this RenderFrameHost is created when sending the
- // SwapOut message, so check if it already exists and delete it.
+ // Since the new RenderFrameHost is now committed, there must be no proxies
+ // for its SiteInstance. Delete any existing ones.
RenderFrameProxyHostMap::iterator iter =
- proxy_hosts_.find(old_site_instance_id);
+ proxy_hosts_.find(render_frame_host_->GetSiteInstance()->GetId());
if (iter != proxy_hosts_.end()) {
delete iter->second;
proxy_hosts_.erase(iter);
}
- RFHPendingDeleteMap::iterator pending_delete_iter =
- pending_delete_hosts_.find(old_site_instance_id);
- if (pending_delete_iter == pending_delete_hosts_.end() ||
- pending_delete_iter->second.get() != old_render_frame_host) {
- pending_delete_hosts_[old_site_instance_id] =
- linked_ptr<RenderFrameHostImpl>(old_render_frame_host.release());
- }
- } else {
- // Capture the active view count on the old RFH SiteInstance, since the
- // ownership will be passed into the proxy and the pointer will be invalid.
- int active_view_count =
- static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance())
- ->active_view_count();
-
- RenderFrameProxyHostMap::iterator iter =
- proxy_hosts_.find(old_site_instance_id);
- CHECK(iter != proxy_hosts_.end());
- iter->second->TakeFrameHostOwnership(old_render_frame_host.Pass());
-
- // If there are no active views in this SiteInstance, it means that
- // this RFH was the last active one in the SiteInstance. Now that we
- // know that all RFHs are swapped out, we can delete all the RFHs and RVHs
- // in this SiteInstance.
- if (!active_view_count) {
- ShutdownRenderFrameHostsInSiteInstance(old_site_instance_id);
- } else {
- // If this is a subframe, it should have a CrossProcessFrameConnector
- // created already and we just need to link it to the proper view in the
- // new process.
- if (!is_main_frame) {
- RenderFrameProxyHost* proxy = GetProxyToParent();
- if (proxy) {
- proxy->SetChildRWHView(
- render_frame_host_->render_view_host()->GetView());
- }
- }
- }
}
+
+ // After all is done, there must never be a proxy in the list which has the
+ // same SiteInstance as the current RenderFrameHost.
+ CHECK(proxy_hosts_.find(render_frame_host_->GetSiteInstance()->GetId()) ==
+ proxy_hosts_.end());
}
-void RenderFrameHostManager::ShutdownRenderFrameHostsInSiteInstance(
+void RenderFrameHostManager::ShutdownRenderFrameProxyHostsInSiteInstance(
int32 site_instance_id) {
// First remove any swapped out RFH for this SiteInstance from our own list.
ClearProxiesInSiteInstance(site_instance_id, frame_tree_node_);
@@ -1209,7 +1398,13 @@ void RenderFrameHostManager::ShutdownRenderFrameHostsInSiteInstance(
}
RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
- const NavigationEntryImpl& entry) {
+ const GURL& url,
+ SiteInstance* instance,
+ ui::PageTransition transition,
+ bool is_restore,
+ bool is_view_source_mode,
+ const GlobalRequestID& transferred_request_id,
+ int bindings) {
// If we are currently navigating cross-process, we want to get back to normal
// and then navigate as usual.
if (cross_navigation_pending_) {
@@ -1218,34 +1413,21 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
cross_navigation_pending_ = false;
}
- // render_frame_host_'s SiteInstance and new_instance will not be deleted
- // before the end of this method, so we don't have to worry about their ref
- // counts dropping to zero.
SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
- SiteInstance* new_instance = current_instance;
+ scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation(
+ url, instance, transition, is_restore, is_view_source_mode);
- // We do not currently swap processes for navigations in webview tag guests.
- bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme);
-
- // Determine if we need a new BrowsingInstance for this entry. If true, this
- // implies that it will get a new SiteInstance (and likely process), and that
- // other tabs in the current BrowsingInstance will be unable to script it.
- // This is used for cases that require a process swap even in the
- // process-per-tab model, such as WebUI pages.
const NavigationEntry* current_entry =
delegate_->GetLastCommittedNavigationEntryForRenderManager();
- bool force_swap = !is_guest_scheme &&
- ShouldSwapBrowsingInstancesForNavigation(current_entry, &entry);
- if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
- new_instance = GetSiteInstanceForEntry(entry, current_instance, force_swap);
- // If force_swap is true, we must use a different SiteInstance. 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);
+ if (new_instance.get() != current_instance) {
+ TRACE_EVENT_INSTANT2(
+ "navigation",
+ "RenderFrameHostManager::UpdateStateForNavigate:New SiteInstance",
+ TRACE_EVENT_SCOPE_THREAD,
+ "current_instance id", current_instance->GetId(),
+ "new_instance id", new_instance->GetId());
- if (new_instance != current_instance) {
// New SiteInstance: create a pending RFH to navigate.
DCHECK(!cross_navigation_pending_);
@@ -1255,26 +1437,15 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
// It must also happen after the above conditional call to CancelPending(),
// otherwise CancelPending may clear the pending_web_ui_ and the page will
// not have its bindings set appropriately.
- SetPendingWebUI(entry);
-
- // Ensure that we have created RFHs for the new RFH's opener chain if
- // we are staying in the same BrowsingInstance. This allows the pending RFH
- // to send cross-process script calls to its opener(s).
- int opener_route_id = MSG_ROUTING_NONE;
- if (new_instance->IsRelatedSiteInstance(current_instance)) {
- opener_route_id =
- delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
- }
-
- // Create a non-swapped-out pending RFH with the given opener and navigate
- // it.
- int route_id = CreateRenderFrame(new_instance, opener_route_id, false,
- delegate_->IsHidden());
- if (route_id == MSG_ROUTING_NONE)
+ SetPendingWebUI(url, bindings);
+ CreateRenderFrameHostForNewSiteInstance(
+ current_instance, new_instance.get(), frame_tree_node_->IsMainFrame());
+ if (!pending_render_frame_host_.get()) {
return NULL;
+ }
// Check if our current RFH is live before we set up a transition.
- if (!render_frame_host_->render_view_host()->IsRenderViewLive()) {
+ if (!render_frame_host_->IsRenderFrameLive()) {
if (!cross_navigation_pending_) {
// The current RFH is not live. There's no reason to sit around with a
// sad tab or a newly created RFH while we wait for the pending RFH to
@@ -1290,61 +1461,65 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
}
// Otherwise, it's safe to treat this as a pending cross-site transition.
+ // We now have a pending RFH.
+ DCHECK(!cross_navigation_pending_);
+ cross_navigation_pending_ = true;
+
+ // PlzNavigate: There is no notion of transfer navigations, and the old
+ // renderer before unload handler has already run at that point, so return
+ // here.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ return pending_render_frame_host_.get();
+ }
+
// We need to wait until the beforeunload handler has run, unless we are
// transferring an existing request (in which case it has already run).
// Suspend the new render view (i.e., don't let it send the cross-site
// Navigate message) until we hear back from the old renderer's
// beforeunload handler. If the handler returns false, we'll have to
// cancel the request.
- DCHECK(!pending_render_frame_host_->render_view_host()->
- are_navigations_suspended());
- bool is_transfer =
- entry.transferred_global_request_id() != GlobalRequestID();
+ //
+ DCHECK(!pending_render_frame_host_->are_navigations_suspended());
+ bool is_transfer = transferred_request_id != GlobalRequestID();
if (is_transfer) {
// We don't need to stop the old renderer or run beforeunload/unload
// handlers, because those have already been done.
- DCHECK(pending_nav_params_->global_request_id ==
- entry.transferred_global_request_id());
+ DCHECK(cross_site_transferring_request_->request_id() ==
+ transferred_request_id);
} else {
// Also make sure the old render view stops, in case a load is in
// progress. (We don't want to do this for transfers, since it will
// interrupt the transfer with an unexpected DidStopLoading.)
- render_frame_host_->render_view_host()->Send(new ViewMsg_Stop(
- render_frame_host_->render_view_host()->GetRoutingID()));
-
- pending_render_frame_host_->render_view_host()->SetNavigationsSuspended(
- true, base::TimeTicks());
-
- // Tell the CrossSiteRequestManager that this RVH has a pending cross-site
- // request, so that ResourceDispatcherHost will know to tell us to run the
- // old page's unload handler before it sends the response.
- // TODO(creis): This needs to be on the RFH.
- pending_render_frame_host_->render_view_host()->
- SetHasPendingCrossSiteRequest(true);
- }
-
- // We now have a pending RFH.
- DCHECK(!cross_navigation_pending_);
- cross_navigation_pending_ = true;
-
- // Unless we are transferring an existing request, we should now
- // tell the old render view to run its beforeunload handler, since it
- // doesn't otherwise know that the cross-site request is happening. This
- // will trigger a call to OnBeforeUnloadACK with the reply.
- if (!is_transfer)
+ render_frame_host_->Send(new FrameMsg_Stop(
+ render_frame_host_->GetRoutingID()));
+ pending_render_frame_host_->SetNavigationsSuspended(true,
+ base::TimeTicks());
+ // Unless we are transferring an existing request, we should now tell the
+ // old render view to run its beforeunload handler, since it doesn't
+ // otherwise know that the cross-site request is happening. This will
+ // trigger a call to OnBeforeUnloadACK with the reply.
render_frame_host_->DispatchBeforeUnload(true);
+ }
return pending_render_frame_host_.get();
}
// Otherwise the same SiteInstance can be used. Navigate render_frame_host_.
DCHECK(!cross_navigation_pending_);
- if (ShouldReuseWebUI(current_entry, &entry)) {
+
+ // It's possible to swap out the current RFH and then decide to navigate in it
+ // anyway (e.g., a cross-process navigation that redirects back to the
+ // original site). In that case, we have a proxy for the current RFH but
+ // haven't deleted it yet. The new navigation will swap it back in, so we can
+ // delete the proxy.
+ DeleteRenderFrameProxyHost(new_instance.get());
+
+ if (ShouldReuseWebUI(current_entry, url)) {
pending_web_ui_.reset();
pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
} else {
- SetPendingWebUI(entry);
-
+ SetPendingWebUI(url, bindings);
// Make sure the new RenderViewHost has the right bindings.
if (pending_web_ui() &&
!render_frame_host_->GetProcess()->IsIsolatedGuest()) {
@@ -1353,15 +1528,14 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
}
}
- if (pending_web_ui() &&
- render_frame_host_->render_view_host()->IsRenderViewLive()) {
+ if (pending_web_ui() && render_frame_host_->IsRenderFrameLive()) {
pending_web_ui()->GetController()->RenderViewReused(
render_frame_host_->render_view_host());
}
// The renderer can exit view source mode when any error or cancellation
// happen. We must overwrite to recover the mode.
- if (entry.IsViewSourceMode()) {
+ if (is_view_source_mode) {
render_frame_host_->render_view_host()->Send(
new ViewMsg_EnableViewSourceMode(
render_frame_host_->render_view_host()->GetRoutingID()));
@@ -1371,6 +1545,8 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
}
void RenderFrameHostManager::CancelPending() {
+ TRACE_EVENT1("navigation", "RenderFrameHostManager::CancelPending",
+ "FrameTreeNode id", frame_tree_node_->frame_tree_node_id());
scoped_ptr<RenderFrameHostImpl> pending_render_frame_host =
pending_render_frame_host_.Pass();
@@ -1383,17 +1559,18 @@ void RenderFrameHostManager::CancelPending() {
// If the SiteInstance for the pending RFH is being used by others, don't
// delete the RFH, just swap it out and it can be reused at a later point.
- SiteInstanceImpl* site_instance = static_cast<SiteInstanceImpl*>(
- pending_render_frame_host->GetSiteInstance());
- if (site_instance->active_view_count() > 1) {
+ SiteInstanceImpl* site_instance =
+ pending_render_frame_host->GetSiteInstance();
+ if (site_instance->active_frame_count() > 1) {
// Any currently suspended navigations are no longer needed.
- pending_render_frame_host->render_view_host()->CancelSuspendedNavigations();
+ pending_render_frame_host->CancelSuspendedNavigations();
RenderFrameProxyHost* proxy =
new RenderFrameProxyHost(site_instance, frame_tree_node_);
proxy_hosts_[site_instance->GetId()] = proxy;
pending_render_frame_host->SwapOut(proxy);
- proxy->TakeFrameHostOwnership(pending_render_frame_host.Pass());
+ if (frame_tree_node_->IsMainFrame())
+ proxy->TakeFrameHostOwnership(pending_render_frame_host.Pass());
} else {
// We won't be coming back, so delete this one.
pending_render_frame_host.reset();
@@ -1416,11 +1593,11 @@ scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::SetRenderFrameHost(
// count top-level ones. This makes the value easier for consumers to
// interpret.
if (render_frame_host_) {
- static_cast<SiteInstanceImpl*>(render_frame_host_->GetSiteInstance())->
+ render_frame_host_->GetSiteInstance()->
IncrementRelatedActiveContentsCount();
}
if (old_render_frame_host) {
- static_cast<SiteInstanceImpl*>(old_render_frame_host->GetSiteInstance())->
+ old_render_frame_host->GetSiteInstance()->
DecrementRelatedActiveContentsCount();
}
}
@@ -1434,6 +1611,10 @@ bool RenderFrameHostManager::IsRVHOnSwappedOutList(
rvh->GetSiteInstance());
if (!proxy)
return false;
+ // If there is a proxy without RFH, it is for a subframe in the SiteInstance
+ // of |rvh|. Subframes should be ignored in this case.
+ if (!proxy->render_frame_host())
+ return false;
return IsOnSwappedOutList(proxy->render_frame_host());
}
@@ -1468,4 +1649,13 @@ RenderFrameProxyHost* RenderFrameHostManager::GetRenderFrameProxyHost(
return NULL;
}
+void RenderFrameHostManager::DeleteRenderFrameProxyHost(
+ SiteInstance* instance) {
+ RenderFrameProxyHostMap::iterator iter = proxy_hosts_.find(instance->GetId());
+ if (iter != proxy_hosts_.end()) {
+ delete iter->second;
+ proxy_hosts_.erase(iter);
+ }
+}
+
} // 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 35abab1668d..7394628bcbf 100644
--- a/chromium/content/browser/frame_host/render_frame_host_manager.h
+++ b/chromium/content/browser/frame_host/render_frame_host_manager.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_MANAGER_H_
#define CONTENT_BROWSER_FRAME_HOST_RENDER_FRAME_HOST_MANAGER_H_
+#include <list>
+
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -16,7 +18,9 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/common/referrer.h"
+#include "ui/base/page_transition_types.h"
+struct FrameMsg_Navigate_Params;
namespace content {
class BrowserContext;
@@ -27,7 +31,9 @@ class FrameTreeNode;
class NavigationControllerImpl;
class NavigationEntry;
class NavigationEntryImpl;
+class RenderFrameHost;
class RenderFrameHostDelegate;
+class RenderFrameHost;
class RenderFrameHostImpl;
class RenderFrameHostManagerTest;
class RenderFrameProxyHost;
@@ -38,8 +44,53 @@ class RenderWidgetHostView;
class TestWebContents;
class WebUIImpl;
-// Manages RenderFrameHosts for a FrameTreeNode. This class acts as a state
-// machine to make cross-process navigations in a frame possible.
+// Manages RenderFrameHosts for a FrameTreeNode. It maintains a
+// current_frame_host() which is the content currently visible to the user. When
+// a frame is told to navigate to a different web site (as determined by
+// SiteInstance), it will replace its current RenderFrameHost with a new
+// RenderFrameHost dedicated to the new SiteInstance, possibly in a new process.
+//
+// Cross-process navigation works like this:
+//
+// - RFHM::Navigate determines whether the destination is cross-site, and if so,
+// it creates a pending_render_frame_host_.
+//
+// - The pending RFH is created in the "navigations suspended" state, meaning no
+// navigation messages are sent to its renderer until the beforeunload handler
+// has a chance to run in the current RFH.
+//
+// - The current RFH runs its beforeunload handler. If it returns false, we
+// cancel all the pending logic. Otherwise we allow the pending RFH to send
+// the navigation request to its renderer.
+//
+// - ResourceDispatcherHost receives a ResourceRequest on the IO thread for the
+// main resource load from the pending RFH. It creates a
+// CrossSiteResourceHandler to check whether a process transfer is needed when
+// the request is ready to commit.
+//
+// - When RDH receives a response, the BufferedResourceHandler determines
+// whether it is a navigation type that doesn't commit (e.g. download, 204 or
+// error page). If so, it sends a message to the new renderer causing it to
+// cancel the request, and the request (e.g. the download) proceeds. In this
+// case, the pending RFH will never become the current RFH, but it remains
+// until the next DidNavigate event for this WebContentsImpl.
+//
+// - After RDH receives a response and determines that it is safe and not a
+// download, the CrossSiteResourceHandler checks whether a transfer for a
+// redirect is needed. If so, it pauses the network response and starts an
+// identical navigation in a new pending RFH. When the identical request is
+// later received by RDH, the response is transferred and unpaused.
+//
+// - Otherwise, the network response commits in the pending RFH's renderer,
+// which sends a DidCommitProvisionalLoad message back to the browser process.
+//
+// - RFHM::CommitPending makes visible the new RFH, and initiates the unload
+// handler in the old RFH. The unload handler will complete in the background.
+//
+// - RenderFrameHostManager may keep the previous RFH alive as a
+// RenderFrameProxyHost, to be used (for example) if the user goes back. The
+// process only stays live if another tab is using it, but if so, the existing
+// frame relationships will be maintained.
class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
public:
// Functions implemented by our owner that we need.
@@ -51,20 +102,29 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// There is additional complexity that some of the functions we need in
// WebContentsImpl are inherited and non-virtual. These are named with
// "RenderManager" so that the duplicate implementation of them will be clear.
+ //
+ // Functions and parameters whose description are prefixed by PlzNavigate are
+ // part of a navigation refactoring project, currently behind the
+ // enable-browser-side-navigation flag. The idea is to move the logic behind
+ // driving navigations from the renderer to the browser.
class CONTENT_EXPORT Delegate {
public:
// Initializes the given renderer if necessary and creates the view ID
// corresponding to this view host. If this method is not called and the
// process is not shared, then the WebContentsImpl will act as though the
// renderer is not running (i.e., it will render "sad tab"). This method is
- // automatically called from LoadURL. |for_main_frame| indicates whether
- // this RenderViewHost is used to render a top-level frame, so the
+ // automatically called from LoadURL. |for_main_frame_navigation| indicates
+ // whether this RenderViewHost is used to render a top-level frame, so the
// appropriate RenderWidgetHostView type is used.
virtual bool CreateRenderViewForRenderManager(
RenderViewHost* render_view_host,
int opener_route_id,
int proxy_routing_id,
- bool for_main_frame) = 0;
+ bool for_main_frame_navigation) = 0;
+ virtual bool CreateRenderFrameForRenderManager(
+ RenderFrameHost* render_frame_host,
+ int parent_routing_id,
+ int proxy_routing_id) = 0;
virtual void BeforeUnloadFiredFromRenderManager(
bool proceed, const base::TimeTicks& proceed_time,
bool* proceed_to_fire_unload) = 0;
@@ -72,8 +132,9 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
RenderViewHost* render_view_host) = 0;
virtual void UpdateRenderViewSizeForRenderManager() = 0;
virtual void CancelModalDialogsForRenderManager() = 0;
- virtual void NotifySwappedFromRenderManager(
- RenderViewHost* old_host, RenderViewHost* new_host) = 0;
+ virtual void NotifySwappedFromRenderManager(RenderFrameHost* old_host,
+ RenderFrameHost* new_host,
+ bool is_main_frame) = 0;
virtual NavigationControllerImpl&
GetControllerForRenderManager() = 0;
@@ -102,9 +163,6 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// Focuses the location bar.
virtual void SetFocusToLocationBar(bool select_all) = 0;
- // Creates a view and sets the size for the specified RVH.
- virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) = 0;
-
// Returns true if views created for this delegate should be created in a
// hidden state.
virtual bool IsHidden() = 0;
@@ -130,7 +188,7 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
RenderViewHostDelegate* render_view_delegate,
RenderWidgetHostDelegate* render_widget_delegate,
Delegate* delegate);
- virtual ~RenderFrameHostManager();
+ ~RenderFrameHostManager() override;
// For arguments, see WebContentsImpl constructor.
void Init(BrowserContext* browser_context,
@@ -174,8 +232,8 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
}
// Sets the pending Web UI for the pending navigation, ensuring that the
- // bindings are appropriate for the given NavigationEntry.
- void SetPendingWebUI(const NavigationEntryImpl& entry);
+ // bindings are appropriate compared to |bindings|.
+ void SetPendingWebUI(const GURL& url, int bindings);
// Called when we want to instruct the renderer to navigate to the given
// navigation entry. It may create a new RenderFrameHost or re-use an existing
@@ -217,28 +275,41 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
const std::vector<GURL>& transfer_url_chain,
const Referrer& referrer,
- PageTransition page_transition,
+ ui::PageTransition page_transition,
bool should_replace_current_entry);
- // The RenderFrameHost has been swapped out, so we should resume the pending
- // network response and allow the pending RenderFrameHost to commit.
- void SwappedOut(RenderFrameHostImpl* render_frame_host);
+ // Received a response from CrossSiteResourceHandler. If the navigation
+ // specifies a transition, this is called and the navigation will not resume
+ // until ResumeResponseDeferredAtStart.
+ void OnDeferredAfterResponseStarted(
+ const GlobalRequestID& global_request_id,
+ RenderFrameHostImpl* pending_render_frame_host);
+
+ // Resume navigation paused after receiving response headers.
+ void ResumeResponseDeferredAtStart();
+
+ // Clear navigation transition data.
+ void ClearNavigationTransitionData();
// Called when a renderer's frame navigates.
void DidNavigateFrame(RenderFrameHostImpl* render_frame_host);
// Called when a renderer sets its opener to null.
- void DidDisownOpener(RenderViewHost* render_view_host);
+ void DidDisownOpener(RenderFrameHost* render_frame_host);
// Helper method to create and initialize a RenderFrameHost. If |swapped_out|
// is true, it will be initially placed on the swapped out hosts list.
- // Otherwise, it will be used for a pending cross-site navigation.
// Returns the routing id of the *view* associated with the frame.
int CreateRenderFrame(SiteInstance* instance,
int opener_route_id,
bool swapped_out,
+ bool for_main_frame_navigation,
bool hidden);
+ // Helper method to create and initialize a RenderFrameProxyHost and return
+ // its routing id.
+ int CreateRenderFrameProxy(SiteInstance* instance);
+
// Sets the passed passed interstitial as the currently showing interstitial.
// |interstitial_page| should be non NULL (use the remove_interstitial_page
// method to unset the interstitial) and no interstitial page should be set
@@ -259,9 +330,9 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
InterstitialPageImpl* interstitial_page() const { return interstitial_page_; }
// NotificationObserver implementation.
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
// Returns whether the given RenderFrameHost (or its associated
// RenderViewHost) is on the list of swapped out RenderFrameHosts.
@@ -275,67 +346,33 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
RenderFrameProxyHost* GetRenderFrameProxyHost(
SiteInstance* instance) const;
- // Runs the unload handler in the current page, when we know that a pending
- // cross-process navigation is going to commit. We may initiate a transfer
- // to a new process after this completes or times out.
- void SwapOutOldPage();
+ // Returns whether |render_frame_host| is on the pending deletion list.
+ bool IsPendingDeletion(RenderFrameHostImpl* render_frame_host);
- // Deletes a RenderFrameHost that was pending shutdown.
- void ClearPendingShutdownRFHForSiteInstance(int32 site_instance_id,
- RenderFrameHostImpl* rfh);
+ // If |render_frame_host| is on the pending deletion list, this deletes it.
+ // Returns whether it was deleted.
+ bool DeleteFromPendingList(RenderFrameHostImpl* render_frame_host);
// Deletes any proxy hosts associated with this node. Used during destruction
// of WebContentsImpl.
void ResetProxyHosts();
+ // Returns the routing id for a RenderFrameHost or RenderFrameHostProxy
+ // that has the given SiteInstance and is associated with this
+ // RenderFrameHostManager. Returns MSG_ROUTING_NONE if none is found.
+ int GetRoutingIdForSiteInstance(SiteInstance* site_instance);
+
+ // PlzNavigate: Called when a navigation is ready to commit, to select the
+ // renderer that will commit it.
+ RenderFrameHostImpl* GetFrameHostForNavigation(const GURL& url,
+ ui::PageTransition transition);
+
private:
friend class RenderFrameHostManagerTest;
friend class TestWebContents;
- // Tracks information about a navigation while a cross-process transition is
- // in progress, in case we need to transfer it to a new RenderFrameHost.
- // When a request is being transferred, deleting the PendingNavigationParams,
- // and thus |cross_site_transferring_request|, will cancel the request being
- // transferred, unless its ReleaseRequest method has been called.
- struct PendingNavigationParams {
- PendingNavigationParams(
- const GlobalRequestID& global_request_id,
- scoped_ptr<CrossSiteTransferringRequest>
- cross_site_transferring_request,
- const std::vector<GURL>& transfer_url,
- Referrer referrer,
- PageTransition page_transition,
- int render_frame_id,
- bool should_replace_current_entry);
- ~PendingNavigationParams();
-
- // The child ID and request ID for the pending navigation. Present whether
- // |request_transfer| is NULL or not.
- GlobalRequestID global_request_id;
-
- // If a pending request needs to be transferred to another process, this
- // owns the request until it's transferred to the new process, so it will be
- // cleaned up if the navigation is cancelled. Otherwise, this is NULL.
- scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request;
-
- // If |request_transfer| is non-NULL, the values below are all set.
-
- // The first entry is the original request URL, and the last entry is the
- // destination URL to request in the new process.
- std::vector<GURL> transfer_url_chain;
-
- // This is the referrer to use for the request in the new process.
- Referrer referrer;
-
- // This is the transition type for the original navigation.
- PageTransition page_transition;
-
- // This is the frame routing ID to use in RequestTransferURL.
- int render_frame_id;
-
- // This is whether the navigation should replace the current history entry.
- bool should_replace_current_entry;
- };
+ FRIEND_TEST_ALL_PREFIXES(CrossProcessFrameTreeBrowserTest,
+ CreateCrossProcessSubframeProxies);
// Used with FrameTree::ForEach to erase RenderFrameProxyHosts from a
// FrameTreeNode's RenderFrameHostManager.
@@ -347,31 +384,67 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// switch. Can be overridden in unit tests.
bool ShouldTransitionCrossSite();
- // Returns true if for the navigation from |current_entry| to |new_entry|,
- // a new SiteInstance and BrowsingInstance should be created (even if we are
- // in a process model that doesn't usually swap). This forces a process swap
- // and severs script connections with existing tabs. Cases where this can
- // happen include transitions between WebUI and regular web pages.
- // Either of the entries may be NULL.
+ // Returns true if for the navigation from |current_effective_url| to
+ // |new_effective_url|, a new SiteInstance and BrowsingInstance should be
+ // created (even if we are in a process model that doesn't usually swap).
+ // This forces a process swap and severs script connections with existing
+ // tabs. Cases where this can happen include transitions between WebUI and
+ // regular web pages. |new_site_instance| may be null.
+ // If there is no current NavigationEntry, then |current_is_view_source_mode|
+ // should be the same as |new_is_view_source_mode|.
+ //
+ // We use the effective URL here, since that's what is used in the
+ // SiteInstance's site and when we later call IsSameWebSite. If there is no
+ // current NavigationEntry, check the current SiteInstance's site, which might
+ // already be committed to a Web UI URL (such as the NTP).
bool ShouldSwapBrowsingInstancesForNavigation(
- const NavigationEntry* current_entry,
- const NavigationEntryImpl* new_entry) const;
+ const GURL& current_effective_url,
+ bool current_is_view_source_mode,
+ SiteInstance* new_site_instance,
+ const GURL& new_effective_url,
+ bool new_is_view_source_mode) const;
// Returns true if it is safe to reuse the current WebUI when navigating from
- // |current_entry| to |new_entry|.
+ // |current_entry| to |new_url|.
bool ShouldReuseWebUI(
const NavigationEntry* current_entry,
- const NavigationEntryImpl* new_entry) const;
+ const GURL& new_url) const;
+
+ // Returns the SiteInstance to use for the navigation.
+ SiteInstance* GetSiteInstanceForNavigation(
+ const GURL& dest_url,
+ SiteInstance* dest_instance,
+ ui::PageTransition dest_transition,
+ bool dest_is_restore,
+ bool dest_is_view_source_mode);
- // Returns an appropriate SiteInstance object for the given NavigationEntry,
+ // Returns an appropriate SiteInstance object for the given |dest_url|,
// possibly reusing the current SiteInstance. If --process-per-tab is used,
// this is only called when ShouldSwapBrowsingInstancesForNavigation returns
- // true.
- SiteInstance* GetSiteInstanceForEntry(
- const NavigationEntryImpl& entry,
+ // true. |dest_instance| will be used if it is not null.
+ // This is a helper function for GetSiteInstanceForNavigation.
+ SiteInstance* GetSiteInstanceForURL(
+ const GURL& dest_url,
+ SiteInstance* dest_instance,
+ ui::PageTransition dest_transition,
+ bool dest_is_restore,
+ bool dest_is_view_source_mode,
SiteInstance* current_instance,
bool force_browsing_instance_swap);
+ // Determines the appropriate url to use as the current url for SiteInstance
+ // selection.
+ const GURL& GetCurrentURLForSiteInstance(
+ SiteInstance* current_instance,
+ NavigationEntry* current_entry);
+
+ // Creates a new RenderFrameHostImpl for the |new_instance| while respecting
+ // the opener route if needed and stores it in pending_render_frame_host_.
+ void CreateRenderFrameHostForNewSiteInstance(
+ SiteInstance* old_instance,
+ SiteInstance* new_instance,
+ bool is_main_frame);
+
// Creates a RenderFrameHost and corresponding RenderViewHost if necessary.
scoped_ptr<RenderFrameHostImpl> CreateRenderFrameHost(SiteInstance* instance,
int view_routing_id,
@@ -386,20 +459,34 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// initialized for another RenderFrameHost.
// TODO(creis): opener_route_id is currently for the RenderViewHost but should
// be for the RenderFrame, since frames can have openers.
- bool InitRenderView(RenderViewHost* render_view_host,
+ bool InitRenderView(RenderViewHostImpl* render_view_host,
int opener_route_id,
int proxy_routing_id,
- bool for_main_frame);
+ bool for_main_frame_navigation);
+
+ // Initialization for RenderFrameHost uses the same sequence as InitRenderView
+ // above.
+ bool InitRenderFrame(RenderFrameHostImpl* render_frame_host);
// Sets the pending RenderFrameHost/WebUI to be the active one. Note that this
// doesn't require the pending render_frame_host_ pointer to be non-NULL,
// since there could be Web UI switching as well. Call this for every commit.
void CommitPending();
- // Shutdown all RenderFrameHosts in a SiteInstance. This is called to shutdown
- // frames when all the frames in a SiteInstance are confirmed to be swapped
- // out.
- void ShutdownRenderFrameHostsInSiteInstance(int32 site_instance_id);
+ // Runs the unload handler in the old RenderFrameHost, after the new
+ // RenderFrameHost has committed. |old_render_frame_host| will either be
+ // deleted or put on the pending delete list during this call.
+ void SwapOutOldFrame(scoped_ptr<RenderFrameHostImpl> old_render_frame_host);
+
+ // Holds |render_frame_host| until it can be deleted when its swap out ACK
+ // arrives.
+ void MoveToPendingDeleteHosts(
+ scoped_ptr<RenderFrameHostImpl> render_frame_host);
+
+ // Shutdown all RenderFrameProxyHosts in a SiteInstance. This is called to
+ // shutdown frames when all the frames in a SiteInstance are confirmed to be
+ // swapped out.
+ void ShutdownRenderFrameProxyHostsInSiteInstance(int32 site_instance_id);
// Helper method to terminate the pending RenderViewHost.
void CancelPending();
@@ -410,12 +497,22 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
scoped_ptr<RenderFrameHostImpl> render_frame_host);
RenderFrameHostImpl* UpdateStateForNavigate(
- const NavigationEntryImpl& entry);
+ const GURL& url,
+ SiteInstance* instance,
+ ui::PageTransition transition,
+ bool is_restore,
+ bool is_view_source_mode,
+ const GlobalRequestID& transferred_request_id,
+ int bindings);
// Called when a renderer process is starting to close. We should not
// schedule new navigations in its swapped out RenderFrameHosts after this.
void RendererProcessClosing(RenderProcessHost* render_process_host);
+ // Helper method to delete a RenderFrameProxyHost from the list, if one exists
+ // for the given |instance|.
+ void DeleteRenderFrameProxyHost(SiteInstance* instance);
+
// For use in creating RenderFrameHosts.
FrameTreeNode* frame_tree_node_;
@@ -453,8 +550,14 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
// associated with the navigation.
scoped_ptr<RenderFrameHostImpl> pending_render_frame_host_;
- // Tracks information about any current pending cross-process navigation.
- scoped_ptr<PendingNavigationParams> pending_nav_params_;
+ // If a pending request needs to be transferred to another process, this
+ // owns the request until it's transferred to the new process, so it will be
+ // cleaned up if the navigation is cancelled. Otherwise, this is NULL.
+ scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request_;
+
+ // Tracks information about any navigation paused after receiving response
+ // headers.
+ scoped_ptr<GlobalRequestID> response_started_id_;
// If either of these is non-NULL, the pending navigation is to a chrome:
// page. The scoped_ptr is used if pending_web_ui_ != web_ui_, the WeakPtr is
@@ -467,10 +570,11 @@ class CONTENT_EXPORT RenderFrameHostManager : public NotificationObserver {
typedef base::hash_map<int32, RenderFrameProxyHost*> RenderFrameProxyHostMap;
RenderFrameProxyHostMap proxy_hosts_;
- // A map of RenderFrameHosts pending shutdown.
- typedef base::hash_map<int32, linked_ptr<RenderFrameHostImpl> >
- RFHPendingDeleteMap;
- RFHPendingDeleteMap pending_delete_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;
+ RFHPendingDeleteList pending_delete_hosts_;
// The intersitial page currently shown if any, not own by this class
// (the InterstitialPage is self-owned, it deletes itself when hidden).
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 ad2689ea138..fcfbd2c585c 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
@@ -7,7 +7,6 @@
#include "base/command_line.h"
#include "base/json/json_reader.h"
#include "base/memory/ref_counted.h"
-#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/browser/child_process_security_policy_impl.h"
@@ -253,7 +252,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
}
// Test for crbug.com/24447. Following a cross-site link with just
-// target=_blank should not create a new SiteInstance.
+// target=_blank should not create a new SiteInstance, unless we
+// are running in --site-per-process mode.
IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
DontSwapProcessWithOnlyTargetBlank) {
StartServer();
@@ -288,10 +288,14 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
EXPECT_EQ("/files/title2.html",
new_shell->web_contents()->GetLastCommittedURL().path());
- // Should have the same SiteInstance.
+ // Should have the same SiteInstance unless we're in site-per-process mode.
scoped_refptr<SiteInstance> blank_site_instance(
new_shell->web_contents()->GetSiteInstance());
- EXPECT_EQ(orig_site_instance, blank_site_instance);
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ EXPECT_EQ(orig_site_instance, blank_site_instance);
+ else
+ EXPECT_NE(orig_site_instance, blank_site_instance);
}
// Test for crbug.com/24447. Following a cross-site link with rel=noreferrer
@@ -329,10 +333,14 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
EXPECT_EQ("/files/title2.html",
shell()->web_contents()->GetLastCommittedURL().path());
- // Should have the same SiteInstance.
+ // Should have the same SiteInstance unless we're in site-per-process mode.
scoped_refptr<SiteInstance> noref_site_instance(
shell()->web_contents()->GetSiteInstance());
- EXPECT_EQ(orig_site_instance, noref_site_instance);
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ EXPECT_EQ(orig_site_instance, noref_site_instance);
+ else
+ EXPECT_NE(orig_site_instance, noref_site_instance);
}
// Test for crbug.com/116192. Targeted links should still work after the
@@ -398,7 +406,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
// If it navigates away to another process, the original window should
// still be able to close it (using a cross-process close message).
NavigateToURL(new_shell, cross_site_url);
- EXPECT_EQ(new_site_instance,
+ EXPECT_EQ(new_site_instance.get(),
new_shell->web_contents()->GetSiteInstance());
WebContentsDestroyedWatcher close_watcher(new_shell->web_contents());
EXPECT_TRUE(ExecuteScriptAndExtractBool(
@@ -411,9 +419,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
// Test that setting the opener to null in a window affects cross-process
// navigations, including those to existing entries. http://crbug.com/156669.
-// Flaky on windows: http://crbug.com/291249
-// This test also crashes under ThreadSanitizer, http://crbug.com/356758.
-#if defined(OS_WIN) || defined(THREAD_SANITIZER)
+// This test crashes under ThreadSanitizer, http://crbug.com/356758.
+#if defined(THREAD_SANITIZER)
#define MAYBE_DisownOpener DISABLED_DisownOpener
#else
#define MAYBE_DisownOpener DisownOpener
@@ -443,6 +450,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
&success));
EXPECT_TRUE(success);
Shell* new_shell = new_shell_observer.GetShell();
+ EXPECT_TRUE(new_shell->web_contents()->HasOpener());
// Wait for the navigation in the new tab to finish, if it hasn't.
WaitForLoadStop(new_shell->web_contents());
@@ -459,10 +467,12 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
scoped_refptr<SiteInstance> new_site_instance(
new_shell->web_contents()->GetSiteInstance());
EXPECT_NE(orig_site_instance, new_site_instance);
+ EXPECT_TRUE(new_shell->web_contents()->HasOpener());
// Now disown the opener.
EXPECT_TRUE(ExecuteScript(new_shell->web_contents(),
"window.opener = null;"));
+ EXPECT_FALSE(new_shell->web_contents()->HasOpener());
// Go back and ensure the opener is still null.
{
@@ -476,6 +486,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
"window.domAutomationController.send(window.opener == null);",
&success));
EXPECT_TRUE(success);
+ EXPECT_FALSE(new_shell->web_contents()->HasOpener());
// Now navigate forward again (creating a new process) and check opener.
NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
@@ -485,6 +496,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, MAYBE_DisownOpener) {
"window.domAutomationController.send(window.opener == null);",
&success));
EXPECT_TRUE(success);
+ EXPECT_FALSE(new_shell->web_contents()->HasOpener());
}
// Test that subframes can disown their openers. http://crbug.com/225528.
@@ -569,7 +581,7 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
WaitForLoadStop(new_contents);
EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
- EXPECT_EQ(orig_site_instance, new_contents->GetSiteInstance());
+ EXPECT_EQ(orig_site_instance.get(), new_contents->GetSiteInstance());
RenderFrameHostManager* new_manager =
static_cast<WebContentsImpl*>(new_contents)->GetRenderManagerForTesting();
@@ -1142,7 +1154,7 @@ class RenderViewHostDestructionObserver : public WebContentsObserver {
public:
explicit RenderViewHostDestructionObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
- virtual ~RenderViewHostDestructionObserver() {}
+ ~RenderViewHostDestructionObserver() override {}
void EnsureRVHGetsDestructed(RenderViewHost* rvh) {
watched_render_view_hosts_.insert(rvh);
}
@@ -1152,7 +1164,7 @@ class RenderViewHostDestructionObserver : public WebContentsObserver {
private:
// WebContentsObserver implementation:
- virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE {
+ void RenderViewDeleted(RenderViewHost* rvh) override {
watched_render_view_hosts_.erase(rvh);
}
@@ -1268,7 +1280,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
new_shell->web_contents()->GetLastCommittedURL().path());
// Should have the same SiteInstance.
- EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
+ EXPECT_EQ(orig_site_instance.get(),
+ new_shell->web_contents()->GetSiteInstance());
// 2. Send the second tab to a different process.
NavigateToURL(new_shell, GetCrossSiteURL("files/title1.html"));
@@ -1283,7 +1296,8 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
WaitForLoadStop(shell()->web_contents());
EXPECT_EQ(GetCrossSiteURL("files/title1.html"),
shell()->web_contents()->GetLastCommittedURL());
- EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance());
+ EXPECT_EQ(new_site_instance.get(),
+ shell()->web_contents()->GetSiteInstance());
}
// Ensure that renderer-side debug URLs do not cause a process swap, since they
@@ -1351,10 +1365,18 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
crash_observer2.Wait();
}
+// The test fails with Android ASAN with changes in v8 that seem unrelated.
+// See http://crbug.com/428329.
+#if defined(OS_ANDROID) && defined(THREAD_SANITIZER)
+#define MAYBE_ClearPendingWebUIOnCommit DISABLED_ClearPendingWebUIOnCommit
+#else
+#define MAYBE_ClearPendingWebUIOnCommit ClearPendingWebUIOnCommit
+#endif
// Ensure that pending_and_current_web_ui_ is cleared when a URL commits.
// Otherwise it might get picked up by InitRenderView when granting bindings
// to other RenderViewHosts. See http://crbug.com/330811.
-IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, ClearPendingWebUIOnCommit) {
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ MAYBE_ClearPendingWebUIOnCommit) {
// Visit a WebUI page with bindings.
GURL webui_url(GURL(std::string(kChromeUIScheme) + "://" +
std::string(kChromeUIGpuHost)));
@@ -1379,7 +1401,7 @@ class RFHMProcessPerTabTest : public RenderFrameHostManagerTest {
public:
RFHMProcessPerTabTest() {}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
command_line->AppendSwitch(switches::kProcessPerTab);
}
};
@@ -1462,4 +1484,27 @@ IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, WebUIGetsBindings) {
new_web_contents->GetRenderViewHost()->GetEnabledBindings());
}
+// crbug.com/424526
+// The test loads a WebUI page in rocess-per-tab mode, then navigates to a blank
+// page and then to a regular page. The bug reproduces if blank page is visited
+// in between WebUI and regular page.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+ ForceSwapAfterWebUIBindings) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(switches::kProcessPerTab);
+ ASSERT_TRUE(test_server()->Start());
+
+ const GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
+ std::string(kChromeUIGpuHost));
+ NavigateToURL(shell(), web_ui_url);
+ EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
+ shell()->web_contents()->GetRenderProcessHost()->GetID()));
+
+ NavigateToURL(shell(), GURL(url::kAboutBlankURL));
+
+ GURL regular_page_url(test_server()->GetURL("files/title2.html"));
+ NavigateToURL(shell(), regular_page_url);
+ EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
+ shell()->web_contents()->GetRenderProcessHost()->GetID()));
+}
+
} // 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 a5100dfbe4b..11c3c8a2704 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
@@ -2,13 +2,17 @@
// 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/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/histogram_tester.h"
+#include "base/time/time.h"
#include "content/browser/frame_host/cross_site_transferring_request.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/frame_host/render_frame_host_manager.h"
+#include "content/browser/frame_host/render_frame_proxy_host.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/common/frame_messages.h"
@@ -23,17 +27,20 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/common/bindings_policy.h"
+#include "content/public/common/content_switches.h"
#include "content/public/common/javascript_message_type.h"
-#include "content/public/common/page_transition_types.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_notification_tracker.h"
#include "content/test/test_content_browser_client.h"
#include "content/test/test_content_client.h"
+#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/load_flags.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/page_transition_types.h"
namespace content {
namespace {
@@ -44,32 +51,32 @@ class RenderFrameHostManagerTestWebUIControllerFactory
RenderFrameHostManagerTestWebUIControllerFactory()
: should_create_webui_(false) {
}
- virtual ~RenderFrameHostManagerTestWebUIControllerFactory() {}
+ ~RenderFrameHostManagerTestWebUIControllerFactory() override {}
void set_should_create_webui(bool should_create_webui) {
should_create_webui_ = should_create_webui;
}
// WebUIFactory implementation.
- virtual WebUIController* CreateWebUIControllerForURL(
- WebUI* web_ui, const GURL& url) const OVERRIDE {
+ WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
+ const GURL& url) const override {
if (!(should_create_webui_ && HasWebUIScheme(url)))
return NULL;
return new WebUIController(web_ui);
}
- virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
+ const GURL& url) const override {
return WebUI::kNoWebUI;
}
- virtual bool UseWebUIForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ bool UseWebUIForURL(BrowserContext* browser_context,
+ const GURL& url) const override {
return HasWebUIScheme(url);
}
- virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ bool UseWebUIBindingsForURL(BrowserContext* browser_context,
+ const GURL& url) const override {
return HasWebUIScheme(url);
}
@@ -82,11 +89,11 @@ class RenderFrameHostManagerTestWebUIControllerFactory
class BeforeUnloadFiredWebContentsDelegate : public WebContentsDelegate {
public:
BeforeUnloadFiredWebContentsDelegate() {}
- virtual ~BeforeUnloadFiredWebContentsDelegate() {}
+ ~BeforeUnloadFiredWebContentsDelegate() override {}
- virtual void BeforeUnloadFired(WebContents* web_contents,
- bool proceed,
- bool* proceed_to_fire_unload) OVERRIDE {
+ void BeforeUnloadFired(WebContents* web_contents,
+ bool proceed,
+ bool* proceed_to_fire_unload) override {
*proceed_to_fire_unload = proceed;
}
@@ -94,6 +101,23 @@ class BeforeUnloadFiredWebContentsDelegate : public WebContentsDelegate {
DISALLOW_COPY_AND_ASSIGN(BeforeUnloadFiredWebContentsDelegate);
};
+class CloseWebContentsDelegate : public WebContentsDelegate {
+ public:
+ CloseWebContentsDelegate() : close_called_(false) {}
+ ~CloseWebContentsDelegate() override {}
+
+ void CloseContents(WebContents* web_contents) override {
+ close_called_ = true;
+ }
+
+ bool is_closed() { return close_called_; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CloseWebContentsDelegate);
+
+ bool close_called_;
+};
+
// This observer keeps track of the last deleted RenderViewHost to avoid
// accessing it and causing use-after-free condition.
class RenderViewHostDeletedObserver : public WebContentsObserver {
@@ -105,7 +129,7 @@ class RenderViewHostDeletedObserver : public WebContentsObserver {
deleted_(false) {
}
- virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE {
+ void RenderViewDeleted(RenderViewHost* render_view_host) override {
if (render_view_host->GetProcess()->GetID() == process_id_ &&
render_view_host->GetRoutingID() == routing_id_) {
deleted_ = true;
@@ -124,6 +148,29 @@ class RenderViewHostDeletedObserver : public WebContentsObserver {
DISALLOW_COPY_AND_ASSIGN(RenderViewHostDeletedObserver);
};
+// This observer keeps track of the last created RenderFrameHost to allow tests
+// to ensure that no RenderFrameHost objects are created when not expected.
+class RenderFrameHostCreatedObserver : public WebContentsObserver {
+ public:
+ RenderFrameHostCreatedObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents),
+ created_(false) {
+ }
+
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
+ created_ = true;
+ }
+
+ bool created() {
+ return created_;
+ }
+
+ private:
+ bool created_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
+};
+
// This observer keeps track of the last deleted RenderFrameHost to avoid
// accessing it and causing use-after-free condition.
class RenderFrameHostDeletedObserver : public WebContentsObserver {
@@ -135,7 +182,7 @@ class RenderFrameHostDeletedObserver : public WebContentsObserver {
deleted_(false) {
}
- virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override {
if (render_frame_host->GetProcess()->GetID() == process_id_ &&
render_frame_host->GetRoutingID() == routing_id_) {
deleted_ = true;
@@ -154,7 +201,6 @@ class RenderFrameHostDeletedObserver : public WebContentsObserver {
DISALLOW_COPY_AND_ASSIGN(RenderFrameHostDeletedObserver);
};
-
// This observer is used to check whether IPC messages are being filtered for
// swapped out RenderFrameHost objects. It observes the plugin crash and favicon
// update events, which the FilterMessagesWhileSwappedOut test simulates being
@@ -167,13 +213,12 @@ class PluginFaviconMessageObserver : public WebContentsObserver {
plugin_crashed_(false),
favicon_received_(false) { }
- virtual void PluginCrashed(const base::FilePath& plugin_path,
- base::ProcessId plugin_pid) OVERRIDE {
+ void PluginCrashed(const base::FilePath& plugin_path,
+ base::ProcessId plugin_pid) override {
plugin_crashed_ = true;
}
- virtual void DidUpdateFaviconURL(
- const std::vector<FaviconURL>& candidates) OVERRIDE {
+ void DidUpdateFaviconURL(const std::vector<FaviconURL>& candidates) override {
favicon_received_ = true;
}
@@ -202,7 +247,7 @@ class FrameLifetimeConsistencyChecker : public WebContentsObserver {
RenderFrameCreated(web_contents->GetMainFrame());
}
- virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE {
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
std::pair<int, int> routing_pair =
std::make_pair(render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID());
@@ -218,7 +263,7 @@ class FrameLifetimeConsistencyChecker : public WebContentsObserver {
}
}
- virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE {
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override {
std::pair<int, int> routing_pair =
std::make_pair(render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID());
@@ -252,13 +297,13 @@ class FrameLifetimeConsistencyChecker : public WebContentsObserver {
class RenderFrameHostManagerTest
: public RenderViewHostImplTestHarness {
public:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
WebUIControllerFactory::RegisterFactory(&factory_);
lifetime_checker_.reset(new FrameLifetimeConsistencyChecker(contents()));
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
lifetime_checker_.reset();
RenderViewHostImplTestHarness::TearDown();
WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
@@ -268,99 +313,114 @@ class RenderFrameHostManagerTest
factory_.set_should_create_webui(should_create_webui);
}
- void StartCrossSiteTransition(TestWebContents* contents) {
- std::vector<GURL> url_chain;
- contents->GetRenderManagerForTesting()->OnCrossSiteResponse(
- contents->GetRenderManagerForTesting()->pending_frame_host(),
- GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
- url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
- EXPECT_TRUE(contents->cross_navigation_pending());
- RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
- contents->GetRenderViewHost());
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
- rvh->rvh_state());
- }
-
void NavigateActiveAndCommit(const GURL& url) {
- // Note: we navigate the active RenderViewHost because previous navigations
+ // Note: we navigate the active RenderFrameHost because previous navigations
// won't have committed yet, so NavigateAndCommit does the wrong thing
// for us.
- controller().LoadURL(url, Referrer(), PAGE_TRANSITION_LINK, std::string());
- TestRenderViewHost* old_rvh = test_rvh();
+ controller().LoadURL(
+ url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ TestRenderFrameHost* old_rfh = contents()->GetMainFrame();
+ TestRenderFrameHost* active_rfh = contents()->GetPendingMainFrame()
+ ? contents()->GetPendingMainFrame()
+ : old_rfh;
// Simulate the BeforeUnload_ACK that is received from the current renderer
// for a cross-site navigation.
- if (old_rvh != active_rvh()) {
- old_rvh->SendBeforeUnloadACK(true);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, old_rvh->rvh_state());
+ if (old_rfh != active_rfh) {
+ old_rfh->SendBeforeUnloadACK(true);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, old_rfh->rfh_state());
}
// Commit the navigation with a new page ID.
int32 max_page_id = contents()->GetMaxPageIDForSiteInstance(
- active_rvh()->GetSiteInstance());
-
- // Simulate the response coming from the pending renderer.
- if (old_rvh != active_rvh())
- StartCrossSiteTransition(contents());
-
- // Simulate the SwapOut_ACK that fires if you commit a cross-site
- // navigation.
- if (old_rvh != active_rvh()) {
- old_rvh->OnSwappedOut(false);
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT,
- old_rvh->rvh_state());
- }
+ active_rfh->GetSiteInstance());
// Use an observer to avoid accessing a deleted renderer later on when the
// state is being checked.
- RenderViewHostDeletedObserver rvh_observer(old_rvh);
- active_test_rvh()->SendNavigate(max_page_id + 1, url);
+ RenderFrameHostDeletedObserver rfh_observer(old_rfh);
+ RenderViewHostDeletedObserver rvh_observer(old_rfh->GetRenderViewHost());
+ active_rfh->SendNavigate(max_page_id + 1, 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()) {
+ expecting_rfh_shutdown = true;
+ EXPECT_TRUE(
+ old_rfh->frame_tree_node()->render_manager()->IsPendingDeletion(
+ old_rfh));
+ }
+ }
- if (old_rvh != active_rvh() && !rvh_observer.deleted())
- EXPECT_TRUE(old_rvh->IsSwappedOut());
+ // 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());
+ EXPECT_TRUE(rvh_observer.deleted());
+ } else {
+ EXPECT_EQ(RenderFrameHostImpl::STATE_SWAPPED_OUT,
+ old_rfh->rfh_state());
+ }
+ }
+ EXPECT_EQ(active_rfh, contents()->GetMainFrame());
+ EXPECT_EQ(NULL, contents()->GetPendingMainFrame());
}
bool ShouldSwapProcesses(RenderFrameHostManager* manager,
const NavigationEntryImpl* current_entry,
const NavigationEntryImpl* new_entry) const {
- return manager->ShouldSwapBrowsingInstancesForNavigation(current_entry,
- new_entry);
+ CHECK(new_entry);
+ BrowserContext* browser_context =
+ manager->delegate_->GetControllerForRenderManager().GetBrowserContext();
+ const GURL& current_effective_url = current_entry ?
+ SiteInstanceImpl::GetEffectiveURL(browser_context,
+ current_entry->GetURL()) :
+ manager->render_frame_host_->GetSiteInstance()->GetSiteURL();
+ bool current_is_view_source_mode = current_entry ?
+ current_entry->IsViewSourceMode() : new_entry->IsViewSourceMode();
+ return manager->ShouldSwapBrowsingInstancesForNavigation(
+ current_effective_url,
+ current_is_view_source_mode,
+ new_entry->site_instance(),
+ SiteInstanceImpl::GetEffectiveURL(browser_context, new_entry->GetURL()),
+ new_entry->IsViewSourceMode());
}
- // Creates a test RenderViewHost that's swapped out.
- TestRenderViewHost* CreateSwappedOutRenderViewHost() {
+ // Creates a test RenderFrameHost that's swapped out.
+ TestRenderFrameHost* CreateSwappedOutRenderFrameHost() {
const GURL kChromeURL("chrome://foo");
const GURL kDestUrl("http://www.google.com/");
// Navigate our first tab to a chrome url and then to the destination.
NavigateActiveAndCommit(kChromeURL);
- TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
- contents()->GetRenderManagerForTesting()->current_host());
+ TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
// Navigate to a cross-site URL.
contents()->GetController().LoadURL(
- kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ kDestUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
EXPECT_TRUE(contents()->cross_navigation_pending());
- // Manually increase the number of active views in the
- // SiteInstance that ntp_rvh belongs to, to prevent it from being
+ // Manually increase the number of active frames in the
+ // SiteInstance that ntp_rfh belongs to, to prevent it from being
// destroyed when it gets swapped out.
- static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
- increment_active_view_count();
+ ntp_rfh->GetSiteInstance()->increment_active_frame_count();
- TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
- contents()->GetRenderManagerForTesting()->pending_render_view_host());
- CHECK(dest_rvh);
- EXPECT_NE(ntp_rvh, dest_rvh);
+ TestRenderFrameHost* dest_rfh = contents()->GetPendingMainFrame();
+ CHECK(dest_rfh);
+ EXPECT_NE(ntp_rfh, dest_rfh);
// BeforeUnload finishes.
- ntp_rvh->SendBeforeUnloadACK(true);
+ ntp_rfh->SendBeforeUnloadACK(true);
- dest_rvh->SendNavigate(101, kDestUrl);
- ntp_rvh->OnSwappedOut(false);
+ dest_rfh->SendNavigate(101, kDestUrl);
+ ntp_rfh->OnSwappedOut();
- EXPECT_TRUE(ntp_rvh->IsSwappedOut());
- return ntp_rvh;
+ EXPECT_TRUE(ntp_rfh->is_swapped_out());
+ return ntp_rfh;
}
private:
@@ -383,54 +443,53 @@ TEST_F(RenderFrameHostManagerTest, NewTabPageProcesses) {
EXPECT_TRUE(active_rvh()->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
NavigateActiveAndCommit(kDestUrl);
+ EXPECT_FALSE(contents()->GetPendingMainFrame());
+
// Make a second tab.
scoped_ptr<TestWebContents> contents2(
TestWebContents::Create(browser_context(), NULL));
// Load the two URLs in the second tab. Note that the first navigation creates
- // a RVH that's not pending (since there is no cross-site transition), so
+ // a RFH that's not pending (since there is no cross-site transition), so
// we use the committed one.
contents2->GetController().LoadURL(
- kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
- TestRenderViewHost* ntp_rvh2 = static_cast<TestRenderViewHost*>(
- contents2->GetRenderManagerForTesting()->current_host());
+ kChromeUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ TestRenderFrameHost* ntp_rfh2 = contents2->GetMainFrame();
EXPECT_FALSE(contents2->cross_navigation_pending());
- ntp_rvh2->SendNavigate(100, kChromeUrl);
+ ntp_rfh2->SendNavigate(100, kChromeUrl);
// The second one is the opposite, creating a cross-site transition and
// requiring a beforeunload ack.
contents2->GetController().LoadURL(
- kDestUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ kDestUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
EXPECT_TRUE(contents2->cross_navigation_pending());
- TestRenderViewHost* dest_rvh2 = static_cast<TestRenderViewHost*>(
- contents2->GetRenderManagerForTesting()->pending_render_view_host());
- ASSERT_TRUE(dest_rvh2);
+ TestRenderFrameHost* dest_rfh2 = contents2->GetPendingMainFrame();
+ ASSERT_TRUE(dest_rfh2);
- ntp_rvh2->SendBeforeUnloadACK(true);
- StartCrossSiteTransition(contents2.get());
- dest_rvh2->SendNavigate(101, kDestUrl);
+ ntp_rfh2->SendBeforeUnloadACK(true);
+ dest_rfh2->SendNavigate(101, kDestUrl);
- // The two RVH's should be different in every way.
- EXPECT_NE(active_rvh()->GetProcess(), dest_rvh2->GetProcess());
- EXPECT_NE(active_rvh()->GetSiteInstance(), dest_rvh2->GetSiteInstance());
- EXPECT_FALSE(active_rvh()->GetSiteInstance()->IsRelatedSiteInstance(
- dest_rvh2->GetSiteInstance()));
+ // The two RFH's should be different in every way.
+ EXPECT_NE(contents()->GetMainFrame()->GetProcess(), dest_rfh2->GetProcess());
+ EXPECT_NE(contents()->GetMainFrame()->GetSiteInstance(),
+ dest_rfh2->GetSiteInstance());
+ EXPECT_FALSE(dest_rfh2->GetSiteInstance()->IsRelatedSiteInstance(
+ contents()->GetMainFrame()->GetSiteInstance()));
// Navigate both to the new tab page, and verify that they share a
// RenderProcessHost (not a SiteInstance).
NavigateActiveAndCommit(kChromeUrl);
+ EXPECT_FALSE(contents()->GetPendingMainFrame());
contents2->GetController().LoadURL(
- kChromeUrl, Referrer(), PAGE_TRANSITION_LINK, std::string());
- dest_rvh2->SendBeforeUnloadACK(true);
- StartCrossSiteTransition(contents2.get());
- static_cast<TestRenderViewHost*>(contents2->GetRenderManagerForTesting()->
- pending_render_view_host())->SendNavigate(102, kChromeUrl);
-
- EXPECT_NE(active_rvh()->GetSiteInstance(),
- contents2->GetRenderViewHost()->GetSiteInstance());
- EXPECT_EQ(active_rvh()->GetSiteInstance()->GetProcess(),
- contents2->GetRenderViewHost()->GetSiteInstance()->GetProcess());
+ kChromeUrl, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
+ dest_rfh2->SendBeforeUnloadACK(true);
+ contents2->GetPendingMainFrame()->SendNavigate(102, kChromeUrl);
+
+ EXPECT_NE(contents()->GetMainFrame()->GetSiteInstance(),
+ contents2->GetMainFrame()->GetSiteInstance());
+ EXPECT_EQ(contents()->GetMainFrame()->GetSiteInstance()->GetProcess(),
+ contents2->GetMainFrame()->GetSiteInstance()->GetProcess());
}
// Ensure that the browser ignores most IPC messages that arrive from a
@@ -445,74 +504,72 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
// Navigate our first tab to a chrome url and then to the destination.
NavigateActiveAndCommit(kChromeURL);
- TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
- contents()->GetRenderManagerForTesting()->current_host());
+ TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
// Send an update favicon message and make sure it works.
const base::string16 ntp_title = base::ASCIIToUTF16("NTP Title");
{
PluginFaviconMessageObserver observer(contents());
- EXPECT_TRUE(ntp_rvh->OnMessageReceived(
+ EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->OnMessageReceived(
ViewHostMsg_UpdateFaviconURL(
- rvh()->GetRoutingID(), icons)));
+ ntp_rfh->GetRenderViewHost()->GetRoutingID(), icons)));
EXPECT_TRUE(observer.favicon_received());
}
- // Create one more view in the same SiteInstance where ntp_rvh
+ // Create one more frame in the same SiteInstance where ntp_rfh
// exists so that it doesn't get deleted on navigation to another
// site.
- static_cast<SiteInstanceImpl*>(ntp_rvh->GetSiteInstance())->
- increment_active_view_count();
+ ntp_rfh->GetSiteInstance()->increment_active_frame_count();
// Navigate to a cross-site URL.
NavigateActiveAndCommit(kDestUrl);
- TestRenderViewHost* dest_rvh = static_cast<TestRenderViewHost*>(
- contents()->GetRenderViewHost());
- ASSERT_TRUE(dest_rvh);
- EXPECT_NE(ntp_rvh, dest_rvh);
+ TestRenderFrameHost* dest_rfh = contents()->GetMainFrame();
+ ASSERT_TRUE(dest_rfh);
+ EXPECT_NE(ntp_rfh, dest_rfh);
// The new RVH should be able to update its favicon.
const base::string16 dest_title = base::ASCIIToUTF16("Google");
{
PluginFaviconMessageObserver observer(contents());
EXPECT_TRUE(
- dest_rvh->OnMessageReceived(
- ViewHostMsg_UpdateFaviconURL(rvh()->GetRoutingID(), icons)));
+ dest_rfh->GetRenderViewHost()->OnMessageReceived(
+ ViewHostMsg_UpdateFaviconURL(
+ dest_rfh->GetRenderViewHost()->GetRoutingID(), icons)));
EXPECT_TRUE(observer.favicon_received());
}
// The old renderer, being slow, now updates the favicon. It should be
// filtered out and not take effect.
- EXPECT_TRUE(ntp_rvh->IsSwappedOut());
+ EXPECT_TRUE(ntp_rfh->is_swapped_out());
{
PluginFaviconMessageObserver observer(contents());
EXPECT_TRUE(
- ntp_rvh->OnMessageReceived(
- ViewHostMsg_UpdateFaviconURL(rvh()->GetRoutingID(), icons)));
+ ntp_rfh->GetRenderViewHost()->OnMessageReceived(
+ ViewHostMsg_UpdateFaviconURL(
+ dest_rfh->GetRenderViewHost()->GetRoutingID(), icons)));
EXPECT_FALSE(observer.favicon_received());
}
+#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());
- // TODO(nasko): Check that the RFH is in swapped out when the state moves
- // from RVH to RFH.
- EXPECT_TRUE(ntp_rvh->main_render_frame_host()->OnMessageReceived(
+ EXPECT_TRUE(ntp_rfh->OnMessageReceived(
FrameHostMsg_PluginCrashed(
- main_rfh()->GetRoutingID(), base::FilePath(), 0)));
+ 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 =
- static_cast<MockRenderProcessHost*>(ntp_rvh->GetProcess());
+ static_cast<MockRenderProcessHost*>(ntp_rfh->GetProcess());
ntp_process_host->sink().ClearMessages();
- RenderFrameHost* ntp_rfh = ntp_rvh->GetMainFrame();
const base::string16 msg = base::ASCIIToUTF16("Message");
bool result = false;
base::string16 unused;
@@ -533,28 +590,71 @@ TEST_F(RenderFrameHostManagerTest, FilterMessagesWhileSwappedOut) {
EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
}
+// 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/");
+
+ // Navigate to the first site.
+ NavigateActiveAndCommit(kUrl1);
+ TestRenderFrameHost* initial_rfh = contents()->GetMainFrame();
+ {
+ RenderFrameHostCreatedObserver observer(contents());
+ initial_rfh->OnCreateChildFrame(
+ initial_rfh->GetProcess()->GetNextRoutingID(), std::string());
+ 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()->increment_active_frame_count();
+
+ // 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(), std::string());
+ EXPECT_FALSE(observer.created());
+ }
+}
+
TEST_F(RenderFrameHostManagerTest, WhiteListSwapCompositorFrame) {
- TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
+ TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
TestRenderWidgetHostView* swapped_out_rwhv =
- static_cast<TestRenderWidgetHostView*>(swapped_out_rvh->GetView());
+ static_cast<TestRenderWidgetHostView*>(
+ swapped_out_rfh->GetRenderViewHost()->GetView());
EXPECT_FALSE(swapped_out_rwhv->did_swap_compositor_frame());
MockRenderProcessHost* process_host =
- static_cast<MockRenderProcessHost*>(swapped_out_rvh->GetProcess());
+ static_cast<MockRenderProcessHost*>(swapped_out_rfh->GetProcess());
process_host->sink().ClearMessages();
cc::CompositorFrame frame;
- ViewHostMsg_SwapCompositorFrame msg(rvh()->GetRoutingID(), 0, frame);
+ ViewHostMsg_SwapCompositorFrame msg(
+ rvh()->GetRoutingID(), 0, frame, std::vector<IPC::Message>());
- EXPECT_TRUE(swapped_out_rvh->OnMessageReceived(msg));
+ EXPECT_TRUE(swapped_out_rfh->render_view_host()->OnMessageReceived(msg));
EXPECT_TRUE(swapped_out_rwhv->did_swap_compositor_frame());
}
// Test if RenderViewHost::GetRenderWidgetHosts() only returns active
// widgets.
TEST_F(RenderFrameHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
- TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
- EXPECT_TRUE(swapped_out_rvh->IsSwappedOut());
+ TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
+ EXPECT_TRUE(swapped_out_rfh->is_swapped_out());
scoped_ptr<RenderWidgetHostIterator> widgets(
RenderWidgetHost::GetRenderWidgetHosts());
@@ -564,8 +664,7 @@ TEST_F(RenderFrameHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
RenderWidgetHost* widget = widgets->GetNextHost();
EXPECT_FALSE(widgets->GetNextHost());
RenderViewHost* rvh = RenderViewHost::From(widget);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT,
- static_cast<RenderViewHostImpl*>(rvh)->rvh_state());
+ EXPECT_TRUE(static_cast<RenderViewHostImpl*>(rvh)->is_active());
}
// Test if RenderViewHost::GetRenderWidgetHosts() returns a subset of
@@ -575,8 +674,8 @@ TEST_F(RenderFrameHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
// including swapped out ones.
TEST_F(RenderFrameHostManagerTest,
GetRenderWidgetHostsWithinGetAllRenderWidgetHosts) {
- TestRenderViewHost* swapped_out_rvh = CreateSwappedOutRenderViewHost();
- EXPECT_TRUE(swapped_out_rvh->IsSwappedOut());
+ TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
+ EXPECT_TRUE(swapped_out_rfh->is_swapped_out());
scoped_ptr<RenderWidgetHostIterator> widgets(
RenderWidgetHost::GetRenderWidgetHosts());
@@ -595,19 +694,18 @@ TEST_F(RenderFrameHostManagerTest,
}
}
-// Test if SiteInstanceImpl::active_view_count() is correctly updated
-// as views in a SiteInstance get swapped out and in.
-TEST_F(RenderFrameHostManagerTest, ActiveViewCountWhileSwappingInandOut) {
+// Test if SiteInstanceImpl::active_frame_count() is correctly updated
+// as frames in a SiteInstance get swapped out and in.
+TEST_F(RenderFrameHostManagerTest, ActiveFrameCountWhileSwappingInAndOut) {
const GURL kUrl1("http://www.google.com/");
const GURL kUrl2("http://www.chromium.org/");
// Navigate to an initial URL.
contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
+ TestRenderFrameHost* rfh1 = main_test_rfh();
- SiteInstanceImpl* instance1 =
- static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance());
- EXPECT_EQ(instance1->active_view_count(), 1U);
+ SiteInstanceImpl* instance1 = rfh1->GetSiteInstance();
+ EXPECT_EQ(instance1->active_frame_count(), 1U);
// Create 2 new tabs and simulate them being the opener chain for the main
// tab. They should be in the same SiteInstance.
@@ -619,26 +717,25 @@ TEST_F(RenderFrameHostManagerTest, ActiveViewCountWhileSwappingInandOut) {
TestWebContents::Create(browser_context(), instance1));
opener1->SetOpener(opener2.get());
- EXPECT_EQ(instance1->active_view_count(), 3U);
+ EXPECT_EQ(instance1->active_frame_count(), 3U);
// Navigate to a cross-site URL (different SiteInstance but same
// BrowsingInstance).
contents()->NavigateAndCommit(kUrl2);
- TestRenderViewHost* rvh2 = test_rvh();
- SiteInstanceImpl* instance2 =
- static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance());
+ TestRenderFrameHost* rfh2 = main_test_rfh();
+ SiteInstanceImpl* instance2 = rfh2->GetSiteInstance();
// rvh2 is on chromium.org which is different from google.com on
// which other tabs are.
- EXPECT_EQ(instance2->active_view_count(), 1U);
+ EXPECT_EQ(instance2->active_frame_count(), 1U);
// There are two active views on google.com now.
- EXPECT_EQ(instance1->active_view_count(), 2U);
+ EXPECT_EQ(instance1->active_frame_count(), 2U);
// Navigate to the original origin (google.com).
contents()->NavigateAndCommit(kUrl1);
- EXPECT_EQ(instance1->active_view_count(), 3U);
+ EXPECT_EQ(instance1->active_frame_count(), 3U);
}
// This deletes a WebContents when the given RVH is deleted. This is
@@ -654,8 +751,7 @@ class RenderViewHostDestroyer : public WebContentsObserver {
render_view_host_(render_view_host),
web_contents_(web_contents) {}
- virtual void RenderViewDeleted(
- RenderViewHost* render_view_host) OVERRIDE {
+ void RenderViewDeleted(RenderViewHost* render_view_host) override {
if (render_view_host == render_view_host_)
delete web_contents_;
}
@@ -679,20 +775,20 @@ TEST_F(RenderFrameHostManagerTest,
// Navigate our first tab to a chrome url and then to the destination.
NavigateActiveAndCommit(kChromeURL);
- TestRenderViewHost* ntp_rvh = static_cast<TestRenderViewHost*>(
- contents()->GetRenderManagerForTesting()->current_host());
+ TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
// Create one more tab and navigate to kUrl1. web_contents is not
// wrapped as scoped_ptr since it intentionally deleted by destroyer
// below as part of this test.
TestWebContents* web_contents =
- TestWebContents::Create(browser_context(), ntp_rvh->GetSiteInstance());
+ TestWebContents::Create(browser_context(), ntp_rfh->GetSiteInstance());
web_contents->NavigateAndCommit(kUrl1);
- RenderViewHostDestroyer destroyer(ntp_rvh, web_contents);
+ RenderViewHostDestroyer destroyer(ntp_rfh->GetRenderViewHost(),
+ web_contents);
// This causes the first tab to navigate to kUrl2, which destroys
- // the ntp_rvh in ShutdownRenderViewHostsInSiteInstance(). When
- // ntp_rvh is destroyed, it also destroys the RVHs in web_contents
+ // the ntp_rfh in ShutdownRenderViewHostsInSiteInstance(). When
+ // ntp_rfh is destroyed, it also destroys the RVHs in web_contents
// too. This can test whether
// SiteInstanceImpl::ShutdownRenderViewHostsInSiteInstance() can
// touch any object freed in this way or not while iterating through
@@ -718,16 +814,17 @@ TEST_F(RenderFrameHostManagerTest, AlwaysSendEnableViewSourceMode) {
// Navigate.
controller().LoadURL(
- kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kUrl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Simulate response from RenderFrame for DispatchBeforeUnload.
base::TimeTicks now = base::TimeTicks::Now();
- main_test_rfh()->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(
- main_test_rfh()->GetRoutingID(), true, now, now));
- ASSERT_TRUE(pending_rvh()); // New pending RenderViewHost will be created.
- RenderViewHost* last_rvh = pending_rvh();
- int32 new_id = contents()->GetMaxPageIDForSiteInstance(
- active_rvh()->GetSiteInstance()) + 1;
- pending_test_rvh()->SendNavigate(new_id, kUrl);
+ contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(
+ contents()->GetMainFrame()->GetRoutingID(), true, now, now));
+ ASSERT_TRUE(contents()->GetPendingMainFrame())
+ << "Expected new pending RenderFrameHost to be created.";
+ RenderFrameHost* last_rfh = contents()->GetPendingMainFrame();
+ int32 new_id =
+ contents()->GetMaxPageIDForSiteInstance(last_rfh->GetSiteInstance()) + 1;
+ contents()->GetPendingMainFrame()->SendNavigate(new_id, kUrl);
EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
ASSERT_TRUE(controller().GetLastCommittedEntry());
EXPECT_TRUE(kUrl == controller().GetLastCommittedEntry()->GetURL());
@@ -740,11 +837,12 @@ TEST_F(RenderFrameHostManagerTest, AlwaysSendEnableViewSourceMode) {
process()->sink().ClearMessages();
// Navigate, again.
controller().LoadURL(
- kUrl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kUrl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// The same RenderViewHost should be reused.
- EXPECT_FALSE(pending_rvh());
- EXPECT_TRUE(last_rvh == rvh());
- test_rvh()->SendNavigate(new_id, kUrl); // The same page_id returned.
+ EXPECT_FALSE(contents()->GetPendingMainFrame());
+ EXPECT_TRUE(last_rfh == contents()->GetMainFrame());
+ // Navigate using the returned page_id.
+ contents()->GetMainFrame()->SendNavigate(new_id, kUrl);
EXPECT_EQ(controller().GetLastCommittedEntryIndex(), 1);
EXPECT_FALSE(controller().GetPendingEntry());
// New message should be sent out to make sure to enter view-source mode.
@@ -788,13 +886,13 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
Source<WebContents>(web_contents.get()));
RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
- RenderFrameHostImpl* host;
+ RenderFrameHostImpl* host = NULL;
// 1) The first navigation. --------------------------
const GURL kUrl1("http://www.google.com/");
NavigationEntryImpl entry1(
NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
- base::string16() /* title */, PAGE_TRANSITION_TYPED,
+ base::string16() /* title */, ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
host = manager->Navigate(entry1);
@@ -807,16 +905,15 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
// Commit to SiteInstance should be delayed until RenderView commit.
EXPECT_TRUE(host == manager->current_frame_host());
ASSERT_TRUE(host);
- EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
- HasSite());
- static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
+ EXPECT_FALSE(host->GetSiteInstance()->HasSite());
+ host->GetSiteInstance()->SetSite(kUrl1);
// 2) Navigate to next site. -------------------------
const GURL kUrl2("http://www.google.com/foo");
NavigationEntryImpl entry2(
NULL /* instance */, -1 /* page_id */, kUrl2,
Referrer(kUrl1, blink::WebReferrerPolicyDefault),
- base::string16() /* title */, PAGE_TRANSITION_LINK,
+ base::string16() /* title */, ui::PAGE_TRANSITION_LINK,
true /* is_renderer_init */);
host = manager->Navigate(entry2);
@@ -828,15 +925,14 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
manager->DidNavigateFrame(host);
EXPECT_TRUE(host == manager->current_frame_host());
ASSERT_TRUE(host);
- EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
- HasSite());
+ EXPECT_TRUE(host->GetSiteInstance()->HasSite());
// 3) Cross-site navigate to next site. --------------
const GURL kUrl3("http://webkit.org/");
NavigationEntryImpl entry3(
NULL /* instance */, -1 /* page_id */, kUrl3,
Referrer(kUrl2, blink::WebReferrerPolicyDefault),
- base::string16() /* title */, PAGE_TRANSITION_LINK,
+ base::string16() /* title */, ui::PAGE_TRANSITION_LINK,
false /* is_renderer_init */);
host = manager->Navigate(entry3);
@@ -850,8 +946,7 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
manager->DidNavigateFrame(manager->pending_frame_host());
EXPECT_TRUE(host == manager->current_frame_host());
ASSERT_TRUE(host);
- EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
- HasSite());
+ EXPECT_TRUE(host->GetSiteInstance()->HasSite());
// Check the pending RenderFrameHost has been committed.
EXPECT_FALSE(manager->pending_frame_host());
@@ -860,194 +955,6 @@ TEST_F(RenderFrameHostManagerTest, Navigate) {
notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
}
-// Tests the Navigate function. In this unit test we verify that the Navigate
-// function can handle a new navigation event before the previous navigation
-// has been committed. This is also a regression test for
-// http://crbug.com/104600.
-TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyReNavigation) {
- TestNotificationTracker notifications;
-
- SiteInstance* instance = SiteInstance::Create(browser_context());
-
- scoped_ptr<TestWebContents> web_contents(
- TestWebContents::Create(browser_context(), instance));
- notifications.ListenFor(NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
- Source<WebContents>(web_contents.get()));
-
- RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
-
- // 1) The first navigation. --------------------------
- const GURL kUrl1("http://www.google.com/");
- NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
- Referrer(), base::string16() /* title */,
- PAGE_TRANSITION_TYPED,
- false /* is_renderer_init */);
- RenderFrameHostImpl* host = manager->Navigate(entry1);
-
- // The RenderFrameHost created in Init will be reused.
- EXPECT_TRUE(host == manager->current_frame_host());
- EXPECT_FALSE(manager->pending_frame_host());
-
- // We should observe a notification.
- EXPECT_TRUE(
- notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
- notifications.Reset();
-
- // Commit.
- manager->DidNavigateFrame(host);
-
- // Commit to SiteInstance should be delayed until RenderView commit.
- EXPECT_TRUE(host == manager->current_frame_host());
- ASSERT_TRUE(host);
- EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
- HasSite());
- static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
-
- // 2) Cross-site navigate to next site. -------------------------
- const GURL kUrl2("http://www.example.com");
- NavigationEntryImpl entry2(
- NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
- base::string16() /* title */, PAGE_TRANSITION_TYPED,
- false /* is_renderer_init */);
- RenderFrameHostImpl* host2 = manager->Navigate(entry2);
- int host2_process_id = host2->GetProcess()->GetID();
-
- // A new RenderFrameHost should be created.
- EXPECT_TRUE(manager->pending_frame_host());
- ASSERT_EQ(host2, manager->pending_frame_host());
- EXPECT_NE(host2, host);
-
- // Check that the navigation is still suspended because the old RVH
- // is not swapped out, yet.
- EXPECT_TRUE(host2->render_view_host()->are_navigations_suspended());
- MockRenderProcessHost* test_process_host2 =
- static_cast<MockRenderProcessHost*>(host2->GetProcess());
- test_process_host2->sink().ClearMessages();
- host2->render_view_host()->NavigateToURL(kUrl2);
- EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
- FrameMsg_Navigate::ID));
-
- // Allow closing the current Render View (precondition for swapping out
- // the RVH): Simulate response from RenderFrame for FrameMsg_BeforeUnload sent
- // by DispatchBeforeUnload.
- TestRenderViewHost* test_host =
- static_cast<TestRenderViewHost*>(host->render_view_host());
- MockRenderProcessHost* test_process_host =
- static_cast<MockRenderProcessHost*>(test_host->GetProcess());
- EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
- FrameMsg_BeforeUnload::ID));
- test_host->SendBeforeUnloadACK(true);
-
- // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
- // call of RenderFrameHostManager::SwapOutOldPage before
- // RenderFrameHostManager::DidNavigateFrame is called.
- // The RVH is swapped out after receiving the unload ack.
- manager->SwapOutOldPage();
- EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
- FrameMsg_SwapOut::ID));
- test_host->OnSwappedOut(false);
-
- EXPECT_EQ(host, manager->current_frame_host());
- EXPECT_FALSE(manager->current_frame_host()->is_swapped_out());
- EXPECT_EQ(host2, manager->pending_frame_host());
- // There should be still no navigation messages being sent.
- EXPECT_FALSE(test_process_host2->sink().GetUniqueMessageMatching(
- FrameMsg_Navigate::ID));
-
- // 3) Cross-site navigate to next site before 2) has committed. --------------
- const GURL kUrl3("http://webkit.org/");
- NavigationEntryImpl entry3(NULL /* instance */, -1 /* page_id */, kUrl3,
- Referrer(), base::string16() /* title */,
- PAGE_TRANSITION_TYPED,
- false /* is_renderer_init */);
- test_process_host->sink().ClearMessages();
- RenderFrameHostImpl* host3 = manager->Navigate(entry3);
-
- // A new RenderFrameHost should be created. host2 is now deleted.
- EXPECT_TRUE(manager->pending_frame_host());
- ASSERT_EQ(host3, manager->pending_frame_host());
- EXPECT_NE(host3, host);
- EXPECT_NE(host3->GetProcess()->GetID(), host2_process_id);
-
- // Navigations in the new RVH should be suspended.
- EXPECT_TRUE(static_cast<RenderViewHostImpl*>(
- host3->render_view_host())->are_navigations_suspended());
- EXPECT_EQ(host, manager->current_frame_host());
- EXPECT_FALSE(manager->current_frame_host()->is_swapped_out());
-
- // Simulate a response to the second beforeunload request.
- EXPECT_TRUE(test_process_host->sink().GetUniqueMessageMatching(
- FrameMsg_BeforeUnload::ID));
- test_host->SendBeforeUnloadACK(true);
-
- // CrossSiteResourceHandler::StartCrossSiteTransition triggers a
- // call of RenderFrameHostManager::SwapOutOldPage before
- // RenderFrameHostManager::DidNavigateFrame is called. Since the previous
- // navigation has already caused the renderer to start swapping out, there
- // will be no more SwapOut messages being sent.
- manager->SwapOutOldPage();
- EXPECT_FALSE(test_process_host->sink().GetUniqueMessageMatching(
- FrameMsg_SwapOut::ID));
- test_host->OnSwappedOut(false);
-
- // Commit.
- manager->DidNavigateFrame(host3);
- EXPECT_TRUE(host3 == manager->current_frame_host());
- ASSERT_TRUE(host3);
- EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host3->GetSiteInstance())->
- HasSite());
- // Check the pending RenderFrameHost has been committed.
- EXPECT_FALSE(manager->pending_frame_host());
-
- // We should observe a notification.
- EXPECT_TRUE(
- notifications.Check1AndReset(NOTIFICATION_RENDER_VIEW_HOST_CHANGED));
-}
-
-// Test that navigation is not blocked when we make new navigation before
-// previous one has been committed. This is also a regression test for
-// http://crbug.com/104600.
-TEST_F(RenderFrameHostManagerTest, NewCrossNavigationBetweenSwapOutAndCommit) {
- const GURL kUrl1("http://www.google.com/");
- const GURL kUrl2("http://www.chromium.org/");
- const GURL kUrl3("http://www.youtube.com/");
-
- contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
-
- // Keep active_view_count nonzero so that no swapped out views in
- // this SiteInstance get forcefully deleted.
- static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance())->
- increment_active_view_count();
-
- // Navigate but don't commit.
- contents()->GetController().LoadURL(
- kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
- EXPECT_TRUE(rvh1->is_waiting_for_beforeunload_ack());
- contents()->ProceedWithCrossSiteNavigation();
- EXPECT_FALSE(rvh1->is_waiting_for_beforeunload_ack());
- StartCrossSiteTransition(contents());
- EXPECT_TRUE(rvh1->IsWaitingForUnloadACK());
-
- rvh1->OnSwappedOut(false);
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
-
- TestRenderViewHost* rvh2 = pending_test_rvh();
- EXPECT_TRUE(rvh2);
- static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance())->
- increment_active_view_count();
-
- contents()->GetController().LoadURL(
- kUrl3, Referrer(), PAGE_TRANSITION_LINK, std::string());
- // Pending rvh2 is already deleted.
- contents()->ProceedWithCrossSiteNavigation();
-
- TestRenderViewHost* rvh3 = pending_test_rvh();
- EXPECT_TRUE(rvh3);
- // Navigation should be already unblocked by rvh1.
- EXPECT_FALSE(rvh3->are_navigations_suspended());
-}
-
// Tests WebUI creation.
TEST_F(RenderFrameHostManagerTest, WebUI) {
set_should_create_webui(true);
@@ -1062,7 +969,7 @@ TEST_F(RenderFrameHostManagerTest, WebUI) {
const GURL kUrl("chrome://foo");
NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl,
Referrer(), base::string16() /* title */,
- PAGE_TRANSITION_TYPED,
+ ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
RenderFrameHostImpl* host = manager->Navigate(entry);
@@ -1077,8 +984,7 @@ TEST_F(RenderFrameHostManagerTest, WebUI) {
// as the navigation starts, rather than lazily after it commits, so we don't
// try to re-use the SiteInstance/process for non Web UI things that may
// get loaded in between.
- EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
- HasSite());
+ EXPECT_TRUE(host->GetSiteInstance()->HasSite());
EXPECT_EQ(kUrl, host->GetSiteInstance()->GetSiteURL());
// The Web UI is committed immediately because the RenderViewHost has not been
@@ -1106,12 +1012,14 @@ TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
// Test the case that new RVH is considered live.
manager1->current_host()->CreateRenderView(
base::string16(), -1, MSG_ROUTING_NONE, -1, false);
+ EXPECT_TRUE(manager1->current_host()->IsRenderViewLive());
+ EXPECT_TRUE(manager1->current_frame_host()->IsRenderFrameLive());
// Navigate to a WebUI page.
const GURL kUrl1("chrome://foo");
NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
Referrer(), base::string16() /* title */,
- PAGE_TRANSITION_TYPED,
+ ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
RenderFrameHostImpl* host1 = manager1->Navigate(entry1);
@@ -1142,7 +1050,7 @@ TEST_F(RenderFrameHostManagerTest, WebUIInNewTab) {
const GURL kUrl2("chrome://foo/bar");
NavigationEntryImpl entry2(NULL /* instance */, -1 /* page_id */, kUrl2,
Referrer(), base::string16() /* title */,
- PAGE_TRANSITION_LINK,
+ ui::PAGE_TRANSITION_LINK,
true /* is_renderer_init */);
RenderFrameHostImpl* host2 = manager2->Navigate(entry2);
@@ -1162,42 +1070,46 @@ TEST_F(RenderFrameHostManagerTest, PageDoesBackAndReload) {
const GURL kUrl2("http://www.evil-site.com/");
// Navigate to a safe site, then an evil site.
- // This will switch RenderViewHosts. We cannot assert that the first and
- // second RVHs are different, though, because the first one may be promptly
+ // This will switch RenderFrameHosts. We cannot assert that the first and
+ // second RFHs are different, though, because the first one may be promptly
// deleted.
contents()->NavigateAndCommit(kUrl1);
contents()->NavigateAndCommit(kUrl2);
- RenderViewHost* evil_rvh = contents()->GetRenderViewHost();
+ TestRenderFrameHost* evil_rfh = contents()->GetMainFrame();
// Now let's simulate the evil page calling history.back().
contents()->OnGoToEntryAtOffset(-1);
- // We should have a new pending RVH.
- // Note that in this case, the navigation has not committed, so evil_rvh will
+ // We should have a new pending RFH.
+ // Note that in this case, the navigation has not committed, so evil_rfh will
// not be deleted yet.
- EXPECT_NE(evil_rvh, contents()->GetRenderManagerForTesting()->
- pending_render_view_host());
+ EXPECT_NE(evil_rfh, contents()->GetPendingMainFrame());
+ EXPECT_NE(evil_rfh->GetRenderViewHost(),
+ contents()->GetPendingMainFrame()->GetRenderViewHost());
- // Before that RVH has committed, the evil page reloads itself.
+ // Before that RFH has committed, the evil page reloads itself.
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
params.url = kUrl2;
- params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
+ params.transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
params.should_update_history = false;
params.gesture = NavigationGestureAuto;
params.was_within_same_page = false;
params.is_post = false;
params.page_state = PageState::CreateFromURL(kUrl2);
- RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(evil_rvh);
- RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(
- rvh->GetProcess()->GetID(), rvh->main_frame_routing_id());
- contents()->GetFrameTree()->root()->navigator()->DidNavigate(rfh, params);
+ contents()->GetFrameTree()->root()->navigator()->DidNavigate(evil_rfh,
+ params);
- // That should have cancelled the pending RVH, and the evil RVH should be the
+ // That should have cancelled the pending RFH, and the evil RFH should be the
// current one.
EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
pending_render_view_host() == NULL);
- EXPECT_EQ(evil_rvh, contents()->GetRenderManagerForTesting()->current_host());
+ EXPECT_TRUE(contents()->GetRenderManagerForTesting()->pending_frame_host() ==
+ NULL);
+ EXPECT_EQ(evil_rfh,
+ contents()->GetRenderManagerForTesting()->current_frame_host());
+ EXPECT_EQ(evil_rfh->GetRenderViewHost(),
+ contents()->GetRenderManagerForTesting()->current_host());
// Also we should not have a pending navigation entry.
EXPECT_TRUE(contents()->GetController().GetPendingEntry() == NULL);
@@ -1214,50 +1126,47 @@ TEST_F(RenderFrameHostManagerTest, NavigateAfterMissingSwapOutACK) {
// Navigate to two pages.
contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
+ TestRenderFrameHost* rfh1 = main_test_rfh();
- // Keep active_view_count nonzero so that no swapped out views in
+ // Keep active_frame_count nonzero so that no swapped out frames in
// this SiteInstance get forcefully deleted.
- static_cast<SiteInstanceImpl*>(rvh1->GetSiteInstance())->
- increment_active_view_count();
+ rfh1->GetSiteInstance()->increment_active_frame_count();
contents()->NavigateAndCommit(kUrl2);
- TestRenderViewHost* rvh2 = test_rvh();
- static_cast<SiteInstanceImpl*>(rvh2->GetSiteInstance())->
- increment_active_view_count();
+ TestRenderFrameHost* rfh2 = main_test_rfh();
+ rfh2->GetSiteInstance()->increment_active_frame_count();
// Now go back, but suppose the SwapOut_ACK isn't received. This shouldn't
// happen, but we have seen it when going back quickly across many entries
// (http://crbug.com/93427).
contents()->GetController().GoBack();
- EXPECT_TRUE(rvh2->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(rfh2->is_waiting_for_beforeunload_ack());
contents()->ProceedWithCrossSiteNavigation();
- EXPECT_FALSE(rvh2->is_waiting_for_beforeunload_ack());
- StartCrossSiteTransition(contents());
- EXPECT_TRUE(rvh2->IsWaitingForUnloadACK());
+ EXPECT_FALSE(rfh2->is_waiting_for_beforeunload_ack());
// The back navigation commits.
const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
- rvh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
- EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh2->rvh_state());
+ rfh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
+ EXPECT_TRUE(rfh2->IsWaitingForUnloadACK());
+ EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh2->rfh_state());
// We should be able to navigate forward.
contents()->GetController().GoForward();
contents()->ProceedWithCrossSiteNavigation();
- StartCrossSiteTransition(contents());
const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry();
- rvh2->SendNavigate(entry2->GetPageID(), entry2->GetURL());
- EXPECT_EQ(rvh2, rvh());
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
- EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh1->rvh_state());
- rvh1->OnSwappedOut(false);
- EXPECT_TRUE(rvh1->IsSwappedOut());
+ rfh2->SendNavigate(entry2->GetPageID(), entry2->GetURL());
+ EXPECT_EQ(rfh2, main_test_rfh());
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
+ 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());
}
-// Test that we create swapped out RVHs for the opener chain when navigating an
+// Test that we create swapped out RFHs for the opener chain when navigating an
// opened tab cross-process. This allows us to support certain cross-process
// JavaScript calls (http://crbug.com/99202).
-TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRVHs) {
+TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRFHs) {
const GURL kUrl1("http://www.google.com/");
const GURL kUrl2("http://www.chromium.org/");
const GURL kChromeUrl("chrome://foo");
@@ -1265,18 +1174,19 @@ TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRVHs) {
// Navigate to an initial URL.
contents()->NavigateAndCommit(kUrl1);
RenderFrameHostManager* manager = contents()->GetRenderManagerForTesting();
+ TestRenderFrameHost* rfh1 = main_test_rfh();
TestRenderViewHost* rvh1 = test_rvh();
// Create 2 new tabs and simulate them being the opener chain for the main
// tab. They should be in the same SiteInstance.
scoped_ptr<TestWebContents> opener1(
- TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
+ TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
RenderFrameHostManager* opener1_manager =
opener1->GetRenderManagerForTesting();
contents()->SetOpener(opener1.get());
scoped_ptr<TestWebContents> opener2(
- TestWebContents::Create(browser_context(), rvh1->GetSiteInstance()));
+ TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
RenderFrameHostManager* opener2_manager =
opener2->GetRenderManagerForTesting();
opener1->SetOpener(opener2.get());
@@ -1284,41 +1194,183 @@ TEST_F(RenderFrameHostManagerTest, CreateSwappedOutOpenerRVHs) {
// Navigate to a cross-site URL (different SiteInstance but same
// BrowsingInstance).
contents()->NavigateAndCommit(kUrl2);
+ TestRenderFrameHost* rfh2 = main_test_rfh();
TestRenderViewHost* rvh2 = test_rvh();
- EXPECT_NE(rvh1->GetSiteInstance(), rvh2->GetSiteInstance());
- EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
- rvh2->GetSiteInstance()));
+ EXPECT_NE(rfh1->GetSiteInstance(), rfh2->GetSiteInstance());
+ EXPECT_TRUE(rfh1->GetSiteInstance()->IsRelatedSiteInstance(
+ rfh2->GetSiteInstance()));
// Ensure rvh1 is placed on swapped out list of the current tab.
+ EXPECT_TRUE(manager->IsOnSwappedOutList(rfh1));
EXPECT_TRUE(manager->IsRVHOnSwappedOutList(rvh1));
+ EXPECT_EQ(rfh1,
+ manager->GetRenderFrameProxyHost(rfh1->GetSiteInstance())
+ ->render_frame_host());
EXPECT_EQ(rvh1,
manager->GetSwappedOutRenderViewHost(rvh1->GetSiteInstance()));
- // Ensure a swapped out RVH is created in the first opener tab.
+ // Ensure a swapped out RFH and RFH is created in the first opener tab.
+ RenderFrameProxyHost* opener1_proxy =
+ opener1_manager->GetRenderFrameProxyHost(rfh2->GetSiteInstance());
+ RenderFrameHostImpl* opener1_rfh = opener1_proxy->render_frame_host();
TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
+ EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rfh));
EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
- EXPECT_TRUE(opener1_rvh->IsSwappedOut());
+ EXPECT_TRUE(opener1_rfh->is_swapped_out());
+ EXPECT_FALSE(opener1_rvh->is_active());
- // Ensure a swapped out RVH is created in the second opener tab.
+ // Ensure a swapped out RFH and RVH is created in the second opener tab.
+ RenderFrameProxyHost* opener2_proxy =
+ opener2_manager->GetRenderFrameProxyHost(rfh2->GetSiteInstance());
+ RenderFrameHostImpl* opener2_rfh = opener2_proxy->render_frame_host();
TestRenderViewHost* opener2_rvh = static_cast<TestRenderViewHost*>(
opener2_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
+ EXPECT_TRUE(opener2_manager->IsOnSwappedOutList(opener2_rfh));
EXPECT_TRUE(opener2_manager->IsRVHOnSwappedOutList(opener2_rvh));
- EXPECT_TRUE(opener2_rvh->IsSwappedOut());
+ EXPECT_TRUE(opener2_rfh->is_swapped_out());
+ EXPECT_FALSE(opener2_rvh->is_active());
// Navigate to a cross-BrowsingInstance URL.
contents()->NavigateAndCommit(kChromeUrl);
- TestRenderViewHost* rvh3 = test_rvh();
- EXPECT_NE(rvh1->GetSiteInstance(), rvh3->GetSiteInstance());
- EXPECT_FALSE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
- rvh3->GetSiteInstance()));
+ TestRenderFrameHost* rfh3 = main_test_rfh();
+ EXPECT_NE(rfh1->GetSiteInstance(), rfh3->GetSiteInstance());
+ EXPECT_FALSE(rfh1->GetSiteInstance()->IsRelatedSiteInstance(
+ rfh3->GetSiteInstance()));
// No scripting is allowed across BrowsingInstances, so we should not create
// swapped out RVHs for the opener chain in this case.
+ EXPECT_FALSE(opener1_manager->GetRenderFrameProxyHost(
+ rfh3->GetSiteInstance()));
EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
- rvh3->GetSiteInstance()));
+ rfh3->GetSiteInstance()));
+ EXPECT_FALSE(opener2_manager->GetRenderFrameProxyHost(
+ rfh3->GetSiteInstance()));
EXPECT_FALSE(opener2_manager->GetSwappedOutRenderViewHost(
- rvh3->GetSiteInstance()));
+ rfh3->GetSiteInstance()));
+}
+
+// Test that a page can disown the opener of the WebContents.
+TEST_F(RenderFrameHostManagerTest, DisownOpener) {
+ const GURL kUrl1("http://www.google.com/");
+ const GURL kUrl2("http://www.chromium.org/");
+
+ // Navigate to an initial URL.
+ contents()->NavigateAndCommit(kUrl1);
+ TestRenderFrameHost* rfh1 = main_test_rfh();
+
+ // Create a new tab and simulate having it be the opener for the main tab.
+ scoped_ptr<TestWebContents> opener1(
+ TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
+ contents()->SetOpener(opener1.get());
+ EXPECT_TRUE(contents()->HasOpener());
+
+ // Navigate to a cross-site URL (different SiteInstance but same
+ // BrowsingInstance).
+ contents()->NavigateAndCommit(kUrl2);
+ TestRenderFrameHost* rfh2 = main_test_rfh();
+ EXPECT_NE(rfh1->GetSiteInstance(), rfh2->GetSiteInstance());
+
+ // Disown the opener from rfh2.
+ rfh2->DidDisownOpener();
+
+ // Ensure the opener is cleared.
+ EXPECT_FALSE(contents()->HasOpener());
+}
+
+// Test that a page can disown a same-site opener of the WebContents.
+TEST_F(RenderFrameHostManagerTest, DisownSameSiteOpener) {
+ const GURL kUrl1("http://www.google.com/");
+
+ // Navigate to an initial URL.
+ contents()->NavigateAndCommit(kUrl1);
+ TestRenderFrameHost* rfh1 = main_test_rfh();
+
+ // Create a new tab and simulate having it be the opener for the main tab.
+ scoped_ptr<TestWebContents> opener1(
+ TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
+ contents()->SetOpener(opener1.get());
+ EXPECT_TRUE(contents()->HasOpener());
+
+ // Disown the opener from rfh1.
+ rfh1->DidDisownOpener();
+
+ // Ensure the opener is cleared even if it is in the same process.
+ EXPECT_FALSE(contents()->HasOpener());
+}
+
+// Test that a page can disown the opener just as a cross-process navigation is
+// in progress.
+TEST_F(RenderFrameHostManagerTest, DisownOpenerDuringNavigation) {
+ const GURL kUrl1("http://www.google.com/");
+ const GURL kUrl2("http://www.chromium.org/");
+
+ // Navigate to an initial URL.
+ contents()->NavigateAndCommit(kUrl1);
+ TestRenderFrameHost* rfh1 = main_test_rfh();
+
+ // Create a new tab and simulate having it be the opener for the main tab.
+ scoped_ptr<TestWebContents> opener1(
+ TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
+ contents()->SetOpener(opener1.get());
+ EXPECT_TRUE(contents()->HasOpener());
+
+ // Navigate to a cross-site URL (different SiteInstance but same
+ // BrowsingInstance).
+ contents()->NavigateAndCommit(kUrl2);
+ TestRenderFrameHost* rfh2 = main_test_rfh();
+ EXPECT_NE(rfh1->GetSiteInstance(), rfh2->GetSiteInstance());
+
+ // Start a back navigation so that rfh1 becomes the pending RFH.
+ contents()->GetController().GoBack();
+ contents()->ProceedWithCrossSiteNavigation();
+
+ // Disown the opener from rfh2.
+ rfh2->DidDisownOpener();
+
+ // Ensure the opener is cleared.
+ EXPECT_FALSE(contents()->HasOpener());
+
+ // The back navigation commits.
+ const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
+ rfh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
+
+ // Ensure the opener is still cleared.
+ EXPECT_FALSE(contents()->HasOpener());
+}
+
+// Test that a page can disown the opener just after a cross-process navigation
+// commits.
+TEST_F(RenderFrameHostManagerTest, DisownOpenerAfterNavigation) {
+ const GURL kUrl1("http://www.google.com/");
+ const GURL kUrl2("http://www.chromium.org/");
+
+ // Navigate to an initial URL.
+ contents()->NavigateAndCommit(kUrl1);
+ TestRenderFrameHost* rfh1 = main_test_rfh();
+
+ // Create a new tab and simulate having it be the opener for the main tab.
+ scoped_ptr<TestWebContents> opener1(
+ TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
+ contents()->SetOpener(opener1.get());
+ EXPECT_TRUE(contents()->HasOpener());
+
+ // Navigate to a cross-site URL (different SiteInstance but same
+ // BrowsingInstance).
+ contents()->NavigateAndCommit(kUrl2);
+ TestRenderFrameHost* rfh2 = main_test_rfh();
+ EXPECT_NE(rfh1->GetSiteInstance(), rfh2->GetSiteInstance());
+
+ // Commit a back navigation before the DidDisownOpener message arrives.
+ // rfh1 will be kept alive because of the opener tab.
+ contents()->GetController().GoBack();
+ contents()->ProceedWithCrossSiteNavigation();
+ const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
+ rfh1->SendNavigate(entry1->GetPageID(), entry1->GetURL());
+
+ // Disown the opener from rfh2.
+ rfh2->DidDisownOpener();
+ EXPECT_FALSE(contents()->HasOpener());
}
// Test that we clean up swapped out RenderViewHosts when a process hosting
@@ -1341,6 +1393,8 @@ TEST_F(RenderFrameHostManagerTest, CleanUpSwappedOutRVHOnProcessCrash) {
// Make sure the new opener RVH is considered live.
opener1_manager->current_host()->CreateRenderView(
base::string16(), -1, MSG_ROUTING_NONE, -1, false);
+ EXPECT_TRUE(opener1_manager->current_host()->IsRenderViewLive());
+ EXPECT_TRUE(opener1_manager->current_frame_host()->IsRenderFrameLive());
// Use a cross-process navigation in the opener to swap out the old RVH.
EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
@@ -1403,11 +1457,16 @@ TEST_F(RenderFrameHostManagerTest, EnableWebUIWithSwappedOutOpener) {
EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
rvh2->GetSiteInstance()));
- // Ensure a swapped out RVH is created in the first opener tab.
+ // Ensure a swapped out RFH and RVH is created in the first opener tab.
+ RenderFrameProxyHost* opener1_proxy =
+ opener1_manager->GetRenderFrameProxyHost(rvh2->GetSiteInstance());
+ RenderFrameHostImpl* opener1_rfh = opener1_proxy->render_frame_host();
TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
+ EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rfh));
EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
- EXPECT_TRUE(opener1_rvh->IsSwappedOut());
+ EXPECT_TRUE(opener1_rfh->is_swapped_out());
+ EXPECT_FALSE(opener1_rvh->is_active());
// Ensure the new RVH has WebUI bindings.
EXPECT_TRUE(rvh2->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
@@ -1425,13 +1484,13 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
- RenderFrameHostImpl* host;
+ RenderFrameHostImpl* host = NULL;
// 1) The first navigation. --------------------------
const GURL kUrl1("http://www.google.com/");
NavigationEntryImpl entry1(
NULL /* instance */, -1 /* page_id */, kUrl1, Referrer(),
- base::string16() /* title */, PAGE_TRANSITION_TYPED,
+ base::string16() /* title */, ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
host = manager->Navigate(entry1);
@@ -1445,8 +1504,7 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
// Commit to SiteInstance should be delayed until RenderView commit.
EXPECT_EQ(host, manager->current_frame_host());
ASSERT_TRUE(host);
- EXPECT_TRUE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
- HasSite());
+ EXPECT_TRUE(host->GetSiteInstance()->HasSite());
// 2) Navigate to a different domain. -------------------------
// Guests stay in the same process on navigation.
@@ -1454,7 +1512,7 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
NavigationEntryImpl entry2(
NULL /* instance */, -1 /* page_id */, kUrl2,
Referrer(kUrl1, blink::WebReferrerPolicyDefault),
- base::string16() /* title */, PAGE_TRANSITION_LINK,
+ base::string16() /* title */, ui::PAGE_TRANSITION_LINK,
true /* is_renderer_init */);
host = manager->Navigate(entry2);
@@ -1466,8 +1524,7 @@ TEST_F(RenderFrameHostManagerTest, NoSwapOnGuestNavigations) {
manager->DidNavigateFrame(host);
EXPECT_EQ(host, manager->current_frame_host());
ASSERT_TRUE(host);
- EXPECT_EQ(static_cast<SiteInstanceImpl*>(host->GetSiteInstance()),
- instance);
+ EXPECT_EQ(host->GetSiteInstance(), instance);
}
// Test that we cancel a pending RVH if we close the tab while it's pending.
@@ -1490,7 +1547,7 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
const GURL kUrl1("http://www.google.com/");
NavigationEntryImpl entry1(NULL /* instance */, -1 /* page_id */, kUrl1,
Referrer(), base::string16() /* title */,
- PAGE_TRANSITION_TYPED,
+ ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
RenderFrameHostImpl* host = manager->Navigate(entry1);
@@ -1508,15 +1565,14 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
// Commit to SiteInstance should be delayed until RenderFrame commits.
EXPECT_EQ(host, manager->current_frame_host());
- EXPECT_FALSE(static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->
- HasSite());
- static_cast<SiteInstanceImpl*>(host->GetSiteInstance())->SetSite(kUrl1);
+ EXPECT_FALSE(host->GetSiteInstance()->HasSite());
+ host->GetSiteInstance()->SetSite(kUrl1);
// 2) Cross-site navigate to next site. -------------------------
const GURL kUrl2("http://www.example.com");
NavigationEntryImpl entry2(
NULL /* instance */, -1 /* page_id */, kUrl2, Referrer(),
- base::string16() /* title */, PAGE_TRANSITION_TYPED,
+ base::string16() /* title */, ui::PAGE_TRANSITION_TYPED,
false /* is_renderer_init */);
RenderFrameHostImpl* host2 = manager->Navigate(entry2);
@@ -1539,214 +1595,118 @@ TEST_F(RenderFrameHostManagerTest, NavigateWithEarlyClose) {
EXPECT_EQ(host, manager->current_frame_host());
}
-// Tests that the RenderViewHost is properly deleted when the SwapOutACK is
-// received before the new page commits.
-TEST_F(RenderFrameHostManagerTest,
- SwapOutACKBeforeNewPageCommitsLeadsToDeletion) {
+TEST_F(RenderFrameHostManagerTest, CloseWithPendingWhileUnresponsive) {
const GURL kUrl1("http://www.google.com/");
const GURL kUrl2("http://www.chromium.org/");
- // Navigate to the first page.
- contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
- RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
-
- // Navigate to new site, simulating onbeforeunload approval.
- controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
- base::TimeTicks now = base::TimeTicks::Now();
- main_test_rfh()->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_TRUE(contents()->cross_navigation_pending());
- TestRenderViewHost* rvh2 =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
-
- // Simulate rvh2's response, which leads to an unload request being sent to
- // rvh1.
- std::vector<GURL> url_chain;
- url_chain.push_back(GURL());
- contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
- contents()->GetRenderManagerForTesting()->pending_frame_host(),
- GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
- url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
- EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
- rvh1->rvh_state());
-
- // Simulate the swap out ack.
- rvh1->OnSwappedOut(false);
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
-
- // The new page commits.
- contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(rvh2, rvh());
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
-
- // rvh1 should have been deleted.
- EXPECT_TRUE(rvh_deleted_observer.deleted());
- rvh1 = NULL;
-}
-
-// Tests that the RenderViewHost is properly swapped out when the SwapOutACK is
-// received before the new page commits.
-TEST_F(RenderFrameHostManagerTest,
- SwapOutACKBeforeNewPageCommitsLeadsToSwapOut) {
- const GURL kUrl1("http://www.google.com/");
- const GURL kUrl2("http://www.chromium.org/");
+ CloseWebContentsDelegate close_delegate;
+ contents()->SetDelegate(&close_delegate);
// Navigate to the first page.
contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
- RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+ TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
- // Increment the number of active views in SiteInstanceImpl so that rvh2 is
- // not deleted on swap out.
- static_cast<SiteInstanceImpl*>(
- rvh1->GetSiteInstance())->increment_active_view_count();
+ // Start to close the tab, but assume it's unresponsive.
+ rfh1->render_view_host()->ClosePage();
+ EXPECT_TRUE(rfh1->render_view_host()->is_waiting_for_close_ack());
- // Navigate to new site, simulating onbeforeunload approval.
- controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
- base::TimeTicks now = base::TimeTicks::Now();
- main_test_rfh()->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_TRUE(contents()->cross_navigation_pending());
- TestRenderViewHost* rvh2 =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
-
- // Simulate rvh2's response, which leads to an unload request being sent to
- // rvh1.
- std::vector<GURL> url_chain;
- url_chain.push_back(GURL());
- contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
- contents()->GetRenderManagerForTesting()->pending_frame_host(),
- GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
- url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
+ // Start a navigation to a new site.
+ controller().LoadURL(
+ kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
- rvh1->rvh_state());
- // Simulate the swap out ack.
- rvh1->OnSwappedOut(false);
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_COMMIT, rvh1->rvh_state());
-
- // The new page commits.
- contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(rvh2, rvh());
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
-
- // rvh1 should be swapped out.
- EXPECT_FALSE(rvh_deleted_observer.deleted());
- EXPECT_TRUE(rvh1->IsSwappedOut());
+ // Simulate the unresponsiveness timer. The tab should close.
+ contents()->RendererUnresponsive(rfh1->render_view_host());
+ EXPECT_TRUE(close_delegate.is_closed());
}
-// Tests that the RenderViewHost is properly deleted when the new
-// page commits before the swap out ack is received.
-TEST_F(RenderFrameHostManagerTest,
- NewPageCommitsBeforeSwapOutACKLeadsToDeletion) {
+// Tests that the RenderFrameHost is properly deleted when the SwapOutACK is
+// received. (SwapOut and the corresponding ACK always occur after commit.)
+// Also tests that an early SwapOutACK is properly ignored.
+TEST_F(RenderFrameHostManagerTest, DeleteFrameAfterSwapOutACK) {
const GURL kUrl1("http://www.google.com/");
const GURL kUrl2("http://www.chromium.org/");
// Navigate to the first page.
contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
- RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+ TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+ RenderFrameHostDeletedObserver rfh_deleted_observer(rfh1);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
// Navigate to new site, simulating onbeforeunload approval.
- controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ controller().LoadURL(
+ kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
base::TimeTicks now = base::TimeTicks::Now();
- main_test_rfh()->OnMessageReceived(
+ contents()->GetMainFrame()->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
EXPECT_TRUE(contents()->cross_navigation_pending());
- TestRenderViewHost* rvh2 =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
-
- // Simulate rvh2's response, which leads to an unload request being sent to
- // rvh1.
- std::vector<GURL> url_chain;
- url_chain.push_back(GURL());
- contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
- contents()->GetRenderManagerForTesting()->pending_frame_host(),
- GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
- url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
+
+ // Simulate the swap out ack, unexpectedly early (before commit). It should
+ // have no effect.
+ rfh1->OnSwappedOut();
EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
- rvh1->rvh_state());
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
// The new page commits.
- contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(rfh2, 1, kUrl2, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(rvh2, rvh());
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
- EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SHUTDOWN, rvh1->rvh_state());
+ 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));
// Simulate the swap out ack.
- rvh1->OnSwappedOut(false);
+ rfh1->OnSwappedOut();
- // rvh1 should have been deleted.
- EXPECT_TRUE(rvh_deleted_observer.deleted());
- rvh1 = NULL;
+ // rfh1 should have been deleted.
+ EXPECT_TRUE(rfh_deleted_observer.deleted());
+ rfh1 = NULL;
}
-// Tests that the RenderViewHost is properly swapped out when the new page
-// commits before the swap out ack is received.
-TEST_F(RenderFrameHostManagerTest,
- NewPageCommitsBeforeSwapOutACKLeadsToSwapOut) {
+// Tests that the RenderFrameHost is properly swapped out when the SwapOut ACK
+// is received. (SwapOut and the corresponding ACK always occur after commit.)
+TEST_F(RenderFrameHostManagerTest, SwapOutFrameAfterSwapOutACK) {
const GURL kUrl1("http://www.google.com/");
const GURL kUrl2("http://www.chromium.org/");
// Navigate to the first page.
contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
- RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+ TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+ RenderFrameHostDeletedObserver rfh_deleted_observer(rfh1);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
- // Increment the number of active views in SiteInstanceImpl so that rvh1 is
+ // Increment the number of active frames in SiteInstanceImpl so that rfh1 is
// not deleted on swap out.
- static_cast<SiteInstanceImpl*>(
- rvh1->GetSiteInstance())->increment_active_view_count();
+ rfh1->GetSiteInstance()->increment_active_frame_count();
// Navigate to new site, simulating onbeforeunload approval.
- controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ controller().LoadURL(
+ kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
base::TimeTicks now = base::TimeTicks::Now();
- main_test_rfh()->OnMessageReceived(
+ contents()->GetMainFrame()->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
EXPECT_TRUE(contents()->cross_navigation_pending());
- TestRenderViewHost* rvh2 =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
-
- // Simulate rvh2's response, which leads to an unload request being sent to
- // rvh1.
- std::vector<GURL> url_chain;
- url_chain.push_back(GURL());
- contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
- contents()->GetRenderManagerForTesting()->pending_frame_host(),
- GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
- url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
- EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_EQ(RenderViewHostImpl::STATE_WAITING_FOR_UNLOAD_ACK,
- rvh1->rvh_state());
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
+ TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
// The new page commits.
- contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(rfh2, 1, kUrl2, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(rvh2, rvh());
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
- EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh1->rvh_state());
+ 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());
// Simulate the swap out ack.
- rvh1->OnSwappedOut(false);
+ rfh1->OnSwappedOut();
- // rvh1 should be swapped out.
- EXPECT_FALSE(rvh_deleted_observer.deleted());
- EXPECT_TRUE(rvh1->IsSwappedOut());
+ // rfh1 should be swapped out.
+ EXPECT_FALSE(rfh_deleted_observer.deleted());
+ EXPECT_TRUE(rfh1->is_swapped_out());
}
// Test that the RenderViewHost is properly swapped out if a navigation in the
@@ -1760,38 +1720,37 @@ TEST_F(RenderFrameHostManagerTest,
// Navigate to the first page.
contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
- RenderViewHostDeletedObserver rvh_deleted_observer(rvh1);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+ TestRenderFrameHost* rfh1 = contents()->GetMainFrame();
+ RenderFrameHostDeletedObserver rfh_deleted_observer(rfh1);
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
- // Increment the number of active views in SiteInstanceImpl so that rvh1 is
+ // Increment the number of active frames in SiteInstanceImpl so that rfh1 is
// not deleted on swap out.
- static_cast<SiteInstanceImpl*>(
- rvh1->GetSiteInstance())->increment_active_view_count();
+ rfh1->GetSiteInstance()->increment_active_frame_count();
// Navigate to new site, simulating onbeforeunload approval.
- controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ controller().LoadURL(
+ kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
base::TimeTicks now = base::TimeTicks::Now();
- main_test_rfh()->OnMessageReceived(
+ rfh1->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
EXPECT_TRUE(contents()->cross_navigation_pending());
- TestRenderViewHost* rvh2 =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+ TestRenderFrameHost* rfh2 = contents()->GetPendingMainFrame();
// The new page commits.
- contents()->TestDidNavigate(rvh2, 1, kUrl2, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(rfh2, 1, kUrl2, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(rvh2, rvh());
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh2->rvh_state());
- EXPECT_EQ(RenderViewHostImpl::STATE_PENDING_SWAP_OUT, rvh1->rvh_state());
+ 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());
// Simulate the swap out ack.
- rvh1->OnSwappedOut(false);
+ rfh1->OnSwappedOut();
- // rvh1 should be swapped out.
- EXPECT_FALSE(rvh_deleted_observer.deleted());
- EXPECT_TRUE(rvh1->IsSwappedOut());
+ // rfh1 should be swapped out.
+ EXPECT_FALSE(rfh_deleted_observer.deleted());
+ EXPECT_TRUE(rfh1->is_swapped_out());
}
// Test that a RenderFrameHost is properly deleted or swapped out when a
@@ -1805,42 +1764,43 @@ TEST_F(RenderFrameHostManagerTest,
// Navigate to the first page.
contents()->NavigateAndCommit(kUrl1);
- TestRenderViewHost* rvh1 = test_rvh();
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, rvh1->rvh_state());
+ TestRenderFrameHost* rfh1 = main_test_rfh();
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh1->rfh_state());
// Navigate to a new site, starting a cross-site navigation.
- controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ controller().LoadURL(
+ kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
{
pending_rfh = contents()->GetFrameTree()->root()->render_manager()
->pending_frame_host();
- RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
+ RenderFrameHostDeletedObserver rfh_deleted_observer(pending_rfh);
// Cancel the navigation by simulating a declined beforeunload dialog.
- main_test_rfh()->OnMessageReceived(
+ contents()->GetMainFrame()->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
EXPECT_FALSE(contents()->cross_navigation_pending());
// Since the pending RFH is the only one for the new SiteInstance, it should
// be deleted.
- EXPECT_TRUE(rvh_deleted_observer.deleted());
+ EXPECT_TRUE(rfh_deleted_observer.deleted());
}
// Start another cross-site navigation.
- controller().LoadURL(kUrl2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ controller().LoadURL(
+ kUrl2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
{
pending_rfh = contents()->GetFrameTree()->root()->render_manager()
->pending_frame_host();
- RenderFrameHostDeletedObserver rvh_deleted_observer(pending_rfh);
+ RenderFrameHostDeletedObserver rfh_deleted_observer(pending_rfh);
- // Increment the number of active views in the new SiteInstance, which will
+ // Increment the number of active frames in the new SiteInstance, which will
// cause the pending RFH to be swapped out instead of deleted.
- static_cast<SiteInstanceImpl*>(
- pending_rfh->GetSiteInstance())->increment_active_view_count();
+ pending_rfh->GetSiteInstance()->increment_active_frame_count();
- main_test_rfh()->OnMessageReceived(
+ contents()->GetMainFrame()->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_FALSE(rvh_deleted_observer.deleted());
+ EXPECT_FALSE(rfh_deleted_observer.deleted());
}
}
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 25f7fbd57ad..0de54b10e83 100644
--- a/chromium/content/browser/frame_host/render_frame_message_filter.h
+++ b/chromium/content/browser/frame_host/render_frame_message_filter.h
@@ -21,10 +21,10 @@ class RenderFrameMessageFilter : public BrowserMessageFilter {
RenderFrameMessageFilter(int render_process_id,
RenderWidgetHelper* render_widget_helper);
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
- virtual ~RenderFrameMessageFilter();
+ ~RenderFrameMessageFilter() override;
void OnCreateChildFrame(int parent_routing_id,
const std::string& frame_name,
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 2c84798fa2c..3db9edf613d 100644
--- a/chromium/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/chromium/content/browser/frame_host/render_frame_proxy_host.cc
@@ -4,23 +4,52 @@
#include "content/browser/frame_host/render_frame_proxy_host.h"
+#include "base/lazy_instance.h"
#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/render_frame_host_impl.h"
#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/site_instance_impl.h"
#include "content/common/frame_messages.h"
+#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_message.h"
namespace content {
+namespace {
+
+// The (process id, routing id) pair that identifies one RenderFrameProxy.
+typedef std::pair<int32, int32> RenderFrameProxyHostID;
+typedef base::hash_map<RenderFrameProxyHostID, RenderFrameProxyHost*>
+ RoutingIDFrameProxyMap;
+base::LazyInstance<RoutingIDFrameProxyMap> g_routing_id_frame_proxy_map =
+ LAZY_INSTANCE_INITIALIZER;
+
+}
+
+// static
+RenderFrameProxyHost* RenderFrameProxyHost::FromID(int process_id,
+ int routing_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ RoutingIDFrameProxyMap* frames = g_routing_id_frame_proxy_map.Pointer();
+ RoutingIDFrameProxyMap::iterator it = frames->find(
+ RenderFrameProxyHostID(process_id, routing_id));
+ return it == frames->end() ? NULL : it->second;
+}
+
RenderFrameProxyHost::RenderFrameProxyHost(SiteInstance* site_instance,
FrameTreeNode* frame_tree_node)
: routing_id_(site_instance->GetProcess()->GetNextRoutingID()),
site_instance_(site_instance),
frame_tree_node_(frame_tree_node) {
GetProcess()->AddRoute(routing_id_, this);
+ CHECK(g_routing_id_frame_proxy_map.Get().insert(
+ std::make_pair(
+ RenderFrameProxyHostID(GetProcess()->GetID(), routing_id_),
+ this)).second);
if (!frame_tree_node_->IsMainFrame() &&
frame_tree_node_->parent()
@@ -39,10 +68,18 @@ RenderFrameProxyHost::RenderFrameProxyHost(SiteInstance* site_instance,
}
RenderFrameProxyHost::~RenderFrameProxyHost() {
- if (GetProcess()->HasConnection())
- Send(new FrameMsg_DeleteProxy(routing_id_));
+ if (GetProcess()->HasConnection()) {
+ // TODO(nasko): For now, don't send this IPC for top-level frames, as
+ // the top-level RenderFrame will delete the RenderFrameProxy.
+ // This can be removed once we don't have a swapped out state on
+ // RenderFrame. See https://crbug.com/357747
+ if (!frame_tree_node_->IsMainFrame())
+ Send(new FrameMsg_DeleteProxy(routing_id_));
+ }
GetProcess()->RemoveRoute(routing_id_);
+ g_routing_id_frame_proxy_map.Get().erase(
+ RenderFrameProxyHostID(GetProcess()->GetID(), routing_id_));
}
void RenderFrameProxyHost::SetChildRWHView(RenderWidgetHostView* view) {
@@ -51,9 +88,14 @@ void RenderFrameProxyHost::SetChildRWHView(RenderWidgetHostView* view) {
}
RenderViewHostImpl* RenderFrameProxyHost::GetRenderViewHost() {
- if (render_frame_host_.get())
- return render_frame_host_->render_view_host();
- return NULL;
+ return frame_tree_node_->frame_tree()->GetRenderViewHost(
+ site_instance_.get());
+}
+
+void RenderFrameProxyHost::TakeFrameHostOwnership(
+ scoped_ptr<RenderFrameHostImpl> render_frame_host) {
+ render_frame_host_ = render_frame_host.Pass();
+ render_frame_host_->set_render_frame_proxy_host(this);
}
scoped_ptr<RenderFrameHostImpl> RenderFrameProxyHost::PassFrameHostOwnership() {
@@ -65,7 +107,11 @@ bool RenderFrameProxyHost::Send(IPC::Message *msg) {
// TODO(nasko): For now, RenderFrameHost uses this object to send IPC messages
// while swapped out. This can be removed once we don't have a swapped out
// state on RenderFrameHosts. See https://crbug.com/357747.
- msg->set_routing_id(routing_id_);
+
+ // Don't reset the routing ID for control messages. See
+ // https://crbug.com/423538
+ if (msg->routing_id() != MSG_ROUTING_CONTROL)
+ msg->set_routing_id(routing_id_);
return GetProcess()->Send(msg);
}
@@ -79,7 +125,48 @@ bool RenderFrameProxyHost::OnMessageReceived(const IPC::Message& msg) {
if (render_frame_host_.get())
return render_frame_host_->OnMessageReceived(msg);
- return false;
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(RenderFrameProxyHost, msg)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+bool RenderFrameProxyHost::InitRenderFrameProxy() {
+ // The process may (if we're sharing a process with another host that already
+ // initialized it) or may not (we have our own process or the old process
+ // crashed) have been initialized. Calling Init multiple times will be
+ // ignored, so this is safe.
+ if (!site_instance_->GetProcess()->Init())
+ return false;
+
+ DCHECK(GetProcess()->HasConnection());
+
+ int parent_routing_id = MSG_ROUTING_NONE;
+ if (frame_tree_node_->parent()) {
+ parent_routing_id = frame_tree_node_->parent()
+ ->render_manager()
+ ->GetRoutingIdForSiteInstance(site_instance_.get());
+ CHECK_NE(parent_routing_id, MSG_ROUTING_NONE);
+ }
+
+ Send(new FrameMsg_NewFrameProxy(routing_id_,
+ parent_routing_id,
+ frame_tree_node_->frame_tree()
+ ->GetRenderViewHost(site_instance_.get())
+ ->GetRoutingID()));
+
+ return true;
+}
+
+void RenderFrameProxyHost::DisownOpener() {
+ Send(new FrameMsg_DisownOpener(GetRoutingID()));
+}
+
+void RenderFrameProxyHost::OnOpenURL(
+ const FrameHostMsg_OpenURL_Params& params) {
+ frame_tree_node_->current_frame_host()->OpenURL(params);
}
} // namespace content
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 218bcc411df..ed3235ca98b 100644
--- a/chromium/content/browser/frame_host/render_frame_proxy_host.h
+++ b/chromium/content/browser/frame_host/render_frame_proxy_host.h
@@ -55,14 +55,20 @@ class RenderFrameProxyHost
: public IPC::Listener,
public IPC::Sender {
public:
+ static RenderFrameProxyHost* FromID(int process_id, int routing_id);
+
RenderFrameProxyHost(SiteInstance* site_instance,
FrameTreeNode* frame_tree_node);
- virtual ~RenderFrameProxyHost();
+ ~RenderFrameProxyHost() override;
RenderProcessHost* GetProcess() {
return site_instance_->GetProcess();
}
+ // Initializes the object and creates the RenderFrameProxy in the process
+ // for the SiteInstance.
+ bool InitRenderFrameProxy();
+
int GetRoutingID() {
return routing_id_;
}
@@ -71,6 +77,8 @@ class RenderFrameProxyHost
return site_instance_.get();
}
+ FrameTreeNode* frame_tree_node() const { return frame_tree_node_; };
+
void SetChildRWHView(RenderWidgetHostView* view);
// TODO(nasko): The following methods should be removed once we don't have a
@@ -81,22 +89,27 @@ class RenderFrameProxyHost
RenderViewHostImpl* GetRenderViewHost();
void TakeFrameHostOwnership(
- scoped_ptr<RenderFrameHostImpl> render_frame_host) {
- render_frame_host_ = render_frame_host.Pass();
- }
+ scoped_ptr<RenderFrameHostImpl> render_frame_host);
scoped_ptr<RenderFrameHostImpl> PassFrameHostOwnership();
// IPC::Sender
- virtual bool Send(IPC::Message* msg) OVERRIDE;
+ bool Send(IPC::Message* msg) override;
// IPC::Listener
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
CrossProcessFrameConnector* cross_process_frame_connector() {
return cross_process_frame_connector_.get();
}
+ // Set the frame's opener to null in the renderer process in response to an
+ // action in another renderer process.
+ void DisownOpener();
+
private:
+ // IPC Message handlers.
+ void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
+
// This RenderFrameProxyHost's routing id.
int routing_id_;
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 d9e32c92c8b..ab1bff89c81 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
@@ -4,6 +4,7 @@
#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/frame_host/cross_process_frame_connector.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/gpu/gpu_messages.h"
@@ -70,6 +71,10 @@ gfx::Rect RenderWidgetHostViewChildFrame::GetViewBounds() const {
return rect;
}
+gfx::Vector2dF RenderWidgetHostViewChildFrame::GetLastScrollOffset() const {
+ return last_scroll_offset_;
+}
+
gfx::NativeView RenderWidgetHostViewChildFrame::GetNativeView() const {
NOTREACHED();
return NULL;
@@ -86,7 +91,7 @@ RenderWidgetHostViewChildFrame::GetNativeViewAccessible() {
return NULL;
}
-void RenderWidgetHostViewChildFrame::SetBackgroundOpaque(bool opaque) {
+void RenderWidgetHostViewChildFrame::SetBackgroundColor(SkColor color) {
}
gfx::Size RenderWidgetHostViewChildFrame::GetPhysicalBackingSize() const {
@@ -111,7 +116,7 @@ void RenderWidgetHostViewChildFrame::ImeCancelComposition() {
NOTREACHED();
}
-#if defined(OS_MACOSX) || defined(USE_AURA)
+#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
void RenderWidgetHostViewChildFrame::ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
@@ -122,7 +127,7 @@ void RenderWidgetHostViewChildFrame::ImeCompositionRangeChanged(
void RenderWidgetHostViewChildFrame::WasShown() {
if (!host_->is_hidden())
return;
- host_->WasShown();
+ host_->WasShown(ui::LatencyInfo());
}
void RenderWidgetHostViewChildFrame::WasHidden() {
@@ -145,8 +150,12 @@ void RenderWidgetHostViewChildFrame::SetIsLoading(bool is_loading) {
NOTREACHED();
}
-void RenderWidgetHostViewChildFrame::TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) {
+void RenderWidgetHostViewChildFrame::TextInputTypeChanged(
+ ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) {
+ NOTREACHED();
}
void RenderWidgetHostViewChildFrame::RenderProcessGone(
@@ -183,11 +192,6 @@ void RenderWidgetHostViewChildFrame::SelectionBoundsChanged(
}
#if defined(OS_ANDROID)
-void RenderWidgetHostViewChildFrame::ShowDisambiguationPopup(
- const gfx::Rect& target_rect,
- const SkBitmap& zoomed_bitmap) {
-}
-
void RenderWidgetHostViewChildFrame::LockCompositingSurface() {
}
@@ -195,28 +199,10 @@ void RenderWidgetHostViewChildFrame::UnlockCompositingSurface() {
}
#endif
-void RenderWidgetHostViewChildFrame::ScrollOffsetChanged() {
-}
-
-void RenderWidgetHostViewChildFrame::AcceleratedSurfaceInitialized(int host_id,
- int route_id) {
-}
-
-void RenderWidgetHostViewChildFrame::AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id) {
- if (frame_connector_)
- frame_connector_->ChildFrameBuffersSwapped(params, gpu_host_id);
-}
-
-void RenderWidgetHostViewChildFrame::AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
- int gpu_host_id) {
-}
-
void RenderWidgetHostViewChildFrame::OnSwapCompositorFrame(
uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) {
+ last_scroll_offset_ = frame->metadata.root_scroll_offset;
if (frame_connector_) {
frame_connector_->ChildFrameCompositorFrameSwapped(
output_surface_id,
@@ -253,9 +239,6 @@ void RenderWidgetHostViewChildFrame::UnlockMouse() {
void RenderWidgetHostViewChildFrame::SetActive(bool active) {
}
-void RenderWidgetHostViewChildFrame::SetTakesFocusOnlyOnMouseDown(bool flag) {
-}
-
void RenderWidgetHostViewChildFrame::SetWindowVisibility(bool visible) {
}
@@ -288,8 +271,8 @@ bool RenderWidgetHostViewChildFrame::PostProcessEventForPluginIme(
void RenderWidgetHostViewChildFrame::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& /* dst_size */,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) {
+ CopyFromCompositingSurfaceCallback& callback,
+ const SkColorType color_type) {
callback.Run(false, SkBitmap());
}
@@ -305,20 +288,13 @@ bool RenderWidgetHostViewChildFrame::CanCopyToVideoFrame() const {
return false;
}
-void RenderWidgetHostViewChildFrame::AcceleratedSurfaceSuspend() {
- NOTREACHED();
-}
-
-void RenderWidgetHostViewChildFrame::AcceleratedSurfaceRelease() {
-}
-
bool RenderWidgetHostViewChildFrame::HasAcceleratedSurface(
const gfx::Size& desired_size) {
return false;
}
gfx::GLSurfaceHandle RenderWidgetHostViewChildFrame::GetCompositingSurface() {
- return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
+ return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NULL_TRANSPORT);
}
#if defined(OS_WIN)
@@ -332,8 +308,15 @@ gfx::NativeViewId RenderWidgetHostViewChildFrame::GetParentForWindowlessPlugin()
}
#endif // defined(OS_WIN)
-SkBitmap::Config RenderWidgetHostViewChildFrame::PreferredReadbackFormat() {
- return SkBitmap::kARGB_8888_Config;
+SkColorType RenderWidgetHostViewChildFrame::PreferredReadbackFormat() {
+ return kN32_SkColorType;
+}
+
+BrowserAccessibilityManager*
+RenderWidgetHostViewChildFrame::CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) {
+ return BrowserAccessibilityManager::Create(
+ BrowserAccessibilityManager::GetEmptyDocument(), delegate);
}
} // 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 e288248aa45..b2895f9f7df 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
@@ -11,8 +11,6 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
-struct ViewHostMsg_TextInputState_Params;
-
namespace content {
class CrossProcessFrameConnector;
class RenderWidgetHost;
@@ -30,7 +28,7 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
: public RenderWidgetHostViewBase {
public:
explicit RenderWidgetHostViewChildFrame(RenderWidgetHost* widget);
- virtual ~RenderWidgetHostViewChildFrame();
+ ~RenderWidgetHostViewChildFrame() override;
void set_cross_process_frame_connector(
CrossProcessFrameConnector* frame_connector) {
@@ -38,125 +36,114 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame
}
// RenderWidgetHostView implementation.
- virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE;
- virtual RenderWidgetHost* GetRenderWidgetHost() const OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void SetBounds(const gfx::Rect& rect) OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual bool HasFocus() const OVERRIDE;
- virtual bool IsSurfaceAvailableForCopy() const OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual bool IsShowing() OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeViewId GetNativeViewId() const OVERRIDE;
- virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
- virtual void SetBackgroundOpaque(bool opaque) OVERRIDE;
- virtual gfx::Size GetPhysicalBackingSize() const OVERRIDE;
+ void InitAsChild(gfx::NativeView parent_view) override;
+ RenderWidgetHost* GetRenderWidgetHost() const override;
+ void SetSize(const gfx::Size& size) override;
+ void SetBounds(const gfx::Rect& rect) override;
+ void Focus() override;
+ bool HasFocus() const override;
+ bool IsSurfaceAvailableForCopy() const override;
+ void Show() override;
+ void Hide() override;
+ bool IsShowing() override;
+ gfx::Rect GetViewBounds() const override;
+ gfx::Vector2dF GetLastScrollOffset() const override;
+ gfx::NativeView GetNativeView() const override;
+ gfx::NativeViewId GetNativeViewId() const override;
+ gfx::NativeViewAccessible GetNativeViewAccessible() override;
+ void SetBackgroundColor(SkColor color) override;
+ gfx::Size GetPhysicalBackingSize() const override;
// RenderWidgetHostViewBase implementation.
- virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) OVERRIDE;
- virtual void InitAsFullscreen(
- RenderWidgetHostView* reference_host_view) OVERRIDE;
- virtual void WasShown() OVERRIDE;
- virtual void WasHidden() OVERRIDE;
- virtual void MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) OVERRIDE;
- virtual void Blur() OVERRIDE;
- virtual void UpdateCursor(const WebCursor& cursor) OVERRIDE;
- virtual void SetIsLoading(bool is_loading) OVERRIDE;
- virtual void TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) OVERRIDE;
- virtual void ImeCancelComposition() OVERRIDE;
-#if defined(OS_MACOSX) || defined(USE_AURA)
- virtual void ImeCompositionRangeChanged(
+ void InitAsPopup(RenderWidgetHostView* parent_host_view,
+ const gfx::Rect& pos) override;
+ void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
+ void WasShown() override;
+ void WasHidden() override;
+ void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
+ void Blur() override;
+ void UpdateCursor(const WebCursor& cursor) override;
+ void SetIsLoading(bool is_loading) override;
+ void TextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) override;
+ void ImeCancelComposition() override;
+#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
+ void ImeCompositionRangeChanged(
const gfx::Range& range,
- const std::vector<gfx::Rect>& character_bounds) OVERRIDE;
+ const std::vector<gfx::Rect>& character_bounds) override;
#endif
- virtual void RenderProcessGone(base::TerminationStatus status,
- int error_code) OVERRIDE;
- virtual void Destroy() OVERRIDE;
- virtual void SetTooltipText(const base::string16& tooltip_text) OVERRIDE;
- virtual void SelectionChanged(const base::string16& text,
- size_t offset,
- const gfx::Range& range) OVERRIDE;
- virtual void SelectionBoundsChanged(
- const ViewHostMsg_SelectionBounds_Params& params) OVERRIDE;
- virtual void ScrollOffsetChanged() OVERRIDE;
- virtual void CopyFromCompositingSurface(
+ void RenderProcessGone(base::TerminationStatus status,
+ int error_code) override;
+ void Destroy() override;
+ void SetTooltipText(const base::string16& tooltip_text) override;
+ void SelectionChanged(const base::string16& text,
+ size_t offset,
+ const gfx::Range& range) override;
+ void SelectionBoundsChanged(
+ const ViewHostMsg_SelectionBounds_Params& params) override;
+ void CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) OVERRIDE;
- virtual void CopyFromCompositingSurfaceToVideoFrame(
+ const SkColorType color_type) override;
+ void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) OVERRIDE;
- virtual bool CanCopyToVideoFrame() const OVERRIDE;
- virtual void AcceleratedSurfaceInitialized(int host_id,
- int route_id) OVERRIDE;
- virtual void AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfaceSuspend() OVERRIDE;
- virtual void AcceleratedSurfaceRelease() OVERRIDE;
- virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE;
- virtual void OnSwapCompositorFrame(
- uint32 output_surface_id,
- scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
- virtual void GetScreenInfo(blink::WebScreenInfo* results) OVERRIDE;
- virtual gfx::Rect GetBoundsInRootWindow() OVERRIDE;
- virtual gfx::GLSurfaceHandle GetCompositingSurface() OVERRIDE;
+ const base::Callback<void(bool)>& callback) override;
+ bool CanCopyToVideoFrame() const override;
+ bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
+ void OnSwapCompositorFrame(uint32 output_surface_id,
+ scoped_ptr<cc::CompositorFrame> frame) override;
+ void GetScreenInfo(blink::WebScreenInfo* results) override;
+ gfx::Rect GetBoundsInRootWindow() override;
+ gfx::GLSurfaceHandle GetCompositingSurface() override;
#if defined(USE_AURA)
- virtual void ProcessAckedTouchEvent(
- const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) OVERRIDE;
+ void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result) override;
#endif // defined(USE_AURA)
- virtual bool LockMouse() OVERRIDE;
- virtual void UnlockMouse() OVERRIDE;
+ bool LockMouse() override;
+ void UnlockMouse() override;
#if defined(OS_MACOSX)
// RenderWidgetHostView implementation.
- virtual void SetActive(bool active) OVERRIDE;
- virtual void SetTakesFocusOnlyOnMouseDown(bool flag) OVERRIDE;
- virtual void SetWindowVisibility(bool visible) OVERRIDE;
- virtual void WindowFrameChanged() OVERRIDE;
- virtual void ShowDefinitionForSelection() OVERRIDE;
- virtual bool SupportsSpeech() const OVERRIDE;
- virtual void SpeakSelection() OVERRIDE;
- virtual bool IsSpeaking() const OVERRIDE;
- virtual void StopSpeaking() OVERRIDE;
+ 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.
- virtual bool PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) OVERRIDE;
+ bool PostProcessEventForPluginIme(
+ const NativeWebKeyboardEvent& event) override;
#endif // defined(OS_MACOSX)
-#if defined(OS_ANDROID)
// RenderWidgetHostViewBase implementation.
- virtual void ShowDisambiguationPopup(
- const gfx::Rect& target_rect,
- const SkBitmap& zoomed_bitmap) OVERRIDE;
- virtual void LockCompositingSurface() OVERRIDE;
- virtual void UnlockCompositingSurface() OVERRIDE;
+#if defined(OS_ANDROID)
+ virtual void LockCompositingSurface() override;
+ virtual void UnlockCompositingSurface() override;
#endif // defined(OS_ANDROID)
#if defined(OS_WIN)
virtual void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) OVERRIDE;
- virtual gfx::NativeViewId GetParentForWindowlessPlugin() const OVERRIDE;
+ gfx::NativeViewAccessible accessible_parent) override;
+ virtual gfx::NativeViewId GetParentForWindowlessPlugin() const override;
#endif
+ BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) override;
- virtual SkBitmap::Config PreferredReadbackFormat() OVERRIDE;
+ SkColorType PreferredReadbackFormat() override;
protected:
friend class RenderWidgetHostView;
+ // The last scroll offset of the view.
+ gfx::Vector2dF last_scroll_offset_;
+
// Members will become private when RenderWidgetHostViewGuest is removed.
// The model object.
RenderWidgetHostImpl* host_;
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 95b4eb36391..7d731ff90fd 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
@@ -20,14 +20,14 @@ namespace {
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
MockRenderWidgetHostDelegate() {}
- virtual ~MockRenderWidgetHostDelegate() {}
+ ~MockRenderWidgetHostDelegate() override {}
};
class RenderWidgetHostViewChildFrameTest : public testing::Test {
public:
RenderWidgetHostViewChildFrameTest() {}
- virtual void SetUp() {
+ void SetUp() override {
browser_context_.reset(new TestBrowserContext);
MockRenderProcessHost* process_host =
new MockRenderProcessHost(browser_context_.get());
@@ -36,7 +36,7 @@ class RenderWidgetHostViewChildFrameTest : public testing::Test {
view_ = new RenderWidgetHostViewChildFrame(widget_host_);
}
- virtual void TearDown() {
+ void TearDown() override {
if (view_)
view_->Destroy();
delete widget_host_;
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 8a02c69f5ea..708f8bf0364 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
@@ -12,7 +12,6 @@
#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/host_shared_bitmap_manager.h"
#include "content/common/input/web_touch_event_traits.h"
#include "content/common/view_messages.h"
#include "content/common/webplugin_geometry.h"
@@ -47,7 +46,7 @@ blink::WebGestureEvent CreateFlingCancelEvent(double time_stamp) {
RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
RenderWidgetHost* widget_host,
BrowserPluginGuest* guest,
- RenderWidgetHostViewBase* platform_view)
+ base::WeakPtr<RenderWidgetHostViewBase> platform_view)
: RenderWidgetHostViewChildFrame(widget_host),
// |guest| is NULL during test.
guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()),
@@ -64,6 +63,19 @@ RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
#endif // defined(USE_AURA)
}
+bool RenderWidgetHostViewGuest::OnMessageReceivedFromEmbedder(
+ const IPC::Message& message,
+ RenderWidgetHostImpl* embedder) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(RenderWidgetHostViewGuest, message,
+ embedder)
+ IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
+ OnHandleInputEvent)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
void RenderWidgetHostViewGuest::WasShown() {
// If the WebContents associated with us showed an interstitial page in the
// beginning, the teardown path might call WasShown() while |host_| is in
@@ -74,7 +86,13 @@ void RenderWidgetHostViewGuest::WasShown() {
// |guest_| is NULL during test.
if ((guest_ && guest_->is_in_destruction()) || !host_->is_hidden())
return;
- host_->WasShown();
+ // Make sure the size of this view matches the size of the WebContentsView.
+ // The two sizes may fall out of sync if we switch RenderWidgetHostViews,
+ // resize, and then switch page, as is the case with interstitial pages.
+ // NOTE: |guest_| is NULL in unit tests.
+ if (guest_)
+ SetSize(guest_->web_contents()->GetViewBounds().size());
+ host_->WasShown(ui::LatencyInfo());
}
void RenderWidgetHostViewGuest::WasHidden() {
@@ -93,6 +111,20 @@ void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect& rect) {
SetSize(rect.size());
}
+void RenderWidgetHostViewGuest::Focus() {
+ // InterstitialPageImpl focuses views directly, so we place focus logic here.
+ // InterstitialPages are not WebContents, and so BrowserPluginGuest does not
+ // have direct access to the interstitial page's RenderWidgetHost.
+ if (guest_)
+ guest_->SetFocus(host_, true);
+}
+
+bool RenderWidgetHostViewGuest::HasFocus() const {
+ if (!guest_)
+ return false;
+ return guest_->focused();
+}
+
#if defined(USE_AURA)
void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
@@ -109,8 +141,11 @@ void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED;
for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(),
end = events.end(); iter != end; ++iter) {
+ if (!gesture_recognizer_->ProcessTouchEventPreDispatch(*(*iter), this))
+ continue;
+
scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
- gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture(
+ gestures.reset(gesture_recognizer_->ProcessTouchEventPostDispatch(
*(*iter), result, this));
ProcessGestures(gestures.get());
}
@@ -125,10 +160,8 @@ gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
gfx::Rect embedder_bounds;
if (rwhv)
embedder_bounds = rwhv->GetViewBounds();
- gfx::Rect shifted_rect = guest_->ToGuestRect(embedder_bounds);
- shifted_rect.set_width(size_.width());
- shifted_rect.set_height(size_.height());
- return shifted_rect;
+ return gfx::Rect(
+ guest_->GetScreenCoordinates(embedder_bounds.origin()), size_);
}
void RenderWidgetHostViewGuest::RenderProcessGone(
@@ -144,7 +177,8 @@ void RenderWidgetHostViewGuest::Destroy() {
// The RenderWidgetHost's destruction led here, so don't call it.
DestroyGuestView();
- platform_view_->Destroy();
+ if (platform_view_) // The platform view might have been destroyed already.
+ platform_view_->Destroy();
}
gfx::Size RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
@@ -157,29 +191,8 @@ base::string16 RenderWidgetHostViewGuest::GetSelectedText() const {
void RenderWidgetHostViewGuest::SetTooltipText(
const base::string16& tooltip_text) {
- platform_view_->SetTooltipText(tooltip_text);
-}
-
-void RenderWidgetHostViewGuest::AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id) {
- if (!guest_)
- return;
-
- FrameMsg_BuffersSwapped_Params guest_params;
- guest_params.size = params.size;
- guest_params.mailbox = params.mailbox;
- guest_params.gpu_route_id = params.route_id;
- guest_params.gpu_host_id = gpu_host_id;
- guest_->SendMessageToEmbedder(
- new BrowserPluginMsg_BuffersSwapped(guest_->instance_id(),
- guest_params));
-}
-
-void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
- int gpu_host_id) {
- NOTREACHED();
+ if (guest_)
+ guest_->SetTooltipText(tooltip_text);
}
void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
@@ -188,39 +201,11 @@ void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
if (!guest_)
return;
- if (!guest_->attached()) {
- // If the guest doesn't have an embedder then there's nothing to give the
- // the frame to.
- return;
- }
- base::SharedMemoryHandle software_frame_handle =
- base::SharedMemory::NULLHandle();
- if (frame->software_frame_data) {
- cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
- scoped_ptr<cc::SharedBitmap> bitmap =
- HostSharedBitmapManager::current()->GetSharedBitmapFromId(
- frame_data->size, frame_data->bitmap_id);
- if (!bitmap)
- return;
-
- RenderWidgetHostView* embedder_rwhv =
- guest_->GetEmbedderRenderWidgetHostView();
- base::ProcessHandle embedder_pid =
- embedder_rwhv->GetRenderWidgetHost()->GetProcess()->GetHandle();
-
- bitmap->memory()->ShareToProcess(embedder_pid, &software_frame_handle);
- }
-
- FrameMsg_CompositorFrameSwapped_Params guest_params;
- frame->AssignTo(&guest_params.frame);
- guest_params.output_surface_id = output_surface_id;
- guest_params.producing_route_id = host_->GetRoutingID();
- guest_params.producing_host_id = host_->GetProcess()->GetID();
- guest_params.shared_memory_handle = software_frame_handle;
-
- guest_->SendMessageToEmbedder(
- new BrowserPluginMsg_CompositorFrameSwapped(guest_->instance_id(),
- guest_params));
+ last_scroll_offset_ = frame->metadata.root_scroll_offset;
+ guest_->SwapCompositorFrame(output_surface_id,
+ host_->GetProcess()->GetID(),
+ host_->GetRoutingID(),
+ frame.Pass());
}
bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
@@ -280,15 +265,27 @@ void RenderWidgetHostViewGuest::MovePluginWindows(
}
void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) {
- platform_view_->UpdateCursor(cursor);
+ // InterstitialPages are not WebContents so we cannot intercept
+ // ViewHostMsg_SetCursor for interstitial pages in BrowserPluginGuest.
+ // All guest RenderViewHosts have RenderWidgetHostViewGuests however,
+ // and so we will always hit this code path.
+ if (!guest_)
+ return;
+ guest_->SendMessageToEmbedder(
+ new BrowserPluginMsg_SetCursor(guest_->browser_plugin_instance_id(),
+ cursor));
+
}
void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) {
platform_view_->SetIsLoading(is_loading);
}
-void RenderWidgetHostViewGuest::TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) {
+void RenderWidgetHostViewGuest::TextInputTypeChanged(
+ ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) {
if (!guest_)
return;
@@ -296,7 +293,7 @@ void RenderWidgetHostViewGuest::TextInputStateChanged(
if (!rwhv)
return;
// Forward the information to embedding RWHV.
- rwhv->TextInputStateChanged(params);
+ rwhv->TextInputTypeChanged(type, input_mode, can_compose_inline, flags);
}
void RenderWidgetHostViewGuest::ImeCancelComposition() {
@@ -322,8 +319,9 @@ void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
return;
std::vector<gfx::Rect> guest_character_bounds;
for (size_t i = 0; i < character_bounds.size(); ++i) {
- gfx::Rect guest_rect = guest_->ToGuestRect(character_bounds[i]);
- guest_character_bounds.push_back(guest_rect);
+ guest_character_bounds.push_back(gfx::Rect(
+ guest_->GetScreenCoordinates(character_bounds[i].origin()),
+ character_bounds[i].size()));
}
// Forward the information to embedding RWHV.
rwhv->ImeCompositionRangeChanged(range, guest_character_bounds);
@@ -345,22 +343,24 @@ void RenderWidgetHostViewGuest::SelectionBoundsChanged(
if (!rwhv)
return;
ViewHostMsg_SelectionBounds_Params guest_params(params);
- guest_params.anchor_rect = guest_->ToGuestRect(params.anchor_rect);
- guest_params.focus_rect = guest_->ToGuestRect(params.focus_rect);
+ guest_params.anchor_rect.set_origin(
+ guest_->GetScreenCoordinates(params.anchor_rect.origin()));
+ guest_params.focus_rect.set_origin(
+ guest_->GetScreenCoordinates(params.focus_rect.origin()));
rwhv->SelectionBoundsChanged(guest_params);
}
-void RenderWidgetHostViewGuest::CopyFromCompositingSurface(
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) {
- CHECK(guest_);
- guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback);
-}
-
-void RenderWidgetHostViewGuest::SetBackgroundOpaque(bool opaque) {
- platform_view_->SetBackgroundOpaque(opaque);
+void RenderWidgetHostViewGuest::SetBackgroundColor(SkColor color) {
+ // Content embedders can toggle opaque backgrounds through this API.
+ // We plumb the value here so that BrowserPlugin updates its compositing
+ // state in response to this change. We also want to preserve this flag
+ // after recovering from a crash so we let BrowserPluginGuest store it.
+ if (!guest_)
+ return;
+ RenderWidgetHostViewBase::SetBackgroundColor(color);
+ bool opaque = GetBackgroundOpaque();
+ host_->SetBackgroundOpaque(opaque);
+ guest_->SetContentsOpaque(opaque);
}
bool RenderWidgetHostViewGuest::LockMouse() {
@@ -384,10 +384,6 @@ void RenderWidgetHostViewGuest::SetActive(bool active) {
platform_view_->SetActive(active);
}
-void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag) {
- platform_view_->SetTakesFocusOnlyOnMouseDown(flag);
-}
-
void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) {
platform_view_->SetWindowVisibility(visible);
}
@@ -413,7 +409,7 @@ void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
// Vertical offset from guest's top to embedder's bottom edge.
embedder_bounds.bottom() - guest_bounds.y());
- RenderWidgetHostViewMacDictionaryHelper helper(platform_view_);
+ RenderWidgetHostViewMacDictionaryHelper helper(platform_view_.get());
helper.SetTargetView(rwhv);
helper.set_offset(guest_offset);
helper.ShowDefinitionForSelection();
@@ -442,12 +438,14 @@ bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
#endif // defined(OS_MACOSX)
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
- const gfx::Rect& target_rect,
+ const gfx::Rect& rect_pixels,
const SkBitmap& zoomed_bitmap) {
}
+#endif // defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
+#if defined(OS_ANDROID)
void RenderWidgetHostViewGuest::LockCompositingSurface() {
}
@@ -544,8 +542,8 @@ void RenderWidgetHostViewGuest::ProcessGestures(
}
}
-SkBitmap::Config RenderWidgetHostViewGuest::PreferredReadbackFormat() {
- return SkBitmap::kARGB_8888_Config;
+SkColorType RenderWidgetHostViewGuest::PreferredReadbackFormat() {
+ return kN32_SkColorType;
}
RenderWidgetHostViewBase*
@@ -554,4 +552,43 @@ RenderWidgetHostViewGuest::GetGuestRenderWidgetHostView() const {
guest_->GetEmbedderRenderWidgetHostView());
}
+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)) {
+ host_->ForwardMouseEvent(
+ *static_cast<const blink::WebMouseEvent*>(event));
+ return;
+ }
+
+ if (event->type == blink::WebInputEvent::MouseWheel) {
+ host_->ForwardWheelEvent(
+ *static_cast<const blink::WebMouseWheelEvent*>(event));
+ return;
+ }
+
+ if (blink::WebInputEvent::isKeyboardEventType(event->type)) {
+ if (!embedder->GetLastKeyboardEvent())
+ return;
+ NativeWebKeyboardEvent keyboard_event(*embedder->GetLastKeyboardEvent());
+ host_->ForwardKeyboardEvent(keyboard_event);
+ return;
+ }
+
+ if (blink::WebInputEvent::isTouchEventType(event->type)) {
+ host_->ForwardTouchEventWithLatencyInfo(
+ *static_cast<const blink::WebTouchEvent*>(event),
+ ui::LatencyInfo());
+ return;
+ }
+
+ if (blink::WebInputEvent::isGestureEventType(event->type)) {
+ host_->ForwardGestureEvent(
+ *static_cast<const blink::WebGestureEvent*>(event));
+ return;
+ }
+}
+
} // namespace content
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 6132b4e8655..2ebd4e66845 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
@@ -18,12 +18,10 @@
#include "ui/gfx/rect.h"
#include "ui/gfx/vector2d_f.h"
-struct ViewHostMsg_TextInputState_Params;
-
namespace content {
+class BrowserPluginGuest;
class RenderWidgetHost;
class RenderWidgetHostImpl;
-class BrowserPluginGuest;
struct NativeWebKeyboardEvent;
// See comments in render_widget_host_view.h about this class and its members.
@@ -41,112 +39,107 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
public ui::GestureConsumer,
public ui::GestureEventHelper {
public:
- RenderWidgetHostViewGuest(RenderWidgetHost* widget,
- BrowserPluginGuest* guest,
- RenderWidgetHostViewBase* platform_view);
- virtual ~RenderWidgetHostViewGuest();
+ RenderWidgetHostViewGuest(
+ RenderWidgetHost* widget,
+ BrowserPluginGuest* guest,
+ base::WeakPtr<RenderWidgetHostViewBase> platform_view);
+ ~RenderWidgetHostViewGuest() override;
+
+ bool OnMessageReceivedFromEmbedder(const IPC::Message& message,
+ RenderWidgetHostImpl* embedder);
// RenderWidgetHostView implementation.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
- virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void SetBounds(const gfx::Rect& rect) OVERRIDE;
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeViewId GetNativeViewId() const OVERRIDE;
- virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
- virtual void SetBackgroundOpaque(bool opaque) OVERRIDE;
- virtual gfx::Size GetPhysicalBackingSize() const OVERRIDE;
- virtual base::string16 GetSelectedText() const OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void InitAsChild(gfx::NativeView parent_view) override;
+ void SetSize(const gfx::Size& size) override;
+ void SetBounds(const gfx::Rect& rect) override;
+ void Focus() override;
+ bool HasFocus() const override;
+ gfx::NativeView GetNativeView() const override;
+ gfx::NativeViewId GetNativeViewId() const override;
+ gfx::NativeViewAccessible GetNativeViewAccessible() override;
+ gfx::Rect GetViewBounds() const override;
+ void SetBackgroundColor(SkColor color) override;
+ gfx::Size GetPhysicalBackingSize() const override;
+ base::string16 GetSelectedText() const override;
// RenderWidgetHostViewBase implementation.
- virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) OVERRIDE;
- virtual void InitAsFullscreen(
- RenderWidgetHostView* reference_host_view) OVERRIDE;
- virtual void WasShown() OVERRIDE;
- virtual void WasHidden() OVERRIDE;
- virtual void MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) OVERRIDE;
- virtual void UpdateCursor(const WebCursor& cursor) OVERRIDE;
- virtual void SetIsLoading(bool is_loading) OVERRIDE;
- virtual void TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) OVERRIDE;
- virtual void ImeCancelComposition() OVERRIDE;
+ void InitAsPopup(RenderWidgetHostView* parent_host_view,
+ const gfx::Rect& pos) override;
+ void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
+ void WasShown() override;
+ void WasHidden() override;
+ void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
+ void UpdateCursor(const WebCursor& cursor) override;
+ void SetIsLoading(bool is_loading) override;
+ void TextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) override;
+ void ImeCancelComposition() override;
#if defined(OS_MACOSX) || defined(USE_AURA)
- virtual void ImeCompositionRangeChanged(
+ void ImeCompositionRangeChanged(
const gfx::Range& range,
- const std::vector<gfx::Rect>& character_bounds) OVERRIDE;
+ const std::vector<gfx::Rect>& character_bounds) override;
#endif
- virtual void RenderProcessGone(base::TerminationStatus status,
- int error_code) OVERRIDE;
- virtual void Destroy() OVERRIDE;
- virtual void SetTooltipText(const base::string16& tooltip_text) OVERRIDE;
- virtual void SelectionChanged(const base::string16& text,
- size_t offset,
- const gfx::Range& range) OVERRIDE;
- virtual void SelectionBoundsChanged(
- const ViewHostMsg_SelectionBounds_Params& params) OVERRIDE;
- virtual void CopyFromCompositingSurface(
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) OVERRIDE;
- virtual void AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
- int gpu_host_id) OVERRIDE;
- virtual void OnSwapCompositorFrame(
- uint32 output_surface_id,
- scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
+ void RenderProcessGone(base::TerminationStatus status,
+ int error_code) override;
+ void Destroy() override;
+ void SetTooltipText(const base::string16& tooltip_text) override;
+ void SelectionChanged(const base::string16& text,
+ size_t offset,
+ const gfx::Range& range) override;
+ void SelectionBoundsChanged(
+ const ViewHostMsg_SelectionBounds_Params& params) override;
+ void OnSwapCompositorFrame(uint32 output_surface_id,
+ scoped_ptr<cc::CompositorFrame> frame) override;
#if defined(USE_AURA)
- virtual void ProcessAckedTouchEvent(
- const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) OVERRIDE;
+ void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result) override;
#endif
- virtual bool LockMouse() OVERRIDE;
- virtual void UnlockMouse() OVERRIDE;
- virtual void GetScreenInfo(blink::WebScreenInfo* results) OVERRIDE;
+ bool LockMouse() override;
+ void UnlockMouse() override;
+ void GetScreenInfo(blink::WebScreenInfo* results) override;
#if defined(OS_MACOSX)
// RenderWidgetHostView implementation.
- virtual void SetActive(bool active) OVERRIDE;
- virtual void SetTakesFocusOnlyOnMouseDown(bool flag) OVERRIDE;
- virtual void SetWindowVisibility(bool visible) OVERRIDE;
- virtual void WindowFrameChanged() OVERRIDE;
- virtual void ShowDefinitionForSelection() OVERRIDE;
- virtual bool SupportsSpeech() const OVERRIDE;
- virtual void SpeakSelection() OVERRIDE;
- virtual bool IsSpeaking() const OVERRIDE;
- virtual void StopSpeaking() OVERRIDE;
+ 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.
- virtual bool PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) OVERRIDE;
+ bool PostProcessEventForPluginIme(
+ const NativeWebKeyboardEvent& event) override;
#endif // defined(OS_MACOSX)
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
// RenderWidgetHostViewBase implementation.
- virtual void ShowDisambiguationPopup(const gfx::Rect& target_rect,
- const SkBitmap& zoomed_bitmap) OVERRIDE;
- virtual void LockCompositingSurface() OVERRIDE;
- virtual void UnlockCompositingSurface() OVERRIDE;
+ void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
+ const SkBitmap& zoomed_bitmap) override;
+#endif // defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
+
+#if defined(OS_ANDROID)
+ virtual void LockCompositingSurface() override;
+ virtual void UnlockCompositingSurface() override;
#endif // defined(OS_ANDROID)
#if defined(OS_WIN)
virtual void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) OVERRIDE;
- virtual gfx::NativeViewId GetParentForWindowlessPlugin() const OVERRIDE;
+ gfx::NativeViewAccessible accessible_parent) override;
+ virtual gfx::NativeViewId GetParentForWindowlessPlugin() const override;
#endif
// Overridden from ui::GestureEventHelper.
- virtual bool CanDispatchToConsumer(ui::GestureConsumer* consumer) OVERRIDE;
- virtual void DispatchGestureEvent(ui::GestureEvent* event) OVERRIDE;
- virtual void DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ bool CanDispatchToConsumer(ui::GestureConsumer* consumer) override;
+ void DispatchGestureEvent(ui::GestureEvent* event) override;
+ void DispatchCancelTouchEvent(ui::TouchEvent* event) override;
- virtual SkBitmap::Config PreferredReadbackFormat() OVERRIDE;
+ SkColorType PreferredReadbackFormat() override;
protected:
friend class RenderWidgetHostView;
@@ -163,6 +156,11 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
RenderWidgetHostViewBase* GetGuestRenderWidgetHostView() 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
// to one another, therefore we access |guest_| through WeakPtr.
base::WeakPtr<BrowserPluginGuest> guest_;
@@ -170,7 +168,7 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest
// The platform view for this RenderWidgetHostView.
// RenderWidgetHostViewGuest mostly only cares about stuff related to
// compositing, the rest are directly forwared to this |platform_view_|.
- RenderWidgetHostViewBase* platform_view_;
+ base::WeakPtr<RenderWidgetHostViewBase> platform_view_;
#if defined(USE_AURA)
scoped_ptr<ui::GestureRecognizer> gesture_recognizer_;
#endif
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 172be978f61..968dc8abc07 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
@@ -20,24 +20,25 @@ namespace {
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
MockRenderWidgetHostDelegate() {}
- virtual ~MockRenderWidgetHostDelegate() {}
+ ~MockRenderWidgetHostDelegate() override {}
};
class RenderWidgetHostViewGuestTest : public testing::Test {
public:
RenderWidgetHostViewGuestTest() {}
- virtual void SetUp() {
+ void SetUp() override {
browser_context_.reset(new TestBrowserContext);
MockRenderProcessHost* process_host =
new MockRenderProcessHost(browser_context_.get());
widget_host_ = new RenderWidgetHostImpl(
&delegate_, process_host, MSG_ROUTING_NONE, false);
view_ = new RenderWidgetHostViewGuest(
- widget_host_, NULL, new TestRenderWidgetHostView(widget_host_));
+ widget_host_, NULL,
+ (new TestRenderWidgetHostView(widget_host_))->GetWeakPtr());
}
- virtual void TearDown() {
+ void TearDown() override {
if (view_)
view_->Destroy();
delete widget_host_;
diff --git a/chromium/content/browser/gamepad/canonical_axis_index_list.h b/chromium/content/browser/gamepad/canonical_axis_index_list.h
deleted file mode 100644
index 58b85a6e189..00000000000
--- a/chromium/content/browser/gamepad/canonical_axis_index_list.h
+++ /dev/null
@@ -1,16 +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.
-
-// This file intentionally does not have header guards, it's included
-// inside a macro to generate enum values.
-
-// This file defines the canonical axes mapping order for gamepad-like devices.
-
-// TODO(SaurabhK): Consolidate with CanonicalAxisIndex enum in
-// gamepad_standard_mappings.h, crbug.com/351558.
-CANONICAL_AXIS_INDEX(AXIS_LEFT_STICK_X, 0)
-CANONICAL_AXIS_INDEX(AXIS_LEFT_STICK_Y, 1)
-CANONICAL_AXIS_INDEX(AXIS_RIGHT_STICK_X, 2)
-CANONICAL_AXIS_INDEX(AXIS_RIGHT_STICK_Y, 3)
-CANONICAL_AXIS_INDEX(NUM_CANONICAL_AXES, 4)
diff --git a/chromium/content/browser/gamepad/canonical_button_index_list.h b/chromium/content/browser/gamepad/canonical_button_index_list.h
deleted file mode 100644
index 153ce0ea3dd..00000000000
--- a/chromium/content/browser/gamepad/canonical_button_index_list.h
+++ /dev/null
@@ -1,28 +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.
-
-// This file intentionally does not have header guards, it's included
-// inside a macro to generate enum values.
-// This defines the canonical button mapping order for gamepad-like devices.
-
-// TODO(SaurabhK): Consolidate with CanonicalButtonIndex enum in
-// gamepad_standard_mappings.h, crbug.com/351558.
-CANONICAL_BUTTON_INDEX(BUTTON_PRIMARY, 0)
-CANONICAL_BUTTON_INDEX(BUTTON_SECONDARY, 1)
-CANONICAL_BUTTON_INDEX(BUTTON_TERTIARY, 2)
-CANONICAL_BUTTON_INDEX(BUTTON_QUATERNARY, 3)
-CANONICAL_BUTTON_INDEX(BUTTON_LEFT_SHOULDER, 4)
-CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_SHOULDER, 5)
-CANONICAL_BUTTON_INDEX(BUTTON_LEFT_TRIGGER, 6)
-CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_TRIGGER, 7)
-CANONICAL_BUTTON_INDEX(BUTTON_BACK_SELECT, 8)
-CANONICAL_BUTTON_INDEX(BUTTON_START, 9)
-CANONICAL_BUTTON_INDEX(BUTTON_LEFT_THUMBSTICK, 10)
-CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_THUMBSTICK, 11)
-CANONICAL_BUTTON_INDEX(BUTTON_DPAD_UP, 12)
-CANONICAL_BUTTON_INDEX(BUTTON_DPAD_DOWN, 13)
-CANONICAL_BUTTON_INDEX(BUTTON_DPAD_LEFT, 14)
-CANONICAL_BUTTON_INDEX(BUTTON_DPAD_RIGHT, 15)
-CANONICAL_BUTTON_INDEX(BUTTON_META, 16)
-CANONICAL_BUTTON_INDEX(NUM_CANONICAL_BUTTONS, 17) \ No newline at end of file
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h
index f3cf7cc7055..9cb4cd11ed7 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher.h
@@ -47,7 +47,7 @@ class GamepadDataFetcherEmpty : public GamepadDataFetcher {
GamepadDataFetcherEmpty();
virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) OVERRIDE;
+ bool devices_changed_hint) override;
private:
DISALLOW_COPY_AND_ASSIGN(GamepadDataFetcherEmpty);
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.h b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.h
index bbbdc1f2c05..989a467a291 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_android.h
@@ -23,10 +23,10 @@ class GamepadPlatformDataFetcherAndroid : public GamepadDataFetcher {
GamepadPlatformDataFetcherAndroid();
virtual ~GamepadPlatformDataFetcherAndroid();
- virtual void PauseHint(bool paused) OVERRIDE;
+ virtual void PauseHint(bool paused) override;
virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) OVERRIDE;
+ bool devices_changed_hint) override;
// Registers the JNI methods for GamepadsReader.
static bool RegisterGamepadPlatformDataFetcherAndroid(JNIEnv* env);
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 a211bb67df1..e99a5e15904 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
@@ -20,6 +20,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/udev_linux.h"
+#include "device/udev_linux/scoped_udev.h"
namespace {
@@ -126,9 +127,7 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
// hardware, get the parent device that is also in the "input" subsystem.
// This function should just walk up the tree one level.
dev = udev_device_get_parent_with_subsystem_devtype(
- dev,
- kInputSubsystem,
- NULL);
+ dev, kInputSubsystem, NULL);
if (!dev) {
// Unable to get device information, don't use this device.
device_fd = -1;
@@ -156,10 +155,8 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
// as good as the information that the device bus has, walk up further
// to the subsystem/device type "usb"/"usb_device" and if this device
// has the same vendor/product id, prefer the description from that.
- struct udev_device *usb_dev = udev_device_get_parent_with_subsystem_devtype(
- dev,
- kUsbSubsystem,
- kUsbDeviceType);
+ struct udev_device* usb_dev = udev_device_get_parent_with_subsystem_devtype(
+ dev, kUsbSubsystem, kUsbDeviceType);
if (usb_dev) {
const char* usb_vendor_id =
udev_device_get_sysattr_value(usb_dev, "idVendor");
@@ -181,11 +178,11 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
// Append the vendor and product information then convert the utf-8
// id string to WebUChar.
- std::string id = name_string + base::StringPrintf(
- " (%sVendor: %s Product: %s)",
- mapper ? "STANDARD GAMEPAD " : "",
- vendor_id,
- product_id);
+ std::string id =
+ name_string + base::StringPrintf(" (%sVendor: %s Product: %s)",
+ mapper ? "STANDARD GAMEPAD " : "",
+ vendor_id,
+ product_id);
base::TruncateUTF8ToByteSize(id, WebGamepad::idLengthCap - 1, &id);
base::string16 tmp16 = base::UTF8ToUTF16(id);
memset(pad.id, 0, sizeof(pad.id));
@@ -193,8 +190,8 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
if (mapper) {
std::string mapping = "standard";
- base::TruncateUTF8ToByteSize(mapping, WebGamepad::mappingLengthCap - 1,
- &mapping);
+ base::TruncateUTF8ToByteSize(
+ mapping, WebGamepad::mappingLengthCap - 1, &mapping);
tmp16 = base::UTF8ToUTF16(mapping);
memset(pad.mapping, 0, sizeof(pad.mapping));
tmp16.copy(pad.mapping, arraysize(pad.mapping) - 1);
@@ -207,31 +204,30 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
}
void GamepadPlatformDataFetcherLinux::EnumerateDevices() {
- udev_enumerate* enumerate = udev_enumerate_new(udev_->udev_handle());
+ device::ScopedUdevEnumeratePtr enumerate(
+ udev_enumerate_new(udev_->udev_handle()));
if (!enumerate)
return;
- int ret = udev_enumerate_add_match_subsystem(enumerate, kInputSubsystem);
+ int ret =
+ udev_enumerate_add_match_subsystem(enumerate.get(), kInputSubsystem);
if (ret != 0)
return;
- ret = udev_enumerate_scan_devices(enumerate);
+ ret = udev_enumerate_scan_devices(enumerate.get());
if (ret != 0)
return;
- udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
- for (udev_list_entry* dev_list_entry = devices;
- dev_list_entry != NULL;
+ udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
+ for (udev_list_entry* dev_list_entry = devices; dev_list_entry != NULL;
dev_list_entry = udev_list_entry_get_next(dev_list_entry)) {
// Get the filename of the /sys entry for the device and create a
// udev_device object (dev) representing it
const char* path = udev_list_entry_get_name(dev_list_entry);
- udev_device* dev = udev_device_new_from_syspath(udev_->udev_handle(), path);
+ device::ScopedUdevDevicePtr dev(
+ udev_device_new_from_syspath(udev_->udev_handle(), path));
if (!dev)
continue;
- RefreshDevice(dev);
- udev_device_unref(dev);
+ RefreshDevice(dev.get());
}
- // Free the enumerator object
- udev_enumerate_unref(enumerate);
}
void GamepadPlatformDataFetcherLinux::ReadDeviceData(size_t index) {
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 f95e52fc0b2..dab9497fef0 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_linux.h
@@ -25,11 +25,11 @@ class UdevLinux;
class GamepadPlatformDataFetcherLinux : public GamepadDataFetcher {
public:
GamepadPlatformDataFetcherLinux();
- virtual ~GamepadPlatformDataFetcherLinux();
+ ~GamepadPlatformDataFetcherLinux() override;
// GamepadDataFetcher implementation.
- virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) OVERRIDE;
+ void GetGamepadData(blink::WebGamepads* pads,
+ bool devices_changed_hint) override;
private:
void RefreshDevice(udev_device* dev);
diff --git a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
index 54e65392864..77c024e9369 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_mac.h
@@ -31,10 +31,10 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher,
public XboxDataFetcher::Delegate {
public:
GamepadPlatformDataFetcherMac();
- virtual ~GamepadPlatformDataFetcherMac();
- virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) OVERRIDE;
- virtual void PauseHint(bool paused) OVERRIDE;
+ ~GamepadPlatformDataFetcherMac() override;
+ void GetGamepadData(blink::WebGamepads* pads,
+ bool devices_changed_hint) override;
+ void PauseHint(bool paused) override;
private:
bool enabled_;
@@ -63,10 +63,10 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher,
void DeviceRemove(IOHIDDeviceRef device);
void ValueChanged(IOHIDValueRef value);
- virtual void XboxDeviceAdd(XboxController* device) OVERRIDE;
- virtual void XboxDeviceRemove(XboxController* device) OVERRIDE;
- virtual void XboxValueChanged(XboxController* device,
- const XboxController::Data& data) OVERRIDE;
+ void XboxDeviceAdd(XboxController* device) override;
+ void XboxDeviceRemove(XboxController* device) override;
+ void XboxValueChanged(XboxController* device,
+ const XboxController::Data& data) override;
void RegisterForNotifications();
void UnregisterFromNotifications();
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 28082a9d529..d5cf220702c 100644
--- a/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
+++ b/chromium/content/browser/gamepad/gamepad_platform_data_fetcher_win.h
@@ -34,8 +34,8 @@ class GamepadPlatformDataFetcherWin : public GamepadDataFetcher {
GamepadPlatformDataFetcherWin();
virtual ~GamepadPlatformDataFetcherWin();
virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) OVERRIDE;
- virtual void PauseHint(bool paused) OVERRIDE;
+ bool devices_changed_hint) override;
+ virtual void PauseHint(bool paused) override;
private:
// XInput-specific implementation for GetGamepadData.
diff --git a/chromium/content/browser/gamepad/gamepad_provider.cc b/chromium/content/browser/gamepad/gamepad_provider.cc
index 16976d96538..caa4cc82c66 100644
--- a/chromium/content/browser/gamepad/gamepad_provider.cc
+++ b/chromium/content/browser/gamepad/gamepad_provider.cc
@@ -175,8 +175,7 @@ bool GamepadProvider::PadState::Match(const WebGamepad& pad) const {
}
void GamepadProvider::PadState::SetPad(const WebGamepad& pad) {
- DCHECK(pad.connected);
- connected_ = true;
+ connected_ = pad.connected;
axes_length_ = pad.axesLength;
buttons_length_ = pad.buttonsLength;
memcpy(id_, pad.id, arraysize(id_));
@@ -230,8 +229,6 @@ void GamepadProvider::DoPoll() {
hwbuf->sequence.WriteEnd();
}
- CheckForUserGesture();
-
if (ever_had_user_gesture_) {
for (unsigned i = 0; i < WebGamepads::itemsLengthCap; ++i) {
WebGamepad& pad = hwbuf->buffer.items[i];
@@ -249,6 +246,8 @@ void GamepadProvider::DoPoll() {
}
}
+ CheckForUserGesture();
+
// Schedule our next interval of polling.
ScheduleDoPoll();
}
@@ -308,7 +307,9 @@ void GamepadProvider::CheckForUserGesture() {
if (user_gesture_observers_.empty() && ever_had_user_gesture_)
return;
- if (GamepadsHaveUserGesture(SharedMemoryAsHardwareBuffer()->buffer)) {
+ bool had_gesture_before = ever_had_user_gesture_;
+ const WebGamepads& pads = SharedMemoryAsHardwareBuffer()->buffer;
+ if (GamepadsHaveUserGesture(pads)) {
ever_had_user_gesture_ = true;
for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
user_gesture_observers_[i].message_loop->PostTask(FROM_HERE,
@@ -316,6 +317,12 @@ void GamepadProvider::CheckForUserGesture() {
}
user_gesture_observers_.clear();
}
+ if (!had_gesture_before && ever_had_user_gesture_) {
+ // Initialize pad_states_ for the first time.
+ for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
+ pad_states_.get()[i].SetPad(pads.items[i]);
+ }
+ }
}
} // namespace content
diff --git a/chromium/content/browser/gamepad/gamepad_provider.h b/chromium/content/browser/gamepad/gamepad_provider.h
index 86a4b17baf3..a81061a21f5 100644
--- a/chromium/content/browser/gamepad/gamepad_provider.h
+++ b/chromium/content/browser/gamepad/gamepad_provider.h
@@ -37,7 +37,7 @@ class CONTENT_EXPORT GamepadProvider :
// Manually specifies the data fetcher. Used for testing.
explicit GamepadProvider(scoped_ptr<GamepadDataFetcher> fetcher);
- virtual ~GamepadProvider();
+ ~GamepadProvider() override;
// Returns the shared memory handle of the gamepad data duplicated into the
// given process.
@@ -56,7 +56,7 @@ class CONTENT_EXPORT GamepadProvider :
void RegisterForUserGesture(const base::Closure& closure);
// base::SystemMonitor::DevicesChangedObserver implementation.
- virtual void OnDevicesChanged(base::SystemMonitor::DeviceType type) OVERRIDE;
+ void OnDevicesChanged(base::SystemMonitor::DeviceType type) override;
private:
void Initialize(scoped_ptr<GamepadDataFetcher> fetcher);
diff --git a/chromium/content/browser/gamepad/gamepad_provider_unittest.cc b/chromium/content/browser/gamepad/gamepad_provider_unittest.cc
index adfef0c5bf3..e4f6571da27 100644
--- a/chromium/content/browser/gamepad/gamepad_provider_unittest.cc
+++ b/chromium/content/browser/gamepad/gamepad_provider_unittest.cc
@@ -131,26 +131,16 @@ TEST_F(GamepadProviderTest, UserGesture) {
GamepadProvider* provider = CreateProvider(no_button_data);
provider->Resume();
- // Register for a user gesture and make sure the provider reads it twice
- // see below for why).
provider->RegisterForUserGesture(listener.GetClosure());
- mock_data_fetcher_->WaitForDataRead();
- mock_data_fetcher_->WaitForDataRead();
+ mock_data_fetcher_->WaitForDataReadAndCallbacksIssued();
// It should not have issued our callback.
message_loop().RunUntilIdle();
EXPECT_FALSE(listener.has_user_gesture());
// Set a button down and wait for it to be read twice.
- //
- // We wait for two reads before calling RunAllPending because the provider
- // will read the data on the background thread (setting the event) and *then*
- // will issue the callback on our thread. Waiting for it to read twice
- // ensures that it was able to issue callbacks for the first read (if it
- // issued one) before we try to check for it.
mock_data_fetcher_->SetTestData(button_down_data);
- mock_data_fetcher_->WaitForDataRead();
- mock_data_fetcher_->WaitForDataRead();
+ mock_data_fetcher_->WaitForDataReadAndCallbacksIssued();
// It should have issued our callback.
message_loop().RunUntilIdle();
diff --git a/chromium/content/browser/gamepad/gamepad_service.cc b/chromium/content/browser/gamepad/gamepad_service.cc
index a2a83b316fa..67930f6118d 100644
--- a/chromium/content/browser/gamepad/gamepad_service.cc
+++ b/chromium/content/browser/gamepad/gamepad_service.cc
@@ -15,24 +15,40 @@
namespace content {
+namespace {
+GamepadService* g_gamepad_service = 0;
+}
+
GamepadService::GamepadService()
: num_active_consumers_(0),
gesture_callback_pending_(false) {
+ SetInstance(this);
}
GamepadService::GamepadService(scoped_ptr<GamepadDataFetcher> fetcher)
: provider_(new GamepadProvider(fetcher.Pass())),
num_active_consumers_(0),
gesture_callback_pending_(false) {
+ SetInstance(this);
thread_checker_.DetachFromThread();
}
GamepadService::~GamepadService() {
+ SetInstance(NULL);
+}
+
+void GamepadService::SetInstance(GamepadService* instance) {
+ // Unit tests can create multiple instances but only one should exist at any
+ // given time so g_gamepad_service should only go from NULL to non-NULL and
+ // vica versa.
+ CHECK(!!instance != !!g_gamepad_service);
+ g_gamepad_service = instance;
}
GamepadService* GamepadService::GetInstance() {
- return Singleton<GamepadService,
- LeakySingletonTraits<GamepadService> >::get();
+ if (!g_gamepad_service)
+ g_gamepad_service = new GamepadService;
+ return g_gamepad_service;
}
void GamepadService::ConsumerBecameActive(GamepadConsumer* consumer) {
@@ -46,6 +62,7 @@ void GamepadService::ConsumerBecameActive(GamepadConsumer* consumer) {
insert_result.first->is_active = true;
if (!insert_result.first->did_observe_user_gesture &&
!gesture_callback_pending_) {
+ gesture_callback_pending_ = true;
provider_->RegisterForUserGesture(
base::Bind(&GamepadService::OnUserGesture,
base::Unretained(this)));
diff --git a/chromium/content/browser/gamepad/gamepad_service.h b/chromium/content/browser/gamepad/gamepad_service.h
index 60081884228..726558936af 100644
--- a/chromium/content/browser/gamepad/gamepad_service.h
+++ b/chromium/content/browser/gamepad/gamepad_service.h
@@ -82,6 +82,7 @@ class CONTENT_EXPORT GamepadService {
private:
friend struct DefaultSingletonTraits<GamepadService>;
friend class GamepadServiceTestConstructor;
+ friend class GamepadServiceTest;
GamepadService();
@@ -91,6 +92,8 @@ class CONTENT_EXPORT GamepadService {
virtual ~GamepadService();
+ static void SetInstance(GamepadService*);
+
void OnUserGesture();
struct ConsumerInfo {
diff --git a/chromium/content/browser/gamepad/gamepad_service_unittest.cc b/chromium/content/browser/gamepad/gamepad_service_unittest.cc
new file mode 100644
index 00000000000..acfa6a37acc
--- /dev/null
+++ b/chromium/content/browser/gamepad/gamepad_service_unittest.cc
@@ -0,0 +1,130 @@
+// 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 "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "content/browser/gamepad/gamepad_consumer.h"
+#include "content/browser/gamepad/gamepad_service.h"
+#include "content/browser/gamepad/gamepad_test_helpers.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+static const int kNumberOfGamepads = blink::WebGamepads::itemsLengthCap;
+}
+
+using blink::WebGamepads;
+
+class ConnectionListener : public GamepadConsumer {
+ public:
+ ConnectionListener() {
+ ClearCounters();
+ }
+
+ void OnGamepadConnected(unsigned index,
+ const blink::WebGamepad& gamepad) override {
+ connected_counter_++;
+ }
+ void OnGamepadDisconnected(unsigned index,
+ const blink::WebGamepad& gamepad) override {
+ disconnected_counter_++;
+ }
+
+ void ClearCounters() {
+ connected_counter_ = 0;
+ disconnected_counter_ = 0;
+ }
+
+ int connected_counter() const { return connected_counter_; }
+ int disconnected_counter() const { return disconnected_counter_; }
+
+ private:
+ int connected_counter_;
+ int disconnected_counter_;
+};
+
+class GamepadServiceTest : public testing::Test {
+ protected:
+ GamepadServiceTest();
+ ~GamepadServiceTest() override;
+
+ void SetPadsConnected(bool connected);
+ void WaitForData();
+
+ int GetConnectedCounter() const {
+ return connection_listener_->connected_counter();
+ }
+ int GetDisconnectedCounter() const {
+ return connection_listener_->disconnected_counter();
+ }
+
+ void SetUp() override;
+
+ private:
+ MockGamepadDataFetcher* fetcher_;
+ GamepadService* service_;
+ scoped_ptr<ConnectionListener> connection_listener_;
+ TestBrowserThreadBundle browser_thread_;
+ WebGamepads test_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(GamepadServiceTest);
+};
+
+GamepadServiceTest::GamepadServiceTest()
+ : browser_thread_(TestBrowserThreadBundle::IO_MAINLOOP) {
+ memset(&test_data_, 0, sizeof(test_data_));
+
+ // Set it so that we have user gesture.
+ test_data_.items[0].buttonsLength = 1;
+ test_data_.items[0].buttons[0].value = 1.f;
+ test_data_.items[0].buttons[0].pressed = true;
+}
+
+GamepadServiceTest::~GamepadServiceTest() {
+ delete service_;
+}
+
+void GamepadServiceTest::SetUp() {
+ fetcher_ = new MockGamepadDataFetcher(test_data_);
+ service_ = new GamepadService(scoped_ptr<GamepadDataFetcher>(fetcher_));
+ connection_listener_.reset((new ConnectionListener));
+ service_->ConsumerBecameActive(connection_listener_.get());
+}
+
+void GamepadServiceTest::SetPadsConnected(bool connected) {
+ for (int i = 0; i < kNumberOfGamepads; ++i) {
+ test_data_.items[i].connected = connected;
+ }
+ fetcher_->SetTestData(test_data_);
+}
+
+void GamepadServiceTest::WaitForData() {
+ connection_listener_->ClearCounters();
+ fetcher_->WaitForDataReadAndCallbacksIssued();
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(GamepadServiceTest, ConnectionsTest) {
+ WaitForData();
+ EXPECT_EQ(0, GetConnectedCounter());
+ EXPECT_EQ(0, GetDisconnectedCounter());
+
+ SetPadsConnected(true);
+ WaitForData();
+ EXPECT_EQ(kNumberOfGamepads, GetConnectedCounter());
+ EXPECT_EQ(0, GetDisconnectedCounter());
+
+ SetPadsConnected(false);
+ WaitForData();
+ EXPECT_EQ(0, GetConnectedCounter());
+ EXPECT_EQ(kNumberOfGamepads, GetDisconnectedCounter());
+
+ WaitForData();
+ EXPECT_EQ(0, GetConnectedCounter());
+ EXPECT_EQ(0, GetDisconnectedCounter());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/gamepad/gamepad_standard_mappings.cc b/chromium/content/browser/gamepad/gamepad_standard_mappings.cc
index 60ae0725fb8..687d4ce154d 100644
--- a/chromium/content/browser/gamepad/gamepad_standard_mappings.cc
+++ b/chromium/content/browser/gamepad/gamepad_standard_mappings.cc
@@ -30,6 +30,10 @@ blink::WebGamepadButton ButtonFromButtonAndAxis(
return blink::WebGamepadButton(button.pressed, value);
}
+blink::WebGamepadButton NullButton() {
+ return blink::WebGamepadButton(false, 0.0);
+}
+
void DpadFromAxis(blink::WebGamepad* mapped, float dir) {
bool up = false;
bool right = false;
@@ -47,14 +51,14 @@ void DpadFromAxis(blink::WebGamepad* mapped, float dir) {
left = dir >= .4f && dir <= 1.f;
}
- mapped->buttons[kButtonDpadUp].pressed = up;
- mapped->buttons[kButtonDpadUp].value = up ? 1.f : 0.f;
- mapped->buttons[kButtonDpadRight].pressed = right;
- mapped->buttons[kButtonDpadRight].value = right ? 1.f : 0.f;
- mapped->buttons[kButtonDpadDown].pressed = down;
- mapped->buttons[kButtonDpadDown].value = down ? 1.f : 0.f;
- mapped->buttons[kButtonDpadLeft].pressed = left;
- mapped->buttons[kButtonDpadLeft].value = left ? 1.f : 0.f;
+ mapped->buttons[BUTTON_INDEX_DPAD_UP].pressed = up;
+ mapped->buttons[BUTTON_INDEX_DPAD_UP].value = up ? 1.f : 0.f;
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT].pressed = right;
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT].value = right ? 1.f : 0.f;
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN].pressed = down;
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN].value = down ? 1.f : 0.f;
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT].pressed = left;
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT].value = left ? 1.f : 0.f;
}
} // namespace content
diff --git a/chromium/content/browser/gamepad/gamepad_standard_mappings.h b/chromium/content/browser/gamepad/gamepad_standard_mappings.h
index e436f0c7497..d4908eff442 100644
--- a/chromium/content/browser/gamepad/gamepad_standard_mappings.h
+++ b/chromium/content/browser/gamepad/gamepad_standard_mappings.h
@@ -24,33 +24,39 @@ GamepadStandardMappingFunction GetGamepadStandardMappingFunction(
// general, err towards leaving it *unmapped* so that content can handle
// appropriately.
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content.browser.input
+// GENERATED_JAVA_PREFIX_TO_STRIP: BUTTON_INDEX_
enum CanonicalButtonIndex {
- kButtonPrimary,
- kButtonSecondary,
- kButtonTertiary,
- kButtonQuaternary,
- kButtonLeftShoulder,
- kButtonRightShoulder,
- kButtonLeftTrigger,
- kButtonRightTrigger,
- kButtonBackSelect,
- kButtonStart,
- kButtonLeftThumbstick,
- kButtonRightThumbstick,
- kButtonDpadUp,
- kButtonDpadDown,
- kButtonDpadLeft,
- kButtonDpadRight,
- kButtonMeta,
- kNumButtons
+ BUTTON_INDEX_PRIMARY,
+ BUTTON_INDEX_SECONDARY,
+ BUTTON_INDEX_TERTIARY,
+ BUTTON_INDEX_QUATERNARY,
+ BUTTON_INDEX_LEFT_SHOULDER,
+ BUTTON_INDEX_RIGHT_SHOULDER,
+ BUTTON_INDEX_LEFT_TRIGGER,
+ BUTTON_INDEX_RIGHT_TRIGGER,
+ BUTTON_INDEX_BACK_SELECT,
+ BUTTON_INDEX_START,
+ BUTTON_INDEX_LEFT_THUMBSTICK,
+ BUTTON_INDEX_RIGHT_THUMBSTICK,
+ BUTTON_INDEX_DPAD_UP,
+ BUTTON_INDEX_DPAD_DOWN,
+ BUTTON_INDEX_DPAD_LEFT,
+ BUTTON_INDEX_DPAD_RIGHT,
+ BUTTON_INDEX_META,
+ BUTTON_INDEX_COUNT
};
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content.browser.input
+// GENERATED_JAVA_PREFIX_TO_STRIP: AXIS_INDEX_
enum CanonicalAxisIndex {
- kAxisLeftStickX,
- kAxisLeftStickY,
- kAxisRightStickX,
- kAxisRightStickY,
- kNumAxes
+ AXIS_INDEX_LEFT_STICK_X,
+ AXIS_INDEX_LEFT_STICK_Y,
+ AXIS_INDEX_RIGHT_STICK_X,
+ AXIS_INDEX_RIGHT_STICK_Y,
+ AXIS_INDEX_COUNT
};
// Matches XInput's trigger deadzone
@@ -62,6 +68,7 @@ blink::WebGamepadButton AxisNegativeAsButton(float input);
blink::WebGamepadButton AxisPositiveAsButton(float input);
blink::WebGamepadButton ButtonFromButtonAndAxis(
blink::WebGamepadButton button, float axis);
+blink::WebGamepadButton NullButton();
void DpadFromAxis(blink::WebGamepad* mapped, float dir);
} // namespace content
diff --git a/chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc b/chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc
index 86c3afde8a1..a0852420c6a 100644
--- a/chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc
+++ b/chromium/content/browser/gamepad/gamepad_standard_mappings_linux.cc
@@ -8,188 +8,206 @@ namespace content {
namespace {
-void MapperXInputStyleGamepad(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperXInputStyleGamepad(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[2]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[5]);
- mapped->buttons[kButtonBackSelect] = input.buttons[6];
- mapped->buttons[kButtonStart] = input.buttons[7];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[9];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[10];
- mapped->buttons[kButtonDpadUp] = AxisNegativeAsButton(input.axes[7]);
- mapped->buttons[kButtonDpadDown] = AxisPositiveAsButton(input.axes[7]);
- mapped->buttons[kButtonDpadLeft] = AxisNegativeAsButton(input.axes[6]);
- mapped->buttons[kButtonDpadRight] = AxisPositiveAsButton(input.axes[6]);
- mapped->buttons[kButtonMeta] = input.buttons[8];
- mapped->axes[kAxisRightStickX] = input.axes[3];
- mapped->axes[kAxisRightStickY] = input.axes[4];
- mapped->buttonsLength = kNumButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[2]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[7]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[7]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ AxisPositiveAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[8];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4];
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperLakeviewResearch(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperLakeviewResearch(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[2];
- mapped->buttons[kButtonTertiary] = input.buttons[3];
- mapped->buttons[kButtonQuaternary] = input.buttons[0];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[6];
- mapped->buttons[kButtonRightShoulder] = input.buttons[7];
- mapped->buttons[kButtonLeftTrigger] = input.buttons[4];
- mapped->buttons[kButtonRightTrigger] = input.buttons[5];
- mapped->buttons[kButtonBackSelect] = input.buttons[9];
- mapped->buttons[kButtonStart] = input.buttons[8];
- mapped->buttons[kButtonDpadUp] = AxisNegativeAsButton(input.axes[5]);
- mapped->buttons[kButtonDpadDown] = AxisPositiveAsButton(input.axes[5]);
- mapped->buttons[kButtonDpadLeft] = AxisNegativeAsButton(input.axes[4]);
- mapped->buttons[kButtonDpadRight] = AxisPositiveAsButton(input.axes[4]);
- mapped->buttonsLength = kNumButtons - 1; // no Meta on this device
- mapped->axesLength = kNumAxes;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[5];
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[8];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[4]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ AxisPositiveAsButton(input.axes[4]);
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; // no Meta on this device
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperPlaystationSixAxis(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperPlaystationSixAxis(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[14];
- mapped->buttons[kButtonSecondary] = input.buttons[13];
- mapped->buttons[kButtonTertiary] = input.buttons[15];
- mapped->buttons[kButtonQuaternary] = input.buttons[12];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[10];
- mapped->buttons[kButtonRightShoulder] = input.buttons[11];
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[12]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[13]);
- mapped->buttons[kButtonBackSelect] = input.buttons[0];
- mapped->buttons[kButtonStart] = input.buttons[3];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[1];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[2];
- mapped->buttons[kButtonDpadUp] = AxisToButton(input.axes[8]);
- mapped->buttons[kButtonDpadDown] = AxisToButton(input.axes[10]);
- mapped->buttons[kButtonDpadLeft] = input.buttons[7];
- mapped->buttons[kButtonDpadRight] = AxisToButton(input.axes[9]);
- mapped->buttons[kButtonMeta] = input.buttons[16];
-
- mapped->buttonsLength = kNumButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[14];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[13];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[15];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[12];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[11];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[12]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[13]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisToButton(input.axes[8]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisToButton(input.axes[10]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] = AxisToButton(input.axes[9]);
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[16];
+
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperDualshock4(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperDualshock4(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
enum Dualshock4Buttons {
- kTouchpadButton = kNumButtons,
- kNumDualshock4Buttons
+ DUALSHOCK_BUTTON_TOUCHPAD = BUTTON_INDEX_COUNT,
+ DUALSHOCK_BUTTON_COUNT
};
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[1];
- mapped->buttons[kButtonSecondary] = input.buttons[2];
- mapped->buttons[kButtonTertiary] = input.buttons[0];
- mapped->buttons[kButtonQuaternary] = input.buttons[3];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[4];
- mapped->buttons[kButtonRightShoulder] = input.buttons[5];
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[3]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[4]);
- mapped->buttons[kButtonBackSelect] = input.buttons[8];
- mapped->buttons[kButtonStart] = input.buttons[9];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[10];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[11];
- mapped->buttons[kButtonDpadUp] = AxisNegativeAsButton(input.axes[7]);
- mapped->buttons[kButtonDpadDown] = AxisPositiveAsButton(input.axes[7]);
- mapped->buttons[kButtonDpadLeft] = AxisNegativeAsButton(input.axes[6]);
- mapped->buttons[kButtonDpadRight] = AxisPositiveAsButton(input.axes[6]);
- mapped->buttons[kButtonMeta] = input.buttons[12];
- mapped->buttons[kTouchpadButton] = input.buttons[13];
- mapped->axes[kAxisRightStickY] = input.axes[5];
-
- mapped->buttonsLength = kNumDualshock4Buttons;
- mapped->axesLength = kNumAxes;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[5];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[3]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[4]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[8];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[11];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[7]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[7]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ AxisPositiveAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[12];
+ mapped->buttons[DUALSHOCK_BUTTON_TOUCHPAD] = input.buttons[13];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
+
+ mapped->buttonsLength = DUALSHOCK_BUTTON_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperXGEAR(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperXGEAR(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[2];
- mapped->buttons[kButtonSecondary] = input.buttons[1];
- mapped->buttons[kButtonTertiary] = input.buttons[3];
- mapped->buttons[kButtonQuaternary] = input.buttons[0];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[6];
- mapped->buttons[kButtonRightShoulder] = input.buttons[7];
- mapped->buttons[kButtonLeftTrigger] = input.buttons[4];
- mapped->buttons[kButtonRightTrigger] = input.buttons[5];
- mapped->buttons[kButtonDpadUp] = AxisNegativeAsButton(input.axes[5]);
- mapped->buttons[kButtonDpadDown] = AxisPositiveAsButton(input.axes[5]);
- mapped->buttons[kButtonDpadLeft] = AxisNegativeAsButton(input.axes[4]);
- mapped->buttons[kButtonDpadRight] = AxisPositiveAsButton(input.axes[4]);
- mapped->axes[kAxisRightStickX] = input.axes[3];
- mapped->axes[kAxisRightStickY] = input.axes[2];
- mapped->buttonsLength = kNumButtons - 1; // no Meta on this device
- mapped->axesLength = kNumAxes;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[5];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[4]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ AxisPositiveAsButton(input.axes[4]);
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[2];
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; // no Meta on this device
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-
-void MapperDragonRiseGeneric(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperDragonRiseGeneric(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonDpadUp] = AxisNegativeAsButton(input.axes[6]);
- mapped->buttons[kButtonDpadDown] = AxisPositiveAsButton(input.axes[6]);
- mapped->buttons[kButtonDpadLeft] = AxisNegativeAsButton(input.axes[5]);
- mapped->buttons[kButtonDpadRight] = AxisPositiveAsButton(input.axes[5]);
- mapped->axes[kAxisLeftStickX] = input.axes[0];
- mapped->axes[kAxisLeftStickY] = input.axes[1];
- mapped->axes[kAxisRightStickX] = input.axes[3];
- mapped->axes[kAxisRightStickY] = input.axes[4];
- mapped->buttonsLength = kNumButtons - 1; // no Meta on this device
- mapped->axesLength = kNumAxes;
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ AxisPositiveAsButton(input.axes[5]);
+ mapped->axes[AXIS_INDEX_LEFT_STICK_X] = input.axes[0];
+ mapped->axes[AXIS_INDEX_LEFT_STICK_Y] = input.axes[1];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4];
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; // no Meta on this device
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperOnLiveWireless(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperOnLiveWireless(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[2]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[5]);
- mapped->buttons[kButtonBackSelect] = input.buttons[6];
- mapped->buttons[kButtonStart] = input.buttons[7];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[9];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[10];
- mapped->buttons[kButtonDpadUp] = AxisNegativeAsButton(input.axes[7]);
- mapped->buttons[kButtonDpadDown] = AxisPositiveAsButton(input.axes[7]);
- mapped->buttons[kButtonDpadLeft] = AxisNegativeAsButton(input.axes[6]);
- mapped->buttons[kButtonDpadRight] = AxisPositiveAsButton(input.axes[6]);
- mapped->buttons[kButtonMeta] = input.buttons[8];
- mapped->axes[kAxisRightStickX] = input.axes[3];
- mapped->axes[kAxisRightStickY] = input.axes[4];
-
- mapped->buttonsLength = kNumButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[2]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[7]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[7]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ AxisPositiveAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[8];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4];
+
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
+void MapperADT1(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
+ *mapped = input;
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[4]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = NullButton();
+ mapped->buttons[BUTTON_INDEX_START] = NullButton();
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[8];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[7]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[7]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ AxisPositiveAsButton(input.axes[6]);
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[6];
+
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
+}
struct MappingData {
const char* const vendor_id;
const char* const product_id;
GamepadStandardMappingFunction function;
} AvailableMappings[] = {
- // http://www.linux-usb.org/usb.ids
- { "0079", "0006", MapperDragonRiseGeneric }, // DragonRise Generic USB
- { "045e", "028e", MapperXInputStyleGamepad }, // Xbox 360 Controller
- { "045e", "028f", MapperXInputStyleGamepad }, // Xbox 360 Wireless Controller
- { "046d", "c21d", MapperXInputStyleGamepad }, // Logitech F310
- { "046d", "c21e", MapperXInputStyleGamepad }, // Logitech F510
- { "046d", "c21f", MapperXInputStyleGamepad }, // Logitech F710
- { "054c", "0268", MapperPlaystationSixAxis }, // Playstation SIXAXIS
- { "054c", "05c4", MapperDualshock4 }, // Playstation Dualshock 4
- { "0925", "0005", MapperLakeviewResearch }, // SmartJoy PLUS Adapter
- { "0925", "8866", MapperLakeviewResearch }, // WiseGroup MP-8866
- { "0e8f", "0003", MapperXGEAR }, // XFXforce XGEAR PS2 Controller
- { "2378", "1008", MapperOnLiveWireless }, // OnLive Controller (Bluetooth)
- { "2378", "100a", MapperOnLiveWireless }, // OnLive Controller (Wired)
+ // http://www.linux-usb.org/usb.ids
+ {"0079", "0006", MapperDragonRiseGeneric}, // DragonRise Generic USB
+ {"045e", "028e", MapperXInputStyleGamepad}, // Xbox 360 Controller
+ {"045e",
+ "028f",
+ MapperXInputStyleGamepad}, // Xbox 360 Wireless Controller
+ {"046d", "c21d", MapperXInputStyleGamepad}, // Logitech F310
+ {"046d", "c21e", MapperXInputStyleGamepad}, // Logitech F510
+ {"046d", "c21f", MapperXInputStyleGamepad}, // Logitech F710
+ {"054c", "0268", MapperPlaystationSixAxis}, // Playstation SIXAXIS
+ {"054c", "05c4", MapperDualshock4}, // Playstation Dualshock 4
+ {"0925", "0005", MapperLakeviewResearch}, // SmartJoy PLUS Adapter
+ {"0925", "8866", MapperLakeviewResearch}, // WiseGroup MP-8866
+ {"0e8f", "0003", MapperXGEAR}, // XFXforce XGEAR PS2 Controller
+ {"2378", "1008", MapperOnLiveWireless}, // OnLive Controller (Bluetooth)
+ {"2378", "100a", MapperOnLiveWireless}, // OnLive Controller (Wired)
+ {"18d1", "2c40", MapperADT1}, // ADT-1 Controller
};
} // namespace
diff --git a/chromium/content/browser/gamepad/gamepad_standard_mappings_mac.mm b/chromium/content/browser/gamepad/gamepad_standard_mappings_mac.mm
index 5481f0e9921..ebb08eda640 100644
--- a/chromium/content/browser/gamepad/gamepad_standard_mappings_mac.mm
+++ b/chromium/content/browser/gamepad/gamepad_standard_mappings_mac.mm
@@ -8,221 +8,233 @@ namespace content {
namespace {
-void MapperXbox360Gamepad(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperXbox360Gamepad(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[2]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[5]);
- mapped->buttons[kButtonBackSelect] = input.buttons[9];
- mapped->buttons[kButtonStart] = input.buttons[8];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[6];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[7];
- mapped->buttons[kButtonDpadUp] = input.buttons[11];
- mapped->buttons[kButtonDpadDown] = input.buttons[12];
- mapped->buttons[kButtonDpadLeft] = input.buttons[13];
- mapped->buttons[kButtonDpadRight] = input.buttons[14];
- mapped->buttons[kButtonMeta] = input.buttons[10];
- mapped->axes[kAxisRightStickX] = input.axes[3];
- mapped->axes[kAxisRightStickY] = input.axes[4];
- mapped->buttonsLength = kNumButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[2]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[8];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = input.buttons[11];
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = input.buttons[12];
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = input.buttons[13];
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] = input.buttons[14];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[10];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4];
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperPlaystationSixAxis(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperPlaystationSixAxis(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[14];
- mapped->buttons[kButtonSecondary] = input.buttons[13];
- mapped->buttons[kButtonTertiary] = input.buttons[15];
- mapped->buttons[kButtonQuaternary] = input.buttons[12];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[10];
- mapped->buttons[kButtonRightShoulder] = input.buttons[11];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[14];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[13];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[15];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[12];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[11];
- mapped->buttons[kButtonLeftTrigger] = ButtonFromButtonAndAxis(
- input.buttons[8], input.axes[14]);
- mapped->buttons[kButtonRightTrigger] = ButtonFromButtonAndAxis(
- input.buttons[9], input.axes[15]);
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] =
+ ButtonFromButtonAndAxis(input.buttons[8], input.axes[14]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] =
+ ButtonFromButtonAndAxis(input.buttons[9], input.axes[15]);
- mapped->buttons[kButtonBackSelect] = input.buttons[0];
- mapped->buttons[kButtonStart] = input.buttons[3];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[1];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[2];
// The SixAxis Dpad is pressure sensative
- mapped->buttons[kButtonDpadUp] = ButtonFromButtonAndAxis(
- input.buttons[4], input.axes[10]);
- mapped->buttons[kButtonDpadDown] = ButtonFromButtonAndAxis(
- input.buttons[6], input.axes[12]);
- mapped->buttons[kButtonDpadLeft] = ButtonFromButtonAndAxis(
- input.buttons[7], input.axes[13]);
- mapped->buttons[kButtonDpadRight] = ButtonFromButtonAndAxis(
- input.buttons[5], input.axes[11]);
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] =
+ ButtonFromButtonAndAxis(input.buttons[4], input.axes[10]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] =
+ ButtonFromButtonAndAxis(input.buttons[6], input.axes[12]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] =
+ ButtonFromButtonAndAxis(input.buttons[7], input.axes[13]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ ButtonFromButtonAndAxis(input.buttons[5], input.axes[11]);
- mapped->buttons[kButtonMeta] = input.buttons[16];
- mapped->axes[kAxisRightStickY] = input.axes[5];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[16];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
- mapped->buttonsLength = kNumButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperDualshock4(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperDualshock4(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
enum Dualshock4Buttons {
- kTouchpadButton = kNumButtons,
- kNumDualshock4Buttons
+ DUALSHOCK_BUTTON_TOUCHPAD = BUTTON_INDEX_COUNT,
+ DUALSHOCK_BUTTON_COUNT
};
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[1];
- mapped->buttons[kButtonSecondary] = input.buttons[2];
- mapped->buttons[kButtonTertiary] = input.buttons[0];
- mapped->buttons[kButtonQuaternary] = input.buttons[3];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[4];
- mapped->buttons[kButtonRightShoulder] = input.buttons[5];
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[3]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[4]);
- mapped->buttons[kButtonBackSelect] = input.buttons[8];
- mapped->buttons[kButtonStart] = input.buttons[9];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[10];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[11];
- mapped->buttons[kButtonMeta] = input.buttons[12];
- mapped->buttons[kTouchpadButton] = input.buttons[13];
- mapped->axes[kAxisRightStickY] = input.axes[5];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[5];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[3]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[4]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[8];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[11];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[12];
+ mapped->buttons[DUALSHOCK_BUTTON_TOUCHPAD] = input.buttons[13];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
DpadFromAxis(mapped, input.axes[9]);
- mapped->buttonsLength = kNumDualshock4Buttons;
- mapped->axesLength = kNumAxes;
+ mapped->buttonsLength = DUALSHOCK_BUTTON_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperDirectInputStyle(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperDirectInputStyle(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[1];
- mapped->buttons[kButtonSecondary] = input.buttons[2];
- mapped->buttons[kButtonTertiary] = input.buttons[0];
- mapped->axes[kAxisRightStickY] = input.axes[5];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
DpadFromAxis(mapped, input.axes[9]);
- mapped->buttonsLength = kNumButtons - 1; /* no meta */
- mapped->axesLength = kNumAxes;
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; /* no meta */
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperMacallyIShock(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperMacallyIShock(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
enum IShockButtons {
- kButtonC = kNumButtons,
- kButtonD,
- kButtonE,
- kNumIShockButtons
+ ISHOCK_BUTTON_C = BUTTON_INDEX_COUNT,
+ ISHOCK_BUTTON_D,
+ ISHOCK_BUTTON_E,
+ ISHOCK_BUTTON_COUNT,
};
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[6];
- mapped->buttons[kButtonSecondary] = input.buttons[5];
- mapped->buttons[kButtonTertiary] = input.buttons[7];
- mapped->buttons[kButtonQuaternary] = input.buttons[4];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[14];
- mapped->buttons[kButtonRightShoulder] = input.buttons[12];
- mapped->buttons[kButtonLeftTrigger] = input.buttons[15];
- mapped->buttons[kButtonRightTrigger] = input.buttons[13];
- mapped->buttons[kButtonBackSelect] = input.buttons[9];
- mapped->buttons[kButtonStart] = input.buttons[10];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[16];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[17];
- mapped->buttons[kButtonDpadUp] = input.buttons[0];
- mapped->buttons[kButtonDpadDown] = input.buttons[1];
- mapped->buttons[kButtonDpadLeft] = input.buttons[2];
- mapped->buttons[kButtonDpadRight] = input.buttons[3];
- mapped->buttons[kButtonMeta] = input.buttons[11];
- mapped->buttons[kButtonC] = input.buttons[8];
- mapped->buttons[kButtonD] = input.buttons[18];
- mapped->buttons[kButtonE] = input.buttons[19];
- mapped->axes[kAxisLeftStickX] = input.axes[0];
- mapped->axes[kAxisLeftStickY] = input.axes[1];
- mapped->axes[kAxisRightStickX] = -input.axes[5];
- mapped->axes[kAxisRightStickY] = input.axes[6];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[5];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[14];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[12];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[15];
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[13];
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[16];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[17];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[11];
+ mapped->buttons[ISHOCK_BUTTON_C] = input.buttons[8];
+ mapped->buttons[ISHOCK_BUTTON_D] = input.buttons[18];
+ mapped->buttons[ISHOCK_BUTTON_E] = input.buttons[19];
+ mapped->axes[AXIS_INDEX_LEFT_STICK_X] = input.axes[0];
+ mapped->axes[AXIS_INDEX_LEFT_STICK_Y] = input.axes[1];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = -input.axes[5];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[6];
- mapped->buttonsLength = kNumIShockButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttonsLength = ISHOCK_BUTTON_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperXGEAR(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperXGEAR(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[2];
- mapped->buttons[kButtonTertiary] = input.buttons[3];
- mapped->buttons[kButtonQuaternary] = input.buttons[0];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[6];
- mapped->buttons[kButtonRightShoulder] = input.buttons[7];
- mapped->buttons[kButtonLeftTrigger] = input.buttons[4];
- mapped->buttons[kButtonRightTrigger] = input.buttons[5];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[5];
DpadFromAxis(mapped, input.axes[9]);
- mapped->axes[kAxisRightStickX] = input.axes[5];
- mapped->axes[kAxisRightStickY] = input.axes[2];
- mapped->buttonsLength = kNumButtons - 1; /* no meta */
- mapped->axesLength = kNumAxes;
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[5];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[2];
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; /* no meta */
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperSmartJoyPLUS(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperSmartJoyPLUS(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[2];
- mapped->buttons[kButtonTertiary] = input.buttons[3];
- mapped->buttons[kButtonQuaternary] = input.buttons[0];
- mapped->buttons[kButtonStart] = input.buttons[8];
- mapped->buttons[kButtonBackSelect] = input.buttons[9];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[6];
- mapped->buttons[kButtonRightShoulder] = input.buttons[7];
- mapped->buttons[kButtonLeftTrigger] = input.buttons[4];
- mapped->buttons[kButtonRightTrigger] = input.buttons[5];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[8];
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[5];
DpadFromAxis(mapped, input.axes[9]);
- mapped->axes[kAxisRightStickY] = input.axes[5];
- mapped->buttonsLength = kNumButtons - 1; /* no meta */
- mapped->axesLength = kNumAxes;
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; /* no meta */
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperDragonRiseGeneric(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperDragonRiseGeneric(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
DpadFromAxis(mapped, input.axes[9]);
- mapped->axes[kAxisLeftStickX] = input.axes[0];
- mapped->axes[kAxisLeftStickY] = input.axes[1];
- mapped->axes[kAxisRightStickX] = input.axes[2];
- mapped->axes[kAxisRightStickY] = input.axes[5];
- mapped->buttonsLength = kNumButtons - 1; /* no meta */
- mapped->axesLength = kNumAxes;
+ mapped->axes[AXIS_INDEX_LEFT_STICK_X] = input.axes[0];
+ mapped->axes[AXIS_INDEX_LEFT_STICK_Y] = input.axes[1];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[2];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1; /* no meta */
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperOnLiveWireless(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperOnLiveWireless(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[0];
- mapped->buttons[kButtonSecondary] = input.buttons[1];
- mapped->buttons[kButtonTertiary] = input.buttons[3];
- mapped->buttons[kButtonQuaternary] = input.buttons[4];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[6];
- mapped->buttons[kButtonRightShoulder] = input.buttons[7];
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[2]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[5]);
- mapped->buttons[kButtonBackSelect] = input.buttons[10];
- mapped->buttons[kButtonStart] = input.buttons[11];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[13];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[14];
- mapped->buttons[kButtonMeta] = input.buttons[12];
- mapped->axes[kAxisRightStickX] = input.axes[3];
- mapped->axes[kAxisRightStickY] = input.axes[4];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[2]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[11];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[13];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[14];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[12];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4];
DpadFromAxis(mapped, input.axes[9]);
- mapped->buttonsLength = kNumButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
+}
+
+void MapperADT1(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
+ *mapped = input;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[3]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[4]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = NullButton();
+ mapped->buttons[BUTTON_INDEX_START] = NullButton();
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[13];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[14];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[12];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
+ DpadFromAxis(mapped, input.axes[9]);
+
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
struct MappingData {
@@ -230,21 +242,22 @@ struct MappingData {
const char* const product_id;
GamepadStandardMappingFunction function;
} AvailableMappings[] = {
- // http://www.linux-usb.org/usb.ids
- { "0079", "0006", MapperDragonRiseGeneric }, // DragonRise Generic USB
- { "045e", "028e", MapperXbox360Gamepad }, // Xbox 360 Controller
- { "045e", "028f", MapperXbox360Gamepad }, // Xbox 360 Wireless Controller
- { "046d", "c216", MapperDirectInputStyle }, // Logitech F310, D mode
- { "046d", "c218", MapperDirectInputStyle }, // Logitech F510, D mode
- { "046d", "c219", MapperDirectInputStyle }, // Logitech F710, D mode
- { "054c", "0268", MapperPlaystationSixAxis }, // Playstation SIXAXIS
- { "054c", "05c4", MapperDualshock4 }, // Playstation Dualshock 4
- { "0925", "0005", MapperSmartJoyPLUS }, // SmartJoy PLUS Adapter
- { "0e8f", "0003", MapperXGEAR }, // XFXforce XGEAR PS2 Controller
- { "2222", "0060", MapperDirectInputStyle }, // Macally iShockX, analog mode
- { "2222", "4010", MapperMacallyIShock }, // Macally iShock
- { "2378", "1008", MapperOnLiveWireless }, // OnLive Controller (Bluetooth)
- { "2378", "100a", MapperOnLiveWireless }, // OnLive Controller (Wired)
+ // http://www.linux-usb.org/usb.ids
+ {"0079", "0006", MapperDragonRiseGeneric}, // DragonRise Generic USB
+ {"045e", "028e", MapperXbox360Gamepad}, // Xbox 360 Controller
+ {"045e", "028f", MapperXbox360Gamepad}, // Xbox 360 Wireless Controller
+ {"046d", "c216", MapperDirectInputStyle}, // Logitech F310, D mode
+ {"046d", "c218", MapperDirectInputStyle}, // Logitech F510, D mode
+ {"046d", "c219", MapperDirectInputStyle}, // Logitech F710, D mode
+ {"054c", "0268", MapperPlaystationSixAxis}, // Playstation SIXAXIS
+ {"054c", "05c4", MapperDualshock4}, // Playstation Dualshock 4
+ {"0925", "0005", MapperSmartJoyPLUS}, // SmartJoy PLUS Adapter
+ {"0e8f", "0003", MapperXGEAR}, // XFXforce XGEAR PS2 Controller
+ {"2222", "0060", MapperDirectInputStyle}, // Macally iShockX, analog mode
+ {"2222", "4010", MapperMacallyIShock}, // Macally iShock
+ {"2378", "1008", MapperOnLiveWireless}, // OnLive Controller (Bluetooth)
+ {"2378", "100a", MapperOnLiveWireless}, // OnLive Controller (Wired)
+ {"18d1", "2c40", MapperADT1}, // ADT-1 Controller
};
} // namespace
diff --git a/chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc b/chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc
index 39ce9fcefab..93c18517453 100644
--- a/chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc
+++ b/chromium/content/browser/gamepad/gamepad_standard_mappings_win.cc
@@ -8,97 +8,116 @@ namespace content {
namespace {
-void MapperLogitechDualAction(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperLogitechDualAction(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[1];
- mapped->buttons[kButtonSecondary] = input.buttons[2];
- mapped->buttons[kButtonTertiary] = input.buttons[0];
- mapped->axes[kAxisRightStickY] = input.axes[5];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
DpadFromAxis(mapped, input.axes[9]);
- mapped->buttonsLength = kNumButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void Mapper2Axes8Keys(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void Mapper2Axes8Keys(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[2];
- mapped->buttons[kButtonSecondary] = input.buttons[1];
- mapped->buttons[kButtonTertiary] = input.buttons[3];
- mapped->buttons[kButtonQuaternary] = input.buttons[0];
- mapped->buttons[kButtonDpadUp] = AxisNegativeAsButton(input.axes[1]);
- mapped->buttons[kButtonDpadDown] = AxisPositiveAsButton(input.axes[1]);
- mapped->buttons[kButtonDpadLeft] = AxisNegativeAsButton(input.axes[0]);
- mapped->buttons[kButtonDpadRight] = AxisPositiveAsButton(input.axes[0]);
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[1]);
+ mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[1]);
+ mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[0]);
+ mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] =
+ AxisPositiveAsButton(input.axes[0]);
// Missing buttons
- mapped->buttons[kButtonLeftTrigger] = blink::WebGamepadButton();
- mapped->buttons[kButtonRightTrigger] = blink::WebGamepadButton();
- mapped->buttons[kButtonLeftThumbstick] = blink::WebGamepadButton();
- mapped->buttons[kButtonRightThumbstick] = blink::WebGamepadButton();
- mapped->buttons[kButtonMeta] = blink::WebGamepadButton();
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = blink::WebGamepadButton();
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = blink::WebGamepadButton();
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = blink::WebGamepadButton();
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = blink::WebGamepadButton();
+ mapped->buttons[BUTTON_INDEX_META] = blink::WebGamepadButton();
- mapped->buttonsLength = kNumButtons - 1;
+ mapped->buttonsLength = BUTTON_INDEX_COUNT - 1;
mapped->axesLength = 0;
}
-void MapperDualshock4(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperDualshock4(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
enum Dualshock4Buttons {
- kTouchpadButton = kNumButtons,
- kNumDualshock4Buttons
+ DUALSHOCK_BUTTON_TOUCHPAD = BUTTON_INDEX_COUNT,
+ DUALSHOCK_BUTTON_COUNT
};
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[1];
- mapped->buttons[kButtonSecondary] = input.buttons[2];
- mapped->buttons[kButtonTertiary] = input.buttons[0];
- mapped->buttons[kButtonQuaternary] = input.buttons[3];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[4];
- mapped->buttons[kButtonRightShoulder] = input.buttons[5];
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[3]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[4]);
- mapped->buttons[kButtonBackSelect] = input.buttons[8];
- mapped->buttons[kButtonStart] = input.buttons[9];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[10];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[11];
- mapped->buttons[kButtonMeta] = input.buttons[12];
- mapped->buttons[kTouchpadButton] = input.buttons[13];
- mapped->axes[kAxisRightStickY] = input.axes[5];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[2];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[5];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[3]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[4]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[8];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[9];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[11];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[12];
+ mapped->buttons[DUALSHOCK_BUTTON_TOUCHPAD] = input.buttons[13];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
DpadFromAxis(mapped, input.axes[9]);
- mapped->buttonsLength = kNumDualshock4Buttons;
- mapped->axesLength = kNumAxes;
+ mapped->buttonsLength = DUALSHOCK_BUTTON_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
-void MapperOnLiveWireless(
- const blink::WebGamepad& input,
- blink::WebGamepad* mapped) {
+void MapperOnLiveWireless(const blink::WebGamepad& input,
+ blink::WebGamepad* mapped) {
*mapped = input;
- mapped->buttons[kButtonPrimary] = input.buttons[0];
- mapped->buttons[kButtonSecondary] = input.buttons[1];
- mapped->buttons[kButtonTertiary] = input.buttons[3];
- mapped->buttons[kButtonQuaternary] = input.buttons[4];
- mapped->buttons[kButtonLeftShoulder] = input.buttons[6];
- mapped->buttons[kButtonRightShoulder] = input.buttons[7];
- mapped->buttons[kButtonLeftTrigger] = AxisToButton(input.axes[2]);
- mapped->buttons[kButtonRightTrigger] = AxisToButton(input.axes[5]);
- mapped->buttons[kButtonBackSelect] = input.buttons[10];
- mapped->buttons[kButtonStart] = input.buttons[11];
- mapped->buttons[kButtonLeftThumbstick] = input.buttons[13];
- mapped->buttons[kButtonRightThumbstick] = input.buttons[14];
- mapped->buttons[kButtonMeta] = input.buttons[12];
- mapped->axes[kAxisRightStickX] = input.axes[3];
- mapped->axes[kAxisRightStickY] = input.axes[4];
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[2]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[5]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[10];
+ mapped->buttons[BUTTON_INDEX_START] = input.buttons[11];
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[13];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[14];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[12];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4];
DpadFromAxis(mapped, input.axes[9]);
- mapped->buttonsLength = kNumButtons;
- mapped->axesLength = kNumAxes;
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
+}
+
+void MapperADT1(const blink::WebGamepad& input, blink::WebGamepad* mapped) {
+ *mapped = input;
+ mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[0];
+ mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[1];
+ mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3];
+ mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[4];
+ mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6];
+ mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7];
+ mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[4]);
+ mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = AxisToButton(input.axes[3]);
+ mapped->buttons[BUTTON_INDEX_BACK_SELECT] = NullButton();
+ mapped->buttons[BUTTON_INDEX_START] = NullButton();
+ mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[13];
+ mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[14];
+ mapped->buttons[BUTTON_INDEX_META] = input.buttons[12];
+ mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5];
+ DpadFromAxis(mapped, input.axes[9]);
+
+ mapped->buttonsLength = BUTTON_INDEX_COUNT;
+ mapped->axesLength = AXIS_INDEX_COUNT;
}
struct MappingData {
@@ -106,12 +125,13 @@ struct MappingData {
const char* const product_id;
GamepadStandardMappingFunction function;
} AvailableMappings[] = {
- // http://www.linux-usb.org/usb.ids
- { "046d", "c216", MapperLogitechDualAction }, // Logitech DualAction
- { "0079", "0011", Mapper2Axes8Keys }, // 2Axes 8Keys Game Pad
- { "054c", "05c4", MapperDualshock4 }, // Playstation Dualshock 4
- { "2378", "1008", MapperOnLiveWireless }, // OnLive Controller (Bluetooth)
- { "2378", "100a", MapperOnLiveWireless }, // OnLive Controller (Wired)
+ // http://www.linux-usb.org/usb.ids
+ {"046d", "c216", MapperLogitechDualAction}, // Logitech DualAction
+ {"0079", "0011", Mapper2Axes8Keys}, // 2Axes 8Keys Game Pad
+ {"054c", "05c4", MapperDualshock4}, // Playstation Dualshock 4
+ {"2378", "1008", MapperOnLiveWireless}, // OnLive Controller (Bluetooth)
+ {"2378", "100a", MapperOnLiveWireless}, // OnLive Controller (Wired)
+ {"18d1", "2c40", MapperADT1}, // ADT-1 Controller
};
} // namespace
diff --git a/chromium/content/browser/gamepad/gamepad_test_helpers.cc b/chromium/content/browser/gamepad/gamepad_test_helpers.cc
index 8837c8e59c3..fc79dcb5ee6 100644
--- a/chromium/content/browser/gamepad/gamepad_test_helpers.cc
+++ b/chromium/content/browser/gamepad/gamepad_test_helpers.cc
@@ -30,6 +30,15 @@ void MockGamepadDataFetcher::WaitForDataRead() {
return read_data_.Wait();
}
+void MockGamepadDataFetcher::WaitForDataReadAndCallbacksIssued() {
+ // The provider will read the data on the background thread (setting the
+ // event) and *then* will issue the callback on the client thread. Waiting for
+ // it to read twice is a simple way to ensure that it was able to issue
+ // callbacks for the first read (if it issued one).
+ WaitForDataRead();
+ WaitForDataRead();
+}
+
void MockGamepadDataFetcher::SetTestData(const blink::WebGamepads& new_data) {
base::AutoLock lock(lock_);
test_data_ = new_data;
diff --git a/chromium/content/browser/gamepad/gamepad_test_helpers.h b/chromium/content/browser/gamepad/gamepad_test_helpers.h
index 2aad5753b27..dbaa9664912 100644
--- a/chromium/content/browser/gamepad/gamepad_test_helpers.h
+++ b/chromium/content/browser/gamepad/gamepad_test_helpers.h
@@ -23,16 +23,21 @@ class MockGamepadDataFetcher : public GamepadDataFetcher {
// returned when the provider queries us.
explicit MockGamepadDataFetcher(const blink::WebGamepads& test_data);
- virtual ~MockGamepadDataFetcher();
+ ~MockGamepadDataFetcher() override;
// GamepadDataFetcher.
- virtual void GetGamepadData(blink::WebGamepads* pads,
- bool devices_changed_hint) OVERRIDE;
+ void GetGamepadData(blink::WebGamepads* pads,
+ bool devices_changed_hint) override;
// Blocks the current thread until the GamepadProvider reads from this
// fetcher on the background thread.
void WaitForDataRead();
+ // Blocks the current thread until the GamepadProvider reads from this
+ // fetcher on the background thread and issued all callbacks related to the
+ // read on the client's thread.
+ void WaitForDataReadAndCallbacksIssued();
+
// Updates the test data.
void SetTestData(const blink::WebGamepads& new_data);
@@ -64,7 +69,7 @@ class GamepadTestHelper {
class GamepadServiceTestConstructor : public GamepadTestHelper {
public:
explicit GamepadServiceTestConstructor(const blink::WebGamepads& test_data);
- virtual ~GamepadServiceTestConstructor();
+ ~GamepadServiceTestConstructor() override;
GamepadService* gamepad_service() { return gamepad_service_; }
MockGamepadDataFetcher* data_fetcher() { return data_fetcher_; }
diff --git a/chromium/content/browser/gamepad/raw_input_data_fetcher_win.h b/chromium/content/browser/gamepad/raw_input_data_fetcher_win.h
index e5a6edd507b..16908c11646 100644
--- a/chromium/content/browser/gamepad/raw_input_data_fetcher_win.h
+++ b/chromium/content/browser/gamepad/raw_input_data_fetcher_win.h
@@ -59,7 +59,7 @@ class RawInputDataFetcher
~RawInputDataFetcher();
// DestructionObserver overrides.
- virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+ virtual void WillDestroyCurrentMessageLoop() override;
bool Available() { return rawinput_available_; }
void StartMonitor();
diff --git a/chromium/content/browser/gamepad/xbox_data_fetcher_mac.h b/chromium/content/browser/gamepad/xbox_data_fetcher_mac.h
index 99a68f209bd..d88ad968233 100644
--- a/chromium/content/browser/gamepad/xbox_data_fetcher_mac.h
+++ b/chromium/content/browser/gamepad/xbox_data_fetcher_mac.h
@@ -163,9 +163,9 @@ class XboxDataFetcher : public XboxController::Delegate {
void AddController(XboxController* controller);
void RemoveController(XboxController* controller);
void RemoveControllerByLocationID(uint32 id);
- virtual void XboxControllerGotData(XboxController* controller,
- const XboxController::Data& data) OVERRIDE;
- virtual void XboxControllerError(XboxController* controller) OVERRIDE;
+ void XboxControllerGotData(XboxController* controller,
+ const XboxController::Data& data) override;
+ void XboxControllerError(XboxController* controller) override;
Delegate* delegate_;
diff --git a/chromium/content/browser/geofencing/OWNERS b/chromium/content/browser/geofencing/OWNERS
new file mode 100644
index 00000000000..1b10b3436d9
--- /dev/null
+++ b/chromium/content/browser/geofencing/OWNERS
@@ -0,0 +1 @@
+mek@chromium.org
diff --git a/chromium/content/browser/geofencing/geofencing_dispatcher_host.cc b/chromium/content/browser/geofencing/geofencing_dispatcher_host.cc
new file mode 100644
index 00000000000..5cae1136bc9
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_dispatcher_host.cc
@@ -0,0 +1,111 @@
+// 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/geofencing/geofencing_dispatcher_host.h"
+
+#include "content/browser/geofencing/geofencing_manager.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_registration.h"
+#include "content/common/geofencing_messages.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+
+namespace content {
+
+static const int kMaxRegionIdLength = 200;
+
+GeofencingDispatcherHost::GeofencingDispatcherHost(
+ GeofencingManager* geofencing_manager)
+ : BrowserMessageFilter(GeofencingMsgStart),
+ manager_(geofencing_manager),
+ weak_factory_(this) {
+}
+
+GeofencingDispatcherHost::~GeofencingDispatcherHost() {
+}
+
+bool GeofencingDispatcherHost::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(GeofencingDispatcherHost, message)
+ IPC_MESSAGE_HANDLER(GeofencingHostMsg_RegisterRegion, OnRegisterRegion)
+ IPC_MESSAGE_HANDLER(GeofencingHostMsg_UnregisterRegion, OnUnregisterRegion)
+ IPC_MESSAGE_HANDLER(GeofencingHostMsg_GetRegisteredRegions,
+ OnGetRegisteredRegions)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void GeofencingDispatcherHost::OnRegisterRegion(
+ int thread_id,
+ int request_id,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ int64 service_worker_registration_id) {
+ // Sanity check on region_id
+ if (region_id.length() > kMaxRegionIdLength) {
+ Send(new GeofencingMsg_RegisterRegionComplete(
+ thread_id, request_id, GeofencingStatus::GEOFENCING_STATUS_ERROR));
+ return;
+ }
+
+ manager_->RegisterRegion(
+ service_worker_registration_id,
+ region_id,
+ region,
+ base::Bind(&GeofencingDispatcherHost::RegisterRegionCompleted,
+ weak_factory_.GetWeakPtr(),
+ thread_id,
+ request_id));
+}
+
+void GeofencingDispatcherHost::OnUnregisterRegion(
+ int thread_id,
+ int request_id,
+ const std::string& region_id,
+ int64 service_worker_registration_id) {
+ // Sanity check on region_id
+ if (region_id.length() > kMaxRegionIdLength) {
+ Send(new GeofencingMsg_UnregisterRegionComplete(
+ thread_id, request_id, GeofencingStatus::GEOFENCING_STATUS_ERROR));
+ return;
+ }
+
+ manager_->UnregisterRegion(
+ service_worker_registration_id,
+ region_id,
+ base::Bind(&GeofencingDispatcherHost::UnregisterRegionCompleted,
+ weak_factory_.GetWeakPtr(),
+ thread_id,
+ request_id));
+}
+
+void GeofencingDispatcherHost::OnGetRegisteredRegions(
+ int thread_id,
+ int request_id,
+ int64 service_worker_registration_id) {
+ GeofencingRegistrations result;
+
+ GeofencingStatus status =
+ manager_->GetRegisteredRegions(service_worker_registration_id, &result);
+ Send(new GeofencingMsg_GetRegisteredRegionsComplete(
+ thread_id, request_id, status, result));
+}
+
+void GeofencingDispatcherHost::RegisterRegionCompleted(
+ int thread_id,
+ int request_id,
+ GeofencingStatus status) {
+ Send(new GeofencingMsg_RegisterRegionComplete(thread_id, request_id, status));
+}
+
+void GeofencingDispatcherHost::UnregisterRegionCompleted(
+ int thread_id,
+ int request_id,
+ GeofencingStatus status) {
+ Send(new GeofencingMsg_UnregisterRegionComplete(
+ thread_id, request_id, status));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geofencing/geofencing_dispatcher_host.h b/chromium/content/browser/geofencing/geofencing_dispatcher_host.h
new file mode 100644
index 00000000000..40ed3a8487b
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_dispatcher_host.h
@@ -0,0 +1,58 @@
+// 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_GEOFENCING_GEOFENCING_DISPATCHER_HOST_H_
+#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_DISPATCHER_HOST_H_
+
+#include "content/common/geofencing_status.h"
+#include "content/public/browser/browser_message_filter.h"
+
+namespace blink {
+struct WebCircularGeofencingRegion;
+}
+
+namespace content {
+
+class GeofencingManager;
+class ServiceWorkerContextWrapper;
+
+class GeofencingDispatcherHost : public BrowserMessageFilter {
+ public:
+ explicit GeofencingDispatcherHost(GeofencingManager* geofencing_manager);
+
+ private:
+ ~GeofencingDispatcherHost() override;
+
+ // BrowserMessageFilter implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ void OnRegisterRegion(int thread_id,
+ int request_id,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ int64 service_worker_registration_id);
+ void OnUnregisterRegion(int thread_id,
+ int request_id,
+ const std::string& region_id,
+ int64 service_worker_registration_id);
+ void OnGetRegisteredRegions(int thread_id,
+ int request_id,
+ int64 service_worker_registration_id);
+
+ void RegisterRegionCompleted(int thread_id,
+ int request_id,
+ GeofencingStatus result);
+ void UnregisterRegionCompleted(int thread_id,
+ int request_id,
+ GeofencingStatus result);
+
+ scoped_refptr<GeofencingManager> manager_;
+ base::WeakPtrFactory<GeofencingDispatcherHost> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeofencingDispatcherHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOFENCING_GEOFENCING_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/geofencing/geofencing_manager.cc b/chromium/content/browser/geofencing/geofencing_manager.cc
new file mode 100644
index 00000000000..6899c73067a
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_manager.cc
@@ -0,0 +1,371 @@
+// 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/geofencing/geofencing_manager.h"
+
+#include <algorithm>
+
+#include "base/callback.h"
+#include "content/browser/geofencing/geofencing_service.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
+#include "url/gurl.h"
+
+namespace content {
+
+struct GeofencingManager::Registration {
+ Registration(int64 service_worker_registration_id,
+ const GURL& service_worker_origin,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback,
+ int64 geofencing_registration_id);
+ int64 service_worker_registration_id;
+ GURL service_worker_origin;
+ std::string region_id;
+ blink::WebCircularGeofencingRegion region;
+
+ // Registration ID as returned by the |GeofencingService|.
+ int64 geofencing_registration_id;
+
+ // Callback to call when registration is completed. This field is reset when
+ // registration is complete.
+ StatusCallback registration_callback;
+
+ // Returns true if registration has been completed, and thus should be
+ // included in calls to GetRegisteredRegions.
+ bool is_active() const { return registration_callback.is_null(); }
+};
+
+GeofencingManager::Registration::Registration(
+ int64 service_worker_registration_id,
+ const GURL& service_worker_origin,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const GeofencingManager::StatusCallback& callback,
+ int64 geofencing_registration_id)
+ : service_worker_registration_id(service_worker_registration_id),
+ service_worker_origin(service_worker_origin),
+ region_id(region_id),
+ region(region),
+ geofencing_registration_id(geofencing_registration_id),
+ registration_callback(callback) {
+}
+
+GeofencingManager::GeofencingManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
+ : service_(nullptr), service_worker_context_(service_worker_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+GeofencingManager::~GeofencingManager() {
+}
+
+void GeofencingManager::Init() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GeofencingManager::InitOnIO, this));
+}
+
+void GeofencingManager::Shutdown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GeofencingManager::ShutdownOnIO, this));
+}
+
+void GeofencingManager::InitOnIO() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ service_ = GeofencingServiceImpl::GetInstance();
+}
+
+void GeofencingManager::ShutdownOnIO() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // Clean up all registrations with the |GeofencingService|.
+ // TODO(mek): This will need to change to support geofence registrations that
+ // outlive the browser, although removing the references to this
+ // |GeofencingManager| from the |GeofencingService| will still be needed.
+ for (const auto& registration : registrations_by_id_) {
+ service_->UnregisterRegion(registration.first);
+ }
+}
+
+void GeofencingManager::RegisterRegion(
+ int64 service_worker_registration_id,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // TODO(mek): Validate region_id and region.
+
+ // Look up service worker. In unit tests |service_worker_context_| might not
+ // be set.
+ GURL service_worker_origin;
+ if (service_worker_context_.get()) {
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->context()->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER);
+ return;
+ }
+
+ service_worker_origin = service_worker_registration->pattern().GetOrigin();
+ }
+
+ if (!service_->IsServiceAvailable()) {
+ callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
+ return;
+ }
+
+ if (FindRegistration(service_worker_registration_id, region_id)) {
+ // Already registered, return an error.
+ // TODO(mek): Use a more specific error code.
+ callback.Run(GEOFENCING_STATUS_ERROR);
+ return;
+ }
+
+ AddRegistration(service_worker_registration_id,
+ service_worker_origin,
+ region_id,
+ region,
+ callback,
+ service_->RegisterRegion(region, this));
+}
+
+void GeofencingManager::UnregisterRegion(int64 service_worker_registration_id,
+ const std::string& region_id,
+ const StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // TODO(mek): Validate region_id.
+
+ // Look up service worker. In unit tests |service_worker_context_| might not
+ // be set.
+ if (service_worker_context_.get()) {
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->context()->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER);
+ return;
+ }
+ }
+
+ if (!service_->IsServiceAvailable()) {
+ callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
+ return;
+ }
+
+ Registration* registration =
+ FindRegistration(service_worker_registration_id, region_id);
+ if (!registration) {
+ // Not registered, return an error.
+ callback.Run(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED);
+ return;
+ }
+
+ if (!registration->is_active()) {
+ // Started registration, but not completed yet, error.
+ callback.Run(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED);
+ return;
+ }
+
+ service_->UnregisterRegion(registration->geofencing_registration_id);
+ ClearRegistration(registration);
+ callback.Run(GEOFENCING_STATUS_OK);
+}
+
+GeofencingStatus GeofencingManager::GetRegisteredRegions(
+ int64 service_worker_registration_id,
+ std::map<std::string, blink::WebCircularGeofencingRegion>* result) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ CHECK(result);
+
+ // Look up service worker. In unit tests |service_worker_context_| might not
+ // be set.
+ if (service_worker_context_.get()) {
+ ServiceWorkerRegistration* service_worker_registration =
+ service_worker_context_->context()->GetLiveRegistration(
+ service_worker_registration_id);
+ if (!service_worker_registration) {
+ return GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER;
+ }
+ }
+
+ if (!service_->IsServiceAvailable()) {
+ return GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE;
+ }
+
+ // Populate result, filtering out inactive registrations.
+ result->clear();
+ ServiceWorkerRegistrationsMap::iterator registrations =
+ registrations_.find(service_worker_registration_id);
+ if (registrations == registrations_.end())
+ return GEOFENCING_STATUS_OK;
+ for (const auto& registration : registrations->second) {
+ if (registration.second.is_active())
+ (*result)[registration.first] = registration.second.region;
+ }
+ return GEOFENCING_STATUS_OK;
+}
+
+void GeofencingManager::RegistrationFinished(int64 geofencing_registration_id,
+ GeofencingStatus status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ Registration* registration = FindRegistrationById(geofencing_registration_id);
+ DCHECK(registration);
+ DCHECK(!registration->is_active());
+ registration->registration_callback.Run(status);
+ registration->registration_callback.Reset();
+
+ // If the registration wasn't succesful, remove it from our storage.
+ if (status != GEOFENCING_STATUS_OK)
+ ClearRegistration(registration);
+}
+
+void GeofencingManager::RegionEntered(int64 geofencing_registration_id) {
+ DispatchGeofencingEvent(blink::WebGeofencingEventTypeEnter,
+ geofencing_registration_id);
+}
+
+void GeofencingManager::RegionExited(int64 geofencing_registration_id) {
+ DispatchGeofencingEvent(blink::WebGeofencingEventTypeLeave,
+ geofencing_registration_id);
+}
+
+GeofencingManager::Registration* GeofencingManager::FindRegistration(
+ int64 service_worker_registration_id,
+ const std::string& region_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ServiceWorkerRegistrationsMap::iterator registrations_iterator =
+ registrations_.find(service_worker_registration_id);
+ if (registrations_iterator == registrations_.end())
+ return nullptr;
+ RegionIdRegistrationMap::iterator registration =
+ registrations_iterator->second.find(region_id);
+ if (registration == registrations_iterator->second.end())
+ return nullptr;
+ return &registration->second;
+}
+
+GeofencingManager::Registration* GeofencingManager::FindRegistrationById(
+ int64 geofencing_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ RegistrationIdRegistrationMap::iterator registration_iterator =
+ registrations_by_id_.find(geofencing_registration_id);
+ if (registration_iterator == registrations_by_id_.end())
+ return nullptr;
+ return &registration_iterator->second->second;
+}
+
+GeofencingManager::Registration& GeofencingManager::AddRegistration(
+ int64 service_worker_registration_id,
+ const GURL& service_worker_origin,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback,
+ int64 geofencing_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!FindRegistration(service_worker_registration_id, region_id));
+ RegionIdRegistrationMap::iterator registration =
+ registrations_[service_worker_registration_id]
+ .insert(std::make_pair(region_id,
+ Registration(service_worker_registration_id,
+ service_worker_origin,
+ region_id,
+ region,
+ callback,
+ geofencing_registration_id)))
+ .first;
+ registrations_by_id_[geofencing_registration_id] = registration;
+ return registration->second;
+}
+
+void GeofencingManager::ClearRegistration(Registration* registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ registrations_by_id_.erase(registration->geofencing_registration_id);
+ ServiceWorkerRegistrationsMap::iterator registrations_iterator =
+ registrations_.find(registration->service_worker_registration_id);
+ DCHECK(registrations_iterator != registrations_.end());
+ registrations_iterator->second.erase(registration->region_id);
+ if (registrations_iterator->second.empty())
+ registrations_.erase(registrations_iterator);
+}
+
+void GeofencingManager::DispatchGeofencingEvent(
+ blink::WebGeofencingEventType event_type,
+ int64 geofencing_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ Registration* registration = FindRegistrationById(geofencing_registration_id);
+ if (!registration ||
+ registration->service_worker_registration_id ==
+ kInvalidServiceWorkerRegistrationId) {
+ // TODO(mek): Log/track these failures.
+ return;
+ }
+
+ service_worker_context_->context()->storage()->FindRegistrationForId(
+ registration->service_worker_registration_id,
+ registration->service_worker_origin,
+ base::Bind(&GeofencingManager::DeliverGeofencingEvent,
+ this,
+ event_type,
+ geofencing_registration_id));
+}
+
+void GeofencingManager::DeliverGeofencingEvent(
+ blink::WebGeofencingEventType event_type,
+ int64 geofencing_registration_id,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ Registration* registration = FindRegistrationById(geofencing_registration_id);
+ if (!registration) {
+ // Geofence got unregistered in the meantime, no longer need to deliver
+ // event.
+ return;
+ }
+
+ if (service_worker_status != SERVICE_WORKER_OK) {
+ // TODO(mek): SW no longer exists, somehow handle this.
+ return;
+ }
+
+ ServiceWorkerVersion* active_version =
+ service_worker_registration->active_version();
+ if (!active_version) {
+ // TODO(mek): No active version, potentially because one is still being
+ // installed. Handle this somehow.
+ return;
+ }
+
+ // Hold on to the service worker registration in the callback to keep it 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 =
+ base::Bind(&GeofencingManager::DeliverGeofencingEventEnd,
+ this,
+ service_worker_registration);
+ active_version->DispatchGeofencingEvent(dispatch_event_callback,
+ event_type,
+ registration->region_id,
+ registration->region);
+}
+
+void GeofencingManager::DeliverGeofencingEventEnd(
+ const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // TODO(mek): log/check result.
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geofencing/geofencing_manager.h b/chromium/content/browser/geofencing/geofencing_manager.h
new file mode 100644
index 00000000000..29c52e4830b
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_manager.h
@@ -0,0 +1,179 @@
+// 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_GEOFENCING_GEOFENCING_MANAGER_H_
+#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/geofencing/geofencing_registration_delegate.h"
+#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/common/content_export.h"
+#include "content/common/geofencing_status.h"
+#include "content/common/service_worker/service_worker_status_code.h"
+
+template <typename T>
+struct DefaultSingletonTraits;
+class GURL;
+
+namespace blink {
+struct WebCircularGeofencingRegion;
+};
+
+namespace content {
+
+class GeofencingService;
+class ServiceWorkerContextWrapper;
+class ServiceWorkerRegistration;
+
+// This is the main API to the geofencing subsystem. There is one instance of
+// this class per storage partition.
+// This class is responsible for keeping track of which geofences are currently
+// registered by websites/workers, persisting this list of registrations and
+// registering them with the global |GeofencingService|.
+// This class is created on the UI thread, but all its methods should only be
+// called from the IO thread.
+// TODO(mek): Implement some kind of persistence of registrations.
+// TODO(mek): Unregister a geofence when the ServiceWorkerRegistration it
+// belongs to goes away.
+class CONTENT_EXPORT GeofencingManager
+ : NON_EXPORTED_BASE(public GeofencingRegistrationDelegate),
+ public base::RefCountedThreadSafe<GeofencingManager> {
+ public:
+ typedef base::Callback<void(GeofencingStatus)> StatusCallback;
+
+ explicit GeofencingManager(
+ const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
+
+ // Init and Shutdown are for use on the UI thread when the storagepartition is
+ // being setup and torn down.
+ void Init();
+ void Shutdown();
+
+ // Initiates registration of a new geofence. StatusCallback is called when
+ // registration has completed or failed (which could possibly be before
+ // RegisterRegion returns.
+ // Attempting to register a region with the same ID as an already registered
+ // (or in progress of being registered) region will fail.
+ // TODO(mek): Behavior when using an already used ID might need to be revised
+ // depending on what the actual spec ends up saying about this.
+ void RegisterRegion(int64 service_worker_registration_id,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback);
+
+ // Unregister a region that was previously registered by a call to
+ // RegisterRegion. Any attempt to unregister a region that has not been
+ // registered, or for which the registration is still in progress
+ // (RegisterRegion hasn't called its callback yet) will fail.
+ // TODO(mek): Maybe better behavior would be to allow unregistering still
+ // in-progress registrations.
+ void UnregisterRegion(int64 service_worker_registration_id,
+ const std::string& region_id,
+ const StatusCallback& callback);
+
+ // Returns all currently registered regions. In case of failure (no geofencing
+ // provider available for example) return an error status, while leaving
+ // |regions| untouched.
+ // This only returns regions for which the callback passed to RegisterRegion
+ // has been called already (so it doesn't include still in progress
+ // registrations).
+ GeofencingStatus GetRegisteredRegions(
+ int64 service_worker_registration_id,
+ std::map<std::string, blink::WebCircularGeofencingRegion>* result);
+
+ void SetServiceForTesting(GeofencingService* service) {
+ service_ = service;
+ }
+
+ protected:
+ friend class base::RefCountedThreadSafe<GeofencingManager>;
+ ~GeofencingManager() override;
+
+ private:
+ // Internal bookkeeping associated with each registered geofence.
+ struct Registration;
+
+ void InitOnIO();
+ void ShutdownOnIO();
+
+ // GeofencingRegistrationDelegate implementation.
+ void RegistrationFinished(int64 geofencing_registration_id,
+ GeofencingStatus status) override;
+ void RegionEntered(int64 geofencing_registration_id) override;
+ void RegionExited(int64 geofencing_registration_id) override;
+
+ // Looks up a particular geofence registration. Returns nullptr if no
+ // registration with the given IDs exists.
+ Registration* FindRegistration(int64 service_worker_registration_id,
+ const std::string& region_id);
+
+ // Looks up a particular geofence registration. Returns nullptr if no
+ // registration with the given ID exists.
+ Registration* FindRegistrationById(int64 geofencing_registration_id);
+
+ // Registers a new registration, returning a reference to the newly inserted
+ // object. Assumes no registration with the same IDs currently exists.
+ Registration& AddRegistration(
+ int64 service_worker_registration_id,
+ const GURL& service_worker_origin,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback,
+ int64 geofencing_registration_id);
+
+ // Clears a registration.
+ void ClearRegistration(Registration* registration);
+
+ // Starts dispatching a particular geofencing |event_type| for the geofence
+ // registration with the given ID. This first looks up the Service Worker
+ // Registration the geofence is associated with, and then attempts to deliver
+ // the event to that service worker.
+ void DispatchGeofencingEvent(blink::WebGeofencingEventType event_type,
+ int64 geofencing_registration_id);
+
+ // Delivers an event to the specified service worker for the given geofence.
+ // If the geofence registration id is no longer valid, this method does
+ // nothing. This assumes the |service_worker_registration| is the service
+ // worker the geofence registration is associated with.
+ void DeliverGeofencingEvent(blink::WebGeofencingEventType event_type,
+ int64 geofencing_registration_id,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration);
+
+ // Called when delivery of a geofence event to a service worker has finished
+ // (or failed to finish).
+ void DeliverGeofencingEventEnd(const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration,
+ ServiceWorkerStatusCode service_worker_status);
+
+ // Map of all registered regions for a particular service worker registration.
+ typedef std::map<std::string, Registration> RegionIdRegistrationMap;
+ // Map of service worker registration id to the regions registered by that
+ // service worker.
+ typedef std::map<int64, RegionIdRegistrationMap>
+ ServiceWorkerRegistrationsMap;
+ ServiceWorkerRegistrationsMap registrations_;
+
+ // Map of all registered regions by geofencing_registration_id.
+ typedef std::map<int64, RegionIdRegistrationMap::iterator>
+ RegistrationIdRegistrationMap;
+ RegistrationIdRegistrationMap registrations_by_id_;
+
+ GeofencingService* service_;
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeofencingManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOFENCING_GEOFENCING_MANAGER_H_
diff --git a/chromium/content/browser/geofencing/geofencing_manager_unittest.cc b/chromium/content/browser/geofencing/geofencing_manager_unittest.cc
new file mode 100644
index 00000000000..cf64b9faa04
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_manager_unittest.cc
@@ -0,0 +1,414 @@
+// 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 "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "content/browser/geofencing/geofencing_manager.h"
+#include "content/browser/geofencing/geofencing_service.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+
+using blink::WebCircularGeofencingRegion;
+typedef std::map<std::string, WebCircularGeofencingRegion> RegionMap;
+
+namespace {
+
+static const char* kTestRegionId = "region-id";
+static const int64 kTestServiceWorkerRegistrationId = 123;
+static const int64 kTestServiceWorkerRegistrationId2 = 456;
+static const int64 kTestGeofencingRegistrationId = 42;
+static const int64 kTestGeofencingRegistrationId2 = 43;
+
+bool RegionsMatch(const WebCircularGeofencingRegion& expected,
+ const WebCircularGeofencingRegion& arg) {
+ return testing::Matches(expected.latitude)(arg.latitude) &&
+ testing::Matches(expected.longitude)(arg.longitude) &&
+ testing::Matches(expected.radius)(arg.radius);
+}
+}
+
+namespace content {
+
+class TestGeofencingService : public GeofencingService {
+ public:
+ MOCK_METHOD0(IsServiceAvailable, bool());
+ MOCK_METHOD2(RegisterRegion,
+ int64(const WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate));
+ MOCK_METHOD1(UnregisterRegion, void(int64 geofencing_registration_id));
+};
+
+ACTION_P(SaveDelegate, delegate) {
+ *delegate = arg1;
+}
+
+ACTION_P(QuitRunner, runner) {
+ runner->Quit();
+}
+
+MATCHER_P(WebCircularGeofencingRegionEq, expected, "") {
+ return RegionsMatch(expected, arg);
+}
+
+class StatusCatcher {
+ public:
+ StatusCatcher() : was_called_(false), runner_(new MessageLoopRunner()) {}
+
+ void Done(GeofencingStatus status) {
+ CHECK(!was_called_);
+ result_ = status;
+ was_called_ = true;
+ runner_->Quit();
+ }
+
+ GeofencingStatus Wait() {
+ runner_->Run();
+ CHECK(was_called_);
+ return result_;
+ }
+
+ private:
+ bool was_called_;
+ GeofencingStatus result_;
+ scoped_refptr<MessageLoopRunner> runner_;
+};
+
+class GeofencingManagerTest : public testing::Test {
+ public:
+ GeofencingManagerTest() : service_(nullptr) {
+ test_region_.latitude = 37.421999;
+ test_region_.longitude = -122.084015;
+ test_region_.radius = 100;
+ expected_regions_[kTestRegionId] = test_region_;
+ }
+
+ void SetUp() override {
+ service_ = new TestGeofencingService();
+ ON_CALL(*service_, IsServiceAvailable())
+ .WillByDefault(testing::Return(false));
+ manager_ = new GeofencingManager(nullptr /* ServiceWorkerContextWrapper */);
+ manager_->SetServiceForTesting(service_);
+ }
+
+ void TearDown() override {
+ manager_ = nullptr;
+ delete service_;
+ service_ = nullptr;
+ }
+
+ void SetHasProviderForTests() {
+ ON_CALL(*service_, IsServiceAvailable())
+ .WillByDefault(testing::Return(true));
+ }
+
+ GeofencingStatus RegisterRegionSync(
+ int64 service_worker_registration_id,
+ const std::string& id,
+ const WebCircularGeofencingRegion& region) {
+ StatusCatcher result;
+ manager_->RegisterRegion(
+ service_worker_registration_id,
+ id,
+ region,
+ base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
+ return result.Wait();
+ }
+
+ GeofencingStatus RegisterRegionSyncWithServiceResult(
+ int64 service_worker_registration_id,
+ const std::string& id,
+ const WebCircularGeofencingRegion& region,
+ GeofencingStatus service_status,
+ int64 geofencing_registration_id) {
+ StatusCatcher result;
+ GeofencingRegistrationDelegate* delegate = 0;
+ EXPECT_CALL(
+ *service_,
+ RegisterRegion(WebCircularGeofencingRegionEq(region), testing::_))
+ .WillOnce(testing::DoAll(SaveDelegate(&delegate),
+ testing::Return(geofencing_registration_id)));
+ manager_->RegisterRegion(
+ service_worker_registration_id,
+ id,
+ region,
+ base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
+ CHECK(delegate);
+ delegate->RegistrationFinished(geofencing_registration_id, service_status);
+ return result.Wait();
+ }
+
+ GeofencingStatus UnregisterRegionSync(int64 service_worker_registration_id,
+ const std::string& id,
+ bool should_call_service,
+ int64 geofencing_registration_id = 0) {
+ StatusCatcher result;
+ if (should_call_service) {
+ EXPECT_CALL(*service_, UnregisterRegion(geofencing_registration_id));
+ }
+ manager_->UnregisterRegion(
+ service_worker_registration_id,
+ id,
+ base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
+ return result.Wait();
+ }
+
+ void VerifyRegions(int64 service_worker_registration_id,
+ const RegionMap& expected_regions) {
+ RegionMap regions;
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ manager_->GetRegisteredRegions(service_worker_registration_id,
+ &regions));
+ EXPECT_EQ(expected_regions.size(), regions.size());
+ for (RegionMap::const_iterator it = expected_regions.begin();
+ it != expected_regions.end();
+ ++it) {
+ EXPECT_THAT(regions[it->first],
+ WebCircularGeofencingRegionEq(it->second));
+ }
+ }
+
+ protected:
+ TestBrowserThreadBundle threads_;
+ TestGeofencingService* service_;
+ scoped_refptr<GeofencingManager> manager_;
+
+ WebCircularGeofencingRegion test_region_;
+ RegionMap expected_regions_;
+};
+
+TEST_F(GeofencingManagerTest, RegisterRegion_NoService) {
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+ RegisterRegionSync(
+ kTestServiceWorkerRegistrationId, kTestRegionId, test_region_));
+}
+
+TEST_F(GeofencingManagerTest, UnregisterRegion_NoService) {
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+ UnregisterRegionSync(
+ kTestServiceWorkerRegistrationId, kTestRegionId, false));
+}
+
+TEST_F(GeofencingManagerTest, GetRegisteredRegions_NoService) {
+ RegionMap regions;
+ EXPECT_EQ(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE,
+ manager_->GetRegisteredRegions(kTestServiceWorkerRegistrationId,
+ &regions));
+ EXPECT_TRUE(regions.empty());
+}
+
+TEST_F(GeofencingManagerTest, RegisterRegion_FailsInService) {
+ SetHasProviderForTests();
+ EXPECT_EQ(
+ GEOFENCING_STATUS_ERROR,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_ERROR,
+ -1));
+}
+
+TEST_F(GeofencingManagerTest, RegisterRegion_SucceedsInService) {
+ SetHasProviderForTests();
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
+ VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
+}
+
+TEST_F(GeofencingManagerTest, RegisterRegion_AlreadyRegistered) {
+ SetHasProviderForTests();
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
+ VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
+
+ WebCircularGeofencingRegion region2;
+ region2.latitude = 43.2;
+ region2.longitude = 1.45;
+ region2.radius = 8.5;
+ EXPECT_EQ(GEOFENCING_STATUS_ERROR,
+ RegisterRegionSync(
+ kTestServiceWorkerRegistrationId, kTestRegionId, region2));
+ VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
+}
+
+TEST_F(GeofencingManagerTest, UnregisterRegion_NotRegistered) {
+ SetHasProviderForTests();
+ EXPECT_EQ(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED,
+ UnregisterRegionSync(
+ kTestServiceWorkerRegistrationId, kTestRegionId, false));
+}
+
+TEST_F(GeofencingManagerTest, UnregisterRegion_Success) {
+ SetHasProviderForTests();
+
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
+
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ UnregisterRegionSync(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ true,
+ kTestGeofencingRegistrationId));
+ VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
+}
+
+TEST_F(GeofencingManagerTest, GetRegisteredRegions_RegistrationInProgress) {
+ SetHasProviderForTests();
+ StatusCatcher result;
+ GeofencingRegistrationDelegate* delegate = nullptr;
+
+ EXPECT_CALL(
+ *service_,
+ RegisterRegion(WebCircularGeofencingRegionEq(test_region_), testing::_))
+ .WillOnce(testing::DoAll(SaveDelegate(&delegate),
+ testing::Return(kTestGeofencingRegistrationId)));
+ manager_->RegisterRegion(
+ kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
+
+ // At this point the manager should have tried registering the region with
+ // the service, resulting in |delegate| being set. Until the callback is
+ // called the registration is not complete though.
+ EXPECT_NE(delegate, nullptr);
+ VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
+
+ // Now call the callback, and verify the registration completed succesfully.
+ delegate->RegistrationFinished(kTestGeofencingRegistrationId,
+ GEOFENCING_STATUS_OK);
+ EXPECT_EQ(GEOFENCING_STATUS_OK, result.Wait());
+ VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
+}
+
+TEST_F(GeofencingManagerTest, UnregisterRegion_RegistrationInProgress) {
+ SetHasProviderForTests();
+ StatusCatcher result;
+ GeofencingRegistrationDelegate* delegate = nullptr;
+
+ EXPECT_CALL(
+ *service_,
+ RegisterRegion(WebCircularGeofencingRegionEq(test_region_), testing::_))
+ .WillOnce(testing::DoAll(SaveDelegate(&delegate),
+ testing::Return(kTestGeofencingRegistrationId)));
+ manager_->RegisterRegion(
+ kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ base::Bind(&StatusCatcher::Done, base::Unretained(&result)));
+
+ // At this point the manager should have tried registering the region with
+ // the service, resulting in |delegate| being set. Until the callback is
+ // called the registration is not complete though.
+ EXPECT_NE(delegate, nullptr);
+
+ EXPECT_EQ(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED,
+ UnregisterRegionSync(
+ kTestServiceWorkerRegistrationId, kTestRegionId, false));
+}
+
+TEST_F(GeofencingManagerTest, GetRegisteredRegions_NoRegions) {
+ SetHasProviderForTests();
+ VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
+}
+
+TEST_F(GeofencingManagerTest, RegisterRegion_SeparateServiceWorkers) {
+ SetHasProviderForTests();
+
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
+
+ VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
+ VerifyRegions(kTestServiceWorkerRegistrationId2, RegionMap());
+
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId2,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId2));
+
+ VerifyRegions(kTestServiceWorkerRegistrationId, expected_regions_);
+ VerifyRegions(kTestServiceWorkerRegistrationId2, expected_regions_);
+}
+
+TEST_F(GeofencingManagerTest, UnregisterRegion_SeparateServiceWorkers) {
+ SetHasProviderForTests();
+
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId2,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId2));
+
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ UnregisterRegionSync(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ true,
+ kTestGeofencingRegistrationId));
+
+ VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
+ VerifyRegions(kTestServiceWorkerRegistrationId2, expected_regions_);
+
+ EXPECT_EQ(GEOFENCING_STATUS_OK,
+ UnregisterRegionSync(kTestServiceWorkerRegistrationId2,
+ kTestRegionId,
+ true,
+ kTestGeofencingRegistrationId2));
+
+ VerifyRegions(kTestServiceWorkerRegistrationId, RegionMap());
+ VerifyRegions(kTestServiceWorkerRegistrationId2, RegionMap());
+}
+
+TEST_F(GeofencingManagerTest, ShutdownCleansRegistrations) {
+ SetHasProviderForTests();
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
+ EXPECT_EQ(
+ GEOFENCING_STATUS_OK,
+ RegisterRegionSyncWithServiceResult(kTestServiceWorkerRegistrationId,
+ kTestRegionId,
+ test_region_,
+ GEOFENCING_STATUS_OK,
+ kTestGeofencingRegistrationId));
+
+ EXPECT_CALL(*service_, UnregisterRegion(kTestGeofencingRegistrationId))
+ .WillOnce(QuitRunner(runner));
+ manager_->Shutdown();
+ runner->Run();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geofencing/geofencing_provider.h b/chromium/content/browser/geofencing/geofencing_provider.h
new file mode 100644
index 00000000000..dec96b5270b
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_provider.h
@@ -0,0 +1,44 @@
+// 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_GEOFENCING_GEOFENCING_PROVIDER_H_
+#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_PROVIDER_H_
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "content/common/geofencing_status.h"
+
+namespace blink {
+struct WebCircularGeofencingRegion;
+};
+
+namespace content {
+
+class GeofencingProvider {
+ public:
+ typedef base::Callback<void(GeofencingStatus)> StatusCallback;
+
+ virtual ~GeofencingProvider() {}
+
+ // Called by |GeofencingService| to register a new fence. GeofencingService is
+ // responsible for handling things like duplicate regions, so platform
+ // specific implementations shouldn't have to worry about things like that.
+ // Also GeofencingService should be making sure the total number of geofences
+ // that is registered with the platform specific provider does not exceed the
+ // number of regions supported by the platform, although that isn't
+ // implemented yet.
+ // Implementations of RegisterRegion must asynchronously call the |callback|
+ // to indicate success or failure.
+ virtual void RegisterRegion(int64 geofencing_registration_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback) = 0;
+
+ // Called by |GeofencingService| to unregister an existing registration. Will
+ // only be called once for each registration.
+ virtual void UnregisterRegion(int64 geofencing_registration_id) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOFENCING_GEOFENCING_PROVIDER_H_
diff --git a/chromium/content/browser/geofencing/geofencing_registration_delegate.h b/chromium/content/browser/geofencing/geofencing_registration_delegate.h
new file mode 100644
index 00000000000..ead0ec8eed0
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_registration_delegate.h
@@ -0,0 +1,31 @@
+// 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_GEOFENCING_GEOFENCING_REGISTRATION_DELEGATE_H_
+#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_REGISTRATION_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "content/common/geofencing_status.h"
+
+namespace content {
+
+// |GeofencingService| has an instance of this class associated with each
+// geofence registration, and uses it to inform about events related to the
+// registration, such as the geofence finishing being registered.
+// These methods will always be called on the IO thread.
+// TODO(mek): Add methods for geofence enter/leave events.
+class GeofencingRegistrationDelegate {
+ public:
+ virtual void RegistrationFinished(int64 geofencing_registration_id,
+ GeofencingStatus status) = 0;
+ virtual void RegionEntered(int64 geofencing_registration_id) = 0;
+ virtual void RegionExited(int64 geofencing_registration_id) = 0;
+
+ protected:
+ virtual ~GeofencingRegistrationDelegate() {}
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOFENCING_GEOFENCING_REGISTRATION_DELEGATE_H_
diff --git a/chromium/content/browser/geofencing/geofencing_service.cc b/chromium/content/browser/geofencing/geofencing_service.cc
new file mode 100644
index 00000000000..11df9529e4d
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_service.cc
@@ -0,0 +1,199 @@
+// 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/geofencing/geofencing_service.h"
+
+#include "base/memory/singleton.h"
+#include "base/message_loop/message_loop.h"
+#include "content/browser/geofencing/geofencing_provider.h"
+#include "content/browser/geofencing/geofencing_registration_delegate.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+
+namespace content {
+
+namespace {
+
+void RunSoon(const base::Closure& callback) {
+ if (!callback.is_null())
+ base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+}
+
+} // namespace
+
+struct GeofencingServiceImpl::Registration {
+ Registration();
+ Registration(const blink::WebCircularGeofencingRegion& region,
+ int64 geofencing_registration_id,
+ GeofencingRegistrationDelegate* delegate);
+
+ blink::WebCircularGeofencingRegion region;
+ int64 geofencing_registration_id;
+ GeofencingRegistrationDelegate* delegate;
+
+ enum RegistrationState {
+ // In progress of being registered with provider.
+ STATE_REGISTERING,
+ // Currently registered with provider.
+ STATE_REGISTERED,
+ // In progress of being registered with provider, but should be unregistered
+ // and deleted.
+ STATE_SHOULD_UNREGISTER_AND_DELETE,
+ // Not currently registered with provider, but still an active registration.
+ STATE_UNREGISTERED
+ };
+ RegistrationState state;
+};
+
+GeofencingServiceImpl::Registration::Registration()
+ : geofencing_registration_id(-1),
+ delegate(nullptr),
+ state(STATE_UNREGISTERED) {
+}
+
+GeofencingServiceImpl::Registration::Registration(
+ const blink::WebCircularGeofencingRegion& region,
+ int64 geofencing_registration_id,
+ GeofencingRegistrationDelegate* delegate)
+ : region(region),
+ geofencing_registration_id(geofencing_registration_id),
+ delegate(delegate),
+ state(STATE_REGISTERING) {
+}
+
+GeofencingServiceImpl::GeofencingServiceImpl() : next_registration_id_(0) {
+}
+
+GeofencingServiceImpl::~GeofencingServiceImpl() {
+}
+
+GeofencingServiceImpl* GeofencingServiceImpl::GetInstance() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return Singleton<GeofencingServiceImpl>::get();
+}
+
+bool GeofencingServiceImpl::IsServiceAvailable() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return EnsureProvider();
+}
+
+int64 GeofencingServiceImpl::RegisterRegion(
+ const blink::WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ int64 geofencing_registration_id = GetNextId();
+ registrations_[geofencing_registration_id] =
+ Registration(region, geofencing_registration_id, delegate);
+
+ if (!EnsureProvider()) {
+ RunSoon(
+ base::Bind(&GeofencingServiceImpl::NotifyRegistrationFinished,
+ base::Unretained(this),
+ geofencing_registration_id,
+ GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE));
+ return geofencing_registration_id;
+ }
+
+ provider_->RegisterRegion(
+ geofencing_registration_id,
+ region,
+ base::Bind(&GeofencingServiceImpl::NotifyRegistrationFinished,
+ base::Unretained(this),
+ geofencing_registration_id));
+ return geofencing_registration_id;
+}
+
+void GeofencingServiceImpl::UnregisterRegion(int64 geofencing_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ RegistrationsMap::iterator registration_iterator =
+ registrations_.find(geofencing_registration_id);
+ DCHECK(registration_iterator != registrations_.end());
+
+ if (!EnsureProvider())
+ return;
+
+ switch (registration_iterator->second.state) {
+ case Registration::STATE_REGISTERED:
+ provider_->UnregisterRegion(geofencing_registration_id);
+ // fallthru
+ case Registration::STATE_UNREGISTERED:
+ registrations_.erase(registration_iterator);
+ break;
+ case Registration::STATE_REGISTERING:
+ // Update state, NotifyRegistrationFinished will take care of actually
+ // unregistering.
+ registration_iterator->second.state =
+ Registration::STATE_SHOULD_UNREGISTER_AND_DELETE;
+ break;
+ case Registration::STATE_SHOULD_UNREGISTER_AND_DELETE:
+ // Should not happen.
+ NOTREACHED();
+ break;
+ }
+}
+
+void GeofencingServiceImpl::SetProviderForTesting(
+ scoped_ptr<GeofencingProvider> provider) {
+ DCHECK(!provider_.get());
+ provider_ = provider.Pass();
+}
+
+int GeofencingServiceImpl::RegistrationCountForTesting() {
+ return registrations_.size();
+}
+
+bool GeofencingServiceImpl::EnsureProvider() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!provider_) {
+ // TODO(mek): Create platform specific provider.
+ return false;
+ }
+ return true;
+}
+
+int64 GeofencingServiceImpl::GetNextId() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return next_registration_id_++;
+}
+
+void GeofencingServiceImpl::NotifyRegistrationFinished(
+ int64 geofencing_registration_id,
+ GeofencingStatus status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ RegistrationsMap::iterator registration_iterator =
+ registrations_.find(geofencing_registration_id);
+ DCHECK(registration_iterator != registrations_.end());
+ DCHECK(registration_iterator->second.state ==
+ Registration::STATE_REGISTERING ||
+ registration_iterator->second.state ==
+ Registration::STATE_SHOULD_UNREGISTER_AND_DELETE);
+
+ if (registration_iterator->second.state ==
+ Registration::STATE_SHOULD_UNREGISTER_AND_DELETE) {
+ // Don't call delegate, but unregister with provider if registration was
+ // succesfull.
+ if (status == GEOFENCING_STATUS_OK) {
+ provider_->UnregisterRegion(geofencing_registration_id);
+ }
+ registrations_.erase(registration_iterator);
+ return;
+ }
+
+ // Normal case, mark as registered and call delegate.
+ registration_iterator->second.state = Registration::STATE_REGISTERED;
+ registration_iterator->second.delegate->RegistrationFinished(
+ geofencing_registration_id, status);
+
+ if (status != GEOFENCING_STATUS_OK) {
+ // Registration failed, remove from our book-keeping.
+ registrations_.erase(registration_iterator);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geofencing/geofencing_service.h b/chromium/content/browser/geofencing/geofencing_service.h
new file mode 100644
index 00000000000..dc3d832ffdf
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_service.h
@@ -0,0 +1,105 @@
+// 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_GEOFENCING_GEOFENCING_SERVICE_H_
+#define CONTENT_BROWSER_GEOFENCING_GEOFENCING_SERVICE_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "content/common/geofencing_status.h"
+
+template <typename T>
+struct DefaultSingletonTraits;
+
+namespace blink {
+struct WebCircularGeofencingRegion;
+};
+
+namespace content {
+
+class GeofencingProvider;
+class GeofencingRegistrationDelegate;
+
+// This interface exists primarily to facilitate testing of classes that depend
+// on GeofencingService. It defines the interface exposed by
+// |GeofencingService|.
+class GeofencingService {
+ public:
+ virtual ~GeofencingService() {}
+
+ // Returns if a geofencing service is available.
+ virtual bool IsServiceAvailable() = 0;
+
+ // Register a region. This returns a unique registration ID, and
+ // asynchronously calls the |delegate|s RegistrationFinished method to
+ // inform the delegate of the result of the attempt to register the region.
+ // This does not transfer ownership of the |delegate|. Callers have to ensure
+ // that the delegate remains valid as long as the region is registered.
+ virtual int64 RegisterRegion(const blink::WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate) = 0;
+
+ // Unregister a region. This is assumed to always succeed. It is safe to call
+ // this even if a registration is still in progress.
+ virtual void UnregisterRegion(int64 geofencing_registration_id) = 0;
+};
+
+// This class combines all the geofence registrations from the various per
+// storage partition |GeofencingManager| instances, and registers a subset
+// of those fences with an underlying platform specific |GeofencingProvider|.
+// TODO(mek): Limit the number of geofences that are registered with the
+// underlying GeofencingProvider.
+class CONTENT_EXPORT GeofencingServiceImpl
+ : NON_EXPORTED_BASE(public GeofencingService) {
+ public:
+ // Gets a pointer to the singleton instance of the geofencing service. This
+ // must only be called on the IO thread so that the GeofencingService is
+ // always instantiated on the same thread. Ownership is NOT returned.
+ static GeofencingServiceImpl* GetInstance();
+
+ // GeofencingServiceInterface implementation.
+ bool IsServiceAvailable() override;
+ int64 RegisterRegion(
+ const blink::WebCircularGeofencingRegion& region,
+ GeofencingRegistrationDelegate* delegate) override;
+ void UnregisterRegion(int64 geofencing_registration_id) override;
+
+ protected:
+ friend class GeofencingServiceTest;
+ friend struct DefaultSingletonTraits<GeofencingServiceImpl>;
+ GeofencingServiceImpl();
+ ~GeofencingServiceImpl() override;
+
+ void SetProviderForTesting(scoped_ptr<GeofencingProvider> provider);
+ int RegistrationCountForTesting();
+
+ private:
+ struct Registration;
+ typedef std::map<int64, Registration> RegistrationsMap;
+
+ // This method checks if a |GeofencingProvider| exists, creates a new one if
+ // not, and finally returns false if it can't create a provider for the
+ // current platform.
+ bool EnsureProvider();
+
+ // Returns a new unique ID to use for the next geofence registration.
+ int64 GetNextId();
+
+ // Notifies the correct delegate that registration has completed for a
+ // specific geofence registration.
+ void NotifyRegistrationFinished(int64 geofencing_registration_id,
+ GeofencingStatus status);
+
+ int64 next_registration_id_;
+ RegistrationsMap registrations_;
+ scoped_ptr<GeofencingProvider> provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeofencingServiceImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOFENCING_GEOFENCING_SERVICE_H_
diff --git a/chromium/content/browser/geofencing/geofencing_service_unittest.cc b/chromium/content/browser/geofencing/geofencing_service_unittest.cc
new file mode 100644
index 00000000000..7fbe0355c8a
--- /dev/null
+++ b/chromium/content/browser/geofencing/geofencing_service_unittest.cc
@@ -0,0 +1,193 @@
+// 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/geofencing/geofencing_provider.h"
+#include "content/browser/geofencing/geofencing_registration_delegate.h"
+#include "content/browser/geofencing/geofencing_service.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+
+using blink::WebCircularGeofencingRegion;
+
+namespace {
+
+bool RegionsMatch(const WebCircularGeofencingRegion& expected,
+ const WebCircularGeofencingRegion& arg) {
+ return testing::Matches(expected.latitude)(arg.latitude) &&
+ testing::Matches(expected.longitude)(arg.longitude) &&
+ testing::Matches(expected.radius)(arg.radius);
+}
+
+} // namespace
+
+namespace content {
+
+class MockGeofencingRegistrationDelegate
+ : public GeofencingRegistrationDelegate {
+ public:
+ MOCK_METHOD2(RegistrationFinished,
+ void(int64 geofencing_registration_id, GeofencingStatus status));
+ MOCK_METHOD1(RegionEntered, void(int64 geofencing_registration_id));
+ MOCK_METHOD1(RegionExited, void(int64 geofencing_registration_id));
+};
+
+class MockGeofencingProvider : public GeofencingProvider {
+ public:
+ MOCK_METHOD3(RegisterRegion,
+ void(int64 geofencing_registration_id,
+ const blink::WebCircularGeofencingRegion& region,
+ const StatusCallback& callback));
+ MOCK_METHOD1(UnregisterRegion, void(int64 geofencing_registration_id));
+};
+
+ACTION_P(QuitRunner, runner) {
+ runner->Quit();
+}
+
+ACTION_P(SaveRegistrationId, geofencing_registration_id) {
+ *geofencing_registration_id = arg0;
+}
+
+ACTION_P(SaveStatusCallback, callback) {
+ *callback = arg2;
+}
+
+MATCHER_P(WebCircularGeofencingRegionEq, expected, "") {
+ return RegionsMatch(expected, arg);
+}
+
+class GeofencingServiceTest : public testing::Test {
+ public:
+ GeofencingServiceTest() : service_(nullptr) {
+ test_region_.latitude = 37.421999;
+ test_region_.longitude = -122.084015;
+ test_region_.radius = 100;
+ }
+
+ void SetUp() override { service_ = new GeofencingServiceImpl(); }
+
+ void TearDown() override { delete service_; }
+
+ void SetProviderForTests() {
+ provider_ = new MockGeofencingProvider();
+ service_->SetProviderForTesting(make_scoped_ptr(provider_));
+ }
+
+ int RegistrationCount() { return service_->RegistrationCountForTesting(); }
+
+ int64 RegisterRegionSync(const WebCircularGeofencingRegion& region,
+ GeofencingStatus provider_status) {
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
+
+ // The registration ID that is passed to the provider.
+ int64 provider_registration_id = -1;
+ // The callback that is passed to the provider.
+ GeofencingProvider::StatusCallback callback;
+
+ EXPECT_CALL(
+ *provider_,
+ RegisterRegion(
+ testing::_, WebCircularGeofencingRegionEq(region), testing::_))
+ .WillOnce(testing::DoAll(SaveRegistrationId(&provider_registration_id),
+ SaveStatusCallback(&callback)));
+
+ int64 geofencing_registration_id =
+ service_->RegisterRegion(region, &delegate_);
+
+ // Service should have synchronously called the provider.
+ CHECK(!callback.is_null());
+ CHECK(provider_registration_id == geofencing_registration_id);
+
+ // Finish up registration by calling the callback and waiting for the
+ // delegate to be called.
+ EXPECT_CALL(
+ delegate_,
+ RegistrationFinished(geofencing_registration_id, provider_status))
+ .WillOnce(QuitRunner(runner));
+ callback.Run(provider_status);
+ runner->Run();
+ return geofencing_registration_id;
+ }
+
+ protected:
+ TestBrowserThreadBundle threads_;
+ GeofencingServiceImpl* service_;
+ MockGeofencingProvider* provider_;
+ MockGeofencingRegistrationDelegate delegate_;
+
+ WebCircularGeofencingRegion test_region_;
+};
+
+TEST_F(GeofencingServiceTest, RegisterRegion_NoProvider) {
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
+ int64 geofencing_registration_id =
+ service_->RegisterRegion(test_region_, &delegate_);
+ EXPECT_CALL(delegate_,
+ RegistrationFinished(
+ geofencing_registration_id,
+ GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE))
+ .WillOnce(QuitRunner(runner));
+ runner->Run();
+ EXPECT_EQ(0, RegistrationCount());
+}
+
+TEST_F(GeofencingServiceTest, RegisterRegion_FailsInProvider) {
+ SetProviderForTests();
+ RegisterRegionSync(test_region_, GEOFENCING_STATUS_ERROR);
+ EXPECT_EQ(0, RegistrationCount());
+}
+
+TEST_F(GeofencingServiceTest, RegisterRegion_SucceedsInProvider) {
+ SetProviderForTests();
+ RegisterRegionSync(test_region_, GEOFENCING_STATUS_OK);
+ EXPECT_EQ(1, RegistrationCount());
+}
+
+TEST_F(GeofencingServiceTest, UnregisterRegion_AfterRegistration) {
+ SetProviderForTests();
+ int geofencing_registration_id =
+ RegisterRegionSync(test_region_, GEOFENCING_STATUS_OK);
+ EXPECT_EQ(1, RegistrationCount());
+
+ EXPECT_CALL(*provider_, UnregisterRegion(geofencing_registration_id));
+ service_->UnregisterRegion(geofencing_registration_id);
+ EXPECT_EQ(0, RegistrationCount());
+}
+
+TEST_F(GeofencingServiceTest, UnregisterRegion_DuringSuccesfullRegistration) {
+ SetProviderForTests();
+ scoped_refptr<MessageLoopRunner> runner(new MessageLoopRunner());
+
+ // The callback that is passed to the provider.
+ GeofencingProvider::StatusCallback callback;
+
+ EXPECT_CALL(
+ *provider_,
+ RegisterRegion(
+ testing::_, WebCircularGeofencingRegionEq(test_region_), testing::_))
+ .WillOnce(SaveStatusCallback(&callback));
+
+ int64 geofencing_registration_id =
+ service_->RegisterRegion(test_region_, &delegate_);
+
+ // Service should have synchronously called the provider.
+ CHECK(!callback.is_null());
+
+ // Call unregister before registration is finished.
+ service_->UnregisterRegion(geofencing_registration_id);
+
+ // Finish up registration by calling the callback and waiting for the
+ // provider to be called. The delegate should not be called in this case.
+ EXPECT_CALL(delegate_, RegistrationFinished(testing::_, testing::_)).Times(0);
+ EXPECT_CALL(*provider_, UnregisterRegion(geofencing_registration_id))
+ .WillOnce(QuitRunner(runner));
+ callback.Run(GEOFENCING_STATUS_OK);
+ runner->Run();
+ EXPECT_EQ(0, RegistrationCount());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geolocation/OWNERS b/chromium/content/browser/geolocation/OWNERS
index df10cf46d57..df3450ea5a7 100644
--- a/chromium/content/browser/geolocation/OWNERS
+++ b/chromium/content/browser/geolocation/OWNERS
@@ -1,3 +1,2 @@
-bulach@chromium.org
mvanouwerkerk@chromium.org
timvolodine@chromium.org
diff --git a/chromium/content/browser/geolocation/empty_wifi_data_provider.cc b/chromium/content/browser/geolocation/empty_wifi_data_provider.cc
index d24213155d5..2a1f7680d89 100644
--- a/chromium/content/browser/geolocation/empty_wifi_data_provider.cc
+++ b/chromium/content/browser/geolocation/empty_wifi_data_provider.cc
@@ -4,6 +4,8 @@
#include "content/browser/geolocation/empty_wifi_data_provider.h"
+#include "content/browser/geolocation/wifi_data_provider_manager.h"
+
namespace content {
EmptyWifiDataProvider::EmptyWifiDataProvider() {
@@ -19,7 +21,7 @@ bool EmptyWifiDataProvider::GetData(WifiData* data) {
}
// static
-WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
+WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
return new EmptyWifiDataProvider();
}
diff --git a/chromium/content/browser/geolocation/empty_wifi_data_provider.h b/chromium/content/browser/geolocation/empty_wifi_data_provider.h
index a02ed2bc9b7..4397e19b547 100644
--- a/chromium/content/browser/geolocation/empty_wifi_data_provider.h
+++ b/chromium/content/browser/geolocation/empty_wifi_data_provider.h
@@ -9,16 +9,16 @@
namespace content {
-// An implementation of WifiDataProviderImplBase that does not provide any
+// An implementation of WifiDataProvider that does not provide any
// data. Used on platforms where a real implementation is not available.
-class EmptyWifiDataProvider : public WifiDataProviderImplBase {
+class EmptyWifiDataProvider : public WifiDataProvider {
public:
EmptyWifiDataProvider();
- // WifiDataProviderImplBase implementation
- virtual void StartDataProvider() OVERRIDE { }
- virtual void StopDataProvider() OVERRIDE { }
- virtual bool GetData(WifiData* data) OVERRIDE;
+ // WifiDataProvider implementation
+ virtual void StartDataProvider() override { }
+ virtual void StopDataProvider() override { }
+ virtual bool GetData(WifiData* data) override;
private:
virtual ~EmptyWifiDataProvider();
diff --git a/chromium/content/browser/geolocation/geolocation_dispatcher_host.cc b/chromium/content/browser/geolocation/geolocation_dispatcher_host.cc
index ad1f2fcc444..9dfec900ea2 100644
--- a/chromium/content/browser/geolocation/geolocation_dispatcher_host.cc
+++ b/chromium/content/browser/geolocation/geolocation_dispatcher_host.cc
@@ -7,72 +7,24 @@
#include <utility>
#include "base/bind.h"
-#include "base/metrics/histogram.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/geolocation/geolocation_provider_impl.h"
#include "content/browser/renderer_host/render_message_filter.h"
-#include "content/browser/renderer_host/render_process_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/content_browser_client.h"
-#include "content/public/common/geoposition.h"
#include "content/common/geolocation_messages.h"
namespace content {
-namespace {
-
-// Geoposition error codes for reporting in UMA.
-enum GeopositionErrorCode {
- // NOTE: Do not renumber these as that would confuse interpretation of
- // previously logged data. When making changes, also update the enum list
- // in tools/metrics/histograms/histograms.xml to keep it in sync.
-
- // There was no error.
- GEOPOSITION_ERROR_CODE_NONE = 0,
-
- // User denied use of geolocation.
- GEOPOSITION_ERROR_CODE_PERMISSION_DENIED = 1,
-
- // Geoposition could not be determined.
- GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE = 2,
-
- // Timeout.
- GEOPOSITION_ERROR_CODE_TIMEOUT = 3,
-
- // NOTE: Add entries only immediately above this line.
- GEOPOSITION_ERROR_CODE_COUNT = 4
-};
-
-void RecordGeopositionErrorCode(Geoposition::ErrorCode error_code) {
- GeopositionErrorCode code = GEOPOSITION_ERROR_CODE_NONE;
- switch (error_code) {
- case Geoposition::ERROR_CODE_NONE:
- code = GEOPOSITION_ERROR_CODE_NONE;
- break;
- case Geoposition::ERROR_CODE_PERMISSION_DENIED:
- code = GEOPOSITION_ERROR_CODE_PERMISSION_DENIED;
- break;
- case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE:
- code = GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE;
- break;
- case Geoposition::ERROR_CODE_TIMEOUT:
- code = GEOPOSITION_ERROR_CODE_TIMEOUT;
- break;
- }
- UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode",
- code,
- GEOPOSITION_ERROR_CODE_COUNT);
-}
-
-} // namespace
GeolocationDispatcherHost::PendingPermission::PendingPermission(
int render_frame_id,
int render_process_id,
- int bridge_id)
+ int bridge_id,
+ const GURL& origin)
: render_frame_id(render_frame_id),
render_process_id(render_process_id),
- bridge_id(bridge_id) {
+ bridge_id(bridge_id),
+ origin(origin) {
}
GeolocationDispatcherHost::PendingPermission::~PendingPermission() {
@@ -81,7 +33,6 @@ GeolocationDispatcherHost::PendingPermission::~PendingPermission() {
GeolocationDispatcherHost::GeolocationDispatcherHost(
WebContents* web_contents)
: WebContentsObserver(web_contents),
- paused_(false),
weak_factory_(this) {
// This is initialized by WebContentsImpl. Do not add any non-trivial
// initialization here, defer to OnStartUpdating which is triggered whenever
@@ -93,15 +44,17 @@ GeolocationDispatcherHost::~GeolocationDispatcherHost() {
void GeolocationDispatcherHost::RenderFrameDeleted(
RenderFrameHost* render_frame_host) {
- OnStopUpdating(render_frame_host);
+ CancelPermissionRequestsForFrame(render_frame_host);
}
-void GeolocationDispatcherHost::RenderViewHostChanged(
- RenderViewHost* old_host,
- RenderViewHost* new_host) {
- updating_frames_.clear();
- paused_ = false;
- geolocation_subscription_.reset();
+void GeolocationDispatcherHost::DidNavigateAnyFrame(
+ RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) {
+ if (details.is_in_page)
+ return;
+
+ CancelPermissionRequestsForFrame(render_frame_host);
}
bool GeolocationDispatcherHost::OnMessageReceived(
@@ -111,118 +64,34 @@ bool GeolocationDispatcherHost::OnMessageReceived(
render_frame_host)
IPC_MESSAGE_HANDLER(GeolocationHostMsg_RequestPermission,
OnRequestPermission)
- IPC_MESSAGE_HANDLER(GeolocationHostMsg_CancelPermissionRequest,
- OnCancelPermissionRequest)
- IPC_MESSAGE_HANDLER(GeolocationHostMsg_StartUpdating, OnStartUpdating)
- IPC_MESSAGE_HANDLER(GeolocationHostMsg_StopUpdating, OnStopUpdating)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void GeolocationDispatcherHost::OnLocationUpdate(
- const Geoposition& geoposition) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- RecordGeopositionErrorCode(geoposition.error_code);
- if (paused_)
- return;
-
- for (std::map<RenderFrameHost*, bool>::iterator i = updating_frames_.begin();
- i != updating_frames_.end(); ++i) {
- i->first->Send(new GeolocationMsg_PositionUpdated(
- i->first->GetRoutingID(), geoposition));
- }
-}
-
void GeolocationDispatcherHost::OnRequestPermission(
RenderFrameHost* render_frame_host,
int bridge_id,
- const GURL& requesting_frame,
+ const GURL& requesting_origin,
bool user_gesture) {
int render_process_id = render_frame_host->GetProcess()->GetID();
int render_frame_id = render_frame_host->GetRoutingID();
PendingPermission pending_permission(
- render_frame_id, render_process_id, bridge_id);
+ render_frame_id, render_process_id, bridge_id, requesting_origin);
pending_permissions_.push_back(pending_permission);
- GetContentClient()->browser()->RequestGeolocationPermission(
+ GetContentClient()->browser()->RequestPermission(
+ content::PERMISSION_GEOLOCATION,
web_contents(),
bridge_id,
- requesting_frame,
+ requesting_origin,
user_gesture,
base::Bind(&GeolocationDispatcherHost::SendGeolocationPermissionResponse,
weak_factory_.GetWeakPtr(),
- render_process_id, render_frame_id, bridge_id),
- &pending_permissions_.back().cancel);
-}
-
-void GeolocationDispatcherHost::OnCancelPermissionRequest(
- RenderFrameHost* render_frame_host,
- int bridge_id,
- const GURL& requesting_frame) {
- int render_process_id = render_frame_host->GetProcess()->GetID();
- int render_frame_id = render_frame_host->GetRoutingID();
- for (size_t i = 0; i < pending_permissions_.size(); ++i) {
- if (pending_permissions_[i].render_process_id == render_process_id &&
- pending_permissions_[i].render_frame_id == render_frame_id &&
- pending_permissions_[i].bridge_id == bridge_id) {
- if (!pending_permissions_[i].cancel.is_null())
- pending_permissions_[i].cancel.Run();
- pending_permissions_.erase(pending_permissions_.begin() + i);
- return;
- }
- }
-}
-
-void GeolocationDispatcherHost::OnStartUpdating(
- RenderFrameHost* render_frame_host,
- const GURL& requesting_frame,
- bool enable_high_accuracy) {
- // StartUpdating() can be invoked as a result of high-accuracy mode
- // being enabled / disabled. No need to record the dispatcher again.
- UMA_HISTOGRAM_BOOLEAN(
- "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
- enable_high_accuracy);
-
- updating_frames_[render_frame_host] = enable_high_accuracy;
- RefreshGeolocationOptions();
-}
-
-void GeolocationDispatcherHost::OnStopUpdating(
- RenderFrameHost* render_frame_host) {
- updating_frames_.erase(render_frame_host);
- RefreshGeolocationOptions();
-}
-
-void GeolocationDispatcherHost::PauseOrResume(bool should_pause) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- paused_ = should_pause;
- RefreshGeolocationOptions();
-}
-
-void GeolocationDispatcherHost::RefreshGeolocationOptions() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (updating_frames_.empty() || paused_) {
- geolocation_subscription_.reset();
- return;
- }
-
- bool high_accuracy = false;
- for (std::map<RenderFrameHost*, bool>::iterator i =
- updating_frames_.begin(); i != updating_frames_.end(); ++i) {
- if (i->second) {
- high_accuracy = true;
- break;
- }
- }
- geolocation_subscription_ = GeolocationProvider::GetInstance()->
- AddLocationUpdateCallback(
- base::Bind(&GeolocationDispatcherHost::OnLocationUpdate,
- base::Unretained(this)),
- high_accuracy);
+ render_process_id,
+ render_frame_id,
+ bridge_id));
}
void GeolocationDispatcherHost::SendGeolocationPermissionResponse(
@@ -254,4 +123,22 @@ void GeolocationDispatcherHost::SendGeolocationPermissionResponse(
NOTREACHED();
}
+void GeolocationDispatcherHost::CancelPermissionRequestsForFrame(
+ RenderFrameHost* render_frame_host) {
+ int render_process_id = render_frame_host->GetProcess()->GetID();
+ int render_frame_id = render_frame_host->GetRoutingID();
+
+ for (size_t i = 0; i < pending_permissions_.size(); ++i) {
+ if (pending_permissions_[i].render_process_id == render_process_id &&
+ pending_permissions_[i].render_frame_id == render_frame_id) {
+ GetContentClient()->browser()->CancelPermissionRequest(
+ content::PERMISSION_GEOLOCATION,
+ web_contents(),
+ pending_permissions_[i].bridge_id,
+ pending_permissions_[i].origin);
+ pending_permissions_.erase(pending_permissions_.begin() + i);
+ }
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/geolocation/geolocation_dispatcher_host.h b/chromium/content/browser/geolocation/geolocation_dispatcher_host.h
index e8bda4026d6..6359de10cce 100644
--- a/chromium/content/browser/geolocation/geolocation_dispatcher_host.h
+++ b/chromium/content/browser/geolocation/geolocation_dispatcher_host.h
@@ -10,77 +10,62 @@
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
-#include "content/browser/geolocation/geolocation_provider_impl.h"
#include "content/public/browser/web_contents_observer.h"
class GURL;
namespace content {
-// GeolocationDispatcherHost is an observer for Geolocation messages.
-// It's the complement of GeolocationDispatcher (owned by RenderView).
+// GeolocationDispatcherHost is an observer for Geolocation permissions-related
+// messages. In this role, it's the complement of GeolocationDispatcher (owned
+// by RenderFrame).
+// TODO(blundell): Eliminate this class in favor of having
+// Mojo handle permissions for geolocation once there is resolution on how
+// that will work. crbug.com/420498
class GeolocationDispatcherHost : public WebContentsObserver {
public:
explicit GeolocationDispatcherHost(WebContents* web_contents);
- virtual ~GeolocationDispatcherHost();
-
- // Pause or resumes geolocation. Resuming when nothing is paused is a no-op.
- // If the web contents is paused while not currently using geolocation but
- // then goes on to do so before being resumed, then it will not get
- // geolocation updates until it is resumed.
- void PauseOrResume(bool should_pause);
+ ~GeolocationDispatcherHost() override;
private:
// WebContentsObserver
- virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void RenderViewHostChanged(RenderViewHost* old_host,
- RenderViewHost* new_host) OVERRIDE;
- virtual bool OnMessageReceived(
- const IPC::Message& msg, RenderFrameHost* render_frame_host) OVERRIDE;
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+ void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override;
+ bool OnMessageReceived(const IPC::Message& msg,
+ RenderFrameHost* render_frame_host) override;
// Message handlers:
+ // TODO(mlamouri): |requesting_origin| should be a security origin to
+ // guarantee that a proper origin is passed.
void OnRequestPermission(RenderFrameHost* render_frame_host,
int bridge_id,
- const GURL& requesting_frame,
+ const GURL& requesting_origin,
bool user_gesture);
- void OnCancelPermissionRequest(RenderFrameHost* render_frame_host,
- int bridge_id,
- const GURL& requesting_frame);
- void OnStartUpdating(RenderFrameHost* render_frame_host,
- const GURL& requesting_frame,
- bool enable_high_accuracy);
- void OnStopUpdating(RenderFrameHost* render_frame_host);
-
- // Updates the geolocation provider with the currently required update
- // options.
- void RefreshGeolocationOptions();
-
- void OnLocationUpdate(const Geoposition& position);
void SendGeolocationPermissionResponse(int render_process_id,
int render_frame_id,
int bridge_id,
bool allowed);
- // A map from the RenderFrameHosts that have requested geolocation updates to
- // the type of accuracy they requested (true = high accuracy).
- std::map<RenderFrameHost*, bool> updating_frames_;
- bool paused_;
+ // Clear pending permissions associated with a given frame and request the
+ // browser to cancel the permission requests.
+ void CancelPermissionRequestsForFrame(RenderFrameHost* render_frame_host);
struct PendingPermission {
PendingPermission(int render_frame_id,
int render_process_id,
- int bridge_id);
+ int bridge_id,
+ const GURL& origin);
~PendingPermission();
int render_frame_id;
int render_process_id;
int bridge_id;
- base::Closure cancel;
+ GURL origin;
};
std::vector<PendingPermission> pending_permissions_;
- scoped_ptr<GeolocationProvider::Subscription> geolocation_subscription_;
-
base::WeakPtrFactory<GeolocationDispatcherHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHost);
diff --git a/chromium/content/browser/geolocation/geolocation_provider_impl.h b/chromium/content/browser/geolocation/geolocation_provider_impl.h
index e3b8762ed44..b3c128649bb 100644
--- a/chromium/content/browser/geolocation/geolocation_provider_impl.h
+++ b/chromium/content/browser/geolocation/geolocation_provider_impl.h
@@ -26,18 +26,18 @@ class CONTENT_EXPORT GeolocationProviderImpl
public base::Thread {
public:
// GeolocationProvider implementation:
- virtual scoped_ptr<GeolocationProvider::Subscription>
- AddLocationUpdateCallback(const LocationUpdateCallback& callback,
- bool use_high_accuracy) OVERRIDE;
- virtual void UserDidOptIntoLocationServices() OVERRIDE;
- virtual void OverrideLocationForTesting(const Geoposition& position) OVERRIDE;
+ scoped_ptr<GeolocationProvider::Subscription> AddLocationUpdateCallback(
+ const LocationUpdateCallback& callback,
+ bool use_high_accuracy) override;
+ void UserDidOptIntoLocationServices() override;
+ void OverrideLocationForTesting(const Geoposition& position) override;
// Callback from the LocationArbitrator. Public for testing.
void OnLocationUpdate(const Geoposition& position);
// Gets a pointer to the singleton instance of the location relayer, which
// is in turn bound to the browser's global context objects. This must only be
- // called on the IO thread so that the GeolocationProviderImpl is always
+ // called on the UI thread so that the GeolocationProviderImpl is always
// instantiated on the same thread. Ownership is NOT returned.
static GeolocationProviderImpl* GetInstance();
@@ -48,7 +48,7 @@ class CONTENT_EXPORT GeolocationProviderImpl
protected:
friend struct DefaultSingletonTraits<GeolocationProviderImpl>;
GeolocationProviderImpl();
- virtual ~GeolocationProviderImpl();
+ ~GeolocationProviderImpl() override;
// Useful for injecting mock geolocation arbitrator in tests.
virtual LocationArbitrator* CreateArbitrator();
@@ -75,8 +75,8 @@ class CONTENT_EXPORT GeolocationProviderImpl
void NotifyClients(const Geoposition& position);
// Thread
- virtual void Init() OVERRIDE;
- virtual void CleanUp() OVERRIDE;
+ void Init() override;
+ void CleanUp() override;
base::CallbackList<void(const Geoposition&)> high_accuracy_callbacks_;
base::CallbackList<void(const Geoposition&)> low_accuracy_callbacks_;
diff --git a/chromium/content/browser/geolocation/geolocation_provider_unittest.cc b/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc
index 95fa1b69145..f201f48e842 100644
--- a/chromium/content/browser/geolocation/geolocation_provider_unittest.cc
+++ b/chromium/content/browser/geolocation/geolocation_provider_impl_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
@@ -27,7 +27,7 @@ namespace content {
class LocationProviderForTestArbitrator : public GeolocationProviderImpl {
public:
LocationProviderForTestArbitrator() : mock_arbitrator_(NULL) {}
- virtual ~LocationProviderForTestArbitrator() {}
+ ~LocationProviderForTestArbitrator() override {}
// Only valid for use on the geolocation thread.
MockLocationArbitrator* mock_arbitrator() const {
@@ -36,7 +36,7 @@ class LocationProviderForTestArbitrator : public GeolocationProviderImpl {
protected:
// GeolocationProviderImpl implementation:
- virtual LocationArbitrator* CreateArbitrator() OVERRIDE;
+ LocationArbitrator* CreateArbitrator() override;
private:
MockLocationArbitrator* mock_arbitrator_;
@@ -61,7 +61,7 @@ class MockGeolocationObserver : public GeolocationObserver {
class AsyncMockGeolocationObserver : public MockGeolocationObserver {
public:
- virtual void OnLocationUpdate(const Geoposition& position) OVERRIDE {
+ void OnLocationUpdate(const Geoposition& position) override {
MockGeolocationObserver::OnLocationUpdate(position);
base::MessageLoop::current()->Quit();
}
@@ -79,7 +79,7 @@ class GeopositionEqMatcher
: expected_(expected) {}
virtual bool MatchAndExplain(const Geoposition& actual,
- MatchResultListener* listener) const OVERRIDE {
+ MatchResultListener* listener) const override {
return actual.latitude == expected_.latitude &&
actual.longitude == expected_.longitude &&
actual.altitude == expected_.altitude &&
@@ -92,11 +92,11 @@ class GeopositionEqMatcher
actual.error_message == expected_.error_message;
}
- virtual void DescribeTo(::std::ostream* os) const OVERRIDE {
+ virtual void DescribeTo(::std::ostream* os) const override {
*os << "which matches the expected position";
}
- virtual void DescribeNegationTo(::std::ostream* os) const OVERRIDE {
+ virtual void DescribeNegationTo(::std::ostream* os) const override {
*os << "which does not match the expected position";
}
@@ -118,7 +118,7 @@ class GeolocationProviderTest : public testing::Test {
provider_(new LocationProviderForTestArbitrator) {
}
- virtual ~GeolocationProviderTest() {}
+ ~GeolocationProviderTest() override {}
LocationProviderForTestArbitrator* provider() { return provider_.get(); }
diff --git a/chromium/content/browser/geolocation/geolocation_service_context.cc b/chromium/content/browser/geolocation/geolocation_service_context.cc
new file mode 100644
index 00000000000..fc6b4aa07cd
--- /dev/null
+++ b/chromium/content/browser/geolocation/geolocation_service_context.cc
@@ -0,0 +1,63 @@
+// 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/geolocation/geolocation_service_context.h"
+
+namespace content {
+
+GeolocationServiceContext::GeolocationServiceContext() : paused_(false) {
+}
+
+GeolocationServiceContext::~GeolocationServiceContext() {
+}
+
+void GeolocationServiceContext::CreateService(
+ const base::Closure& update_callback,
+ mojo::InterfaceRequest<GeolocationService> request) {
+ GeolocationServiceImpl* service =
+ new GeolocationServiceImpl(this, update_callback);
+ services_.push_back(service);
+ mojo::WeakBindToRequest(service, &request);
+ if (geoposition_override_)
+ service->SetOverride(*geoposition_override_.get());
+ else
+ service->StartListeningForUpdates();
+}
+
+void GeolocationServiceContext::ServiceHadConnectionError(
+ GeolocationServiceImpl* service) {
+ auto it = std::find(services_.begin(), services_.end(), service);
+ DCHECK(it != services_.end());
+ services_.erase(it);
+}
+
+void GeolocationServiceContext::PauseUpdates() {
+ paused_ = true;
+ for (auto* service : services_) {
+ service->PauseUpdates();
+ }
+}
+
+void GeolocationServiceContext::ResumeUpdates() {
+ paused_ = false;
+ for (auto* service : services_) {
+ service->ResumeUpdates();
+ }
+}
+
+void GeolocationServiceContext::SetOverride(
+ scoped_ptr<Geoposition> geoposition) {
+ geoposition_override_.swap(geoposition);
+ for (auto* service : services_) {
+ service->SetOverride(*geoposition_override_.get());
+ }
+}
+
+void GeolocationServiceContext::ClearOverride() {
+ for (auto* service : services_) {
+ service->ClearOverride();
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geolocation/geolocation_service_context.h b/chromium/content/browser/geolocation/geolocation_service_context.h
new file mode 100644
index 00000000000..453c8b0dce2
--- /dev/null
+++ b/chromium/content/browser/geolocation/geolocation_service_context.h
@@ -0,0 +1,58 @@
+// 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_GEOLOCATION_GEOLOCATION_SERVICE_CONTEXT_H_
+#define CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_CONTEXT_H_
+
+#include "base/memory/scoped_vector.h"
+#include "content/browser/geolocation/geolocation_service_impl.h"
+
+namespace content {
+
+// Provides information to a set of GeolocationServiceImpl instances that are
+// associated with a given context. Notably, allows pausing and resuming
+// geolocation on these instances.
+class GeolocationServiceContext {
+ public:
+ GeolocationServiceContext();
+ virtual ~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);
+
+ // Called when a service has a connection error. After this call, it is no
+ // longer safe to access |service|.
+ void ServiceHadConnectionError(GeolocationServiceImpl* service);
+
+ // Pauses and resumes geolocation. Resuming when nothing is paused is a
+ // no-op. If a service is added while geolocation is paused, that service
+ // will not get geolocation updates until geolocation is resumed.
+ void PauseUpdates();
+ void ResumeUpdates();
+
+ // Returns whether geolocation updates are currently paused.
+ bool paused() { return paused_; }
+
+ // Enables geolocation override. This method can be used to trigger possible
+ // location-specific behavior in a particular context.
+ void SetOverride(scoped_ptr<Geoposition> geoposition);
+
+ // Disables geolocation override.
+ void ClearOverride();
+
+ private:
+ ScopedVector<GeolocationServiceImpl> services_;
+ bool paused_;
+
+ scoped_ptr<Geoposition> geoposition_override_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeolocationServiceContext);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_CONTEXT_H_
diff --git a/chromium/content/browser/geolocation/geolocation_service_impl.cc b/chromium/content/browser/geolocation/geolocation_service_impl.cc
new file mode 100644
index 00000000000..4c855f27046
--- /dev/null
+++ b/chromium/content/browser/geolocation/geolocation_service_impl.cc
@@ -0,0 +1,155 @@
+// 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/geolocation/geolocation_service_impl.h"
+
+#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 {
+
+namespace {
+
+// Geoposition error codes for reporting in UMA.
+enum GeopositionErrorCode {
+ // NOTE: Do not renumber these as that would confuse interpretation of
+ // previously logged data. When making changes, also update the enum list
+ // in tools/metrics/histograms/histograms.xml to keep it in sync.
+
+ // There was no error.
+ GEOPOSITION_ERROR_CODE_NONE = 0,
+
+ // User denied use of geolocation.
+ GEOPOSITION_ERROR_CODE_PERMISSION_DENIED = 1,
+
+ // Geoposition could not be determined.
+ GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE = 2,
+
+ // Timeout.
+ GEOPOSITION_ERROR_CODE_TIMEOUT = 3,
+
+ // NOTE: Add entries only immediately above this line.
+ GEOPOSITION_ERROR_CODE_COUNT = 4
+};
+
+void RecordGeopositionErrorCode(Geoposition::ErrorCode error_code) {
+ GeopositionErrorCode code = GEOPOSITION_ERROR_CODE_NONE;
+ switch (error_code) {
+ case Geoposition::ERROR_CODE_NONE:
+ code = GEOPOSITION_ERROR_CODE_NONE;
+ break;
+ case Geoposition::ERROR_CODE_PERMISSION_DENIED:
+ code = GEOPOSITION_ERROR_CODE_PERMISSION_DENIED;
+ break;
+ case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE:
+ code = GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE;
+ break;
+ case Geoposition::ERROR_CODE_TIMEOUT:
+ code = GEOPOSITION_ERROR_CODE_TIMEOUT;
+ break;
+ }
+ UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode",
+ code,
+ GEOPOSITION_ERROR_CODE_COUNT);
+}
+
+} // namespace
+
+GeolocationServiceImpl::GeolocationServiceImpl(
+ GeolocationServiceContext* context,
+ const base::Closure& update_callback)
+ : context_(context),
+ update_callback_(update_callback),
+ high_accuracy_(false) {
+ DCHECK(context_);
+}
+
+GeolocationServiceImpl::~GeolocationServiceImpl() {
+}
+
+void GeolocationServiceImpl::PauseUpdates() {
+ geolocation_subscription_.reset();
+}
+
+void GeolocationServiceImpl::ResumeUpdates() {
+ if (position_override_.Validate()) {
+ OnLocationUpdate(position_override_);
+ return;
+ }
+
+ StartListeningForUpdates();
+}
+
+void GeolocationServiceImpl::StartListeningForUpdates() {
+ geolocation_subscription_ =
+ GeolocationProvider::GetInstance()->AddLocationUpdateCallback(
+ base::Bind(&GeolocationServiceImpl::OnLocationUpdate,
+ base::Unretained(this)),
+ high_accuracy_);
+}
+
+void GeolocationServiceImpl::SetHighAccuracy(bool high_accuracy) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
+ high_accuracy);
+ high_accuracy_ = high_accuracy;
+
+ if (position_override_.Validate()) {
+ OnLocationUpdate(position_override_);
+ return;
+ }
+
+ StartListeningForUpdates();
+}
+
+void GeolocationServiceImpl::SetOverride(const Geoposition& position) {
+ position_override_ = position;
+ if (!position_override_.Validate()) {
+ ResumeUpdates();
+ }
+
+ geolocation_subscription_.reset();
+
+ OnLocationUpdate(position_override_);
+}
+
+void GeolocationServiceImpl::ClearOverride() {
+ position_override_ = Geoposition();
+ StartListeningForUpdates();
+}
+
+void GeolocationServiceImpl::OnConnectionError() {
+ context_->ServiceHadConnectionError(this);
+
+ // The above call deleted this instance, so the only safe thing to do is
+ // return.
+}
+
+void GeolocationServiceImpl::OnLocationUpdate(const Geoposition& position) {
+ RecordGeopositionErrorCode(position.error_code);
+ DCHECK(context_);
+
+ if (context_->paused())
+ return;
+
+ MojoGeopositionPtr geoposition(MojoGeoposition::New());
+ geoposition->valid = position.Validate();
+ geoposition->latitude = position.latitude;
+ geoposition->longitude = position.longitude;
+ geoposition->altitude = position.altitude;
+ geoposition->accuracy = position.accuracy;
+ geoposition->altitude_accuracy = position.altitude_accuracy;
+ geoposition->heading = position.heading;
+ geoposition->speed = position.speed;
+ geoposition->timestamp = position.timestamp.ToDoubleT();
+ geoposition->error_code = MojoGeoposition::ErrorCode(position.error_code);
+ geoposition->error_message = position.error_message;
+
+ update_callback_.Run();
+ client()->OnLocationUpdate(geoposition.Pass());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geolocation/geolocation_service_impl.h b/chromium/content/browser/geolocation/geolocation_service_impl.h
new file mode 100644
index 00000000000..172e4e196c8
--- /dev/null
+++ b/chromium/content/browser/geolocation/geolocation_service_impl.h
@@ -0,0 +1,64 @@
+// 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 "base/memory/scoped_ptr.h"
+#include "content/browser/geolocation/geolocation_provider_impl.h"
+#include "content/common/geolocation_service.mojom.h"
+
+#ifndef CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
+#define CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
+
+namespace content {
+
+class GeolocationProvider;
+class GeolocationServiceContext;
+
+// Implements the GeolocationService Mojo interface.
+class GeolocationServiceImpl : public mojo::InterfaceImpl<GeolocationService> {
+ public:
+ // |context| must outlive this object. |update_callback| will be
+ // called when location updates are sent.
+ GeolocationServiceImpl(GeolocationServiceContext* context,
+ const base::Closure& update_callback);
+ ~GeolocationServiceImpl() override;
+
+ // Starts listening for updates.
+ void StartListeningForUpdates();
+
+ // Pauses and resumes sending updates to the client of this instance.
+ void PauseUpdates();
+ void ResumeUpdates();
+
+ // Enables and disables geolocation override.
+ void SetOverride(const Geoposition& position);
+ void ClearOverride();
+
+ private:
+ // GeolocationService:
+ void SetHighAccuracy(bool high_accuracy) override;
+
+ // mojo::InterfaceImpl:
+ void OnConnectionError() override;
+
+ void OnLocationUpdate(const Geoposition& position);
+
+ // Owns this object.
+ GeolocationServiceContext* context_;
+ scoped_ptr<GeolocationProvider::Subscription> geolocation_subscription_;
+ base::Closure update_callback_;
+
+ // Valid iff SetOverride() has been called and ClearOverride() has not
+ // subsequently been called.
+ Geoposition position_override_;
+
+ // Whether this instance is currently observing location updates with high
+ // accuracy.
+ bool high_accuracy_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeolocationServiceImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOLOCATION_GEOLOCATION_SERVICE_IMPL_H_
diff --git a/chromium/content/browser/geolocation/location_arbitrator_impl.cc b/chromium/content/browser/geolocation/location_arbitrator_impl.cc
index b8ed8c49bf5..ef20a0ce468 100644
--- a/chromium/content/browser/geolocation/location_arbitrator_impl.cc
+++ b/chromium/content/browser/geolocation/location_arbitrator_impl.cc
@@ -28,9 +28,9 @@ const int64 LocationArbitratorImpl::kFixStaleTimeoutMilliseconds =
LocationArbitratorImpl::LocationArbitratorImpl(
const LocationUpdateCallback& callback)
- : callback_(callback),
- provider_callback_(
- base::Bind(&LocationArbitratorImpl::LocationUpdateAvailable,
+ : arbitrator_update_callback_(callback),
+ provider_update_callback_(
+ base::Bind(&LocationArbitratorImpl::OnLocationUpdate,
base::Unretained(this))),
position_provider_(NULL),
is_permission_granted_(false),
@@ -116,15 +116,14 @@ void LocationArbitratorImpl::RegisterProvider(
LocationProvider* provider) {
if (!provider)
return;
- provider->SetUpdateCallback(provider_callback_);
+ provider->SetUpdateCallback(provider_update_callback_);
if (is_permission_granted_)
provider->OnPermissionGranted();
providers_.push_back(provider);
}
-void LocationArbitratorImpl::LocationUpdateAvailable(
- const LocationProvider* provider,
- const Geoposition& new_position) {
+void LocationArbitratorImpl::OnLocationUpdate(const LocationProvider* provider,
+ const Geoposition& new_position) {
DCHECK(new_position.Validate() ||
new_position.error_code != Geoposition::ERROR_CODE_NONE);
if (!IsNewPositionBetter(position_, new_position,
@@ -132,7 +131,7 @@ void LocationArbitratorImpl::LocationUpdateAvailable(
return;
position_provider_ = provider;
position_ = new_position;
- callback_.Run(position_);
+ arbitrator_update_callback_.Run(position_);
}
AccessTokenStore* LocationArbitratorImpl::NewAccessTokenStore() {
diff --git a/chromium/content/browser/geolocation/location_arbitrator_impl.h b/chromium/content/browser/geolocation/location_arbitrator_impl.h
index da20e7b1889..3ef7d5dfc6e 100644
--- a/chromium/content/browser/geolocation/location_arbitrator_impl.h
+++ b/chromium/content/browser/geolocation/location_arbitrator_impl.h
@@ -37,15 +37,15 @@ class CONTENT_EXPORT LocationArbitratorImpl : public LocationArbitrator {
typedef base::Callback<void(const Geoposition&)> LocationUpdateCallback;
explicit LocationArbitratorImpl(const LocationUpdateCallback& callback);
- virtual ~LocationArbitratorImpl();
+ ~LocationArbitratorImpl() override;
static GURL DefaultNetworkProviderURL();
// LocationArbitrator
- virtual void StartProviders(bool use_high_accuracy) OVERRIDE;
- virtual void StopProviders() OVERRIDE;
- virtual void OnPermissionGranted() OVERRIDE;
- virtual bool HasPermissionBeenGranted() const OVERRIDE;
+ void StartProviders(bool use_high_accuracy) override;
+ void StopProviders() override;
+ void OnPermissionGranted() override;
+ bool HasPermissionBeenGranted() const override;
protected:
AccessTokenStore* GetAccessTokenStore();
@@ -70,9 +70,9 @@ class CONTENT_EXPORT LocationArbitratorImpl : public LocationArbitrator {
net::URLRequestContextGetter* context_getter);
void DoStartProviders();
- // The providers call this function when a new position is available.
- void LocationUpdateAvailable(const LocationProvider* provider,
- const Geoposition& new_position);
+ // Gets called when a provider has a new position.
+ void OnLocationUpdate(const LocationProvider* provider,
+ const Geoposition& new_position);
// Returns true if |new_position| is an improvement over |old_position|.
// Set |from_same_provider| to true if both the positions came from the same
@@ -82,8 +82,8 @@ class CONTENT_EXPORT LocationArbitratorImpl : public LocationArbitrator {
bool from_same_provider) const;
scoped_refptr<AccessTokenStore> access_token_store_;
- LocationUpdateCallback callback_;
- LocationProvider::LocationProviderUpdateCallback provider_callback_;
+ LocationUpdateCallback arbitrator_update_callback_;
+ LocationProvider::LocationProviderUpdateCallback provider_update_callback_;
ScopedVector<LocationProvider> providers_;
bool use_high_accuracy_;
// The provider which supplied the current |position_|
diff --git a/chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc b/chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc
index 81df7a4326f..bd5eb6e9d07 100644
--- a/chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc
+++ b/chromium/content/browser/geolocation/location_arbitrator_impl_unittest.cc
@@ -73,23 +73,21 @@ class TestingLocationArbitrator : public LocationArbitratorImpl {
access_token_store_(access_token_store) {
}
- virtual base::Time GetTimeNow() const OVERRIDE {
- return GetTimeNowForTest();
- }
+ base::Time GetTimeNow() const override { return GetTimeNowForTest(); }
- virtual AccessTokenStore* NewAccessTokenStore() OVERRIDE {
+ AccessTokenStore* NewAccessTokenStore() override {
return access_token_store_.get();
}
- virtual LocationProvider* NewNetworkLocationProvider(
+ LocationProvider* NewNetworkLocationProvider(
AccessTokenStore* access_token_store,
net::URLRequestContextGetter* context,
const GURL& url,
- const base::string16& access_token) OVERRIDE {
+ const base::string16& access_token) override {
return new MockLocationProvider(&cell_);
}
- virtual LocationProvider* NewSystemLocationProvider() OVERRIDE {
+ LocationProvider* NewSystemLocationProvider() override {
return new MockLocationProvider(&gps_);
}
@@ -107,7 +105,7 @@ class TestingLocationArbitrator : public LocationArbitratorImpl {
class GeolocationLocationArbitratorTest : public testing::Test {
protected:
// testing::Test
- virtual void SetUp() {
+ void SetUp() override {
access_token_store_ = new NiceMock<FakeAccessTokenStore>;
observer_.reset(new MockLocationObserver);
LocationArbitratorImpl::LocationUpdateCallback callback =
@@ -118,8 +116,7 @@ class GeolocationLocationArbitratorTest : public testing::Test {
}
// testing::Test
- virtual void TearDown() {
- }
+ void TearDown() override {}
void CheckLastPositionInfo(double latitude,
double longitude,
diff --git a/chromium/content/browser/geolocation/location_provider_android.h b/chromium/content/browser/geolocation/location_provider_android.h
index b4f5886ceba..e24f67cb980 100644
--- a/chromium/content/browser/geolocation/location_provider_android.h
+++ b/chromium/content/browser/geolocation/location_provider_android.h
@@ -23,11 +23,11 @@ class LocationProviderAndroid : public LocationProviderBase {
void NotifyNewGeoposition(const Geoposition& position);
// LocationProvider.
- virtual bool StartProvider(bool high_accuracy) OVERRIDE;
- virtual void StopProvider() OVERRIDE;
- virtual void GetPosition(Geoposition* position) OVERRIDE;
- virtual void RequestRefresh() OVERRIDE;
- virtual void OnPermissionGranted() OVERRIDE;
+ virtual bool StartProvider(bool high_accuracy) override;
+ virtual void StopProvider() override;
+ virtual void GetPosition(Geoposition* position) override;
+ virtual void RequestRefresh() override;
+ virtual void OnPermissionGranted() override;
private:
Geoposition last_position_;
diff --git a/chromium/content/browser/geolocation/location_provider_base.h b/chromium/content/browser/geolocation/location_provider_base.h
index 36d900bd747..1e3f4430da0 100644
--- a/chromium/content/browser/geolocation/location_provider_base.h
+++ b/chromium/content/browser/geolocation/location_provider_base.h
@@ -14,15 +14,15 @@ class CONTENT_EXPORT LocationProviderBase
: NON_EXPORTED_BASE(public LocationProvider) {
public:
LocationProviderBase();
- virtual ~LocationProviderBase();
+ ~LocationProviderBase() override;
protected:
void NotifyCallback(const Geoposition& position);
// Overridden from LocationProvider:
- virtual void SetUpdateCallback(
- const LocationProviderUpdateCallback& callback) OVERRIDE;
- virtual void RequestRefresh() OVERRIDE;
+ void SetUpdateCallback(
+ const LocationProviderUpdateCallback& callback) override;
+ void RequestRefresh() override;
private:
LocationProviderUpdateCallback callback_;
diff --git a/chromium/content/browser/geolocation/mock_location_arbitrator.h b/chromium/content/browser/geolocation/mock_location_arbitrator.h
index f096b12f720..620bcc88662 100644
--- a/chromium/content/browser/geolocation/mock_location_arbitrator.h
+++ b/chromium/content/browser/geolocation/mock_location_arbitrator.h
@@ -20,11 +20,10 @@ class MockLocationArbitrator : public LocationArbitrator {
bool providers_started() const { return providers_started_; }
// LocationArbitrator:
- virtual void StartProviders(bool use_high_accuracy)
- OVERRIDE;
- virtual void StopProviders() OVERRIDE;
- virtual void OnPermissionGranted() OVERRIDE;
- virtual bool HasPermissionBeenGranted() const OVERRIDE;
+ void StartProviders(bool use_high_accuracy) override;
+ void StopProviders() override;
+ void OnPermissionGranted() override;
+ bool HasPermissionBeenGranted() const override;
private:
bool permission_granted_;
diff --git a/chromium/content/browser/geolocation/mock_location_provider.cc b/chromium/content/browser/geolocation/mock_location_provider.cc
index 22980b1de73..2953ba1be17 100644
--- a/chromium/content/browser/geolocation/mock_location_provider.cc
+++ b/chromium/content/browser/geolocation/mock_location_provider.cc
@@ -86,7 +86,7 @@ class AutoMockLocationProvider : public MockLocationProvider {
position_.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
}
}
- virtual bool StartProvider(bool high_accuracy) OVERRIDE {
+ bool StartProvider(bool high_accuracy) override {
MockLocationProvider::StartProvider(high_accuracy);
if (!requires_permission_to_start_) {
UpdateListenersIfNeeded();
@@ -94,7 +94,7 @@ class AutoMockLocationProvider : public MockLocationProvider {
return true;
}
- virtual void OnPermissionGranted() OVERRIDE {
+ void OnPermissionGranted() override {
MockLocationProvider::OnPermissionGranted();
if (requires_permission_to_start_) {
UpdateListenersIfNeeded();
diff --git a/chromium/content/browser/geolocation/mock_location_provider.h b/chromium/content/browser/geolocation/mock_location_provider.h
index dd7471fb237..882a447330d 100644
--- a/chromium/content/browser/geolocation/mock_location_provider.h
+++ b/chromium/content/browser/geolocation/mock_location_provider.h
@@ -20,16 +20,16 @@ class MockLocationProvider : public LocationProviderBase {
// Will update |*self_ref| to point to |this| on construction, and to NULL
// on destruction.
explicit MockLocationProvider(MockLocationProvider** self_ref);
- virtual ~MockLocationProvider();
+ ~MockLocationProvider() override;
// Updates listeners with the new position.
void HandlePositionChanged(const Geoposition& position);
// LocationProvider implementation.
- virtual bool StartProvider(bool high_accuracy) OVERRIDE;
- virtual void StopProvider() OVERRIDE;
- virtual void GetPosition(Geoposition* position) OVERRIDE;
- virtual void OnPermissionGranted() OVERRIDE;
+ bool StartProvider(bool high_accuracy) override;
+ void StopProvider() override;
+ void GetPosition(Geoposition* position) override;
+ void OnPermissionGranted() override;
Geoposition position_;
enum State { STOPPED, LOW_ACCURACY, HIGH_ACCURACY } state_;
diff --git a/chromium/content/browser/geolocation/network_location_provider.cc b/chromium/content/browser/geolocation/network_location_provider.cc
index 2a9d7c8a3b8..13a6504d006 100644
--- a/chromium/content/browser/geolocation/network_location_provider.cc
+++ b/chromium/content/browser/geolocation/network_location_provider.cc
@@ -108,9 +108,9 @@ NetworkLocationProvider::NetworkLocationProvider(
const GURL& url,
const base::string16& access_token)
: access_token_store_(access_token_store),
- wifi_data_provider_(NULL),
+ wifi_data_provider_manager_(NULL),
wifi_data_update_callback_(
- base::Bind(&NetworkLocationProvider::WifiDataUpdateAvailable,
+ base::Bind(&NetworkLocationProvider::OnWifiDataUpdate,
base::Unretained(this))),
is_wifi_data_complete_(false),
access_token_(access_token),
@@ -120,10 +120,11 @@ NetworkLocationProvider::NetworkLocationProvider(
// Create the position cache.
position_cache_.reset(new PositionCache());
- NetworkLocationRequest::LocationResponseCallback callback =
- base::Bind(&NetworkLocationProvider::LocationResponseAvailable,
- base::Unretained(this));
- request_.reset(new NetworkLocationRequest(url_context_getter, url, callback));
+ request_.reset(new NetworkLocationRequest(
+ url_context_getter,
+ url,
+ base::Bind(&NetworkLocationProvider::OnLocationResponse,
+ base::Unretained(this))));
}
NetworkLocationProvider::~NetworkLocationProvider() {
@@ -153,14 +154,13 @@ void NetworkLocationProvider::OnPermissionGranted() {
}
}
-void NetworkLocationProvider::WifiDataUpdateAvailable(
- WifiDataProvider* provider) {
- DCHECK(provider == wifi_data_provider_);
- is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
+void NetworkLocationProvider::OnWifiDataUpdate() {
+ DCHECK(wifi_data_provider_manager_);
+ is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
OnWifiDataUpdated();
}
-void NetworkLocationProvider::LocationResponseAvailable(
+void NetworkLocationProvider::OnLocationResponse(
const Geoposition& position,
bool server_error,
const base::string16& access_token,
@@ -186,7 +186,7 @@ bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
DCHECK(CalledOnValidThread());
if (IsStarted())
return true;
- DCHECK(wifi_data_provider_ == NULL);
+ DCHECK(wifi_data_provider_manager_ == NULL);
if (!request_->url().is_valid()) {
LOG(WARNING) << "StartProvider() : Failed, Bad URL: "
<< request_->url().possibly_invalid_spec();
@@ -196,7 +196,8 @@ bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
// Registers a callback with the data provider. The first call to Register
// will create a singleton data provider and it will be deleted when the last
// callback is removed with Unregister.
- wifi_data_provider_ = WifiDataProvider::Register(&wifi_data_update_callback_);
+ wifi_data_provider_manager_ =
+ WifiDataProviderManager::Register(&wifi_data_update_callback_);
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
@@ -204,7 +205,7 @@ bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(kDataCompleteWaitSeconds));
// Get the wifi data.
- is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
+ is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
if (is_wifi_data_complete_)
OnWifiDataUpdated();
return true;
@@ -221,9 +222,9 @@ void NetworkLocationProvider::OnWifiDataUpdated() {
void NetworkLocationProvider::StopProvider() {
DCHECK(CalledOnValidThread());
if (IsStarted()) {
- wifi_data_provider_->Unregister(&wifi_data_update_callback_);
+ wifi_data_provider_manager_->Unregister(&wifi_data_update_callback_);
}
- wifi_data_provider_ = NULL;
+ wifi_data_provider_manager_ = NULL;
weak_factory_.InvalidateWeakPtrs();
}
@@ -269,7 +270,7 @@ void NetworkLocationProvider::RequestPosition() {
}
bool NetworkLocationProvider::IsStarted() const {
- return wifi_data_provider_ != NULL;
+ return wifi_data_provider_manager_ != NULL;
}
} // namespace content
diff --git a/chromium/content/browser/geolocation/network_location_provider.h b/chromium/content/browser/geolocation/network_location_provider.h
index 710fd3f4fa6..e3588c64272 100644
--- a/chromium/content/browser/geolocation/network_location_provider.h
+++ b/chromium/content/browser/geolocation/network_location_provider.h
@@ -17,7 +17,7 @@
#include "base/threading/thread.h"
#include "content/browser/geolocation/location_provider_base.h"
#include "content/browser/geolocation/network_location_request.h"
-#include "content/browser/geolocation/wifi_data_provider.h"
+#include "content/browser/geolocation/wifi_data_provider_manager.h"
#include "content/common/content_export.h"
#include "content/public/common/geoposition.h"
@@ -69,38 +69,38 @@ class NetworkLocationProvider
net::URLRequestContextGetter* context,
const GURL& url,
const base::string16& access_token);
- virtual ~NetworkLocationProvider();
+ ~NetworkLocationProvider() override;
// LocationProvider implementation
- virtual bool StartProvider(bool high_accuracy) OVERRIDE;
- virtual void StopProvider() OVERRIDE;
- virtual void GetPosition(Geoposition *position) OVERRIDE;
- virtual void RequestRefresh() OVERRIDE;
- virtual void OnPermissionGranted() OVERRIDE;
+ bool StartProvider(bool high_accuracy) override;
+ void StopProvider() override;
+ void GetPosition(Geoposition* position) override;
+ void RequestRefresh() override;
+ void OnPermissionGranted() override;
private:
// Satisfies a position request from cache or network.
void RequestPosition();
- // Called from a callback when new wifi data is available.
- void WifiDataUpdateAvailable(WifiDataProvider* provider);
+ // Gets called when new wifi data is available.
+ void OnWifiDataUpdate();
- // Internal helper used by WifiDataUpdateAvailable.
+ // Internal helper used by OnWifiDataUpdate.
void OnWifiDataUpdated();
bool IsStarted() const;
- void LocationResponseAvailable(const Geoposition& position,
- bool server_error,
- const base::string16& access_token,
- const WifiData& wifi_data);
+ void OnLocationResponse(const Geoposition& position,
+ bool server_error,
+ const base::string16& access_token,
+ const WifiData& wifi_data);
scoped_refptr<AccessTokenStore> access_token_store_;
// The wifi data provider, acquired via global factories.
- WifiDataProvider* wifi_data_provider_;
+ WifiDataProviderManager* wifi_data_provider_manager_;
- WifiDataProvider::WifiDataUpdateCallback wifi_data_update_callback_;
+ WifiDataProviderManager::WifiDataUpdateCallback wifi_data_update_callback_;
// The wifi data and a flag to indicate if the data set is complete.
WifiData wifi_data_;
diff --git a/chromium/content/browser/geolocation/network_location_provider_unittest.cc b/chromium/content/browser/geolocation/network_location_provider_unittest.cc
index c574b7a7b96..b8ef6cabb52 100644
--- a/chromium/content/browser/geolocation/network_location_provider_unittest.cc
+++ b/chromium/content/browser/geolocation/network_location_provider_unittest.cc
@@ -13,6 +13,7 @@
#include "content/browser/geolocation/fake_access_token_store.h"
#include "content/browser/geolocation/location_arbitrator_impl.h"
#include "content/browser/geolocation/network_location_provider.h"
+#include "content/browser/geolocation/wifi_data_provider.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_status.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -35,8 +36,8 @@ class MessageLoopQuitListener {
CHECK(client_message_loop_);
}
- void LocationUpdateAvailable(const LocationProvider* provider,
- const Geoposition& position) {
+ void OnLocationUpdate(const LocationProvider* provider,
+ const Geoposition& position) {
EXPECT_EQ(client_message_loop_, base::MessageLoop::current());
updated_provider_ = provider;
client_message_loop_->Quit();
@@ -46,38 +47,30 @@ class MessageLoopQuitListener {
const LocationProvider* updated_provider_;
};
-// A mock implementation of WifiDataProviderImplBase for testing. Adapted from
+// A mock implementation of WifiDataProvider for testing. Adapted from
// http://gears.googlecode.com/svn/trunk/gears/geolocation/geolocation_test.cc
-class MockWifiDataProviderImpl : public WifiDataProviderImplBase {
+class MockWifiDataProvider : public WifiDataProvider {
public:
- // Factory method for use with WifiDataProvider::SetFactory.
- static WifiDataProviderImplBase* GetInstance() {
+ // Factory method for use with WifiDataProvider::SetFactoryForTesting.
+ static WifiDataProvider* GetInstance() {
CHECK(instance_);
return instance_;
}
- static MockWifiDataProviderImpl* CreateInstance() {
+ static MockWifiDataProvider* CreateInstance() {
CHECK(!instance_);
- instance_ = new MockWifiDataProviderImpl;
+ instance_ = new MockWifiDataProvider;
return instance_;
}
- MockWifiDataProviderImpl()
- : start_calls_(0),
- stop_calls_(0),
- got_data_(true) {
- }
+ MockWifiDataProvider() : start_calls_(0), stop_calls_(0), got_data_(true) {}
- // WifiDataProviderImplBase implementation.
- virtual void StartDataProvider() OVERRIDE {
- ++start_calls_;
- }
+ // WifiDataProvider implementation.
+ void StartDataProvider() override { ++start_calls_; }
- virtual void StopDataProvider() OVERRIDE {
- ++stop_calls_;
- }
+ void StopDataProvider() override { ++stop_calls_; }
- virtual bool GetData(WifiData* data_out) OVERRIDE {
+ bool GetData(WifiData* data_out) override {
CHECK(data_out);
*data_out = data_;
return got_data_;
@@ -96,33 +89,32 @@ class MockWifiDataProviderImpl : public WifiDataProviderImplBase {
int stop_calls_;
private:
- virtual ~MockWifiDataProviderImpl() {
+ ~MockWifiDataProvider() override {
CHECK(this == instance_);
instance_ = NULL;
}
- static MockWifiDataProviderImpl* instance_;
+ static MockWifiDataProvider* instance_;
WifiData data_;
bool got_data_;
- DISALLOW_COPY_AND_ASSIGN(MockWifiDataProviderImpl);
+ DISALLOW_COPY_AND_ASSIGN(MockWifiDataProvider);
};
-MockWifiDataProviderImpl* MockWifiDataProviderImpl::instance_ = NULL;
+MockWifiDataProvider* MockWifiDataProvider::instance_ = NULL;
// Main test fixture
class GeolocationNetworkProviderTest : public testing::Test {
public:
- virtual void SetUp() {
+ void SetUp() override {
test_server_url_ = GURL(kTestServerUrl);
access_token_store_ = new FakeAccessTokenStore;
- wifi_data_provider_ =
- MockWifiDataProviderImpl::CreateInstance();
+ wifi_data_provider_ = MockWifiDataProvider::CreateInstance();
}
- virtual void TearDown() {
- WifiDataProvider::ResetFactory();
+ void TearDown() override {
+ WifiDataProviderManager::ResetFactoryForTesting();
}
LocationProvider* CreateProvider(bool set_permission_granted) {
@@ -140,7 +132,8 @@ class GeolocationNetworkProviderTest : public testing::Test {
GeolocationNetworkProviderTest() {
// TODO(joth): Really these should be in SetUp, not here, but they take no
// effect on Mac OS Release builds if done there. I kid not. Figure out why.
- WifiDataProvider::SetFactory(MockWifiDataProviderImpl::GetInstance);
+ WifiDataProviderManager::SetFactoryForTesting(
+ MockWifiDataProvider::GetInstance);
}
// Returns the current url fetcher (if any) and advances the id ready for the
@@ -321,7 +314,7 @@ class GeolocationNetworkProviderTest : public testing::Test {
base::MessageLoop main_message_loop_;
scoped_refptr<FakeAccessTokenStore> access_token_store_;
net::TestURLFetcherFactory url_fetcher_factory_;
- scoped_refptr<MockWifiDataProviderImpl> wifi_data_provider_;
+ scoped_refptr<MockWifiDataProvider> wifi_data_provider_;
};
TEST_F(GeolocationNetworkProviderTest, CreateDestroy) {
@@ -473,9 +466,8 @@ TEST_F(GeolocationNetworkProviderTest, NoRequestOnStartupUntilWifiData) {
scoped_ptr<LocationProvider> provider(CreateProvider(true));
EXPECT_TRUE(provider->StartProvider(false));
- provider->SetUpdateCallback(
- base::Bind(&MessageLoopQuitListener::LocationUpdateAvailable,
- base::Unretained(&listener)));
+ provider->SetUpdateCallback(base::Bind(
+ &MessageLoopQuitListener::OnLocationUpdate, base::Unretained(&listener)));
main_message_loop_.RunUntilIdle();
EXPECT_FALSE(get_url_fetcher_and_advance_id())
diff --git a/chromium/content/browser/geolocation/network_location_request.cc b/chromium/content/browser/geolocation/network_location_request.cc
index 8fb6e6a9076..84ba5b05edc 100644
--- a/chromium/content/browser/geolocation/network_location_request.cc
+++ b/chromium/content/browser/geolocation/network_location_request.cc
@@ -103,9 +103,7 @@ NetworkLocationRequest::NetworkLocationRequest(
net::URLRequestContextGetter* context,
const GURL& url,
LocationResponseCallback callback)
- : url_context_(context),
- callback_(callback),
- url_(url) {
+ : url_context_(context), location_response_callback_(callback), url_(url) {
}
NetworkLocationRequest::~NetworkLocationRequest() {
@@ -122,7 +120,7 @@ bool NetworkLocationRequest::MakeRequest(const base::string16& access_token,
url_fetcher_.reset();
}
wifi_data_ = wifi_data;
- timestamp_ = timestamp;
+ wifi_data_timestamp_ = timestamp;
GURL request_url = FormRequestURL(url_);
url_fetcher_.reset(net::URLFetcher::Create(
@@ -136,7 +134,7 @@ bool NetworkLocationRequest::MakeRequest(const base::string16& access_token,
net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SEND_AUTH_DATA);
- start_time_ = base::TimeTicks::Now();
+ request_start_time_ = base::TimeTicks::Now();
url_fetcher_->Start();
return true;
}
@@ -156,7 +154,7 @@ void NetworkLocationRequest::OnURLFetchComplete(
GetLocationFromResponse(status.is_success(),
response_code,
data,
- timestamp_,
+ wifi_data_timestamp_,
source->GetURL(),
&position,
&access_token);
@@ -165,7 +163,8 @@ void NetworkLocationRequest::OnURLFetchComplete(
url_fetcher_.reset();
if (!server_error) {
- const base::TimeDelta request_time = base::TimeTicks::Now() - start_time_;
+ const base::TimeDelta request_time =
+ base::TimeTicks::Now() - request_start_time_;
UMA_HISTOGRAM_CUSTOM_TIMES(
"Net.Wifi.LbsLatency",
@@ -176,7 +175,8 @@ void NetworkLocationRequest::OnURLFetchComplete(
}
DVLOG(1) << "NetworkLocationRequest::OnURLFetchComplete() : run callback.";
- callback_.Run(position, server_error, access_token, wifi_data_);
+ location_response_callback_.Run(
+ position, server_error, access_token, wifi_data_);
}
// Local functions.
@@ -409,7 +409,8 @@ bool ParseServerResponse(const std::string& response_body,
static_cast<const base::DictionaryValue*>(location_value);
// latitude and longitude fields are always required.
- double latitude, longitude;
+ double latitude = 0;
+ double longitude = 0;
if (!GetAsDouble(*location_object, kLatitudeString, &latitude) ||
!GetAsDouble(*location_object, kLongitudeString, &longitude)) {
VLOG(1) << "ParseServerResponse() : location lacks lat and/or long.";
diff --git a/chromium/content/browser/geolocation/network_location_request.h b/chromium/content/browser/geolocation/network_location_request.h
index 6fea08b8bd5..f0734e00c25 100644
--- a/chromium/content/browser/geolocation/network_location_request.h
+++ b/chromium/content/browser/geolocation/network_location_request.h
@@ -41,7 +41,7 @@ class NetworkLocationRequest : private net::URLFetcherDelegate {
NetworkLocationRequest(net::URLRequestContextGetter* context,
const GURL& url,
LocationResponseCallback callback);
- virtual ~NetworkLocationRequest();
+ ~NetworkLocationRequest() override;
// Makes a new request. Returns true if the new request was successfully
// started. In all cases, any currently pending request will be canceled.
@@ -54,20 +54,20 @@ class NetworkLocationRequest : private net::URLFetcherDelegate {
private:
// net::URLFetcherDelegate
- virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
scoped_refptr<net::URLRequestContextGetter> url_context_;
- LocationResponseCallback callback_;
+ LocationResponseCallback location_response_callback_;
const GURL url_;
scoped_ptr<net::URLFetcher> url_fetcher_;
// 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 timestamp_; // Timestamp of the above data, not of the request.
+ base::Time wifi_data_timestamp_;
// The start time for the request.
- base::TimeTicks start_time_;
+ base::TimeTicks request_start_time_;
DISALLOW_COPY_AND_ASSIGN(NetworkLocationRequest);
};
diff --git a/chromium/content/browser/geolocation/wifi_data_provider.cc b/chromium/content/browser/geolocation/wifi_data_provider.cc
index 85595f927ab..cd739e7fb7c 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider.cc
@@ -6,142 +6,48 @@
namespace content {
-// static
-WifiDataProvider* WifiDataProvider::instance_ = NULL;
-
-// static
-WifiDataProvider::ImplFactoryFunction WifiDataProvider::factory_function_ =
- DefaultFactoryFunction;
-
-// static
-void WifiDataProvider::SetFactory(ImplFactoryFunction factory_function_in) {
- factory_function_ = factory_function_in;
-}
-
-// static
-void WifiDataProvider::ResetFactory() {
- factory_function_ = DefaultFactoryFunction;
-}
-
-// static
-WifiDataProvider* WifiDataProvider::Register(WifiDataUpdateCallback* callback) {
- bool need_to_start_data_provider = false;
- if (!instance_) {
- instance_ = new WifiDataProvider();
- need_to_start_data_provider = true;
- }
- DCHECK(instance_);
- instance_->AddCallback(callback);
- // Start the provider after adding the callback, to avoid any race in
- // it running early.
- if (need_to_start_data_provider)
- instance_->StartDataProvider();
- return instance_;
-}
-
-// static
-bool WifiDataProvider::Unregister(WifiDataUpdateCallback* callback) {
- DCHECK(instance_);
- DCHECK(instance_->has_callbacks());
- if (!instance_->RemoveCallback(callback)) {
- return false;
- }
- if (!instance_->has_callbacks()) {
- // Must stop the data provider (and any implementation threads) before
- // destroying to avoid any race conditions in access to the provider in
- // the destructor chain.
- instance_->StopDataProvider();
- delete instance_;
- instance_ = NULL;
- }
- return true;
-}
-
-WifiDataProviderImplBase::WifiDataProviderImplBase()
- : container_(NULL),
- client_loop_(base::MessageLoop::current()) {
+WifiDataProvider::WifiDataProvider()
+ : client_loop_(base::MessageLoop::current()) {
DCHECK(client_loop_);
}
-WifiDataProviderImplBase::~WifiDataProviderImplBase() {
-}
-
-void WifiDataProviderImplBase::SetContainer(WifiDataProvider* container) {
- container_ = container;
+WifiDataProvider::~WifiDataProvider() {
}
-void WifiDataProviderImplBase::AddCallback(WifiDataUpdateCallback* callback) {
+void WifiDataProvider::AddCallback(WifiDataUpdateCallback* callback) {
callbacks_.insert(callback);
}
-bool WifiDataProviderImplBase::RemoveCallback(
- WifiDataUpdateCallback* callback) {
+bool WifiDataProvider::RemoveCallback(WifiDataUpdateCallback* callback) {
return callbacks_.erase(callback) == 1;
}
-bool WifiDataProviderImplBase::has_callbacks() const {
+bool WifiDataProvider::has_callbacks() const {
return !callbacks_.empty();
}
-void WifiDataProviderImplBase::RunCallbacks() {
- client_loop_->PostTask(FROM_HERE, base::Bind(
- &WifiDataProviderImplBase::DoRunCallbacks,
- this));
+void WifiDataProvider::RunCallbacks() {
+ client_loop_->PostTask(FROM_HERE,
+ base::Bind(&WifiDataProvider::DoRunCallbacks, this));
}
-bool WifiDataProviderImplBase::CalledOnClientThread() const {
+bool WifiDataProvider::CalledOnClientThread() const {
return base::MessageLoop::current() == this->client_loop_;
}
-base::MessageLoop* WifiDataProviderImplBase::client_loop() const {
+base::MessageLoop* WifiDataProvider::client_loop() const {
return client_loop_;
}
-void WifiDataProviderImplBase::DoRunCallbacks() {
- // It's possible that all the callbacks (and the container) went away
- // whilst this task was pending. This is fine; the loop will be a no-op.
+void WifiDataProvider::DoRunCallbacks() {
+ // It's possible that all the callbacks went away whilst this task was
+ // pending. This is fine; the loop will be a no-op.
CallbackSet::const_iterator iter = callbacks_.begin();
while (iter != callbacks_.end()) {
WifiDataUpdateCallback* callback = *iter;
++iter; // Advance iter before running, in case callback unregisters.
- callback->Run(container_);
+ callback->Run();
}
}
-WifiDataProvider::WifiDataProvider() {
- DCHECK(factory_function_);
- impl_ = (*factory_function_)();
- DCHECK(impl_.get());
- impl_->SetContainer(this);
-}
-
-WifiDataProvider::~WifiDataProvider() {
- DCHECK(impl_.get());
- impl_->SetContainer(NULL);
-}
-
-bool WifiDataProvider::GetData(WifiData* data) {
- return impl_->GetData(data);
-}
-
-void WifiDataProvider::AddCallback(WifiDataUpdateCallback* callback) {
- impl_->AddCallback(callback);
-}
-
-bool WifiDataProvider::RemoveCallback(WifiDataUpdateCallback* callback) {
- return impl_->RemoveCallback(callback);
-}
-
-bool WifiDataProvider::has_callbacks() const {
- return impl_->has_callbacks();
-}
-
-void WifiDataProvider::StartDataProvider() {
- impl_->StartDataProvider();
-}
-
-void WifiDataProvider::StopDataProvider() {
- impl_->StopDataProvider();
-}
-
} // namespace content
diff --git a/chromium/content/browser/geolocation/wifi_data_provider.h b/chromium/content/browser/geolocation/wifi_data_provider.h
index bfb06ec5444..98d22963e9f 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider.h
@@ -2,19 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// A wifi data provider provides wifi data from the device that is used by a
-// NetworkLocationProvider to obtain a position fix. We use a singleton
-// instance of the wifi data provider, which is used by multiple
-// NetworkLocationProvider objects.
-//
-// This file provides WifiDataProvider, which provides static methods to
-// access the singleton instance. The singleton instance uses a private
-// implementation to abstract across platforms and also to allow mock providers
-// to be used for testing.
-//
-// This file also provides WifiDataProviderImplBase, a base class which
-// provides common functionality for the private implementations.
-
#ifndef CONTENT_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_H_
#define CONTENT_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_H_
@@ -32,16 +19,10 @@
namespace content {
-class WifiDataProvider;
-
-// See class WifiDataProvider for the public client API.
-// WifiDataProvider uses containment to hide platform-specific implementation
-// details from common code. This class provides common functionality for these
-// contained implementation classes. This is a modified pimpl pattern.
-class CONTENT_EXPORT WifiDataProviderImplBase
- : public base::RefCountedThreadSafe<WifiDataProviderImplBase> {
+class CONTENT_EXPORT WifiDataProvider
+ : public base::RefCountedThreadSafe<WifiDataProvider> {
public:
- WifiDataProviderImplBase();
+ WifiDataProvider();
// Tells the provider to start looking for data. Callbacks will start
// receiving notifications after this call.
@@ -56,11 +37,7 @@ class CONTENT_EXPORT WifiDataProviderImplBase
// obtain.
virtual bool GetData(WifiData* data) = 0;
- // Sets the container of this class, which is of type WifiDataProvider.
- // This is required to pass as a parameter when calling a callback.
- void SetContainer(WifiDataProvider* container);
-
- typedef base::Callback<void(WifiDataProvider*)> WifiDataUpdateCallback;
+ typedef base::Closure WifiDataUpdateCallback;
void AddCallback(WifiDataUpdateCallback* callback);
@@ -69,8 +46,8 @@ class CONTENT_EXPORT WifiDataProviderImplBase
bool has_callbacks() const;
protected:
- friend class base::RefCountedThreadSafe<WifiDataProviderImplBase>;
- virtual ~WifiDataProviderImplBase();
+ friend class base::RefCountedThreadSafe<WifiDataProvider>;
+ virtual ~WifiDataProvider();
typedef std::set<WifiDataUpdateCallback*> CallbackSet;
@@ -85,75 +62,12 @@ class CONTENT_EXPORT WifiDataProviderImplBase
private:
void DoRunCallbacks();
- WifiDataProvider* container_;
-
// Reference to the client's message loop. All callbacks should happen in this
// context.
base::MessageLoop* client_loop_;
CallbackSet callbacks_;
- DISALLOW_COPY_AND_ASSIGN(WifiDataProviderImplBase);
-};
-
-// A wifi data provider
-//
-// We use a singleton instance of this class which is shared by multiple network
-// location providers. These location providers access the instance through the
-// Register and Unregister methods.
-class CONTENT_EXPORT WifiDataProvider {
- public:
- // Sets the factory function which will be used by Register to create the
- // implementation used by the singleton instance. This factory approach is
- // used both to abstract accross platform-specific implementations and to
- // inject mock implementations for testing.
- typedef WifiDataProviderImplBase* (*ImplFactoryFunction)(void);
- static void SetFactory(ImplFactoryFunction factory_function_in);
-
- // Resets the factory function to the default.
- static void ResetFactory();
-
- typedef base::Callback<void(WifiDataProvider*)> WifiDataUpdateCallback;
-
- // Registers a callback, which will be run whenever new data is available.
- // Instantiates the singleton if necessary, and always returns it.
- static WifiDataProvider* Register(WifiDataUpdateCallback* callback);
-
- // Removes a callback. If this is the last callback, deletes the singleton
- // instance. Return value indicates success.
- static bool Unregister(WifiDataUpdateCallback* callback);
-
- // Provides whatever data the provider has, which may be nothing. Return
- // value indicates whether this is all the data the provider could ever
- // obtain.
- bool GetData(WifiData* data);
-
- private:
- // Private constructor and destructor, callers access singleton through
- // Register and Unregister.
- WifiDataProvider();
- virtual ~WifiDataProvider();
-
- void AddCallback(WifiDataUpdateCallback* callback);
- bool RemoveCallback(WifiDataUpdateCallback* callback);
- bool has_callbacks() const;
-
- void StartDataProvider();
- void StopDataProvider();
-
- static WifiDataProviderImplBase* DefaultFactoryFunction();
-
- // The singleton-like instance of this class. (Not 'true' singleton, as it
- // may go through multiple create/destroy/create cycles per process instance,
- // e.g. when under test).
- static WifiDataProvider* instance_;
-
- // The factory function used to create the singleton instance.
- static ImplFactoryFunction factory_function_;
-
- // The internal implementation.
- scoped_refptr<WifiDataProviderImplBase> impl_;
-
DISALLOW_COPY_AND_ASSIGN(WifiDataProvider);
};
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
index 49edb23e85c..2b5c218c24b 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/network/geolocation_handler.h"
+#include "content/browser/geolocation/wifi_data_provider_manager.h"
#include "content/public/browser/browser_thread.h"
namespace content {
@@ -166,7 +167,7 @@ bool WifiDataProviderChromeOs::GetAccessPointData(
}
// static
-WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
+WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
return new WifiDataProviderChromeOs();
}
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
index 895d06eaf31..db56ea7da09 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos.h
@@ -11,15 +11,14 @@
namespace content {
-class CONTENT_EXPORT WifiDataProviderChromeOs
- : public WifiDataProviderImplBase {
+class CONTENT_EXPORT WifiDataProviderChromeOs : public WifiDataProvider {
public:
WifiDataProviderChromeOs();
- // WifiDataProviderImplBase
- virtual void StartDataProvider() OVERRIDE;
- virtual void StopDataProvider() OVERRIDE;
- virtual bool GetData(WifiData* data) OVERRIDE;
+ // WifiDataProvider
+ virtual void StartDataProvider() override;
+ virtual void StopDataProvider() override;
+ virtual bool GetData(WifiData* data) override;
private:
friend class GeolocationChromeOsWifiDataProviderTest;
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 f282f31e510..eb0442194cb 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_chromeos_unittest.cc
@@ -19,8 +19,8 @@ class GeolocationChromeOsWifiDataProviderTest : public testing::Test {
GeolocationChromeOsWifiDataProviderTest() {
}
- virtual void SetUp() OVERRIDE {
- chromeos::DBusThreadManager::InitializeWithStub();
+ virtual void SetUp() override {
+ chromeos::DBusThreadManager::Initialize();
chromeos::NetworkHandler::Initialize();
manager_client_ =
chromeos::DBusThreadManager::Get()->GetShillManagerClient();
@@ -29,7 +29,7 @@ class GeolocationChromeOsWifiDataProviderTest : public testing::Test {
message_loop_.RunUntilIdle();
}
- virtual void TearDown() OVERRIDE {
+ virtual void TearDown() override {
provider_ = NULL;
chromeos::NetworkHandler::Shutdown();
chromeos::DBusThreadManager::Shutdown();
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_common.h b/chromium/content/browser/geolocation/wifi_data_provider_common.h
index befdb692114..771dd41efc8 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_common.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_common.h
@@ -25,7 +25,7 @@ base::string16 MacAddressAsString16(const uint8 mac_as_int[6]);
// do polling behavior is taken care of by this base class, and all the platform
// need do is provide the underlying WLAN access API and polling policy.
// Also designed this way for ease of testing the cross-platform behavior.
-class CONTENT_EXPORT WifiDataProviderCommon : public WifiDataProviderImplBase {
+class CONTENT_EXPORT WifiDataProviderCommon : public WifiDataProvider {
public:
// Interface to abstract the low level data OS library call, and to allow
// mocking (hence public).
@@ -38,13 +38,13 @@ class CONTENT_EXPORT WifiDataProviderCommon : public WifiDataProviderImplBase {
WifiDataProviderCommon();
- // WifiDataProviderImplBase implementation
- virtual void StartDataProvider() OVERRIDE;
- virtual void StopDataProvider() OVERRIDE;
- virtual bool GetData(WifiData* data) OVERRIDE;
+ // WifiDataProvider implementation
+ void StartDataProvider() override;
+ void StopDataProvider() override;
+ bool GetData(WifiData* data) override;
protected:
- virtual ~WifiDataProviderCommon();
+ ~WifiDataProviderCommon() override;
// Returns ownership.
virtual WlanApiInterface* NewWlanApi() = 0;
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 9c55dfd3335..53d44bcc770 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_common_unittest.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_common_unittest.cc
@@ -9,6 +9,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "content/browser/geolocation/wifi_data_provider_common.h"
+#include "content/browser/geolocation/wifi_data_provider_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -62,18 +63,18 @@ class MessageLoopQuitter {
public:
explicit MessageLoopQuitter(base::MessageLoop* message_loop)
: message_loop_to_quit_(message_loop),
- callback_(base::Bind(&MessageLoopQuitter::WifiDataUpdateAvailable,
+ callback_(base::Bind(&MessageLoopQuitter::OnWifiDataUpdate,
base::Unretained(this))) {
CHECK(message_loop_to_quit_ != NULL);
}
- void WifiDataUpdateAvailable(WifiDataProvider* provider) {
+ 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_;
- WifiDataProvider::WifiDataUpdateCallback callback_;
+ WifiDataProviderManager::WifiDataUpdateCallback callback_;
};
class WifiDataProviderCommonWithMock : public WifiDataProviderCommon {
@@ -83,11 +84,11 @@ class WifiDataProviderCommonWithMock : public WifiDataProviderCommon {
new_polling_policy_(new MockPollingPolicy) {}
// WifiDataProviderCommon
- virtual WlanApiInterface* NewWlanApi() OVERRIDE {
+ WlanApiInterface* NewWlanApi() override {
CHECK(new_wlan_api_ != NULL);
return new_wlan_api_.release();
}
- virtual WifiPollingPolicy* NewPollingPolicy() OVERRIDE {
+ WifiPollingPolicy* NewPollingPolicy() override {
CHECK(new_polling_policy_ != NULL);
return new_polling_policy_.release();
}
@@ -96,12 +97,12 @@ class WifiDataProviderCommonWithMock : public WifiDataProviderCommon {
scoped_ptr<MockPollingPolicy> new_polling_policy_;
private:
- virtual ~WifiDataProviderCommonWithMock() {}
+ ~WifiDataProviderCommonWithMock() override {}
DISALLOW_COPY_AND_ASSIGN(WifiDataProviderCommonWithMock);
};
-WifiDataProviderImplBase* CreateWifiDataProviderCommonWithMock() {
+WifiDataProvider* CreateWifiDataProviderCommonWithMock() {
return new WifiDataProviderCommonWithMock;
}
@@ -112,13 +113,13 @@ class GeolocationWifiDataProviderCommonTest : public testing::Test {
: loop_quitter_(&main_message_loop_) {
}
- virtual void SetUp() {
+ 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_);
}
- virtual void TearDown() {
+ void TearDown() override {
provider_->RemoveCallback(&loop_quitter_.callback_);
provider_->StopDataProvider();
provider_ = NULL;
@@ -181,7 +182,12 @@ TEST_F(GeolocationWifiDataProviderCommonTest, IntermittentWifi){
main_message_loop_.Run();
}
-TEST_F(GeolocationWifiDataProviderCommonTest, DoAnEmptyScan) {
+#if defined(OS_MACOSX)
+#define MAYBE_DoAnEmptyScan DISABLED_DoAnEmptyScan
+#else
+#define MAYBE_DoAnEmptyScan DoAnEmptyScan
+#endif
+TEST_F(GeolocationWifiDataProviderCommonTest, MAYBE_DoAnEmptyScan) {
EXPECT_CALL(*wlan_api_, GetAccessPointData(_))
.Times(AtLeast(1));
EXPECT_CALL(*polling_policy_, PollingInterval())
@@ -194,7 +200,12 @@ TEST_F(GeolocationWifiDataProviderCommonTest, DoAnEmptyScan) {
EXPECT_EQ(0, static_cast<int>(data.access_point_data.size()));
}
-TEST_F(GeolocationWifiDataProviderCommonTest, DoScanWithResults) {
+#if defined(OS_MACOSX)
+#define MAYBE_DoScanWithResults DISABLED_DoScanWithResults
+#else
+#define MAYBE_DoScanWithResults DoScanWithResults
+#endif
+TEST_F(GeolocationWifiDataProviderCommonTest, MAYBE_DoScanWithResults) {
EXPECT_CALL(*wlan_api_, GetAccessPointData(_))
.Times(AtLeast(1));
EXPECT_CALL(*polling_policy_, PollingInterval())
@@ -218,11 +229,12 @@ TEST_F(GeolocationWifiDataProviderCommonTest, DoScanWithResults) {
TEST_F(GeolocationWifiDataProviderCommonTest, RegisterUnregister) {
MessageLoopQuitter loop_quitter(&main_message_loop_);
- WifiDataProvider::SetFactory(CreateWifiDataProviderCommonWithMock);
- WifiDataProvider::Register(&loop_quitter.callback_);
+ WifiDataProviderManager::SetFactoryForTesting(
+ CreateWifiDataProviderCommonWithMock);
+ WifiDataProviderManager::Register(&loop_quitter.callback_);
main_message_loop_.Run();
- WifiDataProvider::Unregister(&loop_quitter.callback_);
- WifiDataProvider::ResetFactory();
+ WifiDataProviderManager::Unregister(&loop_quitter.callback_);
+ WifiDataProviderManager::ResetFactoryForTesting();
}
} // namespace content
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 81930e08f36..7e783f42942 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm
+++ b/chromium/content/browser/geolocation/wifi_data_provider_corewlan_mac.mm
@@ -55,7 +55,7 @@ class CoreWlanApi : public WifiDataProviderCommon::WlanApiInterface {
bool Init();
// WlanApiInterface
- virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data) OVERRIDE;
+ bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
private:
base::scoped_nsobject<NSBundle> bundle_;
@@ -168,7 +168,7 @@ bool CoreWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
[supported_interfaces count] - interface_error_count,
1,
5,
- 5);
+ 6);
// Return true even if some interfaces failed to scan, so long as at least
// one interface did not fail.
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_linux.cc b/chromium/content/browser/geolocation/wifi_data_provider_linux.cc
index 5838c048e35..1909abfe141 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_linux.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_linux.cc
@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/browser/geolocation/wifi_data_provider_manager.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
@@ -39,7 +40,7 @@ enum { NM_DEVICE_TYPE_WIFI = 2 };
class NetworkManagerWlanApi : public WifiDataProviderCommon::WlanApiInterface {
public:
NetworkManagerWlanApi();
- virtual ~NetworkManagerWlanApi();
+ ~NetworkManagerWlanApi() override;
// Must be called before any other interface method. Will return false if the
// NetworkManager session cannot be created (e.g. not present on this distro),
@@ -53,7 +54,7 @@ class NetworkManagerWlanApi : public WifiDataProviderCommon::WlanApiInterface {
//
// This function makes blocking D-Bus calls, but it's totally fine as
// the code runs in "Geolocation" thread, not the browser's UI thread.
- virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data) OVERRIDE;
+ bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
private:
// Enumerates the list of available network adapter devices known to
@@ -344,7 +345,7 @@ scoped_ptr<dbus::Response> NetworkManagerWlanApi::GetAccessPointProperty(
} // namespace
// static
-WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
+WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
return new WifiDataProviderLinux();
}
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_linux.h b/chromium/content/browser/geolocation/wifi_data_provider_linux.h
index 40f6f14e75f..48584257da1 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_linux.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_linux.h
@@ -22,11 +22,11 @@ class CONTENT_EXPORT WifiDataProviderLinux : public WifiDataProviderCommon {
private:
friend class GeolocationWifiDataProviderLinuxTest;
- virtual ~WifiDataProviderLinux();
+ ~WifiDataProviderLinux() override;
// WifiDataProviderCommon
- virtual WlanApiInterface* NewWlanApi() OVERRIDE;
- virtual WifiPollingPolicy* NewPollingPolicy() OVERRIDE;
+ WlanApiInterface* NewWlanApi() override;
+ WifiPollingPolicy* NewPollingPolicy() override;
// For testing.
WlanApiInterface* NewWlanApiForTesting(dbus::Bus* bus);
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 498b230643c..5a4b546a082 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_linux_unittest.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_linux_unittest.cc
@@ -24,7 +24,7 @@ using ::testing::Unused;
namespace content {
class GeolocationWifiDataProviderLinuxTest : public testing::Test {
- virtual void SetUp() {
+ void SetUp() override {
// Create a mock bus.
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_mac.cc b/chromium/content/browser/geolocation/wifi_data_provider_mac.cc
index 6a87801c893..da541872583 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_mac.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_mac.cc
@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/geolocation/osx_wifi.h"
#include "content/browser/geolocation/wifi_data_provider_common.h"
+#include "content/browser/geolocation/wifi_data_provider_manager.h"
namespace content {
namespace {
@@ -29,7 +30,7 @@ const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
class Apple80211Api : public WifiDataProviderCommon::WlanApiInterface {
public:
Apple80211Api();
- virtual ~Apple80211Api();
+ ~Apple80211Api() override;
// Must be called before any other interface method. Will return false if the
// Apple80211 framework cannot be initialized (e.g. running on post-10.5 OSX),
@@ -37,7 +38,7 @@ class Apple80211Api : public WifiDataProviderCommon::WlanApiInterface {
bool Init();
// WlanApiInterface
- virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data) OVERRIDE;
+ bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
private:
// Handle, context and function pointers for Apple80211 library.
@@ -159,21 +160,21 @@ bool Apple80211Api::GetAccessPointData(WifiData::AccessPointDataSet* data) {
} // namespace
// static
-WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
- return new MacWifiDataProvider();
+WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
+ return new WifiDataProviderMac();
}
-MacWifiDataProvider::MacWifiDataProvider() {
+WifiDataProviderMac::WifiDataProviderMac() {
}
-MacWifiDataProvider::~MacWifiDataProvider() {
+WifiDataProviderMac::~WifiDataProviderMac() {
}
-MacWifiDataProvider::WlanApiInterface* MacWifiDataProvider::NewWlanApi() {
+WifiDataProviderMac::WlanApiInterface* WifiDataProviderMac::NewWlanApi() {
// Try and find a API binding that works: first try the officially supported
// CoreWLAN API, and if this fails (e.g. on OSX 10.5) fall back to the reverse
// engineered Apple80211 API.
- MacWifiDataProvider::WlanApiInterface* core_wlan_api = NewCoreWlanApi();
+ WifiDataProviderMac::WlanApiInterface* core_wlan_api = NewCoreWlanApi();
if (core_wlan_api)
return core_wlan_api;
@@ -181,11 +182,11 @@ MacWifiDataProvider::WlanApiInterface* MacWifiDataProvider::NewWlanApi() {
if (wlan_api->Init())
return wlan_api.release();
- DVLOG(1) << "MacWifiDataProvider : failed to initialize any wlan api";
+ DVLOG(1) << "WifiDataProviderMac : failed to initialize any wlan api";
return NULL;
}
-WifiPollingPolicy* MacWifiDataProvider::NewPollingPolicy() {
+WifiPollingPolicy* WifiDataProviderMac::NewPollingPolicy() {
return new GenericWifiPollingPolicy<kDefaultPollingInterval,
kNoChangePollingInterval,
kTwoNoChangePollingInterval,
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_mac.h b/chromium/content/browser/geolocation/wifi_data_provider_mac.h
index ebb0030df2f..c1bd7985cdc 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_mac.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_mac.h
@@ -12,18 +12,18 @@ namespace content {
// Implementation of the wifi data provider for Mac OSX. Uses different API
// bindings depending on APIs detected available at runtime in order to access
// wifi scan data: Apple80211.h on OSX 10.5, CoreWLAN framework on OSX 10.6.
-class MacWifiDataProvider : public WifiDataProviderCommon {
+class WifiDataProviderMac : public WifiDataProviderCommon {
public:
- MacWifiDataProvider();
+ WifiDataProviderMac();
private:
- virtual ~MacWifiDataProvider();
+ ~WifiDataProviderMac() override;
// WifiDataProviderCommon
- virtual WlanApiInterface* NewWlanApi() OVERRIDE;
- virtual WifiPollingPolicy* NewPollingPolicy() OVERRIDE;
+ WlanApiInterface* NewWlanApi() override;
+ WifiPollingPolicy* NewPollingPolicy() override;
- DISALLOW_COPY_AND_ASSIGN(MacWifiDataProvider);
+ DISALLOW_COPY_AND_ASSIGN(WifiDataProviderMac);
};
// Creates and returns a new API binding for the CoreWLAN API, or NULL if the
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_manager.cc b/chromium/content/browser/geolocation/wifi_data_provider_manager.cc
new file mode 100644
index 00000000000..cf53657e53a
--- /dev/null
+++ b/chromium/content/browser/geolocation/wifi_data_provider_manager.cc
@@ -0,0 +1,98 @@
+// 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/geolocation/wifi_data_provider_manager.h"
+
+#include "content/browser/geolocation/wifi_data_provider.h"
+
+namespace content {
+
+// static
+WifiDataProviderManager* WifiDataProviderManager::instance_ = NULL;
+
+// static
+WifiDataProviderManager::ImplFactoryFunction
+ WifiDataProviderManager::factory_function_ = DefaultFactoryFunction;
+
+// static
+void WifiDataProviderManager::SetFactoryForTesting(
+ ImplFactoryFunction factory_function_in) {
+ factory_function_ = factory_function_in;
+}
+
+// static
+void WifiDataProviderManager::ResetFactoryForTesting() {
+ factory_function_ = DefaultFactoryFunction;
+}
+
+// static
+WifiDataProviderManager* WifiDataProviderManager::Register(
+ WifiDataUpdateCallback* callback) {
+ bool need_to_start_data_provider = false;
+ if (!instance_) {
+ instance_ = new WifiDataProviderManager();
+ need_to_start_data_provider = true;
+ }
+ DCHECK(instance_);
+ instance_->AddCallback(callback);
+ // Start the provider after adding the callback, to avoid any race in
+ // it running early.
+ if (need_to_start_data_provider)
+ instance_->StartDataProvider();
+ return instance_;
+}
+
+// static
+bool WifiDataProviderManager::Unregister(WifiDataUpdateCallback* callback) {
+ DCHECK(instance_);
+ DCHECK(instance_->has_callbacks());
+ if (!instance_->RemoveCallback(callback)) {
+ return false;
+ }
+ if (!instance_->has_callbacks()) {
+ // Must stop the data provider (and any implementation threads) before
+ // destroying to avoid any race conditions in access to the provider in
+ // the destructor chain.
+ instance_->StopDataProvider();
+ delete instance_;
+ instance_ = NULL;
+ }
+ return true;
+}
+
+WifiDataProviderManager::WifiDataProviderManager() {
+ DCHECK(factory_function_);
+ impl_ = (*factory_function_)();
+ DCHECK(impl_.get());
+}
+
+WifiDataProviderManager::~WifiDataProviderManager() {
+ DCHECK(impl_.get());
+}
+
+bool WifiDataProviderManager::GetData(WifiData* data) {
+ return impl_->GetData(data);
+}
+
+void WifiDataProviderManager::AddCallback(WifiDataUpdateCallback* callback) {
+ impl_->AddCallback(callback);
+}
+
+bool WifiDataProviderManager::RemoveCallback(WifiDataUpdateCallback* callback) {
+ return impl_->RemoveCallback(callback);
+}
+
+bool WifiDataProviderManager::has_callbacks() const {
+ return impl_->has_callbacks();
+}
+
+void WifiDataProviderManager::StartDataProvider() {
+ impl_->StartDataProvider();
+}
+
+void WifiDataProviderManager::StopDataProvider() {
+ impl_->StopDataProvider();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_manager.h b/chromium/content/browser/geolocation/wifi_data_provider_manager.h
new file mode 100644
index 00000000000..966c03a5ced
--- /dev/null
+++ b/chromium/content/browser/geolocation/wifi_data_provider_manager.h
@@ -0,0 +1,98 @@
+// 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.
+
+// A wifi data provider provides wifi data from the device that is used by a
+// NetworkLocationProvider to obtain a position fix. We use a singleton
+// instance of the wifi data provider manager, which is used by multiple
+// NetworkLocationProvider objects.
+//
+// This file provides WifiDataProviderManager, which provides static methods to
+// access the singleton instance. The singleton instance uses a private
+// implementation of WifiDataProvider to abstract across platforms and also to
+// allow mock providers to be used for testing.
+
+#ifndef CONTENT_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MANAGER_H_
+#define CONTENT_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MANAGER_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.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"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class WifiDataProvider;
+
+// A manager for wifi data providers.
+//
+// We use a singleton instance of this class which is shared by multiple network
+// location providers. These location providers access the instance through the
+// Register and Unregister methods.
+class CONTENT_EXPORT WifiDataProviderManager {
+ public:
+ typedef WifiDataProvider* (*ImplFactoryFunction)(void);
+
+ // Sets the factory function which will be used by Register to create the
+ // implementation used by the singleton instance. This factory approach is
+ // used both to abstract accross platform-specific implementations and to
+ // inject mock implementations for testing.
+ static void SetFactoryForTesting(ImplFactoryFunction factory_function_in);
+
+ // Resets the factory function to the default.
+ static void ResetFactoryForTesting();
+
+ typedef base::Closure WifiDataUpdateCallback;
+
+ // Registers a callback, which will be run whenever new data is available.
+ // Instantiates the singleton if necessary, and always returns it.
+ static WifiDataProviderManager* Register(WifiDataUpdateCallback* callback);
+
+ // Removes a callback. If this is the last callback, deletes the singleton
+ // instance. Return value indicates success.
+ static bool Unregister(WifiDataUpdateCallback* callback);
+
+ // Provides whatever data the provider has, which may be nothing. Return
+ // value indicates whether this is all the data the provider could ever
+ // obtain.
+ bool GetData(WifiData* data);
+
+ private:
+ // Private constructor and destructor, callers access singleton through
+ // Register and Unregister.
+ WifiDataProviderManager();
+ ~WifiDataProviderManager();
+
+ void AddCallback(WifiDataUpdateCallback* callback);
+ bool RemoveCallback(WifiDataUpdateCallback* callback);
+ bool has_callbacks() const;
+
+ void StartDataProvider();
+ void StopDataProvider();
+
+ static WifiDataProvider* DefaultFactoryFunction();
+
+ // The singleton-like instance of this class. (Not 'true' singleton, as it
+ // may go through multiple create/destroy/create cycles per process instance,
+ // e.g. when under test).
+ static WifiDataProviderManager* instance_;
+
+ // The factory function used to create the singleton instance.
+ static ImplFactoryFunction factory_function_;
+
+ // The internal implementation.
+ scoped_refptr<WifiDataProvider> impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiDataProviderManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GEOLOCATION_WIFI_DATA_PROVIDER_MANAGER_H_
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_win.cc b/chromium/content/browser/geolocation/wifi_data_provider_win.cc
index 9345144438d..66c07c01848 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_win.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_win.cc
@@ -32,6 +32,7 @@
#include "base/win/windows_version.h"
#include "content/browser/geolocation/wifi_data_provider_common.h"
#include "content/browser/geolocation/wifi_data_provider_common_win.h"
+#include "content/browser/geolocation/wifi_data_provider_manager.h"
// Taken from ndis.h for WinCE.
#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L)
@@ -43,7 +44,7 @@ namespace {
const int kInitialBufferSize = 2 << 12; // Good for about 50 APs.
const int kMaximumBufferSize = 2 << 20; // 2MB
-// Length for generic string buffers passed to Win32 APIs.
+// Length for generic string buffers passed to Windows APIs.
const int kStringLength = 512;
// The time periods, in milliseconds, between successive polls of the wifi data.
@@ -147,7 +148,7 @@ bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry,
bool UndefineDosDevice(const base::string16& device_name);
bool DefineDosDeviceIfNotExists(const base::string16& device_name);
HANDLE GetFileHandle(const base::string16& device_name);
-// Makes the OID query and returns a Win32 error code.
+// Makes the OID query and returns a Windows API error code.
int PerformQuery(HANDLE adapter_handle,
BYTE* buffer,
DWORD buffer_size,
@@ -159,17 +160,17 @@ bool ResizeBuffer(int requested_size,
bool GetSystemDirectory(base::string16* path);
} // namespace
-WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() {
- return new Win32WifiDataProvider();
+WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
+ return new WifiDataProviderWin();
}
-Win32WifiDataProvider::Win32WifiDataProvider() {
+WifiDataProviderWin::WifiDataProviderWin() {
}
-Win32WifiDataProvider::~Win32WifiDataProvider() {
+WifiDataProviderWin::~WifiDataProviderWin() {
}
-WifiDataProviderCommon::WlanApiInterface* Win32WifiDataProvider::NewWlanApi() {
+WifiDataProviderCommon::WlanApiInterface* WifiDataProviderWin::NewWlanApi() {
// Use the WLAN interface if we're on Vista and if it's available. Otherwise,
// use NDIS.
WlanApiInterface* api = WindowsWlanApi::Create();
@@ -179,7 +180,7 @@ WifiDataProviderCommon::WlanApiInterface* Win32WifiDataProvider::NewWlanApi() {
return WindowsNdisApi::Create();
}
-WifiPollingPolicy* Win32WifiDataProvider::NewPollingPolicy() {
+WifiPollingPolicy* WifiDataProviderWin::NewPollingPolicy() {
return new GenericWifiPollingPolicy<kDefaultPollingInterval,
kNoChangePollingInterval,
kTwoNoChangePollingInterval,
@@ -244,7 +245,7 @@ void WindowsWlanApi::LogWlanInterfaceCount(int count) {
count,
1,
5,
- 5);
+ 6);
}
bool WindowsWlanApi::GetAccessPointData(
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_win.h b/chromium/content/browser/geolocation/wifi_data_provider_win.h
index c39bd580a79..d67798d5711 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_win.h
+++ b/chromium/content/browser/geolocation/wifi_data_provider_win.h
@@ -10,18 +10,18 @@
namespace content {
-class CONTENT_EXPORT Win32WifiDataProvider : public WifiDataProviderCommon {
+class CONTENT_EXPORT WifiDataProviderWin : public WifiDataProviderCommon {
public:
- Win32WifiDataProvider();
+ WifiDataProviderWin();
private:
- virtual ~Win32WifiDataProvider();
+ virtual ~WifiDataProviderWin();
// WifiDataProviderCommon
virtual WlanApiInterface* NewWlanApi();
virtual WifiPollingPolicy* NewPollingPolicy();
- DISALLOW_COPY_AND_ASSIGN(Win32WifiDataProvider);
+ DISALLOW_COPY_AND_ASSIGN(WifiDataProviderWin);
};
} // namespace content
diff --git a/chromium/content/browser/geolocation/wifi_data_provider_unittest_win.cc b/chromium/content/browser/geolocation/wifi_data_provider_win_unittest.cc
index c74f42c5739..cb3c21ce3ec 100644
--- a/chromium/content/browser/geolocation/wifi_data_provider_unittest_win.cc
+++ b/chromium/content/browser/geolocation/wifi_data_provider_win_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -10,13 +10,13 @@
namespace content {
-TEST(GeolocationWin32WifiDataProviderTest, CreateDestroy) {
+TEST(GeolocationWifiDataProviderWinTest, CreateDestroy) {
// WifiDataProviderCommon requires the client to have a message loop.
base::MessageLoop dummy_loop;
- scoped_refptr<Win32WifiDataProvider> instance(new Win32WifiDataProvider);
+ scoped_refptr<WifiDataProviderWin> instance(new WifiDataProviderWin);
instance = NULL;
SUCCEED();
- // Can't actually call start provider on the Win32WifiDataProvider without
+ // Can't actually call start provider on the WifiDataProviderWin without
// it accessing hardware and so risking making the test flaky.
}
diff --git a/chromium/content/browser/gpu/OWNERS b/chromium/content/browser/gpu/OWNERS
index b66635ae032..954a4d9b72b 100644
--- a/chromium/content/browser/gpu/OWNERS
+++ b/chromium/content/browser/gpu/OWNERS
@@ -1,3 +1,4 @@
+jbauman@chromium.org
kbr@chromium.org
piman@chromium.org
zmo@chromium.org
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 e2d1654e154..032c597c664 100644
--- a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -8,11 +8,13 @@
#include "base/debug/trace_event.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
+#include "base/tracked_objects.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_memory_buffer_factory_host_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/common/child_process_host_impl.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager.h"
@@ -26,8 +28,10 @@ namespace content {
BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
struct BrowserGpuChannelHostFactory::CreateRequest {
- CreateRequest()
- : event(true, false), gpu_host_id(0), route_id(MSG_ROUTING_NONE),
+ CreateRequest(int32 route_id)
+ : event(true, false),
+ gpu_host_id(0),
+ route_id(route_id),
result(CREATE_COMMAND_BUFFER_FAILED) {}
~CreateRequest() {}
base::WaitableEvent event;
@@ -129,6 +133,7 @@ void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
host->EstablishGpuChannel(
gpu_client_id_,
true,
+ true,
base::Bind(
&BrowserGpuChannelHostFactory::EstablishRequest::OnEstablishedOnIO,
this));
@@ -170,6 +175,13 @@ void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain() {
void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
DCHECK(main_loop_->BelongsToCurrentThread());
{
+ // Since the current task synchronously waits for establishing a GPU
+ // channel, it shouldn't be tallied because its execution time has nothing
+ // to do with its efficiency. Using task stopwatch to exclude the waiting
+ // time from the current task run time.
+ tracked_objects::TaskStopwatch stopwatch;
+ stopwatch.Start();
+
// 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.
@@ -178,6 +190,8 @@ void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
"BrowserGpuChannelHostFactory::EstablishGpuChannelSync");
base::ThreadRestrictions::ScopedAllowWait allow_wait;
event_.Wait();
+
+ stopwatch.Stop();
}
FinishOnMain();
}
@@ -209,13 +223,15 @@ void BrowserGpuChannelHostFactory::Terminate() {
BrowserGpuChannelHostFactory::BrowserGpuChannelHostFactory()
: gpu_client_id_(ChildProcessHostImpl::GenerateChildProcessUniqueId()),
shutdown_event_(new base::WaitableEvent(true, false)),
- gpu_host_id_(0),
- next_create_gpu_memory_buffer_request_id_(0) {
+ gpu_memory_buffer_factory_host_(new GpuMemoryBufferFactoryHostImpl),
+ gpu_memory_buffer_manager_(
+ new BrowserGpuMemoryBufferManager(gpu_client_id_)),
+ gpu_host_id_(0) {
}
BrowserGpuChannelHostFactory::~BrowserGpuChannelHostFactory() {
DCHECK(IsMainThread());
- if (pending_request_)
+ if (pending_request_.get())
pending_request_->Cancel();
for (size_t n = 0; n < established_callbacks_.size(); n++)
established_callbacks_[n].Run();
@@ -277,8 +293,7 @@ CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
int32 surface_id,
const GPUCreateCommandBufferConfig& init_params,
int32 route_id) {
- CreateRequest request;
- request.route_id = route_id;
+ CreateRequest request(route_id);
GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
&BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
base::Unretained(this),
@@ -296,77 +311,11 @@ CreateCommandBufferResult BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
return request.result;
}
-void BrowserGpuChannelHostFactory::CreateImageOnIO(
- gfx::PluginWindowHandle window,
- int32 image_id,
- const CreateImageCallback& callback) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
- if (!host) {
- ImageCreatedOnIO(callback, gfx::Size());
- return;
- }
-
- host->CreateImage(
- window,
- gpu_client_id_,
- image_id,
- base::Bind(&BrowserGpuChannelHostFactory::ImageCreatedOnIO, callback));
-}
-
-// static
-void BrowserGpuChannelHostFactory::ImageCreatedOnIO(
- const CreateImageCallback& callback, const gfx::Size size) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&BrowserGpuChannelHostFactory::OnImageCreated,
- callback, size));
-}
-
-// static
-void BrowserGpuChannelHostFactory::OnImageCreated(
- const CreateImageCallback& callback, const gfx::Size size) {
- callback.Run(size);
-}
-
-void BrowserGpuChannelHostFactory::CreateImage(
- gfx::PluginWindowHandle window,
- int32 image_id,
- const CreateImageCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
- &BrowserGpuChannelHostFactory::CreateImageOnIO,
- base::Unretained(this),
- window,
- image_id,
- callback));
-}
-
-void BrowserGpuChannelHostFactory::DeleteImageOnIO(
- int32 image_id, int32 sync_point) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
- if (!host) {
- return;
- }
-
- host->DeleteImage(gpu_client_id_, image_id, sync_point);
-}
-
-void BrowserGpuChannelHostFactory::DeleteImage(
- int32 image_id, int32 sync_point) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
- &BrowserGpuChannelHostFactory::DeleteImageOnIO,
- base::Unretained(this),
- image_id,
- sync_point));
-}
-
GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
CauseForGpuLaunch cause_for_gpu_launch) {
EstablishGpuChannel(cause_for_gpu_launch, base::Closure());
- if (pending_request_)
+ if (pending_request_.get())
pending_request_->Wait();
return gpu_channel_.get();
@@ -376,19 +325,19 @@ void BrowserGpuChannelHostFactory::EstablishGpuChannel(
CauseForGpuLaunch cause_for_gpu_launch,
const base::Closure& callback) {
if (gpu_channel_.get() && gpu_channel_->IsLost()) {
- DCHECK(!pending_request_);
+ DCHECK(!pending_request_.get());
// Recreate the channel if it has been lost.
gpu_channel_ = NULL;
}
- if (!gpu_channel_ && !pending_request_) {
+ if (!gpu_channel_.get() && !pending_request_.get()) {
// We should only get here if the context was lost.
pending_request_ = EstablishRequest::Create(
cause_for_gpu_launch, gpu_client_id_, gpu_host_id_);
}
if (!callback.is_null()) {
- if (gpu_channel_)
+ if (gpu_channel_.get())
callback.Run();
else
established_callbacks_.push_back(callback);
@@ -396,25 +345,28 @@ void BrowserGpuChannelHostFactory::EstablishGpuChannel(
}
GpuChannelHost* BrowserGpuChannelHostFactory::GetGpuChannel() {
- if (gpu_channel_ && !gpu_channel_->IsLost())
- return gpu_channel_;
+ if (gpu_channel_.get() && !gpu_channel_->IsLost())
+ return gpu_channel_.get();
return NULL;
}
void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
DCHECK(IsMainThread());
- DCHECK(pending_request_);
+ DCHECK(pending_request_.get());
if (pending_request_->channel_handle().name.empty()) {
- DCHECK(!gpu_channel_);
+ DCHECK(!gpu_channel_.get());
} else {
GetContentClient()->SetGpuInfo(pending_request_->gpu_info());
- gpu_channel_ = GpuChannelHost::Create(this,
- pending_request_->gpu_info(),
- pending_request_->channel_handle(),
- shutdown_event_.get());
+ gpu_channel_ =
+ GpuChannelHost::Create(this,
+ pending_request_->gpu_info(),
+ pending_request_->channel_handle(),
+ shutdown_event_.get(),
+ BrowserGpuMemoryBufferManager::current());
}
gpu_host_id_ = pending_request_->gpu_host_id();
+ gpu_memory_buffer_factory_host_->set_gpu_host_id(gpu_host_id_);
pending_request_ = NULL;
for (size_t n = 0; n < established_callbacks_.size(); n++)
@@ -423,20 +375,6 @@ void BrowserGpuChannelHostFactory::GpuChannelEstablished() {
established_callbacks_.clear();
}
-scoped_ptr<gfx::GpuMemoryBuffer>
-BrowserGpuChannelHostFactory::AllocateGpuMemoryBuffer(size_t width,
- size_t height,
- unsigned internalformat,
- unsigned usage) {
- if (!GpuMemoryBufferImpl::IsFormatValid(internalformat) ||
- !GpuMemoryBufferImpl::IsUsageValid(usage))
- return scoped_ptr<gfx::GpuMemoryBuffer>();
-
- return GpuMemoryBufferImpl::Create(gfx::Size(width, height),
- internalformat,
- usage).PassAs<gfx::GpuMemoryBuffer>();
-}
-
// static
void BrowserGpuChannelHostFactory::AddFilterOnIO(
int host_id,
@@ -471,90 +409,4 @@ void BrowserGpuChannelHostFactory::SetHandlerForControlMessages(
filter));
}
-void BrowserGpuChannelHostFactory::CreateGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- unsigned internalformat,
- unsigned usage,
- const CreateGpuMemoryBufferCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- uint32 request_id = next_create_gpu_memory_buffer_request_id_++;
- create_gpu_memory_buffer_requests_[request_id] = callback;
- GetIOLoopProxy()->PostTask(
- FROM_HERE,
- base::Bind(&BrowserGpuChannelHostFactory::CreateGpuMemoryBufferOnIO,
- base::Unretained(this),
- handle,
- size,
- internalformat,
- usage,
- request_id));
-}
-
-void BrowserGpuChannelHostFactory::DestroyGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- int32 sync_point) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- GetIOLoopProxy()->PostTask(
- FROM_HERE,
- base::Bind(&BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO,
- base::Unretained(this),
- handle,
- sync_point));
-}
-
-void BrowserGpuChannelHostFactory::CreateGpuMemoryBufferOnIO(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- unsigned internalformat,
- unsigned usage,
- uint32 request_id) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
- if (!host) {
- GpuMemoryBufferCreatedOnIO(request_id, gfx::GpuMemoryBufferHandle());
- return;
- }
-
- host->CreateGpuMemoryBuffer(
- handle,
- size,
- internalformat,
- usage,
- base::Bind(&BrowserGpuChannelHostFactory::GpuMemoryBufferCreatedOnIO,
- base::Unretained(this),
- request_id));
-}
-
-void BrowserGpuChannelHostFactory::GpuMemoryBufferCreatedOnIO(
- uint32 request_id,
- const gfx::GpuMemoryBufferHandle& handle) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated,
- base::Unretained(this),
- request_id,
- handle));
-}
-
-void BrowserGpuChannelHostFactory::OnGpuMemoryBufferCreated(
- uint32 request_id,
- const gfx::GpuMemoryBufferHandle& handle) {
- CreateGpuMemoryBufferCallbackMap::iterator iter =
- create_gpu_memory_buffer_requests_.find(request_id);
- DCHECK(iter != create_gpu_memory_buffer_requests_.end());
- iter->second.Run(handle);
- create_gpu_memory_buffer_requests_.erase(iter);
-}
-
-void BrowserGpuChannelHostFactory::DestroyGpuMemoryBufferOnIO(
- const gfx::GpuMemoryBufferHandle& handle,
- int32 sync_point) {
- GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
- if (!host)
- return;
-
- host->DestroyGpuMemoryBuffer(handle, sync_point);
-}
-
} // namespace content
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 dc85f67ff45..4bc0b413153 100644
--- a/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/chromium/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -10,49 +10,28 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/gpu/client/gpu_channel_host.h"
-#include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
#include "ipc/message_filter.h"
namespace content {
+class BrowserGpuMemoryBufferManager;
+class GpuMemoryBufferFactoryHostImpl;
class CONTENT_EXPORT BrowserGpuChannelHostFactory
- : public GpuChannelHostFactory,
- public GpuMemoryBufferFactoryHost {
+ : public GpuChannelHostFactory {
public:
static void Initialize(bool establish_gpu_channel);
static void Terminate();
static BrowserGpuChannelHostFactory* instance() { return instance_; }
// GpuChannelHostFactory implementation.
- virtual bool IsMainThread() OVERRIDE;
- virtual base::MessageLoop* GetMainLoop() OVERRIDE;
- virtual scoped_refptr<base::MessageLoopProxy> GetIOLoopProxy() OVERRIDE;
- virtual scoped_ptr<base::SharedMemory> AllocateSharedMemory(
- size_t size) OVERRIDE;
- virtual CreateCommandBufferResult CreateViewCommandBuffer(
+ bool IsMainThread() override;
+ base::MessageLoop* GetMainLoop() override;
+ scoped_refptr<base::MessageLoopProxy> GetIOLoopProxy() override;
+ scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t size) override;
+ CreateCommandBufferResult CreateViewCommandBuffer(
int32 surface_id,
const GPUCreateCommandBufferConfig& init_params,
- int32 route_id) OVERRIDE;
- virtual void CreateImage(
- gfx::PluginWindowHandle window,
- int32 image_id,
- const CreateImageCallback& callback) OVERRIDE;
- virtual void DeleteImage(int32 image_idu, int32 sync_point) OVERRIDE;
- virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
- size_t width,
- size_t height,
- unsigned internalformat,
- unsigned usage) OVERRIDE;
-
- // GpuMemoryBufferFactoryHost implementation.
- virtual void CreateGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- unsigned internalformat,
- unsigned usage,
- const CreateGpuMemoryBufferCallback& callback) OVERRIDE;
- virtual void DestroyGpuMemoryBuffer(const gfx::GpuMemoryBufferHandle& handle,
- int32 sync_point) OVERRIDE;
+ int32 route_id) override;
// Specify a task runner and callback to be used for a set of messages. The
// callback will be set up on the current GpuProcessHost, identified by
@@ -78,7 +57,7 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
class EstablishRequest;
BrowserGpuChannelHostFactory();
- virtual ~BrowserGpuChannelHostFactory();
+ ~BrowserGpuChannelHostFactory() override;
void GpuChannelEstablished();
void CreateViewCommandBufferOnIO(
@@ -87,44 +66,18 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
const GPUCreateCommandBufferConfig& init_params);
static void CommandBufferCreatedOnIO(CreateRequest* request,
CreateCommandBufferResult result);
- void CreateImageOnIO(
- gfx::PluginWindowHandle window,
- int32 image_id,
- const CreateImageCallback& callback);
- static void ImageCreatedOnIO(
- const CreateImageCallback& callback, const gfx::Size size);
- static void OnImageCreated(
- const CreateImageCallback& callback, const gfx::Size size);
- void DeleteImageOnIO(int32 image_id, int32 sync_point);
static void AddFilterOnIO(int gpu_host_id,
scoped_refptr<IPC::MessageFilter> filter);
- void CreateGpuMemoryBufferOnIO(const gfx::GpuMemoryBufferHandle& handle,
- const gfx::Size& size,
- unsigned internalformat,
- unsigned usage,
- uint32 request_id);
- void GpuMemoryBufferCreatedOnIO(
- uint32 request_id,
- const gfx::GpuMemoryBufferHandle& handle);
- void OnGpuMemoryBufferCreated(
- uint32 request_id,
- const gfx::GpuMemoryBufferHandle& handle);
- void DestroyGpuMemoryBufferOnIO(const gfx::GpuMemoryBufferHandle& handle,
- int32 sync_point);
-
const int gpu_client_id_;
scoped_ptr<base::WaitableEvent> shutdown_event_;
scoped_refptr<GpuChannelHost> gpu_channel_;
+ scoped_ptr<GpuMemoryBufferFactoryHostImpl> gpu_memory_buffer_factory_host_;
+ scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
int gpu_host_id_;
scoped_refptr<EstablishRequest> pending_request_;
std::vector<base::Closure> established_callbacks_;
- uint32 next_create_gpu_memory_buffer_request_id_;
- typedef std::map<uint32, CreateGpuMemoryBufferCallback>
- CreateGpuMemoryBufferCallbackMap;
- CreateGpuMemoryBufferCallbackMap create_gpu_memory_buffer_requests_;
-
static BrowserGpuChannelHostFactory* instance_;
DISALLOW_COPY_AND_ASSIGN(BrowserGpuChannelHostFactory);
diff --git a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
new file mode 100644
index 00000000000..b5bcebc05ea
--- /dev/null
+++ b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -0,0 +1,250 @@
+// 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/gpu/browser_gpu_memory_buffer_manager.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+namespace {
+
+BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
+
+// Global atomic to generate gpu memory buffer unique IDs.
+base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id;
+
+} // namespace
+
+struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest {
+ AllocateGpuMemoryBufferRequest(const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id)
+ : event(true, false),
+ size(size),
+ format(format),
+ usage(usage),
+ client_id(client_id) {}
+ ~AllocateGpuMemoryBufferRequest() {}
+ base::WaitableEvent event;
+ gfx::Size size;
+ gfx::GpuMemoryBuffer::Format format;
+ gfx::GpuMemoryBuffer::Usage usage;
+ int client_id;
+ scoped_ptr<gfx::GpuMemoryBuffer> result;
+};
+
+BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(int gpu_client_id)
+ : gpu_client_id_(gpu_client_id) {
+ DCHECK(!g_gpu_memory_buffer_manager);
+ g_gpu_memory_buffer_manager = this;
+}
+
+BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() {
+ g_gpu_memory_buffer_manager = nullptr;
+}
+
+// static
+BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() {
+ return g_gpu_memory_buffer_manager;
+}
+
+scoped_ptr<gfx::GpuMemoryBuffer>
+BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO,
+ base::Unretained(&request)));
+
+ // We're blocking the UI thread, which is generally undesirable.
+ TRACE_EVENT0("browser",
+ "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer");
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ request.event.Wait();
+ return request.result.Pass();
+}
+
+void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ base::ProcessHandle child_process_handle,
+ int child_client_id,
+ const AllocationCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext();
+
+ BufferMap& buffers = clients_[child_client_id];
+ DCHECK(buffers.find(new_id) == buffers.end());
+
+ // Note: Handling of cases where the child process is removed before the
+ // allocation completes is less subtle if we set the buffer type to
+ // EMPTY_BUFFER here and verify that this has not changed when allocation
+ // completes.
+ buffers[new_id] = gfx::EMPTY_BUFFER;
+
+ GpuMemoryBufferImpl::AllocateForChildProcess(
+ new_id,
+ size,
+ format,
+ usage,
+ child_process_handle,
+ child_client_id,
+ base::Bind(&BrowserGpuMemoryBufferManager::
+ GpuMemoryBufferAllocatedForChildProcess,
+ base::Unretained(this),
+ child_process_handle,
+ child_client_id,
+ callback));
+}
+
+gfx::GpuMemoryBuffer*
+BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
+ ClientBuffer buffer) {
+ return GpuMemoryBufferImpl::FromClientBuffer(buffer);
+}
+
+void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint(
+ gfx::GpuMemoryBuffer* buffer,
+ uint32 sync_point) {
+ static_cast<GpuMemoryBufferImpl*>(buffer)
+ ->set_destruction_sync_point(sync_point);
+}
+
+void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ base::ProcessHandle child_process_handle,
+ int child_client_id,
+ uint32 sync_point) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(clients_.find(child_client_id) != clients_.end());
+
+ BufferMap& buffers = clients_[child_client_id];
+
+ BufferMap::iterator buffer_it = buffers.find(id);
+ if (buffer_it == buffers.end()) {
+ LOG(ERROR) << "Invalid GpuMemoryBuffer ID for child process.";
+ return;
+ }
+
+ // This can happen if a child process managed to trigger a call to this while
+ // a buffer is in the process of being allocated.
+ if (buffer_it->second == gfx::EMPTY_BUFFER) {
+ LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
+ return;
+ }
+
+ GpuMemoryBufferImpl::DeletedByChildProcess(
+ buffer_it->second, id, child_process_handle, child_client_id, sync_point);
+
+ buffers.erase(buffer_it);
+}
+
+void BrowserGpuMemoryBufferManager::ProcessRemoved(
+ base::ProcessHandle process_handle,
+ int client_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ ClientMap::iterator client_it = clients_.find(client_id);
+ if (client_it == clients_.end())
+ return;
+
+ for (auto &buffer_it : client_it->second) {
+ // This might happen if buffer is currenlty in the process of being
+ // allocated. The buffer will in that case be cleaned up when allocation
+ // completes.
+ if (buffer_it.second == gfx::EMPTY_BUFFER)
+ continue;
+
+ GpuMemoryBufferImpl::DeletedByChildProcess(buffer_it.second,
+ buffer_it.first,
+ process_handle,
+ client_id,
+ 0);
+ }
+
+ clients_.erase(client_it);
+}
+
+void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
+ base::ProcessHandle child_process_handle,
+ int child_client_id,
+ const AllocationCallback& callback,
+ const gfx::GpuMemoryBufferHandle& handle) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ ClientMap::iterator client_it = clients_.find(child_client_id);
+
+ // This can happen if the child process is removed while the buffer is being
+ // allocated.
+ if (client_it == clients_.end()) {
+ if (!handle.is_null()) {
+ GpuMemoryBufferImpl::DeletedByChildProcess(handle.type,
+ handle.id,
+ child_process_handle,
+ child_client_id,
+ 0);
+ }
+ callback.Run(gfx::GpuMemoryBufferHandle());
+ return;
+ }
+
+ BufferMap& buffers = client_it->second;
+
+ BufferMap::iterator buffer_it = buffers.find(handle.id);
+ DCHECK(buffer_it != buffers.end());
+ DCHECK_EQ(buffer_it->second, gfx::EMPTY_BUFFER);
+
+ if (handle.is_null()) {
+ buffers.erase(buffer_it);
+ callback.Run(gfx::GpuMemoryBufferHandle());
+ return;
+ }
+
+ // Store the type for this buffer so it can be cleaned up if the child
+ // process is removed.
+ buffer_it->second = handle.type;
+
+ callback.Run(handle);
+}
+
+// static
+void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
+ AllocateGpuMemoryBufferRequest* request) {
+ GpuMemoryBufferImpl::Create(
+ g_next_gpu_memory_buffer_id.GetNext(),
+ request->size,
+ request->format,
+ request->usage,
+ request->client_id,
+ base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferCreatedOnIO,
+ base::Unretained(request)));
+}
+
+// static
+void BrowserGpuMemoryBufferManager::GpuMemoryBufferCreatedOnIO(
+ AllocateGpuMemoryBufferRequest* request,
+ scoped_ptr<GpuMemoryBufferImpl> buffer) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ request->result = buffer.Pass();
+ request->event.Signal();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
new file mode 100644
index 00000000000..84ad9e5c0f4
--- /dev/null
+++ b/chromium/content/browser/gpu/browser_gpu_memory_buffer_manager.h
@@ -0,0 +1,77 @@
+// 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_GPU_BROWSER_GPU_MEMORY_BUFFER_MANAGER_H_
+#define CONTENT_BROWSER_GPU_BROWSER_GPU_MEMORY_BUFFER_MANAGER_H_
+
+#include "base/callback.h"
+#include "content/common/content_export.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+
+namespace content {
+class GpuMemoryBufferImpl;
+
+class CONTENT_EXPORT BrowserGpuMemoryBufferManager
+ : public gpu::GpuMemoryBufferManager {
+ public:
+ typedef base::Callback<void(const gfx::GpuMemoryBufferHandle& handle)>
+ AllocationCallback;
+
+ explicit BrowserGpuMemoryBufferManager(int gpu_client_id);
+ ~BrowserGpuMemoryBufferManager() override;
+
+ static BrowserGpuMemoryBufferManager* current();
+
+ // Overridden from gpu::GpuMemoryBufferManager:
+ scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage) override;
+ gfx::GpuMemoryBuffer* GpuMemoryBufferFromClientBuffer(
+ ClientBuffer buffer) override;
+ void SetDestructionSyncPoint(gfx::GpuMemoryBuffer* buffer,
+ uint32 sync_point) override;
+
+ void AllocateGpuMemoryBufferForChildProcess(
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ base::ProcessHandle child_process_handle,
+ int child_client_id,
+ const AllocationCallback& callback);
+ void ChildProcessDeletedGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ base::ProcessHandle child_process_handle,
+ int child_client_id,
+ uint32 sync_point);
+ void ProcessRemoved(base::ProcessHandle process_handle, int client_id);
+
+ private:
+ struct AllocateGpuMemoryBufferRequest;
+
+ void GpuMemoryBufferAllocatedForChildProcess(
+ base::ProcessHandle child_process_handle,
+ int child_client_id,
+ const AllocationCallback& callback,
+ const gfx::GpuMemoryBufferHandle& handle);
+
+ static void AllocateGpuMemoryBufferOnIO(
+ AllocateGpuMemoryBufferRequest* request);
+ static void GpuMemoryBufferCreatedOnIO(
+ AllocateGpuMemoryBufferRequest* request,
+ scoped_ptr<GpuMemoryBufferImpl> buffer);
+
+ int gpu_client_id_;
+
+ typedef base::hash_map<gfx::GpuMemoryBufferId, gfx::GpuMemoryBufferType>
+ BufferMap;
+ typedef base::hash_map<int, BufferMap> ClientMap;
+ ClientMap clients_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserGpuMemoryBufferManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GPU_BROWSER_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/chromium/content/browser/gpu/compositor_util.cc b/chromium/content/browser/gpu/compositor_util.cc
index 83ab50cbb29..77cf2bc5a83 100644
--- a/chromium/content/browser/gpu/compositor_util.cc
+++ b/chromium/content/browser/gpu/compositor_util.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
+#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
@@ -19,17 +20,6 @@ namespace {
static bool IsGpuRasterizationBlacklisted() {
GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
- bool field_trial_enabled =
- (base::FieldTrialList::FindFullName(
- "GpuRasterizationExpandedDeviceWhitelist") == "Enabled");
-
- if (field_trial_enabled) {
- return manager->IsFeatureBlacklisted(
- gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION) &&
- manager->IsFeatureBlacklisted(
- gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION_FIELD_TRIAL);
- }
-
return manager->IsFeatureBlacklisted(
gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION);
}
@@ -38,6 +28,10 @@ const char* kGpuCompositingFeatureName = "gpu_compositing";
const char* kWebGLFeatureName = "webgl";
const char* kRasterizationFeatureName = "rasterization";
const char* kThreadedRasterizationFeatureName = "threaded_rasterization";
+const char* kMultipleRasterThreadsFeatureName = "multiple_raster_threads";
+
+const int kMinRasterThreads = 1;
+const int kMaxRasterThreads = 64;
struct GpuFeatureInfo {
std::string name;
@@ -48,7 +42,8 @@ struct GpuFeatureInfo {
};
const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
const GpuFeatureInfo kGpuFeatureInfo[] = {
@@ -66,7 +61,7 @@ const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
{
kGpuCompositingFeatureName,
manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING),
- false,
+ command_line.HasSwitch(switches::kDisableGpuCompositing),
"Gpu compositing has been disabled, either via about:flags or"
" command line. The browser will fall back to software compositing"
" and hardware acceleration will be unavailable.",
@@ -152,8 +147,14 @@ const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
"Threaded rasterization has not been enabled or"
" is not supported by the current system.",
false
- }
-
+ },
+ {
+ kMultipleRasterThreadsFeatureName,
+ false,
+ NumberOfRendererRasterThreads() == 1,
+ "Raster is using a single thread.",
+ false
+ },
};
DCHECK(index < arraysize(kGpuFeatureInfo));
*eof = (index == arraysize(kGpuFeatureInfo) - 1);
@@ -163,7 +164,8 @@ const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
} // namespace
bool IsPinchVirtualViewportEnabled() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
// Command line switches take precedence over platform default.
if (command_line.HasSwitch(cc::switches::kDisablePinchVirtualViewport))
@@ -171,25 +173,7 @@ bool IsPinchVirtualViewportEnabled() {
if (command_line.HasSwitch(cc::switches::kEnablePinchVirtualViewport))
return true;
-#if defined(OS_CHROMEOS)
- return true;
-#else
- return false;
-#endif
-}
-
-bool IsThreadedCompositingEnabled() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- // Command line switches take precedence over blacklist.
- if (command_line.HasSwitch(switches::kDisableThreadedCompositing))
- return false;
- if (command_line.HasSwitch(switches::kEnableThreadedCompositing))
- return true;
-
-#if defined(USE_AURA) || defined(OS_MACOSX)
- // We always want threaded compositing on Aura and Mac (the fallback is a
- // threaded software compositor).
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
return true;
#else
return false;
@@ -197,48 +181,66 @@ bool IsThreadedCompositingEnabled() {
}
bool IsDelegatedRendererEnabled() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
bool enabled = false;
-#if defined(USE_AURA)
- // Enable on Aura.
+#if defined(USE_AURA) || defined(OS_MACOSX)
+ // Enable on Aura and Mac.
enabled = true;
#endif
// Flags override.
enabled |= command_line.HasSwitch(switches::kEnableDelegatedRenderer);
enabled &= !command_line.HasSwitch(switches::kDisableDelegatedRenderer);
-
- // Needs compositing, and thread.
- if (enabled && !IsThreadedCompositingEnabled()) {
- enabled = false;
- LOG(ERROR) << "Disabling delegated-rendering because it needs "
- << "force-compositing-mode and threaded-compositing.";
- }
-
return enabled;
}
bool IsImplSidePaintingEnabled() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kDisableImplSidePainting))
- return false;
- else if (command_line.HasSwitch(switches::kEnableImplSidePainting))
- return true;
- else if (command_line.HasSwitch(
- switches::kEnableBleedingEdgeRenderingFastPaths))
+ if (command_line.HasSwitch(switches::kEnableImplSidePainting))
return true;
+ else if (command_line.HasSwitch(switches::kDisableImplSidePainting))
+ return false;
-#if defined(OS_MACOSX) || defined(OS_WIN)
- return false;
-#else
- return IsThreadedCompositingEnabled();
-#endif
+ return true;
+}
+
+int NumberOfRendererRasterThreads() {
+ int num_raster_threads = 1;
+
+ int force_num_raster_threads = ForceNumberOfRendererRasterThreads();
+ if (force_num_raster_threads)
+ num_raster_threads = force_num_raster_threads;
+
+ return num_raster_threads;
+}
+
+int ForceNumberOfRendererRasterThreads() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ if (!command_line.HasSwitch(switches::kNumRasterThreads))
+ return 0;
+ std::string string_value =
+ command_line.GetSwitchValueASCII(switches::kNumRasterThreads);
+ int force_num_raster_threads = 0;
+ if (base::StringToInt(string_value, &force_num_raster_threads) &&
+ force_num_raster_threads >= kMinRasterThreads &&
+ force_num_raster_threads <= kMaxRasterThreads) {
+ return force_num_raster_threads;
+ } else {
+ LOG(WARNING) << "Failed to parse switch " <<
+ switches::kNumRasterThreads << ": " << string_value;
+ return 0;
+ }
}
bool IsGpuRasterizationEnabled() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (!IsImplSidePaintingEnabled())
return false;
@@ -256,7 +258,8 @@ bool IsGpuRasterizationEnabled() {
}
bool IsForceGpuRasterizationEnabled() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (!IsImplSidePaintingEnabled())
return false;
@@ -264,6 +267,13 @@ bool IsForceGpuRasterizationEnabled() {
return command_line.HasSwitch(switches::kForceGpuRasterization);
}
+bool UseSurfacesEnabled() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+
+ return command_line.HasSwitch(switches::kUseSurfaces);
+}
+
base::Value* GetFeatureStatus() {
GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
std::string gpu_access_blocked_reason;
@@ -287,9 +297,9 @@ base::Value* GetFeatureStatus() {
} else if (gpu_feature_info.blocked ||
gpu_access_blocked) {
status = "unavailable";
- if (gpu_feature_info.fallback_to_software) {
+ if (gpu_feature_info.fallback_to_software)
status += "_software";
- } else
+ else
status += "_off";
} else {
status = "enabled";
@@ -300,13 +310,14 @@ base::Value* GetFeatureStatus() {
if (IsForceGpuRasterizationEnabled())
status += "_force";
}
- if (gpu_feature_info.name == kThreadedRasterizationFeatureName)
+ if (gpu_feature_info.name == kMultipleRasterThreadsFeatureName) {
+ if (ForceNumberOfRendererRasterThreads() > 0)
+ status += "_force";
+ }
+ if (gpu_feature_info.name == kThreadedRasterizationFeatureName ||
+ gpu_feature_info.name == kMultipleRasterThreadsFeatureName)
status += "_on";
}
- if (gpu_feature_info.name == kGpuCompositingFeatureName) {
- if (IsThreadedCompositingEnabled())
- status += "_threaded";
- }
if (gpu_feature_info.name == kWebGLFeatureName &&
(gpu_feature_info.blocked || gpu_access_blocked) &&
manager->ShouldUseSwiftShader()) {
diff --git a/chromium/content/browser/gpu/compositor_util.h b/chromium/content/browser/gpu/compositor_util.h
index 72a3ac0d42d..b26bb94968a 100644
--- a/chromium/content/browser/gpu/compositor_util.h
+++ b/chromium/content/browser/gpu/compositor_util.h
@@ -17,9 +17,6 @@ namespace content {
// flags, or platform default).
CONTENT_EXPORT bool IsPinchVirtualViewportEnabled();
-// Returns true if the threaded compositor is on (via flags or field trial).
-CONTENT_EXPORT bool IsThreadedCompositingEnabled();
-
// Returns true if delegated-renderer is on (via flags, or platform default).
CONTENT_EXPORT bool IsDelegatedRendererEnabled();
@@ -33,6 +30,16 @@ CONTENT_EXPORT bool IsGpuRasterizationEnabled();
// Returns true if force-gpu-rasterization is on (via flags) for the renderer.
CONTENT_EXPORT bool IsForceGpuRasterizationEnabled();
+// Returns the number of raster threads to use for compositing.
+CONTENT_EXPORT int NumberOfRendererRasterThreads();
+
+// Returns the number of raster threads to use for compositing that are forced
+// by the command line.
+CONTENT_EXPORT int ForceNumberOfRendererRasterThreads();
+
+// Returns true if using cc Surfaces is allowed.
+CONTENT_EXPORT bool UseSurfacesEnabled();
+
CONTENT_EXPORT base::Value* GetFeatureStatus();
CONTENT_EXPORT base::Value* GetProblems();
CONTENT_EXPORT base::Value* GetDriverBugWorkarounds();
diff --git a/chromium/content/browser/gpu/compositor_util_browsertest.cc b/chromium/content/browser/gpu/compositor_util_browsertest.cc
index 1f3b9f3f576..550d7773c0a 100644
--- a/chromium/content/browser/gpu/compositor_util_browsertest.cc
+++ b/chromium/content/browser/gpu/compositor_util_browsertest.cc
@@ -15,37 +15,19 @@ namespace content {
typedef ContentBrowserTest CompositorUtilTest;
-// Test that threaded compositing and FCM are in the expected mode on the bots
-// for all platforms.
+// Test that compositing is in the expected mode on the bots for all platforms.
IN_PROC_BROWSER_TEST_F(CompositorUtilTest, CompositingModeAsExpected) {
enum CompositingMode {
- DISABLED,
- ENABLED,
- THREADED, // Implies FCM
- DELEGATED, // Implies threaded
- } expected_mode = DISABLED;
-#if defined(USE_AURA)
- expected_mode = DELEGATED;
-#elif defined(OS_ANDROID)
+ DIRECT,
+ DELEGATED,
+ } expected_mode = DIRECT;
+#if defined(USE_AURA) || defined(OS_ANDROID)
expected_mode = DELEGATED;
#elif defined(OS_MACOSX)
- expected_mode = THREADED;
- // Lion and SnowLeopard have compositing blacklisted when using the Apple
- // software renderer, so results will vary depending if this test is being
- // run in a VM versus actual hardware.
- // http://crbug.com/230931
- if (base::mac::IsOSLionOrEarlier())
- return;
-#elif defined(OS_WIN)
- if (base::win::GetVersion() >= base::win::VERSION_VISTA)
- expected_mode = THREADED;
+ expected_mode = DELEGATED;
#endif
- EXPECT_EQ(expected_mode == THREADED ||
- expected_mode == DELEGATED,
- IsThreadedCompositingEnabled());
- EXPECT_EQ(expected_mode == DELEGATED,
- IsDelegatedRendererEnabled());
+ EXPECT_EQ(expected_mode == DELEGATED, IsDelegatedRendererEnabled());
}
}
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl.cc b/chromium/content/browser/gpu/gpu_data_manager_impl.cc
index 93d15c71108..3e24bb5be2d 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl.cc
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl.cc
@@ -55,6 +55,11 @@ void GpuDataManagerImpl::RequestCompleteGpuInfoIfNeeded() {
private_->RequestCompleteGpuInfoIfNeeded();
}
+bool GpuDataManagerImpl::IsEssentialGpuInfoAvailable() const {
+ base::AutoLock auto_lock(lock_);
+ return private_->IsEssentialGpuInfoAvailable();
+}
+
bool GpuDataManagerImpl::IsCompleteGpuInfoAvailable() const {
base::AutoLock auto_lock(lock_);
return private_->IsCompleteGpuInfoAvailable();
@@ -76,6 +81,11 @@ 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_);
diff --git a/chromium/content/browser/gpu/gpu_data_manager_impl.h b/chromium/content/browser/gpu/gpu_data_manager_impl.h
index 5a783e46c75..981ad7a85b6 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl.h
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl.h
@@ -23,7 +23,6 @@
#include "gpu/config/gpu_info.h"
class GURL;
-struct WebPreferences;
namespace base {
class CommandLine;
@@ -32,6 +31,7 @@ class CommandLine;
namespace content {
class GpuDataManagerImplPrivate;
+struct WebPreferences;
class CONTENT_EXPORT GpuDataManagerImpl
: public NON_EXPORTED_BASE(GpuDataManager) {
@@ -58,31 +58,32 @@ class CONTENT_EXPORT GpuDataManagerImpl
static GpuDataManagerImpl* GetInstance();
// GpuDataManager implementation.
- virtual void InitializeForTesting(
- const std::string& gpu_blacklist_json,
- const gpu::GPUInfo& gpu_info) OVERRIDE;
- virtual bool IsFeatureBlacklisted(int feature) const OVERRIDE;
- virtual gpu::GPUInfo GetGPUInfo() const OVERRIDE;
- virtual void GetGpuProcessHandles(
- const GetGpuProcessHandlesCallback& callback) const OVERRIDE;
- virtual bool GpuAccessAllowed(std::string* reason) const OVERRIDE;
- virtual void RequestCompleteGpuInfoIfNeeded() OVERRIDE;
- virtual bool IsCompleteGpuInfoAvailable() const OVERRIDE;
- virtual void RequestVideoMemoryUsageStatsUpdate() const OVERRIDE;
- virtual bool ShouldUseSwiftShader() const OVERRIDE;
- virtual void RegisterSwiftShaderPath(const base::FilePath& path) OVERRIDE;
- virtual void AddObserver(GpuDataManagerObserver* observer) OVERRIDE;
- virtual void RemoveObserver(GpuDataManagerObserver* observer) OVERRIDE;
- virtual void UnblockDomainFrom3DAPIs(const GURL& url) OVERRIDE;
- virtual void DisableGpuWatchdog() OVERRIDE;
- virtual void SetGLStrings(const std::string& gl_vendor,
- const std::string& gl_renderer,
- const std::string& gl_version) OVERRIDE;
- virtual void GetGLStrings(std::string* gl_vendor,
- std::string* gl_renderer,
- std::string* gl_version) OVERRIDE;
- virtual void DisableHardwareAcceleration() OVERRIDE;
- virtual bool CanUseGpuBrowserCompositor() const OVERRIDE;
+ void InitializeForTesting(const std::string& gpu_blacklist_json,
+ const gpu::GPUInfo& gpu_info) override;
+ bool IsFeatureBlacklisted(int feature) const override;
+ gpu::GPUInfo GetGPUInfo() const override;
+ void GetGpuProcessHandles(
+ const GetGpuProcessHandlesCallback& callback) const override;
+ bool GpuAccessAllowed(std::string* reason) const override;
+ void RequestCompleteGpuInfoIfNeeded() override;
+ bool IsEssentialGpuInfoAvailable() const override;
+ bool IsCompleteGpuInfoAvailable() const override;
+ void RequestVideoMemoryUsageStatsUpdate() const override;
+ bool ShouldUseSwiftShader() const override;
+ void RegisterSwiftShaderPath(const base::FilePath& path) override;
+ bool ShouldUseWarp() const override;
+ void AddObserver(GpuDataManagerObserver* observer) override;
+ void RemoveObserver(GpuDataManagerObserver* observer) override;
+ void UnblockDomainFrom3DAPIs(const GURL& url) override;
+ void DisableGpuWatchdog() override;
+ void SetGLStrings(const std::string& gl_vendor,
+ const std::string& gl_renderer,
+ const std::string& gl_version) override;
+ void GetGLStrings(std::string* gl_vendor,
+ std::string* gl_renderer,
+ std::string* gl_version) override;
+ void DisableHardwareAcceleration() override;
+ bool CanUseGpuBrowserCompositor() const override;
// This collects preliminary GPU info, load GpuBlacklist, and compute the
// preliminary blacklisted features; it should only be called at browser
@@ -205,7 +206,7 @@ class CONTENT_EXPORT GpuDataManagerImpl
};
GpuDataManagerImpl();
- virtual ~GpuDataManagerImpl();
+ ~GpuDataManagerImpl() override;
mutable base::Lock lock_;
scoped_ptr<GpuDataManagerImplPrivate> private_;
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 2c5b91e0142..f71a62c8652 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -23,6 +23,7 @@
#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_switches.h"
#include "gpu/config/gpu_control_list_jsons.h"
#include "gpu/config/gpu_driver_bug_workaround_type.h"
@@ -33,7 +34,6 @@
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gpu_switching_manager.h"
-#include "webkit/common/webpreferences.h"
#if defined(OS_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
@@ -113,7 +113,8 @@ void UpdateStats(const gpu::GPUInfo& gpu_info,
return;
}
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
bool disabled = false;
// Use entry 0 to capture the total number of times that data
@@ -138,9 +139,9 @@ void UpdateStats(const gpu::GPUInfo& gpu_info,
std::vector<uint32> flag_disabled_entries;
disabled = true;
blacklist->GetDecisionEntries(&flag_disabled_entries, disabled);
- for (size_t i = 0; i < flag_disabled_entries.size(); ++i) {
+ for (uint32 disabled_entry : flag_disabled_entries) {
UMA_HISTOGRAM_ENUMERATION("GPU.BlacklistTestResultsPerDisabledEntry",
- flag_disabled_entries[i], max_entry_id + 1);
+ disabled_entry, max_entry_id + 1);
}
const gpu::GpuFeatureType kGpuFeatures[] = {
@@ -225,7 +226,7 @@ void DisplayReconfigCallback(CGDirectDisplayID display,
bool gpu_changed = false;
if (flags & kCGDisplayAddFlag) {
uint32 vendor_id, device_id;
- if (gpu::CollectGpuID(&vendor_id, &device_id) == gpu::kGpuIDSuccess) {
+ if (gpu::CollectGpuID(&vendor_id, &device_id) == gpu::kCollectInfoSuccess) {
gpu_changed = manager->UpdateActiveGpu(vendor_id, device_id);
}
}
@@ -235,81 +236,6 @@ void DisplayReconfigCallback(CGDirectDisplayID display,
}
#endif // OS_MACOSX
-#if defined(OS_ANDROID)
-void ApplyAndroidWorkarounds(const gpu::GPUInfo& gpu_info,
- CommandLine* command_line,
- std::set<int>* workarounds) {
- std::string vendor(StringToLowerASCII(gpu_info.gl_vendor));
- std::string renderer(StringToLowerASCII(gpu_info.gl_renderer));
- std::string version(StringToLowerASCII(gpu_info.gl_version));
-
- bool is_img =
- gpu_info.gl_vendor.find("Imagination") != std::string::npos;
-
- gfx::DeviceDisplayInfo info;
- int default_tile_size = 256;
-
- // TODO(epenner): Now that this is somewhat generic, maybe we can
- // unify this for all platforms (http://crbug.com/159524)
-
- bool real_size_supported = true;
- int display_width = info.GetPhysicalDisplayWidth();
- int display_height = info.GetPhysicalDisplayHeight();
- if (display_width == 0 || display_height == 0) {
- real_size_supported = false;
- display_width = info.GetDisplayWidth();
- display_height = info.GetDisplayHeight();
- }
-
- int portrait_width = std::min(display_width, display_height);
- int landscape_width = std::max(display_width, display_height);
-
- if (real_size_supported) {
- // Maximum HD dimensions should be 768x1280
- // Maximum FHD dimensions should be 1200x1920
- if (portrait_width > 768 || landscape_width > 1280)
- default_tile_size = 384;
- if (portrait_width > 1200 || landscape_width > 1920)
- default_tile_size = 512;
-
- // Adjust for some resolutions that barely straddle an extra
- // tile when in portrait mode. This helps worst case scroll/raster
- // by not needing a full extra tile for each row.
- if (default_tile_size == 256 && portrait_width == 768)
- default_tile_size += 32;
- if (default_tile_size == 384 && portrait_width == 1200)
- default_tile_size += 32;
- } else {
- // We don't know the exact resolution due to screen controls etc.
- // So this just estimates the values above using tile counts.
- int numTiles = (display_width * display_height) / (256 * 256);
- if (numTiles > 16)
- default_tile_size = 384;
- if (numTiles >= 40)
- default_tile_size = 512;
- }
-
- // IMG: Fast async texture uploads only work with non-power-of-two,
- // but still multiple-of-eight sizes.
- // http://crbug.com/168099
- if (is_img)
- default_tile_size -= 8;
-
- // Set the command line if it isn't already set and we changed
- // the default tile size.
- if (default_tile_size != 256 &&
- !command_line->HasSwitch(switches::kDefaultTileWidth) &&
- !command_line->HasSwitch(switches::kDefaultTileHeight)) {
- std::stringstream size;
- size << default_tile_size;
- command_line->AppendSwitchASCII(
- switches::kDefaultTileWidth, size.str());
- command_line->AppendSwitchASCII(
- switches::kDefaultTileHeight, size.str());
- }
-}
-#endif // OS_ANDROID
-
// Block all domains' use of 3D APIs for this many milliseconds if
// approaching a threshold where system stability might be compromised.
const int64 kBlockAllDomainsMs = 10000;
@@ -340,12 +266,12 @@ void GpuDataManagerImplPrivate::InitializeForTesting(
bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
#if defined(OS_CHROMEOS)
if (feature == gpu::GPU_FEATURE_TYPE_PANEL_FITTING &&
- CommandLine::ForCurrentProcess()->HasSwitch(
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisablePanelFitting)) {
return true;
}
#endif // OS_CHROMEOS
- if (use_swiftshader_) {
+ if (use_swiftshader_ || ShouldUseWarp()) {
// 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)
@@ -361,7 +287,7 @@ bool GpuDataManagerImplPrivate::IsDriverBugWorkaroundActive(int feature) const {
}
size_t GpuDataManagerImplPrivate::GetBlacklistedFeatureCount() const {
- if (use_swiftshader_)
+ if (use_swiftshader_ || ShouldUseWarp())
return 1;
return blacklisted_features_.size();
}
@@ -385,7 +311,7 @@ void GpuDataManagerImplPrivate::GetGpuProcessHandles(
bool GpuDataManagerImplPrivate::GpuAccessAllowed(
std::string* reason) const {
- if (use_swiftshader_)
+ if (use_swiftshader_ || ShouldUseWarp())
return true;
if (!gpu_process_accessible_) {
@@ -398,7 +324,7 @@ bool GpuDataManagerImplPrivate::GpuAccessAllowed(
if (card_blacklisted_) {
if (reason) {
*reason = "GPU access is disabled ";
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableGpu))
*reason += "through commandline switch --disable-gpu.";
else
@@ -437,7 +363,7 @@ bool GpuDataManagerImplPrivate::GpuAccessAllowed(
}
void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
- if (complete_gpu_info_already_requested_ || gpu_info_.finalized)
+ if (complete_gpu_info_already_requested_ || IsCompleteGpuInfoAvailable())
return;
complete_gpu_info_already_requested_ = true;
@@ -451,8 +377,20 @@ void GpuDataManagerImplPrivate::RequestCompleteGpuInfoIfNeeded() {
new GpuMsg_CollectGraphicsInfo());
}
+bool GpuDataManagerImplPrivate::IsEssentialGpuInfoAvailable() const {
+ if (gpu_info_.basic_info_state == gpu::kCollectInfoNone ||
+ gpu_info_.context_info_state == gpu::kCollectInfoNone) {
+ return false;
+ }
+ return true;
+}
+
bool GpuDataManagerImplPrivate::IsCompleteGpuInfoAvailable() const {
- return gpu_info_.finalized;
+#if defined(OS_WIN)
+ if (gpu_info_.dx_diagnostics_info_state == gpu::kCollectInfoNone)
+ return false;
+#endif
+ return IsEssentialGpuInfoAvailable();
}
void GpuDataManagerImplPrivate::RequestVideoMemoryUsageStatsUpdate() const {
@@ -472,6 +410,11 @@ void GpuDataManagerImplPrivate::RegisterSwiftShaderPath(
EnableSwiftShaderIfNecessary();
}
+bool GpuDataManagerImplPrivate::ShouldUseWarp() const {
+ return use_warp_ ||
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp);
+}
+
void GpuDataManagerImplPrivate::AddObserver(GpuDataManagerObserver* observer) {
GpuDataManagerImpl::UnlockedSession session(owner_);
observer_list_->AddObserver(observer);
@@ -552,7 +495,8 @@ void GpuDataManagerImplPrivate::Initialize() {
return;
}
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kSkipGpuDataLoading))
return;
@@ -576,9 +520,13 @@ void GpuDataManagerImplPrivate::Initialize() {
gpu::CollectBasicGraphicsInfo(&gpu_info);
}
#if defined(ARCH_CPU_X86_FAMILY)
- if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id)
- gpu_info.finalized = true;
-#endif
+ if (!gpu_info.gpu.vendor_id || !gpu_info.gpu.device_id) {
+ gpu_info.context_info_state = gpu::kCollectInfoNonFatalFailure;
+#if defined(OS_WIN)
+ gpu_info.dx_diagnostics_info_state = gpu::kCollectInfoNonFatalFailure;
+#endif // OS_WIN
+ }
+#endif // ARCH_CPU_X86_FAMILY
std::string gpu_blacklist_string;
std::string gpu_driver_bug_list_string;
@@ -610,7 +558,7 @@ void GpuDataManagerImplPrivate::UpdateGpuInfoHelper() {
gpu::GpuControlList::kOsAny, std::string(), gpu_info_);
}
gpu::GpuDriverBugList::AppendWorkaroundsFromCommandLine(
- &gpu_driver_bugs_, *CommandLine::ForCurrentProcess());
+ &gpu_driver_bugs_, *base::CommandLine::ForCurrentProcess());
// We have to update GpuFeatureType before notify all the observers.
NotifyGpuInfoUpdate();
@@ -618,12 +566,12 @@ 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_)
+ if (use_swiftshader_ || ShouldUseWarp())
return;
gpu::MergeGPUInfo(&gpu_info_, gpu_info);
- complete_gpu_info_already_requested_ =
- complete_gpu_info_already_requested_ || gpu_info_.finalized;
+ if (IsCompleteGpuInfoAvailable())
+ complete_gpu_info_already_requested_ = true;
UpdateGpuInfoHelper();
}
@@ -636,7 +584,7 @@ void GpuDataManagerImplPrivate::UpdateVideoMemoryUsageStats(
}
void GpuDataManagerImplPrivate::AppendRendererCommandLine(
- CommandLine* command_line) const {
+ base::CommandLine* command_line) const {
DCHECK(command_line);
if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
@@ -655,13 +603,14 @@ void GpuDataManagerImplPrivate::AppendRendererCommandLine(
}
void GpuDataManagerImplPrivate::AppendGpuCommandLine(
- CommandLine* command_line) const {
+ base::CommandLine* command_line) const {
DCHECK(command_line);
std::string use_gl =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kUseGL);
base::FilePath swiftshader_path =
- CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kSwiftShaderPath);
if (gpu_driver_bugs_.find(gpu::DISABLE_D3D11) != gpu_driver_bugs_.end())
command_line->AppendSwitch(switches::kDisableD3D11);
@@ -717,10 +666,13 @@ void GpuDataManagerImplPrivate::AppendGpuCommandLine(
gpu_info_.driver_vendor);
command_line->AppendSwitchASCII(switches::kGpuDriverVersion,
gpu_info_.driver_version);
+
+ if (ShouldUseWarp())
+ command_line->AppendSwitch(switches::kUseWarp);
}
void GpuDataManagerImplPrivate::AppendPluginCommandLine(
- CommandLine* command_line) const {
+ base::CommandLine* command_line) const {
DCHECK(command_line);
#if defined(OS_MACOSX)
@@ -767,7 +719,7 @@ void GpuDataManagerImplPrivate::UpdateRendererWebPrefs(
#endif
if (!IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableAcceleratedVideoDecode)) {
prefs->pepper_accelerated_video_decode_enabled = true;
}
@@ -779,6 +731,7 @@ void GpuDataManagerImplPrivate::DisableHardwareAcceleration() {
for (int i = 0; i < gpu::NUMBER_OF_GPU_FEATURE_TYPES; ++i)
blacklisted_features_.insert(i);
+ EnableWarpIfNecessary();
EnableSwiftShaderIfNecessary();
NotifyGpuInfoUpdate();
}
@@ -832,6 +785,7 @@ void GpuDataManagerImplPrivate::ProcessCrashed(
return;
}
{
+ gpu_info_.process_crash_count = GpuProcessHost::gpu_crash_count();
GpuDataManagerImpl::UnlockedSession session(owner_);
observer_list_->Notify(
&GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
@@ -852,7 +806,13 @@ base::ListValue* GpuDataManagerImplPrivate::GetLogMessages() const {
void GpuDataManagerImplPrivate::HandleGpuSwitch() {
GpuDataManagerImpl::UnlockedSession session(owner_);
- observer_list_->Notify(&GpuDataManagerObserver::OnGpuSwitching);
+ // 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);
}
bool GpuDataManagerImplPrivate::UpdateActiveGpu(
@@ -884,6 +844,11 @@ bool GpuDataManagerImplPrivate::UpdateActiveGpu(
}
bool GpuDataManagerImplPrivate::CanUseGpuBrowserCompositor() const {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuCompositing))
+ return false;
+ if (ShouldUseWarp())
+ return true;
if (ShouldUseSwiftShader())
return false;
if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
@@ -930,6 +895,7 @@ GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
: 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),
@@ -939,7 +905,8 @@ GpuDataManagerImplPrivate::GpuDataManagerImplPrivate(
gpu_process_accessible_(true),
finalized_(false) {
DCHECK(owner_);
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableGpu))
DisableHardwareAcceleration();
@@ -965,7 +932,7 @@ void GpuDataManagerImplPrivate::InitializeImpl(
const std::string& gpu_driver_bug_list_json,
const gpu::GPUInfo& gpu_info) {
const bool log_gpu_control_list_decisions =
- CommandLine::ForCurrentProcess()->HasSwitch(
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kLogGpuControlListDecisions);
if (!gpu_blacklist_json.empty()) {
@@ -989,11 +956,6 @@ void GpuDataManagerImplPrivate::InitializeImpl(
UpdateGpuInfo(gpu_info);
UpdateGpuSwitchingManager(gpu_info);
UpdatePreliminaryBlacklistedFeatures();
-
-#if defined(OS_ANDROID)
- ApplyAndroidWorkarounds(
- gpu_info, CommandLine::ForCurrentProcess(), &gpu_driver_bugs_);
-#endif // OS_ANDROID
}
void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
@@ -1007,6 +969,7 @@ void GpuDataManagerImplPrivate::UpdateBlacklistedFeatures(
blacklisted_features_.insert(gpu::GPU_FEATURE_TYPE_WEBGL);
}
+ EnableWarpIfNecessary();
EnableSwiftShaderIfNecessary();
}
@@ -1032,15 +995,34 @@ void GpuDataManagerImplPrivate::NotifyGpuInfoUpdate() {
}
void GpuDataManagerImplPrivate::EnableSwiftShaderIfNecessary() {
+ if (ShouldUseWarp())
+ return;
+
if (!GpuAccessAllowed(NULL) ||
blacklisted_features_.count(gpu::GPU_FEATURE_TYPE_WEBGL)) {
if (!swiftshader_path_.empty() &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSoftwareRasterizer))
use_swiftshader_ = true;
}
}
+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_ =
+ 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
@@ -1148,7 +1130,10 @@ void GpuDataManagerImplPrivate::Notify3DAPIBlocked(const GURL& url,
void GpuDataManagerImplPrivate::OnGpuProcessInitFailure() {
gpu_process_accessible_ = false;
- gpu_info_.finalized = true;
+ gpu_info_.context_info_state = gpu::kCollectInfoFatalFailure;
+#if defined(OS_WIN)
+ gpu_info_.dx_diagnostics_info_state = gpu::kCollectInfoFatalFailure;
+#endif
complete_gpu_info_already_requested_ = true;
// Some observers might be waiting.
NotifyGpuInfoUpdate();
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 8e5514fad31..b3466c14ca5 100644
--- a/chromium/content/browser/gpu/gpu_data_manager_impl_private.h
+++ b/chromium/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -38,10 +38,12 @@ class CONTENT_EXPORT GpuDataManagerImplPrivate {
const GpuDataManager::GetGpuProcessHandlesCallback& callback) const;
bool GpuAccessAllowed(std::string* reason) const;
void RequestCompleteGpuInfoIfNeeded();
+ bool IsEssentialGpuInfoAvailable() const;
bool IsCompleteGpuInfoAvailable() const;
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);
@@ -127,6 +129,8 @@ 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);
@@ -201,6 +205,13 @@ 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;
@@ -231,6 +242,8 @@ 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
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 8955ce1f88d..8bcb01052e7 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
@@ -14,6 +14,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
#define LONG_STRING_CONST(...) #__VA_ARGS__
namespace content {
@@ -25,19 +29,17 @@ class TestObserver : public GpuDataManagerObserver {
: gpu_info_updated_(false),
video_memory_usage_stats_updated_(false) {
}
- virtual ~TestObserver() { }
+ ~TestObserver() override {}
bool gpu_info_updated() const { return gpu_info_updated_; }
bool video_memory_usage_stats_updated() const {
return video_memory_usage_stats_updated_;
}
- virtual void OnGpuInfoUpdate() OVERRIDE {
- gpu_info_updated_ = true;
- }
+ void OnGpuInfoUpdate() override { gpu_info_updated_ = true; }
- virtual void OnVideoMemoryUsageStatsUpdate(
- const GPUVideoMemoryUsageStats& stats) OVERRIDE {
+ void OnVideoMemoryUsageStatsUpdate(
+ const GPUVideoMemoryUsageStats& stats) override {
video_memory_usage_stats_updated_ = true;
}
@@ -69,7 +71,7 @@ class GpuDataManagerImplPrivateTest : public testing::Test {
public:
GpuDataManagerImplPrivateTest() { }
- virtual ~GpuDataManagerImplPrivateTest() { }
+ ~GpuDataManagerImplPrivateTest() override {}
protected:
// scoped_ptr doesn't work with GpuDataManagerImpl because its
@@ -115,11 +117,9 @@ class GpuDataManagerImplPrivateTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(ScopedGpuDataManagerImplPrivate);
};
- virtual void SetUp() {
- }
+ void SetUp() override {}
- virtual void TearDown() {
- }
+ void TearDown() override {}
base::Time JustBeforeExpiration(const GpuDataManagerImplPrivate* manager);
base::Time JustAfterExpiration(const GpuDataManagerImplPrivate* manager);
@@ -158,10 +158,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GpuSideBlacklisting) {
},
{
"id": 2,
- "gl_renderer": {
- "op": "contains",
- "value": "GeForce"
- },
+ "gl_renderer": ".*GeForce.*",
"features": [
"accelerated_2d_canvas"
]
@@ -205,10 +202,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GpuSideExceptions) {
"id": 1,
"exceptions": [
{
- "gl_renderer": {
- "op": "contains",
- "value": "GeForce"
- }
+ "gl_renderer": ".*GeForce.*"
}
],
"features": [
@@ -290,6 +284,22 @@ 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;
@@ -601,7 +611,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListSingle) {
ScopedGpuDataManagerImplPrivate manager;
manager->gpu_driver_bugs_.insert(5);
- CommandLine command_line(0, NULL);
+ base::CommandLine command_line(0, NULL);
manager->AppendGpuCommandLine(&command_line);
EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
@@ -615,7 +625,7 @@ TEST_F(GpuDataManagerImplPrivateTest, GpuDriverBugListMultiple) {
manager->gpu_driver_bugs_.insert(5);
manager->gpu_driver_bugs_.insert(7);
- CommandLine command_line(0, NULL);
+ base::CommandLine command_line(0, NULL);
manager->AppendGpuCommandLine(&command_line);
EXPECT_TRUE(command_line.HasSwitch(switches::kGpuDriverBugWorkarounds));
diff --git a/chromium/content/browser/gpu/gpu_internals_ui.cc b/chromium/content/browser/gpu/gpu_internals_ui.cc
index 997911656e7..4eb492696c5 100644
--- a/chromium/content/browser/gpu/gpu_internals_ui.cc
+++ b/chromium/content/browser/gpu/gpu_internals_ui.cc
@@ -4,11 +4,16 @@
#include "content/browser/gpu/gpu_internals_ui.h"
+#if defined(OS_LINUX) && defined(USE_X11)
+#include <X11/Xlib.h>
+#endif
+
#include <string>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
+#include "base/environment.h"
#include "base/i18n/time_formatting.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
@@ -16,6 +21,7 @@
#include "base/values.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/grit/content_resources.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/web_contents.h"
@@ -27,13 +33,18 @@
#include "content/public/common/url_constants.h"
#include "gpu/config/gpu_feature_type.h"
#include "gpu/config/gpu_info.h"
-#include "grit/content_resources.h"
#include "third_party/angle/src/common/version.h"
+#include "ui/gl/gpu_switching_manager.h"
#if defined(OS_WIN)
#include "ui/base/win/shell.h"
#endif
+#if defined(OS_LINUX) && defined(USE_X11)
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#endif
+
namespace content {
namespace {
@@ -127,6 +138,10 @@ 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)));
+ }
#endif
basic_info->Append(
@@ -157,6 +172,30 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
gpu_info.gl_ws_version));
basic_info->Append(NewDescriptionValuePair("Window system binding extensions",
gpu_info.gl_ws_extensions));
+#if defined(OS_LINUX) && defined(USE_X11)
+ basic_info->Append(NewDescriptionValuePair("Window manager",
+ ui::GuessWindowManagerName()));
+ {
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ std::string value;
+ const char kXDGCurrentDesktop[] = "XDG_CURRENT_DESKTOP";
+ if (env->GetVar(kXDGCurrentDesktop, &value))
+ basic_info->Append(NewDescriptionValuePair(kXDGCurrentDesktop, value));
+ const char kGDMSession[] = "GDMSESSION";
+ if (env->GetVar(kGDMSession, &value))
+ basic_info->Append(NewDescriptionValuePair(kGDMSession, value));
+ const char* kAtomsToCache[] = {
+ "_NET_WM_CM_S0",
+ NULL
+ };
+ ui::X11AtomCache atom_cache(gfx::GetXDisplay(), kAtomsToCache);
+ std::string compositing_manager = XGetSelectionOwner(
+ gfx::GetXDisplay(),
+ atom_cache.GetAtom("_NET_WM_CM_S0")) != None ? "Yes" : "No";
+ basic_info->Append(
+ NewDescriptionValuePair("Compositing manager", compositing_manager));
+ }
+#endif
std::string direct_rendering = gpu_info.direct_rendering ? "Yes" : "No";
basic_info->Append(
NewDescriptionValuePair("Direct rendering", direct_rendering));
@@ -166,6 +205,10 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
basic_info->Append(NewDescriptionValuePair(
"Reset notification strategy", reset_strategy));
+ basic_info->Append(NewDescriptionValuePair(
+ "GPU process crash count",
+ new base::FundamentalValue(gpu_info.process_crash_count)));
+
base::DictionaryValue* info = new base::DictionaryValue();
info->Set("basic_info", basic_info);
@@ -197,17 +240,20 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
class GpuMessageHandler
: public WebUIMessageHandler,
public base::SupportsWeakPtr<GpuMessageHandler>,
- public GpuDataManagerObserver {
+ public GpuDataManagerObserver,
+ public ui::GpuSwitchingObserver {
public:
GpuMessageHandler();
- virtual ~GpuMessageHandler();
+ ~GpuMessageHandler() override;
// WebUIMessageHandler implementation.
- virtual void RegisterMessages() OVERRIDE;
+ void RegisterMessages() override;
// GpuDataManagerObserver implementation.
- virtual void OnGpuInfoUpdate() OVERRIDE;
- virtual void OnGpuSwitching() OVERRIDE;
+ void OnGpuInfoUpdate() override;
+
+ // ui::GpuSwitchingObserver implementation.
+ void OnGpuSwitched() override;
// Messages
void OnBrowserBridgeInitialized(const base::ListValue* list);
@@ -236,6 +282,7 @@ GpuMessageHandler::GpuMessageHandler()
}
GpuMessageHandler::~GpuMessageHandler() {
+ ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
}
@@ -303,8 +350,10 @@ void GpuMessageHandler::OnBrowserBridgeInitialized(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Watch for changes in GPUInfo
- if (!observing_)
+ if (!observing_) {
GpuDataManagerImpl::GetInstance()->AddObserver(this);
+ ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
+ }
observing_ = true;
// Tell GpuDataManager it should have full GpuInfo. If the
@@ -324,7 +373,7 @@ base::Value* GpuMessageHandler::OnRequestClientInfo(
dict->SetString("version", GetContentClient()->GetProduct());
dict->SetString("command_line",
- CommandLine::ForCurrentProcess()->GetCommandLineString());
+ base::CommandLine::ForCurrentProcess()->GetCommandLineString());
dict->SetString("operating_system",
base::SysInfo::OperatingSystemName() + " " +
base::SysInfo::OperatingSystemVersion());
@@ -361,7 +410,7 @@ void GpuMessageHandler::OnGpuInfoUpdate() {
*(gpu_info_val.get()));
}
-void GpuMessageHandler::OnGpuSwitching() {
+void GpuMessageHandler::OnGpuSwitched() {
GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded();
}
diff --git a/chromium/content/browser/gpu/gpu_ipc_browsertests.cc b/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
index cbe45393419..dd78ba6017d 100644
--- a/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/chromium/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -25,7 +25,7 @@ const content::CauseForGpuLaunch kInitCause =
class ContextTestBase : public content::ContentBrowserTest {
public:
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
if (!content::BrowserGpuChannelHostFactory::CanUseForTesting())
return;
@@ -47,12 +47,12 @@ class ContextTestBase : public content::ContentBrowserTest {
WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits(),
NULL));
CHECK(context_.get());
- context_->makeContextCurrent();
+ context_->InitializeOnCurrentThread();
context_support_ = context_->GetContextSupport();
ContentBrowserTest::SetUpOnMainThread();
}
- virtual void TearDownOnMainThread() OVERRIDE {
+ void TearDownOnMainThread() override {
// Must delete the context first.
context_.reset(NULL);
ContentBrowserTest::TearDownOnMainThread();
@@ -73,7 +73,7 @@ namespace content {
class BrowserGpuChannelHostFactoryTest : public ContentBrowserTest {
public:
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
if (!BrowserGpuChannelHostFactory::CanUseForTesting())
return;
@@ -161,7 +161,7 @@ IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
kInitCause,
base::Bind(&BrowserGpuChannelHostFactoryTest::Signal, &event));
EXPECT_TRUE(event);
- EXPECT_EQ(gpu_channel, GetGpuChannel());
+ EXPECT_EQ(gpu_channel.get(), GetGpuChannel());
}
// Fails since UI Compositor establishes a GpuChannel.
diff --git a/chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.cc b/chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.cc
new file mode 100644
index 00000000000..e57bd0c728c
--- /dev/null
+++ b/chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.cc
@@ -0,0 +1,94 @@
+// 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/gpu/gpu_memory_buffer_factory_host_impl.h"
+
+#include "base/bind.h"
+#include "content/browser/gpu/gpu_process_host.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace content {
+
+GpuMemoryBufferFactoryHostImpl::GpuMemoryBufferFactoryHostImpl()
+ : gpu_host_id_(0), next_create_gpu_memory_buffer_request_id_(0) {
+}
+
+GpuMemoryBufferFactoryHostImpl::~GpuMemoryBufferFactoryHostImpl() {
+}
+
+void GpuMemoryBufferFactoryHostImpl::CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ const CreateGpuMemoryBufferCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
+ if (!host) {
+ callback.Run(gfx::GpuMemoryBufferHandle());
+ return;
+ }
+
+ uint32 request_id = next_create_gpu_memory_buffer_request_id_++;
+ create_gpu_memory_buffer_requests_[request_id] = callback;
+
+ host->CreateGpuMemoryBuffer(
+ type,
+ id,
+ size,
+ format,
+ usage,
+ client_id,
+ base::Bind(&GpuMemoryBufferFactoryHostImpl::OnGpuMemoryBufferCreated,
+ base::Unretained(this),
+ request_id));
+}
+
+void GpuMemoryBufferFactoryHostImpl::DestroyGpuMemoryBuffer(
+ gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
+ int client_id,
+ int32 sync_point) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GpuMemoryBufferFactoryHostImpl::DestroyGpuMemoryBufferOnIO,
+ base::Unretained(this),
+ type,
+ id,
+ client_id,
+ sync_point));
+}
+
+void GpuMemoryBufferFactoryHostImpl::DestroyGpuMemoryBufferOnIO(
+ gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
+ int client_id,
+ int32 sync_point) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
+ if (!host)
+ return;
+
+ host->DestroyGpuMemoryBuffer(type, id, client_id, sync_point);
+}
+
+void GpuMemoryBufferFactoryHostImpl::OnGpuMemoryBufferCreated(
+ uint32 request_id,
+ const gfx::GpuMemoryBufferHandle& handle) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ CreateGpuMemoryBufferCallbackMap::iterator iter =
+ create_gpu_memory_buffer_requests_.find(request_id);
+ DCHECK(iter != create_gpu_memory_buffer_requests_.end());
+ iter->second.Run(handle);
+ create_gpu_memory_buffer_requests_.erase(iter);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.h b/chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.h
new file mode 100644
index 00000000000..6cdf6b726d5
--- /dev/null
+++ b/chromium/content/browser/gpu/gpu_memory_buffer_factory_host_impl.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_FACTORY_HOST_IMPL_H_
+#define CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_FACTORY_HOST_IMPL_H_
+
+#include <map>
+
+#include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
+
+namespace content {
+
+class CONTENT_EXPORT GpuMemoryBufferFactoryHostImpl
+ : public GpuMemoryBufferFactoryHost {
+ public:
+ GpuMemoryBufferFactoryHostImpl();
+ ~GpuMemoryBufferFactoryHostImpl() override;
+
+ // Overridden from GpuMemoryBufferFactoryHost:
+ void CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
+ const CreateGpuMemoryBufferCallback& callback) override;
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
+ int client_id,
+ int32 sync_point) override;
+
+ void set_gpu_host_id(int gpu_host_id) { gpu_host_id_ = gpu_host_id; }
+
+ private:
+ void DestroyGpuMemoryBufferOnIO(gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
+ int client_id,
+ int32 sync_point);
+ void OnGpuMemoryBufferCreated(uint32 request_id,
+ const gfx::GpuMemoryBufferHandle& handle);
+
+ int gpu_host_id_;
+ uint32 next_create_gpu_memory_buffer_request_id_;
+ typedef std::map<uint32, CreateGpuMemoryBufferCallback>
+ CreateGpuMemoryBufferCallbackMap;
+ CreateGpuMemoryBufferCallbackMap create_gpu_memory_buffer_requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryHostImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GPU_GPU_MEMORY_BUFFER_FACTORY_HOST_IMPL_H_
diff --git a/chromium/content/browser/gpu/gpu_process_host.cc b/chromium/content/browser/gpu/gpu_process_host.cc
index 9176b6d891c..be7db476b0b 100644
--- a/chromium/content/browser/gpu/gpu_process_host.cc
+++ b/chromium/content/browser/gpu/gpu_process_host.cc
@@ -17,11 +17,12 @@
#include "base/sha1.h"
#include "base/threading/thread.h"
#include "content/browser/browser_child_process_host_impl.h"
+#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/browser/gpu/shader_disk_cache.h"
-#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_resize_helper.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/view_messages.h"
@@ -39,10 +40,10 @@
#include "ipc/ipc_switches.h"
#include "ipc/message_filter.h"
#include "media/base/media_switches.h"
+#include "ui/base/ui_base_switches.h"
#include "ui/events/latency_info.h"
#include "ui/gl/gl_switches.h"
-
#if defined(OS_WIN)
#include "base/win/windows_version.h"
#include "content/common/sandbox_win.h"
@@ -51,7 +52,7 @@
#endif
#if defined(USE_OZONE)
-#include "ui/ozone/ozone_switches.h"
+#include "ui/ozone/public/ozone_switches.h"
#endif
#if defined(USE_X11) && !defined(OS_CHROMEOS)
@@ -62,9 +63,59 @@ namespace content {
bool GpuProcessHost::gpu_enabled_ = true;
bool GpuProcessHost::hardware_gpu_enabled_ = true;
+int GpuProcessHost::gpu_crash_count_ = 0;
+int GpuProcessHost::gpu_recent_crash_count_ = 0;
+bool GpuProcessHost::crashed_before_ = false;
+int GpuProcessHost::swiftshader_crash_count_ = 0;
namespace {
+// Command-line switches to propagate to the GPU process.
+static const char* const kSwitchNames[] = {
+ switches::kDisableAcceleratedVideoDecode,
+ switches::kDisableBreakpad,
+ switches::kDisableGpuSandbox,
+ switches::kDisableGpuWatchdog,
+ switches::kDisableLogging,
+ switches::kDisableSeccompFilterSandbox,
+#if defined(ENABLE_WEBRTC)
+ switches::kDisableWebRtcHWEncoding,
+ switches::kEnableWebRtcHWVp8Encoding,
+#endif
+ switches::kEnableLogging,
+ switches::kEnableShareGroupAsyncTextureUpload,
+#if defined(OS_CHROMEOS)
+ switches::kDisableVaapiAcceleratedVideoEncode,
+#endif
+ switches::kGpuStartupDialog,
+ switches::kGpuSandboxAllowSysVShm,
+ switches::kGpuSandboxFailuresFatal,
+ switches::kGpuSandboxStartEarly,
+ switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode,
+ switches::kLoggingLevel,
+ switches::kLowEndDeviceMode,
+ switches::kNoSandbox,
+ switches::kTestGLLib,
+ switches::kTraceStartup,
+ switches::kTraceToConsole,
+ switches::kV,
+ switches::kVModule,
+#if defined(OS_MACOSX)
+ switches::kDisableRemoteCoreAnimation,
+ switches::kEnableSandboxLogging,
+#endif
+#if defined(USE_AURA)
+ switches::kUIPrioritizeInGpuProcess,
+#endif
+#if defined(USE_OZONE)
+ switches::kOzonePlatform,
+ switches::kOzoneUseSurfaceless,
+#endif
+#if defined(USE_X11) && !defined(OS_CHROMEOS)
+ switches::kX11Display,
+#endif
+};
+
enum GPUProcessLifetimeEvent {
LAUNCHED,
DIED_FIRST_TIME,
@@ -94,7 +145,7 @@ void SendGpuProcessMessage(GpuProcessHost::GpuProcessKind kind,
class GpuSandboxedProcessLauncherDelegate
: public SandboxedProcessLauncherDelegate {
public:
- GpuSandboxedProcessLauncherDelegate(CommandLine* cmd_line,
+ GpuSandboxedProcessLauncherDelegate(base::CommandLine* cmd_line,
ChildProcessHost* host)
#if defined(OS_WIN)
: cmd_line_(cmd_line) {}
@@ -102,10 +153,10 @@ class GpuSandboxedProcessLauncherDelegate
: ipc_fd_(host->TakeClientFileDescriptor()) {}
#endif
- virtual ~GpuSandboxedProcessLauncherDelegate() {}
+ ~GpuSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual bool ShouldSandbox() OVERRIDE {
+ virtual bool ShouldSandbox() override {
bool sandbox = !cmd_line_->HasSwitch(switches::kDisableGpuSandbox);
if(! sandbox) {
DVLOG(1) << "GPU sandbox is disabled";
@@ -114,7 +165,7 @@ class GpuSandboxedProcessLauncherDelegate
}
virtual void PreSandbox(bool* disable_default_policy,
- base::FilePath* exposed_dir) OVERRIDE {
+ base::FilePath* exposed_dir) override {
*disable_default_policy = true;
}
@@ -199,16 +250,14 @@ class GpuSandboxedProcessLauncherDelegate
}
#elif defined(OS_POSIX)
- virtual int GetIpcFd() OVERRIDE {
- return ipc_fd_;
- }
+ base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); }
#endif // OS_WIN
private:
#if defined(OS_WIN)
- CommandLine* cmd_line_;
+ base::CommandLine* cmd_line_;
#elif defined(OS_POSIX)
- int ipc_fd_;
+ base::ScopedFD ipc_fd_;
#endif // OS_WIN
};
@@ -218,8 +267,10 @@ class GpuSandboxedProcessLauncherDelegate
bool GpuProcessHost::ValidateHost(GpuProcessHost* host) {
// The Gpu process is invalid if it's not using SwiftShader, the card is
// blacklisted, and we can kill it and start over.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU) ||
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess) ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kInProcessGPU) ||
(host->valid_ &&
(host->swiftshader_rendering_ ||
!GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()))) {
@@ -325,9 +376,12 @@ GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind)
kind_(kind),
process_launched_(false),
initialized_(false),
+ gpu_crash_recorded_(false),
uma_memory_stats_received_(false) {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess) ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kInProcessGPU)) {
in_process_ = true;
}
@@ -355,67 +409,7 @@ GpuProcessHost::~GpuProcessHost() {
SendOutstandingReplies();
- // Maximum number of times the gpu process is allowed to crash in a session.
- // Once this limit is reached, any request to launch the gpu process will
- // fail.
- const int kGpuMaxCrashCount = 3;
-
- // Number of times the gpu process has crashed in the current browser session.
- static int gpu_crash_count = 0;
- static int gpu_recent_crash_count = 0;
- static base::Time last_gpu_crash_time;
- static bool crashed_before = false;
- static int swiftshader_crash_count = 0;
-
- bool disable_crash_limit = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableGpuProcessCrashLimit);
-
- // Ending only acts as a failure if the GPU process was actually started and
- // was intended for actual rendering (and not just checking caps or other
- // options).
- if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) {
- if (swiftshader_rendering_) {
- UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents",
- DIED_FIRST_TIME + swiftshader_crash_count,
- GPU_PROCESS_LIFETIME_EVENT_MAX);
-
- if (++swiftshader_crash_count >= kGpuMaxCrashCount &&
- !disable_crash_limit) {
- // SwiftShader is too unstable to use. Disable it for current session.
- gpu_enabled_ = false;
- }
- } else {
- ++gpu_crash_count;
- UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
- std::min(DIED_FIRST_TIME + gpu_crash_count,
- GPU_PROCESS_LIFETIME_EVENT_MAX - 1),
- GPU_PROCESS_LIFETIME_EVENT_MAX);
-
- // Allow about 1 GPU crash per hour to be removed from the crash count,
- // so very occasional crashes won't eventually add up and prevent the
- // GPU process from launching.
- ++gpu_recent_crash_count;
- base::Time current_time = base::Time::Now();
- if (crashed_before) {
- int hours_different = (current_time - last_gpu_crash_time).InHours();
- gpu_recent_crash_count =
- std::max(0, gpu_recent_crash_count - hours_different);
- }
-
- crashed_before = true;
- last_gpu_crash_time = current_time;
-
- if ((gpu_recent_crash_count >= kGpuMaxCrashCount && !disable_crash_limit)
- || !initialized_) {
-#if !defined(OS_CHROMEOS)
- // The gpu process is too unstable to use. Disable it for current
- // session.
- hardware_gpu_enabled_ = false;
- GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration();
-#endif
- }
- }
- }
+ RecordProcessCrash();
// In case we never started, clean up.
while (!queued_messages_.empty()) {
@@ -508,7 +502,7 @@ bool GpuProcessHost::Init() {
if (in_process_) {
DCHECK(g_gpu_main_thread_factory);
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitch(switches::kDisableGpuWatchdog);
GpuDataManagerImpl* gpu_data_manager = GpuDataManagerImpl::GetInstance();
@@ -516,7 +510,12 @@ bool GpuProcessHost::Init() {
gpu_data_manager->AppendGpuCommandLine(command_line);
in_process_gpu_thread_.reset(g_gpu_main_thread_factory(channel_id));
- in_process_gpu_thread_->Start();
+ 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
+ in_process_gpu_thread_->StartWithOptions(options);
OnProcessLaunched(); // Fake a callback that the process is ready.
} else if (!LaunchGpuProcess(channel_id)) {
@@ -565,7 +564,6 @@ bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
IPC_MESSAGE_HANDLER(GpuHostMsg_CommandBufferCreated, OnCommandBufferCreated)
IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyCommandBuffer, OnDestroyCommandBuffer)
- IPC_MESSAGE_HANDLER(GpuHostMsg_ImageCreated, OnImageCreated)
IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryBufferCreated,
OnGpuMemoryBufferCreated)
IPC_MESSAGE_HANDLER(GpuHostMsg_DidCreateOffscreenContext,
@@ -576,8 +574,8 @@ bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryUmaStats,
OnGpuMemoryUmaStatsReceived)
#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
- OnAcceleratedSurfaceBuffersSwapped)
+ IPC_MESSAGE_HANDLER_GENERIC(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
+ OnAcceleratedSurfaceBuffersSwapped(message))
#endif
IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyChannel,
OnDestroyChannel)
@@ -602,6 +600,7 @@ void GpuProcessHost::OnChannelConnected(int32 peer_pid) {
void GpuProcessHost::EstablishGpuChannel(
int client_id,
bool share_context,
+ bool allow_future_sync_points,
const EstablishChannelCallback& callback) {
DCHECK(CalledOnValidThread());
TRACE_EVENT0("gpu", "GpuProcessHost::EstablishGpuChannel");
@@ -613,14 +612,15 @@ void GpuProcessHost::EstablishGpuChannel(
return;
}
- if (Send(new GpuMsg_EstablishChannel(client_id, share_context))) {
+ if (Send(new GpuMsg_EstablishChannel(
+ client_id, share_context, allow_future_sync_points))) {
channel_requests_.push(callback);
} else {
DVLOG(1) << "Failed to send GpuMsg_EstablishChannel.";
callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
}
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuShaderDiskCache)) {
CreateChannelCache(client_id);
}
@@ -650,57 +650,41 @@ void GpuProcessHost::CreateViewCommandBuffer(
}
}
-void GpuProcessHost::CreateImage(gfx::PluginWindowHandle window,
- int client_id,
- int image_id,
- const CreateImageCallback& callback) {
- TRACE_EVENT0("gpu", "GpuProcessHost::CreateImage");
-
- DCHECK(CalledOnValidThread());
-
- if (Send(new GpuMsg_CreateImage(window, client_id, image_id))) {
- create_image_requests_.push(callback);
- } else {
- callback.Run(gfx::Size());
- }
-}
-
-void GpuProcessHost::DeleteImage(int client_id,
- int image_id,
- int sync_point) {
- TRACE_EVENT0("gpu", "GpuProcessHost::DeleteImage");
-
- DCHECK(CalledOnValidThread());
-
- Send(new GpuMsg_DeleteImage(client_id, image_id, sync_point));
-}
-
void GpuProcessHost::CreateGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
+ gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
const gfx::Size& size,
- unsigned internalformat,
- unsigned usage,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
const CreateGpuMemoryBufferCallback& callback) {
TRACE_EVENT0("gpu", "GpuProcessHost::CreateGpuMemoryBuffer");
DCHECK(CalledOnValidThread());
- if (Send(new GpuMsg_CreateGpuMemoryBuffer(
- handle, size, internalformat, usage))) {
+ GpuMsg_CreateGpuMemoryBuffer_Params params;
+ params.type = type;
+ params.id = id;
+ params.size = size;
+ params.format = format;
+ params.usage = usage;
+ params.client_id = client_id;
+ if (Send(new GpuMsg_CreateGpuMemoryBuffer(params))) {
create_gpu_memory_buffer_requests_.push(callback);
} else {
callback.Run(gfx::GpuMemoryBufferHandle());
}
}
-void GpuProcessHost::DestroyGpuMemoryBuffer(
- const gfx::GpuMemoryBufferHandle& handle,
- int sync_point) {
+void GpuProcessHost::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
+ int client_id,
+ int sync_point) {
TRACE_EVENT0("gpu", "GpuProcessHost::DestroyGpuMemoryBuffer");
DCHECK(CalledOnValidThread());
- Send(new GpuMsg_DestroyGpuMemoryBuffer(handle, sync_point));
+ Send(new GpuMsg_DestroyGpuMemoryBuffer(type, id, client_id, sync_point));
}
void GpuProcessHost::OnInitialized(bool result, const gpu::GPUInfo& gpu_info) {
@@ -765,17 +749,6 @@ void GpuProcessHost::OnDestroyCommandBuffer(int32 surface_id) {
}
}
-void GpuProcessHost::OnImageCreated(const gfx::Size size) {
- TRACE_EVENT0("gpu", "GpuProcessHost::OnImageCreated");
-
- if (create_image_requests_.empty())
- return;
-
- CreateImageCallback callback = create_image_requests_.front();
- create_image_requests_.pop();
- callback.Run(size);
-}
-
void GpuProcessHost::OnGpuMemoryBufferCreated(
const gfx::GpuMemoryBufferHandle& handle) {
TRACE_EVENT0("gpu", "GpuProcessHost::OnGpuMemoryBufferCreated");
@@ -843,67 +816,10 @@ void GpuProcessHost::OnGpuMemoryUmaStatsReceived(
#if defined(OS_MACOSX)
void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
- TRACE_EVENT0("gpu", "GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped");
-
- if (!ui::LatencyInfo::Verify(params.latency_info,
- "GpuHostMsg_AcceleratedSurfaceBuffersSwapped"))
- return;
-
- gfx::AcceleratedWidget native_widget =
- GpuSurfaceTracker::Get()->AcquireNativeWidget(params.surface_id);
- if (native_widget) {
- RenderWidgetHelper::OnNativeSurfaceBuffersSwappedOnIOThread(this, params);
- return;
- }
-
- gfx::GLSurfaceHandle surface_handle =
- GpuSurfaceTracker::Get()->GetSurfaceHandle(params.surface_id);
- // Compositor window is always gfx::kNullPluginWindow.
- // TODO(jbates) http://crbug.com/105344 This will be removed when there are no
- // plugin windows.
- if (surface_handle.handle != gfx::kNullPluginWindow ||
- surface_handle.transport_type == gfx::TEXTURE_TRANSPORT) {
- RouteOnUIThread(GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
- return;
- }
-
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.sync_point = 0;
-
- int render_process_id = 0;
- int render_widget_id = 0;
- if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
- params.surface_id, &render_process_id, &render_widget_id)) {
- Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
- ack_params));
- return;
- }
- RenderWidgetHelper* helper =
- RenderWidgetHelper::FromProcessHostID(render_process_id);
- if (!helper) {
- Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
- ack_params));
- return;
- }
-
- // Pass the SwapBuffers on to the RenderWidgetHelper to wake up the UI thread
- // if the browser is waiting for a new frame. Otherwise the RenderWidgetHelper
- // will forward to the RenderWidgetHostView via RenderProcessHostImpl and
- // RenderWidgetHostImpl.
- ViewHostMsg_CompositorSurfaceBuffersSwapped_Params view_params;
- view_params.surface_id = params.surface_id;
- view_params.surface_handle = params.surface_handle;
- view_params.route_id = params.route_id;
- view_params.size = params.size;
- view_params.scale_factor = params.scale_factor;
- view_params.gpu_process_host_id = host_id_;
- view_params.latency_info = params.latency_info;
- helper->DidReceiveBackingStoreMsg(ViewHostMsg_CompositorSurfaceBuffersSwapped(
- render_widget_id,
- view_params));
+ const IPC::Message& message) {
+ RenderWidgetResizeHelper::Get()->PostGpuProcessMsg(host_id_, message);
}
-#endif // OS_MACOSX
+#endif
void GpuProcessHost::OnProcessLaunched() {
UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime",
@@ -912,6 +828,7 @@ void GpuProcessHost::OnProcessLaunched() {
void GpuProcessHost::OnProcessCrashed(int exit_code) {
SendOutstandingReplies();
+ RecordProcessCrash();
GpuDataManagerImpl::GetInstance()->ProcessCrashed(
process_->GetTerminationStatus(true /* known_dead */, NULL));
}
@@ -947,9 +864,10 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
return false;
}
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
- CommandLine::StringType gpu_launcher =
+ base::CommandLine::StringType gpu_launcher =
browser_command_line.GetSwitchValueNative(switches::kGpuLauncher);
#if defined(OS_LINUX)
@@ -963,50 +881,15 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) {
if (exe_path.empty())
return false;
- CommandLine* cmd_line = new CommandLine(exe_path);
+ base::CommandLine* cmd_line = new base::CommandLine(exe_path);
cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED)
cmd_line->AppendSwitch(switches::kDisableGpuSandbox);
- // Propagate relevant command line switches.
- static const char* const kSwitchNames[] = {
- switches::kDisableAcceleratedVideoDecode,
- switches::kDisableBreakpad,
- switches::kDisableGpuSandbox,
- switches::kDisableGpuWatchdog,
- switches::kDisableLogging,
- switches::kDisableSeccompFilterSandbox,
-#if defined(ENABLE_WEBRTC)
- switches::kDisableWebRtcHWEncoding,
-#endif
- switches::kEnableLogging,
- switches::kEnableShareGroupAsyncTextureUpload,
- switches::kGpuStartupDialog,
- switches::kGpuSandboxAllowSysVShm,
- switches::kGpuSandboxFailuresFatal,
- switches::kGpuSandboxStartAfterInitialization,
- switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode,
- switches::kLoggingLevel,
- switches::kNoSandbox,
- switches::kTestGLLib,
- switches::kTraceStartup,
- switches::kV,
- switches::kVModule,
-#if defined(OS_MACOSX)
- switches::kEnableSandboxLogging,
-#endif
-#if defined(USE_AURA)
- switches::kUIPrioritizeInGpuProcess,
-#endif
-#if defined(USE_OZONE)
- switches::kOzonePlatform,
-#endif
-#if defined(USE_X11) && !defined(OS_CHROMEOS)
- switches::kX11Display,
-#endif
- };
+ // 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(
@@ -1058,6 +941,13 @@ void GpuProcessHost::SendOutstandingReplies() {
create_command_buffer_requests_.pop();
callback.Run(CREATE_COMMAND_BUFFER_FAILED_AND_CHANNEL_LOST);
}
+
+ while (!create_gpu_memory_buffer_requests_.empty()) {
+ CreateGpuMemoryBufferCallback callback =
+ create_gpu_memory_buffer_requests_.front();
+ create_gpu_memory_buffer_requests_.pop();
+ callback.Run(gfx::GpuMemoryBufferHandle());
+ }
}
void GpuProcessHost::BlockLiveOffscreenContexts() {
@@ -1069,6 +959,72 @@ void GpuProcessHost::BlockLiveOffscreenContexts() {
}
}
+void GpuProcessHost::RecordProcessCrash() {
+ // Skip if a GPU process crash was already counted.
+ if (gpu_crash_recorded_)
+ return;
+
+ // Maximum number of times the GPU process is allowed to crash in a session.
+ // Once this limit is reached, any request to launch the GPU process will
+ // fail.
+ const int kGpuMaxCrashCount = 3;
+
+ // Last time the GPU process crashed.
+ static base::Time last_gpu_crash_time;
+
+ bool disable_crash_limit = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuProcessCrashLimit);
+
+ // Ending only acts as a failure if the GPU process was actually started and
+ // was intended for actual rendering (and not just checking caps or other
+ // options).
+ if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) {
+ gpu_crash_recorded_ = true;
+ if (swiftshader_rendering_) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents",
+ DIED_FIRST_TIME + swiftshader_crash_count_,
+ GPU_PROCESS_LIFETIME_EVENT_MAX);
+
+ if (++swiftshader_crash_count_ >= kGpuMaxCrashCount &&
+ !disable_crash_limit) {
+ // SwiftShader is too unstable to use. Disable it for current session.
+ gpu_enabled_ = false;
+ }
+ } else {
+ ++gpu_crash_count_;
+ UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
+ std::min(DIED_FIRST_TIME + gpu_crash_count_,
+ GPU_PROCESS_LIFETIME_EVENT_MAX - 1),
+ GPU_PROCESS_LIFETIME_EVENT_MAX);
+
+ // Allow about 1 GPU crash per hour to be removed from the crash count,
+ // so very occasional crashes won't eventually add up and prevent the
+ // GPU process from launching.
+ ++gpu_recent_crash_count_;
+ base::Time current_time = base::Time::Now();
+ if (crashed_before_) {
+ int hours_different = (current_time - last_gpu_crash_time).InHours();
+ gpu_recent_crash_count_ =
+ std::max(0, gpu_recent_crash_count_ - hours_different);
+ }
+
+ crashed_before_ = true;
+ last_gpu_crash_time = current_time;
+
+ if ((gpu_recent_crash_count_ >= kGpuMaxCrashCount &&
+ !disable_crash_limit) ||
+ !initialized_) {
+#if !defined(OS_CHROMEOS)
+ // The GPU process is too unstable to use. Disable it for current
+ // session.
+ hardware_gpu_enabled_ = false;
+ GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration();
+#endif
+ }
+ }
+ }
+}
+
std::string GpuProcessHost::GetShaderPrefixKey() {
if (shader_prefix_key_.empty()) {
gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
diff --git a/chromium/content/browser/gpu/gpu_process_host.h b/chromium/content/browser/gpu/gpu_process_host.h
index cf789465248..2952d3869ef 100644
--- a/chromium/content/browser/gpu/gpu_process_host.h
+++ b/chromium/content/browser/gpu/gpu_process_host.h
@@ -26,18 +26,12 @@
#include "gpu/config/gpu_info.h"
#include "ipc/ipc_sender.h"
#include "ipc/message_filter.h"
+#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "url/gurl.h"
struct GPUCreateCommandBufferConfig;
-struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
-struct GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params;
-struct GpuHostMsg_AcceleratedSurfaceRelease_Params;
-
-namespace gfx {
-struct GpuMemoryBufferHandle;
-}
namespace IPC {
struct ChannelHandle;
@@ -67,12 +61,11 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
typedef base::Callback<void(CreateCommandBufferResult)>
CreateCommandBufferCallback;
- typedef base::Callback<void(const gfx::Size)> CreateImageCallback;
-
typedef base::Callback<void(const gfx::GpuMemoryBufferHandle& handle)>
CreateGpuMemoryBufferCallback;
static bool gpu_enabled() { return gpu_enabled_; }
+ static int gpu_crash_count() { return gpu_crash_count_; }
// Creates a new GpuProcessHost or gets an existing one, resulting in the
// launching of a GPU process if required. Returns null on failure. It
@@ -102,7 +95,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
int host_id() const { return host_id_; }
// IPC::Sender implementation.
- virtual bool Send(IPC::Message* msg) OVERRIDE;
+ bool Send(IPC::Message* msg) override;
// Adds a message filter to the GpuProcessHost's channel.
void AddFilter(IPC::MessageFilter* filter);
@@ -112,6 +105,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// and GPUInfo, we call the callback.
void EstablishGpuChannel(int client_id,
bool share_context,
+ bool allow_future_sync_points,
const EstablishChannelCallback& callback);
// Tells the GPU process to create a new command buffer that draws into the
@@ -124,22 +118,19 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
int route_id,
const CreateCommandBufferCallback& callback);
- // Tells the GPU process to create a new image using the given window.
- void CreateImage(
- gfx::PluginWindowHandle window,
- int client_id,
- int image_id,
- const CreateImageCallback& callback);
-
- // Tells the GPU process to delete image.
- void DeleteImage(int client_id, int image_id, int sync_point);
-
- void CreateGpuMemoryBuffer(const gfx::GpuMemoryBufferHandle& handle,
+ // Tells the GPU process to create a new GPU memory buffer.
+ void CreateGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
const gfx::Size& size,
- unsigned internalformat,
- unsigned usage,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ int client_id,
const CreateGpuMemoryBufferCallback& callback);
- void DestroyGpuMemoryBuffer(const gfx::GpuMemoryBufferHandle& handle,
+
+ // Tells the GPU process to destroy GPU memory buffer.
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferType type,
+ gfx::GpuMemoryBufferId id,
+ int client_id,
int sync_point);
// What kind of GPU process, e.g. sandboxed or unsandboxed.
@@ -157,7 +148,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
static bool ValidateHost(GpuProcessHost* host);
GpuProcessHost(int host_id, GpuProcessKind kind);
- virtual ~GpuProcessHost();
+ ~GpuProcessHost() override;
bool Init();
@@ -165,17 +156,16 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
void RouteOnUIThread(const IPC::Message& message);
// BrowserChildProcessHostDelegate implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
- virtual void OnProcessLaunched() OVERRIDE;
- virtual void OnProcessCrashed(int exit_code) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnChannelConnected(int32 peer_pid) override;
+ void OnProcessLaunched() override;
+ void OnProcessCrashed(int exit_code) override;
// Message handlers.
void OnInitialized(bool result, const gpu::GPUInfo& gpu_info);
void OnChannelEstablished(const IPC::ChannelHandle& channel_handle);
void OnCommandBufferCreated(CreateCommandBufferResult result);
void OnDestroyCommandBuffer(int32 surface_id);
- void OnImageCreated(const gfx::Size size);
void OnGpuMemoryBufferCreated(const gfx::GpuMemoryBufferHandle& handle);
void OnDidCreateOffscreenContext(const GURL& url);
void OnDidLoseContext(bool offscreen,
@@ -184,8 +174,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
void OnDidDestroyOffscreenContext(const GURL& url);
void OnGpuMemoryUmaStatsReceived(const GPUMemoryUmaStats& stats);
#if defined(OS_MACOSX)
- void OnAcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params);
+ void OnAcceleratedSurfaceBuffersSwapped(const IPC::Message& message);
#endif
void CreateChannelCache(int32 client_id);
@@ -199,6 +188,9 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
void BlockLiveOffscreenContexts();
+ // Update GPU crash counters. Disable GPU if crash limit is reached.
+ void RecordProcessCrash();
+
std::string GetShaderPrefixKey();
// The serial number of the GpuProcessHost / GpuProcessHostUIShim pair.
@@ -211,9 +203,6 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// The pending create command buffer requests we need to reply to.
std::queue<CreateCommandBufferCallback> create_command_buffer_requests_;
- // The pending create image requests we need to reply to.
- std::queue<CreateImageCallback> create_image_requests_;
-
// The pending create gpu memory buffer requests we need to reply to.
std::queue<CreateGpuMemoryBufferCallback> create_gpu_memory_buffer_requests_;
@@ -241,6 +230,9 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// Time Init started. Used to log total GPU process startup time to UMA.
base::TimeTicks init_start_time_;
+ // Whether this host recorded a GPU crash or not.
+ bool gpu_crash_recorded_;
+
// Master switch for enabling/disabling GPU acceleration for the current
// browser session. It does not change the acceleration settings for
// existing tabs, just the future ones.
@@ -248,6 +240,11 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
static bool hardware_gpu_enabled_;
+ static int gpu_crash_count_;
+ static int gpu_recent_crash_count_;
+ static bool crashed_before_;
+ static int swiftshader_crash_count_;
+
scoped_ptr<BrowserChildProcessHostImpl> process_;
// Track the URLs of the pages which have live offscreen contexts,
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 a6a6805d176..8c4450628e7 100644
--- a/chromium/content/browser/gpu/gpu_process_host_ui_shim.cc
+++ b/chromium/content/browser/gpu/gpu_process_host_ui_shim.cc
@@ -11,18 +11,24 @@
#include "base/id_map.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
+#include "content/browser/gpu/compositor_util.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/renderer_host/render_process_host_impl.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_view_base.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/public/browser/browser_thread.h"
+#if defined(OS_MACOSX)
+#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h"
+#endif
+
#if defined(USE_OZONE)
-#include "ui/ozone/ozone_platform.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/ozone_platform.h"
#endif
namespace content {
@@ -198,24 +204,14 @@ bool GpuProcessHostUIShim::OnControlMessageReceived(
IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message)
IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage,
OnLogMessage)
-
IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized,
OnAcceleratedSurfaceInitialized)
IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
OnAcceleratedSurfaceBuffersSwapped)
- IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfacePostSubBuffer,
- OnAcceleratedSurfacePostSubBuffer)
- IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceSuspend,
- OnAcceleratedSurfaceSuspend)
IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
OnGraphicsInfoCollected)
- IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease,
- OnAcceleratedSurfaceRelease)
IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats,
OnVideoMemoryUsageStatsReceived);
- IPC_MESSAGE_HANDLER(GpuHostMsg_UpdateVSyncParameters,
- OnUpdateVSyncParameters)
- IPC_MESSAGE_HANDLER(GpuHostMsg_FrameDrawn, OnFrameDrawn)
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
@@ -223,23 +219,6 @@ bool GpuProcessHostUIShim::OnControlMessageReceived(
return true;
}
-void GpuProcessHostUIShim::OnUpdateVSyncParameters(int surface_id,
- base::TimeTicks timebase,
- base::TimeDelta interval) {
-
- int render_process_id = 0;
- int render_widget_id = 0;
- if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface(
- surface_id, &render_process_id, &render_widget_id)) {
- return;
- }
- RenderWidgetHost* rwh =
- RenderWidgetHost::FromID(render_process_id, render_widget_id);
- if (!rwh)
- return;
- RenderWidgetHostImpl::From(rwh)->UpdateVSyncParameters(timebase, interval);
-}
-
void GpuProcessHostUIShim::OnLogMessage(
int level,
const std::string& header,
@@ -263,104 +242,38 @@ void GpuProcessHostUIShim::OnAcceleratedSurfaceInitialized(int32 surface_id,
GetRenderWidgetHostViewFromSurfaceID(surface_id);
if (!view)
return;
- view->AcceleratedSurfaceInitialized(host_id_, route_id);
+ view->AcceleratedSurfaceInitialized(route_id);
}
void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
+#if defined(OS_MACOSX)
TRACE_EVENT0("renderer",
"GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
if (!ui::LatencyInfo::Verify(params.latency_info,
- "GpuHostMsg_AcceleratedSurfaceBuffersSwapped"))
+ "GpuHostMsg_AcceleratedSurfaceBuffersSwapped")) {
return;
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.mailbox = params.mailbox;
- ack_params.sync_point = 0;
- ScopedSendOnIOThread delayed_send(
- host_id_,
- new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
- ack_params));
-
- RenderWidgetHostViewBase* view = GetRenderWidgetHostViewFromSurfaceID(
- params.surface_id);
- if (!view)
- return;
-
- delayed_send.Cancel();
-
- GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params view_params = params;
-
- RenderWidgetHostImpl* impl =
- RenderWidgetHostImpl::From(view->GetRenderWidgetHost());
- for (size_t i = 0; i < view_params.latency_info.size(); i++)
- impl->AddLatencyInfoComponentIds(&view_params.latency_info[i]);
-
- // View must send ACK message after next composite.
- view->AcceleratedSurfaceBuffersSwapped(view_params, host_id_);
- view->DidReceiveRendererFrame();
-}
-
-void GpuProcessHostUIShim::OnFrameDrawn(
- const std::vector<ui::LatencyInfo>& latency_info) {
- if (!ui::LatencyInfo::Verify(latency_info,
- "GpuProcessHostUIShim::OnFrameDrawn"))
- return;
- RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
-}
+ }
-void GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params) {
- TRACE_EVENT0("renderer",
- "GpuProcessHostUIShim::OnAcceleratedSurfacePostSubBuffer");
- if (!ui::LatencyInfo::Verify(params.latency_info,
- "GpuHostMsg_AcceleratedSurfacePostSubBuffer"))
- return;
+ // On Mac with delegated rendering, accelerated surfaces are not necessarily
+ // associated with a RenderWidgetHostViewBase.
AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.mailbox = params.mailbox;
- ack_params.sync_point = 0;
- ScopedSendOnIOThread delayed_send(
- host_id_,
- new AcceleratedSurfaceMsg_BufferPresented(params.route_id,
- ack_params));
-
- RenderWidgetHostViewBase* view =
- GetRenderWidgetHostViewFromSurfaceID(params.surface_id);
- if (!view)
- return;
-
- delayed_send.Cancel();
-
- GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params view_params = params;
-
- RenderWidgetHostImpl* impl =
- RenderWidgetHostImpl::From(view->GetRenderWidgetHost());
- for (size_t i = 0; i < view_params.latency_info.size(); i++)
- impl->AddLatencyInfoComponentIds(&view_params.latency_info[i]);
-
- // View must send ACK message after next composite.
- view->AcceleratedSurfacePostSubBuffer(view_params, host_id_);
- view->DidReceiveRendererFrame();
-}
-
-void GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend(int32 surface_id) {
- TRACE_EVENT0("renderer",
- "GpuProcessHostUIShim::OnAcceleratedSurfaceSuspend");
-
- RenderWidgetHostViewBase* view =
- GetRenderWidgetHostViewFromSurfaceID(surface_id);
- if (!view)
- return;
-
- view->AcceleratedSurfaceSuspend();
-}
-
-void GpuProcessHostUIShim::OnAcceleratedSurfaceRelease(
- const GpuHostMsg_AcceleratedSurfaceRelease_Params& params) {
- RenderWidgetHostViewBase* view = GetRenderWidgetHostViewFromSurfaceID(
- params.surface_id);
- if (!view)
- return;
- view->AcceleratedSurfaceRelease();
+ DCHECK(IsDelegatedRendererEnabled());
+ gfx::AcceleratedWidget native_widget =
+ content::GpuSurfaceTracker::Get()->AcquireNativeWidget(params.surface_id);
+ BrowserCompositorCALayerTreeMacGotAcceleratedFrame(
+ native_widget,
+ params.surface_handle,
+ params.surface_id,
+ params.latency_info,
+ params.size,
+ params.scale_factor,
+ &ack_params.disable_throttling,
+ &ack_params.renderer_id);
+ Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id, ack_params));
+#else
+ NOTREACHED();
+#endif
}
void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
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 2fe19789bfe..e47dc9049f7 100644
--- a/chromium/content/browser/gpu/gpu_process_host_ui_shim.h
+++ b/chromium/content/browser/gpu/gpu_process_host_ui_shim.h
@@ -25,8 +25,6 @@
#include "ipc/ipc_sender.h"
struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
-struct GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params;
-struct GpuHostMsg_AcceleratedSurfaceRelease_Params;
namespace ui {
struct LatencyInfo;
@@ -66,13 +64,13 @@ class GpuProcessHostUIShim : public IPC::Listener,
CONTENT_EXPORT static GpuProcessHostUIShim* GetOneInstance();
// IPC::Sender implementation.
- virtual bool Send(IPC::Message* msg) OVERRIDE;
+ bool Send(IPC::Message* msg) override;
// IPC::Listener implementation.
// The GpuProcessHost causes this to be called on the UI thread to
// dispatch the incoming messages from the GPU process, which are
// actually received on the IO thread.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
CONTENT_EXPORT void SimulateRemoveAllContext();
CONTENT_EXPORT void SimulateCrash();
@@ -80,7 +78,7 @@ class GpuProcessHostUIShim : public IPC::Listener,
private:
explicit GpuProcessHostUIShim(int host_id);
- virtual ~GpuProcessHostUIShim();
+ ~GpuProcessHostUIShim() override;
// Message handlers.
bool OnControlMessageReceived(const IPC::Message& message);
@@ -93,17 +91,8 @@ class GpuProcessHostUIShim : public IPC::Listener,
void OnAcceleratedSurfaceInitialized(int32 surface_id, int32 route_id);
void OnAcceleratedSurfaceBuffersSwapped(
const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params);
- void OnAcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params);
- void OnAcceleratedSurfaceSuspend(int32 surface_id);
- void OnAcceleratedSurfaceRelease(
- const GpuHostMsg_AcceleratedSurfaceRelease_Params& params);
void OnVideoMemoryUsageStatsReceived(
const GPUVideoMemoryUsageStats& video_memory_usage_stats);
- void OnUpdateVSyncParameters(int surface_id,
- base::TimeTicks timebase,
- base::TimeDelta interval);
- void OnFrameDrawn(const std::vector<ui::LatencyInfo>& latency_info);
// The serial number of the GpuProcessHost / GpuProcessHostUIShim pair.
int host_id_;
diff --git a/chromium/content/browser/gpu/gpu_surface_tracker.h b/chromium/content/browser/gpu/gpu_surface_tracker.h
index de9d666dbe8..03d182fd14c 100644
--- a/chromium/content/browser/gpu/gpu_surface_tracker.h
+++ b/chromium/content/browser/gpu/gpu_surface_tracker.h
@@ -51,7 +51,7 @@ class GpuSurfaceTracker : public GpuSurfaceLookup {
// GpuSurfaceLookup implementation:
// Returns the native widget associated with a given surface_id.
- virtual gfx::AcceleratedWidget AcquireNativeWidget(int surface_id) OVERRIDE;
+ gfx::AcceleratedWidget AcquireNativeWidget(int surface_id) override;
// Gets the global instance of the surface tracker.
static GpuSurfaceTracker* Get() { return GetInstance(); }
@@ -124,7 +124,7 @@ class GpuSurfaceTracker : public GpuSurfaceLookup {
friend struct DefaultSingletonTraits<GpuSurfaceTracker>;
GpuSurfaceTracker();
- virtual ~GpuSurfaceTracker();
+ ~GpuSurfaceTracker() override;
base::Lock lock_;
SurfaceMap surface_map_;
diff --git a/chromium/content/browser/gpu/shader_disk_cache.cc b/chromium/content/browser/gpu/shader_disk_cache.cc
index c987cefc9a0..a50e3c38b98 100644
--- a/chromium/content/browser/gpu/shader_disk_cache.cc
+++ b/chromium/content/browser/gpu/shader_disk_cache.cc
@@ -4,6 +4,7 @@
#include "content/browser/gpu/shader_disk_cache.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/threading/thread_checker.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/public/browser/browser_thread.h"
@@ -23,6 +24,9 @@ void EntryCloser(disk_cache::Entry* entry) {
entry->Close();
}
+void FreeDiskCacheIterator(scoped_ptr<disk_cache::Backend::Iterator> iterator) {
+}
+
} // namespace
// ShaderDiskCacheEntry handles the work of caching/updating the cached
@@ -95,7 +99,7 @@ class ShaderDiskReadHelper
base::WeakPtr<ShaderDiskCache> cache_;
OpType op_type_;
- void* iter_;
+ scoped_ptr<disk_cache::Backend::Iterator> iter_;
scoped_refptr<net::IOBufferWithSize> buf_;
int host_id_;
disk_cache::Entry* entry_;
@@ -243,7 +247,6 @@ ShaderDiskReadHelper::ShaderDiskReadHelper(
int host_id)
: cache_(cache),
op_type_(OPEN_NEXT),
- iter_(NULL),
buf_(NULL),
host_id_(host_id),
entry_(NULL) {
@@ -257,6 +260,11 @@ void ShaderDiskReadHelper::LoadCache() {
}
void ShaderDiskReadHelper::OnOpComplete(int rv) {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "422516 ShaderDiskReadHelper::OnOpComplete"));
+
DCHECK(CalledOnValidThread());
if (!cache_.get())
return;
@@ -291,16 +299,17 @@ int ShaderDiskReadHelper::OpenNextEntry() {
DCHECK(CalledOnValidThread());
// Called through OnOpComplete, so we know |cache_| is valid.
op_type_ = OPEN_NEXT_COMPLETE;
- return cache_->backend()->OpenNextEntry(
- &iter_,
- &entry_,
- base::Bind(&ShaderDiskReadHelper::OnOpComplete, this));
+ if (!iter_)
+ iter_ = cache_->backend()->CreateIterator();
+ return iter_->OpenNextEntry(
+ &entry_, base::Bind(&ShaderDiskReadHelper::OnOpComplete, this));
}
int ShaderDiskReadHelper::OpenNextEntryComplete(int rv) {
DCHECK(CalledOnValidThread());
// Called through OnOpComplete, so we know |cache_| is valid.
if (rv == net::ERR_FAILED) {
+ iter_.reset();
op_type_ = ITERATION_FINISHED;
return net::OK;
}
@@ -339,16 +348,21 @@ int ShaderDiskReadHelper::ReadComplete(int rv) {
int ShaderDiskReadHelper::IterationComplete(int rv) {
DCHECK(CalledOnValidThread());
// Called through OnOpComplete, so we know |cache_| is valid.
- cache_->backend()->EndEnumeration(&iter_);
- iter_ = NULL;
+ iter_.reset();
op_type_ = TERMINATE;
return net::OK;
}
ShaderDiskReadHelper::~ShaderDiskReadHelper() {
- if (entry_)
+ if (entry_) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&EntryCloser, entry_));
+ }
+ if (iter_) {
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&FreeDiskCacheIterator,
+ base::Passed(&iter_)));
+ }
}
ShaderClearHelper::ShaderClearHelper(scoped_refptr<ShaderDiskCache> cache,
@@ -545,7 +559,7 @@ void ShaderDiskCache::Cache(const std::string& key, const std::string& shader) {
new ShaderDiskCacheEntry(AsWeakPtr(), key, shader);
shim->Cache();
- entry_map_[shim] = shim;
+ entry_map_[shim.get()] = shim;
}
int ShaderDiskCache::Clear(
diff --git a/chromium/content/browser/gpu/shader_disk_cache_unittest.cc b/chromium/content/browser/gpu/shader_disk_cache_unittest.cc
index 9c7061b62bb..15894ef6713 100644
--- a/chromium/content/browser/gpu/shader_disk_cache_unittest.cc
+++ b/chromium/content/browser/gpu/shader_disk_cache_unittest.cc
@@ -25,7 +25,7 @@ class ShaderDiskCacheTest : public testing::Test {
: thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
}
- virtual ~ShaderDiskCacheTest() {}
+ ~ShaderDiskCacheTest() override {}
const base::FilePath& cache_path() { return temp_dir_.path(); }
@@ -36,7 +36,7 @@ class ShaderDiskCacheTest : public testing::Test {
}
private:
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
ShaderCacheFactory::GetInstance()->RemoveCacheInfo(kDefaultClientId);
}
diff --git a/chromium/content/browser/gpu/test_support_gpu.gypi b/chromium/content/browser/gpu/test_support_gpu.gypi
index 9dcedc0cda9..98133776e5c 100644
--- a/chromium/content/browser/gpu/test_support_gpu.gypi
+++ b/chromium/content/browser/gpu/test_support_gpu.gypi
@@ -26,9 +26,9 @@
'<(DEPTH)/third_party/wtl/include',
],
'sources': [
+ '<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.rc',
'<(SHARED_INTERMEDIATE_DIR)/content/content_resources.rc',
'<(SHARED_INTERMEDIATE_DIR)/net/net_resources.rc',
- '<(SHARED_INTERMEDIATE_DIR)/webkit/blink_resources.rc',
],
'conditions': [
['win_use_allocator_shim==1', {
diff --git a/chromium/content/browser/histogram_internals_request_job.cc b/chromium/content/browser/histogram_internals_request_job.cc
index aaa7a43eb26..e29dfca5e42 100644
--- a/chromium/content/browser/histogram_internals_request_job.cc
+++ b/chromium/content/browser/histogram_internals_request_job.cc
@@ -6,6 +6,7 @@
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
+#include "base/profiler/scoped_tracker.h"
#include "content/browser/histogram_synchronizer.h"
#include "net/base/escape.h"
#include "net/base/net_errors.h"
@@ -47,8 +48,8 @@ void AboutHistogram(std::string* data, const std::string& path) {
data->append("</head><body>");
// Display any stats for which we sent off requests the last time.
- data->append("<p>Stats as of last page load;");
- data->append("reload to get stats as of this page load.</p>\n");
+ data->append("<p>Stats accumulated from browser startup to previous ");
+ data->append("page load; reload to get stats as of this page load.</p>\n");
data->append("<table width=\"100%\">\n");
base::StatisticsRecorder::WriteHTMLGraph(unescaped_query, data);
@@ -59,6 +60,11 @@ int HistogramInternalsRequestJob::GetData(
std::string* charset,
std::string* data,
const net::CompletionCallback& callback) const {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "422489 HistogramInternalsRequestJob::GetData"));
+
mime_type->assign("text/html");
charset->assign("UTF8");
diff --git a/chromium/content/browser/histogram_internals_request_job.h b/chromium/content/browser/histogram_internals_request_job.h
index 4be774be87c..6304198477d 100644
--- a/chromium/content/browser/histogram_internals_request_job.h
+++ b/chromium/content/browser/histogram_internals_request_job.h
@@ -17,13 +17,13 @@ class HistogramInternalsRequestJob : public net::URLRequestSimpleJob {
HistogramInternalsRequestJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate);
- virtual int GetData(std::string* mime_type,
- std::string* charset,
- std::string* data,
- const net::CompletionCallback& callback) const OVERRIDE;
+ int GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* data,
+ const net::CompletionCallback& callback) const override;
private:
- virtual ~HistogramInternalsRequestJob() {}
+ ~HistogramInternalsRequestJob() override {}
// The string to select histograms which have |path_| as a substring.
std::string path_;
diff --git a/chromium/content/browser/histogram_message_filter.cc b/chromium/content/browser/histogram_message_filter.cc
index 8a58fff55f6..8eb7c7231ba 100644
--- a/chromium/content/browser/histogram_message_filter.cc
+++ b/chromium/content/browser/histogram_message_filter.cc
@@ -45,7 +45,7 @@ void HistogramMessageFilter::OnGetBrowserHistogram(
// Security: Only allow access to browser histograms when running in the
// context of a test.
bool using_stats_collection_controller =
- CommandLine::ForCurrentProcess()->HasSwitch(
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kStatsCollectionController);
if (!using_stats_collection_controller) {
LOG(ERROR) << "Attempt at reading browser histogram without specifying "
diff --git a/chromium/content/browser/histogram_message_filter.h b/chromium/content/browser/histogram_message_filter.h
index 67867061687..25fa6767b91 100644
--- a/chromium/content/browser/histogram_message_filter.h
+++ b/chromium/content/browser/histogram_message_filter.h
@@ -19,10 +19,10 @@ class HistogramMessageFilter : public BrowserMessageFilter {
HistogramMessageFilter();
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
- virtual ~HistogramMessageFilter();
+ ~HistogramMessageFilter() override;
// Message handlers.
void OnChildHistogramData(int sequence_number,
diff --git a/chromium/content/browser/histogram_synchronizer.h b/chromium/content/browser/histogram_synchronizer.h
index 9ff69d5cfeb..b7d75e03d45 100644
--- a/chromium/content/browser/histogram_synchronizer.h
+++ b/chromium/content/browser/histogram_synchronizer.h
@@ -80,7 +80,7 @@ class HistogramSynchronizer : public HistogramSubscriber {
class RequestContext;
HistogramSynchronizer();
- virtual ~HistogramSynchronizer();
+ ~HistogramSynchronizer() override;
// Establish a new sequence number, and use it to notify all processes
// (renderers, plugins, GPU, etc) of the need to supply, to the browser,
@@ -95,16 +95,16 @@ class HistogramSynchronizer : public HistogramSubscriber {
// Update the number of pending processes for the given |sequence_number|.
// This is called on UI thread.
- virtual void OnPendingProcesses(int sequence_number,
- int pending_processes,
- bool end) OVERRIDE;
+ void OnPendingProcesses(int sequence_number,
+ int pending_processes,
+ bool end) override;
// Send histogram_data back to caller and also record that we are waiting
// for one less histogram data from child process for the given sequence
// number. This method is accessible on UI thread.
- virtual void OnHistogramDataCollected(
+ void OnHistogramDataCollected(
int sequence_number,
- const std::vector<std::string>& pickled_histograms) OVERRIDE;
+ const std::vector<std::string>& pickled_histograms) override;
// Set the callback_thread_ and callback_ members. If these members already
// had values, then as a side effect, post the old callback_ to the old
diff --git a/chromium/content/browser/host_zoom_map_impl.cc b/chromium/content/browser/host_zoom_map_impl.cc
index 1b5f7a2f7d7..81f8182924d 100644
--- a/chromium/content/browser/host_zoom_map_impl.cc
+++ b/chromium/content/browser/host_zoom_map_impl.cc
@@ -21,14 +21,15 @@
#include "content/public/browser/notification_types.h"
#include "content/public/browser/resource_context.h"
#include "content/public/common/page_zoom.h"
+#include "content/public/common/url_constants.h"
#include "net/base/net_util.h"
-static const char* kHostZoomMapKeyName = "content_host_zoom_map";
-
namespace content {
namespace {
+const char kHostZoomMapKeyName[] = "content_host_zoom_map";
+
std::string GetHostFromProcessView(int render_process_id, int render_view_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
RenderViewHost* render_view_host =
@@ -43,12 +44,23 @@ std::string GetHostFromProcessView(int render_process_id, int render_view_id) {
if (!entry)
return std::string();
- return net::GetHostOrSpecFromURL(entry->GetURL());
+ return net::GetHostOrSpecFromURL(HostZoomMap::GetURLFromEntry(entry));
}
} // namespace
-HostZoomMap* HostZoomMap::GetForBrowserContext(BrowserContext* context) {
+GURL HostZoomMap::GetURLFromEntry(const NavigationEntry* entry) {
+ switch (entry->GetPageType()) {
+ case PAGE_TYPE_ERROR:
+ return GURL(kUnreachableWebDataURL);
+ // TODO(wjmaclean): In future, give interstitial pages special treatment as
+ // well.
+ default:
+ return entry->GetURL();
+ }
+}
+
+HostZoomMap* HostZoomMap::GetDefaultForBrowserContext(BrowserContext* context) {
HostZoomMapImpl* rv = static_cast<HostZoomMapImpl*>(
context->GetUserData(kHostZoomMapKeyName));
if (!rv) {
@@ -61,19 +73,29 @@ HostZoomMap* HostZoomMap::GetForBrowserContext(BrowserContext* context) {
// Helper function for setting/getting zoom levels for WebContents without
// having to import HostZoomMapImpl everywhere.
double HostZoomMap::GetZoomLevel(const WebContents* web_contents) {
- HostZoomMapImpl* host_zoom_map = static_cast<HostZoomMapImpl*>(
- HostZoomMap::GetForBrowserContext(web_contents->GetBrowserContext()));
+ HostZoomMapImpl* host_zoom_map =
+ static_cast<HostZoomMapImpl*>(HostZoomMap::GetDefaultForBrowserContext(
+ web_contents->GetBrowserContext()));
return host_zoom_map->GetZoomLevelForWebContents(
*static_cast<const WebContentsImpl*>(web_contents));
}
void HostZoomMap::SetZoomLevel(const WebContents* web_contents, double level) {
- HostZoomMapImpl* host_zoom_map = static_cast<HostZoomMapImpl*>(
- HostZoomMap::GetForBrowserContext(web_contents->GetBrowserContext()));
+ HostZoomMapImpl* host_zoom_map =
+ static_cast<HostZoomMapImpl*>(HostZoomMap::GetDefaultForBrowserContext(
+ web_contents->GetBrowserContext()));
host_zoom_map->SetZoomLevelForWebContents(
*static_cast<const WebContentsImpl*>(web_contents), level);
}
+void HostZoomMap::SendErrorPageZoomLevelRefresh(
+ const WebContents* web_contents) {
+ HostZoomMapImpl* host_zoom_map =
+ static_cast<HostZoomMapImpl*>(HostZoomMap::GetDefaultForBrowserContext(
+ web_contents->GetBrowserContext()));
+ host_zoom_map->SendErrorPageZoomLevelRefresh();
+}
+
HostZoomMapImpl::HostZoomMapImpl()
: default_zoom_level_(0.0) {
registrar_.Add(
@@ -251,7 +273,7 @@ double HostZoomMapImpl::GetZoomLevelForWebContents(
// It is possible for a WebContent's zoom level to be queried before
// a navigation has occurred.
if (entry)
- url = entry->GetURL();
+ url = GetURLFromEntry(entry);
return GetZoomLevelForHostAndScheme(url.scheme(),
net::GetHostOrSpecFromURL(url));
}
@@ -275,7 +297,7 @@ void HostZoomMapImpl::SetZoomLevelForWebContents(
if (!entry)
return;
- GURL url = entry->GetURL();
+ GURL url = GetURLFromEntry(entry);
SetZoomLevelForHost(net::GetHostOrSpecFromURL(url), level);
}
}
@@ -374,7 +396,7 @@ void HostZoomMapImpl::SendZoomLevelChange(const std::string& scheme,
for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
!i.IsAtEnd(); i.Advance()) {
RenderProcessHost* render_process_host = i.GetCurrentValue();
- if (HostZoomMap::GetForBrowserContext(
+ if (HostZoomMap::GetDefaultForBrowserContext(
render_process_host->GetBrowserContext()) == this) {
render_process_host->Send(
new ViewMsg_SetZoomLevelForCurrentURL(scheme, host, level));
@@ -382,6 +404,14 @@ void HostZoomMapImpl::SendZoomLevelChange(const std::string& scheme,
}
}
+void HostZoomMapImpl::SendErrorPageZoomLevelRefresh() {
+ GURL error_url(kUnreachableWebDataURL);
+ std::string host = net::GetHostOrSpecFromURL(error_url);
+ double error_page_zoom_level = GetZoomLevelForHost(host);
+
+ SendZoomLevelChange(std::string(), host, error_page_zoom_level);
+}
+
HostZoomMapImpl::~HostZoomMapImpl() {
}
diff --git a/chromium/content/browser/host_zoom_map_impl.h b/chromium/content/browser/host_zoom_map_impl.h
index 821fa0e4923..78d643d750a 100644
--- a/chromium/content/browser/host_zoom_map_impl.h
+++ b/chromium/content/browser/host_zoom_map_impl.h
@@ -28,36 +28,32 @@ class CONTENT_EXPORT HostZoomMapImpl : public NON_EXPORTED_BASE(HostZoomMap),
public base::SupportsUserData::Data {
public:
HostZoomMapImpl();
- virtual ~HostZoomMapImpl();
+ ~HostZoomMapImpl() override;
// HostZoomMap implementation:
- virtual void CopyFrom(HostZoomMap* copy) OVERRIDE;
- virtual double GetZoomLevelForHostAndScheme(
- const std::string& scheme,
- const std::string& host) const OVERRIDE;
+ void CopyFrom(HostZoomMap* copy) override;
+ double GetZoomLevelForHostAndScheme(const std::string& scheme,
+ const std::string& host) const override;
// TODO(wjmaclean) Should we use a GURL here? crbug.com/384486
- virtual bool HasZoomLevel(const std::string& scheme,
- const std::string& host) const OVERRIDE;
- virtual ZoomLevelVector GetAllZoomLevels() const OVERRIDE;
- virtual void SetZoomLevelForHost(
- const std::string& host,
- double level) OVERRIDE;
- virtual void SetZoomLevelForHostAndScheme(
- const std::string& scheme,
- const std::string& host,
- double level) OVERRIDE;
- virtual bool UsesTemporaryZoomLevel(int render_process_id,
- int render_view_id) const OVERRIDE;
- virtual void SetTemporaryZoomLevel(int render_process_id,
- int render_view_id,
- double level) OVERRIDE;
-
- virtual void ClearTemporaryZoomLevel(int render_process_id,
- int render_view_id) OVERRIDE;
- virtual double GetDefaultZoomLevel() const OVERRIDE;
- virtual void SetDefaultZoomLevel(double level) OVERRIDE;
- virtual scoped_ptr<Subscription> AddZoomLevelChangedCallback(
- const ZoomLevelChangedCallback& callback) OVERRIDE;
+ bool HasZoomLevel(const std::string& scheme,
+ const std::string& host) const override;
+ ZoomLevelVector GetAllZoomLevels() const override;
+ void SetZoomLevelForHost(const std::string& host, double level) override;
+ void SetZoomLevelForHostAndScheme(const std::string& scheme,
+ const std::string& host,
+ double level) override;
+ bool UsesTemporaryZoomLevel(int render_process_id,
+ int render_view_id) const override;
+ void SetTemporaryZoomLevel(int render_process_id,
+ int render_view_id,
+ double level) override;
+
+ void ClearTemporaryZoomLevel(int render_process_id,
+ int render_view_id) override;
+ double GetDefaultZoomLevel() const override;
+ void SetDefaultZoomLevel(double level) override;
+ scoped_ptr<Subscription> AddZoomLevelChangedCallback(
+ const ZoomLevelChangedCallback& callback) override;
// Returns the current zoom level for the specified WebContents. This may
// be a temporary zoom level, depending on UsesTemporaryZoomLevel().
@@ -86,9 +82,11 @@ class CONTENT_EXPORT HostZoomMapImpl : public NON_EXPORTED_BASE(HostZoomMap),
int render_view_id) const;
// NotificationObserver implementation.
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
+
+ void SendErrorPageZoomLevelRefresh();
private:
typedef std::map<std::string, double> HostZoomLevels;
diff --git a/chromium/content/browser/indexed_db/OWNERS b/chromium/content/browser/indexed_db/OWNERS
index d68c26c9187..6d435ba10c4 100644
--- a/chromium/content/browser/indexed_db/OWNERS
+++ b/chromium/content/browser/indexed_db/OWNERS
@@ -1,5 +1,4 @@
dgrogan@chromium.org
michaeln@chromium.org
jsbell@chromium.org
-ericu@chromium.org
cmumford@chromium.org
diff --git a/chromium/content/browser/indexed_db/indexed_db.h b/chromium/content/browser/indexed_db/indexed_db.h
index 3714d40af33..fc46e6d64ca 100644
--- a/chromium/content/browser/indexed_db/indexed_db.h
+++ b/chromium/content/browser/indexed_db/indexed_db.h
@@ -9,19 +9,6 @@ namespace content {
namespace indexed_db {
-enum TransactionMode {
- TRANSACTION_READ_ONLY = 0,
- TRANSACTION_READ_WRITE = 1,
- TRANSACTION_VERSION_CHANGE = 2
-};
-
-enum CursorDirection {
- CURSOR_NEXT = 0,
- CURSOR_NEXT_NO_DUPLICATE = 1,
- CURSOR_PREV = 2,
- CURSOR_PREV_NO_DUPLICATE = 3,
-};
-
enum CursorType {
CURSOR_KEY_AND_VALUE = 0,
CURSOR_KEY_ONLY
diff --git a/chromium/content/browser/indexed_db/indexed_db_active_blob_registry.cc b/chromium/content/browser/indexed_db/indexed_db_active_blob_registry.cc
index b65b24725af..7bda0bbb3ec 100644
--- a/chromium/content/browser/indexed_db/indexed_db_active_blob_registry.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_active_blob_registry.cc
@@ -118,7 +118,7 @@ void IndexedDBActiveBlobRegistry::ReleaseBlobRefThreadSafe(
blob_key));
}
-webkit_blob::ShareableFileReference::FinalReleaseCallback
+storage::ShareableFileReference::FinalReleaseCallback
IndexedDBActiveBlobRegistry::GetFinalReleaseCallback(int64 database_id,
int64 blob_key) {
return base::Bind(
diff --git a/chromium/content/browser/indexed_db/indexed_db_active_blob_registry.h b/chromium/content/browser/indexed_db/indexed_db_active_blob_registry.h
index 92380e13260..b0ebe27fd7c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_active_blob_registry.h
+++ b/chromium/content/browser/indexed_db/indexed_db_active_blob_registry.h
@@ -12,7 +12,7 @@
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
-#include "webkit/common/blob/shareable_file_reference.h"
+#include "storage/common/blob/shareable_file_reference.h"
namespace content {
@@ -31,8 +31,9 @@ class CONTENT_EXPORT IndexedDBActiveBlobRegistry {
// Use DatabaseMetaDataKey::AllBlobsKey for "the whole database".
bool MarkDeletedCheckIfUsed(int64 database_id, int64 blob_key);
- webkit_blob::ShareableFileReference::FinalReleaseCallback
- GetFinalReleaseCallback(int64 database_id, int64 blob_key);
+ storage::ShareableFileReference::FinalReleaseCallback GetFinalReleaseCallback(
+ int64 database_id,
+ int64 blob_key);
// This closure holds a raw pointer to the IndexedDBActiveBlobRegistry,
// and may not be called after it is deleted.
base::Closure GetAddBlobRefCallback(int64 database_id, int64 blob_key);
@@ -42,6 +43,13 @@ class CONTENT_EXPORT IndexedDBActiveBlobRegistry {
void ForceShutdown();
private:
+ // Maps blob_key -> IsDeleted; if the record's absent, it's not in active use
+ // and we don't care if it's deleted.
+ typedef std::map<int64, bool> SingleDBMap;
+ // Maps DB ID -> SingleDBMap
+ typedef std::map<int64, SingleDBMap> AllDBsMap;
+ typedef std::set<int64> DeletedDBSet;
+
void AddBlobRef(int64 database_id, int64 blob_key);
void ReleaseBlobRef(int64 database_id, int64 blob_key);
static void ReleaseBlobRefThreadSafe(
@@ -51,13 +59,6 @@ class CONTENT_EXPORT IndexedDBActiveBlobRegistry {
int64 blob_key,
const base::FilePath& unused);
- // Maps blob_key -> IsDeleted; if the record's absent, it's not in active use
- // and we don't care if it's deleted.
- typedef std::map<int64, bool> SingleDBMap;
- // Maps DB ID -> SingleDBMap
- typedef std::map<int64, SingleDBMap> AllDBsMap;
- typedef std::set<int64> DeletedDBSet;
-
AllDBsMap use_tracker_;
DeletedDBSet deleted_dbs_;
// As long as we've got blobs registered in use_tracker_,
diff --git a/chromium/content/browser/indexed_db/indexed_db_active_blob_registry_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_active_blob_registry_unittest.cc
index c8f84758f80..aa412cf0908 100644
--- a/chromium/content/browser/indexed_db/indexed_db_active_blob_registry_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_active_blob_registry_unittest.cc
@@ -7,20 +7,20 @@
#include "base/test/test_simple_task_runner.h"
#include "content/browser/indexed_db/indexed_db_active_blob_registry.h"
#include "content/browser/indexed_db/indexed_db_backing_store.h"
-#include "content/browser/indexed_db/indexed_db_factory.h"
#include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
+#include "content/browser/indexed_db/mock_indexed_db_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace {
-class MockIDBFactory : public IndexedDBFactory {
+class RegistryTestMockFactory : public MockIndexedDBFactory {
public:
- MockIDBFactory() : IndexedDBFactory(NULL), duplicate_calls_(false) {}
+ RegistryTestMockFactory() : duplicate_calls_(false) {}
- virtual void ReportOutstandingBlobs(const GURL& origin_url,
- bool blobs_outstanding) OVERRIDE {
+ void ReportOutstandingBlobs(const GURL& origin_url,
+ bool blobs_outstanding) override {
if (blobs_outstanding) {
if (origins_.count(origin_url)) {
duplicate_calls_ = true;
@@ -39,32 +39,34 @@ class MockIDBFactory : public IndexedDBFactory {
bool CheckNoOriginsInUse() const {
return !duplicate_calls_ && !origins_.size();
}
+
bool CheckSingleOriginInUse(const GURL& origin) const {
return !duplicate_calls_ && origins_.size() == 1 && origins_.count(origin);
}
- protected:
- virtual ~MockIDBFactory() {}
-
private:
+ ~RegistryTestMockFactory() override {}
+
std::set<GURL> origins_;
bool duplicate_calls_;
- DISALLOW_COPY_AND_ASSIGN(MockIDBFactory);
+ DISALLOW_COPY_AND_ASSIGN(RegistryTestMockFactory);
};
class MockIDBBackingStore : public IndexedDBFakeBackingStore {
public:
- MockIDBBackingStore(IndexedDBFactory* factory, base::TaskRunner* task_runner)
+ typedef std::pair<int64, int64> KeyPair;
+ typedef std::set<KeyPair> KeyPairSet;
+
+ MockIDBBackingStore(IndexedDBFactory* factory,
+ base::SequencedTaskRunner* task_runner)
: IndexedDBFakeBackingStore(factory, task_runner),
duplicate_calls_(false) {}
- virtual void ReportBlobUnused(int64 database_id, int64 blob_key) OVERRIDE {
+ void ReportBlobUnused(int64 database_id, int64 blob_key) override {
unused_blobs_.insert(std::make_pair(database_id, blob_key));
}
- typedef std::pair<int64, int64> KeyPair;
- typedef std::set<KeyPair> KeyPairSet;
bool CheckUnusedBlobsEmpty() const {
return !duplicate_calls_ && !unused_blobs_.size();
}
@@ -76,7 +78,7 @@ class MockIDBBackingStore : public IndexedDBFakeBackingStore {
const KeyPairSet& unused_blobs() const { return unused_blobs_; }
protected:
- virtual ~MockIDBBackingStore() {}
+ ~MockIDBBackingStore() override {}
private:
KeyPairSet unused_blobs_;
@@ -88,28 +90,29 @@ class MockIDBBackingStore : public IndexedDBFakeBackingStore {
// Base class for our test fixtures.
class IndexedDBActiveBlobRegistryTest : public testing::Test {
public:
+ typedef storage::ShareableFileReference::FinalReleaseCallback
+ ReleaseCallback;
+
+ static const int64 kDatabaseId0 = 7;
+ static const int64 kDatabaseId1 = 12;
+ static const int64 kBlobKey0 = 77;
+ static const int64 kBlobKey1 = 14;
+
IndexedDBActiveBlobRegistryTest()
: task_runner_(new base::TestSimpleTaskRunner),
- factory_(new MockIDBFactory),
- backing_store_(new MockIDBBackingStore(factory_, task_runner_)),
+ factory_(new RegistryTestMockFactory),
+ backing_store_(
+ new MockIDBBackingStore(factory_.get(), task_runner_.get())),
registry_(new IndexedDBActiveBlobRegistry(backing_store_.get())) {}
void RunUntilIdle() { task_runner_->RunUntilIdle(); }
- MockIDBFactory* factory() const { return factory_.get(); }
+ RegistryTestMockFactory* factory() const { return factory_.get(); }
MockIDBBackingStore* backing_store() const { return backing_store_.get(); }
IndexedDBActiveBlobRegistry* registry() const { return registry_.get(); }
- static const int64 kDatabaseId0 = 7;
- static const int64 kDatabaseId1 = 12;
- static const int64 kBlobKey0 = 77;
- static const int64 kBlobKey1 = 14;
-
- typedef webkit_blob::ShareableFileReference::FinalReleaseCallback
- ReleaseCallback;
-
private:
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
- scoped_refptr<MockIDBFactory> factory_;
+ scoped_refptr<RegistryTestMockFactory> factory_;
scoped_refptr<MockIDBBackingStore> backing_store_;
scoped_ptr<IndexedDBActiveBlobRegistry> registry_;
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 0a83a914f84..781eadcdab8 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -4,8 +4,8 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
@@ -24,6 +24,7 @@
#include "content/browser/indexed_db/indexed_db_value.h"
#include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
#include "content/browser/indexed_db/leveldb/leveldb_database.h"
+#include "content/browser/indexed_db/leveldb/leveldb_factory.h"
#include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
#include "content/common/indexed_db/indexed_db_key.h"
@@ -31,18 +32,18 @@
#include "content/common/indexed_db/indexed_db_key_range.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/fileapi/file_stream_writer.h"
+#include "storage/browser/fileapi/file_writer_delegate.h"
+#include "storage/browser/fileapi/local_file_stream_writer.h"
+#include "storage/common/database/database_identifier.h"
#include "third_party/WebKit/public/platform/WebIDBTypes.h"
#include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
#include "third_party/leveldatabase/env_chromium.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/fileapi/file_stream_writer.h"
-#include "webkit/browser/fileapi/file_writer_delegate.h"
-#include "webkit/browser/fileapi/local_file_stream_writer.h"
-#include "webkit/common/database/database_identifier.h"
using base::FilePath;
using base::StringPiece;
-using fileapi::FileWriterDelegate;
+using storage::FileWriterDelegate;
namespace content {
@@ -77,18 +78,18 @@ bool MakeIDBBlobDirectory(const FilePath& pathBase,
}
static std::string ComputeOriginIdentifier(const GURL& origin_url) {
- return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1";
+ return storage::GetIdentifierFromOrigin(origin_url) + "@1";
}
static base::FilePath ComputeFileName(const GURL& origin_url) {
return base::FilePath()
- .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url))
+ .AppendASCII(storage::GetIdentifierFromOrigin(origin_url))
.AddExtension(FILE_PATH_LITERAL(".indexeddb.leveldb"));
}
static base::FilePath ComputeBlobPath(const GURL& origin_url) {
return base::FilePath()
- .AppendASCII(webkit_database::GetIdentifierFromOrigin(origin_url))
+ .AppendASCII(storage::GetIdentifierFromOrigin(origin_url))
.AddExtension(FILE_PATH_LITERAL(".indexeddb.blob"));
}
@@ -347,7 +348,7 @@ WARN_UNUSED_RESULT static bool IsSchemaKnown(LevelDBDatabase* db, bool* known) {
// TODO(ericu): Move this down into the member section of this file. I'm
// leaving it here for this CL as it's easier to see the diffs in place.
-WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() {
+WARN_UNUSED_RESULT leveldb::Status IndexedDBBackingStore::SetUpMetadata() {
const uint32 latest_known_data_version =
blink::kSerializedScriptValueVersion;
const std::string schema_version_key = SchemaVersionKey::Encode();
@@ -363,7 +364,7 @@ WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() {
GetInt(transaction.get(), schema_version_key, &db_schema_version, &found);
if (!s.ok()) {
INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
+ return s;
}
if (!found) {
// Initialize new backing store.
@@ -375,7 +376,7 @@ WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() {
// leftover from a partially-purged previous generation of data.
if (!base::DeleteFile(blob_path_, true)) {
INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
+ return IOErrorStatus();
}
} else {
// Upgrade old backing store.
@@ -396,11 +397,11 @@ WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() {
s = GetInt(transaction.get(), it->Key(), &database_id, &found);
if (!s.ok()) {
INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
+ return s;
}
if (!found) {
INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
+ return InternalInconsistencyStatus();
}
std::string int_version_key = DatabaseMetaDataKey::Encode(
database_id, DatabaseMetaDataKey::USER_INT_VERSION);
@@ -419,14 +420,14 @@ WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() {
db_schema_version = 3;
if (!base::DeleteFile(blob_path_, true)) {
INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
+ return IOErrorStatus();
}
}
}
if (!s.ok()) {
INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
+ return s;
}
// All new values will be written using this serialization version.
@@ -434,11 +435,11 @@ WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() {
s = GetInt(transaction.get(), data_version_key, &db_data_version, &found);
if (!s.ok()) {
INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
+ return s;
}
if (!found) {
INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
+ return InternalInconsistencyStatus();
}
if (db_data_version < latest_known_data_version) {
db_data_version = latest_known_data_version;
@@ -449,11 +450,9 @@ WARN_UNUSED_RESULT bool IndexedDBBackingStore::SetUpMetadata() {
DCHECK_EQ(db_data_version, latest_known_data_version);
s = transaction->Commit();
- if (!s.ok()) {
+ if (!s.ok())
INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA);
- return false;
- }
- return true;
+ return s;
}
template <typename DBOrTransaction>
@@ -487,14 +486,13 @@ WARN_UNUSED_RESULT static leveldb::Status GetMaxObjectStoreId(
class DefaultLevelDBFactory : public LevelDBFactory {
public:
DefaultLevelDBFactory() {}
- virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name,
- const LevelDBComparator* comparator,
- scoped_ptr<LevelDBDatabase>* db,
- bool* is_disk_full) OVERRIDE {
+ leveldb::Status OpenLevelDB(const base::FilePath& file_name,
+ const LevelDBComparator* comparator,
+ scoped_ptr<LevelDBDatabase>* db,
+ bool* is_disk_full) override {
return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full);
}
- virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name)
- OVERRIDE {
+ leveldb::Status DestroyLevelDB(const base::FilePath& file_name) override {
return LevelDBDatabase::Destroy(file_name);
}
@@ -564,7 +562,7 @@ static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key,
bool found = false;
leveldb::Status s = leveldb_transaction->Get(leveldb_key, &data, &found);
if (!s.ok()) {
- INTERNAL_READ_ERROR_UNTESTED(READ_BLOB_JOURNAL);
+ INTERNAL_READ_ERROR(READ_BLOB_JOURNAL);
return s;
}
journal->clear();
@@ -572,7 +570,7 @@ static leveldb::Status GetBlobJournal(const StringPiece& leveldb_key,
return leveldb::Status::OK();
StringPiece slice(data);
if (!DecodeBlobJournal(&slice, journal)) {
- INTERNAL_READ_ERROR_UNTESTED(DECODE_BLOB_JOURNAL);
+ INTERNAL_CONSISTENCY_ERROR_UNTESTED(DECODE_BLOB_JOURNAL);
s = InternalInconsistencyStatus();
}
return s;
@@ -654,16 +652,14 @@ static leveldb::Status MergeDatabaseIntoLiveBlobJournal(
static std::string EncodeBlobData(
const std::vector<IndexedDBBlobInfo*>& blob_info) {
std::string ret;
- std::vector<IndexedDBBlobInfo*>::const_iterator iter;
- for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) {
- const IndexedDBBlobInfo& info = **iter;
- EncodeBool(info.is_file(), &ret);
- EncodeVarInt(info.key(), &ret);
- EncodeStringWithLength(info.type(), &ret);
- if (info.is_file())
- EncodeStringWithLength(info.file_name(), &ret);
+ for (const auto* info : blob_info) {
+ EncodeBool(info->is_file(), &ret);
+ EncodeVarInt(info->key(), &ret);
+ EncodeStringWithLength(info->type(), &ret);
+ if (info->is_file())
+ EncodeStringWithLength(info->file_name(), &ret);
else
- EncodeVarInt(info.size(), &ret);
+ EncodeVarInt(info->size(), &ret);
}
return ret;
}
@@ -709,7 +705,7 @@ IndexedDBBackingStore::IndexedDBBackingStore(
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator,
- base::TaskRunner* task_runner)
+ base::SequencedTaskRunner* task_runner)
: indexed_db_factory_(indexed_db_factory),
origin_url_(origin_url),
blob_path_(blob_path),
@@ -725,12 +721,8 @@ IndexedDBBackingStore::~IndexedDBBackingStore() {
if (!blob_path_.empty() && !child_process_ids_granted_.empty()) {
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
- std::set<int>::const_iterator iter;
- for (iter = child_process_ids_granted_.begin();
- iter != child_process_ids_granted_.end();
- ++iter) {
- policy->RevokeAllPermissionsForFile(*iter, blob_path_);
- }
+ for (const auto& pid : child_process_ids_granted_)
+ policy->RevokeAllPermissionsForFile(pid, blob_path_);
}
STLDeleteContainerPairSecondPointers(incognito_blob_map_.begin(),
incognito_blob_map_.end());
@@ -781,8 +773,9 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message,
bool* disk_full,
- base::TaskRunner* task_runner,
- bool clean_journal) {
+ base::SequencedTaskRunner* task_runner,
+ bool clean_journal,
+ leveldb::Status* status) {
*data_loss = blink::WebIDBDataLossNone;
DefaultLevelDBFactory leveldb_factory;
return IndexedDBBackingStore::Open(indexed_db_factory,
@@ -794,7 +787,8 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
disk_full,
&leveldb_factory,
task_runner,
- clean_journal);
+ clean_journal,
+ status);
}
static std::string OriginToCustomHistogramSuffix(const GURL& origin_url) {
@@ -864,7 +858,7 @@ leveldb::Status IndexedDBBackingStore::DestroyBackingStore(
bool IndexedDBBackingStore::ReadCorruptionInfo(const base::FilePath& path_base,
const GURL& origin_url,
- std::string& message) {
+ std::string* message) {
const base::FilePath info_path =
path_base.Append(ComputeCorruptionFileName(origin_url));
@@ -891,7 +885,7 @@ bool IndexedDBBackingStore::ReadCorruptionInfo(const base::FilePath& path_base,
if (val && val->GetType() == base::Value::TYPE_DICTIONARY) {
base::DictionaryValue* dict_val =
static_cast<base::DictionaryValue*>(val.get());
- success = dict_val->GetString("message", &message);
+ success = dict_val->GetString("message", message);
}
}
file.Close();
@@ -934,14 +928,17 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
std::string* data_loss_message,
bool* is_disk_full,
LevelDBFactory* leveldb_factory,
- base::TaskRunner* task_runner,
- bool clean_journal) {
+ base::SequencedTaskRunner* task_runner,
+ bool clean_journal,
+ leveldb::Status* status) {
IDB_TRACE("IndexedDBBackingStore::Open");
DCHECK(!path_base.empty());
*data_loss = blink::WebIDBDataLossNone;
*data_loss_message = "";
*is_disk_full = false;
+ *status = leveldb::Status::OK();
+
scoped_ptr<LevelDBComparator> comparator(new Comparator());
if (!base::IsStringASCII(path_base.AsUTF8Unsafe())) {
@@ -949,8 +946,10 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
origin_url);
}
if (!base::CreateDirectory(path_base)) {
- LOG(ERROR) << "Unable to create IndexedDB database path "
- << path_base.AsUTF8Unsafe();
+ *status =
+ leveldb::Status::IOError("Unable to create IndexedDB database path");
+ LOG(ERROR) << status->ToString() << ": \"" << path_base.AsUTF8Unsafe()
+ << "\"";
HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY,
origin_url);
return scoped_refptr<IndexedDBBackingStore>();
@@ -962,29 +961,30 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
path_base.Append(ComputeBlobPath(origin_url));
if (IsPathTooLong(file_path)) {
+ *status = leveldb::Status::IOError("File path too long");
HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG,
origin_url);
return scoped_refptr<IndexedDBBackingStore>();
}
scoped_ptr<LevelDBDatabase> db;
- leveldb::Status status = leveldb_factory->OpenLevelDB(
+ *status = leveldb_factory->OpenLevelDB(
file_path, comparator.get(), &db, is_disk_full);
- DCHECK(!db == !status.ok());
- if (!status.ok()) {
- if (leveldb_env::IndicatesDiskFull(status)) {
+ DCHECK(!db == !status->ok());
+ if (!status->ok()) {
+ if (leveldb_env::IndicatesDiskFull(*status)) {
*is_disk_full = true;
- } else if (leveldb_env::IsCorruption(status)) {
+ } else if (leveldb_env::IsCorruption(*status)) {
*data_loss = blink::WebIDBDataLossTotal;
- *data_loss_message = leveldb_env::GetCorruptionMessage(status);
+ *data_loss_message = leveldb_env::GetCorruptionMessage(*status);
}
}
bool is_schema_known = false;
if (db) {
std::string corruption_message;
- if (ReadCorruptionInfo(path_base, origin_url, corruption_message)) {
+ if (ReadCorruptionInfo(path_base, origin_url, &corruption_message)) {
LOG(ERROR) << "IndexedDB recovering from a corrupted (and deleted) "
"database.";
HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION,
@@ -1013,21 +1013,21 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
}
}
- DCHECK(status.ok() || !is_schema_known || leveldb_env::IsIOError(status) ||
- leveldb_env::IsCorruption(status));
+ DCHECK(status->ok() || !is_schema_known || leveldb_env::IsIOError(*status) ||
+ leveldb_env::IsCorruption(*status));
if (db) {
HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, origin_url);
- } else if (leveldb_env::IsIOError(status)) {
+ } else if (leveldb_env::IsIOError(*status)) {
LOG(ERROR) << "Unable to open backing store, not trying to recover - "
- << status.ToString();
+ << status->ToString();
HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, origin_url);
return scoped_refptr<IndexedDBBackingStore>();
} else {
- DCHECK(!is_schema_known || leveldb_env::IsCorruption(status));
+ DCHECK(!is_schema_known || leveldb_env::IsCorruption(*status));
LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup";
- status = leveldb_factory->DestroyLevelDB(file_path);
- if (!status.ok()) {
+ *status = leveldb_factory->DestroyLevelDB(file_path);
+ if (!status->ok()) {
LOG(ERROR) << "IndexedDB backing store cleanup failed";
HistogramOpenStatus(INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED,
origin_url);
@@ -1060,9 +1060,10 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
request_context,
db.Pass(),
comparator.Pass(),
- task_runner);
+ task_runner,
+ status);
- if (clean_journal && backing_store &&
+ if (clean_journal && backing_store.get() &&
!backing_store->CleanUpBlobJournal(LiveBlobJournalKey::Encode()).ok()) {
HistogramOpenStatus(
INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR, origin_url);
@@ -1074,17 +1075,19 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
// static
scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
const GURL& origin_url,
- base::TaskRunner* task_runner) {
+ base::SequencedTaskRunner* task_runner,
+ leveldb::Status* status) {
DefaultLevelDBFactory leveldb_factory;
return IndexedDBBackingStore::OpenInMemory(
- origin_url, &leveldb_factory, task_runner);
+ origin_url, &leveldb_factory, task_runner, status);
}
// static
scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
const GURL& origin_url,
LevelDBFactory* leveldb_factory,
- base::TaskRunner* task_runner) {
+ base::SequencedTaskRunner* task_runner,
+ leveldb::Status* status) {
IDB_TRACE("IndexedDBBackingStore::OpenInMemory");
scoped_ptr<LevelDBComparator> comparator(new Comparator());
@@ -1104,7 +1107,8 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
NULL /* request_context */,
db.Pass(),
comparator.Pass(),
- task_runner);
+ task_runner,
+ status);
}
// static
@@ -1115,7 +1119,8 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator,
- base::TaskRunner* task_runner) {
+ base::SequencedTaskRunner* task_runner,
+ leveldb::Status* status) {
// TODO(jsbell): Handle comparator name changes.
scoped_refptr<IndexedDBBackingStore> backing_store(
new IndexedDBBackingStore(indexed_db_factory,
@@ -1125,7 +1130,8 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
db.Pass(),
comparator.Pass(),
task_runner));
- if (!backing_store->SetUpMetadata())
+ *status = backing_store->SetUpMetadata();
+ if (!status->ok())
return scoped_refptr<IndexedDBBackingStore>();
return backing_store;
@@ -1154,6 +1160,7 @@ std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames(
for (*s = it->Seek(start_key);
s->ok() && it->IsValid() && CompareKeys(it->Key(), stop_key) < 0;
*s = it->Next()) {
+ // Decode database name (in iterator key).
StringPiece slice(it->Key());
DatabaseNameKey database_name_key;
if (!DatabaseNameKey::Decode(&slice, &database_name_key) ||
@@ -1161,11 +1168,35 @@ std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames(
INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES);
continue;
}
- found_names.push_back(database_name_key.database_name());
+
+ // Decode database id (in iterator value).
+ int64 database_id = 0;
+ StringPiece valueSlice(it->Value());
+ if (!DecodeInt(&valueSlice, &database_id) || !valueSlice.empty()) {
+ INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES);
+ continue;
+ }
+
+ // Look up version by id.
+ bool found = false;
+ int64 database_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
+ *s = GetVarInt(db_.get(),
+ DatabaseMetaDataKey::Encode(
+ database_id, DatabaseMetaDataKey::USER_INT_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)
+ found_names.push_back(database_name_key.database_name());
}
if (!s->ok())
- INTERNAL_READ_ERROR_UNTESTED(GET_DATABASE_NAMES);
+ INTERNAL_READ_ERROR(GET_DATABASE_NAMES);
return found_names;
}
@@ -1276,6 +1307,7 @@ leveldb::Status IndexedDBBackingStore::CreateIDBDatabaseMetaData(
const base::string16& version,
int64 int_version,
int64* row_id) {
+ // TODO(jsbell): Don't persist metadata if open fails. http://crbug.com/395472
scoped_refptr<LevelDBTransaction> transaction =
IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get());
@@ -1861,8 +1893,8 @@ leveldb::Status IndexedDBBackingStore::PutRecord(
int64 database_id,
int64 object_store_id,
const IndexedDBKey& key,
- IndexedDBValue& value,
- ScopedVector<webkit_blob::BlobDataHandle>* handles,
+ IndexedDBValue* value,
+ ScopedVector<storage::BlobDataHandle>* handles,
RecordIdentifier* record_identifier) {
IDB_TRACE("IndexedDBBackingStore::PutRecord");
if (!KeyPrefix::ValidIds(database_id, object_store_id))
@@ -1881,13 +1913,13 @@ leveldb::Status IndexedDBBackingStore::PutRecord(
std::string v;
EncodeVarInt(version, &v);
- v.append(value.bits);
+ v.append(value->bits);
leveldb_transaction->Put(object_store_data_key, &v);
s = transaction->PutBlobInfoIfNeeded(database_id,
object_store_id,
object_store_data_key,
- &value.blob_info,
+ &value->blob_info,
handles);
if (!s.ok())
return s;
@@ -1961,7 +1993,7 @@ leveldb::Status IndexedDBBackingStore::DeleteRange(
database_id,
object_store_id,
key_range,
- indexed_db::CURSOR_NEXT,
+ blink::WebIDBCursorDirectionNext,
&s);
if (!s.ok())
return s;
@@ -1973,7 +2005,7 @@ leveldb::Status IndexedDBBackingStore::DeleteRange(
database_id,
object_store_id,
key_range,
- indexed_db::CURSOR_PREV,
+ blink::WebIDBCursorDirectionPrev,
&s);
if (!s.ok())
@@ -2161,25 +2193,24 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
ChainedBlobWriterImpl(
int64 database_id,
IndexedDBBackingStore* backing_store,
- WriteDescriptorVec& blobs,
+ WriteDescriptorVec* blobs,
scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback)
: waiting_for_callback_(false),
database_id_(database_id),
backing_store_(backing_store),
callback_(callback),
aborted_(false) {
- blobs_.swap(blobs);
+ blobs_.swap(*blobs);
iter_ = blobs_.begin();
backing_store->task_runner()->PostTask(
FROM_HERE, base::Bind(&ChainedBlobWriterImpl::WriteNextFile, this));
}
- virtual void set_delegate(scoped_ptr<FileWriterDelegate> delegate) OVERRIDE {
+ void set_delegate(scoped_ptr<FileWriterDelegate> delegate) override {
delegate_.reset(delegate.release());
}
- virtual void ReportWriteCompletion(bool succeeded,
- int64 bytes_written) OVERRIDE {
+ void ReportWriteCompletion(bool succeeded, int64 bytes_written) override {
DCHECK(waiting_for_callback_);
DCHECK(!succeeded || bytes_written >= 0);
waiting_for_callback_ = false;
@@ -2200,7 +2231,7 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
}
}
- virtual void Abort() OVERRIDE {
+ void Abort() override {
if (!waiting_for_callback_)
return;
self_ref_ = this;
@@ -2208,13 +2239,13 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
}
private:
- virtual ~ChainedBlobWriterImpl() {}
+ ~ChainedBlobWriterImpl() override {}
void WriteNextFile() {
DCHECK(!waiting_for_callback_);
DCHECK(!aborted_);
if (iter_ == blobs_.end()) {
- DCHECK(!self_ref_);
+ DCHECK(!self_ref_.get());
callback_->Run(true);
return;
} else {
@@ -2240,11 +2271,11 @@ class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
};
class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
- public base::RefCounted<LocalWriteClosure> {
+ public base::RefCountedThreadSafe<LocalWriteClosure> {
public:
LocalWriteClosure(IndexedDBBackingStore::Transaction::ChainedBlobWriter*
chained_blob_writer,
- base::TaskRunner* task_runner)
+ base::SequencedTaskRunner* task_runner)
: chained_blob_writer_(chained_blob_writer),
task_runner_(task_runner),
bytes_written_(0) {}
@@ -2264,19 +2295,23 @@ class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
}
task_runner_->PostTask(
FROM_HERE,
- base::Bind(&LocalWriteClosure::callBlobCallbackOnIDBTaskRunner,
- this,
- write_status == FileWriterDelegate::SUCCESS_COMPLETED));
+ base::Bind(&IndexedDBBackingStore::Transaction::ChainedBlobWriter::
+ ReportWriteCompletion,
+ chained_blob_writer_,
+ write_status == FileWriterDelegate::SUCCESS_COMPLETED,
+ bytes_written_));
}
void writeBlobToFileOnIOThread(const FilePath& file_path,
const GURL& blob_url,
net::URLRequestContext* request_context) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- scoped_ptr<fileapi::FileStreamWriter> writer(
- fileapi::FileStreamWriter::CreateForLocalFile(
- task_runner_, file_path, 0,
- fileapi::FileStreamWriter::CREATE_NEW_FILE));
+ scoped_ptr<storage::FileStreamWriter> writer(
+ storage::FileStreamWriter::CreateForLocalFile(
+ task_runner_.get(),
+ file_path,
+ 0,
+ storage::FileStreamWriter::CREATE_NEW_FILE));
scoped_ptr<FileWriterDelegate> delegate(
new FileWriterDelegate(writer.Pass(),
FileWriterDelegate::FLUSH_ON_COMPLETION));
@@ -2291,16 +2326,21 @@ class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
}
private:
- virtual ~LocalWriteClosure() {}
- friend class base::RefCounted<LocalWriteClosure>;
-
- void callBlobCallbackOnIDBTaskRunner(bool succeeded) {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
- chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_);
+ virtual ~LocalWriteClosure() {
+ // Make sure the last reference to a ChainedBlobWriter is released (and
+ // deleted) on the IDB thread since it owns a transaction which has thread
+ // affinity.
+ IndexedDBBackingStore::Transaction::ChainedBlobWriter* raw_tmp =
+ chained_blob_writer_.get();
+ raw_tmp->AddRef();
+ chained_blob_writer_ = NULL;
+ task_runner_->ReleaseSoon(FROM_HERE, raw_tmp);
}
+ friend class base::RefCountedThreadSafe<LocalWriteClosure>;
- IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_;
- base::TaskRunner* task_runner_;
+ scoped_refptr<IndexedDBBackingStore::Transaction::ChainedBlobWriter>
+ chained_blob_writer_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
int64 bytes_written_;
DISALLOW_COPY_AND_ASSIGN(LocalWriteClosure);
@@ -2348,7 +2388,7 @@ bool IndexedDBBackingStore::WriteBlobFile(
} else {
DCHECK(descriptor.url().is_valid());
scoped_refptr<LocalWriteClosure> write_closure(
- new LocalWriteClosure(chained_blob_writer, task_runner_));
+ new LocalWriteClosure(chained_blob_writer, task_runner_.get()));
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
@@ -2582,11 +2622,9 @@ leveldb::Status IndexedDBBackingStore::CleanUpBlobJournal(
return s;
if (!journal.size())
return leveldb::Status::OK();
- BlobJournalType::iterator journal_iter;
- for (journal_iter = journal.begin(); journal_iter != journal.end();
- ++journal_iter) {
- int64 database_id = journal_iter->first;
- int64 blob_key = journal_iter->second;
+ for (const auto& entry : journal) {
+ int64 database_id = entry.first;
+ int64 blob_key = entry.second;
DCHECK(KeyPrefix::IsValidDatabaseId(database_id));
if (blob_key == DatabaseMetaDataKey::kAllBlobsKey) {
if (!RemoveBlobDirectory(database_id))
@@ -2630,34 +2668,33 @@ leveldb::Status IndexedDBBackingStore::Transaction::GetBlobInfoForRecord(
NOTREACHED();
return InternalInconsistencyStatus();
}
- scoped_ptr<LevelDBIterator> it = transaction()->CreateIterator();
std::string encoded_key = blob_entry_key.Encode();
- leveldb::Status s = it->Seek(encoded_key);
+ bool found;
+ std::string encoded_value;
+ leveldb::Status s = transaction()->Get(encoded_key, &encoded_value, &found);
if (!s.ok())
return s;
- if (it->IsValid() && CompareKeys(it->Key(), encoded_key) == 0) {
- if (!DecodeBlobData(it->Value().as_string(), &value->blob_info)) {
+ if (found) {
+ if (!DecodeBlobData(encoded_value, &value->blob_info)) {
INTERNAL_READ_ERROR(GET_BLOB_INFO_FOR_RECORD);
return InternalInconsistencyStatus();
}
- std::vector<IndexedDBBlobInfo>::iterator iter;
- for (iter = value->blob_info.begin(); iter != value->blob_info.end();
- ++iter) {
- iter->set_file_path(
- backing_store_->GetBlobFileName(database_id, iter->key()));
- iter->set_mark_used_callback(
+ for (auto& entry : value->blob_info) {
+ entry.set_file_path(
+ backing_store_->GetBlobFileName(database_id, entry.key()));
+ entry.set_mark_used_callback(
backing_store_->active_blob_registry()->GetAddBlobRefCallback(
- database_id, iter->key()));
- iter->set_release_callback(
+ database_id, entry.key()));
+ entry.set_release_callback(
backing_store_->active_blob_registry()->GetFinalReleaseCallback(
- database_id, iter->key()));
- if (iter->is_file()) {
+ database_id, entry.key()));
+ if (entry.is_file()) {
base::File::Info info;
- if (base::GetFileInfo(iter->file_path(), &info)) {
+ if (base::GetFileInfo(entry.file_path(), &info)) {
// This should always work, but it isn't fatal if it doesn't; it just
// means a potential slow synchronous call from the renderer later.
- iter->set_last_modified(info.last_modified);
- iter->set_size(info.size);
+ entry.set_last_modified(info.last_modified);
+ entry.set_size(info.size);
}
}
}
@@ -2797,21 +2834,21 @@ leveldb::Status IndexedDBBackingStore::PutIndexDataForRecord(
static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction,
const std::string& target,
std::string* found_key,
- leveldb::Status& s) {
+ leveldb::Status* s) {
scoped_ptr<LevelDBIterator> it = transaction->CreateIterator();
- s = it->Seek(target);
- if (!s.ok())
+ *s = it->Seek(target);
+ if (!s->ok())
return false;
if (!it->IsValid()) {
- s = it->SeekToLast();
- if (!s.ok() || !it->IsValid())
+ *s = it->SeekToLast();
+ if (!s->ok() || !it->IsValid())
return false;
}
while (CompareIndexKeys(it->Key(), target) > 0) {
- s = it->Prev();
- if (!s.ok() || !it->IsValid())
+ *s = it->Prev();
+ if (!s->ok() || !it->IsValid())
return false;
}
@@ -2819,8 +2856,8 @@ static bool FindGreatestKeyLessThanOrEqual(LevelDBTransaction* transaction,
*found_key = it->Key().as_string();
// There can be several index keys that compare equal. We want the last one.
- s = it->Next();
- } while (s.ok() && it->IsValid() && !CompareIndexKeys(it->Key(), target));
+ *s = it->Next();
+ } while (s->ok() && it->IsValid() && !CompareIndexKeys(it->Key(), target));
return true;
}
@@ -3010,7 +3047,7 @@ IndexedDBBackingStore::Cursor::Cursor(
IndexedDBBackingStore::Transaction* transaction,
int64 database_id,
const CursorOptions& cursor_options)
- : backing_store_(backing_store),
+ : backing_store_(backing_store.get()),
transaction_(transaction),
database_id_(database_id),
cursor_options_(cursor_options) {
@@ -3049,19 +3086,20 @@ bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
// TODO(alecflett): avoid a copy here?
IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey();
- bool first_iteration = true;
-
// When iterating with PrevNoDuplicate, spec requires that the
// value we yield for each key is the first duplicate in forwards
// order.
IndexedDBKey last_duplicate_key;
bool forward = cursor_options_.forward;
+ bool first_iteration_forward = forward;
+ bool flipped = false;
for (;;) {
if (next_state == SEEK) {
// TODO(jsbell): Optimize seeking for reverse cursors as well.
- if (first_iteration && key && forward) {
+ if (first_iteration_forward && key) {
+ first_iteration_forward = false;
std::string leveldb_key;
if (primary_key) {
leveldb_key = EncodeKey(*key, *primary_key);
@@ -3069,7 +3107,6 @@ bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
leveldb_key = EncodeKey(*key);
}
*s = iterator_->Seek(leveldb_key);
- first_iteration = false;
} else if (forward) {
*s = iterator_->Next();
} else {
@@ -3086,6 +3123,7 @@ bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
// We need to walk forward because we hit the end of
// the data.
forward = true;
+ flipped = true;
continue;
}
@@ -3097,6 +3135,7 @@ bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
// We need to walk forward because now we're beyond the
// bounds defined by the cursor.
forward = true;
+ flipped = true;
continue;
}
@@ -3116,7 +3155,7 @@ bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
if (primary_key && current_key_->Equals(*key) &&
this->primary_key().IsLessThan(*primary_key))
continue;
- if (current_key_->IsLessThan(*key))
+ if (!flipped && current_key_->IsLessThan(*key))
continue;
} else {
if (primary_key && key->Equals(*current_key_) &&
@@ -3145,6 +3184,7 @@ bool IndexedDBBackingStore::Cursor::Continue(const IndexedDBKey* key,
// between key ranges.
if (!last_duplicate_key.Equals(*current_key_)) {
forward = true;
+ flipped = true;
continue;
}
@@ -3210,24 +3250,22 @@ class ObjectStoreKeyCursorImpl : public IndexedDBBackingStore::Cursor {
database_id,
cursor_options) {}
- virtual Cursor* Clone() OVERRIDE {
- return new ObjectStoreKeyCursorImpl(this);
- }
+ Cursor* Clone() override { return new ObjectStoreKeyCursorImpl(this); }
// IndexedDBBackingStore::Cursor
- virtual IndexedDBValue* value() OVERRIDE {
+ IndexedDBValue* value() override {
NOTREACHED();
return NULL;
}
- virtual bool LoadCurrentRow() OVERRIDE;
+ bool LoadCurrentRow() override;
protected:
- virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
+ std::string EncodeKey(const IndexedDBKey& key) override {
return ObjectStoreDataKey::Encode(
cursor_options_.database_id, cursor_options_.object_store_id, key);
}
- virtual std::string EncodeKey(const IndexedDBKey& key,
- const IndexedDBKey& primary_key) OVERRIDE {
+ std::string EncodeKey(const IndexedDBKey& key,
+ const IndexedDBKey& primary_key) override {
NOTREACHED();
return std::string();
}
@@ -3276,19 +3314,19 @@ class ObjectStoreCursorImpl : public IndexedDBBackingStore::Cursor {
database_id,
cursor_options) {}
- virtual Cursor* Clone() OVERRIDE { return new ObjectStoreCursorImpl(this); }
+ Cursor* Clone() override { return new ObjectStoreCursorImpl(this); }
// IndexedDBBackingStore::Cursor
- virtual IndexedDBValue* value() OVERRIDE { return &current_value_; }
- virtual bool LoadCurrentRow() OVERRIDE;
+ IndexedDBValue* value() override { return &current_value_; }
+ bool LoadCurrentRow() override;
protected:
- virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
+ std::string EncodeKey(const IndexedDBKey& key) override {
return ObjectStoreDataKey::Encode(
cursor_options_.database_id, cursor_options_.object_store_id, key);
}
- virtual std::string EncodeKey(const IndexedDBKey& key,
- const IndexedDBKey& primary_key) OVERRIDE {
+ std::string EncodeKey(const IndexedDBKey& key,
+ const IndexedDBKey& primary_key) override {
NOTREACHED();
return std::string();
}
@@ -3346,32 +3384,30 @@ class IndexKeyCursorImpl : public IndexedDBBackingStore::Cursor {
database_id,
cursor_options) {}
- virtual Cursor* Clone() OVERRIDE { return new IndexKeyCursorImpl(this); }
+ Cursor* Clone() override { return new IndexKeyCursorImpl(this); }
// IndexedDBBackingStore::Cursor
- virtual IndexedDBValue* value() OVERRIDE {
+ IndexedDBValue* value() override {
NOTREACHED();
return NULL;
}
- virtual const IndexedDBKey& primary_key() const OVERRIDE {
- return *primary_key_;
- }
- virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier()
- const OVERRIDE {
+ const IndexedDBKey& primary_key() const override { return *primary_key_; }
+ const IndexedDBBackingStore::RecordIdentifier& record_identifier()
+ const override {
NOTREACHED();
return record_identifier_;
}
- virtual bool LoadCurrentRow() OVERRIDE;
+ bool LoadCurrentRow() override;
protected:
- virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
+ std::string EncodeKey(const IndexedDBKey& key) override {
return IndexDataKey::Encode(cursor_options_.database_id,
cursor_options_.object_store_id,
cursor_options_.index_id,
key);
}
- virtual std::string EncodeKey(const IndexedDBKey& key,
- const IndexedDBKey& primary_key) OVERRIDE {
+ std::string EncodeKey(const IndexedDBKey& key,
+ const IndexedDBKey& primary_key) override {
return IndexDataKey::Encode(cursor_options_.database_id,
cursor_options_.object_store_id,
cursor_options_.index_id,
@@ -3461,29 +3497,27 @@ class IndexCursorImpl : public IndexedDBBackingStore::Cursor {
database_id,
cursor_options) {}
- virtual Cursor* Clone() OVERRIDE { return new IndexCursorImpl(this); }
+ Cursor* Clone() override { return new IndexCursorImpl(this); }
// IndexedDBBackingStore::Cursor
- virtual IndexedDBValue* value() OVERRIDE { return &current_value_; }
- virtual const IndexedDBKey& primary_key() const OVERRIDE {
- return *primary_key_;
- }
- virtual const IndexedDBBackingStore::RecordIdentifier& record_identifier()
- const OVERRIDE {
+ IndexedDBValue* value() override { return &current_value_; }
+ const IndexedDBKey& primary_key() const override { return *primary_key_; }
+ const IndexedDBBackingStore::RecordIdentifier& record_identifier()
+ const override {
NOTREACHED();
return record_identifier_;
}
- virtual bool LoadCurrentRow() OVERRIDE;
+ bool LoadCurrentRow() override;
protected:
- virtual std::string EncodeKey(const IndexedDBKey& key) OVERRIDE {
+ std::string EncodeKey(const IndexedDBKey& key) override {
return IndexDataKey::Encode(cursor_options_.database_id,
cursor_options_.object_store_id,
cursor_options_.index_id,
key);
}
- virtual std::string EncodeKey(const IndexedDBKey& key,
- const IndexedDBKey& primary_key) OVERRIDE {
+ std::string EncodeKey(const IndexedDBKey& key,
+ const IndexedDBKey& primary_key) override {
return IndexDataKey::Encode(cursor_options_.database_id,
cursor_options_.object_store_id,
cursor_options_.index_id,
@@ -3573,7 +3607,7 @@ bool ObjectStoreCursorOptions(
int64 database_id,
int64 object_store_id,
const IndexedDBKeyRange& range,
- indexed_db::CursorDirection direction,
+ blink::WebIDBCursorDirection direction,
IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) {
cursor_options->database_id = database_id;
cursor_options->object_store_id = object_store_id;
@@ -3581,10 +3615,11 @@ bool ObjectStoreCursorOptions(
bool lower_bound = range.lower().IsValid();
bool upper_bound = range.upper().IsValid();
cursor_options->forward =
- (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
- direction == indexed_db::CURSOR_NEXT);
- cursor_options->unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
- direction == indexed_db::CURSOR_PREV_NO_DUPLICATE);
+ (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
+ direction == blink::WebIDBCursorDirectionNext);
+ cursor_options->unique =
+ (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
+ direction == blink::WebIDBCursorDirectionPrevNoDuplicate);
if (!lower_bound) {
cursor_options->low_key =
@@ -3610,7 +3645,7 @@ bool ObjectStoreCursorOptions(
if (!FindGreatestKeyLessThanOrEqual(transaction,
cursor_options->high_key,
&cursor_options->high_key,
- s))
+ &s))
return false;
cursor_options->high_open = false;
}
@@ -3624,7 +3659,7 @@ bool ObjectStoreCursorOptions(
std::string found_high_key;
// TODO(cmumford): Handle this error (crbug.com/363397)
if (!FindGreatestKeyLessThanOrEqual(
- transaction, cursor_options->high_key, &found_high_key, s))
+ transaction, cursor_options->high_key, &found_high_key, &s))
return false;
// If the target key should not be included, but we end up with a smaller
@@ -3646,7 +3681,7 @@ bool IndexCursorOptions(
int64 object_store_id,
int64 index_id,
const IndexedDBKeyRange& range,
- indexed_db::CursorDirection direction,
+ blink::WebIDBCursorDirection direction,
IndexedDBBackingStore::Cursor::CursorOptions* cursor_options) {
DCHECK(transaction);
if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id))
@@ -3659,10 +3694,11 @@ bool IndexCursorOptions(
bool lower_bound = range.lower().IsValid();
bool upper_bound = range.upper().IsValid();
cursor_options->forward =
- (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
- direction == indexed_db::CURSOR_NEXT);
- cursor_options->unique = (direction == indexed_db::CURSOR_NEXT_NO_DUPLICATE ||
- direction == indexed_db::CURSOR_PREV_NO_DUPLICATE);
+ (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
+ direction == blink::WebIDBCursorDirectionNext);
+ cursor_options->unique =
+ (direction == blink::WebIDBCursorDirectionNextNoDuplicate ||
+ direction == blink::WebIDBCursorDirectionPrevNoDuplicate);
if (!lower_bound) {
cursor_options->low_key =
@@ -3685,7 +3721,7 @@ bool IndexCursorOptions(
if (!FindGreatestKeyLessThanOrEqual(transaction,
cursor_options->high_key,
&cursor_options->high_key,
- s))
+ &s))
return false;
cursor_options->high_open = false;
}
@@ -3698,7 +3734,7 @@ bool IndexCursorOptions(
// Seek to the *last* key in the set of non-unique keys
// TODO(cmumford): Handle this error (crbug.com/363397)
if (!FindGreatestKeyLessThanOrEqual(
- transaction, cursor_options->high_key, &found_high_key, s))
+ transaction, cursor_options->high_key, &found_high_key, &s))
return false;
// If the target key should not be included, but we end up with a smaller
@@ -3719,7 +3755,7 @@ IndexedDBBackingStore::OpenObjectStoreCursor(
int64 database_id,
int64 object_store_id,
const IndexedDBKeyRange& range,
- indexed_db::CursorDirection direction,
+ blink::WebIDBCursorDirection direction,
leveldb::Status* s) {
IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreCursor");
*s = leveldb::Status::OK();
@@ -3737,7 +3773,7 @@ IndexedDBBackingStore::OpenObjectStoreCursor(
if (!cursor->FirstSeek(s))
return scoped_ptr<IndexedDBBackingStore::Cursor>();
- return cursor.PassAs<IndexedDBBackingStore::Cursor>();
+ return cursor.Pass();
}
scoped_ptr<IndexedDBBackingStore::Cursor>
@@ -3746,7 +3782,7 @@ IndexedDBBackingStore::OpenObjectStoreKeyCursor(
int64 database_id,
int64 object_store_id,
const IndexedDBKeyRange& range,
- indexed_db::CursorDirection direction,
+ blink::WebIDBCursorDirection direction,
leveldb::Status* s) {
IDB_TRACE("IndexedDBBackingStore::OpenObjectStoreKeyCursor");
*s = leveldb::Status::OK();
@@ -3764,7 +3800,7 @@ IndexedDBBackingStore::OpenObjectStoreKeyCursor(
if (!cursor->FirstSeek(s))
return scoped_ptr<IndexedDBBackingStore::Cursor>();
- return cursor.PassAs<IndexedDBBackingStore::Cursor>();
+ return cursor.Pass();
}
scoped_ptr<IndexedDBBackingStore::Cursor>
@@ -3774,7 +3810,7 @@ IndexedDBBackingStore::OpenIndexKeyCursor(
int64 object_store_id,
int64 index_id,
const IndexedDBKeyRange& range,
- indexed_db::CursorDirection direction,
+ blink::WebIDBCursorDirection direction,
leveldb::Status* s) {
IDB_TRACE("IndexedDBBackingStore::OpenIndexKeyCursor");
*s = leveldb::Status::OK();
@@ -3793,7 +3829,7 @@ IndexedDBBackingStore::OpenIndexKeyCursor(
if (!cursor->FirstSeek(s))
return scoped_ptr<IndexedDBBackingStore::Cursor>();
- return cursor.PassAs<IndexedDBBackingStore::Cursor>();
+ return cursor.Pass();
}
scoped_ptr<IndexedDBBackingStore::Cursor>
@@ -3803,7 +3839,7 @@ IndexedDBBackingStore::OpenIndexCursor(
int64 object_store_id,
int64 index_id,
const IndexedDBKeyRange& range,
- indexed_db::CursorDirection direction,
+ blink::WebIDBCursorDirection direction,
leveldb::Status* s) {
IDB_TRACE("IndexedDBBackingStore::OpenIndexCursor");
LevelDBTransaction* leveldb_transaction = transaction->transaction();
@@ -3821,7 +3857,7 @@ IndexedDBBackingStore::OpenIndexCursor(
if (!cursor->FirstSeek(s))
return scoped_ptr<IndexedDBBackingStore::Cursor>();
- return cursor.PassAs<IndexedDBBackingStore::Cursor>();
+ return cursor.Pass();
}
IndexedDBBackingStore::Transaction::Transaction(
@@ -3844,11 +3880,8 @@ void IndexedDBBackingStore::Transaction::Begin() {
// If incognito, this snapshots blobs just as the above transaction_
// constructor snapshots the leveldb.
- BlobChangeMap::const_iterator iter;
- for (iter = backing_store_->incognito_blob_map_.begin();
- iter != backing_store_->incognito_blob_map_.end();
- ++iter)
- incognito_blob_map_[iter->first] = iter->second->Clone().release();
+ for (const auto& iter : backing_store_->incognito_blob_map_)
+ incognito_blob_map_[iter.first] = iter.second->Clone().release();
}
static GURL getURLFromUUID(const string& uuid) {
@@ -3861,21 +3894,17 @@ leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction(
if (backing_store_->is_incognito())
return leveldb::Status::OK();
- BlobChangeMap::iterator iter = blob_change_map_.begin();
new_blob_entries->clear();
new_files_to_write->clear();
- if (iter != blob_change_map_.end()) {
+ if (!blob_change_map_.empty()) {
// Create LevelDBTransaction for the name generator seed and add-journal.
scoped_refptr<LevelDBTransaction> pre_transaction =
IndexedDBClassFactory::Get()->CreateLevelDBTransaction(
backing_store_->db_.get());
BlobJournalType journal;
- for (; iter != blob_change_map_.end(); ++iter) {
- std::vector<IndexedDBBlobInfo>::iterator info_iter;
+ for (auto& iter : blob_change_map_) {
std::vector<IndexedDBBlobInfo*> new_blob_keys;
- for (info_iter = iter->second->mutable_blob_info().begin();
- info_iter != iter->second->mutable_blob_info().end();
- ++info_iter) {
+ for (auto& entry : iter.second->mutable_blob_info()) {
int64 next_blob_key = -1;
bool result = GetBlobKeyGeneratorCurrentNumber(
pre_transaction.get(), database_id_, &next_blob_key);
@@ -3884,27 +3913,27 @@ leveldb::Status IndexedDBBackingStore::Transaction::HandleBlobPreTransaction(
BlobJournalEntryType journal_entry =
std::make_pair(database_id_, next_blob_key);
journal.push_back(journal_entry);
- if (info_iter->is_file()) {
+ if (entry.is_file()) {
new_files_to_write->push_back(
- WriteDescriptor(info_iter->file_path(),
+ WriteDescriptor(entry.file_path(),
next_blob_key,
- info_iter->size(),
- info_iter->last_modified()));
+ entry.size(),
+ entry.last_modified()));
} else {
new_files_to_write->push_back(
- WriteDescriptor(getURLFromUUID(info_iter->uuid()),
+ WriteDescriptor(getURLFromUUID(entry.uuid()),
next_blob_key,
- info_iter->size()));
+ entry.size()));
}
- info_iter->set_key(next_blob_key);
- new_blob_keys.push_back(&*info_iter);
+ entry.set_key(next_blob_key);
+ new_blob_keys.push_back(&entry);
result = UpdateBlobKeyGeneratorCurrentNumber(
pre_transaction.get(), database_id_, next_blob_key + 1);
if (!result)
return InternalInconsistencyStatus();
}
BlobEntryKey blob_entry_key;
- StringPiece key_piece(iter->second->key());
+ StringPiece key_piece(iter.second->key());
if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
NOTREACHED();
return InternalInconsistencyStatus();
@@ -3924,40 +3953,35 @@ bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() {
if (backing_store_->is_incognito())
return true;
- BlobChangeMap::const_iterator iter = blob_change_map_.begin();
// Look up all old files to remove as part of the transaction, store their
// names in blobs_to_remove_, and remove their old blob data entries.
- if (iter != blob_change_map_.end()) {
- scoped_ptr<LevelDBIterator> db_iter = transaction_->CreateIterator();
- for (; iter != blob_change_map_.end(); ++iter) {
- BlobEntryKey blob_entry_key;
- StringPiece key_piece(iter->second->key());
- if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
- NOTREACHED();
- INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
+ for (const auto& iter : blob_change_map_) {
+ BlobEntryKey blob_entry_key;
+ StringPiece key_piece(iter.second->key());
+ if (!BlobEntryKey::FromObjectStoreDataKey(&key_piece, &blob_entry_key)) {
+ NOTREACHED();
+ INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
+ transaction_ = NULL;
+ return false;
+ }
+ if (database_id_ < 0)
+ database_id_ = blob_entry_key.database_id();
+ else
+ DCHECK_EQ(database_id_, blob_entry_key.database_id());
+ std::string blob_entry_key_bytes = blob_entry_key.Encode();
+ bool found;
+ std::string blob_entry_value_bytes;
+ leveldb::Status s = transaction_->Get(
+ blob_entry_key_bytes, &blob_entry_value_bytes, &found);
+ if (s.ok() && found) {
+ std::vector<IndexedDBBlobInfo> blob_info;
+ if (!DecodeBlobData(blob_entry_value_bytes, &blob_info)) {
+ INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
transaction_ = NULL;
return false;
}
- if (database_id_ < 0)
- database_id_ = blob_entry_key.database_id();
- else
- DCHECK_EQ(database_id_, blob_entry_key.database_id());
- std::string blob_entry_key_bytes = blob_entry_key.Encode();
- db_iter->Seek(blob_entry_key_bytes);
- if (db_iter->IsValid() &&
- !CompareKeys(db_iter->Key(), blob_entry_key_bytes)) {
- std::vector<IndexedDBBlobInfo> blob_info;
- if (!DecodeBlobData(db_iter->Value().as_string(), &blob_info)) {
- INTERNAL_READ_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
- transaction_ = NULL;
- return false;
- }
- std::vector<IndexedDBBlobInfo>::iterator blob_info_iter;
- for (blob_info_iter = blob_info.begin();
- blob_info_iter != blob_info.end();
- ++blob_info_iter)
- blobs_to_remove_.push_back(
- std::make_pair(database_id_, blob_info_iter->key()));
+ for (const auto& blob : blob_info) {
+ blobs_to_remove_.push_back(std::make_pair(database_id_, blob.key()));
transaction_->Remove(blob_entry_key_bytes);
}
}
@@ -3968,14 +3992,12 @@ bool IndexedDBBackingStore::Transaction::CollectBlobFilesToRemove() {
leveldb::Status IndexedDBBackingStore::Transaction::SortBlobsToRemove() {
IndexedDBActiveBlobRegistry* registry =
backing_store_->active_blob_registry();
- BlobJournalType::iterator iter;
BlobJournalType primary_journal, live_blob_journal;
- for (iter = blobs_to_remove_.begin(); iter != blobs_to_remove_.end();
- ++iter) {
- if (registry->MarkDeletedCheckIfUsed(iter->first, iter->second))
- live_blob_journal.push_back(*iter);
+ for (const auto& iter : blobs_to_remove_) {
+ if (registry->MarkDeletedCheckIfUsed(iter.first, iter.second))
+ live_blob_journal.push_back(iter);
else
- primary_journal.push_back(*iter);
+ primary_journal.push_back(iter);
}
UpdatePrimaryJournalWithBlobList(transaction_.get(), primary_journal);
leveldb::Status s =
@@ -3990,14 +4012,14 @@ leveldb::Status IndexedDBBackingStore::Transaction::SortBlobsToRemove() {
leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
scoped_refptr<BlobWriteCallback> callback) {
IDB_TRACE("IndexedDBBackingStore::Transaction::CommitPhaseOne");
- DCHECK(transaction_);
+ DCHECK(transaction_.get());
DCHECK(backing_store_->task_runner()->RunsTasksOnCurrentThread());
leveldb::Status s;
s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
if (!s.ok()) {
- INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
+ INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
transaction_ = NULL;
return s;
}
@@ -4022,7 +4044,7 @@ leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseOne(
if (new_files_to_write.size()) {
// This kicks off the writes of the new blobs, if any.
// This call will zero out new_blob_entries and new_files_to_write.
- WriteNewBlobs(new_blob_entries, new_files_to_write, callback);
+ WriteNewBlobs(&new_blob_entries, &new_files_to_write, callback);
// Remove the add journal, if any; once the blobs are written, and we
// commit, this will do the cleanup.
ClearBlobJournal(transaction_.get(), BlobJournalKey::Encode());
@@ -4050,22 +4072,20 @@ leveldb::Status IndexedDBBackingStore::Transaction::CommitPhaseTwo() {
if (s.ok() && backing_store_->is_incognito() && !blob_change_map_.empty()) {
BlobChangeMap& target_map = backing_store_->incognito_blob_map_;
- BlobChangeMap::iterator iter;
- for (iter = blob_change_map_.begin(); iter != blob_change_map_.end();
- ++iter) {
- BlobChangeMap::iterator target_record = target_map.find(iter->first);
+ for (auto& iter : blob_change_map_) {
+ BlobChangeMap::iterator target_record = target_map.find(iter.first);
if (target_record != target_map.end()) {
delete target_record->second;
target_map.erase(target_record);
}
- if (iter->second) {
- target_map[iter->first] = iter->second;
- iter->second = NULL;
+ if (iter.second) {
+ target_map[iter.first] = iter.second;
+ iter.second = NULL;
}
}
}
if (!s.ok())
- INTERNAL_WRITE_ERROR_UNTESTED(TRANSACTION_COMMIT_METHOD);
+ INTERNAL_WRITE_ERROR(TRANSACTION_COMMIT_METHOD);
else if (blobs_to_remove_.size())
s = backing_store_->CleanUpBlobJournal(BlobJournalKey::Encode());
@@ -4079,14 +4099,14 @@ class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper
BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction,
scoped_refptr<BlobWriteCallback> callback)
: transaction_(transaction), callback_(callback) {}
- virtual void Run(bool succeeded) OVERRIDE {
+ void Run(bool succeeded) override {
callback_->Run(succeeded);
if (succeeded) // Else it's already been deleted during rollback.
transaction_->chained_blob_writer_ = NULL;
}
private:
- virtual ~BlobWriteCallbackWrapper() {}
+ ~BlobWriteCallbackWrapper() override {}
friend class base::RefCounted<IndexedDBBackingStore::BlobWriteCallback>;
IndexedDBBackingStore::Transaction* transaction_;
@@ -4096,22 +4116,19 @@ class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper
};
void IndexedDBBackingStore::Transaction::WriteNewBlobs(
- BlobEntryKeyValuePairVec& new_blob_entries,
- WriteDescriptorVec& new_files_to_write,
+ BlobEntryKeyValuePairVec* new_blob_entries,
+ WriteDescriptorVec* new_files_to_write,
scoped_refptr<BlobWriteCallback> callback) {
- DCHECK_GT(new_files_to_write.size(), 0UL);
+ DCHECK_GT(new_files_to_write->size(), 0UL);
DCHECK_GT(database_id_, 0);
- BlobEntryKeyValuePairVec::iterator blob_entry_iter;
- for (blob_entry_iter = new_blob_entries.begin();
- blob_entry_iter != new_blob_entries.end();
- ++blob_entry_iter) {
+ for (auto& blob_entry_iter : *new_blob_entries) {
// Add the new blob-table entry for each blob to the main transaction, or
// remove any entry that may exist if there's no new one.
- if (!blob_entry_iter->second.size())
- transaction_->Remove(blob_entry_iter->first.Encode());
+ if (!blob_entry_iter.second.size())
+ transaction_->Remove(blob_entry_iter.first.Encode());
else
- transaction_->Put(blob_entry_iter->first.Encode(),
- &blob_entry_iter->second);
+ transaction_->Put(blob_entry_iter.first.Encode(),
+ &blob_entry_iter.second);
}
// Creating the writer will start it going asynchronously.
chained_blob_writer_ =
@@ -4123,11 +4140,12 @@ void IndexedDBBackingStore::Transaction::WriteNewBlobs(
void IndexedDBBackingStore::Transaction::Rollback() {
IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback");
- DCHECK(transaction_.get());
- if (chained_blob_writer_) {
+ if (chained_blob_writer_.get()) {
chained_blob_writer_->Abort();
chained_blob_writer_ = NULL;
}
+ if (transaction_.get() == NULL)
+ return;
transaction_->Rollback();
transaction_ = NULL;
}
@@ -4149,7 +4167,7 @@ void IndexedDBBackingStore::BlobChangeRecord::SetBlobInfo(
}
void IndexedDBBackingStore::BlobChangeRecord::SetHandles(
- ScopedVector<webkit_blob::BlobDataHandle>* handles) {
+ ScopedVector<storage::BlobDataHandle>* handles) {
handles_.clear();
if (handles)
handles_.swap(*handles);
@@ -4161,9 +4179,8 @@ IndexedDBBackingStore::BlobChangeRecord::Clone() const {
new BlobChangeRecord(key_, object_store_id_));
record->blob_info_ = blob_info_;
- ScopedVector<webkit_blob::BlobDataHandle>::const_iterator iter;
- for (iter = handles_.begin(); iter != handles_.end(); ++iter)
- record->handles_.push_back(new webkit_blob::BlobDataHandle(**iter));
+ for (const auto* handle : handles_)
+ record->handles_.push_back(new storage::BlobDataHandle(*handle));
return record.Pass();
}
@@ -4172,7 +4189,7 @@ leveldb::Status IndexedDBBackingStore::Transaction::PutBlobInfoIfNeeded(
int64 object_store_id,
const std::string& object_store_data_key,
std::vector<IndexedDBBlobInfo>* blob_info,
- ScopedVector<webkit_blob::BlobDataHandle>* handles) {
+ ScopedVector<storage::BlobDataHandle>* handles) {
if (!blob_info || blob_info->empty()) {
blob_change_map_.erase(object_store_data_key);
incognito_blob_map_.erase(object_store_data_key);
@@ -4207,7 +4224,7 @@ void IndexedDBBackingStore::Transaction::PutBlobInfo(
int64 object_store_id,
const std::string& object_store_data_key,
std::vector<IndexedDBBlobInfo>* blob_info,
- ScopedVector<webkit_blob::BlobDataHandle>* handles) {
+ ScopedVector<storage::BlobDataHandle>* handles) {
DCHECK_GT(object_store_data_key.size(), 0UL);
if (database_id_ < 0)
database_id_ = database_id;
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 59e381f2fef..a15b2372a6b 100644
--- a/chromium/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/chromium/content/browser/indexed_db/indexed_db_backing_store.h
@@ -29,15 +29,15 @@
#include "content/common/indexed_db/indexed_db_key.h"
#include "content/common/indexed_db/indexed_db_key_path.h"
#include "content/common/indexed_db/indexed_db_key_range.h"
+#include "storage/browser/blob/blob_data_handle.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
#include "url/gurl.h"
-#include "webkit/browser/blob/blob_data_handle.h"
namespace base {
-class TaskRunner;
+class SequencedTaskRunner;
}
-namespace fileapi {
+namespace storage {
class FileWriterDelegate;
}
@@ -50,33 +50,255 @@ namespace content {
class IndexedDBFactory;
class LevelDBComparator;
class LevelDBDatabase;
+class LevelDBFactory;
struct IndexedDBValue;
-class LevelDBFactory {
- public:
- virtual ~LevelDBFactory() {}
- virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name,
- const LevelDBComparator* comparator,
- scoped_ptr<LevelDBDatabase>* db,
- bool* is_disk_full) = 0;
- virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) = 0;
-};
-
class CONTENT_EXPORT IndexedDBBackingStore
: public base::RefCounted<IndexedDBBackingStore> {
public:
- class CONTENT_EXPORT Transaction;
-
class CONTENT_EXPORT Comparator : public LevelDBComparator {
public:
- virtual int Compare(const base::StringPiece& a,
- const base::StringPiece& b) const OVERRIDE;
- virtual const char* Name() const OVERRIDE;
+ int Compare(const base::StringPiece& a,
+ const base::StringPiece& b) const override;
+ const char* Name() const override;
+ };
+
+ class CONTENT_EXPORT RecordIdentifier {
+ public:
+ RecordIdentifier(const std::string& primary_key, int64 version);
+ RecordIdentifier();
+ ~RecordIdentifier();
+
+ const std::string& primary_key() const { return primary_key_; }
+ int64 version() const { return version_; }
+ void Reset(const std::string& primary_key, int64 version) {
+ primary_key_ = primary_key;
+ version_ = version;
+ }
+
+ private:
+ // TODO(jsbell): Make it more clear that this is the *encoded* version of
+ // the key.
+ std::string primary_key_;
+ int64 version_;
+ DISALLOW_COPY_AND_ASSIGN(RecordIdentifier);
+ };
+
+ class BlobWriteCallback : public base::RefCounted<BlobWriteCallback> {
+ public:
+ virtual void Run(bool succeeded) = 0;
+
+ protected:
+ friend class base::RefCounted<BlobWriteCallback>;
+ virtual ~BlobWriteCallback() {}
+ };
+
+ class BlobChangeRecord {
+ public:
+ BlobChangeRecord(const std::string& key, int64 object_store_id);
+ ~BlobChangeRecord();
+
+ const std::string& key() const { return key_; }
+ int64 object_store_id() const { return object_store_id_; }
+ void SetBlobInfo(std::vector<IndexedDBBlobInfo>* blob_info);
+ std::vector<IndexedDBBlobInfo>& mutable_blob_info() { return blob_info_; }
+ const std::vector<IndexedDBBlobInfo>& blob_info() const {
+ return blob_info_;
+ }
+ void SetHandles(ScopedVector<storage::BlobDataHandle>* handles);
+ scoped_ptr<BlobChangeRecord> Clone() const;
+
+ private:
+ std::string key_;
+ int64 object_store_id_;
+ std::vector<IndexedDBBlobInfo> blob_info_;
+ ScopedVector<storage::BlobDataHandle> handles_;
+ DISALLOW_COPY_AND_ASSIGN(BlobChangeRecord);
+ };
+ typedef std::map<std::string, BlobChangeRecord*> BlobChangeMap;
+
+ class CONTENT_EXPORT Transaction {
+ public:
+ explicit Transaction(IndexedDBBackingStore* backing_store);
+ virtual ~Transaction();
+
+ virtual void Begin();
+ // The callback will be called eventually on success or failure, or
+ // immediately if phase one is complete due to lack of any blobs to write.
+ virtual leveldb::Status CommitPhaseOne(scoped_refptr<BlobWriteCallback>);
+ virtual leveldb::Status CommitPhaseTwo();
+ virtual void Rollback();
+ void Reset() {
+ backing_store_ = NULL;
+ transaction_ = NULL;
+ }
+ leveldb::Status PutBlobInfoIfNeeded(
+ int64 database_id,
+ int64 object_store_id,
+ const std::string& object_store_data_key,
+ std::vector<IndexedDBBlobInfo>*,
+ ScopedVector<storage::BlobDataHandle>* handles);
+ void PutBlobInfo(int64 database_id,
+ int64 object_store_id,
+ const std::string& object_store_data_key,
+ std::vector<IndexedDBBlobInfo>*,
+ ScopedVector<storage::BlobDataHandle>* handles);
+
+ LevelDBTransaction* transaction() { return transaction_.get(); }
+
+ leveldb::Status GetBlobInfoForRecord(
+ int64 database_id,
+ const std::string& object_store_data_key,
+ IndexedDBValue* value);
+
+ // This holds a BlobEntryKey and the encoded IndexedDBBlobInfo vector stored
+ // under that key.
+ typedef std::vector<std::pair<BlobEntryKey, std::string> >
+ BlobEntryKeyValuePairVec;
+
+ class WriteDescriptor {
+ public:
+ WriteDescriptor(const GURL& url, int64_t key, int64_t size);
+ WriteDescriptor(const base::FilePath& path,
+ int64_t key,
+ int64_t size,
+ base::Time last_modified);
+
+ bool is_file() const { return is_file_; }
+ const GURL& url() const {
+ DCHECK(!is_file_);
+ return url_;
+ }
+ const base::FilePath& file_path() const {
+ DCHECK(is_file_);
+ return file_path_;
+ }
+ int64_t key() const { return key_; }
+ int64_t size() const { return size_; }
+ base::Time last_modified() const { return last_modified_; }
+
+ private:
+ bool is_file_;
+ GURL url_;
+ base::FilePath file_path_;
+ int64_t key_;
+ int64_t size_;
+ base::Time last_modified_;
+ };
+
+ class ChainedBlobWriter
+ : public base::RefCountedThreadSafe<ChainedBlobWriter> {
+ public:
+ virtual void set_delegate(
+ scoped_ptr<storage::FileWriterDelegate> delegate) = 0;
+
+ // TODO(ericu): Add a reason in the event of failure.
+ virtual void ReportWriteCompletion(bool succeeded,
+ int64 bytes_written) = 0;
+
+ virtual void Abort() = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<ChainedBlobWriter>;
+ virtual ~ChainedBlobWriter() {}
+ };
+
+ class ChainedBlobWriterImpl;
+
+ typedef std::vector<WriteDescriptor> WriteDescriptorVec;
+
+ private:
+ class BlobWriteCallbackWrapper;
+
+ leveldb::Status HandleBlobPreTransaction(
+ BlobEntryKeyValuePairVec* new_blob_entries,
+ WriteDescriptorVec* new_files_to_write);
+ // Returns true on success, false on failure.
+ bool CollectBlobFilesToRemove();
+ // The callback will be called eventually on success or failure.
+ void WriteNewBlobs(BlobEntryKeyValuePairVec* new_blob_entries,
+ WriteDescriptorVec* new_files_to_write,
+ scoped_refptr<BlobWriteCallback> callback);
+ leveldb::Status SortBlobsToRemove();
+
+ IndexedDBBackingStore* backing_store_;
+ scoped_refptr<LevelDBTransaction> transaction_;
+ BlobChangeMap blob_change_map_;
+ BlobChangeMap incognito_blob_map_;
+ int64 database_id_;
+ BlobJournalType blobs_to_remove_;
+ scoped_refptr<ChainedBlobWriter> chained_blob_writer_;
+ };
+
+ class Cursor {
+ public:
+ enum IteratorState { READY = 0, SEEK };
+
+ virtual ~Cursor();
+
+ struct CursorOptions {
+ CursorOptions();
+ ~CursorOptions();
+ int64 database_id;
+ int64 object_store_id;
+ int64 index_id;
+ std::string low_key;
+ bool low_open;
+ std::string high_key;
+ bool high_open;
+ bool forward;
+ bool unique;
+ };
+
+ const IndexedDBKey& key() const { return *current_key_; }
+ bool Continue(leveldb::Status* s) { return Continue(NULL, NULL, SEEK, s); }
+ bool Continue(const IndexedDBKey* key,
+ IteratorState state,
+ leveldb::Status* s) {
+ return Continue(key, NULL, state, s);
+ }
+ bool Continue(const IndexedDBKey* key,
+ const IndexedDBKey* primary_key,
+ IteratorState state,
+ leveldb::Status*);
+ bool Advance(uint32 count, leveldb::Status*);
+ bool FirstSeek(leveldb::Status*);
+
+ virtual Cursor* Clone() = 0;
+ virtual const IndexedDBKey& primary_key() const;
+ virtual IndexedDBValue* value() = 0;
+ virtual const RecordIdentifier& record_identifier() const;
+ virtual bool LoadCurrentRow() = 0;
+
+ protected:
+ Cursor(scoped_refptr<IndexedDBBackingStore> backing_store,
+ Transaction* transaction,
+ int64 database_id,
+ const CursorOptions& cursor_options);
+ explicit Cursor(const IndexedDBBackingStore::Cursor* other);
+
+ virtual std::string EncodeKey(const IndexedDBKey& key) = 0;
+ virtual std::string EncodeKey(const IndexedDBKey& key,
+ const IndexedDBKey& primary_key) = 0;
+
+ bool IsPastBounds() const;
+ bool HaveEnteredRange() const;
+
+ IndexedDBBackingStore* backing_store_;
+ Transaction* transaction_;
+ int64 database_id_;
+ const CursorOptions cursor_options_;
+ scoped_ptr<LevelDBIterator> iterator_;
+ scoped_ptr<IndexedDBKey> current_key_;
+ IndexedDBBackingStore::RecordIdentifier record_identifier_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Cursor);
};
const GURL& origin_url() const { return origin_url_; }
IndexedDBFactory* factory() const { return indexed_db_factory_; }
- base::TaskRunner* task_runner() const { return task_runner_; }
+ base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); }
base::OneShotTimer<IndexedDBBackingStore>* close_timer() {
return &close_timer_;
}
@@ -92,8 +314,9 @@ class CONTENT_EXPORT IndexedDBBackingStore
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message,
bool* disk_full,
- base::TaskRunner* task_runner,
- bool clean_journal);
+ base::SequencedTaskRunner* task_runner,
+ bool clean_journal,
+ leveldb::Status* status);
static scoped_refptr<IndexedDBBackingStore> Open(
IndexedDBFactory* indexed_db_factory,
const GURL& origin_url,
@@ -103,15 +326,18 @@ class CONTENT_EXPORT IndexedDBBackingStore
std::string* data_loss_message,
bool* disk_full,
LevelDBFactory* leveldb_factory,
- base::TaskRunner* task_runner,
- bool clean_journal);
+ base::SequencedTaskRunner* task_runner,
+ bool clean_journal,
+ leveldb::Status* status);
static scoped_refptr<IndexedDBBackingStore> OpenInMemory(
const GURL& origin_url,
- base::TaskRunner* task_runner);
+ base::SequencedTaskRunner* task_runner,
+ leveldb::Status* status);
static scoped_refptr<IndexedDBBackingStore> OpenInMemory(
const GURL& origin_url,
LevelDBFactory* leveldb_factory,
- base::TaskRunner* task_runner);
+ base::SequencedTaskRunner* task_runner,
+ leveldb::Status* status);
void GrantChildProcessPermissions(int child_process_id);
@@ -154,36 +380,6 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64 database_id,
int64 object_store_id) WARN_UNUSED_RESULT;
- class CONTENT_EXPORT RecordIdentifier {
- public:
- RecordIdentifier(const std::string& primary_key, int64 version);
- RecordIdentifier();
- ~RecordIdentifier();
-
- const std::string& primary_key() const { return primary_key_; }
- int64 version() const { return version_; }
- void Reset(const std::string& primary_key, int64 version) {
- primary_key_ = primary_key;
- version_ = version;
- }
-
- private:
- // TODO(jsbell): Make it more clear that this is the *encoded* version of
- // the key.
- std::string primary_key_;
- int64 version_;
- DISALLOW_COPY_AND_ASSIGN(RecordIdentifier);
- };
-
- class BlobWriteCallback : public base::RefCounted<BlobWriteCallback> {
- public:
- virtual void Run(bool succeeded) = 0;
-
- protected:
- virtual ~BlobWriteCallback() {}
- friend class base::RefCounted<BlobWriteCallback>;
- };
-
virtual leveldb::Status GetRecord(
IndexedDBBackingStore::Transaction* transaction,
int64 database_id,
@@ -195,8 +391,8 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64 database_id,
int64 object_store_id,
const IndexedDBKey& key,
- IndexedDBValue& value,
- ScopedVector<webkit_blob::BlobDataHandle>* handles,
+ IndexedDBValue* value,
+ ScopedVector<storage::BlobDataHandle>* handles,
RecordIdentifier* record) WARN_UNUSED_RESULT;
virtual leveldb::Status ClearObjectStore(
IndexedDBBackingStore::Transaction* transaction,
@@ -273,88 +469,19 @@ class CONTENT_EXPORT IndexedDBBackingStore
base::FilePath GetBlobFileName(int64 database_id, int64 key);
- class Cursor {
- public:
- virtual ~Cursor();
-
- enum IteratorState {
- READY = 0,
- SEEK
- };
-
- struct CursorOptions {
- CursorOptions();
- ~CursorOptions();
- int64 database_id;
- int64 object_store_id;
- int64 index_id;
- std::string low_key;
- bool low_open;
- std::string high_key;
- bool high_open;
- bool forward;
- bool unique;
- };
-
- const IndexedDBKey& key() const { return *current_key_; }
- bool Continue(leveldb::Status* s) { return Continue(NULL, NULL, SEEK, s); }
- bool Continue(const IndexedDBKey* key,
- IteratorState state,
- leveldb::Status* s) {
- return Continue(key, NULL, state, s);
- }
- bool Continue(const IndexedDBKey* key,
- const IndexedDBKey* primary_key,
- IteratorState state,
- leveldb::Status*);
- bool Advance(uint32 count, leveldb::Status*);
- bool FirstSeek(leveldb::Status*);
-
- virtual Cursor* Clone() = 0;
- virtual const IndexedDBKey& primary_key() const;
- virtual IndexedDBValue* value() = 0;
- virtual const RecordIdentifier& record_identifier() const;
- virtual bool LoadCurrentRow() = 0;
-
- protected:
- Cursor(scoped_refptr<IndexedDBBackingStore> backing_store,
- Transaction* transaction,
- int64 database_id,
- const CursorOptions& cursor_options);
- explicit Cursor(const IndexedDBBackingStore::Cursor* other);
-
- virtual std::string EncodeKey(const IndexedDBKey& key) = 0;
- virtual std::string EncodeKey(const IndexedDBKey& key,
- const IndexedDBKey& primary_key) = 0;
-
- bool IsPastBounds() const;
- bool HaveEnteredRange() const;
-
- IndexedDBBackingStore* backing_store_;
- Transaction* transaction_;
- int64 database_id_;
- const CursorOptions cursor_options_;
- scoped_ptr<LevelDBIterator> iterator_;
- scoped_ptr<IndexedDBKey> current_key_;
- IndexedDBBackingStore::RecordIdentifier record_identifier_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Cursor);
- };
-
virtual scoped_ptr<Cursor> OpenObjectStoreKeyCursor(
IndexedDBBackingStore::Transaction* transaction,
int64 database_id,
int64 object_store_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
leveldb::Status*);
virtual scoped_ptr<Cursor> OpenObjectStoreCursor(
IndexedDBBackingStore::Transaction* transaction,
int64 database_id,
int64 object_store_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
leveldb::Status*);
virtual scoped_ptr<Cursor> OpenIndexKeyCursor(
IndexedDBBackingStore::Transaction* transaction,
@@ -362,7 +489,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64 object_store_id,
int64 index_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
leveldb::Status*);
virtual scoped_ptr<Cursor> OpenIndexCursor(
IndexedDBBackingStore::Transaction* transaction,
@@ -370,157 +497,24 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64 object_store_id,
int64 index_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
leveldb::Status*);
- class BlobChangeRecord {
- public:
- BlobChangeRecord(const std::string& key, int64 object_store_id);
- ~BlobChangeRecord();
- const std::string& key() const { return key_; }
- int64 object_store_id() const { return object_store_id_; }
- void SetBlobInfo(std::vector<IndexedDBBlobInfo>* blob_info);
- std::vector<IndexedDBBlobInfo>& mutable_blob_info() { return blob_info_; }
- const std::vector<IndexedDBBlobInfo>& blob_info() const {
- return blob_info_;
- }
- void SetHandles(ScopedVector<webkit_blob::BlobDataHandle>* handles);
- scoped_ptr<BlobChangeRecord> Clone() const;
-
- private:
- std::string key_;
- int64 object_store_id_;
- std::vector<IndexedDBBlobInfo> blob_info_;
- ScopedVector<webkit_blob::BlobDataHandle> handles_;
- DISALLOW_COPY_AND_ASSIGN(BlobChangeRecord);
- };
- typedef std::map<std::string, BlobChangeRecord*> BlobChangeMap;
-
- class Transaction {
- public:
- explicit Transaction(IndexedDBBackingStore* backing_store);
- virtual ~Transaction();
- virtual void Begin();
- // The callback will be called eventually on success or failure, or
- // immediately if phase one is complete due to lack of any blobs to write.
- virtual leveldb::Status CommitPhaseOne(scoped_refptr<BlobWriteCallback>);
- virtual leveldb::Status CommitPhaseTwo();
- virtual void Rollback();
- void Reset() {
- backing_store_ = NULL;
- transaction_ = NULL;
- }
- leveldb::Status PutBlobInfoIfNeeded(
- int64 database_id,
- int64 object_store_id,
- const std::string& object_store_data_key,
- std::vector<IndexedDBBlobInfo>*,
- ScopedVector<webkit_blob::BlobDataHandle>* handles);
- void PutBlobInfo(int64 database_id,
- int64 object_store_id,
- const std::string& object_store_data_key,
- std::vector<IndexedDBBlobInfo>*,
- ScopedVector<webkit_blob::BlobDataHandle>* handles);
-
- LevelDBTransaction* transaction() { return transaction_; }
-
- leveldb::Status GetBlobInfoForRecord(
- int64 database_id,
- const std::string& object_store_data_key,
- IndexedDBValue* value);
-
- // This holds a BlobEntryKey and the encoded IndexedDBBlobInfo vector stored
- // under that key.
- typedef std::vector<std::pair<BlobEntryKey, std::string> >
- BlobEntryKeyValuePairVec;
-
- class WriteDescriptor {
- public:
- WriteDescriptor(const GURL& url, int64_t key, int64_t size);
- WriteDescriptor(const base::FilePath& path,
- int64_t key,
- int64_t size,
- base::Time last_modified);
-
- bool is_file() const { return is_file_; }
- const GURL& url() const {
- DCHECK(!is_file_);
- return url_;
- }
- const base::FilePath& file_path() const {
- DCHECK(is_file_);
- return file_path_;
- }
- int64_t key() const { return key_; }
- int64_t size() const { return size_; }
- base::Time last_modified() const { return last_modified_; }
-
- private:
- bool is_file_;
- GURL url_;
- base::FilePath file_path_;
- int64_t key_;
- int64_t size_;
- base::Time last_modified_;
- };
-
- class ChainedBlobWriter : public base::RefCounted<ChainedBlobWriter> {
- public:
- virtual void set_delegate(
- scoped_ptr<fileapi::FileWriterDelegate> delegate) = 0;
-
- // TODO(ericu): Add a reason in the event of failure.
- virtual void ReportWriteCompletion(bool succeeded,
- int64 bytes_written) = 0;
-
- virtual void Abort() = 0;
-
- protected:
- virtual ~ChainedBlobWriter() {}
- friend class base::RefCounted<ChainedBlobWriter>;
- };
-
- class ChainedBlobWriterImpl;
-
- typedef std::vector<WriteDescriptor> WriteDescriptorVec;
-
- private:
- class BlobWriteCallbackWrapper;
-
- leveldb::Status HandleBlobPreTransaction(
- BlobEntryKeyValuePairVec* new_blob_entries,
- WriteDescriptorVec* new_files_to_write);
- // Returns true on success, false on failure.
- bool CollectBlobFilesToRemove();
- // The callback will be called eventually on success or failure.
- void WriteNewBlobs(BlobEntryKeyValuePairVec& new_blob_entries,
- WriteDescriptorVec& new_files_to_write,
- scoped_refptr<BlobWriteCallback> callback);
- leveldb::Status SortBlobsToRemove();
-
- IndexedDBBackingStore* backing_store_;
- scoped_refptr<LevelDBTransaction> transaction_;
- BlobChangeMap blob_change_map_;
- BlobChangeMap incognito_blob_map_;
- int64 database_id_;
- BlobJournalType blobs_to_remove_;
- scoped_refptr<ChainedBlobWriter> chained_blob_writer_;
- };
-
protected:
+ friend class base::RefCounted<IndexedDBBackingStore>;
+
IndexedDBBackingStore(IndexedDBFactory* indexed_db_factory,
const GURL& origin_url,
const base::FilePath& blob_path,
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator,
- base::TaskRunner* task_runner);
+ base::SequencedTaskRunner* task_runner);
virtual ~IndexedDBBackingStore();
- friend class base::RefCounted<IndexedDBBackingStore>;
bool is_incognito() const { return !indexed_db_factory_; }
- bool SetUpMetadata();
+ leveldb::Status SetUpMetadata();
virtual bool WriteBlobFile(
int64 database_id,
@@ -538,11 +532,12 @@ class CONTENT_EXPORT IndexedDBBackingStore
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator,
- base::TaskRunner* task_runner);
+ base::SequencedTaskRunner* task_runner,
+ leveldb::Status* status);
static bool ReadCorruptionInfo(const base::FilePath& path_base,
const GURL& origin_url,
- std::string& message);
+ std::string* message);
leveldb::Status FindKeyInIndex(
IndexedDBBackingStore::Transaction* transaction,
@@ -572,7 +567,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
const std::string origin_identifier_;
net::URLRequestContext* request_context_;
- base::TaskRunner* task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::set<int> child_process_ids_granted_;
BlobChangeMap incognito_blob_map_;
base::OneShotTimer<IndexedDBBackingStore> journal_cleaning_timer_;
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 76d6d5fa526..da9bcda9386 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
@@ -5,23 +5,26 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "base/callback.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/sequenced_task_runner.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/task_runner.h"
#include "base/test/test_simple_task_runner.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
+#include "content/browser/indexed_db/indexed_db_factory_impl.h"
#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/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"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/quota/special_storage_policy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebIDBTypes.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/quota/special_storage_policy.h"
using base::ASCIIToUTF16;
@@ -31,24 +34,23 @@ namespace {
class Comparator : public LevelDBComparator {
public:
- virtual int Compare(const base::StringPiece& a,
- const base::StringPiece& b) const OVERRIDE {
+ int Compare(const base::StringPiece& a,
+ const base::StringPiece& b) const override {
return content::Compare(a, b, false /*index_keys*/);
}
- virtual const char* Name() const OVERRIDE { return "idb_cmp1"; }
+ const char* Name() const override { return "idb_cmp1"; }
};
class DefaultLevelDBFactory : public LevelDBFactory {
public:
DefaultLevelDBFactory() {}
- virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name,
- const LevelDBComparator* comparator,
- scoped_ptr<LevelDBDatabase>* db,
- bool* is_disk_full) OVERRIDE {
+ leveldb::Status OpenLevelDB(const base::FilePath& file_name,
+ const LevelDBComparator* comparator,
+ scoped_ptr<LevelDBDatabase>* db,
+ bool* is_disk_full) override {
return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full);
}
- virtual leveldb::Status DestroyLevelDB(
- const base::FilePath& file_name) OVERRIDE {
+ leveldb::Status DestroyLevelDB(const base::FilePath& file_name) override {
return LevelDBDatabase::Destroy(file_name);
}
@@ -64,23 +66,26 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
const base::FilePath& path_base,
net::URLRequestContext* request_context,
LevelDBFactory* leveldb_factory,
- base::TaskRunner* task_runner) {
+ base::SequencedTaskRunner* task_runner,
+ leveldb::Status* status) {
DCHECK(!path_base.empty());
scoped_ptr<LevelDBComparator> comparator(new Comparator());
- if (!base::CreateDirectory(path_base))
+ if (!base::CreateDirectory(path_base)) {
+ *status = leveldb::Status::IOError("Unable to create base dir");
return scoped_refptr<TestableIndexedDBBackingStore>();
+ }
const base::FilePath file_path = path_base.AppendASCII("test_db_path");
const base::FilePath blob_path = path_base.AppendASCII("test_blob_path");
scoped_ptr<LevelDBDatabase> db;
bool is_disk_full = false;
- leveldb::Status status = leveldb_factory->OpenLevelDB(
+ *status = leveldb_factory->OpenLevelDB(
file_path, comparator.get(), &db, &is_disk_full);
- if (!db || !status.ok())
+ if (!db || !status->ok())
return scoped_refptr<TestableIndexedDBBackingStore>();
scoped_refptr<TestableIndexedDBBackingStore> backing_store(
@@ -92,7 +97,8 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
comparator.Pass(),
task_runner));
- if (!backing_store->SetUpMetadata())
+ *status = backing_store->SetUpMetadata();
+ if (!status->ok())
return scoped_refptr<TestableIndexedDBBackingStore>();
return backing_store;
@@ -107,12 +113,12 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
void ClearRemovals() { removals_.clear(); }
protected:
- virtual ~TestableIndexedDBBackingStore() {}
+ ~TestableIndexedDBBackingStore() override {}
- virtual bool WriteBlobFile(
+ bool WriteBlobFile(
int64 database_id,
const Transaction::WriteDescriptor& descriptor,
- Transaction::ChainedBlobWriter* chained_blob_writer) OVERRIDE {
+ Transaction::ChainedBlobWriter* chained_blob_writer) override {
if (KeyPrefix::IsValidDatabaseId(database_id_)) {
if (database_id_ != database_id) {
return false;
@@ -130,7 +136,7 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
return true;
}
- virtual bool RemoveBlobFile(int64 database_id, int64 key) OVERRIDE {
+ bool RemoveBlobFile(int64 database_id, int64 key) override {
if (database_id_ != database_id ||
!KeyPrefix::IsValidDatabaseId(database_id)) {
return false;
@@ -140,7 +146,7 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
}
// Timers don't play nicely with unit tests.
- virtual void StartJournalCleaningTimer() OVERRIDE {
+ void StartJournalCleaningTimer() override {
CleanPrimaryJournalIgnoreReturn();
}
@@ -151,7 +157,7 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator,
- base::TaskRunner* task_runner)
+ base::SequencedTaskRunner* task_runner)
: IndexedDBBackingStore(indexed_db_factory,
origin_url,
blob_path,
@@ -168,10 +174,10 @@ class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore);
};
-class TestIDBFactory : public IndexedDBFactory {
+class TestIDBFactory : public IndexedDBFactoryImpl {
public:
explicit TestIDBFactory(IndexedDBContextImpl* idb_context)
- : IndexedDBFactory(idb_context) {}
+ : IndexedDBFactoryImpl(idb_context) {}
scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest(
const GURL& origin,
@@ -179,36 +185,40 @@ class TestIDBFactory : public IndexedDBFactory {
blink::WebIDBDataLoss data_loss;
std::string data_loss_reason;
bool disk_full;
+ leveldb::Status status;
scoped_refptr<IndexedDBBackingStore> backing_store =
OpenBackingStore(origin,
context()->data_path(),
url_request_context,
&data_loss,
&data_loss_reason,
- &disk_full);
+ &disk_full,
+ &status);
scoped_refptr<TestableIndexedDBBackingStore> testable_store =
static_cast<TestableIndexedDBBackingStore*>(backing_store.get());
return testable_store;
}
protected:
- virtual ~TestIDBFactory() {}
+ ~TestIDBFactory() override {}
- virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
+ scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
const GURL& origin_url,
const base::FilePath& data_directory,
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message,
bool* disk_full,
- bool first_time) OVERRIDE {
+ bool first_time,
+ leveldb::Status* status) override {
DefaultLevelDBFactory leveldb_factory;
return TestableIndexedDBBackingStore::Open(this,
origin_url,
data_directory,
request_context,
&leveldb_factory,
- context()->TaskRunner());
+ context()->TaskRunner(),
+ status);
}
private:
@@ -218,15 +228,17 @@ class TestIDBFactory : public IndexedDBFactory {
class IndexedDBBackingStoreTest : public testing::Test {
public:
IndexedDBBackingStoreTest() {}
- virtual void SetUp() {
+ void SetUp() override {
const GURL origin("http://localhost:81");
task_runner_ = new base::TestSimpleTaskRunner();
special_storage_policy_ = new MockSpecialStoragePolicy();
special_storage_policy_->SetAllUnlimited(true);
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- idb_context_ = new IndexedDBContextImpl(
- temp_dir_.path(), special_storage_policy_, NULL, task_runner_);
- idb_factory_ = new TestIDBFactory(idb_context_);
+ idb_context_ = new IndexedDBContextImpl(temp_dir_.path(),
+ special_storage_policy_.get(),
+ NULL,
+ task_runner_.get());
+ idb_factory_ = new TestIDBFactory(idb_context_.get());
backing_store_ =
idb_factory_->OpenBackingStoreForTest(origin, &url_request_context_);
@@ -318,6 +330,9 @@ class IndexedDBBackingStoreTest : public testing::Test {
}
protected:
+ // Must be initialized before url_request_context_
+ content::TestBrowserThreadBundle thread_bundle_;
+
base::ScopedTempDir temp_dir_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
@@ -343,7 +358,7 @@ class IndexedDBBackingStoreTest : public testing::Test {
class TestCallback : public IndexedDBBackingStore::BlobWriteCallback {
public:
TestCallback() : called(false), succeeded(false) {}
- virtual void Run(bool succeeded_in) OVERRIDE {
+ void Run(bool succeeded_in) override {
called = true;
succeeded = succeeded_in;
}
@@ -351,7 +366,7 @@ class TestCallback : public IndexedDBBackingStore::BlobWriteCallback {
bool succeeded;
protected:
- virtual ~TestCallback() {}
+ ~TestCallback() override {}
private:
DISALLOW_COPY_AND_ASSIGN(TestCallback);
@@ -359,12 +374,12 @@ class TestCallback : public IndexedDBBackingStore::BlobWriteCallback {
TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
{
- IndexedDBBackingStore::Transaction transaction1(backing_store_);
+ IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
transaction1.Begin();
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
IndexedDBBackingStore::RecordIdentifier record;
leveldb::Status s = backing_store_->PutRecord(
- &transaction1, 1, 1, m_key1, m_value1, &handles, &record);
+ &transaction1, 1, 1, m_key1, &m_value1, &handles, &record);
EXPECT_TRUE(s.ok());
scoped_refptr<TestCallback> callback(new TestCallback());
EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
@@ -374,7 +389,7 @@ TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
}
{
- IndexedDBBackingStore::Transaction transaction2(backing_store_);
+ IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
transaction2.Begin();
IndexedDBValue result_value;
EXPECT_TRUE(
@@ -391,15 +406,15 @@ TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) {
{
- IndexedDBBackingStore::Transaction transaction1(backing_store_);
+ IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
transaction1.Begin();
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
IndexedDBBackingStore::RecordIdentifier record;
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
1,
m_key3,
- m_value3,
+ &m_value3,
&handles,
&record).ok());
scoped_refptr<TestCallback> callback(new TestCallback());
@@ -412,7 +427,7 @@ TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) {
}
{
- IndexedDBBackingStore::Transaction transaction2(backing_store_);
+ IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
transaction2.Begin();
IndexedDBValue result_value;
EXPECT_TRUE(
@@ -429,7 +444,7 @@ TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) {
}
{
- IndexedDBBackingStore::Transaction transaction3(backing_store_);
+ IndexedDBBackingStore::Transaction transaction3(backing_store_.get());
transaction3.Begin();
IndexedDBValue result_value;
EXPECT_TRUE(backing_store_->DeleteRange(&transaction3,
@@ -476,36 +491,36 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
IndexedDBValue value1 = IndexedDBValue("value1", blob_info1);
IndexedDBValue value2 = IndexedDBValue("value2", blob_info2);
IndexedDBValue value3 = IndexedDBValue("value3", blob_info3);
- IndexedDBBackingStore::Transaction transaction1(backing_store_);
+ IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
transaction1.Begin();
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
IndexedDBBackingStore::RecordIdentifier record;
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
i + 1,
key0,
- value0,
+ &value0,
&handles,
&record).ok());
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
i + 1,
key1,
- value1,
+ &value1,
&handles,
&record).ok());
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
i + 1,
key2,
- value2,
+ &value2,
&handles,
&record).ok());
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
i + 1,
key3,
- value3,
+ &value3,
&handles,
&record).ok());
scoped_refptr<TestCallback> callback(new TestCallback());
@@ -517,7 +532,7 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
}
{
- IndexedDBBackingStore::Transaction transaction2(backing_store_);
+ IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
transaction2.Begin();
IndexedDBValue result_value;
EXPECT_TRUE(
@@ -566,36 +581,36 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
IndexedDBValue value1 = IndexedDBValue("value1", blob_info1);
IndexedDBValue value2 = IndexedDBValue("value2", blob_info2);
IndexedDBValue value3 = IndexedDBValue("value3", blob_info3);
- IndexedDBBackingStore::Transaction transaction1(backing_store_);
+ IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
transaction1.Begin();
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
IndexedDBBackingStore::RecordIdentifier record;
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
i + 1,
key0,
- value0,
+ &value0,
&handles,
&record).ok());
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
i + 1,
key1,
- value1,
+ &value1,
&handles,
&record).ok());
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
i + 1,
key2,
- value2,
+ &value2,
&handles,
&record).ok());
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
i + 1,
key3,
- value3,
+ &value3,
&handles,
&record).ok());
scoped_refptr<TestCallback> callback(new TestCallback());
@@ -607,7 +622,7 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
}
{
- IndexedDBBackingStore::Transaction transaction2(backing_store_);
+ IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
transaction2.Begin();
IndexedDBValue result_value;
EXPECT_TRUE(
@@ -625,15 +640,15 @@ TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) {
{
- IndexedDBBackingStore::Transaction transaction1(backing_store_);
+ IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
transaction1.Begin();
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
IndexedDBBackingStore::RecordIdentifier record;
EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
1,
1,
m_key3,
- m_value3,
+ &m_value3,
&handles,
&record).ok());
scoped_refptr<TestCallback> callback(new TestCallback());
@@ -647,7 +662,7 @@ TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) {
IndexedDBValue read_result_value;
{
- IndexedDBBackingStore::Transaction transaction2(backing_store_);
+ IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
transaction2.Begin();
EXPECT_TRUE(
backing_store_->GetRecord(
@@ -667,7 +682,7 @@ TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) {
}
{
- IndexedDBBackingStore::Transaction transaction3(backing_store_);
+ IndexedDBBackingStore::Transaction transaction3(backing_store_.get());
transaction3.Begin();
EXPECT_TRUE(backing_store_->DeleteRange(&transaction3,
1,
@@ -704,15 +719,15 @@ TEST_F(IndexedDBBackingStoreTest, HighIds) {
std::string index_key_raw;
EncodeIDBKey(index_key, &index_key_raw);
{
- IndexedDBBackingStore::Transaction transaction1(backing_store_);
+ IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
transaction1.Begin();
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
IndexedDBBackingStore::RecordIdentifier record;
leveldb::Status s = backing_store_->PutRecord(&transaction1,
high_database_id,
high_object_store_id,
m_key1,
- m_value1,
+ &m_value1,
&handles,
&record);
EXPECT_TRUE(s.ok());
@@ -743,7 +758,7 @@ TEST_F(IndexedDBBackingStoreTest, HighIds) {
}
{
- IndexedDBBackingStore::Transaction transaction2(backing_store_);
+ IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
transaction2.Begin();
IndexedDBValue result_value;
leveldb::Status s = backing_store_->GetRecord(&transaction2,
@@ -792,32 +807,32 @@ TEST_F(IndexedDBBackingStoreTest, InvalidIds) {
IndexedDBValue result_value;
- IndexedDBBackingStore::Transaction transaction1(backing_store_);
+ IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
transaction1.Begin();
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
IndexedDBBackingStore::RecordIdentifier record;
leveldb::Status s = backing_store_->PutRecord(&transaction1,
database_id,
KeyPrefix::kInvalidId,
m_key1,
- m_value1,
+ &m_value1,
&handles,
&record);
EXPECT_FALSE(s.ok());
s = backing_store_->PutRecord(
- &transaction1, database_id, 0, m_key1, m_value1, &handles, &record);
+ &transaction1, database_id, 0, m_key1, &m_value1, &handles, &record);
EXPECT_FALSE(s.ok());
s = backing_store_->PutRecord(&transaction1,
KeyPrefix::kInvalidId,
object_store_id,
m_key1,
- m_value1,
+ &m_value1,
&handles,
&record);
EXPECT_FALSE(s.ok());
s = backing_store_->PutRecord(
- &transaction1, 0, object_store_id, m_key1, m_value1, &handles, &record);
+ &transaction1, 0, object_store_id, m_key1, &m_value1, &handles, &record);
EXPECT_FALSE(s.ok());
s = backing_store_->GetRecord(
@@ -895,7 +910,7 @@ TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
EXPECT_TRUE(s.ok());
EXPECT_GT(database_id, 0);
- IndexedDBBackingStore::Transaction transaction(backing_store_);
+ IndexedDBBackingStore::Transaction transaction(backing_store_.get());
transaction.Begin();
s = backing_store_->CreateObjectStore(&transaction,
@@ -957,6 +972,35 @@ 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 db1_version = 1LL;
+ int64 db1_id;
+
+ // Database records with DEFAULT_INT_VERSION represent stale data,
+ // and should not be enumerated.
+ const base::string16 db2_name(ASCIIToUTF16("db2"));
+ const int64 db2_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
+ int64 db2_id;
+
+ leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
+ db1_name, string_version, 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);
+ EXPECT_TRUE(s.ok());
+ EXPECT_GT(db2_id, db1_id);
+
+ std::vector<base::string16> names = backing_store_->GetDatabaseNames(&s);
+ EXPECT_TRUE(s.ok());
+ EXPECT_EQ(names.size(), 1ULL);
+ EXPECT_EQ(names[0], db1_name);
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_blob_info.cc b/chromium/content/browser/indexed_db/indexed_db_blob_info.cc
index 2c7d9ec019c..e4b1a3a1f12 100644
--- a/chromium/content/browser/indexed_db/indexed_db_blob_info.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_blob_info.cc
@@ -14,8 +14,6 @@ IndexedDBBlobInfo::IndexedDBBlobInfo()
: is_file_(false), size_(-1), key_(DatabaseMetaDataKey::kInvalidBlobKey) {
}
-IndexedDBBlobInfo::~IndexedDBBlobInfo() {}
-
IndexedDBBlobInfo::IndexedDBBlobInfo(const std::string& uuid,
const base::string16& type,
int64 size)
@@ -51,6 +49,8 @@ IndexedDBBlobInfo::IndexedDBBlobInfo(int64 key,
: is_file_(true), type_(type), size_(-1), file_name_(file_name), key_(key) {
}
+IndexedDBBlobInfo::~IndexedDBBlobInfo() {}
+
void IndexedDBBlobInfo::set_size(int64 size) {
DCHECK_EQ(-1, size_);
size_ = size;
diff --git a/chromium/content/browser/indexed_db/indexed_db_blob_info.h b/chromium/content/browser/indexed_db/indexed_db_blob_info.h
index a2ac99149fc..5001b4bb765 100644
--- a/chromium/content/browser/indexed_db/indexed_db_blob_info.h
+++ b/chromium/content/browser/indexed_db/indexed_db_blob_info.h
@@ -11,16 +11,14 @@
#include "base/files/file_path.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
-#include "webkit/common/blob/shareable_file_reference.h"
+#include "storage/common/blob/shareable_file_reference.h"
namespace content {
class CONTENT_EXPORT IndexedDBBlobInfo {
public:
- typedef webkit_blob::ShareableFileReference::FinalReleaseCallback
- ReleaseCallback;
+ typedef storage::ShareableFileReference::FinalReleaseCallback ReleaseCallback;
IndexedDBBlobInfo();
- ~IndexedDBBlobInfo();
// These two are used for Blobs.
IndexedDBBlobInfo(const std::string& uuid,
const base::string16& type,
@@ -35,6 +33,8 @@ class CONTENT_EXPORT IndexedDBBlobInfo {
const base::string16& type,
const base::string16& file_name);
+ ~IndexedDBBlobInfo();
+
bool is_file() const { return is_file_; }
const std::string& uuid() const { return uuid_; }
const base::string16& type() const { return type_; }
diff --git a/chromium/content/browser/indexed_db/indexed_db_browsertest.cc b/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
index ddbfb44bbac..871d9f50f2f 100644
--- a/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -4,10 +4,10 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
@@ -34,12 +34,12 @@
#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"
-#include "webkit/browser/database/database_util.h"
-#include "webkit/browser/quota/quota_manager.h"
+#include "storage/browser/database/database_util.h"
+#include "storage/browser/quota/quota_manager.h"
using base::ASCIIToUTF16;
-using quota::QuotaManager;
-using webkit_database::DatabaseUtil;
+using storage::QuotaManager;
+using storage::DatabaseUtil;
namespace content {
@@ -49,13 +49,13 @@ class IndexedDBBrowserTest : public ContentBrowserTest {
public:
IndexedDBBrowserTest() : disk_usage_(-1) {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
GetTestClassFactory()->Reset();
IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(GetIDBClassFactory);
ContentBrowserTest::SetUp();
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(NULL);
ContentBrowserTest::TearDown();
}
@@ -125,7 +125,7 @@ class IndexedDBBrowserTest : public ContentBrowserTest {
return;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- qm->SetTemporaryGlobalOverrideQuota(bytes, quota::QuotaCallback());
+ qm->SetTemporaryGlobalOverrideQuota(bytes, storage::QuotaCallback());
// Don't return until the quota has been set.
scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
@@ -246,7 +246,7 @@ class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
public:
IndexedDBBrowserTestWithLowQuota() {}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
const int kInitialQuotaKilobytes = 5000;
SetQuota(kInitialQuotaKilobytes);
}
@@ -263,7 +263,7 @@ class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
public:
IndexedDBBrowserTestWithGCExposed() {}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
}
@@ -297,7 +297,7 @@ static void CopyLevelDBToProfile(Shell* shell,
class IndexedDBBrowserTestWithPreexistingLevelDB : public IndexedDBBrowserTest {
public:
IndexedDBBrowserTestWithPreexistingLevelDB() {}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
scoped_refptr<IndexedDBContextImpl> context = GetContext();
context->TaskRunner()->PostTask(
FROM_HERE,
@@ -317,9 +317,7 @@ class IndexedDBBrowserTestWithPreexistingLevelDB : public IndexedDBBrowserTest {
class IndexedDBBrowserTestWithVersion0Schema : public
IndexedDBBrowserTestWithPreexistingLevelDB {
- virtual std::string EnclosingLevelDBDir() OVERRIDE {
- return "migration_from_0";
- }
+ std::string EnclosingLevelDBDir() override { return "migration_from_0"; }
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema, MigrationTest) {
@@ -328,9 +326,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema, MigrationTest) {
class IndexedDBBrowserTestWithVersion123456Schema : public
IndexedDBBrowserTestWithPreexistingLevelDB {
- virtual std::string EnclosingLevelDBDir() OVERRIDE {
- return "schema_version_123456";
- }
+ std::string EnclosingLevelDBDir() override { return "schema_version_123456"; }
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion123456Schema,
@@ -344,9 +340,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion123456Schema,
class IndexedDBBrowserTestWithVersion987654SSVData : public
IndexedDBBrowserTestWithPreexistingLevelDB {
- virtual std::string EnclosingLevelDBDir() OVERRIDE {
- return "ssv_version_987654";
- }
+ std::string EnclosingLevelDBDir() override { return "ssv_version_987654"; }
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion987654SSVData,
@@ -360,9 +354,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion987654SSVData,
class IndexedDBBrowserTestWithCorruptLevelDB : public
IndexedDBBrowserTestWithPreexistingLevelDB {
- virtual std::string EnclosingLevelDBDir() OVERRIDE {
- return "corrupt_leveldb";
- }
+ std::string EnclosingLevelDBDir() override { return "corrupt_leveldb"; }
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithCorruptLevelDB,
@@ -376,9 +368,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithCorruptLevelDB,
class IndexedDBBrowserTestWithMissingSSTFile : public
IndexedDBBrowserTestWithPreexistingLevelDB {
- virtual std::string EnclosingLevelDBDir() OVERRIDE {
- return "missing_sst";
- }
+ std::string EnclosingLevelDBDir() override { return "missing_sst"; }
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithMissingSSTFile,
@@ -504,7 +494,7 @@ static scoped_ptr<net::test_server::HttpResponse> CorruptDBRequestHandler(
scoped_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse);
http_response->set_code(net::HTTP_OK);
- return http_response.PassAs<net::test_server::HttpResponse>();
+ return http_response.Pass();
} else if (request_path == "fail" && !request_query.empty()) {
FailClass failure_class = FAIL_CLASS_NOTHING;
FailMethod failure_method = FAIL_METHOD_NOTHING;
@@ -548,9 +538,16 @@ static scoped_ptr<net::test_server::HttpResponse> CorruptDBRequestHandler(
failure_method = FAIL_METHOD_GET;
else if (fail_method == "Commit")
failure_method = FAIL_METHOD_COMMIT;
- else {
+ else
NOTREACHED() << "Unknown method: \"" << fail_method << "\"";
- }
+ } else if (fail_class == "LevelDBIterator") {
+ failure_class = FAIL_CLASS_LEVELDB_ITERATOR;
+ if (fail_method == "Seek")
+ failure_method = FAIL_METHOD_SEEK;
+ else
+ NOTREACHED() << "Unknown method: \"" << fail_method << "\"";
+ } else {
+ NOTREACHED() << "Unknown class: \"" << fail_class << "\"";
}
DCHECK_GE(instance_num, 1);
@@ -561,7 +558,7 @@ static scoped_ptr<net::test_server::HttpResponse> CorruptDBRequestHandler(
scoped_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse);
http_response->set_code(net::HTTP_OK);
- return http_response.PassAs<net::test_server::HttpResponse>();
+ return http_response.Pass();
}
// A request for a test resource
@@ -574,7 +571,7 @@ static scoped_ptr<net::test_server::HttpResponse> CorruptDBRequestHandler(
if (!base::ReadFileToString(resourcePath, &file_contents))
return scoped_ptr<net::test_server::HttpResponse>();
http_response->set_content(file_contents);
- return http_response.PassAs<net::test_server::HttpResponse>();
+ return http_response.Pass();
}
} // namespace
@@ -590,7 +587,7 @@ IN_PROC_BROWSER_TEST_P(IndexedDBBrowserCorruptionTest,
const GURL& origin_url = embedded_test_server()->base_url();
embedded_test_server()->RegisterRequestHandler(
base::Bind(&CorruptDBRequestHandler,
- base::ConstRef(GetContext()),
+ base::Unretained(GetContext()),
origin_url,
s_corrupt_db_test_prefix,
this));
@@ -605,13 +602,15 @@ IN_PROC_BROWSER_TEST_P(IndexedDBBrowserCorruptionTest,
INSTANTIATE_TEST_CASE_P(IndexedDBBrowserCorruptionTestInstantiation,
IndexedDBBrowserCorruptionTest,
- ::testing::Values("get",
+ ::testing::Values("failGetBlobJournal",
+ "get",
+ "failWebkitGetDatabaseNames",
"iterate",
+ "failTransactionCommit",
"clearObjectStore"));
-// Crashes flakily on various platforms. crbug.com/375856
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
- DISABLED_DeleteCompactsBackingStore) {
+ DeleteCompactsBackingStore) {
const GURL test_url = GetTestUrl("indexeddb", "delete_compact.html");
SimpleTest(GURL(test_url.spec() + "#fill"));
int64 after_filling = RequestDiskUsage();
@@ -632,7 +631,7 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
const int kTestFillBytes = 1024 * 1024 * 5; // 5MB
EXPECT_GT(after_filling, kTestFillBytes);
- const int kTestCompactBytes = 1024 * 1024 * 1; // 1MB
+ const int kTestCompactBytes = 1024 * 10; // 10kB
EXPECT_LT(after_deleting, kTestCompactBytes);
}
@@ -661,7 +660,11 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_VersionChangeCrashResilience) {
NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part2",
"pass - part2 - crash me");
- NavigateToURL(shell(), GURL(kChromeUIBrowserCrashHost));
+ // If we actually crash here then googletest will not run the next step
+ // (VersionChangeCrashResilience) as an optimization. googletest's
+ // ASSERT_DEATH/EXIT fails to work properly (on Windows) due to how we
+ // implement the PRE_* test mechanism.
+ exit(0);
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, VersionChangeCrashResilience) {
@@ -710,19 +713,13 @@ IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ForceCloseEventTest) {
class IndexedDBBrowserTestSingleProcess : public IndexedDBBrowserTest {
public:
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
command_line->AppendSwitch(switches::kSingleProcess);
}
};
-// Crashing on Android due to kSingleProcess flag: http://crbug.com/342525
-#if defined(OS_ANDROID)
-#define MAYBE_RenderThreadShutdownTest DISABLED_RenderThreadShutdownTest
-#else
-#define MAYBE_RenderThreadShutdownTest RenderThreadShutdownTest
-#endif
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestSingleProcess,
- MAYBE_RenderThreadShutdownTest) {
+ RenderThreadShutdownTest) {
SimpleTest(GetTestUrl("indexeddb", "shutdown_with_requests.html"));
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_callbacks.cc b/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
index 74a76fdce53..a5aafddd557 100644
--- a/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_callbacks.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/guid.h"
+#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "content/browser/child_process_security_policy_impl.h"
@@ -21,12 +22,12 @@
#include "content/browser/indexed_db/indexed_db_value.h"
#include "content/common/indexed_db/indexed_db_constants.h"
#include "content/common/indexed_db/indexed_db_messages.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/common/blob/blob_data.h"
-#include "webkit/common/blob/shareable_file_reference.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/common/blob/blob_data.h"
+#include "storage/common/blob/shareable_file_reference.h"
-using webkit_blob::ShareableFileReference;
+using storage::ShareableFileReference;
namespace content {
@@ -46,7 +47,9 @@ IndexedDBCallbacks::IndexedDBCallbacks(IndexedDBDispatcherHost* dispatcher_host,
host_transaction_id_(kNoTransaction),
ipc_database_id_(kNoDatabase),
ipc_database_callbacks_id_(kNoDatabaseCallbacks),
- data_loss_(blink::WebIDBDataLossNone) {}
+ data_loss_(blink::WebIDBDataLossNone),
+ sent_blocked_(false) {
+}
IndexedDBCallbacks::IndexedDBCallbacks(IndexedDBDispatcherHost* dispatcher_host,
int32 ipc_thread_id,
@@ -59,7 +62,9 @@ IndexedDBCallbacks::IndexedDBCallbacks(IndexedDBDispatcherHost* dispatcher_host,
host_transaction_id_(kNoTransaction),
ipc_database_id_(kNoDatabase),
ipc_database_callbacks_id_(kNoDatabaseCallbacks),
- data_loss_(blink::WebIDBDataLossNone) {}
+ data_loss_(blink::WebIDBDataLossNone),
+ sent_blocked_(false) {
+}
IndexedDBCallbacks::IndexedDBCallbacks(IndexedDBDispatcherHost* dispatcher_host,
int32 ipc_thread_id,
@@ -75,7 +80,9 @@ IndexedDBCallbacks::IndexedDBCallbacks(IndexedDBDispatcherHost* dispatcher_host,
origin_url_(origin_url),
ipc_database_id_(kNoDatabase),
ipc_database_callbacks_id_(ipc_database_callbacks_id),
- data_loss_(blink::WebIDBDataLossNone) {}
+ data_loss_(blink::WebIDBDataLossNone),
+ sent_blocked_(false) {
+}
IndexedDBCallbacks::~IndexedDBCallbacks() {}
@@ -85,6 +92,13 @@ void IndexedDBCallbacks::OnError(const IndexedDBDatabaseError& error) {
dispatcher_host_->Send(new IndexedDBMsg_CallbacksError(
ipc_thread_id_, ipc_callbacks_id_, error.code(), error.message()));
dispatcher_host_ = NULL;
+
+ if (!connection_open_start_time_.is_null()) {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "WebCore.IndexedDB.OpenTime.Error",
+ base::TimeTicks::Now() - connection_open_start_time_);
+ connection_open_start_time_ = base::TimeTicks();
+ }
}
void IndexedDBCallbacks::OnSuccess(const std::vector<base::string16>& value) {
@@ -114,8 +128,19 @@ void IndexedDBCallbacks::OnBlocked(int64 existing_version) {
kNoDatabaseCallbacks == ipc_database_callbacks_id_);
DCHECK_EQ(kNoDatabase, ipc_database_id_);
+ if (sent_blocked_)
+ return;
+
+ sent_blocked_ = true;
dispatcher_host_->Send(new IndexedDBMsg_CallbacksIntBlocked(
ipc_thread_id_, ipc_callbacks_id_, existing_version));
+
+ if (!connection_open_start_time_.is_null()) {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "WebCore.IndexedDB.OpenTime.Blocked",
+ base::TimeTicks::Now() - connection_open_start_time_);
+ connection_open_start_time_ = base::TimeTicks();
+ }
}
void IndexedDBCallbacks::OnDataLoss(blink::WebIDBDataLoss data_loss,
@@ -152,6 +177,13 @@ void IndexedDBCallbacks::OnUpgradeNeeded(
params.data_loss = data_loss_;
params.data_loss_message = data_loss_message_;
dispatcher_host_->Send(new IndexedDBMsg_CallbacksUpgradeNeeded(params));
+
+ if (!connection_open_start_time_.is_null()) {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "WebCore.IndexedDB.OpenTime.UpgradeNeeded",
+ base::TimeTicks::Now() - connection_open_start_time_);
+ connection_open_start_time_ = base::TimeTicks();
+ }
}
void IndexedDBCallbacks::OnSuccess(scoped_ptr<IndexedDBConnection> connection,
@@ -179,19 +211,26 @@ void IndexedDBCallbacks::OnSuccess(scoped_ptr<IndexedDBConnection> connection,
ipc_object_id,
IndexedDBDispatcherHost::ConvertMetadata(metadata)));
dispatcher_host_ = NULL;
+
+ if (!connection_open_start_time_.is_null()) {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "WebCore.IndexedDB.OpenTime.Success",
+ base::TimeTicks::Now() - connection_open_start_time_);
+ connection_open_start_time_ = base::TimeTicks();
+ }
}
static std::string CreateBlobData(
const IndexedDBBlobInfo& blob_info,
scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
- webkit_blob::BlobStorageContext* blob_storage_context,
+ storage::BlobStorageContext* blob_storage_context,
base::TaskRunner* task_runner) {
std::string uuid = blob_info.uuid();
if (!uuid.empty()) {
// We're sending back a live blob, not a reference into our backing store.
- scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle(
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle(
blob_storage_context->GetBlobDataFromUUID(uuid));
- dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle);
+ dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle.Pass());
return uuid;
}
scoped_refptr<ShareableFileReference> shareable_file =
@@ -206,13 +245,13 @@ static std::string CreateBlobData(
}
uuid = base::GenerateGUID();
- scoped_refptr<webkit_blob::BlobData> blob_data =
- new webkit_blob::BlobData(uuid);
+ scoped_refptr<storage::BlobData> blob_data = new storage::BlobData(uuid);
+ blob_data->set_content_type(base::UTF16ToUTF8(blob_info.type()));
blob_data->AppendFile(
blob_info.file_path(), 0, blob_info.size(), blob_info.last_modified());
- scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle(
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle(
blob_storage_context->AddFinishedBlob(blob_data.get()));
- dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle);
+ dispatcher_host->HoldBlobDataHandle(uuid, blob_data_handle.Pass());
return uuid;
}
@@ -268,22 +307,20 @@ static void BlobLookupForCursorPrefetch(
static void FillInBlobData(
const std::vector<IndexedDBBlobInfo>& blob_info,
std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info) {
- for (std::vector<IndexedDBBlobInfo>::const_iterator iter = blob_info.begin();
- iter != blob_info.end();
- ++iter) {
- if (iter->is_file()) {
+ for (const auto& iter : blob_info) {
+ if (iter.is_file()) {
IndexedDBMsg_BlobOrFileInfo info;
info.is_file = true;
- info.mime_type = iter->type();
- info.file_name = iter->file_name();
- info.file_path = iter->file_path().AsUTF16Unsafe();
- info.size = iter->size();
- info.last_modified = iter->last_modified().ToDoubleT();
+ info.mime_type = iter.type();
+ info.file_name = iter.file_name();
+ info.file_path = iter.file_path().AsUTF16Unsafe();
+ info.size = iter.size();
+ info.last_modified = iter.last_modified().ToDoubleT();
blob_or_file_info->push_back(info);
} else {
IndexedDBMsg_BlobOrFileInfo info;
- info.mime_type = iter->type();
- info.size = iter->size();
+ info.mime_type = iter.type();
+ info.size = iter.size();
blob_or_file_info->push_back(info);
}
}
@@ -292,10 +329,9 @@ static void FillInBlobData(
void IndexedDBCallbacks::RegisterBlobsAndSend(
const std::vector<IndexedDBBlobInfo>& blob_info,
const base::Closure& callback) {
- std::vector<IndexedDBBlobInfo>::const_iterator iter;
- for (iter = blob_info.begin(); iter != blob_info.end(); ++iter) {
- if (!iter->mark_used_callback().is_null())
- iter->mark_used_callback().Run();
+ for (const auto& iter : blob_info) {
+ if (!iter.mark_used_callback().is_null())
+ iter.mark_used_callback().Run();
}
DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, callback);
@@ -394,9 +430,9 @@ void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& key,
void IndexedDBCallbacks::OnSuccessWithPrefetch(
const std::vector<IndexedDBKey>& keys,
const std::vector<IndexedDBKey>& primary_keys,
- std::vector<IndexedDBValue>& values) {
+ std::vector<IndexedDBValue>* values) {
DCHECK_EQ(keys.size(), primary_keys.size());
- DCHECK_EQ(keys.size(), values.size());
+ DCHECK_EQ(keys.size(), values->size());
DCHECK(dispatcher_host_.get());
@@ -422,36 +458,32 @@ void IndexedDBCallbacks::OnSuccessWithPrefetch(
params->keys = msgKeys;
params->primary_keys = msgPrimaryKeys;
std::vector<std::string>& values_bits = params->values;
- values_bits.resize(values.size());
+ values_bits.resize(values->size());
std::vector<std::vector<IndexedDBMsg_BlobOrFileInfo> >& values_blob_infos =
params->blob_or_file_infos;
- values_blob_infos.resize(values.size());
+ values_blob_infos.resize(values->size());
bool found_blob_info = false;
- std::vector<IndexedDBValue>::iterator iter = values.begin();
- for (size_t i = 0; iter != values.end(); ++iter, ++i) {
+ std::vector<IndexedDBValue>::iterator iter = values->begin();
+ for (size_t i = 0; iter != values->end(); ++iter, ++i) {
values_bits[i].swap(iter->bits);
if (iter->blob_info.size()) {
found_blob_info = true;
FillInBlobData(iter->blob_info, &values_blob_infos[i]);
- std::vector<IndexedDBBlobInfo>::const_iterator blob_iter;
- for (blob_iter = iter->blob_info.begin();
- blob_iter != iter->blob_info.end();
- ++blob_iter) {
- if (!blob_iter->mark_used_callback().is_null())
- blob_iter->mark_used_callback().Run();
+ for (const auto& blob_iter : iter->blob_info) {
+ if (!blob_iter.mark_used_callback().is_null())
+ blob_iter.mark_used_callback().Run();
}
}
}
if (found_blob_info) {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(BlobLookupForCursorPrefetch,
- base::Owned(params.release()),
- dispatcher_host_,
- values));
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(BlobLookupForCursorPrefetch,
+ base::Owned(params.release()),
+ dispatcher_host_,
+ *values));
} else {
dispatcher_host_->Send(
new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params.get()));
@@ -570,4 +602,9 @@ void IndexedDBCallbacks::OnSuccess() {
dispatcher_host_ = NULL;
}
+void IndexedDBCallbacks::SetConnectionOpenStartTime(
+ const base::TimeTicks& start_time) {
+ connection_open_start_time_ = start_time;
+}
+
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_callbacks.h b/chromium/content/browser/indexed_db/indexed_db_callbacks.h
index 8041fb8beae..4b8a2177a8c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_callbacks.h
+++ b/chromium/content/browser/indexed_db/indexed_db_callbacks.h
@@ -83,7 +83,7 @@ class CONTENT_EXPORT IndexedDBCallbacks
virtual void OnSuccessWithPrefetch(
const std::vector<IndexedDBKey>& keys,
const std::vector<IndexedDBKey>& primary_keys,
- std::vector<IndexedDBValue>& values);
+ std::vector<IndexedDBValue>* values);
// IndexedDBDatabase::Get (with key injection)
virtual void OnSuccess(IndexedDBValue* value,
@@ -106,6 +106,8 @@ class CONTENT_EXPORT IndexedDBCallbacks
blink::WebIDBDataLoss data_loss() const { return data_loss_; }
+ void SetConnectionOpenStartTime(const base::TimeTicks& start_time);
+
protected:
virtual ~IndexedDBCallbacks();
@@ -133,6 +135,9 @@ class CONTENT_EXPORT IndexedDBCallbacks
blink::WebIDBDataLoss data_loss_;
std::string data_loss_message_;
+ // The "blocked" event should be sent at most once per request.
+ bool sent_blocked_;
+ base::TimeTicks connection_open_start_time_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBCallbacks);
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_class_factory.cc b/chromium/content/browser/indexed_db/indexed_db_class_factory.cc
index a2a133689dd..78769db3092 100644
--- a/chromium/content/browser/indexed_db/indexed_db_class_factory.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_class_factory.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "content/browser/indexed_db/indexed_db_class_factory.h"
+#include "content/browser/indexed_db/leveldb/leveldb_iterator_impl.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
namespace content {
@@ -27,4 +28,9 @@ LevelDBTransaction* IndexedDBClassFactory::CreateLevelDBTransaction(
return new LevelDBTransaction(db);
}
+content::LevelDBIteratorImpl* IndexedDBClassFactory::CreateIteratorImpl(
+ scoped_ptr<leveldb::Iterator> iterator) {
+ return new LevelDBIteratorImpl(iterator.Pass());
+}
+
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_class_factory.h b/chromium/content/browser/indexed_db/indexed_db_class_factory.h
index eb3c6566463..03b03597f67 100644
--- a/chromium/content/browser/indexed_db/indexed_db_class_factory.h
+++ b/chromium/content/browser/indexed_db/indexed_db_class_factory.h
@@ -6,10 +6,16 @@
#define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_CLASS_FACTORY_H_
#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
+namespace leveldb {
+class Iterator;
+} // namespace leveldb
+
namespace content {
+class LevelDBIteratorImpl;
class LevelDBDatabase;
class LevelDBTransaction;
@@ -23,6 +29,8 @@ class CONTENT_EXPORT IndexedDBClassFactory {
static void SetIndexedDBClassFactoryGetter(GetterCallback* cb);
+ virtual LevelDBIteratorImpl* CreateIteratorImpl(
+ scoped_ptr<leveldb::Iterator> iterator);
virtual LevelDBTransaction* CreateLevelDBTransaction(LevelDBDatabase* db);
protected:
diff --git a/chromium/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
index 49d04362d89..27f72f2b4b5 100644
--- a/chromium/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
@@ -11,6 +11,8 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/leveldb/leveldb_database.h"
+#include "content/browser/indexed_db/leveldb/mock_leveldb_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/leveldatabase/env_chromium.h"
@@ -20,6 +22,9 @@ using content::LevelDBComparator;
using content::LevelDBDatabase;
using content::LevelDBFactory;
using content::LevelDBSnapshot;
+using testing::_;
+using testing::Exactly;
+using testing::Invoke;
namespace base {
class TaskRunner;
@@ -43,10 +48,10 @@ class BustedLevelDBDatabase : public LevelDBDatabase {
const LevelDBComparator* /*comparator*/) {
return scoped_ptr<LevelDBDatabase>(new BustedLevelDBDatabase);
}
- virtual leveldb::Status Get(const base::StringPiece& key,
- std::string* value,
- bool* found,
- const LevelDBSnapshot* = 0) OVERRIDE {
+ leveldb::Status Get(const base::StringPiece& key,
+ std::string* value,
+ bool* found,
+ const LevelDBSnapshot* = 0) override {
return leveldb::Status::IOError("It's busted!");
}
@@ -54,30 +59,25 @@ class BustedLevelDBDatabase : public LevelDBDatabase {
DISALLOW_COPY_AND_ASSIGN(BustedLevelDBDatabase);
};
-class MockLevelDBFactory : public LevelDBFactory {
+class BustedLevelDBFactory : public LevelDBFactory {
public:
- MockLevelDBFactory() : destroy_called_(false) {}
- virtual leveldb::Status OpenLevelDB(
- const base::FilePath& file_name,
- const LevelDBComparator* comparator,
- scoped_ptr<LevelDBDatabase>* db,
- bool* is_disk_full = 0) OVERRIDE {
- *db = BustedLevelDBDatabase::Open(file_name, comparator);
- return leveldb::Status::OK();
+ leveldb::Status OpenLevelDB(const base::FilePath& file_name,
+ const LevelDBComparator* comparator,
+ scoped_ptr<LevelDBDatabase>* db,
+ bool* is_disk_full = 0) override {
+ if (open_error_.ok())
+ *db = BustedLevelDBDatabase::Open(file_name, comparator);
+ return open_error_;
}
- virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name)
- OVERRIDE {
- EXPECT_FALSE(destroy_called_);
- destroy_called_ = true;
+ leveldb::Status DestroyLevelDB(const base::FilePath& file_name) override {
return leveldb::Status::IOError("error");
}
- virtual ~MockLevelDBFactory() { EXPECT_TRUE(destroy_called_); }
-
- private:
- bool destroy_called_;
+ void SetOpenError(const leveldb::Status& open_error) {
+ open_error_ = open_error;
+ }
private:
- DISALLOW_COPY_AND_ASSIGN(MockLevelDBFactory);
+ leveldb::Status open_error_;
};
TEST(IndexedDBIOErrorTest, CleanUpTest) {
@@ -87,13 +87,22 @@ TEST(IndexedDBIOErrorTest, CleanUpTest) {
ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
const base::FilePath path = temp_directory.path();
net::URLRequestContext* request_context = NULL;
- MockLevelDBFactory mock_leveldb_factory;
- blink::WebIDBDataLoss data_loss =
- blink::WebIDBDataLossNone;
+
+ BustedLevelDBFactory busted_factory;
+ content::MockLevelDBFactory mock_leveldb_factory;
+ ON_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).WillByDefault(
+ Invoke(&busted_factory, &BustedLevelDBFactory::OpenLevelDB));
+ ON_CALL(mock_leveldb_factory, DestroyLevelDB(_)).WillByDefault(
+ Invoke(&busted_factory, &BustedLevelDBFactory::DestroyLevelDB));
+
+ EXPECT_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).Times(Exactly(1));
+ EXPECT_CALL(mock_leveldb_factory, DestroyLevelDB(_)).Times(Exactly(1));
+ blink::WebIDBDataLoss data_loss = blink::WebIDBDataLossNone;
std::string data_loss_message;
bool disk_full = false;
- base::TaskRunner* task_runner = NULL;
+ base::SequencedTaskRunner* task_runner = NULL;
bool clean_journal = false;
+ leveldb::Status s;
scoped_refptr<IndexedDBBackingStore> backing_store =
IndexedDBBackingStore::Open(factory,
origin,
@@ -104,44 +113,10 @@ TEST(IndexedDBIOErrorTest, CleanUpTest) {
&disk_full,
&mock_leveldb_factory,
task_runner,
- clean_journal);
+ clean_journal,
+ &s);
}
-// TODO(dgrogan): Remove expect_destroy if we end up not using it again. It is
-// currently set to false in all 4 calls below.
-template <class T>
-class MockErrorLevelDBFactory : public LevelDBFactory {
- public:
- MockErrorLevelDBFactory(T error, bool expect_destroy)
- : error_(error),
- expect_destroy_(expect_destroy),
- destroy_called_(false) {}
- virtual leveldb::Status OpenLevelDB(
- const base::FilePath& file_name,
- const LevelDBComparator* comparator,
- scoped_ptr<LevelDBDatabase>* db,
- bool* is_disk_full = 0) OVERRIDE {
- return MakeIOError(
- "some filename", "some message", leveldb_env::kNewLogger, error_);
- }
- virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name)
- OVERRIDE {
- EXPECT_FALSE(destroy_called_);
- destroy_called_ = true;
- return leveldb::Status::IOError("error");
- }
- virtual ~MockErrorLevelDBFactory() {
- EXPECT_EQ(expect_destroy_, destroy_called_);
- }
-
- private:
- T error_;
- bool expect_destroy_;
- bool destroy_called_;
-
- DISALLOW_COPY_AND_ASSIGN(MockErrorLevelDBFactory);
-};
-
TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
content::IndexedDBFactory* factory = NULL;
const GURL origin("http://localhost:81");
@@ -153,10 +128,22 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
blink::WebIDBDataLossNone;
std::string data_loss_reason;
bool disk_full = false;
- base::TaskRunner* task_runner = NULL;
+ base::SequencedTaskRunner* task_runner = NULL;
bool clean_journal = false;
+ leveldb::Status s;
+
+ BustedLevelDBFactory busted_factory;
+ content::MockLevelDBFactory mock_leveldb_factory;
+ ON_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).WillByDefault(
+ Invoke(&busted_factory, &BustedLevelDBFactory::OpenLevelDB));
+ ON_CALL(mock_leveldb_factory, DestroyLevelDB(_)).WillByDefault(
+ Invoke(&busted_factory, &BustedLevelDBFactory::DestroyLevelDB));
- MockErrorLevelDBFactory<int> mock_leveldb_factory(ENOSPC, false);
+ EXPECT_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).Times(Exactly(4));
+ EXPECT_CALL(mock_leveldb_factory, DestroyLevelDB(_)).Times(Exactly(0));
+
+ busted_factory.SetOpenError(MakeIOError(
+ "some filename", "some message", leveldb_env::kNewLogger, ENOSPC));
scoped_refptr<IndexedDBBackingStore> backing_store =
IndexedDBBackingStore::Open(factory,
origin,
@@ -167,10 +154,14 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
&disk_full,
&mock_leveldb_factory,
task_runner,
- clean_journal);
-
- MockErrorLevelDBFactory<base::File::Error> mock_leveldb_factory2(
- base::File::FILE_ERROR_NO_MEMORY, false);
+ clean_journal,
+ &s);
+ ASSERT_TRUE(s.IsIOError());
+
+ busted_factory.SetOpenError(MakeIOError("some filename",
+ "some message",
+ leveldb_env::kNewLogger,
+ base::File::FILE_ERROR_NO_MEMORY));
scoped_refptr<IndexedDBBackingStore> backing_store2 =
IndexedDBBackingStore::Open(factory,
origin,
@@ -179,11 +170,14 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
&data_loss,
&data_loss_reason,
&disk_full,
- &mock_leveldb_factory2,
+ &mock_leveldb_factory,
task_runner,
- clean_journal);
+ clean_journal,
+ &s);
+ ASSERT_TRUE(s.IsIOError());
- MockErrorLevelDBFactory<int> mock_leveldb_factory3(EIO, false);
+ busted_factory.SetOpenError(MakeIOError(
+ "some filename", "some message", leveldb_env::kNewLogger, EIO));
scoped_refptr<IndexedDBBackingStore> backing_store3 =
IndexedDBBackingStore::Open(factory,
origin,
@@ -192,12 +186,16 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
&data_loss,
&data_loss_reason,
&disk_full,
- &mock_leveldb_factory3,
+ &mock_leveldb_factory,
task_runner,
- clean_journal);
-
- MockErrorLevelDBFactory<base::File::Error> mock_leveldb_factory4(
- base::File::FILE_ERROR_FAILED, false);
+ clean_journal,
+ &s);
+ ASSERT_TRUE(s.IsIOError());
+
+ busted_factory.SetOpenError(MakeIOError("some filename",
+ "some message",
+ leveldb_env::kNewLogger,
+ base::File::FILE_ERROR_FAILED));
scoped_refptr<IndexedDBBackingStore> backing_store4 =
IndexedDBBackingStore::Open(factory,
origin,
@@ -206,9 +204,11 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
&data_loss,
&data_loss_reason,
&disk_full,
- &mock_leveldb_factory4,
+ &mock_leveldb_factory,
task_runner,
- clean_journal);
+ clean_journal,
+ &s);
+ ASSERT_TRUE(s.IsIOError());
}
} // namespace
diff --git a/chromium/content/browser/indexed_db/indexed_db_connection.cc b/chromium/content/browser/indexed_db/indexed_db_connection.cc
index 0669e14c0d0..3ed927937e8 100644
--- a/chromium/content/browser/indexed_db/indexed_db_connection.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_connection.cc
@@ -14,7 +14,7 @@ IndexedDBConnection::IndexedDBConnection(
IndexedDBConnection::~IndexedDBConnection() {}
void IndexedDBConnection::Close() {
- if (!callbacks_)
+ if (!callbacks_.get())
return;
database_->Close(this, false /* forced */);
database_ = NULL;
@@ -22,7 +22,7 @@ void IndexedDBConnection::Close() {
}
void IndexedDBConnection::ForceClose() {
- if (!callbacks_)
+ if (!callbacks_.get())
return;
database_->Close(this, true /* forced */);
database_ = NULL;
@@ -30,6 +30,12 @@ void IndexedDBConnection::ForceClose() {
callbacks_ = NULL;
}
+void IndexedDBConnection::VersionChangeIgnored() {
+ if (!database_.get())
+ return;
+ database_->VersionChangeIgnored();
+}
+
bool IndexedDBConnection::IsConnected() {
return database_.get() != NULL;
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_connection.h b/chromium/content/browser/indexed_db/indexed_db_connection.h
index 95d1f2e86d3..096323d7cd0 100644
--- a/chromium/content/browser/indexed_db/indexed_db_connection.h
+++ b/chromium/content/browser/indexed_db/indexed_db_connection.h
@@ -24,8 +24,10 @@ class CONTENT_EXPORT IndexedDBConnection {
virtual void Close();
virtual bool IsConnected();
- IndexedDBDatabase* database() { return database_; }
- IndexedDBDatabaseCallbacks* callbacks() { return callbacks_; }
+ void VersionChangeIgnored();
+
+ IndexedDBDatabase* database() const { return database_.get(); }
+ IndexedDBDatabaseCallbacks* callbacks() const { return callbacks_.get(); }
private:
// NULL in some unit tests, and after the connection is closed.
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 c2bd0afa62c..b54d59a46ff 100644
--- a/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -9,8 +9,8 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/sequenced_task_runner.h"
@@ -23,22 +23,22 @@
#include "content/browser/indexed_db/indexed_db_connection.h"
#include "content/browser/indexed_db/indexed_db_database.h"
#include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
-#include "content/browser/indexed_db/indexed_db_factory.h"
+#include "content/browser/indexed_db/indexed_db_factory_impl.h"
#include "content/browser/indexed_db/indexed_db_quota_client.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/indexed_db_info.h"
#include "content/public/common/content_switches.h"
+#include "storage/browser/database/database_util.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/browser/quota/special_storage_policy.h"
+#include "storage/common/database/database_identifier.h"
#include "ui/base/text/bytes_formatting.h"
-#include "webkit/browser/database/database_util.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-#include "webkit/browser/quota/special_storage_policy.h"
-#include "webkit/common/database/database_identifier.h"
using base::DictionaryValue;
using base::ListValue;
-using webkit_database::DatabaseUtil;
+using storage::DatabaseUtil;
namespace content {
const base::FilePath::CharType IndexedDBContextImpl::kIndexedDBDirectory[] =
@@ -68,7 +68,7 @@ void GetAllOriginsAndPaths(const base::FilePath& indexeddb_path,
file_path.RemoveExtension().Extension() == kIndexedDBExtension) {
std::string origin_id = file_path.BaseName().RemoveExtension()
.RemoveExtension().MaybeAsASCII();
- origins->push_back(webkit_database::GetOriginFromIdentifier(origin_id));
+ origins->push_back(storage::GetOriginFromIdentifier(origin_id));
if (file_paths)
file_paths->push_back(file_path);
}
@@ -78,7 +78,7 @@ void GetAllOriginsAndPaths(const base::FilePath& indexeddb_path,
// This will be called after the IndexedDBContext is destroyed.
void ClearSessionOnlyOrigins(
const base::FilePath& indexeddb_path,
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy) {
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) {
// TODO(jsbell): DCHECK that this is running on an IndexedDB thread,
// if a global handle to it is ever available.
std::vector<GURL> origins;
@@ -102,8 +102,8 @@ void ClearSessionOnlyOrigins(
IndexedDBContextImpl::IndexedDBContextImpl(
const base::FilePath& data_path,
- quota::SpecialStoragePolicy* special_storage_policy,
- quota::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy,
+ storage::QuotaManagerProxy* quota_manager_proxy,
base::SequencedTaskRunner* task_runner)
: force_keep_session_state_(false),
special_storage_policy_(special_storage_policy),
@@ -119,36 +119,26 @@ IndexedDBContextImpl::IndexedDBContextImpl(
IndexedDBFactory* IndexedDBContextImpl::GetIDBFactory() {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- if (!factory_) {
+ if (!factory_.get()) {
// Prime our cache of origins with existing databases so we can
// detect when dbs are newly created.
GetOriginSet();
- factory_ = new IndexedDBFactory(this);
+ factory_ = new IndexedDBFactoryImpl(this);
}
- return factory_;
+ return factory_.get();
}
std::vector<GURL> IndexedDBContextImpl::GetAllOrigins() {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
- std::vector<GURL> origins;
std::set<GURL>* origins_set = GetOriginSet();
- for (std::set<GURL>::const_iterator iter = origins_set->begin();
- iter != origins_set->end();
- ++iter) {
- origins.push_back(*iter);
- }
- return origins;
+ return std::vector<GURL>(origins_set->begin(), origins_set->end());
}
std::vector<IndexedDBInfo> IndexedDBContextImpl::GetAllOriginsInfo() {
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
std::vector<GURL> origins = GetAllOrigins();
std::vector<IndexedDBInfo> result;
- for (std::vector<GURL>::const_iterator iter = origins.begin();
- iter != origins.end();
- ++iter) {
- const GURL& origin_url = *iter;
-
+ for (const auto& origin_url : origins) {
base::FilePath idb_directory = GetFilePath(origin_url);
size_t connection_count = GetConnectionCount(origin_url);
result.push_back(IndexedDBInfo(origin_url,
@@ -171,24 +161,21 @@ base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
std::sort(origins.begin(), origins.end(), HostNameComparator);
scoped_ptr<base::ListValue> list(new base::ListValue());
- for (std::vector<GURL>::const_iterator iter = origins.begin();
- iter != origins.end();
- ++iter) {
- const GURL& origin_url = *iter;
-
+ for (const auto& origin_url : origins) {
scoped_ptr<base::DictionaryValue> info(new base::DictionaryValue());
info->SetString("url", origin_url.spec());
info->SetString("size", ui::FormatBytes(GetOriginDiskUsage(origin_url)));
info->SetDouble("last_modified",
GetOriginLastModified(origin_url).ToJsTime());
- info->SetString("path", GetFilePath(origin_url).value());
+ if (!is_incognito())
+ info->SetString("path", GetFilePath(origin_url).value());
info->SetDouble("connection_count", GetConnectionCount(origin_url));
// This ends up being O(n^2) since we iterate over all open databases
// to extract just those in the origin, and we're iterating over all
// origins in the outer loop.
- if (factory_) {
+ if (factory_.get()) {
std::pair<IndexedDBFactory::OriginDBMapIterator,
IndexedDBFactory::OriginDBMapIterator> range =
factory_->GetOpenDatabasesForOrigin(origin_url);
@@ -213,11 +200,7 @@ base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
scoped_ptr<base::ListValue> transaction_list(new base::ListValue());
std::vector<const IndexedDBTransaction*> transactions =
db->transaction_coordinator().GetTransactions();
- for (std::vector<const IndexedDBTransaction*>::iterator trans_it =
- transactions.begin();
- trans_it != transactions.end();
- ++trans_it) {
- const IndexedDBTransaction* transaction = *trans_it;
+ for (const auto* transaction : transactions) {
scoped_ptr<base::DictionaryValue> transaction_info(
new base::DictionaryValue());
@@ -263,12 +246,9 @@ base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
"tasks_completed", transaction->diagnostics().tasks_completed);
scoped_ptr<base::ListValue> scope(new base::ListValue());
- for (std::set<int64>::const_iterator scope_it =
- transaction->scope().begin();
- scope_it != transaction->scope().end();
- ++scope_it) {
+ for (const auto& id : transaction->scope()) {
IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator it =
- db->metadata().object_stores.find(*scope_it);
+ db->metadata().object_stores.find(id);
if (it != db->metadata().object_stores.end())
scope->AppendString(it->second.name);
}
@@ -345,7 +325,7 @@ void IndexedDBContextImpl::ForceClose(const GURL origin_url,
if (data_path_.empty() || !IsInOriginSet(origin_url))
return;
- if (factory_)
+ if (factory_.get())
factory_->ForceClose(origin_url);
DCHECK_EQ(0UL, GetConnectionCount(origin_url));
}
@@ -355,14 +335,14 @@ size_t IndexedDBContextImpl::GetConnectionCount(const GURL& origin_url) {
if (data_path_.empty() || !IsInOriginSet(origin_url))
return 0;
- if (!factory_)
+ if (!factory_.get())
return 0;
return factory_->GetConnectionCount(origin_url);
}
base::FilePath IndexedDBContextImpl::GetFilePath(const GURL& origin_url) const {
- std::string origin_id = webkit_database::GetIdentifierFromOrigin(origin_url);
+ std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
return GetIndexedDBFilePath(origin_id);
}
@@ -373,7 +353,7 @@ base::FilePath IndexedDBContextImpl::GetFilePathForTesting(
void IndexedDBContextImpl::SetTaskRunnerForTesting(
base::SequencedTaskRunner* task_runner) {
- DCHECK(!task_runner_);
+ DCHECK(!task_runner_.get());
task_runner_ = task_runner;
}
@@ -382,9 +362,9 @@ void IndexedDBContextImpl::ConnectionOpened(const GURL& origin_url,
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
if (quota_manager_proxy()) {
quota_manager_proxy()->NotifyStorageAccessed(
- quota::QuotaClient::kIndexedDatabase,
+ storage::QuotaClient::kIndexedDatabase,
origin_url,
- quota::kStorageTypeTemporary);
+ storage::kStorageTypeTemporary);
}
if (AddToOriginSet(origin_url)) {
// A newly created db, notify the quota system.
@@ -400,16 +380,16 @@ void IndexedDBContextImpl::ConnectionClosed(const GURL& origin_url,
DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
if (quota_manager_proxy()) {
quota_manager_proxy()->NotifyStorageAccessed(
- quota::QuotaClient::kIndexedDatabase,
+ storage::QuotaClient::kIndexedDatabase,
origin_url,
- quota::kStorageTypeTemporary);
+ storage::kStorageTypeTemporary);
}
- if (factory_ && factory_->GetConnectionCount(origin_url) == 0)
+ if (factory_.get() && factory_->GetConnectionCount(origin_url) == 0)
QueryDiskAndUpdateQuotaUsage(origin_url);
}
void IndexedDBContextImpl::TransactionComplete(const GURL& origin_url) {
- DCHECK(!factory_ || factory_->GetConnectionCount(origin_url) > 0);
+ DCHECK(!factory_.get() || factory_->GetConnectionCount(origin_url) > 0);
QueryDiskAndUpdateQuotaUsage(origin_url);
QueryAvailableQuota(origin_url);
}
@@ -435,12 +415,12 @@ bool IndexedDBContextImpl::IsOverQuota(const GURL& origin_url) {
return WouldBeOverQuota(origin_url, kOneAdditionalByte);
}
-quota::QuotaManagerProxy* IndexedDBContextImpl::quota_manager_proxy() {
- return quota_manager_proxy_;
+storage::QuotaManagerProxy* IndexedDBContextImpl::quota_manager_proxy() {
+ return quota_manager_proxy_.get();
}
IndexedDBContextImpl::~IndexedDBContextImpl() {
- if (factory_) {
+ if (factory_.get()) {
TaskRunner()->PostTask(
FROM_HERE, base::Bind(&IndexedDBFactory::ContextDestroyed, factory_));
factory_ = NULL;
@@ -453,7 +433,7 @@ IndexedDBContextImpl::~IndexedDBContextImpl() {
return;
bool has_session_only_databases =
- special_storage_policy_ &&
+ special_storage_policy_.get() &&
special_storage_policy_->HasSessionOnlyOrigins();
// Clearing only session-only databases, and there are none.
@@ -496,22 +476,23 @@ void IndexedDBContextImpl::QueryDiskAndUpdateQuotaUsage(
// quota_manager_proxy() is NULL in unit tests.
if (quota_manager_proxy()) {
quota_manager_proxy()->NotifyStorageModified(
- quota::QuotaClient::kIndexedDatabase,
+ storage::QuotaClient::kIndexedDatabase,
origin_url,
- quota::kStorageTypeTemporary,
+ storage::kStorageTypeTemporary,
difference);
}
}
}
void IndexedDBContextImpl::GotUsageAndQuota(const GURL& origin_url,
- quota::QuotaStatusCode status,
+ storage::QuotaStatusCode status,
int64 usage,
int64 quota) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(status == quota::kQuotaStatusOk || status == quota::kQuotaErrorAbort)
+ DCHECK(status == storage::kQuotaStatusOk ||
+ status == storage::kQuotaErrorAbort)
<< "status was " << status;
- if (status == quota::kQuotaErrorAbort) {
+ if (status == storage::kQuotaErrorAbort) {
// We seem to no longer care to wait around for the answer.
return;
}
@@ -547,20 +528,15 @@ void IndexedDBContextImpl::QueryAvailableQuota(const GURL& origin_url) {
return;
quota_manager_proxy()->quota_manager()->GetUsageAndQuota(
origin_url,
- quota::kStorageTypeTemporary,
+ storage::kStorageTypeTemporary,
base::Bind(&IndexedDBContextImpl::GotUsageAndQuota, this, origin_url));
}
std::set<GURL>* IndexedDBContextImpl::GetOriginSet() {
if (!origin_set_) {
- origin_set_.reset(new std::set<GURL>);
std::vector<GURL> origins;
GetAllOriginsAndPaths(data_path_, &origins, NULL);
- for (std::vector<GURL>::const_iterator iter = origins.begin();
- iter != origins.end();
- ++iter) {
- origin_set_->insert(*iter);
- }
+ origin_set_.reset(new std::set<GURL>(origins.begin(), origins.end()));
}
return origin_set_.get();
}
@@ -571,8 +547,8 @@ void IndexedDBContextImpl::ResetCaches() {
space_available_map_.clear();
}
-base::TaskRunner* IndexedDBContextImpl::TaskRunner() const {
- return task_runner_;
+base::SequencedTaskRunner* IndexedDBContextImpl::TaskRunner() const {
+ return task_runner_.get();
}
} // namespace content
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 b3ec9850fdd..8fff76c7a30 100644
--- a/chromium/content/browser/indexed_db/indexed_db_context_impl.h
+++ b/chromium/content/browser/indexed_db/indexed_db_context_impl.h
@@ -17,8 +17,8 @@
#include "content/browser/browser_main_loop.h"
#include "content/browser/indexed_db/indexed_db_factory.h"
#include "content/public/browser/indexed_db_context.h"
+#include "storage/common/quota/quota_types.h"
#include "url/gurl.h"
-#include "webkit/common/quota/quota_types.h"
class GURL;
@@ -28,7 +28,7 @@ class FilePath;
class SequencedTaskRunner;
}
-namespace quota {
+namespace storage {
class QuotaManagerProxy;
class SpecialStoragePolicy;
}
@@ -40,29 +40,36 @@ class IndexedDBConnection;
class CONTENT_EXPORT IndexedDBContextImpl
: NON_EXPORTED_BASE(public IndexedDBContext) {
public:
+ // Recorded in histograms, so append only.
+ enum ForceCloseReason {
+ FORCE_CLOSE_DELETE_ORIGIN = 0,
+ FORCE_CLOSE_BACKING_STORE_FAILURE,
+ FORCE_CLOSE_INTERNALS_PAGE,
+ FORCE_CLOSE_REASON_MAX
+ };
+
+ // The indexed db directory.
+ static const base::FilePath::CharType kIndexedDBDirectory[];
+
// If |data_path| is empty, nothing will be saved to disk.
IndexedDBContextImpl(const base::FilePath& data_path,
- quota::SpecialStoragePolicy* special_storage_policy,
- quota::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy,
+ storage::QuotaManagerProxy* quota_manager_proxy,
base::SequencedTaskRunner* task_runner);
IndexedDBFactory* GetIDBFactory();
- // The indexed db directory.
- static const base::FilePath::CharType kIndexedDBDirectory[];
-
// Disables the exit-time deletion of session-only data.
void SetForceKeepSessionState() { force_keep_session_state_ = true; }
// IndexedDBContext implementation:
- virtual base::TaskRunner* TaskRunner() const OVERRIDE;
- virtual std::vector<IndexedDBInfo> GetAllOriginsInfo() OVERRIDE;
- virtual int64 GetOriginDiskUsage(const GURL& origin_url) OVERRIDE;
- virtual void DeleteForOrigin(const GURL& origin_url) OVERRIDE;
- virtual base::FilePath GetFilePathForTesting(
- const std::string& origin_id) const OVERRIDE;
- virtual void SetTaskRunnerForTesting(base::SequencedTaskRunner* task_runner)
- OVERRIDE;
+ base::SequencedTaskRunner* TaskRunner() const override;
+ std::vector<IndexedDBInfo> GetAllOriginsInfo() override;
+ int64 GetOriginDiskUsage(const GURL& origin_url) override;
+ void DeleteForOrigin(const GURL& origin_url) override;
+ base::FilePath GetFilePathForTesting(
+ const std::string& origin_id) const override;
+ void SetTaskRunnerForTesting(base::SequencedTaskRunner* task_runner) override;
// Methods called by IndexedDBDispatcherHost for quota support.
void ConnectionOpened(const GURL& origin_url, IndexedDBConnection* db);
@@ -72,20 +79,12 @@ class CONTENT_EXPORT IndexedDBContextImpl
bool WouldBeOverQuota(const GURL& origin_url, int64 additional_bytes);
bool IsOverQuota(const GURL& origin_url);
- quota::QuotaManagerProxy* quota_manager_proxy();
+ storage::QuotaManagerProxy* quota_manager_proxy();
std::vector<GURL> GetAllOrigins();
base::Time GetOriginLastModified(const GURL& origin_url);
base::ListValue* GetAllOriginsDetails();
- // Recorded in histograms, so append only.
- enum ForceCloseReason {
- FORCE_CLOSE_DELETE_ORIGIN = 0,
- FORCE_CLOSE_BACKING_STORE_FAILURE,
- FORCE_CLOSE_INTERNALS_PAGE,
- FORCE_CLOSE_REASON_MAX
- };
-
// ForceClose takes a value rather than a reference since it may release the
// owning object.
void ForceClose(const GURL origin_url, ForceCloseReason reason);
@@ -103,8 +102,10 @@ class CONTENT_EXPORT IndexedDBContextImpl
data_path_ = data_path;
}
+ bool is_incognito() const { return data_path_.empty(); }
+
protected:
- virtual ~IndexedDBContextImpl();
+ ~IndexedDBContextImpl() override;
private:
FRIEND_TEST_ALL_PREFIXES(IndexedDBTest, ClearLocalState);
@@ -121,7 +122,7 @@ class CONTENT_EXPORT IndexedDBContextImpl
void EnsureDiskUsageCacheInitialized(const GURL& origin_url);
void QueryDiskAndUpdateQuotaUsage(const GURL& origin_url);
void GotUsageAndQuota(const GURL& origin_url,
- quota::QuotaStatusCode,
+ storage::QuotaStatusCode,
int64 usage,
int64 quota);
void GotUpdatedQuota(const GURL& origin_url, int64 usage, int64 quota);
@@ -142,9 +143,9 @@ class CONTENT_EXPORT IndexedDBContextImpl
base::FilePath data_path_;
// If true, nothing (not even session-only data) should be deleted on exit.
bool force_keep_session_state_;
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
- scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
- base::SequencedTaskRunner* task_runner_;
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_ptr<std::set<GURL> > origin_set_;
OriginToSizeMap origin_size_map_;
OriginToSizeMap space_available_map_;
diff --git a/chromium/content/browser/indexed_db/indexed_db_cursor.cc b/chromium/content/browser/indexed_db/indexed_db_cursor.cc
index 7715a998a75..4fc3c0ea44e 100644
--- a/chromium/content/browser/indexed_db/indexed_db_cursor.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_cursor.cc
@@ -19,7 +19,7 @@ namespace content {
IndexedDBCursor::IndexedDBCursor(
scoped_ptr<IndexedDBBackingStore::Cursor> cursor,
indexed_db::CursorType cursor_type,
- IndexedDBDatabase::TaskType task_type,
+ blink::WebIDBTaskType task_type,
IndexedDBTransaction* transaction)
: task_type_(task_type),
cursor_type_(cursor_type),
@@ -170,7 +170,7 @@ void IndexedDBCursor::CursorPrefetchIterationOperation(
}
callbacks->OnSuccessWithPrefetch(
- found_keys, found_primary_keys, found_values);
+ found_keys, found_primary_keys, &found_values);
}
leveldb::Status IndexedDBCursor::PrefetchReset(int used_prefetches,
diff --git a/chromium/content/browser/indexed_db/indexed_db_cursor.h b/chromium/content/browser/indexed_db/indexed_db_cursor.h
index 7c1491aff7f..a0f42000b0c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_cursor.h
+++ b/chromium/content/browser/indexed_db/indexed_db_cursor.h
@@ -13,6 +13,7 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_database.h"
#include "content/common/indexed_db/indexed_db_key_range.h"
+#include "third_party/WebKit/public/platform/WebIDBTypes.h"
namespace content {
@@ -23,7 +24,7 @@ class CONTENT_EXPORT IndexedDBCursor
public:
IndexedDBCursor(scoped_ptr<IndexedDBBackingStore::Cursor> cursor,
indexed_db::CursorType cursor_type,
- IndexedDBDatabase::TaskType task_type,
+ blink::WebIDBTaskType task_type,
IndexedDBTransaction* transaction);
void Advance(uint32 count, scoped_refptr<IndexedDBCallbacks> callbacks);
@@ -59,7 +60,7 @@ class CONTENT_EXPORT IndexedDBCursor
~IndexedDBCursor();
- IndexedDBDatabase::TaskType task_type_;
+ blink::WebIDBTaskType task_type_;
indexed_db::CursorType cursor_type_;
const scoped_refptr<IndexedDBTransaction> transaction_;
diff --git a/chromium/content/browser/indexed_db/indexed_db_database.cc b/chromium/content/browser/indexed_db/indexed_db_database.cc
index cc0738b6d8e..905cf061f3a 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database.cc
@@ -26,9 +26,9 @@
#include "content/browser/indexed_db/indexed_db_value.h"
#include "content/common/indexed_db/indexed_db_key_path.h"
#include "content/common/indexed_db/indexed_db_key_range.h"
+#include "storage/browser/blob/blob_data_handle.h"
#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
#include "third_party/leveldatabase/env_chromium.h"
-#include "webkit/browser/blob/blob_data_handle.h"
using base::ASCIIToUTF16;
using base::Int64ToString16;
@@ -123,6 +123,7 @@ IndexedDBDatabase::IndexedDBDatabase(const base::string16& name,
kInvalidId),
identifier_(unique_identifier),
factory_(factory) {
+ DCHECK(factory != NULL);
}
void IndexedDBDatabase::AddObjectStore(
@@ -271,7 +272,7 @@ void IndexedDBDatabase::CreateObjectStore(int64 transaction_id,
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
+ DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
if (ContainsKey(metadata_.object_stores, object_store_id)) {
DLOG(ERROR) << "Invalid object_store_id";
@@ -320,7 +321,7 @@ void IndexedDBDatabase::DeleteObjectStore(int64 transaction_id,
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
+ DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
if (!ValidateObjectStoreId(object_store_id))
return;
@@ -342,7 +343,7 @@ void IndexedDBDatabase::CreateIndex(int64 transaction_id,
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
+ DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
if (!ValidateObjectStoreIdAndNewIndexId(object_store_id, index_id))
return;
@@ -394,7 +395,7 @@ void IndexedDBDatabase::DeleteIndex(int64 transaction_id,
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
+ DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id))
return;
@@ -459,8 +460,15 @@ void IndexedDBDatabase::Commit(int64 transaction_id) {
// been dispatched to the frontend, so it will find out about that
// asynchronously.
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
- if (transaction)
- transaction->Commit();
+ if (transaction) {
+ scoped_refptr<IndexedDBFactory> factory = factory_;
+ leveldb::Status s = transaction->Commit();
+ if (s.IsCorruption()) {
+ IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
+ "Internal error committing transaction.");
+ factory->HandleBackingStoreCorruption(identifier_.first, error);
+ }
+ }
}
void IndexedDBDatabase::Abort(int64 transaction_id) {
@@ -535,7 +543,7 @@ void IndexedDBDatabase::GetOperation(
id(),
object_store_id,
*key_range,
- indexed_db::CURSOR_NEXT,
+ blink::WebIDBCursorDirectionNext,
&s);
} else if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
// Index Value Retrieval Operation
@@ -545,7 +553,7 @@ void IndexedDBDatabase::GetOperation(
object_store_id,
index_id,
*key_range,
- indexed_db::CURSOR_NEXT,
+ blink::WebIDBCursorDirectionNext,
&s);
} else {
// Index Referenced Value Retrieval Operation
@@ -555,7 +563,7 @@ void IndexedDBDatabase::GetOperation(
object_store_id,
index_id,
*key_range,
- indexed_db::CURSOR_NEXT,
+ blink::WebIDBCursorDirectionNext,
&s);
}
@@ -710,9 +718,9 @@ struct IndexedDBDatabase::PutOperationParams {
PutOperationParams() {}
int64 object_store_id;
IndexedDBValue value;
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
scoped_ptr<IndexedDBKey> key;
- IndexedDBDatabase::PutMode put_mode;
+ blink::WebIDBPutMode put_mode;
scoped_refptr<IndexedDBCallbacks> callbacks;
std::vector<IndexKeys> index_keys;
@@ -723,16 +731,16 @@ struct IndexedDBDatabase::PutOperationParams {
void IndexedDBDatabase::Put(int64 transaction_id,
int64 object_store_id,
IndexedDBValue* value,
- ScopedVector<webkit_blob::BlobDataHandle>* handles,
+ ScopedVector<storage::BlobDataHandle>* handles,
scoped_ptr<IndexedDBKey> key,
- PutMode put_mode,
+ blink::WebIDBPutMode put_mode,
scoped_refptr<IndexedDBCallbacks> callbacks,
const std::vector<IndexKeys>& index_keys) {
IDB_TRACE1("IndexedDBDatabase::Put", "txn.id", transaction_id);
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY);
+ DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
if (!ValidateObjectStoreId(object_store_id))
return;
@@ -754,7 +762,7 @@ void IndexedDBDatabase::Put(int64 transaction_id,
void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
IndexedDBTransaction* transaction) {
IDB_TRACE1("IndexedDBDatabase::PutOperation", "txn.id", transaction->id());
- DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY);
+ DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
bool key_was_generated = false;
DCHECK(metadata_.object_stores.find(params->object_store_id) !=
@@ -764,7 +772,7 @@ void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
DCHECK(object_store.auto_increment || params->key->IsValid());
scoped_ptr<IndexedDBKey> key;
- if (params->put_mode != IndexedDBDatabase::CURSOR_UPDATE &&
+ if (params->put_mode != blink::WebIDBPutModeCursorUpdate &&
object_store.auto_increment && !params->key->IsValid()) {
scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey(
backing_store_.get(), transaction, id(), params->object_store_id);
@@ -783,7 +791,7 @@ void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
DCHECK(key->IsValid());
IndexedDBBackingStore::RecordIdentifier record_identifier;
- if (params->put_mode == IndexedDBDatabase::ADD_ONLY) {
+ if (params->put_mode == blink::WebIDBPutModeAddOnly) {
bool found = false;
leveldb::Status s = backing_store_->KeyExistsInObjectStore(
transaction->BackingStoreTransaction(),
@@ -841,7 +849,7 @@ void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
id(),
params->object_store_id,
*key,
- params->value,
+ &params->value,
&params->handles,
&record_identifier);
if (!s.ok()) {
@@ -865,7 +873,7 @@ void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
}
if (object_store.auto_increment &&
- params->put_mode != IndexedDBDatabase::CURSOR_UPDATE &&
+ params->put_mode != blink::WebIDBPutModeCursorUpdate &&
key->type() == WebIDBKeyTypeNumber) {
leveldb::Status s = UpdateKeyGenerator(backing_store_.get(),
transaction,
@@ -895,7 +903,7 @@ void IndexedDBDatabase::SetIndexKeys(int64 transaction_id,
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
+ DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
// TODO(alecflett): This method could be asynchronous, but we need to
// evaluate if it's worth the extra complexity.
@@ -932,7 +940,7 @@ void IndexedDBDatabase::SetIndexKeys(int64 transaction_id,
const IndexedDBObjectStoreMetadata& object_store_metadata =
metadata_.object_stores[object_store_id];
bool backing_store_success = MakeIndexWriters(transaction,
- backing_store_,
+ backing_store_.get(),
id(),
object_store_metadata,
*primary_key,
@@ -956,7 +964,7 @@ void IndexedDBDatabase::SetIndexKeys(int64 transaction_id,
for (size_t i = 0; i < index_writers.size(); ++i) {
IndexWriter* index_writer = index_writers[i];
index_writer->WriteIndexKeys(record_identifier,
- backing_store_,
+ backing_store_.get(),
transaction->BackingStoreTransaction(),
id(),
object_store_id);
@@ -970,10 +978,10 @@ void IndexedDBDatabase::SetIndexesReady(int64 transaction_id,
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
+ DCHECK_EQ(transaction->mode(), blink::WebIDBTransactionModeVersionChange);
transaction->ScheduleTask(
- IndexedDBDatabase::PREEMPTIVE_TASK,
+ blink::WebIDBTaskTypePreemptive,
base::Bind(&IndexedDBDatabase::SetIndexesReadyOperation,
this,
index_ids.size()));
@@ -994,9 +1002,9 @@ struct IndexedDBDatabase::OpenCursorOperationParams {
int64 object_store_id;
int64 index_id;
scoped_ptr<IndexedDBKeyRange> key_range;
- indexed_db::CursorDirection direction;
+ blink::WebIDBCursorDirection direction;
indexed_db::CursorType cursor_type;
- IndexedDBDatabase::TaskType task_type;
+ blink::WebIDBTaskType task_type;
scoped_refptr<IndexedDBCallbacks> callbacks;
private:
@@ -1008,9 +1016,9 @@ void IndexedDBDatabase::OpenCursor(
int64 object_store_id,
int64 index_id,
scoped_ptr<IndexedDBKeyRange> key_range,
- indexed_db::CursorDirection direction,
+ blink::WebIDBCursorDirection direction,
bool key_only,
- TaskType task_type,
+ blink::WebIDBTaskType task_type,
scoped_refptr<IndexedDBCallbacks> callbacks) {
IDB_TRACE1("IndexedDBDatabase::OpenCursor", "txn.id", transaction_id);
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
@@ -1043,14 +1051,14 @@ void IndexedDBDatabase::OpenCursorOperation(
// until the indexing is complete. This can't happen any earlier
// because we don't want to switch to early mode in case multiple
// indexes are being created in a row, with Put()'s in between.
- if (params->task_type == IndexedDBDatabase::PREEMPTIVE_TASK)
+ if (params->task_type == blink::WebIDBTaskTypePreemptive)
transaction->AddPreemptiveEvent();
leveldb::Status s;
scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
if (params->index_id == IndexedDBIndexMetadata::kInvalidId) {
if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) {
- DCHECK_EQ(params->task_type, IndexedDBDatabase::NORMAL_TASK);
+ DCHECK_EQ(params->task_type, blink::WebIDBTaskTypeNormal);
backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor(
transaction->BackingStoreTransaction(),
id(),
@@ -1068,7 +1076,7 @@ void IndexedDBDatabase::OpenCursorOperation(
&s);
}
} else {
- DCHECK_EQ(params->task_type, IndexedDBDatabase::NORMAL_TASK);
+ DCHECK_EQ(params->task_type, blink::WebIDBTaskTypeNormal);
if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) {
backing_store_cursor = backing_store_->OpenIndexKeyCursor(
transaction->BackingStoreTransaction(),
@@ -1153,7 +1161,7 @@ void IndexedDBDatabase::CountOperation(
id(),
object_store_id,
*key_range,
- indexed_db::CURSOR_NEXT,
+ blink::WebIDBCursorDirectionNext,
&s);
} else {
backing_store_cursor = backing_store_->OpenIndexKeyCursor(
@@ -1162,7 +1170,7 @@ void IndexedDBDatabase::CountOperation(
object_store_id,
index_id,
*key_range,
- indexed_db::CURSOR_NEXT,
+ blink::WebIDBCursorDirectionNext,
&s);
}
if (!s.ok()) {
@@ -1197,7 +1205,7 @@ void IndexedDBDatabase::DeleteRange(
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY);
+ DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
if (!ValidateObjectStoreId(object_store_id))
return;
@@ -1243,7 +1251,7 @@ void IndexedDBDatabase::Clear(int64 transaction_id,
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;
- DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY);
+ DCHECK_NE(transaction->mode(), blink::WebIDBTransactionModeReadOnly);
if (!ValidateObjectStoreId(object_store_id))
return;
@@ -1347,7 +1355,7 @@ void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction,
DCHECK_EQ(transactions_[transaction->id()], transaction);
transactions_.erase(transaction->id());
- if (transaction->mode() == indexed_db::TRANSACTION_VERSION_CHANGE) {
+ if (transaction->mode() == blink::WebIDBTransactionModeVersionChange) {
if (pending_second_half_open_) {
if (committed) {
DCHECK_EQ(pending_second_half_open_->version(), metadata_.int_version);
@@ -1371,11 +1379,14 @@ void IndexedDBDatabase::TransactionFinished(IndexedDBTransaction* transaction,
}
}
-void IndexedDBDatabase::TransactionCommitFailed() {
- // Factory may be null in unit tests.
- if (!factory_)
- return;
- factory_->HandleBackingStoreFailure(backing_store_->origin_url());
+void IndexedDBDatabase::TransactionCommitFailed(const leveldb::Status& status) {
+ if (status.IsCorruption()) {
+ IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
+ "Error committing transaction");
+ factory_->HandleBackingStoreCorruption(backing_store_->origin_url(), error);
+ } else {
+ factory_->HandleBackingStoreFailure(backing_store_->origin_url());
+ }
}
size_t IndexedDBDatabase::ConnectionCount() const {
@@ -1448,7 +1459,7 @@ void IndexedDBDatabase::CreateTransaction(
int64 transaction_id,
IndexedDBConnection* connection,
const std::vector<int64>& object_store_ids,
- uint16 mode) {
+ blink::WebIDBTransactionMode mode) {
IDB_TRACE1("IndexedDBDatabase::CreateTransaction", "txn.id", transaction_id);
DCHECK(connections_.count(connection));
DCHECK(transactions_.find(transaction_id) == transactions_.end());
@@ -1461,9 +1472,9 @@ void IndexedDBDatabase::CreateTransaction(
transaction_id,
connection->callbacks(),
std::set<int64>(object_store_ids.begin(), object_store_ids.end()),
- static_cast<indexed_db::TransactionMode>(mode),
+ mode,
this,
- new IndexedDBBackingStore::Transaction(backing_store_)));
+ new IndexedDBBackingStore::Transaction(backing_store_.get())));
}
void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) {
@@ -1478,7 +1489,7 @@ bool IndexedDBDatabase::IsOpenConnectionBlocked() const {
void IndexedDBDatabase::OpenConnection(
const IndexedDBPendingConnection& connection) {
- DCHECK(backing_store_);
+ DCHECK(backing_store_.get());
// TODO(jsbell): Should have a priority queue so that higher version
// requests are processed first. http://crbug.com/225850
@@ -1575,25 +1586,20 @@ void IndexedDBDatabase::RunVersionChangeTransaction(
scoped_ptr<IndexedDBConnection> connection,
int64 transaction_id,
int64 requested_version) {
-
- DCHECK(callbacks);
+ DCHECK(callbacks.get());
DCHECK(connections_.count(connection.get()));
if (ConnectionCount() > 1) {
DCHECK_NE(blink::WebIDBDataLossTotal, callbacks->data_loss());
// Front end ensures the event is not fired at connections that have
// close_pending set.
- for (ConnectionSet::const_iterator it = connections_.begin();
- it != connections_.end();
- ++it) {
- if (*it != connection.get()) {
- (*it)->callbacks()->OnVersionChange(metadata_.int_version,
- requested_version);
+ for (const auto* iter : connections_) {
+ if (iter != connection.get()) {
+ iter->callbacks()->OnVersionChange(metadata_.int_version,
+ requested_version);
}
}
- // TODO(jsbell): Remove the call to OnBlocked and instead wait
- // until the frontend tells us that all the "versionchange" events
- // have been delivered. http://crbug.com/100123
- callbacks->OnBlocked(metadata_.int_version);
+ // OnBlocked will be fired at the request when one of the other
+ // connections acks that the OnVersionChange was ignored.
DCHECK(!pending_run_version_change_transaction_call_);
pending_run_version_change_transaction_call_.reset(new PendingUpgradeCall(
@@ -1614,7 +1620,7 @@ void IndexedDBDatabase::RunVersionChangeTransactionFinal(
CreateTransaction(transaction_id,
connection.get(),
object_store_ids,
- indexed_db::TRANSACTION_VERSION_CHANGE);
+ blink::WebIDBTransactionModeVersionChange);
transactions_[transaction_id]->ScheduleTask(
base::Bind(&IndexedDBDatabase::VersionChangeOperation,
@@ -1629,18 +1635,15 @@ void IndexedDBDatabase::DeleteDatabase(
scoped_refptr<IndexedDBCallbacks> callbacks) {
if (IsDeleteDatabaseBlocked()) {
- for (ConnectionSet::const_iterator it = connections_.begin();
- it != connections_.end();
- ++it) {
+ for (const auto* connection : connections_) {
// Front end ensures the event is not fired at connections that have
// close_pending set.
- (*it)->callbacks()->OnVersionChange(
+ connection->callbacks()->OnVersionChange(
metadata_.int_version, IndexedDBDatabaseMetadata::NO_INT_VERSION);
}
- // TODO(jsbell): Only fire OnBlocked if there are open
- // connections after the VersionChangeEvents are received, not
- // just set up to fire. http://crbug.com/100123
- callbacks->OnBlocked(metadata_.int_version);
+ // OnBlocked will be fired at the request when one of the other
+ // connections acks that the OnVersionChange was ignored.
+
pending_delete_calls_.push_back(new PendingDeleteCall(callbacks));
return;
}
@@ -1654,11 +1657,17 @@ bool IndexedDBDatabase::IsDeleteDatabaseBlocked() const {
void IndexedDBDatabase::DeleteDatabaseFinal(
scoped_refptr<IndexedDBCallbacks> callbacks) {
DCHECK(!IsDeleteDatabaseBlocked());
- DCHECK(backing_store_);
- if (!backing_store_->DeleteDatabase(metadata_.name).ok()) {
- callbacks->OnError(
- IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
- "Internal error deleting database."));
+ DCHECK(backing_store_.get());
+ leveldb::Status s = backing_store_->DeleteDatabase(metadata_.name);
+ if (!s.ok()) {
+ IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
+ "Internal error deleting database.");
+ callbacks->OnError(error);
+ if (s.IsCorruption()) {
+ GURL origin_url = backing_store_->origin_url();
+ backing_store_ = NULL;
+ factory_->HandleBackingStoreCorruption(origin_url, error);
+ }
return;
}
int64 old_version = metadata_.int_version;
@@ -1667,8 +1676,7 @@ void IndexedDBDatabase::DeleteDatabaseFinal(
metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
metadata_.object_stores.clear();
callbacks->OnSuccess(old_version);
- if (factory_)
- factory_->DatabaseDeleted(identifier_);
+ factory_->DatabaseDeleted(identifier_);
}
void IndexedDBDatabase::ForceClose() {
@@ -1682,6 +1690,16 @@ void IndexedDBDatabase::ForceClose() {
DCHECK(connections_.empty());
}
+void IndexedDBDatabase::VersionChangeIgnored() {
+ if (pending_run_version_change_transaction_call_)
+ pending_run_version_change_transaction_call_->callbacks()->OnBlocked(
+ metadata_.int_version);
+
+ for (const auto& pending_delete_call : pending_delete_calls_)
+ pending_delete_call->callbacks()->OnBlocked(metadata_.int_version);
+}
+
+
void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
DCHECK(connections_.count(connection));
DCHECK(connection->IsConnected());
@@ -1694,12 +1712,9 @@ void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
// complete, but can occur on process termination or forced close.
{
TransactionMap transactions(transactions_);
- for (TransactionMap::const_iterator it = transactions.begin(),
- end = transactions.end();
- it != end;
- ++it) {
- if (it->second->connection() == connection->callbacks())
- it->second->Abort(
+ for (const auto& it : transactions) {
+ if (it.second->connection() == connection->callbacks())
+ it.second->Abort(
IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
"Connection is closing."));
}
@@ -1724,12 +1739,7 @@ void IndexedDBDatabase::Close(IndexedDBConnection* connection, bool forced) {
const GURL origin_url = backing_store_->origin_url();
backing_store_ = NULL;
- // factory_ should only be null in unit tests.
- // TODO(jsbell): DCHECK(factory_ || !in_unit_tests) - somehow.
- if (factory_) {
- factory_->ReleaseDatabase(identifier_, forced);
- factory_ = NULL;
- }
+ factory_->ReleaseDatabase(identifier_, forced);
}
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_database.h b/chromium/content/browser/indexed_db/indexed_db_database.h
index 63a438a4bb6..bcde7190c50 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database.h
+++ b/chromium/content/browser/indexed_db/indexed_db_database.h
@@ -20,6 +20,7 @@
#include "content/browser/indexed_db/indexed_db_pending_connection.h"
#include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
#include "content/browser/indexed_db/list_set.h"
+#include "third_party/WebKit/public/platform/WebIDBTypes.h"
#include "url/gurl.h"
namespace content {
@@ -37,17 +38,6 @@ struct IndexedDBValue;
class CONTENT_EXPORT IndexedDBDatabase
: NON_EXPORTED_BASE(public base::RefCounted<IndexedDBDatabase>) {
public:
- enum TaskType {
- NORMAL_TASK = 0,
- PREEMPTIVE_TASK
- };
-
- enum PutMode {
- ADD_OR_UPDATE,
- ADD_ONLY,
- CURSOR_UPDATE
- };
-
// An index and corresponding set of keys
typedef std::pair<int64, std::vector<IndexedDBKey> > IndexKeys;
@@ -91,10 +81,15 @@ class CONTENT_EXPORT IndexedDBDatabase
void CreateTransaction(int64 transaction_id,
IndexedDBConnection* connection,
const std::vector<int64>& object_store_ids,
- uint16 mode);
+ blink::WebIDBTransactionMode mode);
void Close(IndexedDBConnection* connection, bool forced);
void ForceClose();
+ // Ack that one of the connections notified with a "versionchange" event did
+ // not promptly close. Therefore a "blocked" event should be fired at the
+ // pending connection.
+ void VersionChangeIgnored();
+
void Commit(int64 transaction_id);
void Abort(int64 transaction_id);
void Abort(int64 transaction_id, const IndexedDBDatabaseError& error);
@@ -119,7 +114,7 @@ class CONTENT_EXPORT IndexedDBDatabase
void TransactionFinished(IndexedDBTransaction* transaction, bool committed);
// Called by transactions to report failure committing to the backing store.
- void TransactionCommitFailed();
+ void TransactionCommitFailed(const leveldb::Status& status);
void Get(int64 transaction_id,
int64 object_store_id,
@@ -130,9 +125,9 @@ class CONTENT_EXPORT IndexedDBDatabase
void Put(int64 transaction_id,
int64 object_store_id,
IndexedDBValue* value,
- ScopedVector<webkit_blob::BlobDataHandle>* handles,
+ ScopedVector<storage::BlobDataHandle>* handles,
scoped_ptr<IndexedDBKey> key,
- PutMode mode,
+ blink::WebIDBPutMode mode,
scoped_refptr<IndexedDBCallbacks> callbacks,
const std::vector<IndexKeys>& index_keys);
void SetIndexKeys(int64 transaction_id,
@@ -146,9 +141,9 @@ class CONTENT_EXPORT IndexedDBDatabase
int64 object_store_id,
int64 index_id,
scoped_ptr<IndexedDBKeyRange> key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
bool key_only,
- TaskType task_type,
+ blink::WebIDBTaskType task_type,
scoped_refptr<IndexedDBCallbacks> callbacks);
void Count(int64 transaction_id,
int64 object_store_id,
@@ -229,6 +224,15 @@ class CONTENT_EXPORT IndexedDBDatabase
private:
friend class base::RefCounted<IndexedDBDatabase>;
+ class PendingDeleteCall;
+ class PendingSuccessCall;
+ class PendingUpgradeCall;
+
+ typedef std::map<int64, IndexedDBTransaction*> TransactionMap;
+ typedef std::list<IndexedDBPendingConnection> PendingOpenCallList;
+ typedef std::list<PendingDeleteCall*> PendingDeleteCallList;
+ typedef list_set<IndexedDBConnection*> ConnectionSet;
+
IndexedDBDatabase(const base::string16& name,
IndexedDBBackingStore* backing_store,
IndexedDBFactory* factory,
@@ -273,22 +277,12 @@ class CONTENT_EXPORT IndexedDBDatabase
IndexedDBTransactionCoordinator transaction_coordinator_;
- typedef std::map<int64, IndexedDBTransaction*> TransactionMap;
TransactionMap transactions_;
-
- typedef std::list<IndexedDBPendingConnection> PendingOpenCallList;
PendingOpenCallList pending_open_calls_;
-
- class PendingUpgradeCall;
scoped_ptr<PendingUpgradeCall> pending_run_version_change_transaction_call_;
- class PendingSuccessCall;
scoped_ptr<PendingSuccessCall> pending_second_half_open_;
-
- class PendingDeleteCall;
- typedef std::list<PendingDeleteCall*> PendingDeleteCallList;
PendingDeleteCallList pending_delete_calls_;
- typedef list_set<IndexedDBConnection*> ConnectionSet;
ConnectionSet connections_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabase);
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 dcaf8233657..865086a9b27 100644
--- a/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -16,12 +16,12 @@
#include "content/browser/indexed_db/indexed_db_callbacks.h"
#include "content/browser/indexed_db/indexed_db_connection.h"
#include "content/browser/indexed_db/indexed_db_cursor.h"
-#include "content/browser/indexed_db/indexed_db_factory.h"
#include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
#include "content/browser/indexed_db/indexed_db_value.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/indexed_db/mock_indexed_db_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
@@ -37,12 +37,12 @@ TEST(IndexedDBDatabaseTest, BackingStoreRetention) {
new IndexedDBFakeBackingStore();
EXPECT_TRUE(backing_store->HasOneRef());
- IndexedDBFactory* factory = 0;
+ scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
leveldb::Status s;
scoped_refptr<IndexedDBDatabase> db =
IndexedDBDatabase::Create(ASCIIToUTF16("db"),
- backing_store,
- factory,
+ backing_store.get(),
+ factory.get(),
IndexedDBDatabase::Identifier(),
&s);
ASSERT_TRUE(s.ok());
@@ -56,12 +56,12 @@ TEST(IndexedDBDatabaseTest, ConnectionLifecycle) {
new IndexedDBFakeBackingStore();
EXPECT_TRUE(backing_store->HasOneRef()); // local
- IndexedDBFactory* factory = 0;
+ scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
leveldb::Status s;
scoped_refptr<IndexedDBDatabase> db =
IndexedDBDatabase::Create(ASCIIToUTF16("db"),
- backing_store,
- factory,
+ backing_store.get(),
+ factory.get(),
IndexedDBDatabase::Identifier(),
&s);
ASSERT_TRUE(s.ok());
@@ -114,12 +114,12 @@ TEST(IndexedDBDatabaseTest, ForcedClose) {
new IndexedDBFakeBackingStore();
EXPECT_TRUE(backing_store->HasOneRef());
- IndexedDBFactory* factory = 0;
+ scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
leveldb::Status s;
scoped_refptr<IndexedDBDatabase> database =
IndexedDBDatabase::Create(ASCIIToUTF16("db"),
- backing_store,
- factory,
+ backing_store.get(),
+ factory.get(),
IndexedDBDatabase::Identifier(),
&s);
ASSERT_TRUE(s.ok());
@@ -136,14 +136,14 @@ TEST(IndexedDBDatabaseTest, ForcedClose) {
upgrade_transaction_id,
IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
database->OpenConnection(connection);
- EXPECT_EQ(database, request->connection()->database());
+ EXPECT_EQ(database.get(), request->connection()->database());
const int64 transaction_id = 123;
const std::vector<int64> scope;
database->CreateTransaction(transaction_id,
request->connection(),
scope,
- indexed_db::TRANSACTION_READ_ONLY);
+ blink::WebIDBTransactionModeReadOnly);
request->connection()->ForceClose();
@@ -158,16 +158,14 @@ class MockDeleteCallbacks : public IndexedDBCallbacks {
blocked_called_(false),
success_called_(false) {}
- virtual void OnBlocked(int64 existing_version) OVERRIDE {
- blocked_called_ = true;
- }
- virtual void OnSuccess(int64 result) OVERRIDE { success_called_ = true; }
+ void OnBlocked(int64 existing_version) override { blocked_called_ = true; }
+ void OnSuccess(int64 result) override { success_called_ = true; }
bool blocked_called() const { return blocked_called_; }
bool success_called() const { return success_called_; }
private:
- virtual ~MockDeleteCallbacks() {}
+ ~MockDeleteCallbacks() override {}
bool blocked_called_;
bool success_called_;
@@ -180,12 +178,12 @@ TEST(IndexedDBDatabaseTest, PendingDelete) {
new IndexedDBFakeBackingStore();
EXPECT_TRUE(backing_store->HasOneRef()); // local
- IndexedDBFactory* factory = 0;
+ scoped_refptr<MockIndexedDBFactory> factory = new MockIndexedDBFactory();
leveldb::Status s;
scoped_refptr<IndexedDBDatabase> db =
IndexedDBDatabase::Create(ASCIIToUTF16("db"),
- backing_store,
- factory,
+ backing_store.get(),
+ factory.get(),
IndexedDBDatabase::Identifier(),
&s);
ASSERT_TRUE(s.ok());
@@ -208,7 +206,10 @@ TEST(IndexedDBDatabaseTest, PendingDelete) {
scoped_refptr<MockDeleteCallbacks> request2(new MockDeleteCallbacks());
db->DeleteDatabase(request2);
+ EXPECT_FALSE(request2->blocked_called());
+ db->VersionChangeIgnored();
EXPECT_TRUE(request2->blocked_called());
+
EXPECT_FALSE(backing_store->HasOneRef()); // local and db
db->Close(request1->connection(), true /* forced */);
@@ -223,14 +224,16 @@ void DummyOperation(IndexedDBTransaction* transaction) {
class IndexedDBDatabaseOperationTest : public testing::Test {
public:
- IndexedDBDatabaseOperationTest() : commit_success_(leveldb::Status::OK()) {}
+ IndexedDBDatabaseOperationTest()
+ : commit_success_(leveldb::Status::OK()),
+ factory_(new MockIndexedDBFactory()) {}
- virtual void SetUp() {
+ void SetUp() override {
backing_store_ = new IndexedDBFakeBackingStore();
leveldb::Status s;
db_ = IndexedDBDatabase::Create(ASCIIToUTF16("db"),
- backing_store_,
- NULL /*factory*/,
+ backing_store_.get(),
+ factory_.get(),
IndexedDBDatabase::Identifier(),
&s);
ASSERT_TRUE(s.ok());
@@ -251,10 +254,10 @@ class IndexedDBDatabaseOperationTest : public testing::Test {
transaction_id,
callbacks_,
std::set<int64>() /*scope*/,
- indexed_db::TRANSACTION_VERSION_CHANGE,
- db_,
+ blink::WebIDBTransactionModeVersionChange,
+ db_.get(),
new IndexedDBFakeBackingStore::FakeTransaction(commit_success_));
- db_->TransactionCreated(transaction_);
+ db_->TransactionCreated(transaction_.get());
// Add a dummy task which takes the place of the VersionChangeOperation
// which kicks off the upgrade. This ensures that the transaction has
@@ -275,6 +278,7 @@ class IndexedDBDatabaseOperationTest : public testing::Test {
private:
base::MessageLoop message_loop_;
+ scoped_refptr<MockIndexedDBFactory> factory_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationTest);
};
@@ -386,7 +390,7 @@ TEST_F(IndexedDBDatabaseOperationTest, CreatePutDelete) {
// Put is asynchronous
IndexedDBValue value("value1", std::vector<IndexedDBBlobInfo>());
- ScopedVector<webkit_blob::BlobDataHandle> handles;
+ ScopedVector<storage::BlobDataHandle> handles;
scoped_ptr<IndexedDBKey> key(new IndexedDBKey("key"));
std::vector<IndexedDBDatabase::IndexKeys> index_keys;
scoped_refptr<MockIndexedDBCallbacks> request(
@@ -396,7 +400,7 @@ TEST_F(IndexedDBDatabaseOperationTest, CreatePutDelete) {
&value,
&handles,
key.Pass(),
- IndexedDBDatabase::ADD_ONLY,
+ blink::WebIDBPutModeAddOnly,
request,
index_keys);
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 47265d5c986..3584f03e83a 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -26,13 +26,13 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/database/database_util.h"
+#include "storage/common/database/database_identifier.h"
#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
#include "url/gurl.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/database/database_util.h"
-#include "webkit/common/database/database_identifier.h"
-using webkit_database::DatabaseUtil;
+using storage::DatabaseUtil;
using blink::WebIDBKey;
namespace content {
@@ -50,7 +50,7 @@ IndexedDBDispatcherHost::IndexedDBDispatcherHost(
database_dispatcher_host_(new DatabaseDispatcherHost(this)),
cursor_dispatcher_host_(new CursorDispatcherHost(this)),
ipc_process_id_(ipc_process_id) {
- DCHECK(indexed_db_context_);
+ DCHECK(indexed_db_context_.get());
}
IndexedDBDispatcherHost::IndexedDBDispatcherHost(
@@ -65,7 +65,7 @@ IndexedDBDispatcherHost::IndexedDBDispatcherHost(
database_dispatcher_host_(new DatabaseDispatcherHost(this)),
cursor_dispatcher_host_(new CursorDispatcherHost(this)),
ipc_process_id_(ipc_process_id) {
- DCHECK(indexed_db_context_);
+ DCHECK(indexed_db_context_.get());
}
IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
@@ -211,7 +211,7 @@ uint32 IndexedDBDispatcherHost::TransactionIdToProcessId(
void IndexedDBDispatcherHost::HoldBlobDataHandle(
const std::string& uuid,
- scoped_ptr<webkit_blob::BlobDataHandle>& blob_data_handle) {
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
DCHECK(!ContainsKey(blob_data_handle_map_, uuid));
blob_data_handle_map_[uuid] = blob_data_handle.release();
}
@@ -240,12 +240,9 @@ IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
metadata.int_version = web_metadata.int_version;
metadata.max_object_store_id = web_metadata.max_object_store_id;
- for (content::IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator iter =
- web_metadata.object_stores.begin();
- iter != web_metadata.object_stores.end();
- ++iter) {
+ for (const auto& iter : web_metadata.object_stores) {
const content::IndexedDBObjectStoreMetadata& web_store_metadata =
- iter->second;
+ iter.second;
::IndexedDBObjectStoreMetadata idb_store_metadata;
idb_store_metadata.id = web_store_metadata.id;
idb_store_metadata.name = web_store_metadata.name;
@@ -253,12 +250,9 @@ IndexedDBCursor* IndexedDBDispatcherHost::GetCursorFromId(int32 ipc_cursor_id) {
idb_store_metadata.autoIncrement = web_store_metadata.auto_increment;
idb_store_metadata.max_index_id = web_store_metadata.max_index_id;
- for (content::IndexedDBObjectStoreMetadata::IndexMap::const_iterator
- index_iter = web_store_metadata.indexes.begin();
- index_iter != web_store_metadata.indexes.end();
- ++index_iter) {
+ for (const auto& index_iter : web_store_metadata.indexes) {
const content::IndexedDBIndexMetadata& web_index_metadata =
- index_iter->second;
+ index_iter.second;
::IndexedDBIndexMetadata idb_index_metadata;
idb_index_metadata.id = web_index_metadata.id;
idb_index_metadata.name = web_index_metadata.name;
@@ -278,7 +272,7 @@ void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
base::FilePath indexed_db_path = indexed_db_context_->data_path();
GURL origin_url =
- webkit_database::GetOriginFromIdentifier(params.database_identifier);
+ storage::GetOriginFromIdentifier(params.database_identifier);
Context()->GetIDBFactory()->GetDatabaseNames(
new IndexedDBCallbacks(
@@ -291,10 +285,11 @@ void IndexedDBDispatcherHost::OnIDBFactoryGetDatabaseNames(
void IndexedDBDispatcherHost::OnIDBFactoryOpen(
const IndexedDBHostMsg_FactoryOpen_Params& params) {
DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ base::TimeTicks begin_time = base::TimeTicks::Now();
base::FilePath indexed_db_path = indexed_db_context_->data_path();
GURL origin_url =
- webkit_database::GetOriginFromIdentifier(params.database_identifier);
+ storage::GetOriginFromIdentifier(params.database_identifier);
int64 host_transaction_id = HostTransactionId(params.transaction_id);
@@ -307,6 +302,7 @@ void IndexedDBDispatcherHost::OnIDBFactoryOpen(
params.ipc_database_callbacks_id,
host_transaction_id,
origin_url);
+ callbacks->SetConnectionOpenStartTime(begin_time);
scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks =
new IndexedDBDatabaseCallbacks(
this, params.ipc_thread_id, params.ipc_database_callbacks_id);
@@ -324,7 +320,7 @@ void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
GURL origin_url =
- webkit_database::GetOriginFromIdentifier(params.database_identifier);
+ storage::GetOriginFromIdentifier(params.database_identifier);
base::FilePath indexed_db_path = indexed_db_context_->data_path();
DCHECK(request_context_);
Context()->GetIDBFactory()->DeleteDatabase(
@@ -340,16 +336,15 @@ void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
// to the IndexedDBDispatcherHost.
void IndexedDBDispatcherHost::OnPutHelper(
const IndexedDBHostMsg_DatabasePut_Params& params,
- std::vector<webkit_blob::BlobDataHandle*> handles) {
+ std::vector<storage::BlobDataHandle*> handles) {
database_dispatcher_host_->OnPut(params, handles);
}
void IndexedDBDispatcherHost::OnAckReceivedBlobs(
const std::vector<std::string>& uuids) {
DCHECK(indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
- std::vector<std::string>::const_iterator iter;
- for (iter = uuids.begin(); iter != uuids.end(); ++iter)
- DropBlobDataHandle(*iter);
+ for (const auto& uuid : uuids)
+ DropBlobDataHandle(uuid);
}
void IndexedDBDispatcherHost::FinishTransaction(int64 host_transaction_id,
@@ -447,13 +442,11 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::CloseAll() {
}
DCHECK(transaction_database_map_.empty());
- for (WebIDBObjectIDToURLMap::iterator iter = database_url_map_.begin();
- iter != database_url_map_.end();
- iter++) {
- IndexedDBConnection* connection = map_.Lookup(iter->first);
+ for (const auto& iter : database_url_map_) {
+ IndexedDBConnection* connection = map_.Lookup(iter.first);
if (connection && connection->IsConnected()) {
connection->Close();
- parent_->Context()->ConnectionClosed(iter->second, connection);
+ parent_->Context()->ConnectionClosed(iter.second, connection);
}
}
}
@@ -475,6 +468,8 @@ bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateTransaction,
OnCreateTransaction)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored,
+ OnVersionChangeIgnored)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
@@ -568,6 +563,17 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
connection->Close();
}
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersionChangeIgnored(
+ int32 ipc_database_id) {
+ DCHECK(
+ parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
+ IndexedDBConnection* connection =
+ parent_->GetOrTerminateProcess(&map_, ipc_database_id);
+ if (!connection || !connection->IsConnected())
+ return;
+ connection->VersionChangeIgnored();
+}
+
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
int32 ipc_object_id) {
DCHECK(
@@ -603,7 +609,7 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
const IndexedDBHostMsg_DatabasePut_Params& params) {
- std::vector<webkit_blob::BlobDataHandle*> handles;
+ std::vector<storage::BlobDataHandle*> handles;
for (size_t i = 0; i < params.blob_or_file_info.size(); ++i) {
const IndexedDBMsg_BlobOrFileInfo& info = params.blob_or_file_info[i];
handles.push_back(parent_->blob_storage_context_->context()
@@ -618,12 +624,11 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
const IndexedDBHostMsg_DatabasePut_Params& params,
- std::vector<webkit_blob::BlobDataHandle*> handles) {
-
+ std::vector<storage::BlobDataHandle*> handles) {
DCHECK(
parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
- ScopedVector<webkit_blob::BlobDataHandle> scoped_handles;
+ ScopedVector<storage::BlobDataHandle> scoped_handles;
scoped_handles.swap(handles);
IndexedDBConnection* connection =
@@ -664,15 +669,14 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPut(
IndexedDBValue value;
value.bits = params.value;
value.blob_info.swap(blob_info);
- connection->database()->Put(
- host_transaction_id,
- params.object_store_id,
- &value,
- &scoped_handles,
- make_scoped_ptr(new IndexedDBKey(params.key)),
- static_cast<IndexedDBDatabase::PutMode>(params.put_mode),
- callbacks,
- params.index_keys);
+ connection->database()->Put(host_transaction_id,
+ params.object_store_id,
+ &value,
+ &scoped_handles,
+ make_scoped_ptr(new IndexedDBKey(params.key)),
+ 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
@@ -729,9 +733,9 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnOpenCursor(
params.object_store_id,
params.index_id,
make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
- static_cast<indexed_db::CursorDirection>(params.direction),
+ params.direction,
params.key_only,
- static_cast<IndexedDBDatabase::TaskType>(params.task_type),
+ params.task_type,
callbacks);
}
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 abbdab99234..667ec7cc2e8 100644
--- a/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
+++ b/chromium/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -15,8 +15,8 @@
#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 "url/gurl.h"
-#include "webkit/browser/blob/blob_data_handle.h"
struct IndexedDBDatabaseMetadata;
struct IndexedDBHostMsg_DatabaseCount_Params;
@@ -58,18 +58,18 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
const content::IndexedDBDatabaseMetadata& metadata);
// BrowserMessageFilter implementation.
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
- virtual void OnChannelClosing() OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
- virtual base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& message) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelConnected(int32 peer_pid) override;
+ void OnChannelClosing() override;
+ void OnDestruct() const override;
+ base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
void FinishTransaction(int64 host_transaction_id, bool committed);
// A shortcut for accessing our context.
- IndexedDBContextImpl* Context() { return indexed_db_context_; }
- webkit_blob::BlobStorageContext* blob_storage_context() const {
+ IndexedDBContextImpl* Context() { return indexed_db_context_.get(); }
+ storage::BlobStorageContext* blob_storage_context() const {
return blob_storage_context_->context();
}
@@ -94,9 +94,8 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
static uint32 TransactionIdToRendererTransactionId(int64 host_transaction_id);
static uint32 TransactionIdToProcessId(int64 host_transaction_id);
- void HoldBlobDataHandle(
- const std::string& uuid,
- scoped_ptr<webkit_blob::BlobDataHandle>& blob_data_handle);
+ void HoldBlobDataHandle(const std::string& uuid,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
void DropBlobDataHandle(const std::string& uuid);
private:
@@ -104,30 +103,19 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
friend class BrowserThread;
friend class base::DeleteHelper<IndexedDBDispatcherHost>;
- virtual ~IndexedDBDispatcherHost();
-
- // Message processing. Most of the work is delegated to the dispatcher hosts
- // below.
- void OnIDBFactoryGetDatabaseNames(
- const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& p);
- void OnIDBFactoryOpen(const IndexedDBHostMsg_FactoryOpen_Params& p);
-
- void OnIDBFactoryDeleteDatabase(
- const IndexedDBHostMsg_FactoryDeleteDatabase_Params& p);
-
- void OnAckReceivedBlobs(const std::vector<std::string>& uuids);
- void OnPutHelper(const IndexedDBHostMsg_DatabasePut_Params& params,
- std::vector<webkit_blob::BlobDataHandle*> handles);
-
- void ResetDispatcherHosts();
+ // Used in nested classes.
+ typedef std::map<std::string, storage::BlobDataHandle*> BlobDataHandleMap;
+ typedef std::map<int64, int64> TransactionIDToDatabaseIDMap;
+ typedef std::map<int64, uint64> TransactionIDToSizeMap;
+ typedef std::map<int64, GURL> TransactionIDToURLMap;
+ typedef std::map<int32, GURL> WebIDBObjectIDToURLMap;
// IDMap for RefCounted types
template <typename RefCountedType>
class RefIDMap {
- private:
+ public:
typedef int32 KeyType;
- public:
RefIDMap() {}
~RefIDMap() {}
@@ -154,24 +142,6 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
DISALLOW_COPY_AND_ASSIGN(RefIDMap);
};
- // Helper templates.
- template <class ReturnType>
- ReturnType* GetOrTerminateProcess(IDMap<ReturnType, IDMapOwnPointer>* map,
- int32 ipc_return_object_id);
- template <class ReturnType>
- ReturnType* GetOrTerminateProcess(RefIDMap<ReturnType>* map,
- int32 ipc_return_object_id);
-
- template <typename MapType>
- void DestroyObject(MapType* map, int32 ipc_object_id);
-
- // Used in nested classes.
- typedef std::map<int32, GURL> WebIDBObjectIDToURLMap;
-
- typedef std::map<int64, GURL> TransactionIDToURLMap;
- typedef std::map<int64, uint64> TransactionIDToSizeMap;
- typedef std::map<int64, int64> TransactionIDToDatabaseIDMap;
-
class DatabaseDispatcherHost {
public:
explicit DatabaseDispatcherHost(IndexedDBDispatcherHost* parent);
@@ -188,6 +158,7 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
void OnCreateTransaction(
const IndexedDBHostMsg_DatabaseCreateTransaction_Params&);
void OnClose(int32 ipc_database_id);
+ void OnVersionChangeIgnored(int32 ipc_database_id);
void OnDestroyed(int32 ipc_database_id);
void OnGet(const IndexedDBHostMsg_DatabaseGet_Params& params);
@@ -195,7 +166,7 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
// before posting to the IDB TaskRunner for the rest of the job.
void OnPutWrapper(const IndexedDBHostMsg_DatabasePut_Params& params);
void OnPut(const IndexedDBHostMsg_DatabasePut_Params& params,
- std::vector<webkit_blob::BlobDataHandle*> handles);
+ std::vector<storage::BlobDataHandle*> handles);
void OnSetIndexKeys(
const IndexedDBHostMsg_DatabaseSetIndexKeys_Params& params);
void OnSetIndexesReady(int32 ipc_database_id,
@@ -263,6 +234,34 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
DISALLOW_COPY_AND_ASSIGN(CursorDispatcherHost);
};
+ ~IndexedDBDispatcherHost() override;
+
+ // Helper templates.
+ template <class ReturnType>
+ ReturnType* GetOrTerminateProcess(IDMap<ReturnType, IDMapOwnPointer>* map,
+ int32 ipc_return_object_id);
+ template <class ReturnType>
+ ReturnType* GetOrTerminateProcess(RefIDMap<ReturnType>* map,
+ int32 ipc_return_object_id);
+
+ template <typename MapType>
+ void DestroyObject(MapType* map, int32 ipc_object_id);
+
+ // Message processing. Most of the work is delegated to the dispatcher hosts
+ // below.
+ void OnIDBFactoryGetDatabaseNames(
+ const IndexedDBHostMsg_FactoryGetDatabaseNames_Params& p);
+ void OnIDBFactoryOpen(const IndexedDBHostMsg_FactoryOpen_Params& p);
+
+ void OnIDBFactoryDeleteDatabase(
+ const IndexedDBHostMsg_FactoryDeleteDatabase_Params& p);
+
+ void OnAckReceivedBlobs(const std::vector<std::string>& uuids);
+ void OnPutHelper(const IndexedDBHostMsg_DatabasePut_Params& params,
+ std::vector<storage::BlobDataHandle*> handles);
+
+ void ResetDispatcherHosts();
+
// The getter holds the context until OnChannelConnected() can be called from
// the IO thread, which will extract the net::URLRequestContext from it.
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
@@ -270,7 +269,6 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
scoped_refptr<IndexedDBContextImpl> indexed_db_context_;
scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
- typedef std::map<std::string, webkit_blob::BlobDataHandle*> BlobDataHandleMap;
BlobDataHandleMap blob_data_handle_map_;
// Only access on IndexedDB thread.
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory.h b/chromium/content/browser/indexed_db/indexed_db_factory.h
index c2177de7e56..935ba56c550 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory.h
+++ b/chromium/content/browser/indexed_db/indexed_db_factory.h
@@ -27,7 +27,6 @@ class URLRequestContext;
namespace content {
class IndexedDBBackingStore;
-class IndexedDBContextImpl;
struct IndexedDBPendingConnection;
class CONTENT_EXPORT IndexedDBFactory
@@ -35,53 +34,54 @@ class CONTENT_EXPORT IndexedDBFactory
public:
typedef std::multimap<GURL, IndexedDBDatabase*> OriginDBMap;
typedef OriginDBMap::const_iterator OriginDBMapIterator;
+ typedef std::pair<OriginDBMapIterator, OriginDBMapIterator> OriginDBs;
+
+ virtual void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
+ bool forcedClose) = 0;
+
+ virtual void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
+ const GURL& origin_url,
+ const base::FilePath& data_directory,
+ net::URLRequestContext* request_context) = 0;
+ virtual void Open(const base::string16& name,
+ const IndexedDBPendingConnection& connection,
+ net::URLRequestContext* request_context,
+ const GURL& origin_url,
+ const base::FilePath& data_directory) = 0;
+
+ virtual void DeleteDatabase(const base::string16& name,
+ net::URLRequestContext* request_context,
+ scoped_refptr<IndexedDBCallbacks> callbacks,
+ const GURL& origin_url,
+ const base::FilePath& data_directory) = 0;
+
+ virtual void HandleBackingStoreFailure(const GURL& origin_url) = 0;
+ virtual void HandleBackingStoreCorruption(
+ const GURL& origin_url,
+ const IndexedDBDatabaseError& error) = 0;
- explicit IndexedDBFactory(IndexedDBContextImpl* context);
-
- void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
- bool forcedClose);
-
- void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
- const GURL& origin_url,
- const base::FilePath& data_directory,
- net::URLRequestContext* request_context);
- void Open(const base::string16& name,
- const IndexedDBPendingConnection& connection,
- net::URLRequestContext* request_context,
- const GURL& origin_url,
- const base::FilePath& data_directory);
-
- void DeleteDatabase(const base::string16& name,
- net::URLRequestContext* request_context,
- scoped_refptr<IndexedDBCallbacks> callbacks,
- const GURL& origin_url,
- const base::FilePath& data_directory);
-
- void HandleBackingStoreFailure(const GURL& origin_url);
- void HandleBackingStoreCorruption(const GURL& origin_url,
- const IndexedDBDatabaseError& error);
-
- std::pair<OriginDBMapIterator, OriginDBMapIterator> GetOpenDatabasesForOrigin(
- const GURL& origin_url) const;
+ virtual OriginDBs GetOpenDatabasesForOrigin(const GURL& origin_url) const = 0;
- void ForceClose(const GURL& origin_url);
+ virtual void ForceClose(const GURL& origin_url) = 0;
// Called by the IndexedDBContext destructor so the factory can do cleanup.
- void ContextDestroyed();
+ virtual void ContextDestroyed() = 0;
// Called by the IndexedDBActiveBlobRegistry.
virtual void ReportOutstandingBlobs(const GURL& origin_url,
- bool blobs_outstanding);
+ bool blobs_outstanding) = 0;
// Called by an IndexedDBDatabase when it is actually deleted.
- void DatabaseDeleted(const IndexedDBDatabase::Identifier& identifier);
+ virtual void DatabaseDeleted(
+ const IndexedDBDatabase::Identifier& identifier) = 0;
- size_t GetConnectionCount(const GURL& origin_url) const;
+ virtual size_t GetConnectionCount(const GURL& origin_url) const = 0;
protected:
friend class base::RefCountedThreadSafe<IndexedDBFactory>;
- virtual ~IndexedDBFactory();
+ IndexedDBFactory() {}
+ virtual ~IndexedDBFactory() {}
virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
const GURL& origin_url,
@@ -89,7 +89,8 @@ class CONTENT_EXPORT IndexedDBFactory
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_reason,
- bool* disk_full);
+ bool* disk_full,
+ leveldb::Status* status) = 0;
virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
const GURL& origin_url,
@@ -98,54 +99,10 @@ class CONTENT_EXPORT IndexedDBFactory
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message,
bool* disk_full,
- bool first_time);
-
- void ReleaseBackingStore(const GURL& origin_url, bool immediate);
- void CloseBackingStore(const GURL& origin_url);
- IndexedDBContextImpl* context() const { return context_; }
+ bool first_time,
+ leveldb::Status* status) = 0;
private:
- FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
- BackingStoreReleasedOnForcedClose);
- FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
- BackingStoreReleaseDelayedOnClose);
- FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest, DatabaseFailedOpen);
- FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
- DeleteDatabaseClosesBackingStore);
- FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
- ForceCloseReleasesBackingStore);
- FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
- GetDatabaseNamesClosesBackingStore);
- FRIEND_TEST_ALL_PREFIXES(IndexedDBTest,
- ForceCloseOpenDatabasesOnCommitFailure);
-
- // Called internally after a database is closed, with some delay. If this
- // factory has the last reference, it will be released.
- void MaybeCloseBackingStore(const GURL& origin_url);
- bool HasLastBackingStoreReference(const GURL& origin_url) const;
-
- // Testing helpers, so unit tests don't need to grovel through internal state.
- bool IsDatabaseOpen(const GURL& origin_url,
- const base::string16& name) const;
- bool IsBackingStoreOpen(const GURL& origin_url) const;
- bool IsBackingStorePendingClose(const GURL& origin_url) const;
- void RemoveDatabaseFromMaps(const IndexedDBDatabase::Identifier& identifier);
-
- IndexedDBContextImpl* context_;
-
- typedef std::map<IndexedDBDatabase::Identifier,
- IndexedDBDatabase*> IndexedDBDatabaseMap;
- IndexedDBDatabaseMap database_map_;
- OriginDBMap origin_dbs_;
-
- typedef std::map<GURL, scoped_refptr<IndexedDBBackingStore> >
- IndexedDBBackingStoreMap;
- IndexedDBBackingStoreMap backing_store_map_;
-
- std::set<scoped_refptr<IndexedDBBackingStore> > session_only_backing_stores_;
- IndexedDBBackingStoreMap backing_stores_with_active_blobs_;
- std::set<GURL> backends_opened_since_boot_;
-
DISALLOW_COPY_AND_ASSIGN(IndexedDBFactory);
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory.cc b/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
index 3f08d06c9bd..9a62b78fb4c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -2,8 +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/indexed_db/indexed_db_factory.h"
+#include "content/browser/indexed_db/indexed_db_factory_impl.h"
+#include <utility>
#include <vector>
#include "base/logging.h"
@@ -14,9 +15,9 @@
#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/WebIDBDatabaseException.h"
#include "third_party/leveldatabase/env_chromium.h"
-#include "webkit/common/database/database_identifier.h"
using base::ASCIIToUTF16;
@@ -24,12 +25,14 @@ namespace content {
const int64 kBackingStoreGracePeriodMs = 2000;
-IndexedDBFactory::IndexedDBFactory(IndexedDBContextImpl* context)
- : context_(context) {}
+IndexedDBFactoryImpl::IndexedDBFactoryImpl(IndexedDBContextImpl* context)
+ : context_(context) {
+}
-IndexedDBFactory::~IndexedDBFactory() {}
+IndexedDBFactoryImpl::~IndexedDBFactoryImpl() {
+}
-void IndexedDBFactory::RemoveDatabaseFromMaps(
+void IndexedDBFactoryImpl::RemoveDatabaseFromMaps(
const IndexedDBDatabase::Identifier& identifier) {
IndexedDBDatabaseMap::iterator it = database_map_.find(identifier);
DCHECK(it != database_map_.end());
@@ -47,10 +50,9 @@ void IndexedDBFactory::RemoveDatabaseFromMaps(
}
}
-void IndexedDBFactory::ReleaseDatabase(
+void IndexedDBFactoryImpl::ReleaseDatabase(
const IndexedDBDatabase::Identifier& identifier,
bool forcedClose) {
-
DCHECK(!database_map_.find(identifier)->second->backing_store());
RemoveDatabaseFromMaps(identifier);
@@ -61,8 +63,8 @@ void IndexedDBFactory::ReleaseDatabase(
ReleaseBackingStore(identifier.first, forcedClose);
}
-void IndexedDBFactory::ReleaseBackingStore(const GURL& origin_url,
- bool immediate) {
+void IndexedDBFactoryImpl::ReleaseBackingStore(const GURL& origin_url,
+ bool immediate) {
if (immediate) {
IndexedDBBackingStoreMap::iterator it =
backing_stores_with_active_blobs_.find(origin_url);
@@ -90,17 +92,18 @@ void IndexedDBFactory::ReleaseBackingStore(const GURL& origin_url,
backing_store_map_[origin_url]->close_timer()->Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kBackingStoreGracePeriodMs),
- base::Bind(&IndexedDBFactory::MaybeCloseBackingStore, this, origin_url));
+ base::Bind(
+ &IndexedDBFactoryImpl::MaybeCloseBackingStore, this, origin_url));
}
-void IndexedDBFactory::MaybeCloseBackingStore(const GURL& origin_url) {
+void IndexedDBFactoryImpl::MaybeCloseBackingStore(const GURL& origin_url) {
// Another reference may have opened since the maybe-close was posted, so it
// is necessary to check again.
if (HasLastBackingStoreReference(origin_url))
CloseBackingStore(origin_url);
}
-void IndexedDBFactory::CloseBackingStore(const GURL& origin_url) {
+void IndexedDBFactoryImpl::CloseBackingStore(const GURL& origin_url) {
IndexedDBBackingStoreMap::iterator it = backing_store_map_.find(origin_url);
DCHECK(it != backing_store_map_.end());
// Stop the timer (if it's running) - this may happen if the timer was started
@@ -109,8 +112,8 @@ void IndexedDBFactory::CloseBackingStore(const GURL& origin_url) {
backing_store_map_.erase(it);
}
-bool IndexedDBFactory::HasLastBackingStoreReference(const GURL& origin_url)
- const {
+bool IndexedDBFactoryImpl::HasLastBackingStoreReference(
+ const GURL& origin_url) const {
IndexedDBBackingStore* ptr;
{
// Scope so that the implicit scoped_refptr<> is freed.
@@ -122,9 +125,8 @@ bool IndexedDBFactory::HasLastBackingStoreReference(const GURL& origin_url)
return ptr->HasOneRef();
}
-void IndexedDBFactory::ForceClose(const GURL& origin_url) {
- std::pair<OriginDBMapIterator, OriginDBMapIterator> range =
- GetOpenDatabasesForOrigin(origin_url);
+void IndexedDBFactoryImpl::ForceClose(const GURL& origin_url) {
+ OriginDBs range = GetOpenDatabasesForOrigin(origin_url);
while (range.first != range.second) {
IndexedDBDatabase* db = range.first->second;
@@ -136,22 +138,20 @@ void IndexedDBFactory::ForceClose(const GURL& origin_url) {
ReleaseBackingStore(origin_url, true /* immediate */);
}
-void IndexedDBFactory::ContextDestroyed() {
+void IndexedDBFactoryImpl::ContextDestroyed() {
// Timers on backing stores hold a reference to this factory. When the
// context (which nominally owns this factory) is destroyed during thread
// termination the timers must be stopped so that this factory and the
// stores can be disposed of.
- for (IndexedDBBackingStoreMap::iterator it = backing_store_map_.begin();
- it != backing_store_map_.end();
- ++it)
- it->second->close_timer()->Stop();
+ for (const auto& it : backing_store_map_)
+ it.second->close_timer()->Stop();
backing_store_map_.clear();
backing_stores_with_active_blobs_.clear();
context_ = NULL;
}
-void IndexedDBFactory::ReportOutstandingBlobs(const GURL& origin_url,
- bool blobs_outstanding) {
+void IndexedDBFactoryImpl::ReportOutstandingBlobs(const GURL& origin_url,
+ bool blobs_outstanding) {
if (!context_)
return;
if (blobs_outstanding) {
@@ -171,24 +171,27 @@ void IndexedDBFactory::ReportOutstandingBlobs(const GURL& origin_url,
}
}
-void IndexedDBFactory::GetDatabaseNames(
+void IndexedDBFactoryImpl::GetDatabaseNames(
scoped_refptr<IndexedDBCallbacks> callbacks,
const GURL& origin_url,
const base::FilePath& data_directory,
net::URLRequestContext* request_context) {
- IDB_TRACE("IndexedDBFactory::GetDatabaseNames");
+ IDB_TRACE("IndexedDBFactoryImpl::GetDatabaseNames");
// TODO(dgrogan): Plumb data_loss back to script eventually?
blink::WebIDBDataLoss data_loss;
std::string data_loss_message;
bool disk_full;
+ leveldb::Status s;
+ // TODO(cmumford): Handle this error
scoped_refptr<IndexedDBBackingStore> backing_store =
OpenBackingStore(origin_url,
data_directory,
request_context,
&data_loss,
&data_loss_message,
- &disk_full);
- if (!backing_store) {
+ &disk_full,
+ &s);
+ if (!backing_store.get()) {
callbacks->OnError(
IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error opening backing store for "
@@ -196,24 +199,30 @@ void IndexedDBFactory::GetDatabaseNames(
return;
}
- leveldb::Status s;
std::vector<base::string16> names = backing_store->GetDatabaseNames(&s);
if (!s.ok()) {
- // TODO(cmumford): Handle this error
DLOG(ERROR) << "Internal error getting database names";
+ IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
+ "Internal error opening backing store for "
+ "indexedDB.webkitGetDatabaseNames.");
+ callbacks->OnError(error);
+ backing_store = NULL;
+ if (s.IsCorruption())
+ HandleBackingStoreCorruption(origin_url, error);
+ return;
}
callbacks->OnSuccess(names);
backing_store = NULL;
ReleaseBackingStore(origin_url, false /* immediate */);
}
-void IndexedDBFactory::DeleteDatabase(
+void IndexedDBFactoryImpl::DeleteDatabase(
const base::string16& name,
net::URLRequestContext* request_context,
scoped_refptr<IndexedDBCallbacks> callbacks,
const GURL& origin_url,
const base::FilePath& data_directory) {
- IDB_TRACE("IndexedDBFactory::DeleteDatabase");
+ IDB_TRACE("IndexedDBFactoryImpl::DeleteDatabase");
IndexedDBDatabase::Identifier unique_identifier(origin_url, name);
IndexedDBDatabaseMap::iterator it = database_map_.find(unique_identifier);
if (it != database_map_.end()) {
@@ -227,39 +236,45 @@ void IndexedDBFactory::DeleteDatabase(
blink::WebIDBDataLoss data_loss;
std::string data_loss_message;
bool disk_full = false;
+ leveldb::Status s;
scoped_refptr<IndexedDBBackingStore> backing_store =
OpenBackingStore(origin_url,
data_directory,
request_context,
&data_loss,
&data_loss_message,
- &disk_full);
- if (!backing_store) {
- callbacks->OnError(
- IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
- ASCIIToUTF16(
- "Internal error opening backing store "
- "for indexedDB.deleteDatabase.")));
+ &disk_full,
+ &s);
+ if (!backing_store.get()) {
+ IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
+ ASCIIToUTF16(
+ "Internal error opening backing store "
+ "for indexedDB.deleteDatabase."));
+ callbacks->OnError(error);
+ if (s.IsCorruption()) {
+ HandleBackingStoreCorruption(origin_url, error);
+ }
return;
}
- leveldb::Status s;
scoped_refptr<IndexedDBDatabase> database = IndexedDBDatabase::Create(
- name, backing_store, this, unique_identifier, &s);
- if (!database) {
+ name, backing_store.get(), this, unique_identifier, &s);
+ if (!database.get()) {
IndexedDBDatabaseError error(
blink::WebIDBDatabaseExceptionUnknownError,
ASCIIToUTF16(
"Internal error creating database backend for "
"indexedDB.deleteDatabase."));
callbacks->OnError(error);
- if (leveldb_env::IsCorruption(s))
+ if (leveldb_env::IsCorruption(s)) {
+ backing_store = NULL;
HandleBackingStoreCorruption(origin_url, error);
+ }
return;
}
- database_map_[unique_identifier] = database;
- origin_dbs_.insert(std::make_pair(origin_url, database));
+ database_map_[unique_identifier] = database.get();
+ origin_dbs_.insert(std::make_pair(origin_url, database.get()));
database->DeleteDatabase(callbacks);
RemoveDatabaseFromMaps(unique_identifier);
database = NULL;
@@ -267,7 +282,7 @@ void IndexedDBFactory::DeleteDatabase(
ReleaseBackingStore(origin_url, false /* immediate */);
}
-void IndexedDBFactory::DatabaseDeleted(
+void IndexedDBFactoryImpl::DatabaseDeleted(
const IndexedDBDatabase::Identifier& identifier) {
// NULL after ContextDestroyed() called, and in some unit tests.
if (!context_)
@@ -275,7 +290,7 @@ void IndexedDBFactory::DatabaseDeleted(
context_->DatabaseDeleted(identifier.first);
}
-void IndexedDBFactory::HandleBackingStoreFailure(const GURL& origin_url) {
+void IndexedDBFactoryImpl::HandleBackingStoreFailure(const GURL& origin_url) {
// NULL after ContextDestroyed() called, and in some unit tests.
if (!context_)
return;
@@ -283,7 +298,7 @@ void IndexedDBFactory::HandleBackingStoreFailure(const GURL& origin_url) {
IndexedDBContextImpl::FORCE_CLOSE_BACKING_STORE_FAILURE);
}
-void IndexedDBFactory::HandleBackingStoreCorruption(
+void IndexedDBFactoryImpl::HandleBackingStoreCorruption(
const GURL& origin_url,
const IndexedDBDatabaseError& error) {
// Make a copy of origin_url as this is likely a reference to a member of a
@@ -302,17 +317,17 @@ void IndexedDBFactory::HandleBackingStoreCorruption(
DLOG(ERROR) << "Unable to delete backing store: " << s.ToString();
}
-bool IndexedDBFactory::IsDatabaseOpen(const GURL& origin_url,
- const base::string16& name) const {
+bool IndexedDBFactoryImpl::IsDatabaseOpen(const GURL& origin_url,
+ const base::string16& name) const {
return !!database_map_.count(IndexedDBDatabase::Identifier(origin_url, name));
}
-bool IndexedDBFactory::IsBackingStoreOpen(const GURL& origin_url) const {
+bool IndexedDBFactoryImpl::IsBackingStoreOpen(const GURL& origin_url) const {
return backing_store_map_.find(origin_url) != backing_store_map_.end();
}
-bool IndexedDBFactory::IsBackingStorePendingClose(const GURL& origin_url)
- const {
+bool IndexedDBFactoryImpl::IsBackingStorePendingClose(
+ const GURL& origin_url) const {
IndexedDBBackingStoreMap::const_iterator it =
backing_store_map_.find(origin_url);
if (it == backing_store_map_.end())
@@ -320,14 +335,16 @@ bool IndexedDBFactory::IsBackingStorePendingClose(const GURL& origin_url)
return it->second->close_timer()->IsRunning();
}
-scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStoreHelper(
+scoped_refptr<IndexedDBBackingStore>
+IndexedDBFactoryImpl::OpenBackingStoreHelper(
const GURL& origin_url,
const base::FilePath& data_directory,
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message,
bool* disk_full,
- bool first_time) {
+ bool first_time,
+ leveldb::Status* status) {
return IndexedDBBackingStore::Open(this,
origin_url,
data_directory,
@@ -336,16 +353,18 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStoreHelper(
data_loss_message,
disk_full,
context_->TaskRunner(),
- first_time);
+ first_time,
+ status);
}
-scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStore(
+scoped_refptr<IndexedDBBackingStore> IndexedDBFactoryImpl::OpenBackingStore(
const GURL& origin_url,
const base::FilePath& data_directory,
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message,
- bool* disk_full) {
+ bool* disk_full,
+ leveldb::Status* status) {
const bool open_in_memory = data_directory.empty();
IndexedDBBackingStoreMap::iterator it2 = backing_store_map_.find(origin_url);
@@ -357,8 +376,8 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStore(
scoped_refptr<IndexedDBBackingStore> backing_store;
bool first_time = false;
if (open_in_memory) {
- backing_store =
- IndexedDBBackingStore::OpenInMemory(origin_url, context_->TaskRunner());
+ backing_store = IndexedDBBackingStore::OpenInMemory(
+ origin_url, context_->TaskRunner(), status);
} else {
first_time = !backends_opened_since_boot_.count(origin_url);
@@ -368,7 +387,8 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStore(
data_loss,
data_loss_message,
disk_full,
- first_time);
+ first_time,
+ status);
}
if (backing_store.get()) {
@@ -389,12 +409,12 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStore(
return 0;
}
-void IndexedDBFactory::Open(const base::string16& name,
- const IndexedDBPendingConnection& connection,
- net::URLRequestContext* request_context,
- const GURL& origin_url,
- const base::FilePath& data_directory) {
- IDB_TRACE("IndexedDBFactory::Open");
+void IndexedDBFactoryImpl::Open(const base::string16& name,
+ const IndexedDBPendingConnection& connection,
+ net::URLRequestContext* request_context,
+ const GURL& origin_url,
+ const base::FilePath& data_directory) {
+ IDB_TRACE("IndexedDBFactoryImpl::Open");
scoped_refptr<IndexedDBDatabase> database;
IndexedDBDatabase::Identifier unique_identifier(origin_url, name);
IndexedDBDatabaseMap::iterator it = database_map_.find(unique_identifier);
@@ -404,14 +424,16 @@ void IndexedDBFactory::Open(const base::string16& name,
bool disk_full = false;
bool was_open = (it != database_map_.end());
if (!was_open) {
+ leveldb::Status s;
scoped_refptr<IndexedDBBackingStore> backing_store =
OpenBackingStore(origin_url,
data_directory,
request_context,
&data_loss,
&data_loss_message,
- &disk_full);
- if (!backing_store) {
+ &disk_full,
+ &s);
+ if (!backing_store.get()) {
if (disk_full) {
connection.callbacks->OnError(
IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionQuotaError,
@@ -420,17 +442,20 @@ void IndexedDBFactory::Open(const base::string16& name,
"backing store for indexedDB.open.")));
return;
}
- connection.callbacks->OnError(IndexedDBDatabaseError(
- blink::WebIDBDatabaseExceptionUnknownError,
- ASCIIToUTF16(
- "Internal error opening backing store for indexedDB.open.")));
+ IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
+ ASCIIToUTF16(
+ "Internal error opening backing store"
+ " for indexedDB.open."));
+ connection.callbacks->OnError(error);
+ if (s.IsCorruption()) {
+ HandleBackingStoreCorruption(origin_url, error);
+ }
return;
}
- leveldb::Status s;
database = IndexedDBDatabase::Create(
- name, backing_store, this, unique_identifier, &s);
- if (!database) {
+ name, backing_store.get(), this, unique_identifier, &s);
+ if (!database.get()) {
DLOG(ERROR) << "Unable to create the database";
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
ASCIIToUTF16(
@@ -454,22 +479,21 @@ void IndexedDBFactory::Open(const base::string16& name,
database->OpenConnection(connection);
if (!was_open && database->ConnectionCount() > 0) {
- database_map_[unique_identifier] = database;
- origin_dbs_.insert(std::make_pair(origin_url, database));
+ database_map_[unique_identifier] = database.get();
+ origin_dbs_.insert(std::make_pair(origin_url, database.get()));
}
}
-std::pair<IndexedDBFactory::OriginDBMapIterator,
- IndexedDBFactory::OriginDBMapIterator>
-IndexedDBFactory::GetOpenDatabasesForOrigin(const GURL& origin_url) const {
+std::pair<IndexedDBFactoryImpl::OriginDBMapIterator,
+ IndexedDBFactoryImpl::OriginDBMapIterator>
+IndexedDBFactoryImpl::GetOpenDatabasesForOrigin(const GURL& origin_url) const {
return origin_dbs_.equal_range(origin_url);
}
-size_t IndexedDBFactory::GetConnectionCount(const GURL& origin_url) const {
+size_t IndexedDBFactoryImpl::GetConnectionCount(const GURL& origin_url) const {
size_t count(0);
- std::pair<OriginDBMapIterator, OriginDBMapIterator> range =
- GetOpenDatabasesForOrigin(origin_url);
+ OriginDBs range = GetOpenDatabasesForOrigin(origin_url);
for (OriginDBMapIterator it = range.first; it != range.second; ++it)
count += it->second->ConnectionCount();
diff --git a/chromium/content/browser/indexed_db/indexed_db_factory_impl.h b/chromium/content/browser/indexed_db/indexed_db_factory_impl.h
new file mode 100644
index 00000000000..da9d2a9a45b
--- /dev/null
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_impl.h
@@ -0,0 +1,136 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_FACTORY_IMPL_H_
+#define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_FACTORY_IMPL_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "content/browser/indexed_db/indexed_db_factory.h"
+
+namespace content {
+
+class IndexedDBContextImpl;
+
+class CONTENT_EXPORT IndexedDBFactoryImpl : public IndexedDBFactory {
+ public:
+ explicit IndexedDBFactoryImpl(IndexedDBContextImpl* context);
+
+ // content::IndexedDBFactory overrides:
+ void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
+ bool forcedClose) override;
+
+ void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
+ const GURL& origin_url,
+ const base::FilePath& data_directory,
+ net::URLRequestContext* request_context) override;
+ void Open(const base::string16& name,
+ const IndexedDBPendingConnection& connection,
+ net::URLRequestContext* request_context,
+ const GURL& origin_url,
+ const base::FilePath& data_directory) override;
+
+ void DeleteDatabase(const base::string16& name,
+ net::URLRequestContext* request_context,
+ scoped_refptr<IndexedDBCallbacks> callbacks,
+ const GURL& origin_url,
+ const base::FilePath& data_directory) override;
+
+ void HandleBackingStoreFailure(const GURL& origin_url) override;
+ void HandleBackingStoreCorruption(
+ const GURL& origin_url,
+ const IndexedDBDatabaseError& error) override;
+
+ OriginDBs GetOpenDatabasesForOrigin(const GURL& origin_url) const override;
+
+ void ForceClose(const GURL& origin_url) override;
+
+ // Called by the IndexedDBContext destructor so the factory can do cleanup.
+ void ContextDestroyed() override;
+
+ // Called by the IndexedDBActiveBlobRegistry.
+ void ReportOutstandingBlobs(const GURL& origin_url,
+ bool blobs_outstanding) override;
+
+ // Called by an IndexedDBDatabase when it is actually deleted.
+ void DatabaseDeleted(
+ const IndexedDBDatabase::Identifier& identifier) override;
+
+ size_t GetConnectionCount(const GURL& origin_url) const override;
+
+ protected:
+ ~IndexedDBFactoryImpl() override;
+
+ scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
+ const GURL& origin_url,
+ const base::FilePath& data_directory,
+ net::URLRequestContext* request_context,
+ blink::WebIDBDataLoss* data_loss,
+ std::string* data_loss_reason,
+ bool* disk_full,
+ leveldb::Status* s) override;
+
+ scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
+ const GURL& origin_url,
+ const base::FilePath& data_directory,
+ net::URLRequestContext* request_context,
+ blink::WebIDBDataLoss* data_loss,
+ std::string* data_loss_message,
+ bool* disk_full,
+ bool first_time,
+ leveldb::Status* s) override;
+
+ void ReleaseBackingStore(const GURL& origin_url, bool immediate);
+ void CloseBackingStore(const GURL& origin_url);
+ IndexedDBContextImpl* context() const { return context_; }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
+ BackingStoreReleasedOnForcedClose);
+ FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
+ BackingStoreReleaseDelayedOnClose);
+ FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest, DatabaseFailedOpen);
+ FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
+ DeleteDatabaseClosesBackingStore);
+ FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
+ ForceCloseReleasesBackingStore);
+ FRIEND_TEST_ALL_PREFIXES(IndexedDBFactoryTest,
+ GetDatabaseNamesClosesBackingStore);
+ FRIEND_TEST_ALL_PREFIXES(IndexedDBTest,
+ ForceCloseOpenDatabasesOnCommitFailure);
+
+ typedef std::map<IndexedDBDatabase::Identifier, IndexedDBDatabase*>
+ IndexedDBDatabaseMap;
+ typedef std::map<GURL, scoped_refptr<IndexedDBBackingStore> >
+ IndexedDBBackingStoreMap;
+
+ // Called internally after a database is closed, with some delay. If this
+ // factory has the last reference, it will be released.
+ void MaybeCloseBackingStore(const GURL& origin_url);
+ bool HasLastBackingStoreReference(const GURL& origin_url) const;
+
+ // Testing helpers, so unit tests don't need to grovel through internal state.
+ bool IsDatabaseOpen(const GURL& origin_url, const base::string16& name) const;
+ bool IsBackingStoreOpen(const GURL& origin_url) const;
+ bool IsBackingStorePendingClose(const GURL& origin_url) const;
+ void RemoveDatabaseFromMaps(const IndexedDBDatabase::Identifier& identifier);
+
+ IndexedDBContextImpl* context_;
+
+ IndexedDBDatabaseMap database_map_;
+ OriginDBMap origin_dbs_;
+ IndexedDBBackingStoreMap backing_store_map_;
+
+ std::set<scoped_refptr<IndexedDBBackingStore> > session_only_backing_stores_;
+ IndexedDBBackingStoreMap backing_stores_with_active_blobs_;
+ std::set<GURL> backends_opened_since_boot_;
+
+ DISALLOW_COPY_AND_ASSIGN(IndexedDBFactoryImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_FACTORY_IMPL_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 975f9bcbcd3..70f8ae64ad5 100644
--- a/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -2,9 +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/indexed_db/indexed_db_factory.h"
-
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
@@ -12,13 +10,14 @@
#include "base/test/test_simple_task_runner.h"
#include "content/browser/indexed_db/indexed_db_connection.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
+#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 "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
#include "third_party/WebKit/public/platform/WebIDBTypes.h"
#include "url/gurl.h"
-#include "webkit/common/database/database_identifier.h"
using base::ASCIIToUTF16;
@@ -26,10 +25,10 @@ namespace content {
namespace {
-class MockIDBFactory : public IndexedDBFactory {
+class MockIDBFactory : public IndexedDBFactoryImpl {
public:
explicit MockIDBFactory(IndexedDBContextImpl* context)
- : IndexedDBFactory(context) {}
+ : IndexedDBFactoryImpl(context) {}
scoped_refptr<IndexedDBBackingStore> TestOpenBackingStore(
const GURL& origin,
const base::FilePath& data_directory) {
@@ -37,13 +36,15 @@ class MockIDBFactory : public IndexedDBFactory {
blink::WebIDBDataLossNone;
std::string data_loss_message;
bool disk_full;
+ leveldb::Status s;
scoped_refptr<IndexedDBBackingStore> backing_store =
OpenBackingStore(origin,
data_directory,
NULL /* request_context */,
&data_loss,
&data_loss_message,
- &disk_full);
+ &disk_full,
+ &s);
EXPECT_EQ(blink::WebIDBDataLossNone, data_loss);
return backing_store;
}
@@ -58,7 +59,7 @@ class MockIDBFactory : public IndexedDBFactory {
}
private:
- virtual ~MockIDBFactory() {}
+ ~MockIDBFactory() override {}
DISALLOW_COPY_AND_ASSIGN(MockIDBFactory);
};
@@ -108,8 +109,8 @@ TEST_F(IndexedDBFactoryTest, BackingStoreLifetime) {
scoped_refptr<IndexedDBBackingStore> disk_store3 =
factory()->TestOpenBackingStore(origin2, temp_directory.path());
- factory()->TestCloseBackingStore(disk_store1);
- factory()->TestCloseBackingStore(disk_store3);
+ factory()->TestCloseBackingStore(disk_store1.get());
+ factory()->TestCloseBackingStore(disk_store3.get());
EXPECT_FALSE(disk_store1->HasOneRef());
EXPECT_FALSE(disk_store2->HasOneRef());
@@ -161,8 +162,8 @@ TEST_F(IndexedDBFactoryTest, MemoryBackingStoreLifetime) {
scoped_refptr<IndexedDBBackingStore> mem_store3 =
factory()->TestOpenBackingStore(origin2, base::FilePath());
- factory()->TestCloseBackingStore(mem_store1);
- factory()->TestCloseBackingStore(mem_store3);
+ factory()->TestCloseBackingStore(mem_store1.get());
+ factory()->TestCloseBackingStore(mem_store3.get());
EXPECT_FALSE(mem_store1->HasOneRef());
EXPECT_FALSE(mem_store2->HasOneRef());
@@ -189,29 +190,31 @@ TEST_F(IndexedDBFactoryTest, RejectLongOrigins) {
GURL too_long_origin("http://" + origin + ":81/");
scoped_refptr<IndexedDBBackingStore> diskStore1 =
factory()->TestOpenBackingStore(too_long_origin, base_path);
- EXPECT_FALSE(diskStore1);
+ EXPECT_FALSE(diskStore1.get());
GURL ok_origin("http://someorigin.com:82/");
scoped_refptr<IndexedDBBackingStore> diskStore2 =
factory()->TestOpenBackingStore(ok_origin, base_path);
- EXPECT_TRUE(diskStore2);
+ EXPECT_TRUE(diskStore2.get());
}
-class DiskFullFactory : public IndexedDBFactory {
+class DiskFullFactory : public IndexedDBFactoryImpl {
public:
explicit DiskFullFactory(IndexedDBContextImpl* context)
- : IndexedDBFactory(context) {}
+ : IndexedDBFactoryImpl(context) {}
private:
- virtual ~DiskFullFactory() {}
- virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
+ ~DiskFullFactory() override {}
+ scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
const GURL& origin_url,
const base::FilePath& data_directory,
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message,
- bool* disk_full) OVERRIDE {
+ bool* disk_full,
+ leveldb::Status* s) override {
*disk_full = true;
+ *s = leveldb::Status::IOError("Disk is full");
return scoped_refptr<IndexedDBBackingStore>();
}
@@ -222,14 +225,14 @@ class LookingForQuotaErrorMockCallbacks : public IndexedDBCallbacks {
public:
LookingForQuotaErrorMockCallbacks()
: IndexedDBCallbacks(NULL, 0, 0), error_called_(false) {}
- virtual void OnError(const IndexedDBDatabaseError& error) OVERRIDE {
+ void OnError(const IndexedDBDatabaseError& error) override {
error_called_ = true;
EXPECT_EQ(blink::WebIDBDatabaseExceptionQuotaError, error.code());
}
bool error_called() const { return error_called_; }
private:
- virtual ~LookingForQuotaErrorMockCallbacks() {}
+ ~LookingForQuotaErrorMockCallbacks() override {}
bool error_called_;
DISALLOW_COPY_AND_ASSIGN(LookingForQuotaErrorMockCallbacks);
@@ -431,21 +434,21 @@ class UpgradeNeededCallbacks : public MockIndexedDBCallbacks {
public:
UpgradeNeededCallbacks() {}
- virtual void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
- const IndexedDBDatabaseMetadata& metadata) OVERRIDE {
+ void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
+ const IndexedDBDatabaseMetadata& metadata) override {
EXPECT_TRUE(connection_.get());
EXPECT_FALSE(connection.get());
}
- virtual void OnUpgradeNeeded(
+ void OnUpgradeNeeded(
int64 old_version,
scoped_ptr<IndexedDBConnection> connection,
- const content::IndexedDBDatabaseMetadata& metadata) OVERRIDE {
+ const content::IndexedDBDatabaseMetadata& metadata) override {
connection_ = connection.Pass();
}
protected:
- virtual ~UpgradeNeededCallbacks() {}
+ ~UpgradeNeededCallbacks() override {}
private:
DISALLOW_COPY_AND_ASSIGN(UpgradeNeededCallbacks);
@@ -455,13 +458,13 @@ class ErrorCallbacks : public MockIndexedDBCallbacks {
public:
ErrorCallbacks() : MockIndexedDBCallbacks(false), saw_error_(false) {}
- virtual void OnError(const IndexedDBDatabaseError& error) OVERRIDE {
+ void OnError(const IndexedDBDatabaseError& error) override {
saw_error_= true;
}
bool saw_error() const { return saw_error_; }
private:
- virtual ~ErrorCallbacks() {}
+ ~ErrorCallbacks() override {}
bool saw_error_;
DISALLOW_COPY_AND_ASSIGN(ErrorCallbacks);
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 461c0808c60..49040ae9478 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
@@ -20,7 +20,7 @@ IndexedDBFakeBackingStore::IndexedDBFakeBackingStore()
}
IndexedDBFakeBackingStore::IndexedDBFakeBackingStore(
IndexedDBFactory* factory,
- base::TaskRunner* task_runner)
+ base::SequencedTaskRunner* task_runner)
: IndexedDBBackingStore(factory,
GURL("http://localhost:81"),
base::FilePath(),
@@ -82,8 +82,8 @@ leveldb::Status IndexedDBFakeBackingStore::PutRecord(
int64 database_id,
int64 object_store_id,
const IndexedDBKey& key,
- IndexedDBValue& value,
- ScopedVector<webkit_blob::BlobDataHandle>* handles,
+ IndexedDBValue* value,
+ ScopedVector<storage::BlobDataHandle>* handles,
RecordIdentifier* record) {
return leveldb::Status::OK();
}
@@ -163,7 +163,7 @@ IndexedDBFakeBackingStore::OpenObjectStoreKeyCursor(
int64 database_id,
int64 object_store_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
leveldb::Status* s) {
return scoped_ptr<IndexedDBBackingStore::Cursor>();
}
@@ -173,7 +173,7 @@ IndexedDBFakeBackingStore::OpenObjectStoreCursor(
int64 database_id,
int64 object_store_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
leveldb::Status* s) {
return scoped_ptr<IndexedDBBackingStore::Cursor>();
}
@@ -184,7 +184,7 @@ IndexedDBFakeBackingStore::OpenIndexKeyCursor(
int64 object_store_id,
int64 index_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
leveldb::Status* s) {
return scoped_ptr<IndexedDBBackingStore::Cursor>();
}
@@ -195,7 +195,7 @@ IndexedDBFakeBackingStore::OpenIndexCursor(
int64 object_store_id,
int64 index_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
+ blink::WebIDBCursorDirection,
leveldb::Status* s) {
return scoped_ptr<IndexedDBBackingStore::Cursor>();
}
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 fef28af3bd9..9a4fd0927a6 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
@@ -10,7 +10,7 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
namespace base {
-class TaskRunner;
+class SequencedTaskRunner;
}
namespace content {
@@ -21,126 +21,118 @@ class IndexedDBFakeBackingStore : public IndexedDBBackingStore {
public:
IndexedDBFakeBackingStore();
IndexedDBFakeBackingStore(IndexedDBFactory* factory,
- base::TaskRunner* task_runner);
- virtual std::vector<base::string16> GetDatabaseNames(leveldb::Status* s)
- OVERRIDE;
- virtual leveldb::Status GetIDBDatabaseMetaData(const base::string16& name,
- IndexedDBDatabaseMetadata*,
- bool* found) OVERRIDE;
- virtual leveldb::Status CreateIDBDatabaseMetaData(
- const base::string16& name,
- const base::string16& version,
- int64 int_version,
- int64* row_id) OVERRIDE;
- virtual bool UpdateIDBDatabaseIntVersion(Transaction*,
- int64 row_id,
- int64 version) OVERRIDE;
- virtual leveldb::Status DeleteDatabase(const base::string16& name) OVERRIDE;
-
- virtual leveldb::Status CreateObjectStore(Transaction*,
- int64 database_id,
- int64 object_store_id,
- const base::string16& name,
- const IndexedDBKeyPath&,
- bool auto_increment) OVERRIDE;
-
- virtual leveldb::Status DeleteObjectStore(Transaction* transaction,
- int64 database_id,
- int64 object_store_id) OVERRIDE;
-
- virtual leveldb::Status PutRecord(
- IndexedDBBackingStore::Transaction* transaction,
- int64 database_id,
- int64 object_store_id,
- const IndexedDBKey& key,
- IndexedDBValue& value,
- ScopedVector<webkit_blob::BlobDataHandle>* handles,
- RecordIdentifier* record) OVERRIDE;
-
- virtual leveldb::Status ClearObjectStore(Transaction*,
- int64 database_id,
- int64 object_store_id) OVERRIDE;
- virtual leveldb::Status DeleteRecord(Transaction*,
- int64 database_id,
- int64 object_store_id,
- const RecordIdentifier&) OVERRIDE;
- virtual leveldb::Status GetKeyGeneratorCurrentNumber(Transaction*,
- int64 database_id,
- int64 object_store_id,
- int64* current_number)
- OVERRIDE;
- virtual leveldb::Status MaybeUpdateKeyGeneratorCurrentNumber(
+ base::SequencedTaskRunner* task_runner);
+ std::vector<base::string16> GetDatabaseNames(leveldb::Status* s) override;
+ leveldb::Status GetIDBDatabaseMetaData(const base::string16& name,
+ IndexedDBDatabaseMetadata*,
+ bool* found) override;
+ leveldb::Status CreateIDBDatabaseMetaData(const base::string16& name,
+ const base::string16& version,
+ int64 int_version,
+ int64* row_id) override;
+ bool UpdateIDBDatabaseIntVersion(Transaction*,
+ int64 row_id,
+ int64 version) override;
+ leveldb::Status DeleteDatabase(const base::string16& name) override;
+
+ leveldb::Status CreateObjectStore(Transaction*,
+ int64 database_id,
+ int64 object_store_id,
+ const base::string16& name,
+ const IndexedDBKeyPath&,
+ bool auto_increment) override;
+
+ leveldb::Status DeleteObjectStore(Transaction* transaction,
+ int64 database_id,
+ int64 object_store_id) override;
+
+ leveldb::Status PutRecord(IndexedDBBackingStore::Transaction* transaction,
+ int64 database_id,
+ int64 object_store_id,
+ const IndexedDBKey& key,
+ IndexedDBValue* value,
+ ScopedVector<storage::BlobDataHandle>* handles,
+ RecordIdentifier* record) override;
+
+ leveldb::Status ClearObjectStore(Transaction*,
+ int64 database_id,
+ int64 object_store_id) override;
+ leveldb::Status DeleteRecord(Transaction*,
+ int64 database_id,
+ int64 object_store_id,
+ const RecordIdentifier&) override;
+ leveldb::Status GetKeyGeneratorCurrentNumber(Transaction*,
+ int64 database_id,
+ int64 object_store_id,
+ int64* current_number) override;
+ leveldb::Status MaybeUpdateKeyGeneratorCurrentNumber(
Transaction*,
int64 database_id,
int64 object_store_id,
int64 new_number,
- bool check_current) OVERRIDE;
- virtual leveldb::Status KeyExistsInObjectStore(
+ bool check_current) override;
+ leveldb::Status KeyExistsInObjectStore(
Transaction*,
int64 database_id,
int64 object_store_id,
const IndexedDBKey&,
RecordIdentifier* found_record_identifier,
- bool* found) OVERRIDE;
-
- virtual leveldb::Status CreateIndex(Transaction*,
- int64 database_id,
- int64 object_store_id,
- int64 index_id,
- const base::string16& name,
- const IndexedDBKeyPath&,
- bool is_unique,
- bool is_multi_entry) OVERRIDE;
- virtual leveldb::Status DeleteIndex(Transaction*,
- int64 database_id,
- int64 object_store_id,
- int64 index_id) OVERRIDE;
- virtual leveldb::Status PutIndexDataForRecord(Transaction*,
- int64 database_id,
- int64 object_store_id,
- int64 index_id,
- const IndexedDBKey&,
- const RecordIdentifier&)
- OVERRIDE;
- virtual void ReportBlobUnused(int64 database_id, int64 blob_key) OVERRIDE;
- virtual scoped_ptr<Cursor> OpenObjectStoreKeyCursor(
+ bool* found) override;
+
+ leveldb::Status CreateIndex(Transaction*,
+ int64 database_id,
+ int64 object_store_id,
+ int64 index_id,
+ const base::string16& name,
+ const IndexedDBKeyPath&,
+ bool is_unique,
+ bool is_multi_entry) override;
+ leveldb::Status DeleteIndex(Transaction*,
+ int64 database_id,
+ int64 object_store_id,
+ int64 index_id) override;
+ leveldb::Status PutIndexDataForRecord(Transaction*,
+ int64 database_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKey&,
+ const RecordIdentifier&) override;
+ void ReportBlobUnused(int64 database_id, int64 blob_key) override;
+ scoped_ptr<Cursor> OpenObjectStoreKeyCursor(
Transaction* transaction,
int64 database_id,
int64 object_store_id,
const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
- leveldb::Status*) OVERRIDE;
- virtual scoped_ptr<Cursor> OpenObjectStoreCursor(
- Transaction* transaction,
- int64 database_id,
- int64 object_store_id,
- const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
- leveldb::Status*) OVERRIDE;
- virtual scoped_ptr<Cursor> OpenIndexKeyCursor(
- Transaction* transaction,
- int64 database_id,
- int64 object_store_id,
- int64 index_id,
- const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
- leveldb::Status*) OVERRIDE;
- virtual scoped_ptr<Cursor> OpenIndexCursor(Transaction* transaction,
- int64 database_id,
- int64 object_store_id,
- int64 index_id,
- const IndexedDBKeyRange& key_range,
- indexed_db::CursorDirection,
- leveldb::Status*) OVERRIDE;
+ blink::WebIDBCursorDirection,
+ leveldb::Status*) override;
+ scoped_ptr<Cursor> OpenObjectStoreCursor(Transaction* transaction,
+ int64 database_id,
+ int64 object_store_id,
+ const IndexedDBKeyRange& key_range,
+ blink::WebIDBCursorDirection,
+ leveldb::Status*) override;
+ scoped_ptr<Cursor> OpenIndexKeyCursor(Transaction* transaction,
+ int64 database_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKeyRange& key_range,
+ blink::WebIDBCursorDirection,
+ leveldb::Status*) override;
+ scoped_ptr<Cursor> OpenIndexCursor(Transaction* transaction,
+ int64 database_id,
+ int64 object_store_id,
+ int64 index_id,
+ const IndexedDBKeyRange& key_range,
+ blink::WebIDBCursorDirection,
+ leveldb::Status*) override;
class FakeTransaction : public IndexedDBBackingStore::Transaction {
public:
explicit FakeTransaction(leveldb::Status phase_two_result);
- virtual void Begin() OVERRIDE;
- virtual leveldb::Status CommitPhaseOne(
- scoped_refptr<BlobWriteCallback>) OVERRIDE;
- virtual leveldb::Status CommitPhaseTwo() OVERRIDE;
- virtual void Rollback() OVERRIDE;
+ void Begin() override;
+ leveldb::Status CommitPhaseOne(scoped_refptr<BlobWriteCallback>) override;
+ leveldb::Status CommitPhaseTwo() override;
+ void Rollback() override;
private:
leveldb::Status result_;
@@ -150,8 +142,9 @@ class IndexedDBFakeBackingStore : public IndexedDBBackingStore {
protected:
friend class base::RefCounted<IndexedDBFakeBackingStore>;
- virtual ~IndexedDBFakeBackingStore();
+ ~IndexedDBFakeBackingStore() override;
+ private:
DISALLOW_COPY_AND_ASSIGN(IndexedDBFakeBackingStore);
};
diff --git a/chromium/content/browser/indexed_db/indexed_db_index_writer.cc b/chromium/content/browser/indexed_db/indexed_db_index_writer.cc
index 0f5a25419ab..c9de8a3acb8 100644
--- a/chromium/content/browser/indexed_db/indexed_db_index_writer.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_index_writer.cc
@@ -131,16 +131,13 @@ bool MakeIndexWriters(
bool* completed) {
*completed = false;
- for (std::vector<IndexedDBDatabase::IndexKeys>::const_iterator it =
- index_keys.begin();
- it != index_keys.end();
- ++it) {
+ for (const auto& it : index_keys) {
IndexedDBObjectStoreMetadata::IndexMap::const_iterator found =
- object_store.indexes.find(it->first);
+ object_store.indexes.find(it.first);
if (found == object_store.indexes.end())
continue;
const IndexedDBIndexMetadata& index = found->second;
- IndexedDBDatabase::IndexKeys keys = *it;
+ IndexedDBDatabase::IndexKeys keys = it;
// If the object_store is using auto_increment, then any indexes with an
// identical key_path need to also use the primary (generated) key as a key.
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 5e181f43c89..472e1b9abcf 100644
--- a/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -11,6 +11,7 @@
#include "base/threading/platform_thread.h"
#include "base/values.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
+#include "content/grit/content_resources.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
@@ -20,10 +21,9 @@
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/common/url_constants.h"
-#include "grit/content_resources.h"
+#include "storage/common/database/database_identifier.h"
#include "third_party/zlib/google/zip.h"
#include "ui/base/text/bytes_formatting.h"
-#include "webkit/common/database/database_identifier.h"
namespace content {
@@ -44,7 +44,6 @@ IndexedDBInternalsUI::IndexedDBInternalsUI(WebUI* web_ui)
WebUIDataSource* source =
WebUIDataSource::Create(kChromeUIIndexedDBInternalsHost);
- source->SetUseJsonJSFormatV2();
source->SetJsonPath("strings.js");
source->AddResourcePath("indexeddb_internals.js",
IDR_INDEXED_DB_INTERNALS_JS);
@@ -87,15 +86,19 @@ void IndexedDBInternalsUI::GetAllOriginsOnIndexedDBThread(
const base::FilePath& context_path) {
DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
- scoped_ptr<base::ListValue> info_list(static_cast<IndexedDBContextImpl*>(
- context.get())->GetAllOriginsDetails());
+ IndexedDBContextImpl* context_impl =
+ static_cast<IndexedDBContextImpl*>(context.get());
- BrowserThread::PostTask(BrowserThread::UI,
- FROM_HERE,
- base::Bind(&IndexedDBInternalsUI::OnOriginsReady,
- base::Unretained(this),
- base::Passed(&info_list),
- context_path));
+ scoped_ptr<base::ListValue> info_list(context_impl->GetAllOriginsDetails());
+ bool is_incognito = context_impl->is_incognito();
+
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&IndexedDBInternalsUI::OnOriginsReady,
+ base::Unretained(this),
+ base::Passed(&info_list),
+ is_incognito ? base::FilePath() : context_path));
}
void IndexedDBInternalsUI::OnOriginsReady(scoped_ptr<base::ListValue> origins,
@@ -148,7 +151,7 @@ bool IndexedDBInternalsUI::GetOriginContext(
base::Bind(&FindContext, path, &result_partition, context);
BrowserContext::ForEachStoragePartition(browser_context, cb);
- if (!result_partition || !(*context))
+ if (!result_partition || !(context->get()))
return false;
return true;
@@ -163,7 +166,7 @@ void IndexedDBInternalsUI::DownloadOriginData(const base::ListValue* args) {
if (!GetOriginData(args, &partition_path, &origin_url, &context))
return;
- DCHECK(context);
+ DCHECK(context.get());
context->TaskRunner()->PostTask(
FROM_HERE,
base::Bind(&IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread,
@@ -213,7 +216,7 @@ void IndexedDBInternalsUI::DownloadOriginDataOnIndexedDBThread(
// has completed.
base::FilePath temp_path = temp_dir.Take();
- std::string origin_id = webkit_database::GetIdentifierFromOrigin(origin_url);
+ std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
base::FilePath zip_path =
temp_path.AppendASCII(origin_id).AddExtension(FILE_PATH_LITERAL("zip"));
@@ -301,12 +304,12 @@ void IndexedDBInternalsUI::OnDownloadDataReady(
class FileDeleter : public DownloadItem::Observer {
public:
explicit FileDeleter(const base::FilePath& temp_dir) : temp_dir_(temp_dir) {}
- virtual ~FileDeleter();
+ ~FileDeleter() override;
- virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE;
- virtual void OnDownloadOpened(DownloadItem* item) OVERRIDE {}
- virtual void OnDownloadRemoved(DownloadItem* item) OVERRIDE {}
- virtual void OnDownloadDestroyed(DownloadItem* item) OVERRIDE {}
+ void OnDownloadUpdated(DownloadItem* download) override;
+ void OnDownloadOpened(DownloadItem* item) override {}
+ void OnDownloadRemoved(DownloadItem* item) override {}
+ void OnDownloadDestroyed(DownloadItem* item) override {}
private:
const base::FilePath temp_dir_;
@@ -332,7 +335,7 @@ void FileDeleter::OnDownloadUpdated(DownloadItem* item) {
FileDeleter::~FileDeleter() {
base::ScopedTempDir path;
- bool will_delete ALLOW_UNUSED = path.Set(temp_dir_);
+ bool will_delete = path.Set(temp_dir_);
DCHECK(will_delete);
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_internals_ui.h b/chromium/content/browser/indexed_db/indexed_db_internals_ui.h
index f51df01db09..157978f433b 100644
--- a/chromium/content/browser/indexed_db/indexed_db_internals_ui.h
+++ b/chromium/content/browser/indexed_db/indexed_db_internals_ui.h
@@ -27,7 +27,7 @@ class StoragePartition;
class IndexedDBInternalsUI : public WebUIController {
public:
explicit IndexedDBInternalsUI(WebUI* web_ui);
- virtual ~IndexedDBInternalsUI();
+ ~IndexedDBInternalsUI() override;
private:
void GetAllOrigins(const base::ListValue* args);
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 d0064267c93..f8a3a1e51bd 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.cc
@@ -54,7 +54,7 @@
// <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 [DatabaseNameKey]
+// <0, 0, 0, 201, origin, database name> => Database id (int) [DatabaseNameKey]
//
//
// Database metadata: [DatabaseMetaDataKey]
@@ -160,6 +160,9 @@
// 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.
using base::StringPiece;
using blink::WebIDBKeyType;
@@ -377,10 +380,9 @@ void EncodeIDBKeyPath(const IndexedDBKeyPath& value, std::string* into) {
}
void EncodeBlobJournal(const BlobJournalType& journal, std::string* into) {
- BlobJournalType::const_iterator iter;
- for (iter = journal.begin(); iter != journal.end(); ++iter) {
- EncodeVarInt(iter->first, into);
- EncodeVarInt(iter->second, into);
+ for (const auto& iter : journal) {
+ EncodeVarInt(iter.first, into);
+ EncodeVarInt(iter.second, into);
}
}
@@ -1436,7 +1438,7 @@ std::string DatabaseMetaDataKey::Encode(int64 database_id,
}
ObjectStoreMetaDataKey::ObjectStoreMetaDataKey()
- : object_store_id_(-1), meta_data_type_(-1) {}
+ : object_store_id_(-1), meta_data_type_(0xFF) {}
bool ObjectStoreMetaDataKey::Decode(StringPiece* slice,
ObjectStoreMetaDataKey* result) {
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 85bc091b56b..de16b55f07b 100644
--- a/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/chromium/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -90,19 +90,6 @@ CONTENT_EXPORT int Compare(const base::StringPiece& a,
class KeyPrefix {
public:
- KeyPrefix();
- explicit KeyPrefix(int64 database_id);
- KeyPrefix(int64 database_id, int64 object_store_id);
- KeyPrefix(int64 database_id, int64 object_store_id, int64 index_id);
- static KeyPrefix CreateWithSpecialIndex(int64 database_id,
- int64 object_store_id,
- int64 index_id);
-
- static bool Decode(base::StringPiece* slice, KeyPrefix* result);
- std::string Encode() const;
- static std::string EncodeEmpty();
- int Compare(const KeyPrefix& other) const;
-
// These are serialized to disk; any new items must be appended, and none can
// be deleted.
enum Type {
@@ -138,6 +125,21 @@ class KeyPrefix {
static const int64 kMaxIndexId =
(1ULL << kMaxIndexIdBits) - 1; // max signed int32
+ static const int64 kInvalidId = -1;
+
+ KeyPrefix();
+ explicit KeyPrefix(int64 database_id);
+ KeyPrefix(int64 database_id, int64 object_store_id);
+ KeyPrefix(int64 database_id, int64 object_store_id, int64 index_id);
+ static KeyPrefix CreateWithSpecialIndex(int64 database_id,
+ int64 object_store_id,
+ int64 index_id);
+
+ static bool Decode(base::StringPiece* slice, KeyPrefix* result);
+ std::string Encode() const;
+ static std::string EncodeEmpty();
+ int Compare(const KeyPrefix& other) const;
+
CONTENT_EXPORT static bool IsValidDatabaseId(int64 database_id);
static bool IsValidObjectStoreId(int64 index_id);
static bool IsValidIndexId(int64 index_id);
@@ -158,17 +160,16 @@ class KeyPrefix {
int64 object_store_id_;
int64 index_id_;
- static const int64 kInvalidId = -1;
-
private:
- static std::string EncodeInternal(int64 database_id,
- int64 object_store_id,
- int64 index_id);
// Special constructor for CreateWithSpecialIndex()
KeyPrefix(enum Type,
int64 database_id,
int64 object_store_id,
int64 index_id);
+
+ static std::string EncodeInternal(int64 database_id,
+ int64 object_store_id,
+ int64 index_id);
};
class SchemaVersionKey {
@@ -378,6 +379,11 @@ class IndexNamesKey {
class ObjectStoreDataKey {
public:
+ static const int64 kSpecialIndexNumber;
+
+ ObjectStoreDataKey();
+ ~ObjectStoreDataKey();
+
static bool Decode(base::StringPiece* slice, ObjectStoreDataKey* result);
CONTENT_EXPORT static std::string Encode(int64 database_id,
int64 object_store_id,
@@ -386,10 +392,6 @@ class ObjectStoreDataKey {
int64 object_store_id,
const IndexedDBKey& user_key);
scoped_ptr<IndexedDBKey> user_key() const;
- static const int64 kSpecialIndexNumber;
- ObjectStoreDataKey();
- ~ObjectStoreDataKey();
-
private:
std::string encoded_user_key_;
};
@@ -408,9 +410,9 @@ class ExistsEntryKey {
const IndexedDBKey& user_key);
scoped_ptr<IndexedDBKey> user_key() const;
+ private:
static const int64 kSpecialIndexNumber;
- private:
std::string encoded_user_key_;
DISALLOW_COPY_AND_ASSIGN(ExistsEntryKey);
};
@@ -433,9 +435,9 @@ class BlobEntryKey {
int64 database_id() const { return database_id_; }
int64 object_store_id() const { return object_store_id_; }
+ private:
static const int64 kSpecialIndexNumber;
- private:
static std::string Encode(int64 database_id,
int64 object_store_id,
const std::string& encoded_user_key);
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 0bd647cff3a..5f9edf1a811 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
@@ -726,15 +726,13 @@ TEST(IndexedDBLevelDBCodingTest, EncodeDecodeBlobJournal) {
journals.push_back(journal);
}
- std::vector<BlobJournalType>::const_iterator journal_iter;
- for (journal_iter = journals.begin(); journal_iter != journals.end();
- ++journal_iter) {
+ for (const auto& journal_iter : journals) {
std::string encoding;
- EncodeBlobJournal(*journal_iter, &encoding);
+ EncodeBlobJournal(journal_iter, &encoding);
StringPiece slice(encoding);
BlobJournalType journal_out;
EXPECT_TRUE(DecodeBlobJournal(&slice, &journal_out));
- EXPECT_EQ(*journal_iter, journal_out);
+ EXPECT_EQ(journal_iter, journal_out);
}
journals.clear();
@@ -751,10 +749,9 @@ TEST(IndexedDBLevelDBCodingTest, EncodeDecodeBlobJournal) {
journals.push_back(journal);
}
- for (journal_iter = journals.begin(); journal_iter != journals.end();
- ++journal_iter) {
+ for (const auto& journal_iter : journals) {
std::string encoding;
- EncodeBlobJournal(*journal_iter, &encoding);
+ EncodeBlobJournal(journal_iter, &encoding);
StringPiece slice(encoding);
BlobJournalType journal_out;
EXPECT_FALSE(DecodeBlobJournal(&slice, &journal_out));
diff --git a/chromium/content/browser/indexed_db/indexed_db_metadata.h b/chromium/content/browser/indexed_db/indexed_db_metadata.h
index 68df82ed842..a597616c55f 100644
--- a/chromium/content/browser/indexed_db/indexed_db_metadata.h
+++ b/chromium/content/browser/indexed_db/indexed_db_metadata.h
@@ -14,6 +14,8 @@
namespace content {
struct IndexedDBIndexMetadata {
+ static const int64 kInvalidId = -1;
+
IndexedDBIndexMetadata() {}
IndexedDBIndexMetadata(const base::string16& name,
int64 id,
@@ -30,11 +32,13 @@ struct IndexedDBIndexMetadata {
IndexedDBKeyPath key_path;
bool unique;
bool multi_entry;
-
- static const int64 kInvalidId = -1;
};
struct CONTENT_EXPORT IndexedDBObjectStoreMetadata {
+ typedef std::map<int64, IndexedDBIndexMetadata> IndexMap;
+
+ static const int64 kInvalidId = -1;
+
IndexedDBObjectStoreMetadata();
IndexedDBObjectStoreMetadata(const base::string16& name,
int64 id,
@@ -48,9 +52,6 @@ struct CONTENT_EXPORT IndexedDBObjectStoreMetadata {
bool auto_increment;
int64 max_index_id;
- static const int64 kInvalidId = -1;
-
- typedef std::map<int64, IndexedDBIndexMetadata> IndexMap;
IndexMap indexes;
};
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 5e0cea898e0..d8af36c5566 100644
--- a/chromium/content/browser/indexed_db/indexed_db_quota_client.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_quota_client.cc
@@ -10,19 +10,19 @@
#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/net_util.h"
-#include "webkit/browser/database/database_util.h"
+#include "storage/browser/database/database_util.h"
-using quota::QuotaClient;
-using webkit_database::DatabaseUtil;
+using storage::QuotaClient;
+using storage::DatabaseUtil;
namespace content {
namespace {
-quota::QuotaStatusCode DeleteOriginDataOnIndexedDBThread(
+storage::QuotaStatusCode DeleteOriginDataOnIndexedDBThread(
IndexedDBContextImpl* context,
const GURL& origin) {
context->DeleteForOrigin(origin);
- return quota::kQuotaStatusOk;
+ return storage::kQuotaStatusOk;
}
int64 GetOriginUsageOnIndexedDBThread(IndexedDBContextImpl* context,
@@ -49,11 +49,9 @@ void GetOriginsForHostOnIndexedDBThread(IndexedDBContextImpl* context,
std::set<GURL>* origins_to_return) {
DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
std::vector<GURL> all_origins = context->GetAllOrigins();
- for (std::vector<GURL>::const_iterator iter = all_origins.begin();
- iter != all_origins.end();
- ++iter) {
- if (host == net::GetHostOrSpecFromURL(*iter))
- origins_to_return->insert(*iter);
+ for (const auto& origin_url : all_origins) {
+ if (host == net::GetHostOrSpecFromURL(origin_url))
+ origins_to_return->insert(origin_url);
}
}
@@ -72,13 +70,13 @@ QuotaClient::ID IndexedDBQuotaClient::id() const { return kIndexedDatabase; }
void IndexedDBQuotaClient::OnQuotaManagerDestroyed() { delete this; }
void IndexedDBQuotaClient::GetOriginUsage(const GURL& origin_url,
- quota::StorageType type,
+ storage::StorageType type,
const GetUsageCallback& callback) {
DCHECK(!callback.is_null());
- DCHECK(indexed_db_context_);
+ DCHECK(indexed_db_context_.get());
// IndexedDB is in the temp namespace for now.
- if (type != quota::kStorageTypeTemporary) {
+ if (type != storage::kStorageTypeTemporary) {
callback.Run(0);
return;
}
@@ -98,13 +96,13 @@ void IndexedDBQuotaClient::GetOriginUsage(const GURL& origin_url,
}
void IndexedDBQuotaClient::GetOriginsForType(
- quota::StorageType type,
+ storage::StorageType type,
const GetOriginsCallback& callback) {
DCHECK(!callback.is_null());
- DCHECK(indexed_db_context_);
+ DCHECK(indexed_db_context_.get());
// All databases are in the temp namespace for now.
- if (type != quota::kStorageTypeTemporary) {
+ if (type != storage::kStorageTypeTemporary) {
callback.Run(std::set<GURL>());
return;
}
@@ -125,14 +123,14 @@ void IndexedDBQuotaClient::GetOriginsForType(
}
void IndexedDBQuotaClient::GetOriginsForHost(
- quota::StorageType type,
+ storage::StorageType type,
const std::string& host,
const GetOriginsCallback& callback) {
DCHECK(!callback.is_null());
- DCHECK(indexed_db_context_);
+ DCHECK(indexed_db_context_.get());
// All databases are in the temp namespace for now.
- if (type != quota::kStorageTypeTemporary) {
+ if (type != storage::kStorageTypeTemporary) {
callback.Run(std::set<GURL>());
return;
}
@@ -154,16 +152,16 @@ void IndexedDBQuotaClient::GetOriginsForHost(
}
void IndexedDBQuotaClient::DeleteOriginData(const GURL& origin,
- quota::StorageType type,
+ storage::StorageType type,
const DeletionCallback& callback) {
- if (type != quota::kStorageTypeTemporary) {
- callback.Run(quota::kQuotaErrorNotSupported);
+ if (type != storage::kStorageTypeTemporary) {
+ callback.Run(storage::kQuotaErrorNotSupported);
return;
}
// No task runner means unit test; no cleanup necessary.
if (!indexed_db_context_->TaskRunner()) {
- callback.Run(quota::kQuotaStatusOk);
+ callback.Run(storage::kQuotaStatusOk);
return;
}
@@ -175,8 +173,8 @@ void IndexedDBQuotaClient::DeleteOriginData(const GURL& origin,
callback);
}
-bool IndexedDBQuotaClient::DoesSupport(quota::StorageType type) const {
- return type == quota::kStorageTypeTemporary;
+bool IndexedDBQuotaClient::DoesSupport(storage::StorageType type) const {
+ return type == storage::kStorageTypeTemporary;
}
} // namespace content
diff --git a/chromium/content/browser/indexed_db/indexed_db_quota_client.h b/chromium/content/browser/indexed_db/indexed_db_quota_client.h
index 6f4c50ef690..7894a653f26 100644
--- a/chromium/content/browser/indexed_db/indexed_db_quota_client.h
+++ b/chromium/content/browser/indexed_db/indexed_db_quota_client.h
@@ -12,9 +12,9 @@
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "content/common/content_export.h"
-#include "webkit/browser/quota/quota_client.h"
-#include "webkit/browser/quota/quota_task.h"
-#include "webkit/common/quota/quota_types.h"
+#include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_task.h"
+#include "storage/common/quota/quota_types.h"
namespace content {
class IndexedDBContextImpl;
@@ -22,32 +22,31 @@ class IndexedDBContextImpl;
// A QuotaClient implementation to integrate IndexedDB
// with the quota management system. This interface is used
// on the IO thread by the quota manager.
-class IndexedDBQuotaClient : public quota::QuotaClient,
- public quota::QuotaTaskObserver {
+class IndexedDBQuotaClient : public storage::QuotaClient,
+ public storage::QuotaTaskObserver {
public:
CONTENT_EXPORT explicit IndexedDBQuotaClient(
IndexedDBContextImpl* indexed_db_context);
- CONTENT_EXPORT virtual ~IndexedDBQuotaClient();
+ CONTENT_EXPORT ~IndexedDBQuotaClient() override;
// QuotaClient method overrides
- virtual ID id() const OVERRIDE;
- virtual void OnQuotaManagerDestroyed() OVERRIDE;
- CONTENT_EXPORT virtual void GetOriginUsage(const GURL& origin_url,
- quota::StorageType type,
- const GetUsageCallback& callback)
- OVERRIDE;
- CONTENT_EXPORT virtual void GetOriginsForType(
- quota::StorageType type,
- const GetOriginsCallback& callback) OVERRIDE;
- CONTENT_EXPORT virtual void GetOriginsForHost(
- quota::StorageType type,
+ ID id() const override;
+ void OnQuotaManagerDestroyed() override;
+ CONTENT_EXPORT void GetOriginUsage(const GURL& origin_url,
+ storage::StorageType type,
+ const GetUsageCallback& callback) override;
+ CONTENT_EXPORT void GetOriginsForType(
+ storage::StorageType type,
+ const GetOriginsCallback& callback) override;
+ CONTENT_EXPORT void GetOriginsForHost(
+ storage::StorageType type,
const std::string& host,
- const GetOriginsCallback& callback) OVERRIDE;
- CONTENT_EXPORT virtual void DeleteOriginData(const GURL& origin,
- quota::StorageType type,
- const DeletionCallback& callback)
- OVERRIDE;
- virtual bool DoesSupport(quota::StorageType type) const OVERRIDE;
+ const GetOriginsCallback& callback) override;
+ CONTENT_EXPORT void DeleteOriginData(
+ const GURL& origin,
+ storage::StorageType type,
+ const DeletionCallback& callback) override;
+ bool DoesSupport(storage::StorageType type) const override;
private:
scoped_refptr<IndexedDBContextImpl> indexed_db_context_;
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 54ce775d6e2..f0befd24666 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
@@ -5,8 +5,8 @@
#include <map>
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/test/test_simple_task_runner.h"
@@ -18,12 +18,12 @@
#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"
-#include "webkit/common/database/database_identifier.h"
// Declared to shorten the line lengths.
-static const quota::StorageType kTemp = quota::kStorageTypeTemporary;
-static const quota::StorageType kPerm = quota::kStorageTypePersistent;
+static const storage::StorageType kTemp = storage::kStorageTypeTemporary;
+static const storage::StorageType kPerm = storage::kStorageTypePersistent;
namespace content {
@@ -43,19 +43,18 @@ class IndexedDBQuotaClientTest : public testing::Test {
weak_factory_(this) {
browser_context_.reset(new TestBrowserContext());
- scoped_refptr<quota::QuotaManager> quota_manager =
- new MockQuotaManager(
- false /*in_memory*/,
- browser_context_->GetPath(),
- base::MessageLoop::current()->message_loop_proxy(),
- base::MessageLoop::current()->message_loop_proxy(),
- browser_context_->GetSpecialStoragePolicy());
+ scoped_refptr<storage::QuotaManager> quota_manager =
+ new MockQuotaManager(false /*in_memory*/,
+ browser_context_->GetPath(),
+ base::MessageLoop::current()->message_loop_proxy(),
+ base::MessageLoop::current()->message_loop_proxy(),
+ browser_context_->GetSpecialStoragePolicy());
idb_context_ =
new IndexedDBContextImpl(browser_context_->GetPath(),
browser_context_->GetSpecialStoragePolicy(),
quota_manager->proxy(),
- task_runner_);
+ task_runner_.get());
base::MessageLoop::current()->RunUntilIdle();
setup_temp_dir();
}
@@ -70,16 +69,16 @@ class IndexedDBQuotaClientTest : public testing::Test {
idb_context()->set_data_path_for_testing(indexeddb_dir);
}
- virtual ~IndexedDBQuotaClientTest() {
+ ~IndexedDBQuotaClientTest() override {
FlushIndexedDBTaskRunner();
idb_context_ = NULL;
browser_context_.reset();
base::MessageLoop::current()->RunUntilIdle();
}
- int64 GetOriginUsage(quota::QuotaClient* client,
+ int64 GetOriginUsage(storage::QuotaClient* client,
const GURL& origin,
- quota::StorageType type) {
+ storage::StorageType type) {
usage_ = -1;
client->GetOriginUsage(
origin,
@@ -92,8 +91,8 @@ class IndexedDBQuotaClientTest : public testing::Test {
return usage_;
}
- const std::set<GURL>& GetOriginsForType(quota::QuotaClient* client,
- quota::StorageType type) {
+ const std::set<GURL>& GetOriginsForType(storage::QuotaClient* client,
+ storage::StorageType type) {
origins_.clear();
client->GetOriginsForType(
type,
@@ -104,8 +103,8 @@ class IndexedDBQuotaClientTest : public testing::Test {
return origins_;
}
- const std::set<GURL>& GetOriginsForHost(quota::QuotaClient* client,
- quota::StorageType type,
+ const std::set<GURL>& GetOriginsForHost(storage::QuotaClient* client,
+ storage::StorageType type,
const std::string& host) {
origins_.clear();
client->GetOriginsForHost(
@@ -118,9 +117,9 @@ class IndexedDBQuotaClientTest : public testing::Test {
return origins_;
}
- quota::QuotaStatusCode DeleteOrigin(quota::QuotaClient* client,
- const GURL& origin_url) {
- delete_status_ = quota::kQuotaStatusUnknown;
+ storage::QuotaStatusCode DeleteOrigin(storage::QuotaClient* client,
+ const GURL& origin_url) {
+ delete_status_ = storage::kQuotaStatusUnknown;
client->DeleteOriginData(
origin_url,
kTemp,
@@ -131,7 +130,7 @@ class IndexedDBQuotaClientTest : public testing::Test {
return delete_status_;
}
- IndexedDBContextImpl* idb_context() { return idb_context_; }
+ IndexedDBContextImpl* idb_context() { return idb_context_.get(); }
void SetFileSizeTo(const base::FilePath& path, int size) {
std::string junk(size, 'a');
@@ -140,7 +139,7 @@ class IndexedDBQuotaClientTest : public testing::Test {
void AddFakeIndexedDB(const GURL& origin, int size) {
base::FilePath file_path_origin = idb_context()->GetFilePathForTesting(
- webkit_database::GetIdentifierFromOrigin(origin));
+ storage::GetIdentifierFromOrigin(origin));
if (!base::CreateDirectory(file_path_origin)) {
LOG(ERROR) << "failed to base::CreateDirectory "
<< file_path_origin.value();
@@ -157,7 +156,7 @@ class IndexedDBQuotaClientTest : public testing::Test {
origins_ = origins;
}
- void OnDeleteOriginComplete(quota::QuotaStatusCode code) {
+ void OnDeleteOriginComplete(storage::QuotaStatusCode code) {
delete_status_ = code;
}
@@ -168,7 +167,7 @@ class IndexedDBQuotaClientTest : public testing::Test {
scoped_refptr<IndexedDBContextImpl> idb_context_;
content::TestBrowserThreadBundle thread_bundle_;
scoped_ptr<TestBrowserContext> browser_context_;
- quota::QuotaStatusCode delete_status_;
+ storage::QuotaStatusCode delete_status_;
base::WeakPtrFactory<IndexedDBQuotaClientTest> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBQuotaClientTest);
@@ -237,8 +236,8 @@ TEST_F(IndexedDBQuotaClientTest, DeleteOrigin) {
EXPECT_EQ(1000, GetOriginUsage(&client, kOriginA, kTemp));
EXPECT_EQ(50, GetOriginUsage(&client, kOriginB, kTemp));
- quota::QuotaStatusCode delete_status = DeleteOrigin(&client, kOriginA);
- EXPECT_EQ(quota::kQuotaStatusOk, delete_status);
+ storage::QuotaStatusCode delete_status = DeleteOrigin(&client, kOriginA);
+ EXPECT_EQ(storage::kQuotaStatusOk, delete_status);
EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kTemp));
EXPECT_EQ(50, GetOriginUsage(&client, kOriginB, kTemp));
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction.cc b/chromium/content/browser/indexed_db/indexed_db_transaction.cc
index 4de6784ae8c..6609e02499b 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction.cc
@@ -54,7 +54,7 @@ IndexedDBTransaction::IndexedDBTransaction(
int64 id,
scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
const std::set<int64>& object_store_ids,
- indexed_db::TransactionMode mode,
+ blink::WebIDBTransactionMode mode,
IndexedDBDatabase* database,
IndexedDBBackingStore::Transaction* backing_store_transaction)
: id_(id),
@@ -86,7 +86,7 @@ IndexedDBTransaction::~IndexedDBTransaction() {
DCHECK(abort_task_stack_.empty());
}
-void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type,
+void IndexedDBTransaction::ScheduleTask(blink::WebIDBTaskType type,
Operation task) {
DCHECK_NE(state_, COMMITTING);
if (state_ == FINISHED)
@@ -94,7 +94,7 @@ void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type,
timeout_timer_.Stop();
used_ = true;
- if (type == IndexedDBDatabase::NORMAL_TASK) {
+ if (type == blink::WebIDBTaskTypeNormal) {
task_queue_.push(task);
++diagnostics_.tasks_scheduled;
} else {
@@ -212,12 +212,12 @@ class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback {
explicit BlobWriteCallbackImpl(
scoped_refptr<IndexedDBTransaction> transaction)
: transaction_(transaction) {}
- virtual void Run(bool succeeded) OVERRIDE {
+ void Run(bool succeeded) override {
transaction_->BlobWriteComplete(succeeded);
}
protected:
- virtual ~BlobWriteCallbackImpl() {}
+ ~BlobWriteCallbackImpl() override {}
private:
scoped_refptr<IndexedDBTransaction> transaction_;
@@ -235,14 +235,16 @@ void IndexedDBTransaction::BlobWriteComplete(bool success) {
"Failed to write blobs."));
}
-void IndexedDBTransaction::Commit() {
+leveldb::Status IndexedDBTransaction::Commit() {
IDB_TRACE1("IndexedDBTransaction::Commit", "txn.id", id());
+ timeout_timer_.Stop();
+
// In multiprocess ports, front-end may have requested a commit but
// an abort has already been initiated asynchronously by the
// back-end.
if (state_ == FINISHED)
- return;
+ return leveldb::Status::OK();
DCHECK_NE(state_, COMMITTING);
DCHECK(!used_ || state_ == STARTED);
@@ -252,27 +254,31 @@ void IndexedDBTransaction::Commit() {
// create_index which are considered synchronous by the front-end
// but are processed asynchronously.
if (HasPendingTasks())
- return;
+ return leveldb::Status::OK();
state_ = COMMITTING;
+ leveldb::Status s;
if (!used_) {
- CommitPhaseTwo();
+ s = CommitPhaseTwo();
} else {
scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback(
new BlobWriteCallbackImpl(this));
// CommitPhaseOne will call the callback synchronously if there are no blobs
// to write.
- if (!transaction_->CommitPhaseOne(callback).ok())
+ s = transaction_->CommitPhaseOne(callback);
+ if (!s.ok())
Abort(IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionDataError,
"Error processing blob journal."));
}
+
+ return s;
}
-void IndexedDBTransaction::CommitPhaseTwo() {
+leveldb::Status IndexedDBTransaction::CommitPhaseTwo() {
// Abort may have been called just as the blob write completed.
if (state_ == FINISHED)
- return;
+ return leveldb::Status::OK();
DCHECK_EQ(state_, COMMITTING);
@@ -281,11 +287,16 @@ void IndexedDBTransaction::CommitPhaseTwo() {
// alive while executing this method.
scoped_refptr<IndexedDBTransaction> protect(this);
- timeout_timer_.Stop();
-
state_ = FINISHED;
- bool committed = !used_ || transaction_->CommitPhaseTwo().ok();
+ leveldb::Status s;
+ bool committed;
+ if (!used_) {
+ committed = true;
+ } else {
+ s = transaction_->CommitPhaseTwo();
+ committed = s.ok();
+ }
// Backing store resources (held via cursors) must be released
// before script callbacks are fired, as the script callbacks may
@@ -312,10 +323,11 @@ void IndexedDBTransaction::CommitPhaseTwo() {
IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error committing transaction."));
database_->TransactionFinished(this, false);
- database_->TransactionCommitFailed();
+ database_->TransactionCommitFailed(s);
}
database_ = NULL;
+ return s;
}
void IndexedDBTransaction::ProcessTaskQueue() {
@@ -370,7 +382,7 @@ void IndexedDBTransaction::ProcessTaskQueue() {
// Otherwise, start a timer in case the front-end gets wedged and
// never requests further activity. Read-only transactions don't
// block other transactions, so don't time those out.
- if (mode_ != indexed_db::TRANSACTION_READ_ONLY) {
+ if (mode_ != blink::WebIDBTransactionModeReadOnly) {
timeout_timer_.Start(
FROM_HERE,
base::TimeDelta::FromSeconds(kInactivityTimeoutPeriodSeconds),
@@ -385,10 +397,8 @@ void IndexedDBTransaction::Timeout() {
}
void IndexedDBTransaction::CloseOpenCursors() {
- for (std::set<IndexedDBCursor*>::iterator i = open_cursors_.begin();
- i != open_cursors_.end();
- ++i)
- (*i)->Close();
+ for (auto* cursor : open_cursors_)
+ cursor->Close();
open_cursors_.clear();
}
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction.h b/chromium/content/browser/indexed_db/indexed_db_transaction.h
index e30422f15ab..bd0e543035c 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction.h
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction.h
@@ -17,6 +17,7 @@
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_database.h"
#include "content/browser/indexed_db/indexed_db_database_error.h"
+#include "third_party/WebKit/public/platform/WebIDBTypes.h"
namespace content {
@@ -29,28 +30,36 @@ class CONTENT_EXPORT IndexedDBTransaction
public:
typedef base::Callback<void(IndexedDBTransaction*)> Operation;
+ enum State {
+ CREATED, // Created, but not yet started by coordinator.
+ STARTED, // Started by the coordinator.
+ COMMITTING, // In the process of committing, possibly waiting for blobs
+ // to be written.
+ FINISHED, // Either aborted or committed.
+ };
+
IndexedDBTransaction(
int64 id,
scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
const std::set<int64>& object_store_ids,
- indexed_db::TransactionMode,
+ blink::WebIDBTransactionMode,
IndexedDBDatabase* db,
IndexedDBBackingStore::Transaction* backing_store_transaction);
virtual void Abort();
- void Commit();
+ leveldb::Status Commit();
void Abort(const IndexedDBDatabaseError& error);
// Called by the transaction coordinator when this transaction is unblocked.
void Start();
- indexed_db::TransactionMode mode() const { return mode_; }
+ blink::WebIDBTransactionMode mode() const { return mode_; }
const std::set<int64>& scope() const { return object_store_ids_; }
void ScheduleTask(Operation task) {
- ScheduleTask(IndexedDBDatabase::NORMAL_TASK, task);
+ ScheduleTask(blink::WebIDBTaskTypeNormal, task);
}
- void ScheduleTask(IndexedDBDatabase::TaskType, Operation task);
+ void ScheduleTask(blink::WebIDBTaskType, Operation task);
void ScheduleAbortTask(Operation abort_task);
void RegisterOpenCursor(IndexedDBCursor* cursor);
void UnregisterOpenCursor(IndexedDBCursor* cursor);
@@ -64,16 +73,8 @@ class CONTENT_EXPORT IndexedDBTransaction
}
int64 id() const { return id_; }
- IndexedDBDatabase* database() const { return database_; }
- IndexedDBDatabaseCallbacks* connection() const { return callbacks_; }
-
- enum State {
- CREATED, // Created, but not yet started by coordinator.
- STARTED, // Started by the coordinator.
- COMMITTING, // In the process of committing, possibly waiting for blobs
- // to be written.
- FINISHED, // Either aborted or committed.
- };
+ IndexedDBDatabase* database() const { return database_.get(); }
+ IndexedDBDatabaseCallbacks* connection() const { return callbacks_.get(); }
State state() const { return state_; }
bool IsTimeoutTimerRunning() const { return timeout_timer_.IsRunning(); }
@@ -108,12 +109,12 @@ class CONTENT_EXPORT IndexedDBTransaction
void BlobWriteComplete(bool success);
void ProcessTaskQueue();
void CloseOpenCursors();
- void CommitPhaseTwo();
+ leveldb::Status CommitPhaseTwo();
void Timeout();
const int64 id_;
const std::set<int64> object_store_ids_;
- const indexed_db::TransactionMode mode_;
+ const blink::WebIDBTransactionMode mode_;
bool used_;
State state_;
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc b/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
index a1eaad41ecd..ca7f3838b88 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
+#include "third_party/WebKit/public/platform/WebIDBTypes.h"
namespace content {
@@ -44,7 +45,7 @@ bool IndexedDBTransactionCoordinator::IsRunningVersionChangeTransaction()
const {
return !started_transactions_.empty() &&
(*started_transactions_.begin())->mode() ==
- indexed_db::TRANSACTION_VERSION_CHANGE;
+ blink::WebIDBTransactionModeVersionChange;
}
#ifndef NDEBUG
@@ -66,16 +67,10 @@ std::vector<const IndexedDBTransaction*>
IndexedDBTransactionCoordinator::GetTransactions() const {
std::vector<const IndexedDBTransaction*> result;
- for (TransactionSet::const_iterator it = started_transactions_.begin();
- it != started_transactions_.end();
- ++it) {
- result.push_back(*it);
- }
- for (TransactionSet::const_iterator it = queued_transactions_.begin();
- it != queued_transactions_.end();
- ++it) {
- result.push_back(*it);
- }
+ for (const auto& transaction : started_transactions_)
+ result.push_back(transaction.get());
+ for (const auto& transaction : queued_transactions_)
+ result.push_back(transaction.get());
return result;
}
@@ -93,11 +88,8 @@ void IndexedDBTransactionCoordinator::ProcessQueuedTransactions() {
// data. ("Version change" transactions are exclusive, but handled by the
// connection sequencing in IndexedDBDatabase.)
std::set<int64> locked_scope;
- for (TransactionSet::const_iterator it = started_transactions_.begin();
- it != started_transactions_.end();
- ++it) {
- IndexedDBTransaction* transaction = *it;
- if (transaction->mode() == indexed_db::TRANSACTION_READ_WRITE) {
+ for (const auto& transaction : started_transactions_) {
+ if (transaction->mode() == blink::WebIDBTransactionModeReadWrite) {
// Started read/write transactions have exclusive access to the object
// stores within their scopes.
locked_scope.insert(transaction->scope().begin(),
@@ -109,14 +101,14 @@ void IndexedDBTransactionCoordinator::ProcessQueuedTransactions() {
while (it != queued_transactions_.end()) {
scoped_refptr<IndexedDBTransaction> transaction = *it;
++it;
- if (CanStartTransaction(transaction, locked_scope)) {
+ if (CanStartTransaction(transaction.get(), locked_scope)) {
DCHECK_EQ(IndexedDBTransaction::CREATED, transaction->state());
queued_transactions_.erase(transaction);
started_transactions_.insert(transaction);
transaction->Start();
DCHECK_EQ(IndexedDBTransaction::STARTED, transaction->state());
}
- if (transaction->mode() == indexed_db::TRANSACTION_READ_WRITE) {
+ if (transaction->mode() == blink::WebIDBTransactionModeReadWrite) {
// Either the transaction started, so it has exclusive access to the
// stores in its scope, or per the spec the transaction which was
// created first must get access first, so the stores are also locked.
@@ -147,16 +139,16 @@ bool IndexedDBTransactionCoordinator::CanStartTransaction(
const std::set<int64>& locked_scope) const {
DCHECK(queued_transactions_.count(transaction));
switch (transaction->mode()) {
- case indexed_db::TRANSACTION_VERSION_CHANGE:
+ case blink::WebIDBTransactionModeVersionChange:
DCHECK_EQ(1u, queued_transactions_.size());
DCHECK(started_transactions_.empty());
DCHECK(locked_scope.empty());
return true;
- case indexed_db::TRANSACTION_READ_ONLY:
+ case blink::WebIDBTransactionModeReadOnly:
return true;
- case indexed_db::TRANSACTION_READ_WRITE:
+ case blink::WebIDBTransactionModeReadWrite:
return !DoSetsIntersect(transaction->scope(), locked_scope);
}
NOTREACHED();
diff --git a/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.h b/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.h
index 98db0b39de0..890541dfd24 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.h
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction_coordinator.h
@@ -37,6 +37,8 @@ class IndexedDBTransactionCoordinator {
std::vector<const IndexedDBTransaction*> GetTransactions() const;
private:
+ typedef list_set<scoped_refptr<IndexedDBTransaction> > TransactionSet;
+
void ProcessQueuedTransactions();
bool CanStartTransaction(IndexedDBTransaction* const transaction,
const std::set<int64>& locked_scope) const;
@@ -44,7 +46,6 @@ class IndexedDBTransactionCoordinator {
// Transactions in different states are grouped below.
// list_set is used to provide stable ordering; required by spec
// for the queue, convenience for diagnostics for the rest.
- typedef list_set<scoped_refptr<IndexedDBTransaction> > TransactionSet;
TransactionSet queued_transactions_;
TransactionSet started_transactions_;
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 c6a1244d4dc..e033dd79e64 100644
--- a/chromium/content/browser/indexed_db/indexed_db_transaction_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_transaction_unittest.cc
@@ -10,6 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
#include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
+#include "content/browser/indexed_db/mock_indexed_db_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -31,7 +32,7 @@ class AbortObserver {
class IndexedDBTransactionTest : public testing::Test {
public:
- IndexedDBTransactionTest() {
+ IndexedDBTransactionTest() : factory_(new MockIndexedDBFactory()) {
backing_store_ = new IndexedDBFakeBackingStore();
CreateDB();
}
@@ -40,11 +41,10 @@ class IndexedDBTransactionTest : public testing::Test {
// 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
- IndexedDBFactory* factory = NULL;
leveldb::Status s;
db_ = IndexedDBDatabase::Create(base::ASCIIToUTF16("db"),
- backing_store_,
- factory,
+ backing_store_.get(),
+ factory_.get(),
IndexedDBDatabase::Identifier(),
&s);
ASSERT_TRUE(s.ok());
@@ -64,12 +64,14 @@ class IndexedDBTransactionTest : public testing::Test {
private:
base::MessageLoop message_loop_;
+ scoped_refptr<MockIndexedDBFactory> factory_;
DISALLOW_COPY_AND_ASSIGN(IndexedDBTransactionTest);
};
-class IndexedDBTransactionTestMode : public IndexedDBTransactionTest,
- public testing::WithParamInterface<indexed_db::TransactionMode> {
+class IndexedDBTransactionTestMode
+ : public IndexedDBTransactionTest,
+ public testing::WithParamInterface<blink::WebIDBTransactionMode> {
public:
IndexedDBTransactionTestMode() {}
private:
@@ -84,10 +86,10 @@ TEST_F(IndexedDBTransactionTest, Timeout) {
id,
new MockIndexedDBDatabaseCallbacks(),
scope,
- indexed_db::TRANSACTION_READ_WRITE,
- db_,
+ blink::WebIDBTransactionModeReadWrite,
+ db_.get(),
new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
- db_->TransactionCreated(transaction);
+ db_->TransactionCreated(transaction.get());
// No conflicting transactions, so coordinator will start it immediately:
EXPECT_EQ(IndexedDBTransaction::STARTED, transaction->state());
@@ -128,10 +130,10 @@ TEST_F(IndexedDBTransactionTest, NoTimeoutReadOnly) {
id,
new MockIndexedDBDatabaseCallbacks(),
scope,
- indexed_db::TRANSACTION_READ_ONLY,
- db_,
+ blink::WebIDBTransactionModeReadOnly,
+ db_.get(),
new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
- db_->TransactionCreated(transaction);
+ db_->TransactionCreated(transaction.get());
// No conflicting transactions, so coordinator will start it immediately:
EXPECT_EQ(IndexedDBTransaction::STARTED, transaction->state());
@@ -161,7 +163,7 @@ TEST_P(IndexedDBTransactionTestMode, ScheduleNormalTask) {
new MockIndexedDBDatabaseCallbacks(),
scope,
GetParam(),
- db_,
+ db_.get(),
new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
EXPECT_FALSE(transaction->HasPendingTasks());
@@ -171,7 +173,7 @@ TEST_P(IndexedDBTransactionTestMode, ScheduleNormalTask) {
EXPECT_EQ(0, transaction->diagnostics().tasks_scheduled);
EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
- db_->TransactionCreated(transaction);
+ db_->TransactionCreated(transaction.get());
EXPECT_FALSE(transaction->HasPendingTasks());
EXPECT_TRUE(transaction->IsTaskQueueEmpty());
@@ -179,7 +181,7 @@ TEST_P(IndexedDBTransactionTestMode, ScheduleNormalTask) {
EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
transaction->ScheduleTask(
- IndexedDBDatabase::NORMAL_TASK,
+ blink::WebIDBTaskTypeNormal,
base::Bind(&IndexedDBTransactionTest::DummyOperation,
base::Unretained(this)));
@@ -222,8 +224,8 @@ TEST_F(IndexedDBTransactionTest, SchedulePreemptiveTask) {
id,
new MockIndexedDBDatabaseCallbacks(),
scope,
- indexed_db::TRANSACTION_VERSION_CHANGE,
- db_,
+ blink::WebIDBTransactionModeVersionChange,
+ db_.get(),
new IndexedDBFakeBackingStore::FakeTransaction(commit_failure));
EXPECT_FALSE(transaction->HasPendingTasks());
@@ -233,7 +235,7 @@ TEST_F(IndexedDBTransactionTest, SchedulePreemptiveTask) {
EXPECT_EQ(0, transaction->diagnostics().tasks_scheduled);
EXPECT_EQ(0, transaction->diagnostics().tasks_completed);
- db_->TransactionCreated(transaction);
+ db_->TransactionCreated(transaction.get());
EXPECT_FALSE(transaction->HasPendingTasks());
EXPECT_TRUE(transaction->IsTaskQueueEmpty());
@@ -241,7 +243,7 @@ TEST_F(IndexedDBTransactionTest, SchedulePreemptiveTask) {
EXPECT_TRUE(transaction->preemptive_task_queue_.empty());
transaction->ScheduleTask(
- IndexedDBDatabase::PREEMPTIVE_TASK,
+ blink::WebIDBTaskTypePreemptive,
base::Bind(&IndexedDBTransactionTest::DummyOperation,
base::Unretained(this)));
transaction->AddPreemptiveEvent();
@@ -284,9 +286,9 @@ TEST_P(IndexedDBTransactionTestMode, AbortTasks) {
new MockIndexedDBDatabaseCallbacks(),
scope,
GetParam(),
- db_,
+ db_.get(),
new IndexedDBFakeBackingStore::FakeTransaction(commit_failure));
- db_->TransactionCreated(transaction);
+ db_->TransactionCreated(transaction.get());
AbortObserver observer;
transaction->ScheduleTask(
@@ -314,16 +316,16 @@ TEST_P(IndexedDBTransactionTestMode, AbortPreemptive) {
new MockIndexedDBDatabaseCallbacks(),
scope,
GetParam(),
- db_,
+ db_.get(),
new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
- db_->TransactionCreated(transaction);
+ db_->TransactionCreated(transaction.get());
// No conflicting transactions, so coordinator will start it immediately:
EXPECT_EQ(IndexedDBTransaction::STARTED, transaction->state());
EXPECT_FALSE(transaction->IsTimeoutTimerRunning());
transaction->ScheduleTask(
- IndexedDBDatabase::PREEMPTIVE_TASK,
+ blink::WebIDBTaskTypePreemptive,
base::Bind(&IndexedDBTransactionTest::DummyOperation,
base::Unretained(this)));
EXPECT_EQ(0, transaction->pending_preemptive_events_);
@@ -356,11 +358,9 @@ TEST_P(IndexedDBTransactionTestMode, AbortPreemptive) {
transaction->diagnostics().tasks_scheduled);
}
-static const indexed_db::TransactionMode kTestModes[] = {
- indexed_db::TRANSACTION_READ_ONLY,
- indexed_db::TRANSACTION_READ_WRITE,
- indexed_db::TRANSACTION_VERSION_CHANGE
-};
+static const blink::WebIDBTransactionMode kTestModes[] = {
+ blink::WebIDBTransactionModeReadOnly, blink::WebIDBTransactionModeReadWrite,
+ blink::WebIDBTransactionModeVersionChange};
INSTANTIATE_TEST_CASE_P(IndexedDBTransactions,
IndexedDBTransactionTestMode,
diff --git a/chromium/content/browser/indexed_db/indexed_db_unittest.cc b/chromium/content/browser/indexed_db/indexed_db_unittest.cc
index 6fa627b1632..ddb1fdc66bd 100644
--- a/chromium/content/browser/indexed_db/indexed_db_unittest.cc
+++ b/chromium/content/browser/indexed_db/indexed_db_unittest.cc
@@ -2,23 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/indexed_db/indexed_db_connection.h"
#include "content/browser/indexed_db/indexed_db_context_impl.h"
+#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/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"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/browser/quota/special_storage_policy.h"
-#include "webkit/common/database/database_identifier.h"
namespace content {
@@ -61,13 +62,16 @@ TEST_F(IndexedDBTest, ClearSessionOnlyDatabases) {
// Create the scope which will ensure we run the destructor of the context
// which should trigger the clean up.
{
- scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
- temp_dir.path(), special_storage_policy_, NULL, task_runner_);
+ scoped_refptr<IndexedDBContextImpl> idb_context =
+ new IndexedDBContextImpl(temp_dir.path(),
+ special_storage_policy_.get(),
+ NULL,
+ task_runner_.get());
normal_path = idb_context->GetFilePathForTesting(
- webkit_database::GetIdentifierFromOrigin(kNormalOrigin));
+ storage::GetIdentifierFromOrigin(kNormalOrigin));
session_only_path = idb_context->GetFilePathForTesting(
- webkit_database::GetIdentifierFromOrigin(kSessionOnlyOrigin));
+ storage::GetIdentifierFromOrigin(kSessionOnlyOrigin));
ASSERT_TRUE(base::CreateDirectory(normal_path));
ASSERT_TRUE(base::CreateDirectory(session_only_path));
FlushIndexedDBTaskRunner();
@@ -92,16 +96,19 @@ TEST_F(IndexedDBTest, SetForceKeepSessionState) {
{
// Create some indexedDB paths.
// With the levelDB backend, these are directories.
- scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
- temp_dir.path(), special_storage_policy_, NULL, task_runner_);
+ scoped_refptr<IndexedDBContextImpl> idb_context =
+ new IndexedDBContextImpl(temp_dir.path(),
+ special_storage_policy_.get(),
+ NULL,
+ task_runner_.get());
// Save session state. This should bypass the destruction-time deletion.
idb_context->SetForceKeepSessionState();
normal_path = idb_context->GetFilePathForTesting(
- webkit_database::GetIdentifierFromOrigin(kNormalOrigin));
+ storage::GetIdentifierFromOrigin(kNormalOrigin));
session_only_path = idb_context->GetFilePathForTesting(
- webkit_database::GetIdentifierFromOrigin(kSessionOnlyOrigin));
+ storage::GetIdentifierFromOrigin(kSessionOnlyOrigin));
ASSERT_TRUE(base::CreateDirectory(normal_path));
ASSERT_TRUE(base::CreateDirectory(session_only_path));
message_loop_.RunUntilIdle();
@@ -123,10 +130,10 @@ class ForceCloseDBCallbacks : public IndexedDBCallbacks {
idb_context_(idb_context),
origin_url_(origin_url) {}
- virtual void OnSuccess() OVERRIDE {}
- virtual void OnSuccess(const std::vector<base::string16>&) OVERRIDE {}
- virtual void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
- const IndexedDBDatabaseMetadata& metadata) OVERRIDE {
+ void OnSuccess() override {}
+ void OnSuccess(const std::vector<base::string16>&) override {}
+ void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
+ const IndexedDBDatabaseMetadata& metadata) override {
connection_ = connection.Pass();
idb_context_->ConnectionOpened(origin_url_, connection_.get());
}
@@ -134,7 +141,7 @@ class ForceCloseDBCallbacks : public IndexedDBCallbacks {
IndexedDBConnection* connection() { return connection_.get(); }
protected:
- virtual ~ForceCloseDBCallbacks() {}
+ ~ForceCloseDBCallbacks() override {}
private:
scoped_refptr<IndexedDBContextImpl> idb_context_;
@@ -160,8 +167,11 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
const GURL kTestOrigin("http://test/");
- scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
- temp_dir.path(), special_storage_policy_, NULL, task_runner_);
+ scoped_refptr<IndexedDBContextImpl> idb_context =
+ new IndexedDBContextImpl(temp_dir.path(),
+ special_storage_policy_.get(),
+ NULL,
+ task_runner_.get());
scoped_refptr<ForceCloseDBCallbacks> open_callbacks =
new ForceCloseDBCallbacks(idb_context, kTestOrigin);
@@ -172,7 +182,7 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
IndexedDBFactory* factory = idb_context->GetIDBFactory();
test_path = idb_context->GetFilePathForTesting(
- webkit_database::GetIdentifierFromOrigin(kTestOrigin));
+ storage::GetIdentifierFromOrigin(kTestOrigin));
IndexedDBPendingConnection open_connection(open_callbacks,
open_db_callbacks,
@@ -219,10 +229,10 @@ TEST_F(IndexedDBTest, DeleteFailsIfDirectoryLocked) {
const GURL kTestOrigin("http://test/");
scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
- temp_dir.path(), special_storage_policy_, NULL, task_runner_);
+ temp_dir.path(), special_storage_policy_.get(), NULL, task_runner_.get());
base::FilePath test_path = idb_context->GetFilePathForTesting(
- webkit_database::GetIdentifierFromOrigin(kTestOrigin));
+ storage::GetIdentifierFromOrigin(kTestOrigin));
ASSERT_TRUE(base::CreateDirectory(test_path));
scoped_ptr<LevelDBLock> lock =
@@ -245,9 +255,10 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
scoped_refptr<IndexedDBContextImpl> context = new IndexedDBContextImpl(
- temp_dir.path(), special_storage_policy_, NULL, task_runner_);
+ temp_dir.path(), special_storage_policy_.get(), NULL, task_runner_.get());
- scoped_refptr<IndexedDBFactory> factory = context->GetIDBFactory();
+ scoped_refptr<IndexedDBFactoryImpl> factory =
+ static_cast<IndexedDBFactoryImpl*>(context->GetIDBFactory());
scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
@@ -273,7 +284,8 @@ TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
EXPECT_TRUE(factory->IsBackingStoreOpen(kTestOrigin));
// Simulate the write failure.
- callbacks->connection()->database()->TransactionCommitFailed();
+ leveldb::Status status = leveldb::Status::IOError("Simulated failure");
+ callbacks->connection()->database()->TransactionCommitFailed(status);
EXPECT_TRUE(db_callbacks->forced_close_called());
EXPECT_FALSE(factory->IsBackingStoreOpen(kTestOrigin));
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc b/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
index 16f4fc79c61..5f48cbef60e 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_database.cc
@@ -16,14 +16,16 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
+#include "content/browser/indexed_db/indexed_db_class_factory.h"
#include "content/browser/indexed_db/leveldb/leveldb_comparator.h"
-#include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
+#include "content/browser/indexed_db/leveldb/leveldb_iterator_impl.h"
#include "content/browser/indexed_db/leveldb/leveldb_write_batch.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/env_idb.h"
#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
#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/filter_policy.h"
#include "third_party/leveldatabase/src/include/leveldb/slice.h"
using base::StringPiece;
@@ -89,14 +91,18 @@ LevelDBDatabase::~LevelDBDatabase() {
env_.reset();
}
-static leveldb::Status OpenDB(leveldb::Comparator* comparator,
- leveldb::Env* env,
- const base::FilePath& path,
- leveldb::DB** db) {
+static leveldb::Status OpenDB(
+ leveldb::Comparator* comparator,
+ leveldb::Env* env,
+ const base::FilePath& path,
+ leveldb::DB** db,
+ scoped_ptr<const leveldb::FilterPolicy>* filter_policy) {
+ filter_policy->reset(leveldb::NewBloomFilterPolicy(10));
leveldb::Options options;
options.comparator = comparator;
options.create_if_missing = true;
options.paranoid_checks = true;
+ options.filter_policy = filter_policy->get();
options.compression = leveldb::kSnappyCompression;
// For info about the troubles we've run into with this parameter, see:
@@ -105,7 +111,9 @@ static leveldb::Status OpenDB(leveldb::Comparator* comparator,
options.env = env;
// ChromiumEnv assumes UTF8, converts back to FilePath before using.
- return leveldb::DB::Open(options, path.AsUTF8Unsafe(), db);
+ leveldb::Status s = leveldb::DB::Open(options, path.AsUTF8Unsafe(), db);
+
+ return s;
}
leveldb::Status LevelDBDatabase::Destroy(const base::FilePath& file_name) {
@@ -120,7 +128,8 @@ class LockImpl : public LevelDBLock {
public:
explicit LockImpl(leveldb::Env* env, leveldb::FileLock* lock)
: env_(env), lock_(lock) {}
- virtual ~LockImpl() { env_->UnlockFile(lock_); }
+ ~LockImpl() override { env_->UnlockFile(lock_); }
+
private:
leveldb::Env* env_;
leveldb::FileLock* lock_;
@@ -263,12 +272,18 @@ leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name,
const LevelDBComparator* comparator,
scoped_ptr<LevelDBDatabase>* result,
bool* is_disk_full) {
+ base::TimeTicks begin_time = base::TimeTicks::Now();
+
scoped_ptr<ComparatorAdapter> comparator_adapter(
new ComparatorAdapter(comparator));
leveldb::DB* db;
- const leveldb::Status s =
- OpenDB(comparator_adapter.get(), leveldb::IDBEnv(), file_name, &db);
+ scoped_ptr<const leveldb::FilterPolicy> filter_policy;
+ const leveldb::Status s = OpenDB(comparator_adapter.get(),
+ leveldb::IDBEnv(),
+ file_name,
+ &db,
+ &filter_policy);
if (!s.ok()) {
HistogramLevelDBError("WebCore.IndexedDB.LevelDBOpenErrors", s);
@@ -283,12 +298,16 @@ leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name,
return s;
}
+ UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.OpenTime",
+ base::TimeTicks::Now() - begin_time);
+
CheckFreeSpace("Success", file_name);
(*result).reset(new LevelDBDatabase);
(*result)->db_ = make_scoped_ptr(db);
(*result)->comparator_adapter_ = comparator_adapter.Pass();
(*result)->comparator_ = comparator;
+ (*result)->filter_policy_ = filter_policy.Pass();
return s;
}
@@ -300,8 +319,12 @@ scoped_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory(
scoped_ptr<leveldb::Env> in_memory_env(leveldb::NewMemEnv(leveldb::IDBEnv()));
leveldb::DB* db;
- const leveldb::Status s = OpenDB(
- comparator_adapter.get(), in_memory_env.get(), base::FilePath(), &db);
+ scoped_ptr<const leveldb::FilterPolicy> filter_policy;
+ const leveldb::Status s = OpenDB(comparator_adapter.get(),
+ in_memory_env.get(),
+ base::FilePath(),
+ &db,
+ &filter_policy);
if (!s.ok()) {
LOG(ERROR) << "Failed to open in-memory LevelDB database: " << s.ToString();
@@ -313,12 +336,15 @@ scoped_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory(
result->db_ = make_scoped_ptr(db);
result->comparator_adapter_ = comparator_adapter.Pass();
result->comparator_ = comparator;
+ result->filter_policy_ = filter_policy.Pass();
return result.Pass();
}
leveldb::Status LevelDBDatabase::Put(const StringPiece& key,
std::string* value) {
+ base::TimeTicks begin_time = base::TimeTicks::Now();
+
leveldb::WriteOptions write_options;
write_options.sync = kSyncWrites;
@@ -326,6 +352,9 @@ leveldb::Status LevelDBDatabase::Put(const StringPiece& key,
db_->Put(write_options, MakeSlice(key), MakeSlice(*value));
if (!s.ok())
LOG(ERROR) << "LevelDB put failed: " << s.ToString();
+ else
+ UMA_HISTOGRAM_TIMES("WebCore.IndexedDB.LevelDB.PutTime",
+ base::TimeTicks::Now() - begin_time);
return s;
}
@@ -362,6 +391,7 @@ leveldb::Status LevelDBDatabase::Get(const StringPiece& key,
}
leveldb::Status LevelDBDatabase::Write(const LevelDBWriteBatch& write_batch) {
+ base::TimeTicks begin_time = base::TimeTicks::Now();
leveldb::WriteOptions write_options;
write_options.sync = kSyncWrites;
@@ -370,81 +400,13 @@ leveldb::Status LevelDBDatabase::Write(const LevelDBWriteBatch& write_batch) {
if (!s.ok()) {
HistogramLevelDBError("WebCore.IndexedDB.LevelDBWriteErrors", s);
LOG(ERROR) << "LevelDB write failed: " << s.ToString();
+ } else {
+ UMA_HISTOGRAM_TIMES("WebCore.IndexedDB.LevelDB.WriteTime",
+ base::TimeTicks::Now() - begin_time);
}
return s;
}
-namespace {
-class IteratorImpl : public LevelDBIterator {
- public:
- virtual ~IteratorImpl() {}
-
- virtual bool IsValid() const OVERRIDE;
- virtual leveldb::Status SeekToLast() OVERRIDE;
- virtual leveldb::Status Seek(const StringPiece& target) OVERRIDE;
- virtual leveldb::Status Next() OVERRIDE;
- virtual leveldb::Status Prev() OVERRIDE;
- virtual StringPiece Key() const OVERRIDE;
- virtual StringPiece Value() const OVERRIDE;
-
- private:
- friend class content::LevelDBDatabase;
- explicit IteratorImpl(scoped_ptr<leveldb::Iterator> iterator);
- void CheckStatus();
-
- scoped_ptr<leveldb::Iterator> iterator_;
-
- DISALLOW_COPY_AND_ASSIGN(IteratorImpl);
-};
-} // namespace
-
-IteratorImpl::IteratorImpl(scoped_ptr<leveldb::Iterator> it)
- : iterator_(it.Pass()) {}
-
-void IteratorImpl::CheckStatus() {
- const leveldb::Status& s = iterator_->status();
- if (!s.ok())
- LOG(ERROR) << "LevelDB iterator error: " << s.ToString();
-}
-
-bool IteratorImpl::IsValid() const { return iterator_->Valid(); }
-
-leveldb::Status IteratorImpl::SeekToLast() {
- iterator_->SeekToLast();
- CheckStatus();
- return iterator_->status();
-}
-
-leveldb::Status IteratorImpl::Seek(const StringPiece& target) {
- iterator_->Seek(MakeSlice(target));
- CheckStatus();
- return iterator_->status();
-}
-
-leveldb::Status IteratorImpl::Next() {
- DCHECK(IsValid());
- iterator_->Next();
- CheckStatus();
- return iterator_->status();
-}
-
-leveldb::Status IteratorImpl::Prev() {
- DCHECK(IsValid());
- iterator_->Prev();
- CheckStatus();
- return iterator_->status();
-}
-
-StringPiece IteratorImpl::Key() const {
- DCHECK(IsValid());
- return MakeStringPiece(iterator_->key());
-}
-
-StringPiece IteratorImpl::Value() const {
- DCHECK(IsValid());
- return MakeStringPiece(iterator_->value());
-}
-
scoped_ptr<LevelDBIterator> LevelDBDatabase::CreateIterator(
const LevelDBSnapshot* snapshot) {
leveldb::ReadOptions read_options;
@@ -453,7 +415,8 @@ scoped_ptr<LevelDBIterator> LevelDBDatabase::CreateIterator(
read_options.snapshot = snapshot ? snapshot->snapshot_ : 0;
scoped_ptr<leveldb::Iterator> i(db_->NewIterator(read_options));
- return scoped_ptr<LevelDBIterator>(new IteratorImpl(i.Pass()));
+ return scoped_ptr<LevelDBIterator>(
+ IndexedDBClassFactory::Get()->CreateIteratorImpl(i.Pass()));
}
const LevelDBComparator* LevelDBDatabase::Comparator() const {
@@ -464,6 +427,8 @@ void LevelDBDatabase::Compact(const base::StringPiece& start,
const base::StringPiece& stop) {
const leveldb::Slice start_slice = MakeSlice(start);
const leveldb::Slice stop_slice = MakeSlice(stop);
+ // NULL batch means just wait for earlier writes to be done
+ db_->Write(leveldb::WriteOptions(), NULL);
db_->CompactRange(&start_slice, &stop_slice);
}
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_database.h b/chromium/content/browser/indexed_db/leveldb/leveldb_database.h
index f6bf7bed5bf..ddc6aa5c100 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_database.h
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_database.h
@@ -18,6 +18,7 @@
namespace leveldb {
class Comparator;
class DB;
+class FilterPolicy;
class Env;
class Snapshot;
}
@@ -58,15 +59,14 @@ class CONTENT_EXPORT LevelDBDatabase {
public:
explicit ComparatorAdapter(const LevelDBComparator* comparator);
- virtual int Compare(const leveldb::Slice& a,
- const leveldb::Slice& b) const OVERRIDE;
+ int Compare(const leveldb::Slice& a,
+ const leveldb::Slice& b) const override;
- virtual const char* Name() const OVERRIDE;
+ const char* Name() const override;
- virtual void FindShortestSeparator(std::string* start,
- const leveldb::Slice& limit) const
- OVERRIDE;
- virtual void FindShortSuccessor(std::string* key) const OVERRIDE;
+ void FindShortestSeparator(std::string* start,
+ const leveldb::Slice& limit) const override;
+ void FindShortSuccessor(std::string* key) const override;
private:
const LevelDBComparator* comparator_;
@@ -104,6 +104,7 @@ class CONTENT_EXPORT LevelDBDatabase {
scoped_ptr<leveldb::Env> env_;
scoped_ptr<leveldb::Comparator> comparator_adapter_;
scoped_ptr<leveldb::DB> db_;
+ scoped_ptr<const leveldb::FilterPolicy> filter_policy_;
const LevelDBComparator* comparator_;
};
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_factory.h b/chromium/content/browser/indexed_db/leveldb/leveldb_factory.h
new file mode 100644
index 00000000000..31974ee9098
--- /dev/null
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_factory.h
@@ -0,0 +1,33 @@
+// 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_INDEXED_DB_LEVELDB_LEVELDB_FACTORY_H_
+#define CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_FACTORY_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "third_party/leveldatabase/src/include/leveldb/status.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace content {
+
+class LevelDBComparator;
+class LevelDBDatabase;
+
+class CONTENT_EXPORT LevelDBFactory {
+ public:
+ virtual ~LevelDBFactory() {}
+ virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name,
+ const LevelDBComparator* comparator,
+ scoped_ptr<LevelDBDatabase>* db,
+ bool* is_disk_full) = 0;
+ virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) = 0;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_FACTORY_H_
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_iterator.h b/chromium/content/browser/indexed_db/leveldb/leveldb_iterator.h
index 1069a8b0a3c..d5efa4bf519 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_iterator.h
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_iterator.h
@@ -6,11 +6,12 @@
#define CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_ITERATOR_H_
#include "base/strings/string_piece.h"
+#include "content/common/content_export.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
namespace content {
-class LevelDBIterator {
+class CONTENT_EXPORT LevelDBIterator {
public:
virtual ~LevelDBIterator() {}
virtual bool IsValid() const = 0;
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc b/chromium/content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc
new file mode 100644
index 00000000000..46c99f4b60b
--- /dev/null
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc
@@ -0,0 +1,72 @@
+// 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 "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/indexed_db/leveldb/leveldb_iterator_impl.h"
+
+static leveldb::Slice MakeSlice(const base::StringPiece& s) {
+ return leveldb::Slice(s.begin(), s.size());
+}
+
+static base::StringPiece MakeStringPiece(const leveldb::Slice& s) {
+ return base::StringPiece(s.data(), s.size());
+}
+
+namespace content {
+
+LevelDBIteratorImpl::~LevelDBIteratorImpl() {
+}
+
+LevelDBIteratorImpl::LevelDBIteratorImpl(scoped_ptr<leveldb::Iterator> it)
+ : iterator_(it.Pass()) {
+}
+
+void LevelDBIteratorImpl::CheckStatus() {
+ const leveldb::Status& s = iterator_->status();
+ if (!s.ok())
+ LOG(ERROR) << "LevelDB iterator error: " << s.ToString();
+}
+
+bool LevelDBIteratorImpl::IsValid() const {
+ return iterator_->Valid();
+}
+
+leveldb::Status LevelDBIteratorImpl::SeekToLast() {
+ iterator_->SeekToLast();
+ CheckStatus();
+ return iterator_->status();
+}
+
+leveldb::Status LevelDBIteratorImpl::Seek(const base::StringPiece& target) {
+ iterator_->Seek(MakeSlice(target));
+ CheckStatus();
+ return iterator_->status();
+}
+
+leveldb::Status LevelDBIteratorImpl::Next() {
+ DCHECK(IsValid());
+ iterator_->Next();
+ CheckStatus();
+ return iterator_->status();
+}
+
+leveldb::Status LevelDBIteratorImpl::Prev() {
+ DCHECK(IsValid());
+ iterator_->Prev();
+ CheckStatus();
+ return iterator_->status();
+}
+
+base::StringPiece LevelDBIteratorImpl::Key() const {
+ DCHECK(IsValid());
+ return MakeStringPiece(iterator_->key());
+}
+
+base::StringPiece LevelDBIteratorImpl::Value() const {
+ DCHECK(IsValid());
+ return MakeStringPiece(iterator_->value());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_iterator_impl.h b/chromium/content/browser/indexed_db/leveldb/leveldb_iterator_impl.h
new file mode 100644
index 00000000000..72b92e0f93b
--- /dev/null
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_iterator_impl.h
@@ -0,0 +1,42 @@
+// 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_INDEXED_DB_LEVELDB_LEVELDB_ITERATOR_IMPL_H_
+#define CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_ITERATOR_IMPL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
+#include "content/common/content_export.h"
+#include "third_party/leveldatabase/src/include/leveldb/iterator.h"
+
+namespace content {
+
+class CONTENT_EXPORT LevelDBIteratorImpl : public content::LevelDBIterator {
+ public:
+ ~LevelDBIteratorImpl() override;
+ bool IsValid() const override;
+ leveldb::Status SeekToLast() override;
+ leveldb::Status Seek(const base::StringPiece& target) override;
+ leveldb::Status Next() override;
+ leveldb::Status Prev() override;
+ base::StringPiece Key() const override;
+ base::StringPiece Value() const override;
+
+ protected:
+ explicit LevelDBIteratorImpl(scoped_ptr<leveldb::Iterator> iterator);
+
+ private:
+ void CheckStatus();
+
+ friend class IndexedDBClassFactory;
+ friend class MockBrowserTestIndexedDBClassFactory;
+
+ scoped_ptr<leveldb::Iterator> iterator_;
+
+ DISALLOW_COPY_AND_ASSIGN(LevelDBIteratorImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_ITERATOR_IMPL_H_
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_transaction.cc b/chromium/content/browser/indexed_db/leveldb/leveldb_transaction.cc
index e20d404c3c5..a9e71093322 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_transaction.cc
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_transaction.cc
@@ -5,6 +5,8 @@
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
#include "content/browser/indexed_db/leveldb/leveldb_database.h"
#include "content/browser/indexed_db/leveldb/leveldb_write_batch.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
@@ -25,9 +27,8 @@ LevelDBTransaction::Record::Record() : deleted(false) {}
LevelDBTransaction::Record::~Record() {}
void LevelDBTransaction::Clear() {
- for (DataType::iterator it = data_.begin(); it != data_.end(); ++it) {
- delete it->second;
- }
+ for (const auto& it : data_)
+ delete it.second;
data_.clear();
}
@@ -93,20 +94,22 @@ leveldb::Status LevelDBTransaction::Commit() {
return leveldb::Status::OK();
}
+ base::TimeTicks begin_time = base::TimeTicks::Now();
scoped_ptr<LevelDBWriteBatch> write_batch = LevelDBWriteBatch::Create();
- for (DataType::iterator iterator = data_.begin(); iterator != data_.end();
- ++iterator) {
- if (!iterator->second->deleted)
- write_batch->Put(iterator->first, iterator->second->value);
+ for (const auto& iterator : data_) {
+ if (!iterator.second->deleted)
+ write_batch->Put(iterator.first, iterator.second->value);
else
- write_batch->Remove(iterator->first);
+ write_batch->Remove(iterator.first);
}
leveldb::Status s = db_->Write(*write_batch);
if (s.ok()) {
Clear();
finished_ = true;
+ UMA_HISTOGRAM_TIMES("WebCore.IndexedDB.LevelDB.Transaction.CommitTime",
+ base::TimeTicks::Now() - begin_time);
}
return s;
}
@@ -118,7 +121,7 @@ void LevelDBTransaction::Rollback() {
}
scoped_ptr<LevelDBIterator> LevelDBTransaction::CreateIterator() {
- return TransactionIterator::Create(this).PassAs<LevelDBIterator>();
+ return TransactionIterator::Create(this);
}
scoped_ptr<LevelDBTransaction::DataIterator>
@@ -439,12 +442,8 @@ void LevelDBTransaction::UnregisterIterator(TransactionIterator* iterator) {
}
void LevelDBTransaction::NotifyIterators() {
- for (std::set<TransactionIterator*>::iterator i = iterators_.begin();
- i != iterators_.end();
- ++i) {
- TransactionIterator* transaction_iterator = *i;
+ for (auto* transaction_iterator : iterators_)
transaction_iterator->DataChanged();
- }
}
scoped_ptr<LevelDBDirectTransaction> LevelDBDirectTransaction::Create(
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_transaction.h b/chromium/content/browser/indexed_db/leveldb/leveldb_transaction.h
index f6b5a95e121..28d76569374 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_transaction.h
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_transaction.h
@@ -24,7 +24,6 @@ class LevelDBWriteBatch;
class CONTENT_EXPORT LevelDBTransaction
: public base::RefCounted<LevelDBTransaction> {
public:
-
void Put(const base::StringPiece& key, std::string* value);
void Remove(const base::StringPiece& key);
virtual leveldb::Status Get(const base::StringPiece& key,
@@ -72,15 +71,15 @@ class CONTENT_EXPORT LevelDBTransaction
class DataIterator : public LevelDBIterator {
public:
static scoped_ptr<DataIterator> Create(LevelDBTransaction* transaction);
- virtual ~DataIterator();
-
- virtual bool IsValid() const OVERRIDE;
- virtual leveldb::Status SeekToLast() OVERRIDE;
- virtual leveldb::Status Seek(const base::StringPiece& slice) OVERRIDE;
- virtual leveldb::Status Next() OVERRIDE;
- virtual leveldb::Status Prev() OVERRIDE;
- virtual base::StringPiece Key() const OVERRIDE;
- virtual base::StringPiece Value() const OVERRIDE;
+ ~DataIterator() override;
+
+ bool IsValid() const override;
+ leveldb::Status SeekToLast() override;
+ leveldb::Status Seek(const base::StringPiece& slice) override;
+ leveldb::Status Next() override;
+ leveldb::Status Prev() override;
+ base::StringPiece Key() const override;
+ base::StringPiece Value() const override;
bool IsDeleted() const;
private:
@@ -93,20 +92,22 @@ class CONTENT_EXPORT LevelDBTransaction
class TransactionIterator : public LevelDBIterator {
public:
- virtual ~TransactionIterator();
+ ~TransactionIterator() override;
static scoped_ptr<TransactionIterator> Create(
scoped_refptr<LevelDBTransaction> transaction);
- virtual bool IsValid() const OVERRIDE;
- virtual leveldb::Status SeekToLast() OVERRIDE;
- virtual leveldb::Status Seek(const base::StringPiece& target) OVERRIDE;
- virtual leveldb::Status Next() OVERRIDE;
- virtual leveldb::Status Prev() OVERRIDE;
- virtual base::StringPiece Key() const OVERRIDE;
- virtual base::StringPiece Value() const OVERRIDE;
+ bool IsValid() const override;
+ leveldb::Status SeekToLast() override;
+ leveldb::Status Seek(const base::StringPiece& target) override;
+ leveldb::Status Next() override;
+ leveldb::Status Prev() override;
+ base::StringPiece Key() const override;
+ base::StringPiece Value() const override;
void DataChanged();
private:
+ enum Direction { FORWARD, REVERSE };
+
explicit TransactionIterator(scoped_refptr<LevelDBTransaction> transaction);
void HandleConflictsAndDeletes();
void SetCurrentIteratorToSmallestKey();
@@ -121,10 +122,6 @@ class CONTENT_EXPORT LevelDBTransaction
scoped_ptr<LevelDBIterator> db_iterator_;
LevelDBIterator* current_;
- enum Direction {
- FORWARD,
- REVERSE
- };
Direction direction_;
mutable bool data_changed_;
diff --git a/chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc b/chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc
index 83fdd59b878..7c649872a2d 100644
--- a/chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc
+++ b/chromium/content/browser/indexed_db/leveldb/leveldb_unittest.cc
@@ -25,12 +25,12 @@ namespace {
class SimpleComparator : public LevelDBComparator {
public:
- virtual int Compare(const base::StringPiece& a,
- const base::StringPiece& b) const OVERRIDE {
+ int Compare(const base::StringPiece& a,
+ const base::StringPiece& b) const override {
size_t len = std::min(a.size(), b.size());
return memcmp(a.begin(), b.begin(), len);
}
- virtual const char* Name() const OVERRIDE { return "temp_comparator"; }
+ const char* Name() const override { return "temp_comparator"; }
};
} // namespace
@@ -51,7 +51,7 @@ TEST(LevelDBDatabaseTest, CorruptionTest) {
put_value = value;
leveldb::Status status = leveldb->Put(key, &put_value);
EXPECT_TRUE(status.ok());
- leveldb.Pass();
+ leveldb.reset();
EXPECT_FALSE(leveldb);
LevelDBDatabase::Open(temp_directory.path(), &comparator, &leveldb);
@@ -61,7 +61,7 @@ TEST(LevelDBDatabaseTest, CorruptionTest) {
EXPECT_TRUE(status.ok());
EXPECT_TRUE(found);
EXPECT_EQ(value, got_value);
- leveldb.Pass();
+ leveldb.reset();
EXPECT_FALSE(leveldb);
base::FilePath file_path = temp_directory.path().AppendASCII("CURRENT");
diff --git a/chromium/content/browser/indexed_db/leveldb/mock_leveldb_factory.cc b/chromium/content/browser/indexed_db/leveldb/mock_leveldb_factory.cc
new file mode 100644
index 00000000000..61ff10b85b2
--- /dev/null
+++ b/chromium/content/browser/indexed_db/leveldb/mock_leveldb_factory.cc
@@ -0,0 +1,14 @@
+// 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/indexed_db/leveldb/mock_leveldb_factory.h"
+
+namespace content {
+
+MockLevelDBFactory::MockLevelDBFactory() {
+}
+
+MockLevelDBFactory::~MockLevelDBFactory() {
+}
+
+} // namespace content
diff --git a/chromium/content/browser/indexed_db/leveldb/mock_leveldb_factory.h b/chromium/content/browser/indexed_db/leveldb/mock_leveldb_factory.h
new file mode 100644
index 00000000000..dacb86081d0
--- /dev/null
+++ b/chromium/content/browser/indexed_db/leveldb/mock_leveldb_factory.h
@@ -0,0 +1,29 @@
+// 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_INDEXED_DB_LEVELDB_MOCK_LEVELDB_FACTORY_H_
+#define CONTENT_BROWSER_INDEXED_DB_LEVELDB_MOCK_LEVELDB_FACTORY_H_
+
+#include "base/files/file_path.h"
+#include "content/browser/indexed_db/leveldb/leveldb_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace content {
+
+class MockLevelDBFactory : public LevelDBFactory {
+ public:
+ MockLevelDBFactory();
+ ~MockLevelDBFactory();
+ MOCK_METHOD4(OpenLevelDB,
+ leveldb::Status(const base::FilePath& file_name,
+ const LevelDBComparator* comparator,
+ scoped_ptr<LevelDBDatabase>* db,
+ bool* is_disk_full));
+ MOCK_METHOD1(DestroyLevelDB,
+ leveldb::Status(const base::FilePath& file_name));
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_INDEXED_DB_LEVELDB_MOCK_LEVELDB_FACTORY_H_
diff --git a/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc b/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
index 0014070b3a2..a683f3759fb 100644
--- a/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
+++ b/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
@@ -5,6 +5,7 @@
#include <string>
#include "base/logging.h"
+#include "content/browser/indexed_db/leveldb/leveldb_iterator_impl.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
#include "content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
@@ -51,9 +52,9 @@ class LevelDBTestTansaction : public LevelDBTransaction {
DCHECK_GT(fail_on_call_num, 0);
}
- virtual leveldb::Status Get(const base::StringPiece& key,
- std::string* value,
- bool* found) OVERRIDE {
+ leveldb::Status Get(const base::StringPiece& key,
+ std::string* value,
+ bool* found) override {
if (fail_method_ != FAIL_METHOD_GET ||
++current_call_num_ != fail_on_call_num_)
return LevelDBTransaction::Get(key, value, found);
@@ -62,7 +63,7 @@ class LevelDBTestTansaction : public LevelDBTransaction {
return leveldb::Status::Corruption("Corrupted for the test");
}
- virtual leveldb::Status Commit() OVERRIDE {
+ leveldb::Status Commit() override {
if (fail_method_ != FAIL_METHOD_COMMIT ||
++current_call_num_ != fail_on_call_num_)
return LevelDBTransaction::Commit();
@@ -71,7 +72,7 @@ class LevelDBTestTansaction : public LevelDBTransaction {
}
private:
- virtual ~LevelDBTestTansaction() {}
+ ~LevelDBTestTansaction() override {}
FailMethod fail_method_;
int fail_on_call_num_;
@@ -85,22 +86,22 @@ class LevelDBTraceTansaction : public LevelDBTransaction {
commit_tracer_(s_class_name, "Commit", tx_num),
get_tracer_(s_class_name, "Get", tx_num) {}
- virtual leveldb::Status Get(const base::StringPiece& key,
- std::string* value,
- bool* found) OVERRIDE {
+ leveldb::Status Get(const base::StringPiece& key,
+ std::string* value,
+ bool* found) override {
get_tracer_.log_call();
return LevelDBTransaction::Get(key, value, found);
}
- virtual leveldb::Status Commit() OVERRIDE {
+ leveldb::Status Commit() override {
commit_tracer_.log_call();
return LevelDBTransaction::Commit();
}
private:
- virtual ~LevelDBTraceTansaction() {}
+ static const std::string s_class_name;
- const static std::string s_class_name;
+ ~LevelDBTraceTansaction() override {}
FunctionTracer commit_tracer_;
FunctionTracer get_tracer_;
@@ -108,6 +109,86 @@ class LevelDBTraceTansaction : public LevelDBTransaction {
const std::string LevelDBTraceTansaction::s_class_name = "LevelDBTransaction";
+class LevelDBTraceIteratorImpl : public LevelDBIteratorImpl {
+ public:
+ LevelDBTraceIteratorImpl(scoped_ptr<leveldb::Iterator> iterator, int inst_num)
+ : LevelDBIteratorImpl(iterator.Pass()),
+ is_valid_tracer_(s_class_name, "IsValid", inst_num),
+ seek_to_last_tracer_(s_class_name, "SeekToLast", inst_num),
+ seek_tracer_(s_class_name, "Seek", inst_num),
+ next_tracer_(s_class_name, "Next", inst_num),
+ prev_tracer_(s_class_name, "Prev", inst_num),
+ key_tracer_(s_class_name, "Key", inst_num),
+ value_tracer_(s_class_name, "Value", inst_num) {}
+ ~LevelDBTraceIteratorImpl() override {}
+
+ private:
+ static const std::string s_class_name;
+
+ bool IsValid() const override {
+ is_valid_tracer_.log_call();
+ return LevelDBIteratorImpl::IsValid();
+ }
+ leveldb::Status SeekToLast() override {
+ seek_to_last_tracer_.log_call();
+ return LevelDBIteratorImpl::SeekToLast();
+ }
+ leveldb::Status Seek(const base::StringPiece& target) override {
+ seek_tracer_.log_call();
+ return LevelDBIteratorImpl::Seek(target);
+ }
+ leveldb::Status Next() override {
+ next_tracer_.log_call();
+ return LevelDBIteratorImpl::Next();
+ }
+ leveldb::Status Prev() override {
+ prev_tracer_.log_call();
+ return LevelDBIteratorImpl::Prev();
+ }
+ base::StringPiece Key() const override {
+ key_tracer_.log_call();
+ return LevelDBIteratorImpl::Key();
+ }
+ base::StringPiece Value() const override {
+ value_tracer_.log_call();
+ return LevelDBIteratorImpl::Value();
+ }
+
+ mutable FunctionTracer is_valid_tracer_;
+ mutable FunctionTracer seek_to_last_tracer_;
+ mutable FunctionTracer seek_tracer_;
+ mutable FunctionTracer next_tracer_;
+ mutable FunctionTracer prev_tracer_;
+ mutable FunctionTracer key_tracer_;
+ mutable FunctionTracer value_tracer_;
+};
+
+const std::string LevelDBTraceIteratorImpl::s_class_name = "LevelDBIterator";
+
+class LevelDBTestIteratorImpl : public content::LevelDBIteratorImpl {
+ public:
+ LevelDBTestIteratorImpl(scoped_ptr<leveldb::Iterator> iterator,
+ FailMethod fail_method,
+ int fail_on_call_num)
+ : LevelDBIteratorImpl(iterator.Pass()),
+ fail_method_(fail_method),
+ fail_on_call_num_(fail_on_call_num),
+ current_call_num_(0) {}
+ ~LevelDBTestIteratorImpl() override {}
+
+ private:
+ leveldb::Status Seek(const base::StringPiece& target) override {
+ if (fail_method_ != FAIL_METHOD_SEEK ||
+ ++current_call_num_ != fail_on_call_num_)
+ return LevelDBIteratorImpl::Seek(target);
+ return leveldb::Status::Corruption("Corrupted for test");
+ }
+
+ FailMethod fail_method_;
+ int fail_on_call_num_;
+ int current_call_num_;
+};
+
MockBrowserTestIndexedDBClassFactory::MockBrowserTestIndexedDBClassFactory()
: failure_class_(FAIL_CLASS_NOTHING),
failure_method_(FAIL_METHOD_NOTHING),
@@ -139,6 +220,27 @@ MockBrowserTestIndexedDBClassFactory::CreateLevelDBTransaction(
}
}
+LevelDBIteratorImpl* MockBrowserTestIndexedDBClassFactory::CreateIteratorImpl(
+ scoped_ptr<leveldb::Iterator> iterator) {
+ instance_count_[FAIL_CLASS_LEVELDB_ITERATOR] =
+ instance_count_[FAIL_CLASS_LEVELDB_ITERATOR] + 1;
+ if (only_trace_calls_) {
+ return new LevelDBTraceIteratorImpl(
+ iterator.Pass(), instance_count_[FAIL_CLASS_LEVELDB_ITERATOR]);
+ } else {
+ if (failure_class_ == FAIL_CLASS_LEVELDB_ITERATOR &&
+ instance_count_[FAIL_CLASS_LEVELDB_ITERATOR] ==
+ fail_on_instance_num_[FAIL_CLASS_LEVELDB_ITERATOR]) {
+ return new LevelDBTestIteratorImpl(
+ iterator.Pass(),
+ failure_method_,
+ fail_on_call_num_[FAIL_CLASS_LEVELDB_ITERATOR]);
+ } else {
+ return new LevelDBIteratorImpl(iterator.Pass());
+ }
+ }
+}
+
void MockBrowserTestIndexedDBClassFactory::FailOperation(
FailClass failure_class,
FailMethod failure_method,
diff --git a/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h b/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
index b30f150cb4a..9e40b60a90a 100644
--- a/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
+++ b/chromium/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
@@ -16,6 +16,7 @@ class LevelDBDatabase;
enum FailClass {
FAIL_CLASS_NOTHING,
+ FAIL_CLASS_LEVELDB_ITERATOR,
FAIL_CLASS_LEVELDB_TRANSACTION,
};
@@ -23,14 +24,16 @@ enum FailMethod {
FAIL_METHOD_NOTHING,
FAIL_METHOD_COMMIT,
FAIL_METHOD_GET,
+ FAIL_METHOD_SEEK,
};
class MockBrowserTestIndexedDBClassFactory : public IndexedDBClassFactory {
public:
MockBrowserTestIndexedDBClassFactory();
- virtual ~MockBrowserTestIndexedDBClassFactory();
- virtual LevelDBTransaction* CreateLevelDBTransaction(
- LevelDBDatabase* db) OVERRIDE;
+ ~MockBrowserTestIndexedDBClassFactory() override;
+ LevelDBTransaction* CreateLevelDBTransaction(LevelDBDatabase* db) override;
+ LevelDBIteratorImpl* CreateIteratorImpl(
+ scoped_ptr<leveldb::Iterator> iterator) override;
void FailOperation(FailClass failure_class,
FailMethod failure_method,
diff --git a/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h b/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h
index fecfd1abb29..24743fe0b32 100644
--- a/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h
+++ b/chromium/content/browser/indexed_db/mock_indexed_db_callbacks.h
@@ -17,16 +17,16 @@ class MockIndexedDBCallbacks : public IndexedDBCallbacks {
MockIndexedDBCallbacks();
explicit MockIndexedDBCallbacks(bool expect_connection);
- virtual void OnSuccess() OVERRIDE;
- virtual void OnSuccess(int64 result) OVERRIDE;
- virtual void OnSuccess(const std::vector<base::string16>& result) OVERRIDE;
- virtual void OnSuccess(const IndexedDBKey& key) OVERRIDE;
- virtual void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
- const IndexedDBDatabaseMetadata& metadata) OVERRIDE;
+ void OnSuccess() override;
+ void OnSuccess(int64 result) override;
+ void OnSuccess(const std::vector<base::string16>& result) override;
+ void OnSuccess(const IndexedDBKey& key) override;
+ void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
+ const IndexedDBDatabaseMetadata& metadata) override;
IndexedDBConnection* connection() { return connection_.get(); }
protected:
- virtual ~MockIndexedDBCallbacks();
+ ~MockIndexedDBCallbacks() override;
scoped_ptr<IndexedDBConnection> connection_;
diff --git a/chromium/content/browser/indexed_db/mock_indexed_db_database_callbacks.h b/chromium/content/browser/indexed_db/mock_indexed_db_database_callbacks.h
index 7252a9fde0a..31a29645a25 100644
--- a/chromium/content/browser/indexed_db/mock_indexed_db_database_callbacks.h
+++ b/chromium/content/browser/indexed_db/mock_indexed_db_database_callbacks.h
@@ -14,17 +14,17 @@ class MockIndexedDBDatabaseCallbacks : public IndexedDBDatabaseCallbacks {
public:
MockIndexedDBDatabaseCallbacks();
- virtual void OnVersionChange(int64 old_version, int64 new_version) OVERRIDE {}
- virtual void OnForcedClose() OVERRIDE;
- virtual void OnAbort(int64 transaction_id,
- const IndexedDBDatabaseError& error) OVERRIDE;
- virtual void OnComplete(int64 transaction_id) OVERRIDE {}
+ void OnVersionChange(int64 old_version, int64 new_version) override {}
+ void OnForcedClose() override;
+ void OnAbort(int64 transaction_id,
+ const IndexedDBDatabaseError& error) override;
+ void OnComplete(int64 transaction_id) override {}
bool abort_called() const { return abort_called_; }
bool forced_close_called() const { return forced_close_called_; }
private:
- virtual ~MockIndexedDBDatabaseCallbacks() {}
+ ~MockIndexedDBDatabaseCallbacks() override {}
bool abort_called_;
bool forced_close_called_;
diff --git a/chromium/content/browser/indexed_db/mock_indexed_db_factory.cc b/chromium/content/browser/indexed_db/mock_indexed_db_factory.cc
new file mode 100644
index 00000000000..1c95226f6e4
--- /dev/null
+++ b/chromium/content/browser/indexed_db/mock_indexed_db_factory.cc
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/indexed_db/mock_indexed_db_factory.h"
+
+namespace content {
+
+MockIndexedDBFactory::MockIndexedDBFactory() {
+}
+
+MockIndexedDBFactory::~MockIndexedDBFactory() {
+}
+
+IndexedDBFactory::OriginDBs MockIndexedDBFactory::GetOpenDatabasesForOrigin(
+ const GURL& origin_url) const {
+ return OriginDBs();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/indexed_db/mock_indexed_db_factory.h b/chromium/content/browser/indexed_db/mock_indexed_db_factory.h
new file mode 100644
index 00000000000..6860cfa7da8
--- /dev/null
+++ b/chromium/content/browser/indexed_db/mock_indexed_db_factory.h
@@ -0,0 +1,85 @@
+// 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_INDEXED_DB_MOCK_INDEXED_DB_FACTORY_H_
+#define CONTENT_BROWSER_INDEXED_DB_MOCK_INDEXED_DB_FACTORY_H_
+
+#include <string>
+
+#include "content/browser/indexed_db/indexed_db_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace content {
+
+class MockIndexedDBFactory : public IndexedDBFactory {
+ public:
+ MockIndexedDBFactory();
+ MOCK_METHOD2(ReleaseDatabase,
+ void(const IndexedDBDatabase::Identifier& identifier,
+ bool forcedClose));
+ MOCK_METHOD4(GetDatabaseNames,
+ void(scoped_refptr<IndexedDBCallbacks> callbacks,
+ const GURL& origin_url,
+ const base::FilePath& data_directory,
+ net::URLRequestContext* request_context));
+ MOCK_METHOD5(Open,
+ void(const base::string16& name,
+ const IndexedDBPendingConnection& connection,
+ net::URLRequestContext* request_context,
+ const GURL& origin_url,
+ const base::FilePath& data_directory));
+ MOCK_METHOD5(DeleteDatabase,
+ void(const base::string16& name,
+ net::URLRequestContext* request_context,
+ scoped_refptr<IndexedDBCallbacks> callbacks,
+ const GURL& origin_url,
+ const base::FilePath& data_directory));
+ MOCK_METHOD1(HandleBackingStoreFailure, void(const GURL& origin_url));
+ MOCK_METHOD2(HandleBackingStoreCorruption,
+ void(const GURL& origin_url,
+ const IndexedDBDatabaseError& error));
+ // The Android NDK implements a subset of STL, and the gtest templates can't
+ // deal with std::pair's. This means we can't use GoogleMock for this method
+ virtual OriginDBs GetOpenDatabasesForOrigin(
+ const GURL& origin_url) const override;
+ MOCK_METHOD1(ForceClose, void(const GURL& origin_url));
+ MOCK_METHOD0(ContextDestroyed, void());
+ MOCK_METHOD1(DatabaseDeleted,
+ void(const IndexedDBDatabase::Identifier& identifier));
+ MOCK_CONST_METHOD1(GetConnectionCount, size_t(const GURL& origin_url));
+
+ MOCK_METHOD2(ReportOutstandingBlobs,
+ void(const GURL& origin_url, bool blobs_outstanding));
+
+ protected:
+ virtual ~MockIndexedDBFactory();
+
+ MOCK_METHOD7(OpenBackingStore,
+ scoped_refptr<IndexedDBBackingStore>(
+ const GURL& origin_url,
+ const base::FilePath& data_directory,
+ net::URLRequestContext* request_context,
+ blink::WebIDBDataLoss* data_loss,
+ std::string* data_loss_reason,
+ bool* disk_full,
+ leveldb::Status* s));
+
+ MOCK_METHOD8(OpenBackingStoreHelper,
+ scoped_refptr<IndexedDBBackingStore>(
+ const GURL& origin_url,
+ const base::FilePath& data_directory,
+ net::URLRequestContext* request_context,
+ blink::WebIDBDataLoss* data_loss,
+ std::string* data_loss_message,
+ bool* disk_full,
+ bool first_time,
+ leveldb::Status* s));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockIndexedDBFactory);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_INDEXED_DB_MOCK_INDEXED_DB_FACTORY_H_
diff --git a/chromium/content/browser/loader/OWNERS b/chromium/content/browser/loader/OWNERS
index 1e9e8232811..747dc150159 100644
--- a/chromium/content/browser/loader/OWNERS
+++ b/chromium/content/browser/loader/OWNERS
@@ -1,2 +1 @@
-davidben@chromium.org
mmenke@chromium.org \ No newline at end of file
diff --git a/chromium/content/browser/loader/async_resource_handler.cc b/chromium/content/browser/loader/async_resource_handler.cc
index 69e831bd298..5125bec8607 100644
--- a/chromium/content/browser/loader/async_resource_handler.cc
+++ b/chromium/content/browser/loader/async_resource_handler.cc
@@ -14,6 +14,7 @@
#include "base/memory/shared_memory.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
#include "content/browser/devtools/devtools_netlog_observer.h"
#include "content/browser/host_zoom_map_impl.h"
#include "content/browser/loader/resource_buffer.h"
@@ -29,6 +30,7 @@
#include "net/base/load_flags.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/url_request/redirect_info.h"
using base::TimeTicks;
@@ -41,7 +43,7 @@ static int kMaxAllocationSize = 1024 * 32;
void GetNumericArg(const std::string& name, int* result) {
const std::string& value =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
if (!value.empty())
base::StringToInt(value, result);
}
@@ -71,7 +73,7 @@ class DependentIOBuffer : public net::WrappedIOBuffer {
backing_(backing) {
}
private:
- virtual ~DependentIOBuffer() {}
+ ~DependentIOBuffer() override {}
scoped_refptr<ResourceBuffer> backing_;
};
@@ -112,6 +114,13 @@ void AsyncResourceHandler::OnFollowRedirect(int request_id) {
return;
}
+ if (!redirect_start_time_.is_null()) {
+ UMA_HISTOGRAM_TIMES("Net.AsyncResourceHandler_RedirectHopTime",
+ TimeTicks::Now() - redirect_start_time_);
+ // Reset start time.
+ redirect_start_time_ = TimeTicks();
+ }
+
ResumeIfDeferred();
}
@@ -134,19 +143,22 @@ bool AsyncResourceHandler::OnUploadProgress(uint64 position,
new ResourceMsg_UploadProgress(GetRequestID(), position, size));
}
-bool AsyncResourceHandler::OnRequestRedirected(const GURL& new_url,
- ResourceResponse* response,
- bool* defer) {
+bool AsyncResourceHandler::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) {
const ResourceRequestInfoImpl* info = GetRequestInfo();
if (!info->filter())
return false;
+ redirect_start_time_ = TimeTicks::Now();
+
*defer = did_defer_ = true;
OnDefer();
if (rdh_->delegate()) {
rdh_->delegate()->OnRequestRedirected(
- new_url, request(), info->GetContext(), response);
+ redirect_info.new_url, request(), info->GetContext(), response);
}
DevToolsNetLogObserver::PopulateResponseInfo(request(), response);
@@ -159,8 +171,7 @@ bool AsyncResourceHandler::OnRequestRedirected(const GURL& new_url,
// and hopefully those will eventually all be owned by the browser. It's
// possible this is still needed while renderer-owned ones exist.
return info->filter()->Send(new ResourceMsg_ReceivedRedirect(
- GetRequestID(), new_url, request()->first_party_for_cookies(),
- response->head));
+ GetRequestID(), redirect_info, response->head));
}
bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response,
@@ -185,7 +196,7 @@ bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response,
HostZoomMap* host_zoom_map =
GetHostZoomMapForResourceContext(info->GetContext());
- if (info->GetResourceType() == ResourceType::MAIN_FRAME && host_zoom_map) {
+ if (info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME && host_zoom_map) {
const GURL& request_url = request()->url();
info->filter()->Send(new ViewMsg_SetZoomLevelForLoadingURL(
info->GetRouteID(),
diff --git a/chromium/content/browser/loader/async_resource_handler.h b/chromium/content/browser/loader/async_resource_handler.h
index b0821191e0d..e2954f4975a 100644
--- a/chromium/content/browser/loader/async_resource_handler.h
+++ b/chromium/content/browser/loader/async_resource_handler.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
#include "content/browser/loader/resource_handler.h"
#include "content/browser/loader/resource_message_delegate.h"
#include "url/gurl.h"
@@ -30,27 +31,26 @@ class AsyncResourceHandler : public ResourceHandler,
public:
AsyncResourceHandler(net::URLRequest* request,
ResourceDispatcherHostImpl* rdh);
- virtual ~AsyncResourceHandler();
+ ~AsyncResourceHandler() override;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
// ResourceHandler implementation:
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
- virtual bool OnRequestRedirected(const GURL& new_url,
- ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE;
+ bool OnUploadProgress(uint64 position, uint64 size) override;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL& url, bool* defer) override;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
+ void OnDataDownloaded(int bytes_downloaded) override;
private:
// IPC message handlers:
@@ -78,6 +78,8 @@ class AsyncResourceHandler : public ResourceHandler,
int64_t reported_transfer_size_;
+ base::TimeTicks redirect_start_time_;
+
DISALLOW_COPY_AND_ASSIGN(AsyncResourceHandler);
};
diff --git a/chromium/content/browser/loader/buffered_resource_handler.cc b/chromium/content/browser/loader/buffered_resource_handler.cc
index 8fb8c5d4484..f96b5506d8c 100644
--- a/chromium/content/browser/loader/buffered_resource_handler.cc
+++ b/chromium/content/browser/loader/buffered_resource_handler.cc
@@ -16,7 +16,6 @@
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/browser/loader/stream_resource_handler.h"
-#include "content/browser/plugin_service_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_save_info.h"
@@ -32,6 +31,10 @@
#include "net/http/http_content_disposition.h"
#include "net/http/http_response_headers.h"
+#if defined(ENABLE_PLUGINS)
+#include "content/browser/plugin_service_impl.h"
+#endif
+
namespace content {
namespace {
@@ -70,7 +73,7 @@ class DependentIOBuffer : public net::WrappedIOBuffer {
}
private:
- virtual ~DependentIOBuffer() {}
+ ~DependentIOBuffer() override {}
scoped_refptr<net::IOBuffer> buf_;
};
@@ -348,7 +351,7 @@ bool BufferedResourceHandler::SelectNextHandler(bool* defer) {
request(),
true, // is_content_initiated
must_download,
- content::DownloadItem::kInvalidId,
+ DownloadItem::kInvalidId,
scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo()),
DownloadUrlParameters::OnStartedCallback()));
return UseAlternateNextHandler(handler.Pass(), std::string());
diff --git a/chromium/content/browser/loader/buffered_resource_handler.h b/chromium/content/browser/loader/buffered_resource_handler.h
index 0b6d6989097..8735359e21e 100644
--- a/chromium/content/browser/loader/buffered_resource_handler.h
+++ b/chromium/content/browser/loader/buffered_resource_handler.h
@@ -28,26 +28,25 @@ class BufferedResourceHandler
BufferedResourceHandler(scoped_ptr<ResourceHandler> next_handler,
ResourceDispatcherHostImpl* host,
net::URLRequest* request);
- virtual ~BufferedResourceHandler();
+ ~BufferedResourceHandler() override;
private:
// ResourceHandler implementation:
- virtual void SetController(ResourceController* controller) OVERRIDE;
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
+ void SetController(ResourceController* controller) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
// ResourceController implementation:
- virtual void Resume() OVERRIDE;
- virtual void Cancel() OVERRIDE;
- virtual void CancelAndIgnore() OVERRIDE;
- virtual void CancelWithError(int error_code) OVERRIDE;
+ void Resume() override;
+ void Cancel() override;
+ void CancelAndIgnore() override;
+ void CancelWithError(int error_code) override;
bool ProcessResponse(bool* defer);
diff --git a/chromium/content/browser/loader/certificate_resource_handler.cc b/chromium/content/browser/loader/certificate_resource_handler.cc
index 9b3a607eb46..eb1976bef05 100644
--- a/chromium/content/browser/loader/certificate_resource_handler.cc
+++ b/chromium/content/browser/loader/certificate_resource_handler.cc
@@ -12,6 +12,7 @@
#include "net/base/mime_sniffer.h"
#include "net/base/mime_util.h"
#include "net/http/http_response_headers.h"
+#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_status.h"
@@ -34,10 +35,10 @@ bool CertificateResourceHandler::OnUploadProgress(uint64 position,
return true;
}
-bool CertificateResourceHandler::OnRequestRedirected(const GURL& url,
- ResourceResponse* resp,
- bool* defer) {
- url_ = url;
+bool CertificateResourceHandler::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* resp,
+ bool* defer) {
return true;
}
diff --git a/chromium/content/browser/loader/certificate_resource_handler.h b/chromium/content/browser/loader/certificate_resource_handler.h
index 9c67860eb7e..e8ce4ba4be3 100644
--- a/chromium/content/browser/loader/certificate_resource_handler.h
+++ b/chromium/content/browser/loader/certificate_resource_handler.h
@@ -14,7 +14,6 @@
#include "base/memory/scoped_ptr.h"
#include "content/browser/loader/resource_handler.h"
#include "net/base/mime_util.h"
-#include "url/gurl.h"
namespace net {
class IOBuffer;
@@ -32,40 +31,39 @@ namespace content {
class CertificateResourceHandler : public ResourceHandler {
public:
explicit CertificateResourceHandler(net::URLRequest* request);
- virtual ~CertificateResourceHandler();
+ ~CertificateResourceHandler() override;
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
+ bool OnUploadProgress(uint64 position, uint64 size) override;
// Not needed, as this event handler ought to be the final resource.
- virtual bool OnRequestRedirected(const GURL& url,
- ResourceResponse* resp,
- bool* defer) OVERRIDE;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* resp,
+ bool* defer) override;
// Check if this indeed an X509 cert.
- virtual bool OnResponseStarted(ResourceResponse* resp,
- bool* defer) OVERRIDE;
+ bool OnResponseStarted(ResourceResponse* resp, bool* defer) override;
// Pass-through implementation.
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnWillStart(const GURL& url, bool* defer) override;
// Pass-through implementation.
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
// Create a new buffer to store received data.
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
// A read was completed, maybe allocate a new buffer for further data.
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
// Done downloading the certificate.
- virtual void OnResponseCompleted(const net::URLRequestStatus& urs,
- const std::string& sec_info,
- bool* defer) OVERRIDE;
+ void OnResponseCompleted(const net::URLRequestStatus& urs,
+ const std::string& sec_info,
+ bool* defer) override;
// N/A to cert downloading.
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE;
+ void OnDataDownloaded(int bytes_downloaded) override;
private:
typedef std::vector<std::pair<scoped_refptr<net::IOBuffer>,
@@ -73,7 +71,6 @@ class CertificateResourceHandler : public ResourceHandler {
void AssembleResource();
- GURL url_;
size_t content_length_;
ContentVector buffer_;
scoped_refptr<net::IOBuffer> read_buffer_;
diff --git a/chromium/content/browser/loader/cross_site_resource_handler.cc b/chromium/content/browser/loader/cross_site_resource_handler.cc
index 8fa7238c357..2ec5ee56934 100644
--- a/chromium/content/browser/loader/cross_site_resource_handler.cc
+++ b/chromium/content/browser/loader/cross_site_resource_handler.cc
@@ -11,11 +11,12 @@
#include "base/logging.h"
#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/cross_site_request_manager.h"
#include "content/browser/frame_host/cross_site_transferring_request.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/browser/site_instance_impl.h"
+#include "content/browser/transition_request_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/global_request_id.h"
@@ -39,14 +40,12 @@ struct CrossSiteResponseParams {
CrossSiteResponseParams(
int render_frame_id,
const GlobalRequestID& global_request_id,
- bool is_transfer,
const std::vector<GURL>& transfer_url_chain,
const Referrer& referrer,
- PageTransition page_transition,
+ ui::PageTransition page_transition,
bool should_replace_current_entry)
: render_frame_id(render_frame_id),
global_request_id(global_request_id),
- is_transfer(is_transfer),
transfer_url_chain(transfer_url_chain),
referrer(referrer),
page_transition(page_transition),
@@ -55,19 +54,15 @@ struct CrossSiteResponseParams {
int render_frame_id;
GlobalRequestID global_request_id;
- bool is_transfer;
std::vector<GURL> transfer_url_chain;
Referrer referrer;
- PageTransition page_transition;
+ ui::PageTransition page_transition;
bool should_replace_current_entry;
};
void OnCrossSiteResponseHelper(const CrossSiteResponseParams& params) {
- scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request;
- if (params.is_transfer) {
- cross_site_transferring_request.reset(new CrossSiteTransferringRequest(
- params.global_request_id));
- }
+ scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request(
+ new CrossSiteTransferringRequest(params.global_request_id));
RenderFrameHostImpl* rfh =
RenderFrameHostImpl::FromID(params.global_request_id.child_id,
@@ -84,12 +79,29 @@ void OnCrossSiteResponseHelper(const CrossSiteResponseParams& params) {
}
}
+void OnDeferredAfterResponseStartedHelper(
+ const GlobalRequestID& global_request_id,
+ int render_frame_id,
+ const TransitionLayerData& transition_data) {
+ RenderFrameHostImpl* rfh =
+ RenderFrameHostImpl::FromID(global_request_id.child_id, render_frame_id);
+ if (rfh)
+ rfh->OnDeferredAfterResponseStarted(global_request_id, transition_data);
+}
+
+// Returns whether a transfer is needed by doing a check on the UI thread.
bool CheckNavigationPolicyOnUI(GURL url, int process_id, int render_frame_id) {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess));
RenderFrameHostImpl* rfh =
RenderFrameHostImpl::FromID(process_id, render_frame_id);
if (!rfh)
return false;
+ // A transfer is not needed if the current SiteInstance doesn't yet have a
+ // site. This is the case for tests that use NavigateToURL.
+ if (!rfh->GetSiteInstance()->HasSite())
+ return false;
+
// TODO(nasko): This check is very simplistic and is used temporarily only
// for --site-per-process. It should be updated to match the check performed
// by RenderFrameHostManager::UpdateStateForNavigate.
@@ -117,54 +129,63 @@ CrossSiteResourceHandler::~CrossSiteResourceHandler() {
}
bool CrossSiteResourceHandler::OnRequestRedirected(
- const GURL& new_url,
+ const net::RedirectInfo& redirect_info,
ResourceResponse* response,
bool* defer) {
- // Top-level requests change their cookie first-party URL on redirects, while
- // subframes retain the parent's value.
- if (GetRequestInfo()->GetResourceType() == ResourceType::MAIN_FRAME)
- request()->set_first_party_for_cookies(new_url);
-
// We should not have started the transition before being redirected.
DCHECK(!in_cross_site_transition_);
- return next_handler_->OnRequestRedirected(new_url, response, defer);
+ return next_handler_->OnRequestRedirected(redirect_info, response, defer);
}
bool CrossSiteResourceHandler::OnResponseStarted(
ResourceResponse* response,
bool* defer) {
+ response_ = response;
+ has_started_response_ = true;
+
+ // Store this handler on the ExtraRequestInfo, so that RDH can call our
+ // ResumeResponse method when we are ready to resume.
+ ResourceRequestInfoImpl* info = GetRequestInfo();
+ info->set_cross_site_handler(this);
+
+ TransitionLayerData transition_data;
+ bool is_navigation_transition =
+ TransitionRequestManager::GetInstance()->GetPendingTransitionRequest(
+ info->GetChildID(), info->GetRenderFrameID(), request()->url(),
+ &transition_data);
+
+ if (is_navigation_transition) {
+ if (response_.get())
+ transition_data.response_headers = response_->head.headers;
+ transition_data.request_url = request()->url();
+
+ return OnNavigationTransitionResponseStarted(response, defer,
+ transition_data);
+ } else {
+ return OnNormalResponseStarted(response, defer);
+ }
+}
+
+bool CrossSiteResourceHandler::OnNormalResponseStarted(
+ ResourceResponse* response,
+ bool* defer) {
// At this point, we know that the response is safe to send back to the
// renderer: it is not a download, and it has passed the SSL and safe
// browsing checks.
// We should not have already started the transition before now.
DCHECK(!in_cross_site_transition_);
- has_started_response_ = true;
ResourceRequestInfoImpl* info = GetRequestInfo();
- // We will need to swap processes if either (1) a redirect that requires a
- // transfer occurred before we got here, or (2) a pending cross-site request
- // was already in progress. Note that a swap may no longer be needed if we
- // transferred back into the original process due to a redirect.
+ // We only need to pause the response if a transfer to a different process is
+ // required. Other cross-process navigations can proceed immediately, since
+ // we run the unload handler at commit time.
+ // Note that a process swap may no longer be necessary if we transferred back
+ // into the original process due to a redirect.
bool should_transfer =
GetContentClient()->browser()->ShouldSwapProcessesForRedirect(
info->GetContext(), request()->original_url(), request()->url());
- // When the --site-per-process flag is passed, we transfer processes for
- // cross-site navigations. This is skipped if a transfer is already required
- // or for WebUI processes for now, since pages like the NTP host multiple
- // cross-site WebUI iframes.
- if (!should_transfer &&
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
- !ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
- info->GetChildID())) {
- return DeferForNavigationPolicyCheck(info, response, defer);
- }
-
- bool swap_needed = should_transfer ||
- CrossSiteRequestManager::GetInstance()->
- HasPendingCrossSiteRequest(info->GetChildID(), info->GetRouteID());
-
// If this is a download, just pass the response through without doing a
// cross-site check. The renderer will see it is a download and abort the
// request.
@@ -180,26 +201,72 @@ bool CrossSiteResourceHandler::OnResponseStarted(
//
// TODO(davidben): Unify IsDownload() and is_stream(). Several places need to
// check for both and remembering about streams is error-prone.
- if (!swap_needed || info->IsDownload() || info->is_stream() ||
+ if (info->IsDownload() || info->is_stream() ||
(response->head.headers.get() &&
response->head.headers->response_code() == 204)) {
return next_handler_->OnResponseStarted(response, defer);
}
- // Now that we know a swap is needed and we have something to commit, we
- // pause to let the UI thread run the unload handler of the previous page
- // and set up a transfer if needed.
- StartCrossSiteTransition(response, should_transfer);
+ // When the --site-per-process flag is passed, we transfer processes for
+ // cross-site navigations. This is skipped if a transfer is already required
+ // or for WebUI processes for now, since pages like the NTP host multiple
+ // cross-site WebUI iframes.
+ if (!should_transfer &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess) &&
+ !ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
+ info->GetChildID())) {
+ return DeferForNavigationPolicyCheck(info, response, defer);
+ }
- // Defer loading until after the onunload event handler has run.
+ if (!should_transfer)
+ return next_handler_->OnResponseStarted(response, defer);
+
+ // Now that we know a transfer is needed and we have something to commit, we
+ // pause to let the UI thread set up the transfer.
+ StartCrossSiteTransition(response);
+
+ // Defer loading until after the new renderer process has issued a
+ // corresponding request.
*defer = true;
OnDidDefer();
return true;
}
+bool CrossSiteResourceHandler::OnNavigationTransitionResponseStarted(
+ ResourceResponse* response,
+ bool* defer,
+ const TransitionLayerData& transition_data) {
+ ResourceRequestInfoImpl* info = GetRequestInfo();
+
+ GlobalRequestID global_id(info->GetChildID(), info->GetRequestID());
+ int render_frame_id = info->GetRenderFrameID();
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &OnDeferredAfterResponseStartedHelper,
+ global_id,
+ render_frame_id,
+ transition_data));
+
+ *defer = true;
+ OnDidDefer();
+ return true;
+}
+
+void CrossSiteResourceHandler::ResumeResponseDeferredAtStart(int request_id) {
+ bool defer = false;
+ if (!OnNormalResponseStarted(response_.get(), &defer)) {
+ controller()->Cancel();
+ } else if (!defer) {
+ ResumeIfDeferred();
+ }
+}
+
void CrossSiteResourceHandler::ResumeOrTransfer(bool is_transfer) {
if (is_transfer) {
- StartCrossSiteTransition(response_, is_transfer);
+ StartCrossSiteTransition(response_.get());
} else {
ResumeResponse();
}
@@ -215,23 +282,9 @@ void CrossSiteResourceHandler::OnResponseCompleted(
const std::string& security_info,
bool* defer) {
if (!in_cross_site_transition_) {
- ResourceRequestInfoImpl* info = GetRequestInfo();
- // If we've already completed the transition, or we're canceling the
- // request, or an error occurred with no cross-process navigation in
- // progress, then we should just pass this through.
- if (has_started_response_ ||
- status.status() != net::URLRequestStatus::FAILED ||
- !CrossSiteRequestManager::GetInstance()->HasPendingCrossSiteRequest(
- info->GetChildID(), info->GetRouteID())) {
- next_handler_->OnResponseCompleted(status, security_info, defer);
- return;
- }
-
- // An error occurred. We should wait now for the cross-process transition,
- // so that the error message (e.g., 404) can be displayed to the user.
- // Also continue with the logic below to remember that we completed
- // during the cross-site transition.
- StartCrossSiteTransition(NULL, false);
+ // If we're not transferring, then we should pass this through.
+ next_handler_->OnResponseCompleted(status, security_info, defer);
+ return;
}
// We have to buffer the call until after the transition completes.
@@ -248,13 +301,15 @@ void CrossSiteResourceHandler::OnResponseCompleted(
// We can now send the response to the new renderer, which will cause
// WebContentsImpl to swap in the new renderer and destroy the old one.
void CrossSiteResourceHandler::ResumeResponse() {
+ TRACE_EVENT_ASYNC_END0(
+ "navigation", "CrossSiteResourceHandler transition", this);
DCHECK(request());
in_cross_site_transition_ = false;
ResourceRequestInfoImpl* info = GetRequestInfo();
if (has_started_response_) {
// Send OnResponseStarted to the new renderer.
- DCHECK(response_);
+ DCHECK(response_.get());
bool defer = false;
if (!next_handler_->OnResponseStarted(response_.get(), &defer)) {
controller()->Cancel();
@@ -286,11 +341,11 @@ void CrossSiteResourceHandler::SetLeakRequestsForTesting(
leak_requests_for_testing_ = leak_requests_for_testing;
}
-// Prepare to render the cross-site response in a new RenderFrameHost, by
-// telling the old RenderFrameHost to run its onunload handler.
+// Prepare to transfer the response to a new RenderFrameHost.
void CrossSiteResourceHandler::StartCrossSiteTransition(
- ResourceResponse* response,
- bool should_transfer) {
+ ResourceResponse* response) {
+ TRACE_EVENT_ASYNC_BEGIN0(
+ "navigation", "CrossSiteResourceHandler transition", this);
in_cross_site_transition_ = true;
response_ = response;
@@ -310,14 +365,13 @@ void CrossSiteResourceHandler::StartCrossSiteTransition(
std::vector<GURL> transfer_url_chain;
Referrer referrer;
int render_frame_id = info->GetRenderFrameID();
- if (should_transfer) {
- transfer_url_chain = request()->url_chain();
- referrer = Referrer(GURL(request()->referrer()), info->GetReferrerPolicy());
+ transfer_url_chain = request()->url_chain();
+ referrer = Referrer(GURL(request()->referrer()), info->GetReferrerPolicy());
+
+ AppCacheInterceptor::PrepareForCrossSiteTransfer(
+ request(), global_id.child_id);
+ ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id);
- AppCacheInterceptor::PrepareForCrossSiteTransfer(
- request(), global_id.child_id);
- ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id);
- }
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -325,7 +379,6 @@ void CrossSiteResourceHandler::StartCrossSiteTransition(
&OnCrossSiteResponseHelper,
CrossSiteResponseParams(render_frame_id,
global_id,
- should_transfer,
transfer_url_chain,
referrer,
info->GetPageTransition(),
diff --git a/chromium/content/browser/loader/cross_site_resource_handler.h b/chromium/content/browser/loader/cross_site_resource_handler.h
index 257af02c01b..f0410462996 100644
--- a/chromium/content/browser/loader/cross_site_resource_handler.h
+++ b/chromium/content/browser/loader/cross_site_resource_handler.h
@@ -17,28 +17,28 @@ class URLRequest;
namespace content {
-// Ensures that cross-site responses are delayed until the onunload handler of
-// the previous page is allowed to run. This handler wraps an
-// AsyncEventHandler, and it sits inside SafeBrowsing and Buffered event
-// handlers. This is important, so that it can intercept OnResponseStarted
-// after we determine that a response is safe and not a download.
+struct TransitionLayerData;
+
+// Ensures that responses are delayed for navigations that must be transferred
+// to a different process. This handler wraps an AsyncEventHandler, and it sits
+// inside SafeBrowsing and Buffered event handlers. This is important, so that
+// it can intercept OnResponseStarted after we determine that a response is safe
+// and not a download.
class CrossSiteResourceHandler : public LayeredResourceHandler {
public:
CrossSiteResourceHandler(scoped_ptr<ResourceHandler> next_handler,
net::URLRequest* request);
- virtual ~CrossSiteResourceHandler();
+ ~CrossSiteResourceHandler() override;
// ResourceHandler implementation:
- virtual bool OnRequestRedirected(const GURL& new_url,
- ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnReadCompleted(int bytes_read,
- bool* defer) OVERRIDE;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
// We can now send the response to the new renderer, which will cause
// WebContentsImpl to swap in the new renderer and destroy the old one.
@@ -49,11 +49,18 @@ class CrossSiteResourceHandler : public LayeredResourceHandler {
CONTENT_EXPORT static void SetLeakRequestsForTesting(
bool leak_requests_for_testing);
+ // Navigations are deferred at OnResponseStarted to parse out any navigation
+ // transition link headers, and give the navigation transition (if it exists)
+ // a chance to run.
+ void ResumeResponseDeferredAtStart(int request_id);
+
+ // Returns whether the handler is deferred.
+ bool did_defer_for_testing() const { return did_defer_; }
+
private:
- // Prepare to render the cross-site response in a new RenderViewHost, by
- // telling the old RenderViewHost to run its onunload handler.
- void StartCrossSiteTransition(ResourceResponse* response,
- bool should_transfer);
+ // Prepare to transfer the cross-site response to a new RenderFrameHost, by
+ // asking it to issue an identical request (on the UI thread).
+ void StartCrossSiteTransition(ResourceResponse* response);
// Defer the navigation to the UI thread to check whether transfer is required
// or not. Currently only used in --site-per-process.
@@ -61,6 +68,14 @@ class CrossSiteResourceHandler : public LayeredResourceHandler {
ResourceResponse* response,
bool* defer);
+ bool OnNavigationTransitionResponseStarted(
+ ResourceResponse* response,
+ bool* defer,
+ const TransitionLayerData& transition_data);
+
+ bool OnNormalResponseStarted(ResourceResponse* response,
+ bool* defer);
+
void ResumeOrTransfer(bool is_transfer);
void ResumeIfDeferred();
diff --git a/chromium/content/browser/loader/detachable_resource_handler.cc b/chromium/content/browser/loader/detachable_resource_handler.cc
index b8ef55d4fff..ab7e240b1ee 100644
--- a/chromium/content/browser/loader/detachable_resource_handler.cc
+++ b/chromium/content/browser/loader/detachable_resource_handler.cc
@@ -9,6 +9,7 @@
#include "content/browser/loader/resource_request_info_impl.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/url_request/url_request.h"
#include "net/url_request/url_request_status.h"
namespace {
@@ -69,8 +70,12 @@ void DetachableResourceHandler::Detach() {
// Resume if necessary. The request may have been deferred, say, waiting on a
// full buffer in AsyncResourceHandler. Now that it has been detached, resume
// and drain it.
- if (is_deferred_)
+ if (is_deferred_) {
+ // The nested ResourceHandler may have logged that it's blocking the
+ // request. Log it as no longer doing so, to avoid a DCHECK on resume.
+ request()->LogUnblocked();
Resume();
+ }
}
void DetachableResourceHandler::SetController(ResourceController* controller) {
@@ -89,15 +94,17 @@ bool DetachableResourceHandler::OnUploadProgress(uint64 position, uint64 size) {
return next_handler_->OnUploadProgress(position, size);
}
-bool DetachableResourceHandler::OnRequestRedirected(const GURL& url,
- ResourceResponse* response,
- bool* defer) {
+bool DetachableResourceHandler::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) {
DCHECK(!is_deferred_);
if (!next_handler_)
return true;
- bool ret = next_handler_->OnRequestRedirected(url, response, &is_deferred_);
+ bool ret = next_handler_->OnRequestRedirected(
+ redirect_info, response, &is_deferred_);
*defer = is_deferred_;
return ret;
}
@@ -144,7 +151,7 @@ bool DetachableResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int min_size) {
if (!next_handler_) {
DCHECK_EQ(-1, min_size);
- if (!read_buffer_)
+ if (!read_buffer_.get())
read_buffer_ = new net::IOBuffer(kReadBufSize);
*buf = read_buffer_;
*buf_size = kReadBufSize;
diff --git a/chromium/content/browser/loader/detachable_resource_handler.h b/chromium/content/browser/loader/detachable_resource_handler.h
index 9a685701a9d..64d23ef2628 100644
--- a/chromium/content/browser/loader/detachable_resource_handler.h
+++ b/chromium/content/browser/loader/detachable_resource_handler.h
@@ -37,7 +37,7 @@ class DetachableResourceHandler : public ResourceHandler,
DetachableResourceHandler(net::URLRequest* request,
base::TimeDelta cancel_delay,
scoped_ptr<ResourceHandler> next_handler);
- virtual ~DetachableResourceHandler();
+ ~DetachableResourceHandler() override;
bool is_detached() const { return next_handler_ == NULL; }
void Detach();
@@ -47,29 +47,28 @@ class DetachableResourceHandler : public ResourceHandler,
}
// ResourceHandler implementation:
- virtual void SetController(ResourceController* controller) OVERRIDE;
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
- virtual bool OnRequestRedirected(const GURL& url,
- ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE;
+ void SetController(ResourceController* controller) override;
+ bool OnUploadProgress(uint64 position, uint64 size) override;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL& url, bool* defer) override;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
+ void OnDataDownloaded(int bytes_downloaded) override;
// ResourceController implementation:
- virtual void Resume() OVERRIDE;
- virtual void Cancel() OVERRIDE;
- virtual void CancelAndIgnore() OVERRIDE;
- virtual void CancelWithError(int error_code) OVERRIDE;
+ void Resume() override;
+ void Cancel() override;
+ void CancelAndIgnore() override;
+ void CancelWithError(int error_code) override;
private:
scoped_ptr<ResourceHandler> next_handler_;
diff --git a/chromium/content/browser/loader/layered_resource_handler.cc b/chromium/content/browser/loader/layered_resource_handler.cc
index 1c65820f610..fa15b0de40f 100644
--- a/chromium/content/browser/loader/layered_resource_handler.cc
+++ b/chromium/content/browser/loader/layered_resource_handler.cc
@@ -35,11 +35,12 @@ bool LayeredResourceHandler::OnUploadProgress(uint64 position,
return next_handler_->OnUploadProgress(position, size);
}
-bool LayeredResourceHandler::OnRequestRedirected(const GURL& url,
- ResourceResponse* response,
- bool* defer) {
+bool LayeredResourceHandler::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) {
DCHECK(next_handler_.get());
- return next_handler_->OnRequestRedirected(url, response, defer);
+ return next_handler_->OnRequestRedirected(redirect_info, response, defer);
}
bool LayeredResourceHandler::OnResponseStarted(ResourceResponse* response,
diff --git a/chromium/content/browser/loader/layered_resource_handler.h b/chromium/content/browser/loader/layered_resource_handler.h
index dc6de2314dc..0c098f9a8d7 100644
--- a/chromium/content/browser/loader/layered_resource_handler.h
+++ b/chromium/content/browser/loader/layered_resource_handler.h
@@ -21,27 +21,25 @@ class CONTENT_EXPORT LayeredResourceHandler : public ResourceHandler {
public:
LayeredResourceHandler(net::URLRequest* request,
scoped_ptr<ResourceHandler> next_handler);
- virtual ~LayeredResourceHandler();
+ ~LayeredResourceHandler() override;
// ResourceHandler implementation:
- virtual void SetController(ResourceController* controller) OVERRIDE;
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
- virtual bool OnRequestRedirected(const GURL& url,
- ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
- virtual bool OnReadCompleted(int bytes_read,
- bool* defer) OVERRIDE;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE;
+ void SetController(ResourceController* controller) override;
+ bool OnUploadProgress(uint64 position, uint64 size) override;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL& url, bool* defer) override;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
+ void OnDataDownloaded(int bytes_downloaded) override;
scoped_ptr<ResourceHandler> next_handler_;
};
diff --git a/chromium/content/browser/loader/navigation_resource_handler.cc b/chromium/content/browser/loader/navigation_resource_handler.cc
new file mode 100644
index 00000000000..393b295776e
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_resource_handler.cc
@@ -0,0 +1,149 @@
+// 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/loader/navigation_resource_handler.h"
+
+#include "base/logging.h"
+#include "content/browser/devtools/devtools_netlog_observer.h"
+#include "content/browser/loader/navigation_url_loader_impl_core.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/browser/resource_context_impl.h"
+#include "content/browser/streams/stream.h"
+#include "content/browser/streams/stream_context.h"
+#include "content/public/browser/resource_controller.h"
+#include "content/public/browser/stream_handle.h"
+#include "content/public/common/resource_response.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request.h"
+
+namespace content {
+
+NavigationResourceHandler::NavigationResourceHandler(
+ net::URLRequest* request,
+ NavigationURLLoaderImplCore* core)
+ : ResourceHandler(request),
+ core_(core) {
+ core_->set_resource_handler(this);
+}
+
+NavigationResourceHandler::~NavigationResourceHandler() {
+ if (core_) {
+ core_->NotifyRequestFailed(net::ERR_ABORTED);
+ DetachFromCore();
+ }
+}
+
+void NavigationResourceHandler::Cancel() {
+ controller()->Cancel();
+ core_ = nullptr;
+}
+
+void NavigationResourceHandler::FollowRedirect() {
+ controller()->Resume();
+}
+
+void NavigationResourceHandler::SetController(ResourceController* controller) {
+ writer_.set_controller(controller);
+ ResourceHandler::SetController(controller);
+}
+
+bool NavigationResourceHandler::OnUploadProgress(uint64 position, uint64 size) {
+ return true;
+}
+
+bool NavigationResourceHandler::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) {
+ DCHECK(core_);
+
+ // TODO(davidben): Perform a CSP check here, and anything else that would have
+ // been done renderer-side.
+ DevToolsNetLogObserver::PopulateResponseInfo(request(), response);
+ core_->NotifyRequestRedirected(redirect_info, response);
+ *defer = true;
+ return true;
+}
+
+bool NavigationResourceHandler::OnResponseStarted(ResourceResponse* response,
+ bool* defer) {
+ DCHECK(core_);
+
+ ResourceRequestInfoImpl* info = GetRequestInfo();
+
+ // If the BufferedResourceHandler intercepted this request and converted it
+ // into a download, it will still call OnResponseStarted and immediately
+ // cancel. Ignore the call; OnReadCompleted will happen shortly.
+ //
+ // TODO(davidben): Move the dispatch out of BufferedResourceHandler. Perhaps
+ // all the way to the UI thread. Downloads, user certificates, etc., should be
+ // dispatched at the navigation layer.
+ if (info->IsDownload() || info->is_stream())
+ return true;
+
+ StreamContext* stream_context =
+ GetStreamContextForResourceContext(info->GetContext());
+ 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();
+ return true;
+}
+
+bool NavigationResourceHandler::OnWillStart(const GURL& url, bool* defer) {
+ return true;
+}
+
+bool NavigationResourceHandler::OnBeforeNetworkStart(const GURL& url,
+ bool* defer) {
+ return true;
+}
+
+bool NavigationResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) {
+ writer_.OnWillRead(buf, buf_size, min_size);
+ return true;
+}
+
+bool NavigationResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
+ writer_.OnReadCompleted(bytes_read, defer);
+ return true;
+}
+
+void NavigationResourceHandler::OnResponseCompleted(
+ const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) {
+ // If the request has already committed, close the stream and leave it as-is.
+ //
+ // TODO(davidben): The net error code should be passed through StreamWriter
+ // down to the stream's consumer. See https://crbug.com/426162.
+ if (writer_.stream()) {
+ writer_.Finalize();
+ return;
+ }
+
+ if (core_) {
+ DCHECK_NE(net::OK, status.error());
+ core_->NotifyRequestFailed(status.error());
+ DetachFromCore();
+ }
+}
+
+void NavigationResourceHandler::OnDataDownloaded(int bytes_downloaded) {
+ NOTREACHED();
+}
+
+void NavigationResourceHandler::DetachFromCore() {
+ DCHECK(core_);
+ core_->set_resource_handler(nullptr);
+ core_ = nullptr;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/loader/navigation_resource_handler.h b/chromium/content/browser/loader/navigation_resource_handler.h
new file mode 100644
index 00000000000..59090260de9
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_resource_handler.h
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_LOADER_NAVIGATION_RESOURCE_HANDLER_H_
+#define CONTENT_BROWSER_LOADER_NAVIGATION_RESOURCE_HANDLER_H_
+
+#include "base/macros.h"
+#include "content/browser/loader/resource_handler.h"
+#include "content/browser/loader/stream_writer.h"
+
+namespace content {
+
+class NavigationURLLoaderImplCore;
+
+// PlzNavigate: The leaf ResourceHandler used with NavigationURLLoaderImplCore.
+class NavigationResourceHandler : public ResourceHandler {
+ public:
+ NavigationResourceHandler(net::URLRequest* request,
+ NavigationURLLoaderImplCore* core);
+ ~NavigationResourceHandler() override;
+
+ // Called by the loader the cancel the request.
+ void Cancel();
+
+ // Called to the loader to resume a paused redirect.
+ void FollowRedirect();
+
+ // ResourceHandler implementation.
+ void SetController(ResourceController* controller) override;
+ bool OnUploadProgress(uint64 position, uint64 size) override;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL& url, bool* defer) override;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
+ void OnDataDownloaded(int bytes_downloaded) override;
+
+ private:
+ // Clears |core_| and its reference to the resource handler. After calling
+ // this, the lifetime of the request is no longer tied to |core_|.
+ void DetachFromCore();
+
+ NavigationURLLoaderImplCore* core_;
+ StreamWriter writer_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationResourceHandler);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_CERTIFICATE_RESOURCE_HANDLER_H_
diff --git a/chromium/content/browser/loader/navigation_url_loader.cc b/chromium/content/browser/loader/navigation_url_loader.cc
new file mode 100644
index 00000000000..e0e1e9e7735
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader.cc
@@ -0,0 +1,37 @@
+// 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/loader/navigation_url_loader.h"
+
+#include "content/browser/frame_host/navigation_request_info.h"
+#include "content/browser/loader/navigation_url_loader_factory.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
+
+namespace content {
+
+static NavigationURLLoaderFactory* g_factory = nullptr;
+
+scoped_ptr<NavigationURLLoader> NavigationURLLoader::Create(
+ BrowserContext* browser_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ ResourceRequestBody* request_body,
+ NavigationURLLoaderDelegate* delegate) {
+ if (g_factory) {
+ return g_factory->CreateLoader(browser_context, frame_tree_node_id,
+ common_params, request_info.Pass(),
+ request_body, delegate);
+ }
+ return scoped_ptr<NavigationURLLoader>(new NavigationURLLoaderImpl(
+ browser_context, frame_tree_node_id, common_params, request_info.Pass(),
+ request_body, delegate));
+}
+
+void NavigationURLLoader::SetFactoryForTesting(
+ NavigationURLLoaderFactory* factory) {
+ g_factory = factory;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/loader/navigation_url_loader.h b/chromium/content/browser/loader/navigation_url_loader.h
new file mode 100644
index 00000000000..7713e736610
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader.h
@@ -0,0 +1,62 @@
+// 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_LOADER_NAVIGATION_URL_LOADER_H_
+#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_H_
+
+#include "base/basictypes.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class BrowserContext;
+class NavigationURLLoaderDelegate;
+class NavigationURLLoaderFactory;
+class ResourceRequestBody;
+struct CommonNavigationParams;
+struct NavigationRequestInfo;
+
+// PlzNavigate: The navigation logic's UI thread entry point into the resource
+// loading stack. It exposes an interface to control the request prior to
+// receiving the response. If the NavigationURLLoader is destroyed before
+// OnResponseStarted is called, the request is aborted.
+class CONTENT_EXPORT NavigationURLLoader {
+ public:
+ // Creates a NavigationURLLoader. The caller is responsible for ensuring that
+ // |delegate| outlives the loader. |request_body| must not be accessed on the
+ // UI thread after this point.
+ //
+ // TODO(davidben): When navigation is disentangled from the loader, the
+ // 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(
+ BrowserContext* browser_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ ResourceRequestBody* request_body,
+ NavigationURLLoaderDelegate* delegate);
+
+ // For testing purposes; sets the factory for use in testing.
+ static void SetFactoryForTesting(NavigationURLLoaderFactory* factory);
+
+ virtual ~NavigationURLLoader() {}
+
+ // Called in response to OnRequestRedirected to continue processing the
+ // request.
+ virtual void FollowRedirect() = 0;
+
+ protected:
+ NavigationURLLoader() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NavigationURLLoader);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_H_
diff --git a/chromium/content/browser/loader/navigation_url_loader_delegate.h b/chromium/content/browser/loader/navigation_url_loader_delegate.h
new file mode 100644
index 00000000000..199f48a2a98
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader_delegate.h
@@ -0,0 +1,52 @@
+// 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_LOADER_NAVIGATION_URL_LOADER_DELEGATE_H_
+#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_DELEGATE_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+
+namespace net {
+struct RedirectInfo;
+}
+
+namespace content {
+
+class StreamHandle;
+struct ResourceResponse;
+
+// PlzNavigate: The delegate interface to NavigationURLLoader.
+class CONTENT_EXPORT NavigationURLLoaderDelegate {
+ public:
+ // Called when the request is redirected. Call FollowRedirect to continue
+ // processing the request.
+ virtual void OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ const scoped_refptr<ResourceResponse>& response) = 0;
+
+ // Called when the request receives its response. No further calls will be
+ // made to the delegate. The response body is returned as a stream in
+ // |body_stream|.
+ virtual void OnResponseStarted(
+ const scoped_refptr<ResourceResponse>& response,
+ scoped_ptr<StreamHandle> body_stream) = 0;
+
+ // Called if the request fails before receving a response. |net_error| is a
+ // network error code for the failure.
+ virtual void OnRequestFailed(int net_error) = 0;
+
+ protected:
+ NavigationURLLoaderDelegate() {}
+ virtual ~NavigationURLLoaderDelegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_DELEGATE_H_
diff --git a/chromium/content/browser/loader/navigation_url_loader_factory.h b/chromium/content/browser/loader/navigation_url_loader_factory.h
new file mode 100644
index 00000000000..ddb4fe1dc3d
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader_factory.h
@@ -0,0 +1,36 @@
+// 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_LOADER_NAVIGATION_URL_LOADER_FACTORY_H_
+#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/loader/navigation_url_loader.h"
+
+namespace content {
+
+// NavigationURLLoader::Create uses the currently registered factory to create
+// the loader. This is intended for testing.
+class NavigationURLLoaderFactory {
+ public:
+ virtual scoped_ptr<NavigationURLLoader> CreateLoader(
+ BrowserContext* browser_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ ResourceRequestBody* request_body,
+ NavigationURLLoaderDelegate* delegate) = 0;
+
+ protected:
+ NavigationURLLoaderFactory() {}
+ virtual ~NavigationURLLoaderFactory() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderFactory);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_FACTORY_H_
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl.cc b/chromium/content/browser/loader/navigation_url_loader_impl.cc
new file mode 100644
index 00000000000..b6dbed08685
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader_impl.cc
@@ -0,0 +1,76 @@
+// 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/loader/navigation_url_loader_impl.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "content/browser/frame_host/navigation_request_info.h"
+#include "content/browser/loader/navigation_url_loader_delegate.h"
+#include "content/browser/loader/navigation_url_loader_impl_core.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/stream_handle.h"
+
+namespace content {
+
+NavigationURLLoaderImpl::NavigationURLLoaderImpl(
+ BrowserContext* browser_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ ResourceRequestBody* request_body,
+ NavigationURLLoaderDelegate* delegate)
+ : delegate_(delegate),
+ weak_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ core_ = new NavigationURLLoaderImplCore(weak_factory_.GetWeakPtr());
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&NavigationURLLoaderImplCore::Start, base::Unretained(core_),
+ browser_context->GetResourceContext(), frame_tree_node_id,
+ common_params, base::Passed(&request_info),
+ make_scoped_refptr(request_body)));
+}
+
+NavigationURLLoaderImpl::~NavigationURLLoaderImpl() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, core_);
+ core_ = nullptr;
+}
+
+void NavigationURLLoaderImpl::FollowRedirect() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&NavigationURLLoaderImplCore::FollowRedirect,
+ base::Unretained(core_)));
+}
+
+void NavigationURLLoaderImpl::NotifyRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ const scoped_refptr<ResourceResponse>& response) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ delegate_->OnRequestRedirected(redirect_info, response);
+}
+
+void NavigationURLLoaderImpl::NotifyResponseStarted(
+ const scoped_refptr<ResourceResponse>& response,
+ scoped_ptr<StreamHandle> body) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ delegate_->OnResponseStarted(response, body.Pass());
+}
+
+void NavigationURLLoaderImpl::NotifyRequestFailed(int net_error) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ delegate_->OnRequestFailed(net_error);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl.h b/chromium/content/browser/loader/navigation_url_loader_impl.h
new file mode 100644
index 00000000000..ecfd2382e8e
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader_impl.h
@@ -0,0 +1,66 @@
+// 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_LOADER_NAVIGATION_URL_LOADER_IMPL_H_
+#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_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/navigation_url_loader.h"
+
+namespace net {
+struct RedirectInfo;
+}
+
+namespace content {
+
+class NavigationURLLoaderImplCore;
+class StreamHandle;
+struct ResourceResponse;
+
+class NavigationURLLoaderImpl : public NavigationURLLoader {
+ public:
+ // The caller is responsible for ensuring that |delegate| outlives the loader.
+ NavigationURLLoaderImpl(BrowserContext* browser_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ ResourceRequestBody* request_body,
+ NavigationURLLoaderDelegate* delegate);
+ ~NavigationURLLoaderImpl() override;
+
+ // Called in response to OnRequestRedirected to continue processing the
+ // request.
+ void FollowRedirect() override;
+
+ private:
+ friend class NavigationURLLoaderImplCore;
+
+ // Notifies the delegate of a redirect.
+ void NotifyRequestRedirected(const net::RedirectInfo& redirect_info,
+ const scoped_refptr<ResourceResponse>& response);
+
+ // Notifies the delegate that the response has started.
+ void NotifyResponseStarted(const scoped_refptr<ResourceResponse>& response,
+ scoped_ptr<StreamHandle> body);
+
+ // Notifies the delegate the request failed to return a response.
+ void NotifyRequestFailed(int net_error);
+
+ NavigationURLLoaderDelegate* delegate_;
+
+ // |core_| is deleted on the IO thread in a subsequent task when the
+ // NavigationURLLoaderImpl goes out of scope.
+ NavigationURLLoaderImplCore* core_;
+
+ base::WeakPtrFactory<NavigationURLLoaderImpl> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_H_
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl_core.cc b/chromium/content/browser/loader/navigation_url_loader_impl_core.cc
new file mode 100644
index 00000000000..48845e8aa0c
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader_impl_core.cc
@@ -0,0 +1,104 @@
+// 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/loader/navigation_url_loader_impl_core.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "content/browser/frame_host/navigation_request_info.h"
+#include "content/browser/loader/navigation_resource_handler.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/common/navigation_params.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/stream_handle.h"
+#include "content/public/common/resource_response.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/redirect_info.h"
+
+namespace content {
+
+NavigationURLLoaderImplCore::NavigationURLLoaderImplCore(
+ const base::WeakPtr<NavigationURLLoaderImpl>& loader)
+ : loader_(loader),
+ resource_handler_(nullptr) {
+ // This object is created on the UI thread but otherwise is accessed and
+ // deleted on the IO thread.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+NavigationURLLoaderImplCore::~NavigationURLLoaderImplCore() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (resource_handler_)
+ resource_handler_->Cancel();
+}
+
+void NavigationURLLoaderImplCore::Start(
+ ResourceContext* resource_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ ResourceRequestBody* request_body) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ResourceDispatcherHostImpl::Get()->BeginNavigationRequest(
+ resource_context, frame_tree_node_id,
+ common_params, *request_info, request_body,
+ this);
+}
+
+void NavigationURLLoaderImplCore::FollowRedirect() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (resource_handler_)
+ resource_handler_->FollowRedirect();
+}
+
+
+void NavigationURLLoaderImplCore::NotifyRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* response) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // Make a copy of the ResourceResponse before it is passed to another thread.
+ //
+ // TODO(davidben): This copy could be avoided if ResourceResponse weren't
+ // reference counted and the loader stack passed unique ownership of the
+ // response. https://crbug.com/416050
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&NavigationURLLoaderImpl::NotifyRequestRedirected, loader_,
+ redirect_info, response->DeepCopy()));
+}
+
+void NavigationURLLoaderImplCore::NotifyResponseStarted(
+ ResourceResponse* response,
+ scoped_ptr<StreamHandle> body) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // If, by the time the task reaches the UI thread, |loader_| has already been
+ // destroyed, NotifyResponseStarted will not run. |body| will be destructed
+ // and the request released at that point.
+
+ // Make a copy of the ResourceResponse before it is passed to another thread.
+ //
+ // TODO(davidben): This copy could be avoided if ResourceResponse weren't
+ // reference counted and the loader stack passed unique ownership of the
+ // response. https://crbug.com/416050
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&NavigationURLLoaderImpl::NotifyResponseStarted, loader_,
+ response->DeepCopy(), base::Passed(&body)));
+}
+
+void NavigationURLLoaderImplCore::NotifyRequestFailed(int net_error) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&NavigationURLLoaderImpl::NotifyRequestFailed, loader_,
+ net_error));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/loader/navigation_url_loader_impl_core.h b/chromium/content/browser/loader/navigation_url_loader_impl_core.h
new file mode 100644
index 00000000000..f31d3ccbdc3
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader_impl_core.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_LOADER_NAVIGATION_URL_LOADER_IMPL_CORE_H_
+#define CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_CORE_H_
+
+#include "base/basictypes.h"
+#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"
+
+namespace net {
+class URLRequest;
+struct RedirectInfo;
+}
+
+namespace content {
+
+class FrameTreeNode;
+class NavigationResourceHandler;
+class ResourceContext;
+class ResourceHandler;
+class ResourceRequestBody;
+class StreamHandle;
+struct ResourceResponse;
+
+// The IO-thread counterpart to the NavigationURLLoaderImpl. It lives on the IO
+// thread and is owned by the UI-thread NavigationURLLoaderImpl.
+// NavigationURLLoaderImplCore interacts with the ResourceDispatcherHost stack
+// and forwards signals back to the loader on the UI thread.
+class NavigationURLLoaderImplCore {
+ public:
+ // Creates a new NavigationURLLoaderImplCore that forwards signals back to
+ // |loader| on the UI thread.
+ explicit NavigationURLLoaderImplCore(
+ const base::WeakPtr<NavigationURLLoaderImpl>& loader);
+ ~NavigationURLLoaderImplCore();
+
+ // Starts the request.
+ void Start(ResourceContext* resource_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ scoped_ptr<NavigationRequestInfo> request_info,
+ ResourceRequestBody* request_body);
+
+ // Follows the current pending redirect.
+ void FollowRedirect();
+
+ void set_resource_handler(NavigationResourceHandler* resource_handler) {
+ resource_handler_ = resource_handler;
+ }
+
+ // Notifies |loader_| on the UI thread that the request was redirected.
+ void NotifyRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response);
+
+ // Notifies |loader_| on the UI thread that the response started.
+ void NotifyResponseStarted(ResourceResponse* response,
+ scoped_ptr<StreamHandle> body);
+
+ // Notifies |loader_| on the UI thread that the request failed.
+ void NotifyRequestFailed(int net_error);
+
+ private:
+ base::WeakPtr<NavigationURLLoaderImpl> loader_;
+ NavigationResourceHandler* resource_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderImplCore);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_NAVIGATION_URL_LOADER_IMPL_CORE_H_
diff --git a/chromium/content/browser/loader/navigation_url_loader_unittest.cc b/chromium/content/browser/loader/navigation_url_loader_unittest.cc
new file mode 100644
index 00000000000..e81cad218be
--- /dev/null
+++ b/chromium/content/browser/loader/navigation_url_loader_unittest.cc
@@ -0,0 +1,389 @@
+// 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 "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 "content/browser/frame_host/navigation_request_info.h"
+#include "content/browser/loader/navigation_url_loader_delegate.h"
+#include "content/browser/loader/navigation_url_loader_impl.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/streams/stream.h"
+#include "content/browser/streams/stream_context.h"
+#include "content/browser/streams/stream_registry.h"
+#include "content/browser/streams/stream_url_request_job.h"
+#include "content/common/navigation_params.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/browser/stream_handle.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/resource_response.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/redirect_info.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job_factory_impl.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 {
+
+class StreamProtocolHandler
+ : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+ StreamProtocolHandler(StreamRegistry* registry) : registry_(registry) {}
+
+ // net::URLRequestJobFactory::ProtocolHandler implementation.
+ net::URLRequestJob* MaybeCreateJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ scoped_refptr<Stream> stream = registry_->GetStream(request->url());
+ if (stream.get())
+ return new StreamURLRequestJob(request, network_delegate, stream);
+ return nullptr;
+ }
+
+ private:
+ StreamRegistry* registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(StreamProtocolHandler);
+};
+
+class TestNavigationURLLoaderDelegate : public NavigationURLLoaderDelegate {
+ public:
+ TestNavigationURLLoaderDelegate()
+ : net_error_(0) {
+ }
+
+ const net::RedirectInfo& redirect_info() const { return redirect_info_; }
+ ResourceResponse* redirect_response() const {
+ return redirect_response_.get();
+ }
+ ResourceResponse* response() const { return response_.get(); }
+ StreamHandle* body() const { return body_.get(); }
+ int net_error() const { return net_error_; }
+
+ void WaitForRequestRedirected() {
+ request_redirected_.reset(new base::RunLoop);
+ request_redirected_->Run();
+ request_redirected_.reset();
+ }
+
+ void WaitForResponseStarted() {
+ response_started_.reset(new base::RunLoop);
+ response_started_->Run();
+ response_started_.reset();
+ }
+
+ void WaitForRequestFailed() {
+ request_failed_.reset(new base::RunLoop);
+ request_failed_->Run();
+ request_failed_.reset();
+ }
+
+ void ReleaseBody() {
+ body_.reset();
+ }
+
+ // NavigationURLLoaderDelegate implementation.
+ void OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ const scoped_refptr<ResourceResponse>& response) override {
+ redirect_info_ = redirect_info;
+ redirect_response_ = response;
+ ASSERT_TRUE(request_redirected_);
+ request_redirected_->Quit();
+ }
+
+ void OnResponseStarted(const scoped_refptr<ResourceResponse>& response,
+ scoped_ptr<StreamHandle> body) override {
+ response_ = response;
+ body_ = body.Pass();
+ ASSERT_TRUE(response_started_);
+ response_started_->Quit();
+ }
+
+ void OnRequestFailed(int net_error) override {
+ net_error_ = net_error;
+ ASSERT_TRUE(request_failed_);
+ request_failed_->Quit();
+ }
+
+ private:
+ net::RedirectInfo redirect_info_;
+ scoped_refptr<ResourceResponse> redirect_response_;
+ scoped_refptr<ResourceResponse> response_;
+ scoped_ptr<StreamHandle> body_;
+ int net_error_;
+
+ scoped_ptr<base::RunLoop> request_redirected_;
+ scoped_ptr<base::RunLoop> response_started_;
+ scoped_ptr<base::RunLoop> request_failed_;
+};
+
+class RequestBlockingResourceDispatcherHostDelegate
+ : public ResourceDispatcherHostDelegate {
+ public:
+ // ResourceDispatcherHostDelegate implementation:
+ bool ShouldBeginRequest(const std::string& method,
+ const GURL& url,
+ ResourceType resource_type,
+ ResourceContext* resource_context) override {
+ return false;
+ }
+};
+
+} // namespace
+
+class NavigationURLLoaderTest : public testing::Test {
+ public:
+ NavigationURLLoaderTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ browser_context_(new TestBrowserContext) {
+ BrowserContext::EnsureResourceContextInitialized(browser_context_.get());
+ base::RunLoop().RunUntilIdle();
+ net::URLRequestContext* request_context =
+ browser_context_->GetResourceContext()->GetRequestContext();
+ // Attach URLRequestTestJob and make streams work.
+ job_factory_.SetProtocolHandler(
+ "test", net::URLRequestTestJob::CreateProtocolHandler());
+ job_factory_.SetProtocolHandler(
+ "blob", new StreamProtocolHandler(
+ StreamContext::GetFor(browser_context_.get())->registry()));
+ request_context->set_job_factory(&job_factory_);
+
+ // NavigationURLLoader is only used for browser-side navigations.
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableBrowserSideNavigation);
+ }
+
+ scoped_ptr<NavigationURLLoader> MakeTestLoader(
+ const GURL& url,
+ NavigationURLLoaderDelegate* delegate) {
+ FrameHostMsg_BeginNavigation_Params begin_params;
+ CommonNavigationParams common_params;
+ begin_params.method = "GET";
+ common_params.url = url;
+ scoped_ptr<NavigationRequestInfo> request_info(
+ new NavigationRequestInfo(begin_params));
+ request_info->first_party_for_cookies = url;
+ request_info->is_main_frame = true;
+
+ return NavigationURLLoader::Create(
+ browser_context_.get(), 0,
+ common_params, request_info.Pass(), nullptr, delegate);
+ }
+
+ // Helper function for fetching the body of a URL to a string.
+ std::string FetchURL(const GURL& url) {
+ net::TestDelegate delegate;
+ net::URLRequestContext* request_context =
+ browser_context_->GetResourceContext()->GetRequestContext();
+ scoped_ptr<net::URLRequest> request(request_context->CreateRequest(
+ url, net::DEFAULT_PRIORITY, &delegate, nullptr));
+ request->Start();
+ base::RunLoop().Run();
+
+ EXPECT_TRUE(request->status().is_success());
+ EXPECT_EQ(200, request->response_headers()->response_code());
+ return delegate.data_received();
+ }
+
+ protected:
+ TestBrowserThreadBundle thread_bundle_;
+ net::URLRequestJobFactoryImpl job_factory_;
+ scoped_ptr<TestBrowserContext> browser_context_;
+ ResourceDispatcherHostImpl host_;
+};
+
+// Tests that a basic request works.
+TEST_F(NavigationURLLoaderTest, Basic) {
+ TestNavigationURLLoaderDelegate delegate;
+ scoped_ptr<NavigationURLLoader> loader =
+ MakeTestLoader(net::URLRequestTestJob::test_url_1(), &delegate);
+
+ // Wait for the response to come back.
+ delegate.WaitForResponseStarted();
+
+ // Check the response is correct.
+ EXPECT_EQ("text/html", delegate.response()->head.mime_type);
+ EXPECT_EQ(200, delegate.response()->head.headers->response_code());
+
+ // Check the body is correct.
+ EXPECT_EQ(net::URLRequestTestJob::test_data_1(),
+ FetchURL(delegate.body()->GetURL()));
+}
+
+// Tests that request failures are propagated correctly.
+TEST_F(NavigationURLLoaderTest, RequestFailed) {
+ TestNavigationURLLoaderDelegate delegate;
+ scoped_ptr<NavigationURLLoader> loader =
+ MakeTestLoader(GURL("bogus:bogus"), &delegate);
+
+ // Wait for the request to fail as expected.
+ delegate.WaitForRequestFailed();
+ EXPECT_EQ(net::ERR_UNKNOWN_URL_SCHEME, delegate.net_error());
+}
+
+// Test that redirects are sent to the delegate.
+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);
+
+ // Wait for the request to redirect.
+ delegate.WaitForRequestRedirected();
+ EXPECT_EQ(net::URLRequestTestJob::test_url_2(),
+ delegate.redirect_info().new_url);
+ EXPECT_EQ("GET", delegate.redirect_info().new_method);
+ EXPECT_EQ(net::URLRequestTestJob::test_url_2(),
+ delegate.redirect_info().new_first_party_for_cookies);
+ EXPECT_EQ(302, delegate.redirect_response()->head.headers->response_code());
+
+ // Wait for the response to complete.
+ loader->FollowRedirect();
+ delegate.WaitForResponseStarted();
+
+ // Check the response is correct.
+ EXPECT_EQ("text/html", delegate.response()->head.mime_type);
+ EXPECT_EQ(200, delegate.response()->head.headers->response_code());
+
+ // Release the body and check it is correct.
+ EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
+ EXPECT_EQ(net::URLRequestTestJob::test_data_2(),
+ FetchURL(delegate.body()->GetURL()));
+}
+
+// Tests that the destroying the loader cancels the request.
+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);
+
+ // Wait for the request to redirect.
+ delegate.WaitForRequestRedirected();
+
+ // Destroy the loader and verify that URLRequestTestJob no longer has anything
+ // paused.
+ loader.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(net::URLRequestTestJob::ProcessOnePendingMessage());
+}
+
+// Test that the delegate is not called if OnResponseStarted and destroying the
+// loader race.
+TEST_F(NavigationURLLoaderTest, CancelResponseRace) {
+ TestNavigationURLLoaderDelegate delegate;
+ scoped_ptr<NavigationURLLoader> loader =
+ MakeTestLoader(net::URLRequestTestJob::test_url_redirect_to_url_2(),
+ &delegate);
+
+ // Wait for the request to redirect.
+ delegate.WaitForRequestRedirected();
+
+ // In the same event loop iteration, follow the redirect (allowing the
+ // response to go through) and destroy the loader.
+ loader->FollowRedirect();
+ loader.reset();
+
+ // Verify the URLRequestTestJob no longer has anything paused and that no
+ // response body was received.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(net::URLRequestTestJob::ProcessOnePendingMessage());
+ EXPECT_FALSE(delegate.body());
+}
+
+// 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);
+
+ // Wait for the request to redirect.
+ delegate.WaitForRequestRedirected();
+
+ // Cancel all requests.
+ host_.CancelRequestsForContext(browser_context_->GetResourceContext());
+
+ // Wait for the request to now be aborted.
+ delegate.WaitForRequestFailed();
+ EXPECT_EQ(net::ERR_ABORTED, delegate.net_error());
+}
+
+// Tests that, if the request is blocked by the ResourceDispatcherHostDelegate,
+// the caller is informed appropriately.
+TEST_F(NavigationURLLoaderTest, RequestBlocked) {
+ RequestBlockingResourceDispatcherHostDelegate rdh_delegate;
+ host_.SetDelegate(&rdh_delegate);
+
+ TestNavigationURLLoaderDelegate delegate;
+ scoped_ptr<NavigationURLLoader> loader =
+ MakeTestLoader(net::URLRequestTestJob::test_url_1(), &delegate);
+
+ // Wait for the request to fail as expected.
+ delegate.WaitForRequestFailed();
+ EXPECT_EQ(net::ERR_ABORTED, delegate.net_error());
+
+ host_.SetDelegate(nullptr);
+}
+
+// Tests that ownership leaves the loader once the response is received.
+TEST_F(NavigationURLLoaderTest, LoaderDetached) {
+ // Fake a top-level request to a URL whose body does not load immediately.
+ TestNavigationURLLoaderDelegate delegate;
+ scoped_ptr<NavigationURLLoader> loader =
+ MakeTestLoader(net::URLRequestTestJob::test_url_2(), &delegate);
+
+ // Wait for the response to come back.
+ delegate.WaitForResponseStarted();
+
+ // Check the response is correct.
+ EXPECT_EQ("text/html", delegate.response()->head.mime_type);
+ EXPECT_EQ(200, delegate.response()->head.headers->response_code());
+
+ // Destroy the loader.
+ loader.reset();
+ base::RunLoop().RunUntilIdle();
+
+ // Check the body can still be fetched through the StreamHandle.
+ EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
+ EXPECT_EQ(net::URLRequestTestJob::test_data_2(),
+ FetchURL(delegate.body()->GetURL()));
+}
+
+// Tests that the request is owned by the body StreamHandle.
+TEST_F(NavigationURLLoaderTest, OwnedByHandle) {
+ // Fake a top-level request to a URL whose body does not load immediately.
+ TestNavigationURLLoaderDelegate delegate;
+ scoped_ptr<NavigationURLLoader> loader =
+ MakeTestLoader(net::URLRequestTestJob::test_url_2(), &delegate);
+
+ // Wait for the response to come back.
+ delegate.WaitForResponseStarted();
+
+ // Release the body.
+ delegate.ReleaseBody();
+ base::RunLoop().RunUntilIdle();
+
+ // Verify that URLRequestTestJob no longer has anything paused.
+ EXPECT_FALSE(net::URLRequestTestJob::ProcessOnePendingMessage());
+}
+
+} // namespace content
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 2a4f9b39c5a..a09293faf3b 100644
--- a/chromium/content/browser/loader/power_save_block_resource_throttle.h
+++ b/chromium/content/browser/loader/power_save_block_resource_throttle.h
@@ -19,12 +19,12 @@ class PowerSaveBlocker;
class PowerSaveBlockResourceThrottle : public ResourceThrottle {
public:
PowerSaveBlockResourceThrottle();
- virtual ~PowerSaveBlockResourceThrottle();
+ ~PowerSaveBlockResourceThrottle() override;
// ResourceThrottle overrides:
- virtual void WillStartRequest(bool* defer) OVERRIDE;
- virtual void WillProcessResponse(bool* defer) OVERRIDE;
- virtual const char* GetNameForLogging() const OVERRIDE;
+ void WillStartRequest(bool* defer) override;
+ void WillProcessResponse(bool* defer) override;
+ const char* GetNameForLogging() const override;
private:
void ActivatePowerSaveBlocker();
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 caf36cddf39..00e63928076 100644
--- a/chromium/content/browser/loader/redirect_to_file_resource_handler.cc
+++ b/chromium/content/browser/loader/redirect_to_file_resource_handler.cc
@@ -15,9 +15,9 @@
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
#include "net/base/net_errors.h"
-#include "webkit/common/blob/shareable_file_reference.h"
+#include "storage/common/blob/shareable_file_reference.h"
-using webkit_blob::ShareableFileReference;
+using storage::ShareableFileReference;
namespace {
@@ -38,7 +38,7 @@ class DependentIOBuffer : public net::WrappedIOBuffer {
backing_(backing) {
}
private:
- virtual ~DependentIOBuffer() {}
+ ~DependentIOBuffer() override {}
scoped_refptr<net::IOBuffer> backing_;
};
@@ -121,7 +121,7 @@ class RedirectToFileResourceHandler::Writer {
// We create a ShareableFileReference that's deletable for the temp file
// created as a result of the download.
- scoped_refptr<webkit_blob::ShareableFileReference> deletable_file_;
+ scoped_refptr<storage::ShareableFileReference> deletable_file_;
DISALLOW_COPY_AND_ASSIGN(Writer);
};
@@ -157,11 +157,8 @@ void RedirectToFileResourceHandler::
bool RedirectToFileResourceHandler::OnResponseStarted(
ResourceResponse* response,
bool* defer) {
- if (response->head.error_code == net::OK ||
- response->head.error_code == net::ERR_IO_PENDING) {
- DCHECK(writer_);
- response->head.download_file_path = writer_->path();
- }
+ DCHECK(writer_);
+ response->head.download_file_path = writer_->path();
return next_handler_->OnResponseStarted(response, defer);
}
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 07763f5c16a..1778921e370 100644
--- a/chromium/content/browser/loader/redirect_to_file_resource_handler.h
+++ b/chromium/content/browser/loader/redirect_to_file_resource_handler.h
@@ -25,7 +25,7 @@ class FileStream;
class GrowableIOBuffer;
}
-namespace webkit_blob {
+namespace storage {
class ShareableFileReference;
}
@@ -46,7 +46,7 @@ class CONTENT_EXPORT RedirectToFileResourceHandler
// |next_handler|.
RedirectToFileResourceHandler(scoped_ptr<ResourceHandler> next_handler,
net::URLRequest* request);
- virtual ~RedirectToFileResourceHandler();
+ ~RedirectToFileResourceHandler() override;
// Replace the CreateTemporaryFileStream implementation with a mocked one for
// testing purposes. The function should create a net::FileStream and a
@@ -56,22 +56,20 @@ class CONTENT_EXPORT RedirectToFileResourceHandler
const CreateTemporaryFileStreamFunction& create_temporary_file_stream);
// LayeredResourceHandler implementation:
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL& url, bool* defer) override;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
private:
- void DidCreateTemporaryFile(
- base::File::Error error_code,
- scoped_ptr<net::FileStream> file_stream,
- webkit_blob::ShareableFileReference* deletable_file);
+ void DidCreateTemporaryFile(base::File::Error error_code,
+ scoped_ptr<net::FileStream> file_stream,
+ storage::ShareableFileReference* deletable_file);
// Called by RedirectToFileResourceHandler::Writer.
void DidWriteToFile(int result);
@@ -94,7 +92,7 @@ class CONTENT_EXPORT RedirectToFileResourceHandler
int write_cursor_;
// Helper writer object which maintains references to the net::FileStream and
- // webkit_blob::ShareableFileReference. This is maintained separately so that,
+ // storage::ShareableFileReference. This is maintained separately so that,
// on Windows, the temporary file isn't deleted until after it is closed.
class Writer;
Writer* writer_;
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc b/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
index 0858bd67e03..8673c07b086 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_browsertest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_browsertest.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/memory/ref_counted.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -18,12 +19,12 @@
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_content_browser_client.h"
#include "content/shell/browser/shell_network_delegate.h"
-#include "content/test/net/url_request_failed_job.h"
-#include "content/test/net/url_request_mock_http_job.h"
#include "net/base/net_errors.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"
+#include "net/test/url_request/url_request_failed_job.h"
+#include "net/test/url_request/url_request_mock_http_job.h"
using base::ASCIIToUTF16;
@@ -35,25 +36,28 @@ class ResourceDispatcherHostBrowserTest : public ContentBrowserTest,
ResourceDispatcherHostBrowserTest() : got_downloads_(false) {}
protected:
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
base::FilePath path = GetTestFilePath("", "");
BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&URLRequestMockHTTPJob::AddUrlHandler, path));
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &net::URLRequestMockHTTPJob::AddUrlHandler,
+ path,
+ make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&URLRequestFailedJob::AddUrlHandler));
+ base::Bind(&net::URLRequestFailedJob::AddUrlHandler));
}
- virtual void OnDownloadCreated(
- DownloadManager* manager,
- DownloadItem* item) OVERRIDE {
+ void OnDownloadCreated(DownloadManager* manager,
+ DownloadItem* item) override {
if (!got_downloads_)
got_downloads_ = !!manager->InProgressCount();
}
GURL GetMockURL(const std::string& file) {
- return URLRequestMockHTTPJob::GetMockUrl(
+ return net::URLRequestMockHTTPJob::GetMockUrl(
base::FilePath().AppendASCII(file));
}
@@ -219,9 +223,10 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
ASSERT_FALSE(got_downloads());
}
+// Flaky everywhere. http://crbug.com/130404
// Tests that onunload is run for cross-site requests. (Bug 1114994)
IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
- CrossSiteOnunloadCookie) {
+ DISABLED_CrossSiteOnunloadCookie) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url = embedded_test_server()->GetURL("/onunload_cookie.html");
@@ -266,7 +271,7 @@ scoped_ptr<net::test_server::HttpResponse> NoContentResponseHandler(
scoped_ptr<net::test_server::BasicHttpResponse> http_response(
new net::test_server::BasicHttpResponse);
http_response->set_code(net::HTTP_NO_CONTENT);
- return http_response.PassAs<net::test_server::HttpResponse>();
+ return http_response.Pass();
}
} // namespace
@@ -333,12 +338,12 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
CheckTitleTest(url, "Title Of Awesomeness");
}
+// Flaky everywhere. http://crbug.com/130404
// Tests that a cross-site navigation to an error page (resulting in the link
// doctor page) still runs the onunload handler and can support navigations
// away from the link doctor page. (Bug 1235537)
-// Flaky: http://crbug.com/100823
IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
- CrossSiteNavigationErrorPage) {
+ DISABLED_CrossSiteNavigationErrorPage) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/onunload_cookie.html"));
@@ -348,7 +353,7 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
// TODO(creis): If this causes crashes or hangs, it might be for the same
// reason as ErrorPageTest::DNSError. See bug 1199491 and
// http://crbug.com/22877.
- GURL failed_url = URLRequestFailedJob::GetMockHttpUrl(
+ GURL failed_url = net::URLRequestFailedJob::GetMockHttpUrl(
net::ERR_NAME_NOT_RESOLVED);
NavigateToURL(shell(), failed_url);
@@ -393,7 +398,7 @@ IN_PROC_BROWSER_TEST_F(ResourceDispatcherHostBrowserTest,
// TODO(creis): If this causes crashes or hangs, it might be for the same
// reason as ErrorPageTest::DNSError. See bug 1199491 and
// http://crbug.com/22877.
- GURL failed_url = URLRequestFailedJob::GetMockHttpUrl(
+ GURL failed_url = net::URLRequestFailedJob::GetMockHttpUrl(
net::ERR_NAME_NOT_RESOLVED);
NavigateToURL(shell(), failed_url);
@@ -445,7 +450,7 @@ scoped_ptr<net::test_server::HttpResponse> HandleRedirectRequest(
http_response->set_code(net::HTTP_FOUND);
http_response->AddCustomHeader(
"Location", request.relative_url.substr(request_path.length()));
- return http_response.PassAs<net::test_server::HttpResponse>();
+ return http_response.Pass();
}
} // namespace
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
index 0e5abc6653c..26ecf1d8dbb 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -27,15 +27,18 @@
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/cert_store_impl.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/cross_site_request_manager.h"
#include "content/browser/download/download_resource_handler.h"
#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/navigation_request_info.h"
+#include "content/browser/frame_host/navigator.h"
#include "content/browser/loader/async_resource_handler.h"
#include "content/browser/loader/buffered_resource_handler.h"
#include "content/browser/loader/cross_site_resource_handler.h"
#include "content/browser/loader/detachable_resource_handler.h"
+#include "content/browser/loader/navigation_resource_handler.h"
+#include "content/browser/loader/navigation_url_loader_impl_core.h"
#include "content/browser/loader/power_save_block_resource_throttle.h"
#include "content/browser/loader/redirect_to_file_resource_handler.h"
#include "content/browser/loader/resource_message_filter.h"
@@ -44,7 +47,6 @@
#include "content/browser/loader/sync_resource_handler.h"
#include "content/browser/loader/throttling_resource_handler.h"
#include "content/browser/loader/upload_data_stream_builder.h"
-#include "content/browser/plugin_service_impl.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/resource_context_impl.h"
@@ -52,10 +54,10 @@
#include "content/browser/streams/stream.h"
#include "content/browser/streams/stream_context.h"
#include "content/browser/streams/stream_registry.h"
-#include "content/browser/worker_host/worker_service_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/appcache_interfaces.h"
+#include "content/common/navigation_params.h"
#include "content/common/resource_messages.h"
-#include "content/common/resource_request_body.h"
#include "content/common/ssl_status_serialization.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
@@ -67,6 +69,7 @@
#include "content/public/browser/resource_request_details.h"
#include "content/public/browser/resource_throttle.h"
#include "content/public/browser/stream_handle.h"
+#include "content/public/browser/stream_info.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/process_type.h"
@@ -87,20 +90,23 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job_factory.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_url_request_job_factory.h"
+#include "storage/browser/fileapi/file_permission_policy.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/common/blob/blob_data.h"
+#include "storage/common/blob/shareable_file_reference.h"
#include "url/url_constants.h"
-#include "webkit/common/blob/blob_data.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/blob/blob_url_request_job_factory.h"
-#include "webkit/browser/fileapi/file_permission_policy.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/common/appcache/appcache_interfaces.h"
-#include "webkit/common/blob/shareable_file_reference.h"
+
+#if defined(ENABLE_PLUGINS)
+#include "content/browser/plugin_service_impl.h"
+#endif
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
-using webkit_blob::ShareableFileReference;
+using storage::ShareableFileReference;
// ----------------------------------------------------------------------------
@@ -137,10 +143,64 @@ const double kMaxRequestsPerProcessRatio = 0.45;
// same resource (see bugs 46104 and 31014).
const int kDefaultDetachableCancelDelayMs = 30000;
-bool IsDetachableResourceType(ResourceType::Type type) {
+enum SHA1HistogramTypes {
+ // SHA-1 is not present in the certificate chain.
+ SHA1_NOT_PRESENT = 0,
+ // SHA-1 is present in the certificate chain, and the leaf expires on or
+ // after January 1, 2017.
+ SHA1_EXPIRES_AFTER_JANUARY_2017 = 1,
+ // SHA-1 is present in the certificate chain, and the leaf expires on or
+ // after June 1, 2016.
+ SHA1_EXPIRES_AFTER_JUNE_2016 = 2,
+ // SHA-1 is present in the certificate chain, and the leaf expires on or
+ // after January 1, 2016.
+ SHA1_EXPIRES_AFTER_JANUARY_2016 = 3,
+ // SHA-1 is present in the certificate chain, but the leaf expires before
+ // January 1, 2016
+ SHA1_PRESENT = 4,
+ // Always keep this at the end.
+ SHA1_HISTOGRAM_TYPES_MAX,
+};
+
+void RecordCertificateHistograms(const net::SSLInfo& ssl_info,
+ ResourceType resource_type) {
+ // The internal representation of the dates for UI treatment of SHA-1.
+ // See http://crbug.com/401365 for details
+ static const int64_t kJanuary2017 = INT64_C(13127702400000000);
+ static const int64_t kJune2016 = INT64_C(13109213000000000);
+ static const int64_t kJanuary2016 = INT64_C(13096080000000000);
+
+ SHA1HistogramTypes sha1_histogram = SHA1_NOT_PRESENT;
+ if (ssl_info.cert_status & net::CERT_STATUS_SHA1_SIGNATURE_PRESENT) {
+ DCHECK(ssl_info.cert.get());
+ if (ssl_info.cert->valid_expiry() >=
+ base::Time::FromInternalValue(kJanuary2017)) {
+ sha1_histogram = SHA1_EXPIRES_AFTER_JANUARY_2017;
+ } else if (ssl_info.cert->valid_expiry() >=
+ base::Time::FromInternalValue(kJune2016)) {
+ sha1_histogram = SHA1_EXPIRES_AFTER_JUNE_2016;
+ } else if (ssl_info.cert->valid_expiry() >=
+ base::Time::FromInternalValue(kJanuary2016)) {
+ sha1_histogram = SHA1_EXPIRES_AFTER_JANUARY_2016;
+ } else {
+ sha1_histogram = SHA1_PRESENT;
+ }
+ }
+ if (resource_type == RESOURCE_TYPE_MAIN_FRAME) {
+ UMA_HISTOGRAM_ENUMERATION("Net.Certificate.SHA1.MainFrame",
+ sha1_histogram,
+ SHA1_HISTOGRAM_TYPES_MAX);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Net.Certificate.SHA1.Subresource",
+ sha1_histogram,
+ SHA1_HISTOGRAM_TYPES_MAX);
+ }
+}
+
+bool IsDetachableResourceType(ResourceType type) {
switch (type) {
- case ResourceType::PREFETCH:
- case ResourceType::PING:
+ case RESOURCE_TYPE_PREFETCH:
+ case RESOURCE_TYPE_PING:
return true;
default:
return false;
@@ -172,7 +232,8 @@ void AbortRequestBeforeItStarts(ResourceMessageFilter* filter,
void SetReferrerForRequest(net::URLRequest* request, const Referrer& referrer) {
if (!referrer.url.is_valid() ||
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoReferrers)) {
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kNoReferrers)) {
request->SetReferrer(std::string());
} else {
request->SetReferrer(referrer.url.spec());
@@ -201,7 +262,7 @@ void SetReferrerForRequest(net::URLRequest* request, const Referrer& referrer) {
bool ShouldServiceRequest(int process_type,
int child_id,
const ResourceHostMsg_Request& request_data,
- fileapi::FileSystemContext* file_system_context) {
+ storage::FileSystemContext* file_system_context) {
if (process_type == PROCESS_TYPE_PLUGIN)
return true;
@@ -228,7 +289,7 @@ bool ShouldServiceRequest(int process_type,
return false;
}
if (iter->type() == ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM) {
- fileapi::FileSystemURL url =
+ storage::FileSystemURL url =
file_system_context->CrackURL(iter->filesystem_url());
if (!policy->CanReadFileSystemFile(child_id, url)) {
NOTREACHED() << "Denied unauthorized upload of "
@@ -248,16 +309,6 @@ void RemoveDownloadFileFromChildSecurityPolicy(int child_id,
child_id, path);
}
-#if defined(OS_WIN)
-#pragma warning(disable: 4748)
-#pragma optimize("", off)
-#endif
-
-#if defined(OS_WIN)
-#pragma optimize("", on)
-#pragma warning(default: 4748)
-#endif
-
DownloadInterruptReason CallbackAndReturn(
const DownloadUrlParameters::OnStartedCallback& started_cb,
DownloadInterruptReason interrupt_reason) {
@@ -310,11 +361,49 @@ bool IsValidatedSCT(
return sct_status.status == net::ct::SCT_STATUS_OK;
}
-webkit_blob::BlobStorageContext* GetBlobStorageContext(
- ResourceMessageFilter* filter) {
- if (!filter->blob_storage_context())
+storage::BlobStorageContext* GetBlobStorageContext(
+ ChromeBlobStorageContext* blob_storage_context) {
+ if (!blob_storage_context)
return NULL;
- return filter->blob_storage_context()->context();
+ return blob_storage_context->context();
+}
+
+void AttachRequestBodyBlobDataHandles(
+ ResourceRequestBody* body,
+ storage::BlobStorageContext* blob_context) {
+ DCHECK(blob_context);
+ for (size_t i = 0; i < body->elements()->size(); ++i) {
+ const ResourceRequestBody::Element& element = (*body->elements())[i];
+ if (element.type() != ResourceRequestBody::Element::TYPE_BLOB)
+ continue;
+ scoped_ptr<storage::BlobDataHandle> handle =
+ blob_context->GetBlobDataFromUUID(element.blob_uuid());
+ DCHECK(handle);
+ if (!handle)
+ continue;
+ // Ensure the blob and any attached shareable files survive until
+ // upload completion. The |body| takes ownership of |handle|.
+ const void* key = handle.get();
+ body->SetUserData(key, handle.release());
+ }
+}
+
+// PlzNavigate
+// This method is called in the UI thread to send the timestamp of a resource
+// request to the respective Navigator (for an UMA histogram).
+void LogResourceRequestTimeOnUI(
+ base::TimeTicks timestamp,
+ int render_process_id,
+ int render_frame_id,
+ const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ RenderFrameHostImpl* host =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
+ if (host != NULL) {
+ DCHECK(host->frame_tree_node()->IsMainFrame());
+ host->frame_tree_node()->navigator()->LogResourceRequestTime(
+ timestamp, url);
+ }
}
} // namespace
@@ -387,6 +476,17 @@ void ResourceDispatcherHostImpl::RemoveResourceContext(
active_resource_contexts_.erase(context);
}
+void ResourceDispatcherHostImpl::ResumeResponseDeferredAtStart(
+ const GlobalRequestID& id) {
+ ResourceLoader* loader = GetLoader(id);
+ if (loader) {
+ // The response we were meant to resume could have already been canceled.
+ ResourceRequestInfoImpl* info = loader->GetRequestInfo();
+ if (info->cross_site_handler())
+ info->cross_site_handler()->ResumeResponseDeferredAtStart(id.request_id);
+ }
+}
+
void ResourceDispatcherHostImpl::CancelRequestsForContext(
ResourceContext* context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -398,7 +498,7 @@ 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<linked_ptr<ResourceLoader>> LoaderList;
LoaderList loaders_to_cancel;
for (LoaderMap::iterator i = pending_loaders_.begin();
@@ -444,15 +544,16 @@ void ResourceDispatcherHostImpl::CancelRequestsForContext(
for (LoaderList::iterator i = loaders_to_cancel.begin();
i != loaders_to_cancel.end(); ++i) {
// There is no strict requirement that this be the case, but currently
- // downloads, streams, detachable requests, and transferred 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.
+ // 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());
}
#endif
@@ -517,6 +618,15 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
}
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.
+ //
+ // TODO(davidben): Is this correct? If this came from a
+ // ViewHostMsg_DownloadUrl in a frame, should it have first-party URL set
+ // appropriately?
+ request->set_first_party_url_policy(
+ net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
+
// Check if the renderer is permitted to request the requested URL.
if (!ChildProcessSecurityPolicyImpl::GetInstance()->
CanRequestURL(child_id, url)) {
@@ -543,7 +653,7 @@ DownloadInterruptReason ResourceDispatcherHostImpl::BeginDownload(
if (request->url().SchemeIs(url::kBlobScheme)) {
ChromeBlobStorageContext* blob_context =
GetChromeBlobStorageContextForResourceContext(context);
- webkit_blob::BlobProtocolHandler::SetRequestedBlobDataHandle(
+ storage::BlobProtocolHandler::SetRequestedBlobDataHandle(
request.get(),
blob_context->context()->GetBlobDataFromPublicURL(request->url()));
}
@@ -631,23 +741,19 @@ ResourceDispatcherHostImpl::MaybeInterceptAsStream(net::URLRequest* request,
origin));
info->set_is_stream(true);
- delegate_->OnStreamCreated(
- request,
- handler->stream()->CreateHandle(
- request->url(),
- mime_type,
- response->head.headers));
- return handler.PassAs<ResourceHandler>();
-}
-
-void ResourceDispatcherHostImpl::ClearSSLClientAuthHandlerForRequest(
- net::URLRequest* request) {
- ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request);
- if (info) {
- ResourceLoader* loader = GetLoader(info->GetGlobalRequestID());
- if (loader)
- loader->ClearSSLClientAuthHandler();
+ scoped_ptr<StreamInfo> stream_info(new StreamInfo);
+ stream_info->handle = handler->stream()->CreateHandle();
+ stream_info->original_url = request->url();
+ stream_info->mime_type = mime_type;
+ // Make a copy of the response headers so it is safe to pass across threads;
+ // the old handler (AsyncResourceHandler) may modify it in parallel via the
+ // ResourceDispatcherHostDelegate.
+ if (response->head.headers.get()) {
+ stream_info->response_headers =
+ new net::HttpResponseHeaders(response->head.headers->raw_headers());
}
+ delegate_->OnStreamCreated(request, stream_info.Pass());
+ return handler.Pass();
}
ResourceDispatcherHostLoginDelegate*
@@ -667,7 +773,7 @@ bool ResourceDispatcherHostImpl::HandleExternalProtocol(ResourceLoader* loader,
ResourceRequestInfoImpl* info = loader->GetRequestInfo();
- if (!ResourceType::IsFrame(info->GetResourceType()))
+ if (!IsResourceTypeFrame(info->GetResourceType()))
return false;
const net::URLRequestJobFactory* job_factory =
@@ -713,7 +819,7 @@ void ResourceDispatcherHostImpl::DidReceiveResponse(ResourceLoader* loader) {
if (loader->request()->was_fetched_via_proxy() &&
loader->request()->was_fetched_via_spdy() &&
- loader->request()->url().SchemeIs("http")) {
+ loader->request()->url().SchemeIs(url::kHttpScheme)) {
scheduler_->OnReceivedSpdyProxiedHttpResponse(
info->GetChildID(), info->GetRouteID());
}
@@ -737,7 +843,7 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
ResourceRequestInfo* info = loader->GetRequestInfo();
// Record final result of all resource loads.
- if (info->GetResourceType() == ResourceType::MAIN_FRAME) {
+ if (info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME) {
// This enumeration has "3" appended to its name to distinguish it from
// older versions.
UMA_HISTOGRAM_SPARSE_SLOWLY(
@@ -758,7 +864,7 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
"Net.CertificateTransparency.MainFrameValidSCTCount", num_valid_scts);
}
} else {
- if (info->GetResourceType() == ResourceType::IMAGE) {
+ if (info->GetResourceType() == RESOURCE_TYPE_IMAGE) {
UMA_HISTOGRAM_SPARSE_SLOWLY(
"Net.ErrorCodesForImages",
-loader->request()->status().error());
@@ -769,6 +875,11 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
-loader->request()->status().error());
}
+ if (loader->request()->url().SchemeIsSecure()) {
+ RecordCertificateHistograms(loader->request()->ssl_info(),
+ info->GetResourceType());
+ }
+
if (delegate_)
delegate_->RequestComplete(loader->request());
@@ -856,6 +967,19 @@ void ResourceDispatcherHostImpl::OnRequestResource(
int routing_id,
int request_id,
const ResourceHostMsg_Request& request_data) {
+ // When logging time-to-network only care about main frame and non-transfer
+ // navigations.
+ if (request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME &&
+ request_data.transferred_request_request_id == -1) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&LogResourceRequestTimeOnUI,
+ TimeTicks::Now(),
+ filter_->child_id(),
+ request_data.render_frame_id,
+ request_data.url));
+ }
BeginRequest(request_id, request_data, NULL, routing_id);
}
@@ -890,10 +1014,13 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
GlobalRequestID new_request_id(child_id, request_id);
// Clear out data that depends on |info| before updating it.
+ // We always need to move the memory stats to the new process. In contrast,
+ // stats.num_requests is only tracked for some requests (those that require
+ // file descriptors for their shared memory buffer).
IncrementOutstandingRequestsMemory(-1, *info);
- OustandingRequestsStats empty_stats = { 0, 0 };
- OustandingRequestsStats old_stats = GetOutstandingRequestsStats(*info);
- UpdateOutstandingRequestsStats(*info, empty_stats);
+ bool should_update_count = info->counted_as_in_flight_request();
+ if (should_update_count)
+ IncrementOutstandingRequestsCount(-1, info);
pending_loaders_.erase(old_request_id);
// ResourceHandlers should always get state related to the request from the
@@ -906,8 +1033,9 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
// 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;
- UpdateOutstandingRequestsStats(*info, old_stats);
IncrementOutstandingRequestsMemory(1, *info);
+ if (should_update_count)
+ IncrementOutstandingRequestsCount(1, info);
if (old_routing_id != new_routing_id) {
if (blocked_loaders_map_.find(old_routing_id) !=
blocked_loaders_map_.end()) {
@@ -999,9 +1127,7 @@ void ResourceDispatcherHostImpl::BeginRequest(
}
// Allow the observer to block/handle the request.
- if (delegate_ && !delegate_->ShouldBeginRequest(child_id,
- route_id,
- request_data.method,
+ if (delegate_ && !delegate_->ShouldBeginRequest(request_data.method,
request_data.url,
request_data.resource_type,
resource_context)) {
@@ -1034,6 +1160,13 @@ void ResourceDispatcherHostImpl::BeginRequest(
new_request->set_first_party_for_cookies(
request_data.first_party_for_cookies);
+ // 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) {
+ new_request->set_first_party_url_policy(
+ net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
+ }
+
const Referrer referrer(request_data.referrer, request_data.referrer_policy);
SetReferrerForRequest(new_request.get(), referrer);
@@ -1043,18 +1176,31 @@ void ResourceDispatcherHostImpl::BeginRequest(
new_request->SetLoadFlags(load_flags);
+ storage::BlobStorageContext* blob_context =
+ GetBlobStorageContext(filter_->blob_storage_context());
// Resolve elements from request_body and prepare upload data.
if (request_data.request_body.get()) {
+ // |blob_context| could be null when the request is from the plugins because
+ // ResourceMessageFilters created in PluginProcessHost don't have the blob
+ // context.
+ if (blob_context) {
+ // Attaches the BlobDataHandles to request_body not to free the blobs and
+ // any attached shareable files until upload completion. These data will
+ // be used in UploadDataStream and ServiceWorkerURLRequestJob.
+ AttachRequestBodyBlobDataHandles(
+ request_data.request_body.get(),
+ blob_context);
+ }
new_request->set_upload(UploadDataStreamBuilder::Build(
request_data.request_body.get(),
- GetBlobStorageContext(filter_),
+ blob_context,
filter_->file_system_context(),
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
.get()));
}
bool allow_download = request_data.allow_download &&
- ResourceType::IsFrame(request_data.resource_type);
+ IsResourceTypeFrame(request_data.resource_type);
// Make extra info and read footer (contains request ID).
ResourceRequestInfoImpl* extra_info =
@@ -1075,6 +1221,8 @@ void ResourceDispatcherHostImpl::BeginRequest(
false, // is stream
allow_download,
request_data.has_user_gesture,
+ request_data.enable_load_timing,
+ request_data.enable_upload_progress,
request_data.referrer_policy,
request_data.visiblity_state,
resource_context,
@@ -1086,20 +1234,29 @@ void ResourceDispatcherHostImpl::BeginRequest(
if (new_request->url().SchemeIs(url::kBlobScheme)) {
// Hang on to a reference to ensure the blob is not released prior
// to the job being started.
- webkit_blob::BlobProtocolHandler::SetRequestedBlobDataHandle(
+ storage::BlobProtocolHandler::SetRequestedBlobDataHandle(
new_request.get(),
- filter_->blob_storage_context()->context()->
- GetBlobDataFromPublicURL(new_request->url()));
+ filter_->blob_storage_context()->context()->GetBlobDataFromPublicURL(
+ new_request->url()));
}
- // Initialize the service worker handler for the request.
+ // Initialize the service worker handler for the request. We don't use
+ // ServiceWorker for synchronous loads to avoid renderer deadlocks. We
+ // don't use ServiceWorker for favicons to avoid cache tainting.
+ bool is_favicon_load = request_data.resource_type == RESOURCE_TYPE_FAVICON;
ServiceWorkerRequestHandler::InitializeHandler(
new_request.get(),
filter_->service_worker_context(),
- GetBlobStorageContext(filter_),
+ blob_context,
child_id,
request_data.service_worker_provider_id,
- request_data.resource_type);
+ request_data.skip_service_worker || is_sync_load || is_favicon_load,
+ request_data.fetch_request_mode,
+ request_data.fetch_credentials_mode,
+ request_data.resource_type,
+ request_data.fetch_request_context_type,
+ request_data.fetch_frame_type,
+ request_data.request_body);
// Have the appcache associate its extra info with the request.
AppCacheInterceptor::SetExtraRequestInfo(
@@ -1153,20 +1310,41 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
handler.Pass()));
}
- // Install a CrossSiteResourceHandler for all main frame requests. This will
- // let us check whether a transfer is required and pause for the unload
- // handler either if so or if a cross-process navigation is already under way.
- bool is_swappable_navigation =
- request_data.resource_type == ResourceType::MAIN_FRAME;
- // If we are using --site-per-process, install it for subframes as well.
- if (!is_swappable_navigation &&
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) {
- is_swappable_navigation =
- request_data.resource_type == ResourceType::SUB_FRAME;
+ // PlzNavigate: If using --enable-browser-side-navigation, the
+ // CrossSiteResourceHandler is not needed. This codepath is not used for the
+ // actual navigation request, but only the subsequent blob URL load. This does
+ // not require request transfers.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation)) {
+ // Install a CrossSiteResourceHandler for all main frame requests. This will
+ // check whether a transfer is required and, if so, pause for the UI thread
+ // to drive the transfer.
+ bool is_swappable_navigation =
+ request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME;
+ // If we are using --site-per-process, install it for subframes as well.
+ if (!is_swappable_navigation &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess)) {
+ is_swappable_navigation =
+ request_data.resource_type == RESOURCE_TYPE_SUB_FRAME;
+ }
+ if (is_swappable_navigation && process_type == PROCESS_TYPE_RENDERER)
+ handler.reset(new CrossSiteResourceHandler(handler.Pass(), request));
}
- if (is_swappable_navigation && process_type == PROCESS_TYPE_RENDERER)
- handler.reset(new CrossSiteResourceHandler(handler.Pass(), request));
+ return AddStandardHandlers(request, request_data.resource_type,
+ resource_context, filter_->appcache_service(),
+ child_id, route_id, handler.Pass());
+}
+
+scoped_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) {
// Insert a buffered event handler before the actual one.
handler.reset(
new BufferedResourceHandler(handler.Pass(), this, request));
@@ -1175,10 +1353,8 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
if (delegate_) {
delegate_->RequestBeginning(request,
resource_context,
- filter_->appcache_service(),
- request_data.resource_type,
- child_id,
- route_id,
+ appcache_service,
+ resource_type,
&throttles);
}
@@ -1208,7 +1384,7 @@ void ResourceDispatcherHostImpl::RegisterDownloadedTempFile(
int child_id, int request_id, const base::FilePath& file_path) {
scoped_refptr<ShareableFileReference> reference =
ShareableFileReference::Get(file_path);
- DCHECK(reference);
+ DCHECK(reference.get());
registered_temp_files_[child_id][request_id] = reference;
ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
@@ -1288,13 +1464,15 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
false, // is_main_frame
false, // parent_is_main_frame
-1, // parent_render_frame_id
- ResourceType::SUB_RESOURCE,
- PAGE_TRANSITION_LINK,
+ RESOURCE_TYPE_SUB_RESOURCE,
+ ui::PAGE_TRANSITION_LINK,
false, // should_replace_current_entry
download, // is_download
false, // is_stream
download, // allow_download
false, // has_user_gesture
+ false, // enable_load_timing
+ false, // enable_upload_progress
blink::WebReferrerPolicyDefault,
blink::WebPageVisibilityStateVisible,
context,
@@ -1302,10 +1480,11 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
true); // is_async
}
-void ResourceDispatcherHostImpl::OnRenderViewHostCreated(
- int child_id,
- int route_id) {
- scheduler_->OnClientCreated(child_id, route_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);
}
void ResourceDispatcherHostImpl::OnRenderViewHostDeleted(
@@ -1315,6 +1494,31 @@ void ResourceDispatcherHostImpl::OnRenderViewHostDeleted(
CancelRequestsForRoute(child_id, route_id);
}
+void ResourceDispatcherHostImpl::OnRenderViewHostSetIsLoading(int child_id,
+ int route_id,
+ bool is_loading) {
+ 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) {
+ scheduler_->OnAudibilityChanged(child_id, route_id, is_playing);
+}
+
// This function is only used for saving feature.
void ResourceDispatcherHostImpl::BeginSaveFile(
const GURL& url,
@@ -1388,12 +1592,9 @@ void ResourceDispatcherHostImpl::CancelTransferringNavigation(
void ResourceDispatcherHostImpl::ResumeDeferredNavigation(
const GlobalRequestID& id) {
ResourceLoader* loader = GetLoader(id);
- if (loader) {
- // The response we were meant to resume could have already been canceled.
- ResourceRequestInfoImpl* info = loader->GetRequestInfo();
- if (info->cross_site_handler())
- info->cross_site_handler()->ResumeResponse();
- }
+ // The response we were meant to resume could have already been canceled.
+ if (loader)
+ loader->CompleteTransfer();
}
// The object died, so cancel and detach all requests associated with it except
@@ -1564,23 +1765,28 @@ ResourceDispatcherHostImpl::IncrementOutstandingRequestsMemory(
ResourceDispatcherHostImpl::OustandingRequestsStats
ResourceDispatcherHostImpl::IncrementOutstandingRequestsCount(
int count,
- const ResourceRequestInfoImpl& info) {
+ ResourceRequestInfoImpl* info) {
DCHECK_EQ(1, abs(count));
num_in_flight_requests_ += count;
- OustandingRequestsStats stats = GetOutstandingRequestsStats(info);
+ // Keep track of whether this request is counting toward the number of
+ // in-flight requests for this process, in case we need to transfer it to
+ // another process. This should be a toggle.
+ DCHECK_NE(info->counted_as_in_flight_request(), count > 0);
+ info->set_counted_as_in_flight_request(count > 0);
+
+ OustandingRequestsStats stats = GetOutstandingRequestsStats(*info);
stats.num_requests += count;
DCHECK_GE(stats.num_requests, 0);
- UpdateOutstandingRequestsStats(info, stats);
+ UpdateOutstandingRequestsStats(*info, stats);
return stats;
}
bool ResourceDispatcherHostImpl::HasSufficientResourcesForRequest(
- const net::URLRequest* request_) {
- const ResourceRequestInfoImpl* info =
- ResourceRequestInfoImpl::ForRequest(request_);
- OustandingRequestsStats stats = IncrementOutstandingRequestsCount(1, *info);
+ net::URLRequest* request) {
+ ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request);
+ OustandingRequestsStats stats = IncrementOutstandingRequestsCount(1, info);
if (stats.num_requests > max_num_in_flight_requests_per_process_)
return false;
@@ -1591,10 +1797,175 @@ bool ResourceDispatcherHostImpl::HasSufficientResourcesForRequest(
}
void ResourceDispatcherHostImpl::FinishedWithResourcesForRequest(
- const net::URLRequest* request_) {
- const ResourceRequestInfoImpl* info =
- ResourceRequestInfoImpl::ForRequest(request_);
- IncrementOutstandingRequestsCount(-1, *info);
+ net::URLRequest* request) {
+ ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request);
+ IncrementOutstandingRequestsCount(-1, info);
+}
+
+void ResourceDispatcherHostImpl::BeginNavigationRequest(
+ ResourceContext* resource_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& params,
+ const NavigationRequestInfo& info,
+ scoped_refptr<ResourceRequestBody> request_body,
+ NavigationURLLoaderImplCore* loader) {
+ // PlzNavigate: BeginNavigationRequest currently should only be used for the
+ // browser-side navigations project.
+ CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserSideNavigation));
+
+ ResourceType resource_type = info.is_main_frame ?
+ RESOURCE_TYPE_MAIN_FRAME : RESOURCE_TYPE_SUB_FRAME;
+
+ if (is_shutdown_ ||
+ // TODO(davidben): Check ShouldServiceRequest here. This is important; it
+ // 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.navigation_params.method,
+ params.url,
+ resource_type,
+ resource_context))) {
+ loader->NotifyRequestFailed(net::ERR_ABORTED);
+ return;
+ }
+
+ // Save the URL on the stack to help catch URLRequests which outlive their
+ // URLRequestContexts. See https://crbug.com/90971
+ char url_buf[128];
+ base::strlcpy(url_buf, params.url.spec().c_str(), arraysize(url_buf));
+ base::debug::Alias(url_buf);
+ CHECK(ContainsKey(active_resource_contexts_, resource_context));
+
+ const net::URLRequestContext* request_context =
+ resource_context->GetRequestContext();
+
+ int load_flags = info.navigation_params.load_flags;
+ load_flags |= net::LOAD_VERIFY_EV_CERT;
+ if (info.is_main_frame) {
+ load_flags |= net::LOAD_MAIN_FRAME;
+ } else {
+ load_flags |= net::LOAD_SUB_FRAME;
+ }
+ // Add a flag to selectively bypass the data reduction proxy if the resource
+ // type is not an image.
+ load_flags |= net::LOAD_BYPASS_DATA_REDUCTION_PROXY;
+
+ // TODO(davidben): BuildLoadFlagsForRequest includes logic for
+ // CanSendCookiesForOrigin and CanReadRawCookies. Is this needed here?
+
+ // Sync loads should have maximum priority and should be the only
+ // requests that have the ignore limits flag set.
+ DCHECK(!(load_flags & net::LOAD_IGNORE_LIMITS));
+
+ // TODO(davidben): OverrideCookieStoreForRenderProcess handling for
+ // prerender. There may not be a renderer process yet, so we need to use the
+ // ResourceContext or something.
+ scoped_ptr<net::URLRequest> new_request;
+ new_request = request_context->CreateRequest(params.url, net::HIGHEST,
+ nullptr, nullptr);
+
+ new_request->set_method(info.navigation_params.method);
+ new_request->set_first_party_for_cookies(
+ info.first_party_for_cookies);
+ if (info.is_main_frame) {
+ new_request->set_first_party_url_policy(
+ net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
+ }
+
+ SetReferrerForRequest(new_request.get(), params.referrer);
+
+ net::HttpRequestHeaders headers;
+ headers.AddHeadersFromString(info.navigation_params.headers);
+ new_request->SetExtraRequestHeaders(headers);
+
+ new_request->SetLoadFlags(load_flags);
+
+ // Resolve elements from request_body and prepare upload data.
+ if (info.navigation_params.request_body.get()) {
+ storage::BlobStorageContext* blob_context = GetBlobStorageContext(
+ GetChromeBlobStorageContextForResourceContext(resource_context));
+ AttachRequestBodyBlobDataHandles(
+ info.navigation_params.request_body.get(),
+ blob_context);
+ // TODO(davidben): The FileSystemContext is null here. In the case where
+ // another renderer requested this navigation, this should be the same
+ // FileSystemContext passed into ShouldServiceRequest.
+ new_request->set_upload(UploadDataStreamBuilder::Build(
+ info.navigation_params.request_body.get(),
+ blob_context,
+ nullptr, // file_system_context
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
+ .get()));
+ }
+
+ request_id_--;
+
+ // Make extra info and read footer (contains request ID).
+ //
+ // TODO(davidben): Associate the request with the FrameTreeNode and/or tab so
+ // that IO thread -> UI thread hops will work.
+ ResourceRequestInfoImpl* extra_info =
+ new ResourceRequestInfoImpl(
+ PROCESS_TYPE_BROWSER,
+ -1, // child_id
+ -1, // route_id
+ -1, // request_data.origin_pid,
+ request_id_,
+ -1, // request_data.render_frame_id,
+ info.is_main_frame,
+ info.parent_is_main_frame,
+ -1, // request_data.parent_render_frame_id,
+ resource_type,
+ params.transition,
+ // should_replace_current_entry. This was only maintained at layer for
+ // request transfers and isn't needed for browser-side navigations.
+ false,
+ false, // is download
+ false, // is stream
+ params.allow_download,
+ info.navigation_params.has_user_gesture,
+ true, // enable_load_timing
+ false, // enable_upload_progress
+ params.referrer.policy,
+ // TODO(davidben): This is only used for prerenders. Replace
+ // is_showing with something for that. Or maybe it just comes from the
+ // same mechanism as the cookie one.
+ blink::WebPageVisibilityStateVisible,
+ resource_context,
+ base::WeakPtr<ResourceMessageFilter>(), // filter
+ true);
+ // Request takes ownership.
+ extra_info->AssociateWithRequest(new_request.get());
+
+ if (new_request->url().SchemeIs(url::kBlobScheme)) {
+ // Hang on to a reference to ensure the blob is not released prior
+ // to the job being started.
+ ChromeBlobStorageContext* blob_context =
+ GetChromeBlobStorageContextForResourceContext(resource_context);
+ storage::BlobProtocolHandler::SetRequestedBlobDataHandle(
+ new_request.get(),
+ blob_context->context()->GetBlobDataFromPublicURL(new_request->url()));
+ }
+
+ // TODO(davidben): Attach ServiceWorkerRequestHandler.
+
+ // TODO(davidben): Attach AppCacheInterceptor.
+
+ scoped_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;
+ // currently it's a no-op.
+ handler = AddStandardHandlers(new_request.get(), resource_type,
+ resource_context,
+ nullptr, // appcache_service
+ -1, // child_id
+ -1, // route_id
+ handler.Pass());
+
+ BeginRequestInternal(new_request.Pass(), handler.Pass());
}
// static
@@ -1925,15 +2296,15 @@ int ResourceDispatcherHostImpl::BuildLoadFlagsForRequest(
// keep-alive connection created to load a sub-frame or a sub-resource could
// be reused to load a main frame.
load_flags |= net::LOAD_VERIFY_EV_CERT;
- if (request_data.resource_type == ResourceType::MAIN_FRAME) {
+ if (request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME) {
load_flags |= net::LOAD_MAIN_FRAME;
- } else if (request_data.resource_type == ResourceType::SUB_FRAME) {
+ } else if (request_data.resource_type == RESOURCE_TYPE_SUB_FRAME) {
load_flags |= net::LOAD_SUB_FRAME;
- } else if (request_data.resource_type == ResourceType::PREFETCH) {
+ } else if (request_data.resource_type == RESOURCE_TYPE_PREFETCH) {
load_flags |= (net::LOAD_PREFETCH | net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
- } else if (request_data.resource_type == ResourceType::FAVICON) {
+ } else if (request_data.resource_type == RESOURCE_TYPE_FAVICON) {
load_flags |= net::LOAD_DO_NOT_PROMPT_FOR_LOGIN;
- } else if (request_data.resource_type == ResourceType::IMAGE) {
+ } else if (request_data.resource_type == RESOURCE_TYPE_IMAGE) {
// Prevent third-party image content from prompting for login, as this
// is often a scam to extract credentials for another domain from the user.
// Only block image loads, as the attack applies largely to the "src"
@@ -1969,6 +2340,11 @@ int ResourceDispatcherHostImpl::BuildLoadFlagsForRequest(
load_flags &= ~net::LOAD_REPORT_RAW_HEADERS;
}
+ // Add a flag to selectively bypass the data reduction proxy if the resource
+ // type is not an image.
+ if (request_data.resource_type != RESOURCE_TYPE_IMAGE)
+ load_flags |= net::LOAD_BYPASS_DATA_REDUCTION_PROXY;
+
return load_flags;
}
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_impl.h b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
index 3cc7b4fd1ec..a96af553b4a 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/chromium/content/browser/loader/resource_dispatcher_host_impl.h
@@ -30,16 +30,17 @@
#include "content/browser/loader/resource_loader_delegate.h"
#include "content/browser/loader/resource_scheduler.h"
#include "content/common/content_export.h"
+#include "content/common/resource_request_body.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_url_parameters.h"
#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/common/resource_type.h"
#include "ipc/ipc_message.h"
#include "net/cookies/canonical_cookie.h"
#include "net/url_request/url_request.h"
-#include "webkit/common/resource_type.h"
class ResourceHandler;
struct ResourceHostMsg_Request;
@@ -48,11 +49,13 @@ namespace net {
class URLRequestJobFactory;
}
-namespace webkit_blob {
+namespace storage {
class ShareableFileReference;
}
namespace content {
+class AppCacheService;
+class NavigationURLLoaderImplCore;
class ResourceContext;
class ResourceDispatcherHostDelegate;
class ResourceMessageDelegate;
@@ -60,7 +63,9 @@ class ResourceMessageFilter;
class ResourceRequestInfoImpl;
class SaveFileManager;
class WebContentsImpl;
+struct CommonNavigationParams;
struct DownloadSaveInfo;
+struct NavigationRequestInfo;
struct Referrer;
class CONTENT_EXPORT ResourceDispatcherHostImpl
@@ -68,16 +73,16 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
public ResourceLoaderDelegate {
public:
ResourceDispatcherHostImpl();
- virtual ~ResourceDispatcherHostImpl();
+ ~ResourceDispatcherHostImpl() override;
// Returns the current ResourceDispatcherHostImpl. May return NULL if it
// hasn't been created yet.
static ResourceDispatcherHostImpl* Get();
// ResourceDispatcherHost implementation:
- virtual void SetDelegate(ResourceDispatcherHostDelegate* delegate) OVERRIDE;
- virtual void SetAllowCrossOriginAuthPrompt(bool value) OVERRIDE;
- virtual DownloadInterruptReason BeginDownload(
+ void SetDelegate(ResourceDispatcherHostDelegate* delegate) override;
+ void SetAllowCrossOriginAuthPrompt(bool value) override;
+ DownloadInterruptReason BeginDownload(
scoped_ptr<net::URLRequest> request,
const Referrer& referrer,
bool is_content_initiated,
@@ -87,11 +92,10 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
bool prefer_cache,
scoped_ptr<DownloadSaveInfo> save_info,
uint32 download_id,
- const DownloadStartedCallback& started_callback) OVERRIDE;
- virtual void ClearLoginDelegateForRequest(net::URLRequest* request) OVERRIDE;
- virtual void BlockRequestsForRoute(int child_id, int route_id) OVERRIDE;
- virtual void ResumeBlockedRequestsForRoute(
- int child_id, int route_id) OVERRIDE;
+ 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.
@@ -103,6 +107,9 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Notify the ResourceDispatcherHostImpl of a resource context destruction.
void RemoveResourceContext(ResourceContext* context);
+ // Resumes a request that deferred at response start.
+ void ResumeResponseDeferredAtStart(const GlobalRequestID& id);
+
// Force cancels any pending requests for the given |context|. This is
// necessary to ensure that before |context| goes away, all requests
// for it are dead.
@@ -159,11 +166,30 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
}
// Called when a RenderViewHost is created.
- void OnRenderViewHostCreated(int child_id, int route_id);
+ void OnRenderViewHostCreated(int child_id,
+ int route_id,
+ bool is_visible,
+ bool is_audible);
// Called when a RenderViewHost is deleted.
void OnRenderViewHostDeleted(int child_id, int route_id);
+ // Called when a RenderViewHost starts or stops loading.
+ void OnRenderViewHostSetIsLoading(int child_id,
+ 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);
@@ -211,27 +237,34 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Must be called after the ResourceRequestInfo has been created
// and associated with the request. If |payload| is set to a non-empty value,
- // the value will be sent to the old resource handler instead of cancelling
+ // the value will be sent to the old resource handler instead of canceling
// it, except on HTTP errors.
scoped_ptr<ResourceHandler> MaybeInterceptAsStream(
net::URLRequest* request,
ResourceResponse* response,
std::string* payload);
- void ClearSSLClientAuthHandlerForRequest(net::URLRequest* request);
-
ResourceScheduler* scheduler() { return scheduler_.get(); }
// Called by a ResourceHandler when it's ready to start reading data and
// sending it to the renderer. Returns true if there are enough file
// descriptors available for the shared memory buffer. If false is returned,
// the request should cancel.
- bool HasSufficientResourcesForRequest(const net::URLRequest* request_);
+ bool HasSufficientResourcesForRequest(net::URLRequest* request);
// Called by a ResourceHandler after it has finished its request and is done
// using its shared memory buffer. Frees up that file descriptor to be used
// elsewhere.
- void FinishedWithResourcesForRequest(const net::URLRequest* request_);
+ void FinishedWithResourcesForRequest(net::URLRequest* request);
+
+ // PlzNavigate: Begins a request for NavigationURLLoader. |loader| is the
+ // loader to attach to the leaf resource handler.
+ void BeginNavigationRequest(ResourceContext* resource_context,
+ int64 frame_tree_node_id,
+ const CommonNavigationParams& common_params,
+ const NavigationRequestInfo& info,
+ scoped_refptr<ResourceRequestBody> request_body,
+ NavigationURLLoaderImplCore* loader);
private:
friend class ResourceDispatcherHostTest;
@@ -256,16 +289,14 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
friend class ResourceMessageDelegate;
// ResourceLoaderDelegate implementation:
- virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
+ ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
ResourceLoader* loader,
- net::AuthChallengeInfo* auth_info) OVERRIDE;
- virtual bool HandleExternalProtocol(ResourceLoader* loader,
- const GURL& url) OVERRIDE;
- virtual void DidStartRequest(ResourceLoader* loader) OVERRIDE;
- virtual void DidReceiveRedirect(ResourceLoader* loader,
- const GURL& new_url) OVERRIDE;
- virtual void DidReceiveResponse(ResourceLoader* loader) OVERRIDE;
- virtual void DidFinishLoading(ResourceLoader* loader) OVERRIDE;
+ net::AuthChallengeInfo* auth_info) override;
+ bool HandleExternalProtocol(ResourceLoader* loader, const GURL& url) override;
+ void DidStartRequest(ResourceLoader* loader) override;
+ void DidReceiveRedirect(ResourceLoader* loader, const GURL& new_url) override;
+ void DidReceiveResponse(ResourceLoader* loader) override;
+ void DidFinishLoading(ResourceLoader* loader) override;
// An init helper that runs on the IO thread.
void OnInit();
@@ -304,12 +335,12 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
int count,
const ResourceRequestInfoImpl& info);
- // Called every time an in flight request is issued or finished. |count|
- // indicates whether the request is issuing or finishing. |count| must be 1
- // or -1.
+ // Called when an in flight request allocates or releases a shared memory
+ // buffer. |count| indicates whether the request is issuing or finishing.
+ // |count| must be 1 or -1.
OustandingRequestsStats IncrementOutstandingRequestsCount(
int count,
- const ResourceRequestInfoImpl& info);
+ ResourceRequestInfoImpl* info);
// Estimate how much heap space |request| will consume to run.
static int CalculateApproximateMemoryCost(net::URLRequest* request);
@@ -372,6 +403,18 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
int child_id,
ResourceContext* resource_context);
+ // Wraps |handler| in the standard resource handlers for normal resource
+ // loading and navigation requests. This adds BufferedResourceHandler and
+ // ResourceThrottles.
+ scoped_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);
+
void OnDataDownloadedACK(int request_id);
void OnUploadProgressACK(int request_id);
void OnCancelRequest(int request_id);
@@ -423,7 +466,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// Collection of temp files downloaded for child processes via
// the download_to_file mechanism. We avoid deleting them until
// the client no longer needs them.
- typedef std::map<int, scoped_refptr<webkit_blob::ShareableFileReference> >
+ typedef std::map<int, scoped_refptr<storage::ShareableFileReference> >
DeletableFilesMap; // key is request id
typedef std::map<int, DeletableFilesMap>
RegisteredTempFiles; // key is child process id
diff --git a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
index a815032ac6f..d18facde88a 100644
--- a/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -6,8 +6,8 @@
#include "base/basictypes.h"
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
@@ -23,7 +23,7 @@
#include "content/browser/loader/resource_loader.h"
#include "content/browser/loader/resource_message_filter.h"
#include "content/browser/loader/resource_request_info_impl.h"
-#include "content/browser/worker_host/worker_service_impl.h"
+#include "content/common/appcache_interfaces.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/resource_messages.h"
#include "content/common/view_messages.h"
@@ -37,10 +37,10 @@
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/test_content_browser_client.h"
+#include "net/base/elements_upload_data_stream.h"
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/base/upload_bytes_element_reader.h"
-#include "net/base/upload_data_stream.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
@@ -49,14 +49,13 @@
#include "net/url_request/url_request_simple_job.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
+#include "storage/common/blob/shareable_file_reference.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/common/appcache/appcache_interfaces.h"
-#include "webkit/common/blob/shareable_file_reference.h"
// TODO(eroman): Write unit tests for SafeBrowsing that exercise
// SafeBrowsingResourceHandler.
-using webkit_blob::ShareableFileReference;
+using storage::ShareableFileReference;
namespace content {
@@ -126,10 +125,9 @@ static int RequestIDForMessage(const IPC::Message& msg) {
return request_id;
}
-static ResourceHostMsg_Request CreateResourceRequest(
- const char* method,
- ResourceType::Type type,
- const GURL& url) {
+static ResourceHostMsg_Request CreateResourceRequest(const char* method,
+ ResourceType type,
+ const GURL& url) {
ResourceHostMsg_Request request;
request.method = std::string(method);
request.url = url;
@@ -139,12 +137,12 @@ static ResourceHostMsg_Request CreateResourceRequest(
request.origin_pid = 0;
request.resource_type = type;
request.request_context = 0;
- request.appcache_host_id = appcache::kAppCacheNoHostId;
+ request.appcache_host_id = kAppCacheNoHostId;
request.download_to_file = false;
request.is_main_frame = true;
request.parent_is_main_frame = false;
request.parent_render_frame_id = -1;
- request.transition_type = PAGE_TRANSITION_LINK;
+ request.transition_type = ui::PAGE_TRANSITION_LINK;
request.allow_download = true;
return request;
}
@@ -225,7 +223,7 @@ class TestFilter : public ResourceMessageFilter {
int received_after_canceled() const { return received_after_canceled_; }
// ResourceMessageFilter override
- virtual bool Send(IPC::Message* msg) OVERRIDE {
+ bool Send(IPC::Message* msg) override {
// No messages should be received when the process has been canceled.
if (canceled_)
received_after_canceled_++;
@@ -237,7 +235,7 @@ class TestFilter : public ResourceMessageFilter {
ResourceContext* resource_context() { return resource_context_; }
protected:
- virtual ~TestFilter() {}
+ ~TestFilter() override {}
private:
void GetContexts(const ResourceHostMsg_Request& request,
@@ -267,12 +265,10 @@ class ForwardingFilter : public TestFilter {
}
// TestFilter override
- virtual bool Send(IPC::Message* msg) OVERRIDE {
- return dest_->Send(msg);
- }
+ bool Send(IPC::Message* msg) override { return dest_->Send(msg); }
private:
- virtual ~ForwardingFilter() {}
+ ~ForwardingFilter() override {}
IPC::Sender* dest_;
@@ -280,7 +276,7 @@ class ForwardingFilter : public TestFilter {
};
// This class is a variation on URLRequestTestJob that will call
-// URLRequest::OnBeforeNetworkStart before starting.
+// URLRequest::WillStartUsingNetwork before starting.
class URLRequestTestDelayedNetworkJob : public net::URLRequestTestJob {
public:
URLRequestTestDelayedNetworkJob(net::URLRequest* request,
@@ -288,7 +284,7 @@ class URLRequestTestDelayedNetworkJob : public net::URLRequestTestJob {
: net::URLRequestTestJob(request, network_delegate) {}
// Only start if not deferred for network start.
- virtual void Start() OVERRIDE {
+ void Start() override {
bool defer = false;
NotifyBeforeNetworkStart(&defer);
if (defer)
@@ -296,12 +292,10 @@ class URLRequestTestDelayedNetworkJob : public net::URLRequestTestJob {
net::URLRequestTestJob::Start();
}
- virtual void ResumeNetworkStart() OVERRIDE {
- net::URLRequestTestJob::StartAsync();
- }
+ void ResumeNetworkStart() override { net::URLRequestTestJob::StartAsync(); }
private:
- virtual ~URLRequestTestDelayedNetworkJob() {}
+ ~URLRequestTestDelayedNetworkJob() override {}
DISALLOW_COPY_AND_ASSIGN(URLRequestTestDelayedNetworkJob);
};
@@ -335,7 +329,7 @@ class URLRequestTestDelayedStartJob : public net::URLRequestTestJob {
}
// Do nothing until you're told to.
- virtual void Start() OVERRIDE {}
+ void Start() override {}
// Finish starting a URL request whose job is an instance of
// URLRequestTestDelayedStartJob. It is illegal to call this routine
@@ -366,7 +360,7 @@ class URLRequestTestDelayedStartJob : public net::URLRequestTestJob {
}
protected:
- virtual ~URLRequestTestDelayedStartJob() {
+ ~URLRequestTestDelayedStartJob() override {
for (URLRequestTestDelayedStartJob** job = &list_head_; *job;
job = &(*job)->next_) {
if (*job == this) {
@@ -413,10 +407,10 @@ class URLRequestTestDelayedCompletionJob : public net::URLRequestTestJob {
auto_advance) {}
protected:
- virtual ~URLRequestTestDelayedCompletionJob() {}
+ ~URLRequestTestDelayedCompletionJob() override {}
private:
- virtual bool NextReadAsync() OVERRIDE { return true; }
+ bool NextReadAsync() override { return true; }
};
class URLRequestBigJob : public net::URLRequestSimpleJob {
@@ -426,10 +420,10 @@ class URLRequestBigJob : public net::URLRequestSimpleJob {
: net::URLRequestSimpleJob(request, network_delegate) {
}
- virtual int GetData(std::string* mime_type,
- std::string* charset,
- std::string* data,
- const net::CompletionCallback& callback) const OVERRIDE {
+ int GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* data,
+ const net::CompletionCallback& callback) const override {
*mime_type = "text/plain";
*charset = "UTF-8";
@@ -446,7 +440,7 @@ class URLRequestBigJob : public net::URLRequestSimpleJob {
}
private:
- virtual ~URLRequestBigJob() {}
+ ~URLRequestBigJob() override {}
// big-job:substring,N
static bool ParseURL(const GURL& url, std::string* text, int* count) {
@@ -493,20 +487,29 @@ class TestURLRequestJobFactory : public net::URLRequestJobFactory {
network_start_notification_ = notification;
}
- virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
+ net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE;
+ net::NetworkDelegate* network_delegate) const override;
- virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
+ net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const override;
+
+ net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override;
+
+ bool IsHandledProtocol(const std::string& scheme) const override {
return supported_schemes_.count(scheme) > 0;
}
- virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
+ bool IsHandledURL(const GURL& url) const override {
return supported_schemes_.count(url.scheme()) > 0;
}
- virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
+ bool IsSafeRedirectTarget(const GURL& location) const override {
return false;
}
@@ -528,9 +531,7 @@ class TestUserData : public base::SupportsUserData::Data {
: was_deleted_(was_deleted) {
}
- virtual ~TestUserData() {
- *was_deleted_ = true;
- }
+ ~TestUserData() override { *was_deleted_ = true; }
private:
bool* was_deleted_;
@@ -539,9 +540,9 @@ class TestUserData : public base::SupportsUserData::Data {
class TransfersAllNavigationsContentBrowserClient
: public TestContentBrowserClient {
public:
- virtual bool ShouldSwapProcessesForRedirect(ResourceContext* resource_context,
- const GURL& current_url,
- const GURL& new_url) OVERRIDE {
+ bool ShouldSwapProcessesForRedirect(ResourceContext* resource_context,
+ const GURL& current_url,
+ const GURL& new_url) override {
return true;
}
};
@@ -568,13 +569,13 @@ class GenericResourceThrottle : public ResourceThrottle {
error_code_for_cancellation_(code) {
}
- virtual ~GenericResourceThrottle() {
+ ~GenericResourceThrottle() override {
if (active_throttle_ == this)
active_throttle_ = NULL;
}
// ResourceThrottle implementation:
- virtual void WillStartRequest(bool* defer) OVERRIDE {
+ void WillStartRequest(bool* defer) override {
ASSERT_EQ(NULL, active_throttle_);
if (flags_ & DEFER_STARTING_REQUEST) {
active_throttle_ = this;
@@ -590,7 +591,7 @@ class GenericResourceThrottle : public ResourceThrottle {
}
}
- virtual void WillProcessResponse(bool* defer) OVERRIDE {
+ void WillProcessResponse(bool* defer) override {
ASSERT_EQ(NULL, active_throttle_);
if (flags_ & DEFER_PROCESSING_RESPONSE) {
active_throttle_ = this;
@@ -598,7 +599,7 @@ class GenericResourceThrottle : public ResourceThrottle {
}
}
- virtual void OnBeforeNetworkStart(bool* defer) OVERRIDE {
+ void WillStartUsingNetwork(bool* defer) override {
ASSERT_EQ(NULL, active_throttle_);
if (flags_ & DEFER_NETWORK_START) {
@@ -607,7 +608,7 @@ class GenericResourceThrottle : public ResourceThrottle {
}
}
- virtual const char* GetNameForLogging() const OVERRIDE {
+ const char* GetNameForLogging() const override {
return "GenericResourceThrottle";
}
@@ -659,14 +660,11 @@ class TestResourceDispatcherHostDelegate
// ResourceDispatcherHostDelegate implementation:
- virtual void RequestBeginning(
- net::URLRequest* request,
- ResourceContext* resource_context,
- appcache::AppCacheService* appcache_service,
- ResourceType::Type resource_type,
- int child_id,
- int route_id,
- ScopedVector<ResourceThrottle>* throttles) OVERRIDE {
+ void RequestBeginning(net::URLRequest* request,
+ ResourceContext* resource_context,
+ AppCacheService* appcache_service,
+ ResourceType resource_type,
+ ScopedVector<ResourceThrottle>* throttles) override {
if (user_data_) {
const void* key = user_data_.get();
request->SetUserData(key, user_data_.release());
@@ -733,7 +731,7 @@ class ResourceDispatcherHostTest : public testing::Test,
}
// IPC::Sender implementation
- virtual bool Send(IPC::Message* msg) OVERRIDE {
+ bool Send(IPC::Message* msg) override {
accum_.AddMessage(*msg);
if (send_data_received_acks_ &&
@@ -755,12 +753,12 @@ class ResourceDispatcherHostTest : public testing::Test,
friend class TestURLRequestJobFactory;
// testing::Test
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ChildProcessSecurityPolicyImpl::GetInstance()->Add(0);
HandleScheme("test");
}
- virtual void TearDown() {
+ void TearDown() override {
EXPECT_TRUE(URLRequestTestDelayedStartJob::DelayedStartQueueEmpty());
URLRequestTestDelayedStartJob::ClearQueue();
@@ -778,8 +776,6 @@ class ResourceDispatcherHostTest : public testing::Test,
ResourceDispatcherHostImpl::Get()->CancelRequestsForContext(
browser_context_->GetResourceContext());
- WorkerServiceImpl::GetInstance()->PerformTeardownForTesting();
-
browser_context_.reset();
base::RunLoop().RunUntilIdle();
}
@@ -801,9 +797,10 @@ class ResourceDispatcherHostTest : public testing::Test,
// Generates a request using the given filter and resource type.
void MakeTestRequestWithResourceType(ResourceMessageFilter* filter,
- int render_view_id, int request_id,
+ int render_view_id,
+ int request_id,
const GURL& url,
- ResourceType::Type type);
+ ResourceType type);
void CancelRequest(int request_id);
void RendererCancelRequest(int request_id) {
@@ -895,7 +892,7 @@ void ResourceDispatcherHostTest::MakeTestRequest(int render_view_id,
int request_id,
const GURL& url) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
- url, ResourceType::SUB_RESOURCE);
+ url, RESOURCE_TYPE_SUB_RESOURCE);
}
void ResourceDispatcherHostTest::MakeTestRequestWithResourceType(
@@ -903,7 +900,7 @@ void ResourceDispatcherHostTest::MakeTestRequestWithResourceType(
int render_view_id,
int request_id,
const GURL& url,
- ResourceType::Type type) {
+ ResourceType type) {
ResourceHostMsg_Request request =
CreateResourceRequest("GET", type, url);
ResourceHostMsg_RequestResource msg(render_view_id, request_id, request);
@@ -1042,7 +1039,7 @@ TEST_F(ResourceDispatcherHostTest, TestMany) {
MakeTestRequest(0, 3, net::URLRequestTestJob::test_url_3());
MakeTestRequestWithResourceType(filter_.get(), 0, 4,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
MakeTestRequest(0, 5, net::URLRequestTestJob::test_url_redirect_to_url_2());
// Finish the redirection
@@ -1076,7 +1073,7 @@ TEST_F(ResourceDispatcherHostTest, Cancel) {
MakeTestRequestWithResourceType(filter_.get(), 0, 4,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
CancelRequest(2);
@@ -1127,7 +1124,7 @@ TEST_F(ResourceDispatcherHostTest, Cancel) {
TEST_F(ResourceDispatcherHostTest, DetachedResourceTimesOut) {
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_2(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
GlobalRequestID global_request_id(filter_->child_id(), 1);
ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(
host_.GetURLRequest(global_request_id));
@@ -1169,14 +1166,14 @@ TEST_F(ResourceDispatcherHostTest, DetachedResourceTimesOut) {
TEST_F(ResourceDispatcherHostTest, DeletedFilterDetached) {
// test_url_1's data is available synchronously, so use 2 and 3.
ResourceHostMsg_Request request_prefetch = CreateResourceRequest(
- "GET", ResourceType::PREFETCH, net::URLRequestTestJob::test_url_2());
+ "GET", RESOURCE_TYPE_PREFETCH, net::URLRequestTestJob::test_url_2());
ResourceHostMsg_Request request_ping = CreateResourceRequest(
- "GET", ResourceType::PING, net::URLRequestTestJob::test_url_3());
+ "GET", RESOURCE_TYPE_PING, net::URLRequestTestJob::test_url_3());
ResourceHostMsg_RequestResource msg_prefetch(0, 1, request_prefetch);
- host_.OnMessageReceived(msg_prefetch, filter_);
+ host_.OnMessageReceived(msg_prefetch, filter_.get());
ResourceHostMsg_RequestResource msg_ping(0, 2, request_ping);
- host_.OnMessageReceived(msg_ping, filter_);
+ host_.OnMessageReceived(msg_ping, filter_.get());
// Remove the filter before processing the requests by simulating channel
// closure.
@@ -1220,11 +1217,11 @@ TEST_F(ResourceDispatcherHostTest, DeletedFilterDetached) {
// resources should continue to load, even when redirected.
TEST_F(ResourceDispatcherHostTest, DeletedFilterDetachedRedirect) {
ResourceHostMsg_Request request = CreateResourceRequest(
- "GET", ResourceType::PREFETCH,
+ "GET", RESOURCE_TYPE_PREFETCH,
net::URLRequestTestJob::test_url_redirect_to_url_2());
ResourceHostMsg_RequestResource msg(0, 1, request);
- host_.OnMessageReceived(msg, filter_);
+ host_.OnMessageReceived(msg, filter_.get());
// Remove the filter before processing the request by simulating channel
// closure.
@@ -1300,7 +1297,7 @@ TEST_F(ResourceDispatcherHostTest, DetachWhileStartIsDeferred) {
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_1(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
// Cancel request must come from the renderer for a detachable resource to
// detach.
RendererCancelRequest(1);
@@ -1370,7 +1367,7 @@ TEST_F(ResourceDispatcherHostTest, PausedStartError) {
EXPECT_EQ(0, host_.pending_requests());
}
-// Test the OnBeforeNetworkStart throttle.
+// Test the WillStartUsingNetwork throttle.
TEST_F(ResourceDispatcherHostTest, ThrottleNetworkStart) {
// Arrange to have requests deferred before processing response headers.
TestResourceDispatcherHostDelegate delegate;
@@ -1466,11 +1463,11 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
// request 1 goes to the test delegate
ResourceHostMsg_Request request = CreateResourceRequest(
- "GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1());
+ "GET", RESOURCE_TYPE_SUB_RESOURCE, net::URLRequestTestJob::test_url_1());
MakeTestRequestWithResourceType(test_filter.get(), 0, 1,
net::URLRequestTestJob::test_url_1(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
// request 2 goes to us
MakeTestRequest(0, 2, net::URLRequestTestJob::test_url_2());
@@ -1478,12 +1475,12 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
// request 3 goes to the test delegate
MakeTestRequestWithResourceType(test_filter.get(), 0, 3,
net::URLRequestTestJob::test_url_3(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
// request 4 goes to us
MakeTestRequestWithResourceType(filter_.get(), 0, 4,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
// Make sure all requests have finished stage one. test_url_1 will have
@@ -1540,7 +1537,7 @@ TEST_F(ResourceDispatcherHostTest, TestProcessCancel) {
TEST_F(ResourceDispatcherHostTest, TestProcessCancelDetachedTimesOut) {
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
GlobalRequestID global_request_id(filter_->child_id(), 1);
ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(
host_.GetURLRequest(global_request_id));
@@ -1651,7 +1648,7 @@ TEST_F(ResourceDispatcherHostTest, TestBlockingCancelingRequests) {
// Blocked detachable resources should not delay cancellation.
MakeTestRequestWithResourceType(filter_.get(), 1, 5,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
// Flush all the pending requests.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1685,19 +1682,19 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsProcessDies) {
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_1(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(second_filter.get(), 0, 2,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(filter_.get(), 0, 3,
net::URLRequestTestJob::test_url_3(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(second_filter.get(), 0, 4,
net::URLRequestTestJob::test_url_1(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(second_filter.get(), 0, 5,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
// Simulate process death.
host_.CancelRequestsForProcess(second_filter->child_id());
@@ -1733,28 +1730,28 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
MakeTestRequestWithResourceType(filter_.get(), 0, 1,
net::URLRequestTestJob::test_url_1(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(filter_.get(), 1, 2,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(filter_.get(), 0, 3,
net::URLRequestTestJob::test_url_3(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(second_filter.get(), 1, 4,
net::URLRequestTestJob::test_url_1(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(filter_.get(), 2, 5,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(filter_.get(), 2, 6,
net::URLRequestTestJob::test_url_3(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(filter_.get(), 0, 7,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
MakeTestRequestWithResourceType(second_filter.get(), 1, 8,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
host_.CancelRequestsForProcess(filter_->child_id());
host_.CancelRequestsForProcess(second_filter->child_id());
@@ -1766,15 +1763,17 @@ TEST_F(ResourceDispatcherHostTest, TestBlockedRequestsDontLeak) {
// Test the private helper method "CalculateApproximateMemoryCost()".
TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
net::URLRequestContext context;
- net::URLRequest req(
- GURL("http://www.google.com"), net::DEFAULT_PRIORITY, NULL, &context);
- EXPECT_EQ(4427,
- ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(&req));
+ scoped_ptr<net::URLRequest> req(context.CreateRequest(
+ GURL("http://www.google.com"), net::DEFAULT_PRIORITY, NULL, NULL));
+ EXPECT_EQ(
+ 4427,
+ ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(req.get()));
// Add 9 bytes of referrer.
- req.SetReferrer("123456789");
- EXPECT_EQ(4436,
- ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(&req));
+ req->SetReferrer("123456789");
+ EXPECT_EQ(
+ 4436,
+ ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(req.get()));
// Add 33 bytes of upload content.
std::string upload_content;
@@ -1782,12 +1781,13 @@ TEST_F(ResourceDispatcherHostTest, CalculateApproximateMemoryCost) {
std::fill(upload_content.begin(), upload_content.end(), 'x');
scoped_ptr<net::UploadElementReader> reader(new net::UploadBytesElementReader(
upload_content.data(), upload_content.size()));
- req.set_upload(make_scoped_ptr(
- net::UploadDataStream::CreateWithReader(reader.Pass(), 0)));
+ req->set_upload(
+ net::ElementsUploadDataStream::CreateWithReader(reader.Pass(), 0));
// Since the upload throttling is disabled, this has no effect on the cost.
- EXPECT_EQ(4436,
- ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(&req));
+ EXPECT_EQ(
+ 4436,
+ ResourceDispatcherHostImpl::CalculateApproximateMemoryCost(req.get()));
}
// Test that too much memory for outstanding requests for a particular
@@ -1815,25 +1815,25 @@ TEST_F(ResourceDispatcherHostTest, TooMuchOutstandingRequestsMemory) {
for (size_t i = 0; i < kMaxRequests; ++i) {
MakeTestRequestWithResourceType(filter_.get(), 0, i + 1,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
}
// Issue two more requests for our process -- these should fail immediately.
MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequests + 1,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequests + 2,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
// Issue two requests for the second process -- these should succeed since
// it is just process 0 that is saturated.
MakeTestRequestWithResourceType(second_filter.get(), 0, kMaxRequests + 3,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
MakeTestRequestWithResourceType(second_filter.get(), 0, kMaxRequests + 4,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
// Flush all the pending requests.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -1884,25 +1884,25 @@ TEST_F(ResourceDispatcherHostTest, TooManyOutstandingRequests) {
for (size_t i = 0; i < kMaxRequestsPerProcess; ++i) {
MakeTestRequestWithResourceType(filter_.get(), 0, i + 1,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
}
// Issue another request for our process -- this should fail immediately.
MakeTestRequestWithResourceType(filter_.get(), 0, kMaxRequestsPerProcess + 1,
net::URLRequestTestJob::test_url_2(),
- ResourceType::SUB_RESOURCE);
+ RESOURCE_TYPE_SUB_RESOURCE);
// Issue a request for the second process -- this should succeed, because it
// is just process 0 that is saturated.
MakeTestRequestWithResourceType(
second_filter.get(), 0, kMaxRequestsPerProcess + 2,
- net::URLRequestTestJob::test_url_2(), ResourceType::SUB_RESOURCE);
+ net::URLRequestTestJob::test_url_2(), RESOURCE_TYPE_SUB_RESOURCE);
// Issue a request for the third process -- this should fail, because the
// global limit has been reached.
MakeTestRequestWithResourceType(
third_filter.get(), 0, kMaxRequestsPerProcess + 3,
- net::URLRequestTestJob::test_url_2(), ResourceType::SUB_RESOURCE);
+ net::URLRequestTestJob::test_url_2(), RESOURCE_TYPE_SUB_RESOURCE);
// Flush all the pending requests.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -2046,7 +2046,7 @@ TEST_F(ResourceDispatcherHostTest, ForbiddenDownload) {
// Only MAIN_FRAMEs can trigger a download.
MakeTestRequestWithResourceType(filter_.get(), 0, 1, GURL("http:bla"),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
// Flush all pending requests.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -2092,7 +2092,7 @@ TEST_F(ResourceDispatcherHostTest, IgnoreCancelForDownloads) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
// Return some data so that the request is identified as a download
// and the proper resource handlers are created.
EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
@@ -2127,7 +2127,7 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContext) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
// Return some data so that the request is identified as a download
// and the proper resource handlers are created.
EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
@@ -2158,7 +2158,7 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextDetached) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
net::URLRequestTestJob::test_url_4(),
- ResourceType::PREFETCH); // detachable type
+ RESOURCE_TYPE_PREFETCH); // detachable type
// Simulate a cancel coming from the renderer.
RendererCancelRequest(request_id);
@@ -2194,7 +2194,7 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
GlobalRequestID global_request_id(filter_->child_id(), request_id);
@@ -2243,7 +2243,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationHtml) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
// Now that we're blocked on the redirect, update the response and unblock by
// telling the AsyncResourceHandler to follow the redirect.
@@ -2269,7 +2269,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationHtml) {
int new_request_id = 2;
ResourceHostMsg_Request request =
- CreateResourceRequest("GET", ResourceType::MAIN_FRAME,
+ CreateResourceRequest("GET", RESOURCE_TYPE_MAIN_FRAME,
GURL("http://other.com/blech"));
request.transferred_request_child_id = filter_->child_id();
request.transferred_request_request_id = request_id;
@@ -2288,6 +2288,88 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationHtml) {
CheckSuccessfulRequest(msgs[1], kResponseBody);
}
+// Test transferring two navigations with text/html, to ensure the resource
+// accounting works.
+TEST_F(ResourceDispatcherHostTest, TransferTwoNavigationsHtml) {
+ // 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.
+ const std::string kResponseBody = "hello world";
+ SetResponse("HTTP/1.1 200 OK\n"
+ "Content-Type: text/html\n\n",
+ kResponseBody);
+
+ HandleScheme("http");
+
+ // Temporarily replace ContentBrowserClient with one that will trigger the
+ // transfer navigation code paths.
+ TransfersAllNavigationsContentBrowserClient new_client;
+ ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client);
+
+ // Make the first request.
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
+ GURL("http://example.com/blah"),
+ RESOURCE_TYPE_MAIN_FRAME);
+
+ // Make a second request from the same process.
+ int second_request_id = 2;
+ MakeTestRequestWithResourceType(filter_.get(), render_view_id,
+ second_request_id,
+ GURL("http://example.com/foo"),
+ RESOURCE_TYPE_MAIN_FRAME);
+
+ // Flush all the pending requests to get the response through the
+ // BufferedResourceHandler.
+ 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();
+
+ // Transfer the first request.
+ int new_render_view_id = 1;
+ int new_request_id = 5;
+ ResourceHostMsg_Request request =
+ CreateResourceRequest("GET", RESOURCE_TYPE_MAIN_FRAME,
+ GURL("http://example.com/blah"));
+ request.transferred_request_child_id = filter_->child_id();
+ request.transferred_request_request_id = request_id;
+
+ 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();
+
+ // Transfer the second request.
+ int new_second_request_id = 6;
+ ResourceHostMsg_Request second_request =
+ CreateResourceRequest("GET", RESOURCE_TYPE_MAIN_FRAME,
+ GURL("http://example.com/foo"));
+ request.transferred_request_child_id = filter_->child_id();
+ request.transferred_request_request_id = second_request_id;
+
+ ResourceHostMsg_RequestResource second_transfer_request_msg(
+ new_render_view_id, new_second_request_id, second_request);
+ host_.OnMessageReceived(second_transfer_request_msg, second_filter.get());
+ base::MessageLoop::current()->RunUntilIdle();
+
+ // Check generated messages.
+ ResourceIPCAccumulator::ClassifiedMessages msgs;
+ accum_.GetClassifiedMessages(&msgs);
+
+ ASSERT_EQ(2U, msgs.size());
+ CheckSuccessfulRequest(msgs[0], kResponseBody);
+}
+
// Test transferred navigations with text/plain, which causes
// BufferedResourceHandler to buffer the response to sniff the content
// before the transfer occurs.
@@ -2314,7 +2396,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationText) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
// Now that we're blocked on the redirect, update the response and unblock by
// telling the AsyncResourceHandler to follow the redirect. Use a text/plain
@@ -2342,7 +2424,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationText) {
int new_request_id = 2;
ResourceHostMsg_Request request =
- CreateResourceRequest("GET", ResourceType::MAIN_FRAME,
+ CreateResourceRequest("GET", RESOURCE_TYPE_MAIN_FRAME,
GURL("http://other.com/blech"));
request.transferred_request_child_id = filter_->child_id();
request.transferred_request_request_id = request_id;
@@ -2390,7 +2472,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
first_child_id = first_filter->child_id();
ResourceHostMsg_Request first_request =
- CreateResourceRequest("GET", ResourceType::MAIN_FRAME,
+ CreateResourceRequest("GET", RESOURCE_TYPE_MAIN_FRAME,
GURL("http://example.com/blah"));
ResourceHostMsg_RequestResource first_request_msg(
@@ -2426,7 +2508,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) {
int new_request_id = 2;
ResourceHostMsg_Request request =
- CreateResourceRequest("GET", ResourceType::MAIN_FRAME,
+ CreateResourceRequest("GET", RESOURCE_TYPE_MAIN_FRAME,
GURL("http://other.com/blech"));
request.transferred_request_child_id = first_child_id;
request.transferred_request_request_id = request_id;
@@ -2470,7 +2552,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
// Now that we're blocked on the redirect, simulate hitting another redirect.
SetResponse("HTTP/1.1 302 Found\n"
@@ -2505,7 +2587,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
int new_request_id = 2;
ResourceHostMsg_Request request =
- CreateResourceRequest("GET", ResourceType::MAIN_FRAME,
+ CreateResourceRequest("GET", RESOURCE_TYPE_MAIN_FRAME,
GURL("http://other.com/blech"));
request.transferred_request_child_id = filter_->child_id();
request.transferred_request_request_id = request_id;
@@ -2523,7 +2605,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) {
EXPECT_EQ(second_filter->child_id(), info->GetChildID());
EXPECT_EQ(new_render_view_id, info->GetRouteID());
EXPECT_EQ(new_request_id, info->GetRequestID());
- EXPECT_EQ(second_filter, info->filter());
+ EXPECT_EQ(second_filter.get(), info->filter());
// Let request complete.
base::MessageLoop::current()->RunUntilIdle();
@@ -2543,7 +2625,7 @@ TEST_F(ResourceDispatcherHostTest, UnknownURLScheme) {
HandleScheme("http");
MakeTestRequestWithResourceType(filter_.get(), 0, 1, GURL("foo://bar"),
- ResourceType::MAIN_FRAME);
+ RESOURCE_TYPE_MAIN_FRAME);
// Flush all pending requests.
while (net::URLRequestTestJob::ProcessOnePendingMessage()) {}
@@ -2605,7 +2687,7 @@ TEST_F(ResourceDispatcherHostTest, DataSentBeforeDetach) {
MakeTestRequestWithResourceType(filter_.get(), render_view_id, request_id,
GURL("http://example.com/blah"),
- ResourceType::PREFETCH);
+ RESOURCE_TYPE_PREFETCH);
// Get a bit of data before cancelling.
EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
@@ -2764,7 +2846,7 @@ TEST_F(ResourceDispatcherHostTest, RegisterDownloadedTempFile) {
// The child releases from the request.
ResourceHostMsg_ReleaseDownloadedFile release_msg(kRequestID);
- host_.OnMessageReceived(release_msg, filter_);
+ host_.OnMessageReceived(release_msg, filter_.get());
// Still readable because there is another reference to the file. (The child
// may take additional blob references.)
@@ -2819,10 +2901,10 @@ TEST_F(ResourceDispatcherHostTest, ReleaseTemporiesOnProcessExit) {
TEST_F(ResourceDispatcherHostTest, DownloadToFile) {
// Make a request which downloads to file.
ResourceHostMsg_Request request = CreateResourceRequest(
- "GET", ResourceType::SUB_RESOURCE, net::URLRequestTestJob::test_url_1());
+ "GET", RESOURCE_TYPE_SUB_RESOURCE, net::URLRequestTestJob::test_url_1());
request.download_to_file = true;
ResourceHostMsg_RequestResource request_msg(0, 1, request);
- host_.OnMessageReceived(request_msg, filter_);
+ host_.OnMessageReceived(request_msg, filter_.get());
// Running the message loop until idle does not work because
// RedirectToFileResourceHandler posts things to base::WorkerPool. Instead,
@@ -2877,7 +2959,7 @@ TEST_F(ResourceDispatcherHostTest, DownloadToFile) {
// RunUntilIdle doesn't work because base::WorkerPool is involved.
ShareableFileReleaseWaiter waiter(response_head.download_file_path);
ResourceHostMsg_ReleaseDownloadedFile release_msg(1);
- host_.OnMessageReceived(release_msg, filter_);
+ host_.OnMessageReceived(release_msg, filter_.get());
waiter.Wait();
// The release callback runs before the delete is scheduled, so pump the
// message loop for the delete itself. (This relies on the delete happening on
@@ -2927,4 +3009,17 @@ net::URLRequestJob* TestURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
}
}
+net::URLRequestJob* TestURLRequestJobFactory::MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const {
+ return nullptr;
+}
+
+net::URLRequestJob* TestURLRequestJobFactory::MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const {
+ return nullptr;
+}
+
} // namespace content
diff --git a/chromium/content/browser/loader/resource_handler.h b/chromium/content/browser/loader/resource_handler.h
index a9d8a38aaa9..306a672616c 100644
--- a/chromium/content/browser/loader/resource_handler.h
+++ b/chromium/content/browser/loader/resource_handler.h
@@ -25,6 +25,7 @@ namespace net {
class IOBuffer;
class URLRequest;
class URLRequestStatus;
+struct RedirectInfo;
} // namespace net
namespace content {
@@ -51,7 +52,7 @@ class CONTENT_EXPORT ResourceHandler
// false. Set |*defer| to true to defer the redirect. The redirect may be
// followed later on via ResourceDispatcherHost::FollowDeferredRedirect. If
// the handler returns false, then the request is cancelled.
- virtual bool OnRequestRedirected(const GURL& url,
+ virtual bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
ResourceResponse* response,
bool* defer) = 0;
diff --git a/chromium/content/browser/loader/resource_loader.cc b/chromium/content/browser/loader/resource_loader.cc
index 0becbf42a3d..eae75eb4be5 100644
--- a/chromium/content/browser/loader/resource_loader.cc
+++ b/chromium/content/browser/loader/resource_loader.cc
@@ -14,6 +14,7 @@
#include "content/browser/loader/detachable_resource_handler.h"
#include "content/browser/loader/resource_loader_delegate.h"
#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/browser/service_worker/service_worker_request_handler.h"
#include "content/browser/ssl/ssl_client_auth_handler.h"
#include "content/browser/ssl/ssl_manager.h"
#include "content/common/ssl_status_serialization.h"
@@ -29,6 +30,7 @@
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "net/ssl/client_cert_store.h"
+#include "net/url_request/redirect_info.h"
#include "net/url_request/url_request_status.h"
using base::TimeDelta;
@@ -37,9 +39,9 @@ using base::TimeTicks;
namespace content {
namespace {
-void PopulateResourceResponse(net::URLRequest* request,
+void PopulateResourceResponse(ResourceRequestInfoImpl* info,
+ net::URLRequest* request,
ResourceResponse* response) {
- response->head.error_code = request->status().error();
response->head.request_time = request->request_time();
response->head.response_time = request->response_time();
response->head.headers = request->response_headers();
@@ -53,13 +55,24 @@ void PopulateResourceResponse(net::URLRequest* request,
response_info.npn_negotiated_protocol;
response->head.connection_info = response_info.connection_info;
response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
+ response->head.proxy_server = response_info.proxy_server;
response->head.socket_address = request->GetSocketAddress();
+ if (ServiceWorkerRequestHandler* handler =
+ ServiceWorkerRequestHandler::GetHandler(request)) {
+ handler->GetExtraResponseInfo(
+ &response->head.was_fetched_via_service_worker,
+ &response->head.was_fallback_required_by_service_worker,
+ &response->head.original_url_via_service_worker,
+ &response->head.response_type_via_service_worker,
+ &response->head.service_worker_fetch_start,
+ &response->head.service_worker_fetch_ready,
+ &response->head.service_worker_fetch_end);
+ }
AppCacheInterceptor::GetExtraResponseInfo(
request,
&response->head.appcache_id,
&response->head.appcache_manifest_url);
- // TODO(mmenke): Figure out if LOAD_ENABLE_LOAD_TIMING is safe to remove.
- if (request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)
+ if (info->is_load_timing_enabled())
request->GetLoadTimingInfo(&response->head.load_timing);
}
@@ -83,8 +96,7 @@ ResourceLoader::ResourceLoader(scoped_ptr<net::URLRequest> request,
ResourceLoader::~ResourceLoader() {
if (login_delegate_.get())
login_delegate_->OnRequestCancelled();
- if (ssl_client_auth_handler_.get())
- ssl_client_auth_handler_->OnRequestCancelled();
+ ssl_client_auth_handler_.reset();
// Run ResourceHandler destructor before we tear-down the rest of our state
// as the ResourceHandler may want to inspect the URLRequest and other state.
@@ -148,7 +160,8 @@ void ResourceLoader::ReportUploadProgress() {
bool too_much_time_passed = time_since_last > kOneSecond;
if (is_finished || enough_new_progress || too_much_time_passed) {
- if (request_->load_flags() & net::LOAD_ENABLE_UPLOAD_PROGRESS) {
+ ResourceRequestInfoImpl* info = GetRequestInfo();
+ if (info->is_upload_progress_enabled()) {
handler_->OnUploadProgress(progress.position(), progress.size());
waiting_for_upload_progress_ack_ = true;
}
@@ -158,7 +171,7 @@ void ResourceLoader::ReportUploadProgress() {
}
void ResourceLoader::MarkAsTransferring() {
- CHECK(ResourceType::IsFrame(GetRequestInfo()->GetResourceType()))
+ CHECK(IsResourceTypeFrame(GetRequestInfo()->GetResourceType()))
<< "Can only transfer for navigations";
is_transferring_ = true;
}
@@ -183,16 +196,12 @@ void ResourceLoader::ClearLoginDelegate() {
login_delegate_ = NULL;
}
-void ResourceLoader::ClearSSLClientAuthHandler() {
- ssl_client_auth_handler_ = NULL;
-}
-
void ResourceLoader::OnUploadProgressACK() {
waiting_for_upload_progress_ack_ = false;
}
void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
- const GURL& new_url,
+ const net::RedirectInfo& redirect_info,
bool* defer) {
DCHECK_EQ(request_.get(), unused);
@@ -203,27 +212,27 @@ void ResourceLoader::OnReceivedRedirect(net::URLRequest* unused,
if (info->GetProcessType() != PROCESS_TYPE_PLUGIN &&
!ChildProcessSecurityPolicyImpl::GetInstance()->
- CanRequestURL(info->GetChildID(), new_url)) {
+ CanRequestURL(info->GetChildID(), redirect_info.new_url)) {
VLOG(1) << "Denied unauthorized request for "
- << new_url.possibly_invalid_spec();
+ << redirect_info.new_url.possibly_invalid_spec();
// Tell the renderer that this request was disallowed.
Cancel();
return;
}
- delegate_->DidReceiveRedirect(this, new_url);
+ delegate_->DidReceiveRedirect(this, redirect_info.new_url);
- if (delegate_->HandleExternalProtocol(this, new_url)) {
+ if (delegate_->HandleExternalProtocol(this, redirect_info.new_url)) {
// The request is complete so we can remove it.
CancelAndIgnore();
return;
}
scoped_refptr<ResourceResponse> response(new ResourceResponse());
- PopulateResourceResponse(request_.get(), response.get());
+ PopulateResourceResponse(info, request_.get(), response.get());
- if (!handler_->OnRequestRedirected(new_url, response.get(), defer)) {
+ if (!handler_->OnRequestRedirected(redirect_info, response.get(), defer)) {
Cancel();
} else if (*defer) {
deferred_stage_ = DEFERRED_REDIRECT; // Follow redirect when resumed.
@@ -259,12 +268,14 @@ void ResourceLoader::OnCertificateRequested(
return;
}
- DCHECK(!ssl_client_auth_handler_.get())
+ DCHECK(!ssl_client_auth_handler_)
<< "OnCertificateRequested called with ssl_client_auth_handler pending";
- ssl_client_auth_handler_ = new SSLClientAuthHandler(
+ ssl_client_auth_handler_.reset(new SSLClientAuthHandler(
GetRequestInfo()->GetContext()->CreateClientCertStore(),
request_.get(),
- cert_info);
+ cert_info,
+ base::Bind(&ResourceLoader::ContinueWithCertificate,
+ weak_ptr_factory_.GetWeakPtr())));
ssl_client_auth_handler_->SelectCertificate();
}
@@ -280,7 +291,6 @@ void ResourceLoader::OnSSLCertificateError(net::URLRequest* request,
SSLManager::OnSSLCertificateError(
weak_ptr_factory_.GetWeakPtr(),
- info->GetGlobalRequestID(),
info->GetResourceType(),
request_->url(),
render_process_id,
@@ -375,8 +385,7 @@ void ResourceLoader::OnReadCompleted(net::URLRequest* unused, int bytes_read) {
}
}
-void ResourceLoader::CancelSSLRequest(const GlobalRequestID& id,
- int error,
+void ResourceLoader::CancelSSLRequest(int error,
const net::SSLInfo* ssl_info) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -393,7 +402,7 @@ void ResourceLoader::CancelSSLRequest(const GlobalRequestID& id,
}
}
-void ResourceLoader::ContinueSSLRequest(const GlobalRequestID& id) {
+void ResourceLoader::ContinueSSLRequest() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DVLOG(1) << "ContinueSSLRequest() url: " << request_->url().spec();
@@ -483,10 +492,7 @@ void ResourceLoader::CancelRequestInternal(int error, bool from_renderer) {
login_delegate_->OnRequestCancelled();
login_delegate_ = NULL;
}
- if (ssl_client_auth_handler_.get()) {
- ssl_client_auth_handler_->OnRequestCancelled();
- ssl_client_auth_handler_ = NULL;
- }
+ ssl_client_auth_handler_.reset();
request_->CancelWithError(error);
@@ -510,7 +516,7 @@ void ResourceLoader::StoreSignedCertificateTimestamps(
for (net::SignedCertificateTimestampAndStatusList::const_iterator iter =
sct_list.begin(); iter != sct_list.end(); ++iter) {
- const int sct_id(sct_store->Store(iter->sct, process_id));
+ const int sct_id(sct_store->Store(iter->sct.get(), process_id));
sct_ids->push_back(
SignedCertificateTimestampIDAndStatus(sct_id, iter->status));
}
@@ -520,7 +526,7 @@ void ResourceLoader::CompleteResponseStarted() {
ResourceRequestInfoImpl* info = GetRequestInfo();
scoped_refptr<ResourceResponse> response(new ResourceResponse());
- PopulateResourceResponse(request_.get(), response.get());
+ PopulateResourceResponse(info, request_.get(), response.get());
if (request_->ssl_info().cert.get()) {
int cert_id = CertStore::GetInstance()->StoreCert(
@@ -606,7 +612,7 @@ void ResourceLoader::ReadMore(int* bytes_read) {
return;
}
- DCHECK(buf);
+ DCHECK(buf.get());
DCHECK(buf_size > 0);
request_->Read(buf.get(), buf_size, bytes_read);
@@ -672,7 +678,7 @@ void ResourceLoader::CallDidFinishLoading() {
void ResourceLoader::RecordHistograms() {
ResourceRequestInfoImpl* info = GetRequestInfo();
- if (info->GetResourceType() == ResourceType::PREFETCH) {
+ if (info->GetResourceType() == RESOURCE_TYPE_PREFETCH) {
PrefetchStatus status = STATUS_UNDEFINED;
TimeDelta total_time = base::TimeTicks::Now() - request_->creation_time();
@@ -702,4 +708,9 @@ void ResourceLoader::RecordHistograms() {
}
}
+void ResourceLoader::ContinueWithCertificate(net::X509Certificate* cert) {
+ ssl_client_auth_handler_.reset();
+ request_->ContinueWithCertificate(cert);
+}
+
} // namespace content
diff --git a/chromium/content/browser/loader/resource_loader.h b/chromium/content/browser/loader/resource_loader.h
index d06f58ca617..d740ec03b06 100644
--- a/chromium/content/browser/loader/resource_loader.h
+++ b/chromium/content/browser/loader/resource_loader.h
@@ -15,6 +15,10 @@
#include "content/public/common/signed_certificate_timestamp_id_and_status.h"
#include "net/url_request/url_request.h"
+namespace net {
+class X509Certificate;
+}
+
namespace content {
class ResourceDispatcherHostLoginDelegate;
class ResourceLoaderDelegate;
@@ -31,7 +35,7 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
ResourceLoader(scoped_ptr<net::URLRequest> request,
scoped_ptr<ResourceHandler> handler,
ResourceLoaderDelegate* delegate);
- virtual ~ResourceLoader();
+ ~ResourceLoader() override;
void StartRequest();
void CancelRequest(bool from_renderer);
@@ -46,7 +50,6 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
ResourceRequestInfoImpl* GetRequestInfo();
void ClearLoginDelegate();
- void ClearSSLClientAuthHandler();
// IPC message handlers:
void OnUploadProgressACK();
@@ -56,33 +59,29 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
FRIEND_TEST_ALL_PREFIXES(ResourceLoaderTest, ClientCertStoreNull);
// net::URLRequest::Delegate implementation:
- virtual void OnReceivedRedirect(net::URLRequest* request,
- const GURL& new_url,
- bool* defer) OVERRIDE;
- virtual void OnAuthRequired(net::URLRequest* request,
- net::AuthChallengeInfo* info) OVERRIDE;
- virtual void OnCertificateRequested(net::URLRequest* request,
- net::SSLCertRequestInfo* info) OVERRIDE;
- virtual void OnSSLCertificateError(net::URLRequest* request,
- const net::SSLInfo& info,
- bool fatal) OVERRIDE;
- virtual void OnBeforeNetworkStart(net::URLRequest* request,
- bool* defer) OVERRIDE;
- virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
- virtual void OnReadCompleted(net::URLRequest* request,
- int bytes_read) OVERRIDE;
+ void OnReceivedRedirect(net::URLRequest* request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer) override;
+ void OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* info) override;
+ void OnCertificateRequested(net::URLRequest* request,
+ net::SSLCertRequestInfo* info) override;
+ void OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& info,
+ bool fatal) override;
+ void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override;
+ void OnResponseStarted(net::URLRequest* request) override;
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
// SSLErrorHandler::Delegate implementation:
- virtual void CancelSSLRequest(const GlobalRequestID& id,
- int error,
- const net::SSLInfo* ssl_info) OVERRIDE;
- virtual void ContinueSSLRequest(const GlobalRequestID& id) OVERRIDE;
+ void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) override;
+ void ContinueSSLRequest() override;
// ResourceController implementation:
- virtual void Resume() OVERRIDE;
- virtual void Cancel() OVERRIDE;
- virtual void CancelAndIgnore() OVERRIDE;
- virtual void CancelWithError(int error_code) OVERRIDE;
+ void Resume() override;
+ void Cancel() override;
+ void CancelAndIgnore() override;
+ void CancelWithError(int error_code) override;
void StartRequestInternal();
void CancelRequestInternal(int error, bool from_renderer);
@@ -103,6 +102,7 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
void ResponseCompleted();
void CallDidFinishLoading();
void RecordHistograms();
+ void ContinueWithCertificate(net::X509Certificate* cert);
bool is_deferred() const { return deferred_stage_ != DEFERRED_NONE; }
@@ -133,7 +133,7 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
ResourceLoaderDelegate* delegate_;
scoped_refptr<ResourceDispatcherHostLoginDelegate> login_delegate_;
- scoped_refptr<SSLClientAuthHandler> ssl_client_auth_handler_;
+ scoped_ptr<SSLClientAuthHandler> ssl_client_auth_handler_;
uint64 last_upload_position_;
bool waiting_for_upload_progress_ack_;
diff --git a/chromium/content/browser/loader/resource_loader_unittest.cc b/chromium/content/browser/loader/resource_loader_unittest.cc
index d2fdd99b3ba..635f566f7dd 100644
--- a/chromium/content/browser/loader/resource_loader_unittest.cc
+++ b/chromium/content/browser/loader/resource_loader_unittest.cc
@@ -4,8 +4,8 @@
#include "content/browser/loader/resource_loader.h"
-#include "base/file_util.h"
#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "content/browser/browser_thread_impl.h"
@@ -27,10 +27,10 @@
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
+#include "storage/common/blob/shareable_file_reference.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/common/blob/shareable_file_reference.h"
-using webkit_blob::ShareableFileReference;
+using storage::ShareableFileReference;
namespace content {
namespace {
@@ -44,7 +44,7 @@ class ClientCertStoreStub : public net::ClientCertStore {
: response_(certs),
request_count_(0) {}
- virtual ~ClientCertStoreStub() {}
+ ~ClientCertStoreStub() override {}
// Returns |cert_authorities| field of the certificate request passed in the
// most recent call to GetClientCerts().
@@ -62,9 +62,9 @@ class ClientCertStoreStub : public net::ClientCertStore {
}
// net::ClientCertStore:
- virtual void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
- net::CertificateList* selected_certs,
- const base::Closure& callback) OVERRIDE {
+ void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
+ net::CertificateList* selected_certs,
+ const base::Closure& callback) override {
++request_count_;
requested_authorities_ = cert_request_info.cert_authorities;
*selected_certs = response_;
@@ -127,39 +127,38 @@ class ResourceHandlerStub : public ResourceHandler {
}
// ResourceHandler implementation:
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE {
+ bool OnUploadProgress(uint64 position, uint64 size) override {
NOTREACHED();
return true;
}
- virtual bool OnRequestRedirected(const GURL& url,
- ResourceResponse* response,
- bool* defer) OVERRIDE {
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override {
NOTREACHED();
return true;
}
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE {
- EXPECT_FALSE(response_);
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override {
+ EXPECT_FALSE(response_.get());
response_ = response;
return true;
}
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE {
+ bool OnWillStart(const GURL& url, bool* defer) override {
EXPECT_TRUE(start_url_.is_empty());
start_url_ = url;
*defer = defer_request_on_will_start_;
return true;
}
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE {
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override {
return true;
}
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE {
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override {
EXPECT_TRUE(expect_reads_);
EXPECT_FALSE(received_on_will_read_);
EXPECT_FALSE(received_eof_);
@@ -171,7 +170,7 @@ class ResourceHandlerStub : public ResourceHandler {
return true;
}
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE {
+ bool OnReadCompleted(int bytes_read, bool* defer) override {
EXPECT_TRUE(received_on_will_read_);
EXPECT_TRUE(expect_reads_);
EXPECT_FALSE(received_response_completed_);
@@ -190,9 +189,9 @@ class ResourceHandlerStub : public ResourceHandler {
return !cancel_on_read_completed_;
}
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE {
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override {
EXPECT_FALSE(received_response_completed_);
if (status.is_success() && expect_reads_)
EXPECT_TRUE(received_eof_);
@@ -201,7 +200,7 @@ class ResourceHandlerStub : public ResourceHandler {
status_ = status;
}
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE {
+ void OnDataDownloaded(int bytes_downloaded) override {
EXPECT_FALSE(expect_reads_);
total_bytes_downloaded_ += bytes_downloaded;
}
@@ -229,12 +228,11 @@ class SelectCertificateBrowserClient : public TestContentBrowserClient {
public:
SelectCertificateBrowserClient() : call_count_(0) {}
- virtual void SelectClientCertificate(
+ void SelectClientCertificate(
int render_process_id,
int render_view_id,
- const net::HttpNetworkSession* network_session,
net::SSLCertRequestInfo* cert_request_info,
- const base::Callback<void(net::X509Certificate*)>& callback) OVERRIDE {
+ const base::Callback<void(net::X509Certificate*)>& callback) override {
++call_count_;
passed_certs_ = cert_request_info->client_certs;
}
@@ -257,7 +255,7 @@ class ResourceContextStub : public MockResourceContext {
explicit ResourceContextStub(net::URLRequestContext* test_request_context)
: MockResourceContext(test_request_context) {}
- virtual scoped_ptr<net::ClientCertStore> CreateClientCertStore() OVERRIDE {
+ scoped_ptr<net::ClientCertStore> CreateClientCertStore() override {
return dummy_cert_store_.Pass();
}
@@ -305,21 +303,22 @@ class ResourceLoaderTest : public testing::Test,
virtual scoped_ptr<ResourceHandler> WrapResourceHandler(
scoped_ptr<ResourceHandlerStub> leaf_handler,
net::URLRequest* request) {
- return leaf_handler.PassAs<ResourceHandler>();
+ return leaf_handler.Pass();
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
const int kRenderProcessId = 1;
const int kRenderViewId = 2;
scoped_ptr<net::URLRequest> request(
- new net::URLRequest(test_url(),
- net::DEFAULT_PRIORITY,
- NULL,
- resource_context_.GetRequestContext()));
+ resource_context_.GetRequestContext()->CreateRequest(
+ test_url(),
+ net::DEFAULT_PRIORITY,
+ NULL /* delegate */,
+ NULL /* cookie_store */));
raw_ptr_to_request_ = request.get();
ResourceRequestInfo::AllocateForTesting(request.get(),
- ResourceType::MAIN_FRAME,
+ RESOURCE_TYPE_MAIN_FRAME,
&resource_context_,
kRenderProcessId,
kRenderViewId,
@@ -335,20 +334,20 @@ class ResourceLoaderTest : public testing::Test,
}
// ResourceLoaderDelegate:
- virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
+ ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
ResourceLoader* loader,
- net::AuthChallengeInfo* auth_info) OVERRIDE {
+ net::AuthChallengeInfo* auth_info) override {
return NULL;
}
- virtual bool HandleExternalProtocol(ResourceLoader* loader,
- const GURL& url) OVERRIDE {
+ bool HandleExternalProtocol(ResourceLoader* loader,
+ const GURL& url) override {
return false;
}
- virtual void DidStartRequest(ResourceLoader* loader) OVERRIDE {}
- virtual void DidReceiveRedirect(ResourceLoader* loader,
- const GURL& new_url) OVERRIDE {}
- virtual void DidReceiveResponse(ResourceLoader* loader) OVERRIDE {}
- virtual void DidFinishLoading(ResourceLoader* loader) OVERRIDE {}
+ void DidStartRequest(ResourceLoader* loader) override {}
+ void DidReceiveRedirect(ResourceLoader* loader,
+ const GURL& new_url) override {}
+ void DidReceiveResponse(ResourceLoader* loader) override {}
+ void DidFinishLoading(ResourceLoader* loader) override {}
content::TestBrowserThreadBundle thread_bundle_;
@@ -377,8 +376,7 @@ TEST_F(ResourceLoaderTest, ClientCertStoreLookup) {
// Ownership of the |test_store| is about to be turned over to ResourceLoader.
// We need to keep raw pointer copies to access these objects later.
ClientCertStoreStub* raw_ptr_to_store = test_store.get();
- resource_context_.SetClientCertStore(
- test_store.PassAs<net::ClientCertStore>());
+ resource_context_.SetClientCertStore(test_store.Pass());
// Prepare a dummy certificate request.
scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
@@ -498,9 +496,9 @@ class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest {
loader_.reset();
}
- virtual scoped_ptr<ResourceHandler> WrapResourceHandler(
+ scoped_ptr<ResourceHandler> WrapResourceHandler(
scoped_ptr<ResourceHandlerStub> leaf_handler,
- net::URLRequest* request) OVERRIDE {
+ net::URLRequest* request) override {
leaf_handler->set_expect_reads(false);
// Make a temporary file.
@@ -523,14 +521,13 @@ class ResourceLoaderRedirectToFileTest : public ResourceLoaderTest {
// Inject them into the handler.
scoped_ptr<RedirectToFileResourceHandler> handler(
- new RedirectToFileResourceHandler(
- leaf_handler.PassAs<ResourceHandler>(), request));
+ new RedirectToFileResourceHandler(leaf_handler.Pass(), request));
redirect_to_file_resource_handler_ = handler.get();
handler->SetCreateTemporaryFileStreamFunctionForTesting(
base::Bind(&ResourceLoaderRedirectToFileTest::PostCallback,
base::Unretained(this),
- base::Passed(file_stream.PassAs<net::FileStream>())));
- return handler.PassAs<ResourceHandler>();
+ base::Passed(&file_stream)));
+ return handler.Pass();
}
private:
diff --git a/chromium/content/browser/loader/resource_message_filter.cc b/chromium/content/browser/loader/resource_message_filter.cc
index 137029cf644..9ffa29f5716 100644
--- a/chromium/content/browser/loader/resource_message_filter.cc
+++ b/chromium/content/browser/loader/resource_message_filter.cc
@@ -10,7 +10,7 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/resource_messages.h"
#include "content/public/browser/resource_context.h"
-#include "webkit/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_context.h"
namespace content {
@@ -19,7 +19,7 @@ ResourceMessageFilter::ResourceMessageFilter(
int process_type,
ChromeAppCacheService* appcache_service,
ChromeBlobStorageContext* blob_storage_context,
- fileapi::FileSystemContext* file_system_context,
+ storage::FileSystemContext* file_system_context,
ServiceWorkerContextWrapper* service_worker_context,
const GetContextsCallback& get_contexts_callback)
: BrowserMessageFilter(ResourceMsgStart),
diff --git a/chromium/content/browser/loader/resource_message_filter.h b/chromium/content/browser/loader/resource_message_filter.h
index 90af00e7e73..3b52a7773c0 100644
--- a/chromium/content/browser/loader/resource_message_filter.h
+++ b/chromium/content/browser/loader/resource_message_filter.h
@@ -10,13 +10,13 @@
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
-#include "webkit/common/resource_type.h"
+#include "content/public/common/resource_type.h"
struct ResourceHostMsg_Request;
-namespace fileapi {
+namespace storage {
class FileSystemContext;
-} // namespace fileapi
+} // namespace storage
namespace net {
class URLRequestContext;
@@ -42,26 +42,24 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
// |appcache_service|, |blob_storage_context|, |file_system_context| may be
// NULL in unittests or for requests from the (NPAPI) plugin process.
- ResourceMessageFilter(
- int child_id,
- int process_type,
- ChromeAppCacheService* appcache_service,
- ChromeBlobStorageContext* blob_storage_context,
- fileapi::FileSystemContext* file_system_context,
- ServiceWorkerContextWrapper* service_worker_context,
- const GetContextsCallback& get_contexts_callback);
+ ResourceMessageFilter(int child_id,
+ int process_type,
+ ChromeAppCacheService* appcache_service,
+ ChromeBlobStorageContext* blob_storage_context,
+ storage::FileSystemContext* file_system_context,
+ ServiceWorkerContextWrapper* service_worker_context,
+ const GetContextsCallback& get_contexts_callback);
// BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelClosing() override;
+ bool OnMessageReceived(const IPC::Message& message) override;
void GetContexts(const ResourceHostMsg_Request& request,
ResourceContext** resource_context,
net::URLRequestContext** request_context);
// Returns the net::URLRequestContext for the given request.
- net::URLRequestContext* GetURLRequestContext(
- ResourceType::Type request_type);
+ net::URLRequestContext* GetURLRequestContext(ResourceType request_type);
ChromeAppCacheService* appcache_service() const {
return appcache_service_.get();
@@ -71,7 +69,7 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
return blob_storage_context_.get();
}
- fileapi::FileSystemContext* file_system_context() const {
+ storage::FileSystemContext* file_system_context() const {
return file_system_context_.get();
}
@@ -86,7 +84,7 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
protected:
// Protected destructor so that we can be overriden in tests.
- virtual ~ResourceMessageFilter();
+ ~ResourceMessageFilter() override;
private:
// The ID of the child process.
@@ -96,7 +94,7 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter {
scoped_refptr<ChromeAppCacheService> appcache_service_;
scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
GetContextsCallback get_contexts_callback_;
diff --git a/chromium/content/browser/loader/resource_request_info_impl.cc b/chromium/content/browser/loader/resource_request_info_impl.cc
index 03d925ee786..8cae9a5c93b 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.cc
+++ b/chromium/content/browser/loader/resource_request_info_impl.cc
@@ -6,9 +6,9 @@
#include "content/browser/loader/global_routing_id.h"
#include "content/browser/loader/resource_message_filter.h"
-#include "content/browser/worker_host/worker_service_impl.h"
#include "content/common/net/url_request_user_data.h"
#include "content/public/browser/global_request_id.h"
+#include "content/public/common/process_type.h"
#include "net/url_request/url_request.h"
namespace content {
@@ -23,14 +23,13 @@ const ResourceRequestInfo* ResourceRequestInfo::ForRequest(
}
// static
-void ResourceRequestInfo::AllocateForTesting(
- net::URLRequest* request,
- ResourceType::Type resource_type,
- ResourceContext* context,
- int render_process_id,
- int render_view_id,
- int render_frame_id,
- bool is_async) {
+void ResourceRequestInfo::AllocateForTesting(net::URLRequest* request,
+ ResourceType resource_type,
+ ResourceContext* context,
+ int render_process_id,
+ int render_view_id,
+ int render_frame_id,
+ bool is_async) {
ResourceRequestInfoImpl* info =
new ResourceRequestInfoImpl(
PROCESS_TYPE_RENDERER, // process_type
@@ -39,16 +38,18 @@ void ResourceRequestInfo::AllocateForTesting(
0, // origin_pid
0, // request_id
render_frame_id, // render_frame_id
- resource_type == ResourceType::MAIN_FRAME, // is_main_frame
+ resource_type == RESOURCE_TYPE_MAIN_FRAME, // is_main_frame
false, // parent_is_main_frame
0, // parent_render_frame_id
resource_type, // resource_type
- PAGE_TRANSITION_LINK, // transition_type
+ ui::PAGE_TRANSITION_LINK, // transition_type
false, // should_replace_current_entry
false, // is_download
false, // is_stream
true, // allow_download
false, // has_user_gesture
+ false, // enable load timing
+ false, // enable upload progress
blink::WebReferrerPolicyDefault, // referrer_policy
blink::WebPageVisibilityStateVisible, // visibility_state
context, // context
@@ -96,13 +97,15 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl(
bool is_main_frame,
bool parent_is_main_frame,
int parent_render_frame_id,
- ResourceType::Type resource_type,
- PageTransition transition_type,
+ ResourceType resource_type,
+ ui::PageTransition transition_type,
bool should_replace_current_entry,
bool is_download,
bool is_stream,
bool allow_download,
bool has_user_gesture,
+ bool enable_load_timing,
+ bool enable_upload_progress,
blink::WebReferrerPolicy referrer_policy,
blink::WebPageVisibilityState visibility_state,
ResourceContext* context,
@@ -124,7 +127,10 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl(
is_stream_(is_stream),
allow_download_(allow_download),
has_user_gesture_(has_user_gesture),
+ enable_load_timing_(enable_load_timing),
+ enable_upload_progress_(enable_upload_progress),
was_ignored_by_handler_(false),
+ counted_as_in_flight_request_(false),
resource_type_(resource_type),
transition_type_(transition_type),
memory_cost_(0),
@@ -174,7 +180,7 @@ int ResourceRequestInfoImpl::GetParentRenderFrameID() const {
return parent_render_frame_id_;
}
-ResourceType::Type ResourceRequestInfoImpl::GetResourceType() const {
+ResourceType ResourceRequestInfoImpl::GetResourceType() const {
return resource_type_;
}
@@ -191,7 +197,7 @@ ResourceRequestInfoImpl::GetVisibilityState() const {
return visibility_state_;
}
-PageTransition ResourceRequestInfoImpl::GetPageTransition() const {
+ui::PageTransition ResourceRequestInfoImpl::GetPageTransition() const {
return transition_type_;
}
@@ -206,18 +212,7 @@ bool ResourceRequestInfoImpl::WasIgnoredByHandler() const {
bool ResourceRequestInfoImpl::GetAssociatedRenderFrame(
int* render_process_id,
int* render_frame_id) const {
- // If the request is from the worker process, find a content that owns the
- // worker.
- if (process_type_ == PROCESS_TYPE_WORKER) {
- // Need to display some related UI for this network request - pick an
- // arbitrary parent to do so.
- if (!WorkerServiceImpl::GetInstance()->GetRendererForWorker(
- child_id_, render_process_id, render_frame_id)) {
- *render_process_id = -1;
- *render_frame_id = -1;
- return false;
- }
- } else if (process_type_ == PROCESS_TYPE_PLUGIN) {
+ if (process_type_ == PROCESS_TYPE_PLUGIN) {
*render_process_id = origin_pid_;
*render_frame_id = render_frame_id_;
} else {
diff --git a/chromium/content/browser/loader/resource_request_info_impl.h b/chromium/content/browser/loader/resource_request_info_impl.h
index 82c81c0985e..6b75fcdae87 100644
--- a/chromium/content/browser/loader/resource_request_info_impl.h
+++ b/chromium/content/browser/loader/resource_request_info_impl.h
@@ -15,8 +15,8 @@
#include "base/supports_user_data.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/common/referrer.h"
+#include "content/public/common/resource_type.h"
#include "net/base/load_states.h"
-#include "webkit/common/resource_type.h"
namespace content {
class CrossSiteResourceHandler;
@@ -49,42 +49,43 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
bool is_main_frame,
bool parent_is_main_frame,
int parent_render_frame_id,
- ResourceType::Type resource_type,
- PageTransition transition_type,
+ ResourceType resource_type,
+ ui::PageTransition transition_type,
bool should_replace_current_entry,
bool is_download,
bool is_stream,
bool allow_download,
bool has_user_gesture,
+ bool enable_load_timing,
+ bool enable_upload_progress,
blink::WebReferrerPolicy referrer_policy,
blink::WebPageVisibilityState visibility_state,
ResourceContext* context,
base::WeakPtr<ResourceMessageFilter> filter,
bool is_async);
- virtual ~ResourceRequestInfoImpl();
+ ~ResourceRequestInfoImpl() override;
// ResourceRequestInfo implementation:
- virtual ResourceContext* GetContext() const OVERRIDE;
- virtual int GetChildID() const OVERRIDE;
- virtual int GetRouteID() const OVERRIDE;
- virtual int GetOriginPID() const OVERRIDE;
- virtual int GetRequestID() const OVERRIDE;
- virtual int GetRenderFrameID() const OVERRIDE;
- virtual bool IsMainFrame() const OVERRIDE;
- virtual bool ParentIsMainFrame() const OVERRIDE;
- virtual int GetParentRenderFrameID() const OVERRIDE;
- virtual ResourceType::Type GetResourceType() const OVERRIDE;
- virtual int GetProcessType() const OVERRIDE;
- virtual blink::WebReferrerPolicy GetReferrerPolicy() const OVERRIDE;
- virtual blink::WebPageVisibilityState GetVisibilityState() const OVERRIDE;
- virtual PageTransition GetPageTransition() const OVERRIDE;
- virtual bool HasUserGesture() const OVERRIDE;
- virtual bool WasIgnoredByHandler() const OVERRIDE;
- virtual bool GetAssociatedRenderFrame(int* render_process_id,
- int* render_frame_id) const OVERRIDE;
- virtual bool IsAsync() const OVERRIDE;
- virtual bool IsDownload() const OVERRIDE;
-
+ ResourceContext* GetContext() const override;
+ int GetChildID() const override;
+ int GetRouteID() const override;
+ int GetOriginPID() const override;
+ int GetRequestID() const override;
+ int GetRenderFrameID() const override;
+ bool IsMainFrame() const override;
+ bool ParentIsMainFrame() const override;
+ int GetParentRenderFrameID() const override;
+ ResourceType GetResourceType() const override;
+ int GetProcessType() const override;
+ blink::WebReferrerPolicy GetReferrerPolicy() const override;
+ blink::WebPageVisibilityState GetVisibilityState() const override;
+ ui::PageTransition GetPageTransition() const override;
+ bool HasUserGesture() const override;
+ bool WasIgnoredByHandler() const override;
+ bool GetAssociatedRenderFrame(int* render_process_id,
+ int* render_frame_id) const override;
+ bool IsAsync() const override;
+ bool IsDownload() const override;
CONTENT_EXPORT void AssociateWithRequest(net::URLRequest* request);
@@ -147,11 +148,25 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
was_ignored_by_handler_ = value;
}
+ // Whether this request has been counted towards the number of in flight
+ // requests, which is only true for requests that require a file descriptor
+ // for their shared memory buffer.
+ bool counted_as_in_flight_request() const {
+ return counted_as_in_flight_request_;
+ }
+ void set_counted_as_in_flight_request(bool was_counted) {
+ counted_as_in_flight_request_ = was_counted;
+ }
+
// The approximate in-memory size (bytes) that we credited this request
// as consuming in |outstanding_requests_memory_cost_map_|.
int memory_cost() const { return memory_cost_; }
void set_memory_cost(int cost) { memory_cost_ = cost; }
+ bool is_load_timing_enabled() const { return enable_load_timing_; }
+
+ bool is_upload_progress_enabled() const { return enable_upload_progress_; }
+
private:
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
DeletedFilterDetached);
@@ -175,9 +190,12 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo,
bool is_stream_;
bool allow_download_;
bool has_user_gesture_;
+ bool enable_load_timing_;
+ bool enable_upload_progress_;
bool was_ignored_by_handler_;
- ResourceType::Type resource_type_;
- PageTransition transition_type_;
+ bool counted_as_in_flight_request_;
+ ResourceType resource_type_;
+ ui::PageTransition transition_type_;
int memory_cost_;
blink::WebReferrerPolicy referrer_policy_;
blink::WebPageVisibilityState visibility_state_;
diff --git a/chromium/content/browser/loader/resource_scheduler.cc b/chromium/content/browser/loader/resource_scheduler.cc
index a826580cdcd..82d96ab5162 100644
--- a/chromium/content/browser/loader/resource_scheduler.cc
+++ b/chromium/content/browser/loader/resource_scheduler.cc
@@ -6,7 +6,10 @@
#include "content/browser/loader/resource_scheduler.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
#include "base/stl_util.h"
+#include "base/time/time.h"
#include "content/common/resource_messages.h"
#include "content/browser/loader/resource_message_delegate.h"
#include "content/public/browser/resource_controller.h"
@@ -22,9 +25,28 @@
namespace content {
+namespace {
+
+void PostHistogram(const char* base_name,
+ const char* suffix,
+ base::TimeDelta time) {
+ std::string histogram_name =
+ base::StringPrintf("ResourceScheduler.%s.%s", base_name, suffix);
+ base::HistogramBase* histogram_counter = base::Histogram::FactoryTimeGet(
+ histogram_name,
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMinutes(5),
+ 50,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ histogram_counter->AddTime(time);
+}
+
+} // namespace
+
+static const size_t kCoalescedTimerPeriod = 5000;
static const size_t kMaxNumDelayableRequestsPerClient = 10;
static const size_t kMaxNumDelayableRequestsPerHost = 6;
-
+static const size_t kMaxNumThrottledRequestsPerClient = 1;
struct ResourceScheduler::RequestPriorityParams {
RequestPriorityParams()
@@ -121,28 +143,51 @@ class ResourceScheduler::ScheduledResourceRequest
const RequestPriorityParams& priority)
: ResourceMessageDelegate(request),
client_id_(client_id),
+ client_state_on_creation_(scheduler->GetClientState(client_id_)),
request_(request),
ready_(false),
deferred_(false),
+ classification_(NORMAL_REQUEST),
scheduler_(scheduler),
priority_(priority),
- fifo_ordering_(0),
- accounted_as_delayable_request_(false) {
+ fifo_ordering_(0) {
TRACE_EVENT_ASYNC_BEGIN1("net", "URLRequest", request_,
"url", request->url().spec());
}
- virtual ~ScheduledResourceRequest() {
- scheduler_->RemoveRequest(this);
- }
+ ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); }
void Start() {
TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request_, "Queued");
ready_ = true;
- if (deferred_ && request_->status().is_success()) {
+ if (!request_->status().is_success())
+ return;
+ 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 (deferred_) {
deferred_ = false;
controller()->Resume();
+ time_was_deferred = time - time_deferred_;
}
+ PostHistogram("RequestTimeDeferred", client_state, time_was_deferred);
+ PostHistogram(
+ "RequestTimeThrottled", client_state, 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) {
@@ -158,16 +203,16 @@ class ResourceScheduler::ScheduledResourceRequest
void set_fifo_ordering(uint32 fifo_ordering) {
fifo_ordering_ = fifo_ordering;
}
- bool accounted_as_delayable_request() const {
- return accounted_as_delayable_request_;
+ RequestClassification classification() const {
+ return classification_;
}
- void set_accounted_as_delayable_request(bool accounted) {
- accounted_as_delayable_request_ = accounted;
+ void set_classification(RequestClassification classification) {
+ classification_ = classification;
}
private:
// ResourceMessageDelegate interface:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ bool OnMessageReceived(const IPC::Message& message) override {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message)
IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority)
@@ -177,28 +222,28 @@ class ResourceScheduler::ScheduledResourceRequest
}
// ResourceThrottle interface:
- virtual void WillStartRequest(bool* defer) OVERRIDE {
+ void WillStartRequest(bool* defer) override {
deferred_ = *defer = !ready_;
+ time_deferred_ = base::TimeTicks::Now();
}
- virtual const char* GetNameForLogging() const OVERRIDE {
- return "ResourceScheduler";
- }
+ const char* GetNameForLogging() const override { return "ResourceScheduler"; }
void DidChangePriority(int request_id, net::RequestPriority new_priority,
int intra_priority_value) {
scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value);
}
- ClientId client_id_;
+ const ClientId client_id_;
+ const ResourceScheduler::ClientState client_state_on_creation_;
net::URLRequest* request_;
bool ready_;
bool deferred_;
+ RequestClassification classification_;
ResourceScheduler* scheduler_;
RequestPriorityParams priority_;
uint32 fifo_ordering_;
- // True if the request is delayable in |in_flight_requests_|.
- bool accounted_as_delayable_request_;
+ base::TimeTicks time_deferred_;
DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
};
@@ -229,20 +274,38 @@ void ResourceScheduler::RequestQueue::Insert(
// Each client represents a tab.
class ResourceScheduler::Client {
public:
- Client()
- : has_body_(false),
+ explicit Client(ResourceScheduler* scheduler,
+ bool is_visible,
+ bool is_audible)
+ : is_audible_(is_audible),
+ is_visible_(is_visible),
+ is_loaded_(false),
+ is_paused_(false),
+ has_body_(false),
using_spdy_proxy_(false),
- total_delayable_count_(0) {}
- ~Client() {}
+ in_flight_delayable_count_(0),
+ total_layout_blocking_count_(0),
+ throttle_state_(ResourceScheduler::THROTTLED) {
+ scheduler_ = scheduler;
+ }
+
+ ~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();
+ }
void ScheduleRequest(
net::URLRequest* url_request,
ScheduledResourceRequest* request) {
- if (ShouldStartRequest(request) == START_REQUEST) {
+ if (ShouldStartRequest(request) == START_REQUEST)
StartRequest(request);
- } else {
+ else
pending_requests_.Insert(request);
- }
+ SetRequestClassification(request, ClassifyRequest(request));
}
void RemoveRequest(ScheduledResourceRequest* request) {
@@ -262,14 +325,83 @@ class ResourceScheduler::Client {
for (RequestSet::iterator it = in_flight_requests_.begin();
it != in_flight_requests_.end(); ++it) {
unowned_requests.insert(*it);
- (*it)->set_accounted_as_delayable_request(false);
+ (*it)->set_classification(NORMAL_REQUEST);
}
ClearInFlightRequests();
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) {
+ if (is_audible == is_audible_) {
+ return;
+ }
+ is_audible_ = is_audible;
+ UpdateThrottleState();
+ }
+
+ void OnVisibilityChanged(bool is_visible) {
+ if (is_visible == is_visible_) {
+ return;
+ }
+ is_visible_ = is_visible;
+ UpdateThrottleState();
+ }
+
+ void OnLoadingStateChanged(bool is_loaded) {
+ if (is_loaded == is_loaded_) {
+ return;
+ }
+ is_loaded_ = is_loaded;
+ UpdateThrottleState();
+ }
+
+ 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() {
has_body_ = false;
+ is_loaded_ = false;
}
void OnWillInsertBody() {
@@ -293,7 +425,7 @@ class ResourceScheduler::Client {
DCHECK(ContainsKey(in_flight_requests_, request));
// The priority and SPDY support may have changed, so update the
// delayable count.
- SetRequestDelayable(request, IsDelayableRequest(request));
+ SetRequestClassification(request, ClassifyRequest(request));
// Request has already started.
return;
}
@@ -307,53 +439,140 @@ 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 = -2,
- DO_NOT_START_REQUEST_AND_KEEP_SEARCHING = -1,
- START_REQUEST = 1,
+ DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
+ DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
+ START_REQUEST,
};
void InsertInFlightRequest(ScheduledResourceRequest* request) {
in_flight_requests_.insert(request);
- if (IsDelayableRequest(request))
- SetRequestDelayable(request, true);
+ SetRequestClassification(request, ClassifyRequest(request));
}
void EraseInFlightRequest(ScheduledResourceRequest* request) {
size_t erased = in_flight_requests_.erase(request);
DCHECK_EQ(1u, erased);
- SetRequestDelayable(request, false);
- DCHECK_LE(total_delayable_count_, in_flight_requests_.size());
+ // Clear any special state that we were tracking for this request.
+ SetRequestClassification(request, NORMAL_REQUEST);
}
void ClearInFlightRequests() {
in_flight_requests_.clear();
- total_delayable_count_ = 0;
+ in_flight_delayable_count_ = 0;
+ total_layout_blocking_count_ = 0;
+ }
+
+ size_t CountRequestsWithClassification(
+ const RequestClassification classification, const bool include_pending) {
+ size_t classification_request_count = 0;
+ for (RequestSet::const_iterator it = in_flight_requests_.begin();
+ it != in_flight_requests_.end(); ++it) {
+ if ((*it)->classification() == classification)
+ classification_request_count++;
+ }
+ if (include_pending) {
+ for (RequestQueue::NetQueue::const_iterator
+ it = pending_requests_.GetNextHighestIterator();
+ it != pending_requests_.End(); ++it) {
+ if ((*it)->classification() == classification)
+ classification_request_count++;
+ }
+ }
+ return classification_request_count;
}
- bool IsDelayableRequest(ScheduledResourceRequest* request) {
+ void SetRequestClassification(ScheduledResourceRequest* request,
+ RequestClassification classification) {
+ RequestClassification old_classification = request->classification();
+ if (old_classification == classification)
+ return;
+
+ if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST)
+ in_flight_delayable_count_--;
+ if (old_classification == LAYOUT_BLOCKING_REQUEST)
+ total_layout_blocking_count_--;
+
+ if (classification == IN_FLIGHT_DELAYABLE_REQUEST)
+ in_flight_delayable_count_++;
+ if (classification == LAYOUT_BLOCKING_REQUEST)
+ total_layout_blocking_count_++;
+
+ request->set_classification(classification);
+ DCHECK_EQ(
+ CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false),
+ in_flight_delayable_count_);
+ DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true),
+ total_layout_blocking_count_);
+ }
+
+ RequestClassification ClassifyRequest(ScheduledResourceRequest* request) {
+ // If a request is already marked as layout-blocking make sure to keep the
+ // classification across redirects unless the priority was lowered.
+ if (request->classification() == LAYOUT_BLOCKING_REQUEST &&
+ request->url_request()->priority() > net::LOW) {
+ return LAYOUT_BLOCKING_REQUEST;
+ }
+
+ if (!has_body_ && request->url_request()->priority() > net::LOW)
+ return LAYOUT_BLOCKING_REQUEST;
+
if (request->url_request()->priority() < net::LOW) {
net::HostPortPair host_port_pair =
net::HostPortPair::FromURL(request->url_request()->url());
net::HttpServerProperties& http_server_properties =
*request->url_request()->context()->http_server_properties();
- if (!http_server_properties.SupportsSpdy(host_port_pair)) {
- return true;
+ if (!http_server_properties.SupportsSpdy(host_port_pair) &&
+ ContainsKey(in_flight_requests_, request)) {
+ return IN_FLIGHT_DELAYABLE_REQUEST;
}
}
- return false;
- }
-
- void SetRequestDelayable(ScheduledResourceRequest* request,
- bool delayable) {
- if (request->accounted_as_delayable_request() == delayable)
- return;
- if (delayable)
- total_delayable_count_++;
- else
- total_delayable_count_--;
- request->set_accounted_as_delayable_request(delayable);
+ return NORMAL_REQUEST;
}
bool ShouldKeepSearching(
@@ -379,46 +598,77 @@ class ResourceScheduler::Client {
// ShouldStartRequest is the main scheduling algorithm.
//
- // Requests are categorized into two categories:
+ // Requests are evaluated on five attributes:
//
- // 1. Immediately issued requests, which are:
- //
- // * Higher priority requests (>= net::LOW).
+ // 1. Non-delayable requests:
// * Synchronous requests.
- // * Requests to SPDY-capable origin servers.
// * Non-HTTP[S] requests.
//
- // 2. The remainder are delayable requests, which follow these rules:
+ // 2. Requests to SPDY-capable origin servers.
//
- // * If no high priority requests are in flight, start loading low priority
- // requests.
- // * Once the renderer has a <body>, start loading delayable requests.
+ // 3. High-priority requests:
+ // * Higher priority requests (>= net::LOW).
+ //
+ // 4. Layout-blocking requests:
+ // * High-priority requests (> net::LOW) initiated before the renderer has
+ // a <body>.
+ //
+ // 5. Low priority requests
+ //
+ // The following rules are followed:
+ //
+ // ACTIVE_AND_LOADING and UNTHROTTLED Clients follow these rules:
+ // * Non-delayable, High-priority and SPDY capable requests are issued
+ // immediately.
+ // * Low priority requests are delayable.
+ // * Allow one delayable request to load at a time while layout-blocking
+ // requests are loading or the body tag has not yet been parsed.
+ // * If no high priority or layout-blocking requests are in flight, start
+ // loading delayable requests.
// * Never exceed 10 delayable requests in flight per client.
// * Never exceed 6 delayable requests for a given host.
- // * Prior to <body>, allow one delayable request to load at a time.
+ //
+ // THROTTLED Clients follow these rules:
+ // * Non-delayable and SPDY-capable requests are issued immediately.
+ // * At most one non-SPDY 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();
+ // Syncronous requests could block the entire render, which could impact
+ // user-observable Clients.
+ if (!ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) {
+ return START_REQUEST;
+ }
+
// 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 (using_spdy_proxy_ && url_request.url().SchemeIs("http")) {
- return START_REQUEST;
+ if (throttle_state_ == COALESCED) {
+ return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
}
- net::HttpServerProperties& http_server_properties =
- *url_request.context()->http_server_properties();
-
- if (url_request.priority() >= net::LOW ||
- !ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) {
+ if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme)) {
return START_REQUEST;
}
net::HostPortPair host_port_pair =
net::HostPortPair::FromURL(url_request.url());
+ net::HttpServerProperties& http_server_properties =
+ *url_request.context()->http_server_properties();
// TODO(willchan): We should really improve this algorithm as described in
// crbug.com/164101. Also, theoretically we should not count a SPDY request
@@ -427,8 +677,18 @@ class ResourceScheduler::Client {
return START_REQUEST;
}
- size_t num_delayable_requests_in_flight = total_delayable_count_;
- if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) {
+ if (throttle_state_ == THROTTLED &&
+ in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) {
+ // There may still be SPDY-capable requests that should be issued.
+ return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
+ }
+
+ // High-priority and layout-blocking requests.
+ if (url_request.priority() >= net::LOW) {
+ return START_REQUEST;
+ }
+
+ if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient) {
return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
}
@@ -439,9 +699,10 @@ class ResourceScheduler::Client {
}
bool have_immediate_requests_in_flight =
- in_flight_requests_.size() > num_delayable_requests_in_flight;
- if (have_immediate_requests_in_flight && !has_body_ &&
- num_delayable_requests_in_flight != 0) {
+ in_flight_requests_.size() > in_flight_delayable_count_;
+ if (have_immediate_requests_in_flight &&
+ (!has_body_ || total_layout_blocking_count_ != 0) &&
+ in_flight_delayable_count_ != 0) {
return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
}
@@ -485,15 +746,37 @@ class ResourceScheduler::Client {
}
}
+ bool is_audible_;
+ bool is_visible_;
+ bool is_loaded_;
+ bool is_paused_;
bool has_body_;
bool using_spdy_proxy_;
RequestQueue pending_requests_;
RequestSet in_flight_requests_;
+ ResourceScheduler* scheduler_;
// The number of delayable in-flight requests.
- size_t total_delayable_count_;
+ 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() {
+ResourceScheduler::ResourceScheduler()
+ : should_coalesce_(false),
+ should_throttle_(false),
+ active_clients_loading_(0),
+ coalesced_clients_(0),
+ coalescing_timer_(new base::Timer(true /* retain_user_task */,
+ true /* is_repeating */)) {
+ std::string throttling_trial_group =
+ base::FieldTrialList::FindFullName("RequestThrottlingAndCoalescing");
+ if (throttling_trial_group == "Throttle") {
+ should_throttle_ = true;
+ } else if (throttling_trial_group == "Coalesce") {
+ should_coalesce_ = true;
+ should_throttle_ = true;
+ }
}
ResourceScheduler::~ResourceScheduler() {
@@ -501,15 +784,31 @@ 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(
int child_id,
int route_id,
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)));
+ scoped_ptr<ScheduledResourceRequest> request(new ScheduledResourceRequest(
+ client_id,
+ url_request,
+ this,
+ RequestPriorityParams(url_request->priority(), 0)));
ClientMap::iterator it = client_map_.find(client_id);
if (it == client_map_.end()) {
@@ -519,12 +818,12 @@ scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
// 3. The tab is closed while a RequestResource IPC is in flight.
unowned_requests_.insert(request.get());
request->Start();
- return request.PassAs<ResourceThrottle>();
+ return request.Pass();
}
Client* client = it->second;
client->ScheduleRequest(url_request, request.get());
- return request.PassAs<ResourceThrottle>();
+ return request.Pass();
}
void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
@@ -543,12 +842,20 @@ void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
client->RemoveRequest(request);
}
-void ResourceScheduler::OnClientCreated(int child_id, int route_id) {
+void ResourceScheduler::OnClientCreated(int child_id,
+ int route_id,
+ bool is_visible,
+ bool is_audible) {
DCHECK(CalledOnValidThread());
ClientId client_id = MakeClientId(child_id, route_id);
DCHECK(!ContainsKey(client_map_, client_id));
- client_map_[client_id] = new Client;
+ Client* client = new Client(this, is_visible, is_audible);
+ client_map_[client_id] = client;
+
+ // TODO(aiolos): set Client visibility/audibility when signals are added
+ // this will UNTHROTTLE Clients as needed
+ client->UpdateThrottleState();
}
void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
@@ -560,7 +867,6 @@ void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
return;
Client* client = it->second;
-
// FYI, ResourceDispatcherHost cancels all of the requests after this function
// is called. It should end up canceling all of the requests except for a
// cross-renderer navigation.
@@ -574,6 +880,31 @@ void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
client_map_.erase(it);
}
+void ResourceScheduler::OnLoadingStateChanged(int child_id,
+ int route_id,
+ bool is_loaded) {
+ Client* client = GetClient(child_id, route_id);
+ DCHECK(client);
+ 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);
@@ -617,6 +948,116 @@ 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();
+}
+
+ResourceScheduler::Client* ResourceScheduler::GetClient(int child_id,
+ int route_id) {
+ ClientId client_id = MakeClientId(child_id, route_id);
+ ClientMap::iterator client_it = client_map_.find(client_id);
+ if (client_it == client_map_.end()) {
+ return NULL;
+ }
+ 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(ScheduledResourceRequest* 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 0e918f10c6d..2b8d7373b4f 100644
--- a/chromium/content/browser/loader/resource_scheduler.h
+++ b/chromium/content/browser/loader/resource_scheduler.h
@@ -12,6 +12,7 @@
#include "base/compiler_specific.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"
@@ -52,9 +53,55 @@ 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,
+ };
+
+ enum RequestClassification {
+ NORMAL_REQUEST,
+ // Low priority in-flight requests
+ IN_FLIGHT_DELAYABLE_REQUEST,
+ // High-priority requests received before the renderer has a <body>
+ LAYOUT_BLOCKING_REQUEST,
+ };
+
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.
@@ -64,11 +111,23 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
// 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);
+ void OnClientCreated(int child_id,
+ int route_id,
+ bool is_visible,
+ bool is_audible);
// Called when a renderer is destroyed.
void OnClientDeleted(int child_id, int route_id);
+ // 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.
@@ -78,13 +137,29 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
// resource loads won't interfere with first paint.
void OnWillInsertBody(int child_id, int route_id);
- // Signals from the IO thread
+ // Signals from the IO thread:
// Called when we received a response to a http request that was served
// from a proxy using SPDY.
void OnReceivedSpdyProxiedHttpResponse(int child_id, int route_id);
+ // 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);
+
private:
+ enum ClientState {
+ // Observable client.
+ ACTIVE,
+ // Non-observable client.
+ BACKGROUND,
+ // No client found.
+ UNKNOWN,
+ };
+
class RequestQueue;
class ScheduledResourceRequest;
struct RequestPriorityParams;
@@ -101,6 +176,31 @@ 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;
+
// Update the queue position for |request|, possibly causing it to start
// loading.
//
@@ -114,7 +214,16 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
// 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_;
+ // This is a repeating timer to initiate requests on COALESCED Clients.
+ scoped_ptr<base::Timer> coalescing_timer_;
RequestSet unowned_requests_;
};
diff --git a/chromium/content/browser/loader/resource_scheduler_filter.cc b/chromium/content/browser/loader/resource_scheduler_filter.cc
index 4c825dab987..b9f240d4fc1 100644
--- a/chromium/content/browser/loader/resource_scheduler_filter.cc
+++ b/chromium/content/browser/loader/resource_scheduler_filter.cc
@@ -8,7 +8,7 @@
#include "content/browser/loader/resource_scheduler.h"
#include "content/common/frame_messages.h"
#include "content/common/view_messages.h"
-#include "content/public/common/page_transition_types.h"
+#include "ui/base/page_transition_types.h"
namespace content {
namespace {
@@ -43,9 +43,17 @@ bool ResourceSchedulerFilter::OnMessageReceived(const IPC::Message& message) {
&message, &iter, &params)) {
break;
}
- if (PageTransitionIsMainFrame(params.transition) &&
+ if (ui::PageTransitionIsMainFrame(params.transition) &&
!params.was_within_same_page) {
- scheduler->OnNavigate(child_id_, message.routing_id());
+ // We need to track the RenderViewHost routing_id because of downstream
+ // dependencies (crbug.com/392171 DownloadRequestHandle,
+ // SaveFileManager, ResourceDispatcherHostImpl, MediaStreamUIProxy,
+ // SpeechRecognitionDispatcherHost and possibly others). They look up
+ // the view based on the ID stored in the resource requests.
+ // Once those dependencies are unwound or moved to RenderFrameHost
+ // (crbug.com/304341) we can move the client to be based on the
+ // routing_id of the RenderFrameHost.
+ scheduler->OnNavigate(child_id_, params.render_view_routing_id);
}
break;
}
diff --git a/chromium/content/browser/loader/resource_scheduler_filter.h b/chromium/content/browser/loader/resource_scheduler_filter.h
index 9f4c5f3a7ed..0a6c23ab9f3 100644
--- a/chromium/content/browser/loader/resource_scheduler_filter.h
+++ b/chromium/content/browser/loader/resource_scheduler_filter.h
@@ -19,10 +19,10 @@ class ResourceSchedulerFilter : public BrowserMessageFilter {
explicit ResourceSchedulerFilter(int child_id);
// BrowserMessageFilter methods:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
- virtual ~ResourceSchedulerFilter();
+ ~ResourceSchedulerFilter() override;
int child_id_;
};
diff --git a/chromium/content/browser/loader/resource_scheduler_unittest.cc b/chromium/content/browser/loader/resource_scheduler_unittest.cc
index f4cb0e0f091..2d1b0fe34bd 100644
--- a/chromium/content/browser/loader/resource_scheduler_unittest.cc
+++ b/chromium/content/browser/loader/resource_scheduler_unittest.cc
@@ -6,7 +6,10 @@
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
+#include "base/timer/mock_timer.h"
+#include "base/timer/timer.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_message_filter.h"
@@ -16,13 +19,18 @@
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_throttle.h"
#include "content/public/common/process_type.h"
+#include "content/public/common/resource_type.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_factory.h"
+#include "content/test/test_web_contents.h"
#include "net/base/host_port_pair.h"
#include "net/base/request_priority.h"
#include "net/http/http_server_properties_impl.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/common/resource_type.h"
+#include "ui/events/latency_info.h"
namespace content {
@@ -32,6 +40,12 @@ class TestRequestFactory;
const int kChildId = 30;
const int kRouteId = 75;
+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:
@@ -42,6 +56,7 @@ class TestRequest : public ResourceController {
url_request_(url_request.Pass()) {
throttle_->set_controller_for_testing(this);
}
+ ~TestRequest() override {}
bool started() const { return started_; }
@@ -51,14 +66,18 @@ class TestRequest : public ResourceController {
started_ = !deferred;
}
+ void Cancel() override {
+ // Alert the scheduler that the request can be deleted.
+ throttle_.reset(0);
+ }
+
const net::URLRequest* url_request() const { return url_request_.get(); }
protected:
// ResourceController interface:
- virtual void Cancel() OVERRIDE {}
- virtual void CancelAndIgnore() OVERRIDE {}
- virtual void CancelWithError(int error_code) OVERRIDE {}
- virtual void Resume() OVERRIDE { started_ = true; }
+ void CancelAndIgnore() override {}
+ void CancelWithError(int error_code) override {}
+ void Resume() override { started_ = true; }
private:
bool started_;
@@ -70,15 +89,14 @@ class CancelingTestRequest : public TestRequest {
public:
CancelingTestRequest(scoped_ptr<ResourceThrottle> throttle,
scoped_ptr<net::URLRequest> url_request)
- : TestRequest(throttle.Pass(), url_request.Pass()) {
- }
+ : TestRequest(throttle.Pass(), url_request.Pass()) {}
void set_request_to_cancel(scoped_ptr<TestRequest> request_to_cancel) {
request_to_cancel_ = request_to_cancel.Pass();
}
private:
- virtual void Resume() OVERRIDE {
+ void Resume() override {
TestRequest::Resume();
request_to_cancel_.reset();
}
@@ -88,10 +106,8 @@ class CancelingTestRequest : public TestRequest {
class FakeResourceContext : public ResourceContext {
private:
- virtual net::HostResolver* GetHostResolver() OVERRIDE { return NULL; }
- virtual net::URLRequestContext* GetRequestContext() OVERRIDE { return NULL; }
- virtual bool AllowMicAccess(const GURL& origin) OVERRIDE { return false; }
- virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE { return false; }
+ net::HostResolver* GetHostResolver() override { return NULL; }
+ net::URLRequestContext* GetRequestContext() override { return NULL; }
};
class FakeResourceMessageFilter : public ResourceMessageFilter {
@@ -109,7 +125,7 @@ class FakeResourceMessageFilter : public ResourceMessageFilter {
}
private:
- virtual ~FakeResourceMessageFilter() {}
+ ~FakeResourceMessageFilter() override {}
void GetContexts(const ResourceHostMsg_Request& request,
ResourceContext** resource_context,
@@ -126,67 +142,121 @@ class ResourceSchedulerTest : public testing::Test {
ResourceSchedulerTest()
: next_request_id_(0),
ui_thread_(BrowserThread::UI, &message_loop_),
- io_thread_(BrowserThread::IO, &message_loop_) {
- scheduler_.OnClientCreated(kChildId, kRouteId);
+ io_thread_(BrowserThread::IO, &message_loop_),
+ 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(
+ kBackgroundChildId, kBackgroundRouteId, false, false);
context_.set_http_server_properties(http_server_properties_.GetWeakPtr());
}
- virtual ~ResourceSchedulerTest() {
+ ~ResourceSchedulerTest() override {
scheduler_.OnClientDeleted(kChildId, kRouteId);
+ scheduler_.OnClientDeleted(kBackgroundChildId, kBackgroundRouteId);
}
- scoped_ptr<net::URLRequest> NewURLRequestWithRoute(
+ scoped_ptr<net::URLRequest> NewURLRequestWithChildAndRoute(
const char* url,
net::RequestPriority priority,
- int route_id) {
+ int child_id,
+ int route_id,
+ bool is_async) {
scoped_ptr<net::URLRequest> url_request(
context_.CreateRequest(GURL(url), priority, NULL, NULL));
ResourceRequestInfoImpl* info = new ResourceRequestInfoImpl(
- PROCESS_TYPE_RENDERER, // process_type
- kChildId, // child_id
- route_id, // route_id
- 0, // origin_pid
- ++next_request_id_, // request_id
- MSG_ROUTING_NONE, // render_frame_id
- false, // is_main_frame
- false, // parent_is_main_frame
- 0, // parent_render_frame_id
- ResourceType::SUB_RESOURCE, // resource_type
- PAGE_TRANSITION_LINK, // transition_type
- false, // should_replace_current_entry
- false, // is_download
- false, // is_stream
- true, // allow_download
- false, // has_user_gesture
- blink::WebReferrerPolicyDefault, // referrer_policy
- blink::WebPageVisibilityStateVisible, // visibility_state
- NULL, // context
+ PROCESS_TYPE_RENDERER, // process_type
+ child_id, // child_id
+ route_id, // route_id
+ 0, // origin_pid
+ ++next_request_id_, // request_id
+ MSG_ROUTING_NONE, // render_frame_id
+ false, // is_main_frame
+ false, // parent_is_main_frame
+ 0, // parent_render_frame_id
+ RESOURCE_TYPE_SUB_RESOURCE, // resource_type
+ ui::PAGE_TRANSITION_LINK, // transition_type
+ false, // should_replace_current_entry
+ false, // is_download
+ false, // is_stream
+ true, // allow_download
+ false, // has_user_gesture
+ false, // enable_load_timing
+ false, // enable_upload_progress
+ blink::WebReferrerPolicyDefault, // referrer_policy
+ blink::WebPageVisibilityStateVisible, // visibility_state
+ NULL, // context
base::WeakPtr<ResourceMessageFilter>(), // filter
- true); // is_async
+ is_async); // is_async
info->AssociateWithRequest(url_request.get());
return url_request.Pass();
}
scoped_ptr<net::URLRequest> NewURLRequest(const char* url,
net::RequestPriority priority) {
- return NewURLRequestWithRoute(url, priority, kRouteId);
+ return NewURLRequestWithChildAndRoute(
+ url, priority, kChildId, kRouteId, true);
}
TestRequest* NewRequestWithRoute(const char* url,
net::RequestPriority priority,
int route_id) {
- scoped_ptr<net::URLRequest> url_request(
- NewURLRequestWithRoute(url, priority, route_id));
- scoped_ptr<ResourceThrottle> throttle(scheduler_.ScheduleRequest(
- kChildId, route_id, url_request.get()));
+ return NewRequestWithChildAndRoute(url, priority, route_id, kChildId);
+ }
+
+ TestRequest* NewRequestWithChildAndRoute(const char* url,
+ net::RequestPriority priority,
+ int child_id,
+ int route_id) {
+ return GetNewTestRequest(url, priority, child_id, route_id, true);
+ }
+
+ TestRequest* NewRequest(const char* url, net::RequestPriority priority) {
+ return NewRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
+ }
+
+ TestRequest* NewBackgroundRequest(const char* url,
+ net::RequestPriority priority) {
+ return NewRequestWithChildAndRoute(
+ url, priority, kBackgroundChildId, kBackgroundRouteId);
+ }
+
+ TestRequest* NewSyncRequest(const char* url, net::RequestPriority priority) {
+ return NewSyncRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
+ }
+
+ TestRequest* NewBackgroundSyncRequest(const char* url,
+ net::RequestPriority priority) {
+ return NewSyncRequestWithChildAndRoute(
+ url, priority, kBackgroundChildId, kBackgroundRouteId);
+ }
+
+ TestRequest* NewSyncRequestWithChildAndRoute(const char* url,
+ net::RequestPriority priority,
+ int child_id,
+ int route_id) {
+ return GetNewTestRequest(url, priority, child_id, route_id, false);
+ }
+
+ TestRequest* GetNewTestRequest(const char* url,
+ net::RequestPriority priority,
+ int child_id,
+ int route_id,
+ bool is_async) {
+ scoped_ptr<net::URLRequest> url_request(NewURLRequestWithChildAndRoute(
+ url, priority, child_id, route_id, is_async));
+ scoped_ptr<ResourceThrottle> throttle(
+ scheduler_.ScheduleRequest(child_id, route_id, url_request.get()));
TestRequest* request = new TestRequest(throttle.Pass(), url_request.Pass());
request->Start();
return request;
}
- TestRequest* NewRequest(const char* url, net::RequestPriority priority) {
- return NewRequestWithRoute(url, priority, kRouteId);
- }
void ChangeRequestPriority(TestRequest* request,
net::RequestPriority new_priority,
@@ -201,12 +271,18 @@ class ResourceSchedulerTest : public testing::Test {
rdh_.OnMessageReceived(msg, filter.get());
}
+ void FireCoalescingTimer() {
+ EXPECT_TRUE(mock_timer_->IsRunning());
+ mock_timer_->Fire();
+ }
+
int next_request_id_;
base::MessageLoopForIO message_loop_;
BrowserThreadImpl ui_thread_;
BrowserThreadImpl io_thread_;
ResourceDispatcherHostImpl rdh_;
ResourceScheduler scheduler_;
+ base::MockTimer* mock_timer_;
net::HttpServerPropertiesImpl http_server_properties_;
net::TestURLRequestContext context_;
};
@@ -234,16 +310,42 @@ TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInserted) {
EXPECT_TRUE(high->started());
EXPECT_TRUE(low->started());
EXPECT_FALSE(low2->started());
+ high.reset();
scheduler_.OnWillInsertBody(kChildId, kRouteId);
EXPECT_TRUE(low2->started());
}
+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));
+ EXPECT_TRUE(high->started());
+ EXPECT_TRUE(low->started());
+ EXPECT_FALSE(low2->started());
+ scheduler_.OnWillInsertBody(kChildId, kRouteId);
+ EXPECT_FALSE(low2->started());
+ high.reset();
+ EXPECT_TRUE(low2->started());
+}
+
+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(
+ NewRequest("http://host/lowest", net::LOWEST));
+ EXPECT_TRUE(low->started());
+ EXPECT_TRUE(lowest->started());
+ EXPECT_FALSE(lowest2->started());
+ scheduler_.OnWillInsertBody(kChildId, kRouteId);
+ EXPECT_TRUE(lowest2->started());
+}
+
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(
- NewRequest("https://spdyhost/high", net::LOWEST));
+ 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));
EXPECT_TRUE(high->started());
@@ -251,6 +353,7 @@ TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInsertedExceptSpdy) {
EXPECT_TRUE(low->started());
EXPECT_FALSE(low2->started());
scheduler_.OnWillInsertBody(kChildId, kRouteId);
+ high.reset();
EXPECT_TRUE(low2->started());
}
@@ -293,8 +396,8 @@ TEST_F(ResourceSchedulerTest, CancelOtherRequestsWhileResuming) {
scoped_ptr<net::URLRequest> url_request(
NewURLRequest("http://host/low2", net::LOWEST));
- scoped_ptr<ResourceThrottle> throttle(scheduler_.ScheduleRequest(
- kChildId, kRouteId, url_request.get()));
+ scoped_ptr<ResourceThrottle> throttle(
+ scheduler_.ScheduleRequest(kChildId, kRouteId, url_request.get()));
scoped_ptr<CancelingTestRequest> low2(new CancelingTestRequest(
throttle.Pass(), url_request.Pass()));
low2->Start();
@@ -391,6 +494,8 @@ TEST_F(ResourceSchedulerTest, RaisePriorityInQueue) {
}
scheduler_.OnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+
EXPECT_TRUE(request->started());
EXPECT_FALSE(idle->started());
}
@@ -420,6 +525,8 @@ TEST_F(ResourceSchedulerTest, LowerPriority) {
}
scheduler_.OnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+
EXPECT_FALSE(request->started());
EXPECT_TRUE(idle->started());
}
@@ -427,7 +534,7 @@ 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/high", net::LOWEST));
+ scoped_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));
@@ -457,7 +564,7 @@ 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/high", net::LOWEST));
+ scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
ScopedVector<TestRequest> lows;
@@ -473,19 +580,52 @@ TEST_F(ResourceSchedulerTest, HigherIntraPriorityGoesToFrontOfQueue) {
EXPECT_FALSE(request->started());
scheduler_.OnWillInsertBody(kChildId, kRouteId);
+ high.reset();
EXPECT_TRUE(request->started());
}
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/high", net::LOWEST));
+ scoped_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
scoped_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));
@@ -531,6 +671,1543 @@ TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
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);
+ 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);
+ 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->CancelRequest();
+ request->Cancel();
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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();
+
+ 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();
+
+ // 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();
+
+ 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();
+
+ 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->is_hidden());
+ EXPECT_EQ(scheduler->IsClientVisibleForTesting(rvh2->GetProcess()->GetID(),
+ rvh1->GetRoutingID()),
+ !rvh2->is_hidden());
+
+ // 1 visible, 1 hidden
+ rvh1->WasShown(ui::LatencyInfo());
+ rvh2->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->WasHidden();
+ rvh2->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();
+}
+
} // unnamed namespace
} // namespace content
diff --git a/chromium/content/browser/loader/stream_resource_handler.cc b/chromium/content/browser/loader/stream_resource_handler.cc
index 46713fc67fa..08827e19feb 100644
--- a/chromium/content/browser/loader/stream_resource_handler.cc
+++ b/chromium/content/browser/loader/stream_resource_handler.cc
@@ -4,31 +4,23 @@
#include "content/browser/loader/stream_resource_handler.h"
-#include "base/guid.h"
#include "base/logging.h"
-#include "content/browser/streams/stream.h"
-#include "content/browser/streams/stream_registry.h"
-#include "content/public/browser/resource_controller.h"
-#include "net/base/io_buffer.h"
-#include "net/url_request/url_request_status.h"
-#include "url/url_constants.h"
namespace content {
StreamResourceHandler::StreamResourceHandler(net::URLRequest* request,
StreamRegistry* registry,
const GURL& origin)
- : ResourceHandler(request),
- read_buffer_(NULL) {
- // TODO(tyoshino): Find a way to share this with the blob URL creation in
- // WebKit.
- GURL url(std::string(url::kBlobScheme) + ":" + origin.spec() +
- base::GenerateGUID());
- stream_ = new Stream(registry, this, url);
+ : ResourceHandler(request) {
+ writer_.InitializeStream(registry, origin);
}
StreamResourceHandler::~StreamResourceHandler() {
- stream_->RemoveWriteObserver(this);
+}
+
+void StreamResourceHandler::SetController(ResourceController* controller) {
+ writer_.set_controller(controller);
+ ResourceHandler::SetController(controller);
}
bool StreamResourceHandler::OnUploadProgress(uint64 position,
@@ -36,9 +28,10 @@ bool StreamResourceHandler::OnUploadProgress(uint64 position,
return true;
}
-bool StreamResourceHandler::OnRequestRedirected(const GURL& url,
- ResourceResponse* resp,
- bool* defer) {
+bool StreamResourceHandler::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* resp,
+ bool* defer) {
return true;
}
@@ -58,33 +51,12 @@ bool StreamResourceHandler::OnBeforeNetworkStart(const GURL& url, bool* defer) {
bool StreamResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
int* buf_size,
int min_size) {
- static const int kReadBufSize = 32768;
-
- DCHECK(buf && buf_size);
- if (!read_buffer_.get())
- read_buffer_ = new net::IOBuffer(kReadBufSize);
- *buf = read_buffer_.get();
- *buf_size = kReadBufSize;
-
+ writer_.OnWillRead(buf, buf_size, min_size);
return true;
}
bool StreamResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
- if (!bytes_read)
- return true;
-
- // We have more data to read.
- DCHECK(read_buffer_.get());
-
- // Release the ownership of the buffer, and store a reference
- // to it. A new one will be allocated in OnWillRead().
- scoped_refptr<net::IOBuffer> buffer;
- read_buffer_.swap(buffer);
- stream_->AddData(buffer, bytes_read);
-
- if (!stream_->can_add_data())
- *defer = true;
-
+ writer_.OnReadCompleted(bytes_read, defer);
return true;
}
@@ -92,19 +64,11 @@ void StreamResourceHandler::OnResponseCompleted(
const net::URLRequestStatus& status,
const std::string& sec_info,
bool* defer) {
- stream_->Finalize();
+ writer_.Finalize();
}
void StreamResourceHandler::OnDataDownloaded(int bytes_downloaded) {
NOTREACHED();
}
-void StreamResourceHandler::OnSpaceAvailable(Stream* stream) {
- controller()->Resume();
-}
-
-void StreamResourceHandler::OnClose(Stream* stream) {
- controller()->Cancel();
-}
-
} // namespace content
diff --git a/chromium/content/browser/loader/stream_resource_handler.h b/chromium/content/browser/loader/stream_resource_handler.h
index 3b8bc217890..4ec226e21e1 100644
--- a/chromium/content/browser/loader/stream_resource_handler.h
+++ b/chromium/content/browser/loader/stream_resource_handler.h
@@ -8,8 +8,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/browser/loader/resource_handler.h"
-#include "content/browser/streams/stream_write_observer.h"
-#include "url/gurl.h"
+#include "content/browser/loader/stream_writer.h"
namespace net {
class URLRequest;
@@ -20,8 +19,7 @@ namespace content {
class StreamRegistry;
// Redirect this resource to a stream.
-class StreamResourceHandler : public StreamWriteObserver,
- public ResourceHandler {
+class StreamResourceHandler : public ResourceHandler {
public:
// |origin| will be used to construct the URL for the Stream. See
// WebCore::BlobURL and and WebCore::SecurityOrigin in Blink to understand
@@ -29,44 +27,42 @@ class StreamResourceHandler : public StreamWriteObserver,
StreamResourceHandler(net::URLRequest* request,
StreamRegistry* registry,
const GURL& origin);
- virtual ~StreamResourceHandler();
+ ~StreamResourceHandler() override;
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
+ void SetController(ResourceController* controller) override;
+
+ bool OnUploadProgress(uint64 position, uint64 size) override;
// Not needed, as this event handler ought to be the final resource.
- virtual bool OnRequestRedirected(const GURL& url,
- ResourceResponse* resp,
- bool* defer) OVERRIDE;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* resp,
+ bool* defer) override;
- virtual bool OnResponseStarted(ResourceResponse* resp,
- bool* defer) OVERRIDE;
+ bool OnResponseStarted(ResourceResponse* resp, bool* defer) override;
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnWillStart(const GURL& url, bool* defer) override;
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
// Create a new buffer to store received data.
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
// A read was completed, forward the data to the Stream.
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& sec_info,
- bool* defer) OVERRIDE;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& sec_info,
+ bool* defer) override;
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE;
+ void OnDataDownloaded(int bytes_downloaded) override;
- Stream* stream() { return stream_.get(); }
+ Stream* stream() { return writer_.stream(); }
private:
- virtual void OnSpaceAvailable(Stream* stream) OVERRIDE;
- virtual void OnClose(Stream* stream) OVERRIDE;
+ StreamWriter writer_;
- scoped_refptr<Stream> stream_;
- scoped_refptr<net::IOBuffer> read_buffer_;
DISALLOW_COPY_AND_ASSIGN(StreamResourceHandler);
};
diff --git a/chromium/content/browser/loader/stream_writer.cc b/chromium/content/browser/loader/stream_writer.cc
new file mode 100644
index 00000000000..99b5ee1d3b0
--- /dev/null
+++ b/chromium/content/browser/loader/stream_writer.cc
@@ -0,0 +1,82 @@
+// 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/loader/stream_writer.h"
+
+#include "base/guid.h"
+#include "content/browser/streams/stream.h"
+#include "content/browser/streams/stream_registry.h"
+#include "content/public/browser/resource_controller.h"
+#include "net/base/io_buffer.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace content {
+
+StreamWriter::StreamWriter() : controller_(nullptr) {
+}
+
+StreamWriter::~StreamWriter() {
+ if (stream_.get())
+ Finalize();
+}
+
+void StreamWriter::InitializeStream(StreamRegistry* registry,
+ const GURL& origin) {
+ DCHECK(!stream_.get());
+
+ // TODO(tyoshino): Find a way to share this with the blob URL creation in
+ // WebKit.
+ GURL url(std::string(url::kBlobScheme) + ":" + origin.spec() +
+ base::GenerateGUID());
+ stream_ = new Stream(registry, this, url);
+}
+
+void StreamWriter::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) {
+ static const int kReadBufSize = 32768;
+
+ DCHECK(buf);
+ DCHECK(buf_size);
+ DCHECK_LE(min_size, kReadBufSize);
+ if (!read_buffer_.get())
+ read_buffer_ = new net::IOBuffer(kReadBufSize);
+ *buf = read_buffer_.get();
+ *buf_size = kReadBufSize;
+}
+
+void StreamWriter::OnReadCompleted(int bytes_read, bool* defer) {
+ if (!bytes_read)
+ return;
+
+ // We have more data to read.
+ DCHECK(read_buffer_.get());
+
+ // Release the ownership of the buffer, and store a reference
+ // to it. A new one will be allocated in OnWillRead().
+ scoped_refptr<net::IOBuffer> buffer;
+ read_buffer_.swap(buffer);
+ stream_->AddData(buffer, bytes_read);
+
+ if (!stream_->can_add_data())
+ *defer = true;
+}
+
+void StreamWriter::Finalize() {
+ DCHECK(stream_.get());
+ stream_->Finalize();
+ stream_->RemoveWriteObserver(this);
+ stream_ = nullptr;
+}
+
+void StreamWriter::OnSpaceAvailable(Stream* stream) {
+ controller_->Resume();
+}
+
+void StreamWriter::OnClose(Stream* stream) {
+ controller_->Cancel();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/loader/stream_writer.h b/chromium/content/browser/loader/stream_writer.h
new file mode 100644
index 00000000000..a611e26dde6
--- /dev/null
+++ b/chromium/content/browser/loader/stream_writer.h
@@ -0,0 +1,83 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_LOADER_STREAM_WRITER_H_
+#define CONTENT_BROWSER_LOADER_STREAM_WRITER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "content/browser/streams/stream_write_observer.h"
+
+class GURL;
+
+namespace net {
+class IOBuffer;
+}
+
+namespace content {
+
+class ResourceController;
+class Stream;
+class StreamRegistry;
+
+// StreamWriter is a helper class for ResourceHandlers which route their output
+// into a Stream. It manages an internal buffer and handles back-pressure from
+// the Stream's reader.
+class StreamWriter : public StreamWriteObserver {
+ public:
+ // Creates a new StreamWriter without an initialized Stream or controller. The
+ // controller must be set before the writer is used.
+ StreamWriter();
+ ~StreamWriter() override;
+
+ Stream* stream() { return stream_.get(); }
+
+ void set_controller(ResourceController* controller) {
+ controller_ = controller;
+ }
+
+ // Initializes the writer with a new Stream in |registry|. |origin| will be
+ // used to construct the URL for the Stream. See WebCore::BlobURL and and
+ // WebCore::SecurityOrigin in Blink to understand how origin check is done on
+ // resource loading.
+ void InitializeStream(StreamRegistry* registry,
+ const GURL& origin);
+
+ // Prepares a buffer to read data from the request. This call will be followed
+ // by either OnReadCompleted (on successful read or EOF) or destruction. The
+ // buffer may not be recycled until OnReadCompleted is called. If |min_size|
+ // is not -1, it is the minimum size of the returned buffer.
+ //
+ // OnWillRead may be called before the stream is initialized. This is to
+ // support BufferedResourceHandler which reads the initial chunk of data
+ // early.
+ void OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size);
+
+ // A read was completed, forward the data to the Stream. If |*defer| is set to
+ // true, the implementation must not continue to process the request until
+ // Resume is called on |controller_|.
+ //
+ // InitializeStream must have been called before calling OnReadCompleted.
+ void OnReadCompleted(int bytes_read, bool* defer);
+
+ // Called when there is no more data to read to the stream.
+ void Finalize();
+
+ private:
+ // StreamWriteObserver implementation.
+ void OnSpaceAvailable(Stream* stream) override;
+ void OnClose(Stream* stream) override;
+
+ ResourceController* controller_;
+ scoped_refptr<Stream> stream_;
+ scoped_refptr<net::IOBuffer> read_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(StreamWriter);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_LOADER_STREAM_WRITER_H_
diff --git a/chromium/content/browser/loader/sync_resource_handler.cc b/chromium/content/browser/loader/sync_resource_handler.cc
index 090b9391056..1da8887daa9 100644
--- a/chromium/content/browser/loader/sync_resource_handler.cc
+++ b/chromium/content/browser/loader/sync_resource_handler.cc
@@ -14,6 +14,7 @@
#include "content/public/browser/resource_request_info.h"
#include "net/base/io_buffer.h"
#include "net/http/http_response_headers.h"
+#include "net/url_request/redirect_info.h"
namespace content {
@@ -45,23 +46,24 @@ bool SyncResourceHandler::OnUploadProgress(uint64 position, uint64 size) {
}
bool SyncResourceHandler::OnRequestRedirected(
- const GURL& new_url,
+ const net::RedirectInfo& redirect_info,
ResourceResponse* response,
bool* defer) {
if (rdh_->delegate()) {
rdh_->delegate()->OnRequestRedirected(
- new_url, request(), GetRequestInfo()->GetContext(), response);
+ redirect_info.new_url, request(), GetRequestInfo()->GetContext(),
+ response);
}
DevToolsNetLogObserver::PopulateResponseInfo(request(), response);
// TODO(darin): It would be much better if this could live in WebCore, but
// doing so requires API changes at all levels. Similar code exists in
// WebCore/platform/network/cf/ResourceHandleCFNet.cpp :-(
- if (new_url.GetOrigin() != result_.final_url.GetOrigin()) {
+ if (redirect_info.new_url.GetOrigin() != result_.final_url.GetOrigin()) {
LOG(ERROR) << "Cross origin redirect denied";
return false;
}
- result_.final_url = new_url;
+ result_.final_url = redirect_info.new_url;
total_transfer_size_ += request()->GetTotalReceivedBytes();
return true;
diff --git a/chromium/content/browser/loader/sync_resource_handler.h b/chromium/content/browser/loader/sync_resource_handler.h
index 693b48f3b37..09713e2e504 100644
--- a/chromium/content/browser/loader/sync_resource_handler.h
+++ b/chromium/content/browser/loader/sync_resource_handler.h
@@ -31,24 +31,23 @@ class SyncResourceHandler : public ResourceHandler {
SyncResourceHandler(net::URLRequest* request,
IPC::Message* result_message,
ResourceDispatcherHostImpl* resource_dispatcher_host);
- virtual ~SyncResourceHandler();
+ ~SyncResourceHandler() override;
- virtual bool OnUploadProgress(uint64 position, uint64 size) OVERRIDE;
- virtual bool OnRequestRedirected(const GURL& new_url,
- ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
- int* buf_size,
- int min_size) OVERRIDE;
- virtual bool OnReadCompleted(int bytes_read, bool* defer) OVERRIDE;
- virtual void OnResponseCompleted(const net::URLRequestStatus& status,
- const std::string& security_info,
- bool* defer) OVERRIDE;
- virtual void OnDataDownloaded(int bytes_downloaded) OVERRIDE;
+ bool OnUploadProgress(uint64 position, uint64 size) override;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL& url, bool* defer) override;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
+ bool OnWillRead(scoped_refptr<net::IOBuffer>* buf,
+ int* buf_size,
+ int min_size) override;
+ bool OnReadCompleted(int bytes_read, bool* defer) override;
+ void OnResponseCompleted(const net::URLRequestStatus& status,
+ const std::string& security_info,
+ bool* defer) override;
+ void OnDataDownloaded(int bytes_downloaded) override;
private:
enum { kReadBufSize = 3840 };
diff --git a/chromium/content/browser/loader/temporary_file_stream.cc b/chromium/content/browser/loader/temporary_file_stream.cc
index 0569d490100..e904d88e107 100644
--- a/chromium/content/browser/loader/temporary_file_stream.cc
+++ b/chromium/content/browser/loader/temporary_file_stream.cc
@@ -10,9 +10,9 @@
#include "base/memory/ref_counted.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/file_stream.h"
-#include "webkit/common/blob/shareable_file_reference.h"
+#include "storage/common/blob/shareable_file_reference.h"
-using webkit_blob::ShareableFileReference;
+using storage::ShareableFileReference;
namespace content {
@@ -43,7 +43,7 @@ void DidCreateTemporaryFile(
scoped_ptr<net::FileStream> file_stream(
new net::FileStream(file_proxy->TakeFile(), task_runner));
- callback.Run(error_code, file_stream.Pass(), deletable_file);
+ callback.Run(error_code, file_stream.Pass(), deletable_file.get());
}
} // namespace
diff --git a/chromium/content/browser/loader/temporary_file_stream.h b/chromium/content/browser/loader/temporary_file_stream.h
index 1cb4bc25be8..280359636d8 100644
--- a/chromium/content/browser/loader/temporary_file_stream.h
+++ b/chromium/content/browser/loader/temporary_file_stream.h
@@ -14,7 +14,7 @@ namespace net {
class FileStream;
}
-namespace webkit_blob {
+namespace storage {
class ShareableFileReference;
}
@@ -22,20 +22,20 @@ namespace content {
typedef base::Callback<void(base::File::Error,
scoped_ptr<net::FileStream>,
- webkit_blob::ShareableFileReference*)>
+ storage::ShareableFileReference*)>
CreateTemporaryFileStreamCallback;
// Creates a temporary file and asynchronously calls |callback| with a
-// net::FileStream and webkit_blob::ShareableFileReference. The file is deleted
-// when the webkit_blob::ShareableFileReference is deleted. Note it is the
-// consumer's responsibility to ensure the webkit_blob::ShareableFileReference
+// net::FileStream and storage::ShareableFileReference. The file is deleted
+// when the storage::ShareableFileReference is deleted. Note it is the
+// consumer's responsibility to ensure the storage::ShareableFileReference
// stays in scope until net::FileStream has finished closing the file. On error,
// |callback| is called with an error in the first parameter.
//
// This function may only be called on the IO thread.
//
// TODO(davidben): Juggling the net::FileStream and
-// webkit_blob::ShareableFileReference lifetimes is a nuisance. The two should
+// storage::ShareableFileReference lifetimes is a nuisance. The two should
// be tied together so the consumer need not deal with it.
CONTENT_EXPORT void CreateTemporaryFileStream(
const CreateTemporaryFileStreamCallback& callback);
diff --git a/chromium/content/browser/loader/temporary_file_stream_unittest.cc b/chromium/content/browser/loader/temporary_file_stream_unittest.cc
index 1903d446b76..854a5ddf5ab 100644
--- a/chromium/content/browser/loader/temporary_file_stream_unittest.cc
+++ b/chromium/content/browser/loader/temporary_file_stream_unittest.cc
@@ -10,18 +10,18 @@
#include "base/basictypes.h"
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
+#include "storage/common/blob/shareable_file_reference.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/common/blob/shareable_file_reference.h"
-using webkit_blob::ShareableFileReference;
+using storage::ShareableFileReference;
namespace content {
diff --git a/chromium/content/browser/loader/throttling_resource_handler.cc b/chromium/content/browser/loader/throttling_resource_handler.cc
index a302f1da797..1f17d336b6d 100644
--- a/chromium/content/browser/loader/throttling_resource_handler.cc
+++ b/chromium/content/browser/loader/throttling_resource_handler.cc
@@ -31,22 +31,23 @@ ThrottlingResourceHandler::ThrottlingResourceHandler(
ThrottlingResourceHandler::~ThrottlingResourceHandler() {
}
-bool ThrottlingResourceHandler::OnRequestRedirected(const GURL& new_url,
- ResourceResponse* response,
- bool* defer) {
+bool ThrottlingResourceHandler::OnRequestRedirected(
+ const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) {
DCHECK(!cancelled_by_resource_throttle_);
*defer = false;
while (next_index_ < throttles_.size()) {
int index = next_index_;
- throttles_[index]->WillRedirectRequest(new_url, defer);
+ throttles_[index]->WillRedirectRequest(redirect_info.new_url, defer);
next_index_++;
if (cancelled_by_resource_throttle_)
return false;
if (*defer) {
OnRequestDefered(index);
deferred_stage_ = DEFERRED_REDIRECT;
- deferred_url_ = new_url;
+ deferred_redirect_ = redirect_info;
deferred_response_ = response;
return true; // Do not cancel.
}
@@ -54,7 +55,7 @@ bool ThrottlingResourceHandler::OnRequestRedirected(const GURL& new_url,
next_index_ = 0; // Reset for next time.
- return next_handler_->OnRequestRedirected(new_url, response, defer);
+ return next_handler_->OnRequestRedirected(redirect_info, response, defer);
}
bool ThrottlingResourceHandler::OnWillStart(const GURL& url, bool* defer) {
@@ -87,7 +88,7 @@ bool ThrottlingResourceHandler::OnBeforeNetworkStart(const GURL& url,
*defer = false;
while (next_index_ < throttles_.size()) {
int index = next_index_;
- throttles_[index]->OnBeforeNetworkStart(defer);
+ throttles_[index]->WillStartUsingNetwork(defer);
next_index_++;
if (cancelled_by_resource_throttle_)
return false;
@@ -199,13 +200,13 @@ void ThrottlingResourceHandler::ResumeNetworkStart() {
void ThrottlingResourceHandler::ResumeRedirect() {
DCHECK(!cancelled_by_resource_throttle_);
- GURL new_url = deferred_url_;
- deferred_url_ = GURL();
+ net::RedirectInfo redirect_info = deferred_redirect_;
+ deferred_redirect_ = net::RedirectInfo();
scoped_refptr<ResourceResponse> response;
deferred_response_.swap(response);
bool defer = false;
- if (!OnRequestRedirected(new_url, response.get(), &defer)) {
+ if (!OnRequestRedirected(redirect_info, response.get(), &defer)) {
controller()->Cancel();
} else if (!defer) {
controller()->Resume();
diff --git a/chromium/content/browser/loader/throttling_resource_handler.h b/chromium/content/browser/loader/throttling_resource_handler.h
index fd284dbba2c..0d1287d644e 100644
--- a/chromium/content/browser/loader/throttling_resource_handler.h
+++ b/chromium/content/browser/loader/throttling_resource_handler.h
@@ -9,6 +9,7 @@
#include "base/memory/scoped_vector.h"
#include "content/browser/loader/layered_resource_handler.h"
#include "content/public/browser/resource_controller.h"
+#include "net/url_request/redirect_info.h"
#include "url/gurl.h"
namespace net {
@@ -28,22 +29,21 @@ class ThrottlingResourceHandler : public LayeredResourceHandler,
ThrottlingResourceHandler(scoped_ptr<ResourceHandler> next_handler,
net::URLRequest* request,
ScopedVector<ResourceThrottle> throttles);
- virtual ~ThrottlingResourceHandler();
+ ~ThrottlingResourceHandler() override;
// LayeredResourceHandler overrides:
- virtual bool OnRequestRedirected(const GURL& url,
- ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnResponseStarted(ResourceResponse* response,
- bool* defer) OVERRIDE;
- virtual bool OnWillStart(const GURL& url, bool* defer) OVERRIDE;
- virtual bool OnBeforeNetworkStart(const GURL& url, bool* defer) OVERRIDE;
+ bool OnRequestRedirected(const net::RedirectInfo& redirect_info,
+ ResourceResponse* response,
+ bool* defer) override;
+ bool OnResponseStarted(ResourceResponse* response, bool* defer) override;
+ bool OnWillStart(const GURL& url, bool* defer) override;
+ bool OnBeforeNetworkStart(const GURL& url, bool* defer) override;
// ResourceController implementation:
- virtual void Cancel() OVERRIDE;
- virtual void CancelAndIgnore() OVERRIDE;
- virtual void CancelWithError(int error_code) OVERRIDE;
- virtual void Resume() OVERRIDE;
+ void Cancel() override;
+ void CancelAndIgnore() override;
+ void CancelWithError(int error_code) override;
+ void Resume() override;
private:
void ResumeStart();
@@ -68,6 +68,7 @@ class ThrottlingResourceHandler : public LayeredResourceHandler,
size_t next_index_;
GURL deferred_url_;
+ net::RedirectInfo deferred_redirect_;
scoped_refptr<ResourceResponse> deferred_response_;
bool cancelled_by_resource_throttle_;
diff --git a/chromium/content/browser/loader/upload_data_stream_builder.cc b/chromium/content/browser/loader/upload_data_stream_builder.cc
index 2db9fdf0fef..376e221d2a6 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder.cc
+++ b/chromium/content/browser/loader/upload_data_stream_builder.cc
@@ -7,15 +7,15 @@
#include "base/logging.h"
#include "content/browser/fileapi/upload_file_system_file_element_reader.h"
#include "content/common/resource_request_body.h"
+#include "net/base/elements_upload_data_stream.h"
#include "net/base/upload_bytes_element_reader.h"
-#include "net/base/upload_data_stream.h"
#include "net/base/upload_file_element_reader.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
-using webkit_blob::BlobData;
-using webkit_blob::BlobDataHandle;
-using webkit_blob::BlobStorageContext;
+using storage::BlobData;
+using storage::BlobDataHandle;
+using storage::BlobStorageContext;
namespace content {
namespace {
@@ -30,7 +30,7 @@ class BytesElementReader : public net::UploadBytesElementReader {
DCHECK_EQ(ResourceRequestBody::Element::TYPE_BYTES, element.type());
}
- virtual ~BytesElementReader() {}
+ ~BytesElementReader() override {}
private:
scoped_refptr<ResourceRequestBody> resource_request_body_;
@@ -55,7 +55,7 @@ class FileElementReader : public net::UploadFileElementReader {
DCHECK_EQ(ResourceRequestBody::Element::TYPE_FILE, element.type());
}
- virtual ~FileElementReader() {}
+ ~FileElementReader() override {}
private:
scoped_refptr<ResourceRequestBody> resource_request_body_;
@@ -64,12 +64,11 @@ class FileElementReader : public net::UploadFileElementReader {
};
void ResolveBlobReference(
- ResourceRequestBody* body,
- webkit_blob::BlobStorageContext* blob_context,
+ storage::BlobStorageContext* blob_context,
const ResourceRequestBody::Element& element,
std::vector<const ResourceRequestBody::Element*>* resolved_elements) {
DCHECK(blob_context);
- scoped_ptr<webkit_blob::BlobDataHandle> handle =
+ scoped_ptr<storage::BlobDataHandle> handle =
blob_context->GetBlobDataFromUUID(element.blob_uuid());
DCHECK(handle);
if (!handle)
@@ -85,11 +84,6 @@ void ResolveBlobReference(
DCHECK_NE(BlobData::Item::TYPE_BLOB, item.type());
resolved_elements->push_back(&item);
}
-
- // Ensure the blob and any attached shareable files survive until
- // upload completion. The |body| takes ownership of |handle|.
- const void* key = handle.get();
- body->SetUserData(key, handle.release());
}
} // namespace
@@ -97,14 +91,14 @@ void ResolveBlobReference(
scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
ResourceRequestBody* body,
BlobStorageContext* blob_context,
- fileapi::FileSystemContext* file_system_context,
+ storage::FileSystemContext* file_system_context,
base::TaskRunner* file_task_runner) {
// Resolve all blob elements.
std::vector<const ResourceRequestBody::Element*> resolved_elements;
for (size_t i = 0; i < body->elements()->size(); ++i) {
const ResourceRequestBody::Element& element = (*body->elements())[i];
if (element.type() == ResourceRequestBody::Element::TYPE_BLOB)
- ResolveBlobReference(body, blob_context, element, &resolved_elements);
+ ResolveBlobReference(blob_context, element, &resolved_elements);
else
resolved_elements.push_back(&element);
}
@@ -121,6 +115,9 @@ scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
new FileElementReader(body, file_task_runner, element));
break;
case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
+ // If |body| contains any filesystem URLs, the caller should have
+ // supplied a FileSystemContext.
+ DCHECK(file_system_context);
element_readers.push_back(
new content::UploadFileSystemFileElementReader(
file_system_context,
@@ -140,7 +137,8 @@ scoped_ptr<net::UploadDataStream> UploadDataStreamBuilder::Build(
}
return make_scoped_ptr(
- new net::UploadDataStream(element_readers.Pass(), body->identifier()));
+ new net::ElementsUploadDataStream(element_readers.Pass(),
+ body->identifier()));
}
} // namespace content
diff --git a/chromium/content/browser/loader/upload_data_stream_builder.h b/chromium/content/browser/loader/upload_data_stream_builder.h
index 60b6f337c22..228aade7979 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder.h
+++ b/chromium/content/browser/loader/upload_data_stream_builder.h
@@ -12,7 +12,7 @@ namespace base {
class TaskRunner;
}
-namespace fileapi {
+namespace storage {
class FileSystemContext;
}
@@ -20,7 +20,7 @@ namespace net {
class UploadDataStream;
}
-namespace webkit_blob {
+namespace storage {
class BlobStorageContext;
}
@@ -32,18 +32,18 @@ class CONTENT_EXPORT UploadDataStreamBuilder {
public:
// Creates a new UploadDataStream from this request body.
//
- // This also resolves any blob references using the given |blob_context|
- // and binds those blob references to the ResourceRequestBody ensuring that
- // the blob data remains valid for the lifetime of the ResourceRequestBody
- // object.
+ // If |body| contains any blob references, the caller is responsible for
+ // making sure them outlive the returned value of UploadDataStream. We do this
+ // by binding the BlobDataHandles of them to ResourceRequestBody in
+ // ResourceDispatcherHostImpl::BeginRequest().
//
// |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(
ResourceRequestBody* body,
- webkit_blob::BlobStorageContext* blob_context,
- fileapi::FileSystemContext* file_system_context,
+ storage::BlobStorageContext* blob_context,
+ storage::FileSystemContext* file_system_context,
base::TaskRunner* file_task_runner);
};
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 67a57e3d9ab..dfd22b25317 100644
--- a/chromium/content/browser/loader/upload_data_stream_builder_unittest.cc
+++ b/chromium/content/browser/loader/upload_data_stream_builder_unittest.cc
@@ -6,8 +6,8 @@
#include <algorithm>
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
@@ -16,13 +16,13 @@
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_data_stream.h"
#include "net/base/upload_file_element_reader.h"
+#include "storage/browser/blob/blob_storage_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-using webkit_blob::BlobData;
-using webkit_blob::BlobDataHandle;
-using webkit_blob::BlobStorageContext;
+using storage::BlobData;
+using storage::BlobDataHandle;
+using storage::BlobStorageContext;
namespace content {
namespace {
@@ -76,15 +76,17 @@ TEST(UploadDataStreamBuilderTest, CreateUploadDataStreamWithoutBlob) {
request_body.get(), NULL, NULL, base::MessageLoopProxy::current().get()));
EXPECT_EQ(kIdentifier, upload->identifier());
- ASSERT_EQ(request_body->elements()->size(), upload->element_readers().size());
+ ASSERT_TRUE(upload->GetElementReaders());
+ ASSERT_EQ(request_body->elements()->size(),
+ upload->GetElementReaders()->size());
const net::UploadBytesElementReader* r1 =
- upload->element_readers()[0]->AsBytesReader();
+ (*upload->GetElementReaders())[0]->AsBytesReader();
ASSERT_TRUE(r1);
EXPECT_EQ(kData, std::string(r1->bytes(), r1->length()));
const net::UploadFileElementReader* r2 =
- upload->element_readers()[1]->AsFileReader();
+ (*upload->GetElementReaders())[1]->AsFileReader();
ASSERT_TRUE(r2);
EXPECT_EQ(kFilePath, r2->path().value());
EXPECT_EQ(kFileOffset, r2->range_offset());
@@ -105,7 +107,7 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
const std::string blob_id0("id-0");
scoped_refptr<BlobData> blob_data(new BlobData(blob_id0));
scoped_ptr<BlobDataHandle> handle1 =
- blob_storage_context.AddFinishedBlob(blob_data);
+ blob_storage_context.AddFinishedBlob(blob_data.get());
const std::string blob_id1("id-1");
blob_data = new BlobData(blob_id1);
@@ -113,7 +115,7 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
blob_data->AppendFile(
base::FilePath(FILE_PATH_LITERAL("BlobFile.txt")), 0, 20, time1);
scoped_ptr<BlobDataHandle> handle2 =
- blob_storage_context.AddFinishedBlob(blob_data);
+ blob_storage_context.AddFinishedBlob(blob_data.get());
// Setup upload data elements for comparison.
ResourceRequestBody::Element blob_element1, blob_element2;
@@ -150,11 +152,12 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
NULL,
base::MessageLoopProxy::current().get()));
- ASSERT_EQ(2U, upload->element_readers().size());
+ ASSERT_TRUE(upload->GetElementReaders());
+ ASSERT_EQ(2U, upload->GetElementReaders()->size());
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[0], upload_element1));
+ *(*upload->GetElementReaders())[0], upload_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[1], upload_element2));
+ *(*upload->GetElementReaders())[1], upload_element2));
// Test having only one blob reference that refers to empty blob data.
request_body = new ResourceRequestBody();
@@ -165,7 +168,8 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
&blob_storage_context,
NULL,
base::MessageLoopProxy::current().get());
- ASSERT_EQ(0U, upload->element_readers().size());
+ ASSERT_TRUE(upload->GetElementReaders());
+ ASSERT_EQ(0U, upload->GetElementReaders()->size());
// Test having only one blob reference.
request_body = new ResourceRequestBody();
@@ -176,11 +180,12 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
&blob_storage_context,
NULL,
base::MessageLoopProxy::current().get());
- ASSERT_EQ(2U, upload->element_readers().size());
+ ASSERT_TRUE(upload->GetElementReaders());
+ ASSERT_EQ(2U, upload->GetElementReaders()->size());
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[0], blob_element1));
+ *(*upload->GetElementReaders())[0], blob_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[1], blob_element2));
+ *(*upload->GetElementReaders())[1], blob_element2));
// Test having one blob reference at the beginning.
request_body = new ResourceRequestBody();
@@ -199,15 +204,16 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
&blob_storage_context,
NULL,
base::MessageLoopProxy::current().get());
- ASSERT_EQ(4U, upload->element_readers().size());
+ ASSERT_TRUE(upload->GetElementReaders());
+ ASSERT_EQ(4U, upload->GetElementReaders()->size());
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[0], blob_element1));
+ *(*upload->GetElementReaders())[0], blob_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[1], blob_element2));
+ *(*upload->GetElementReaders())[1], blob_element2));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[2], upload_element1));
+ *(*upload->GetElementReaders())[2], upload_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[3], upload_element2));
+ *(*upload->GetElementReaders())[3], upload_element2));
// Test having one blob reference at the end.
request_body = new ResourceRequestBody();
@@ -226,15 +232,16 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
&blob_storage_context,
NULL,
base::MessageLoopProxy::current().get());
- ASSERT_EQ(4U, upload->element_readers().size());
+ ASSERT_TRUE(upload->GetElementReaders());
+ ASSERT_EQ(4U, upload->GetElementReaders()->size());
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[0], upload_element1));
+ *(*upload->GetElementReaders())[0], upload_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[1], upload_element2));
+ *(*upload->GetElementReaders())[1], upload_element2));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[2], blob_element1));
+ *(*upload->GetElementReaders())[2], blob_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[3], blob_element2));
+ *(*upload->GetElementReaders())[3], blob_element2));
// Test having one blob reference in the middle.
request_body = new ResourceRequestBody();
@@ -253,15 +260,16 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
&blob_storage_context,
NULL,
base::MessageLoopProxy::current().get());
- ASSERT_EQ(4U, upload->element_readers().size());
+ ASSERT_TRUE(upload->GetElementReaders());
+ ASSERT_EQ(4U, upload->GetElementReaders()->size());
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[0], upload_element1));
+ *(*upload->GetElementReaders())[0], upload_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[1], blob_element1));
+ *(*upload->GetElementReaders())[1], blob_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[2], blob_element2));
+ *(*upload->GetElementReaders())[2], blob_element2));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[3], upload_element2));
+ *(*upload->GetElementReaders())[3], upload_element2));
// Test having multiple blob references.
request_body = new ResourceRequestBody();
@@ -282,23 +290,24 @@ TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
&blob_storage_context,
NULL,
base::MessageLoopProxy::current().get());
- ASSERT_EQ(8U, upload->element_readers().size());
+ ASSERT_TRUE(upload->GetElementReaders());
+ ASSERT_EQ(8U, upload->GetElementReaders()->size());
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[0], blob_element1));
+ *(*upload->GetElementReaders())[0], blob_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[1], blob_element2));
+ *(*upload->GetElementReaders())[1], blob_element2));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[2], upload_element1));
+ *(*upload->GetElementReaders())[2], upload_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[3], blob_element1));
+ *(*upload->GetElementReaders())[3], blob_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[4], blob_element2));
+ *(*upload->GetElementReaders())[4], blob_element2));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[5], blob_element1));
+ *(*upload->GetElementReaders())[5], blob_element1));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[6], blob_element2));
+ *(*upload->GetElementReaders())[6], blob_element2));
EXPECT_TRUE(AreElementsEqual(
- *upload->element_readers()[7], upload_element2));
+ *(*upload->GetElementReaders())[7], upload_element2));
}
// Clean up for ASAN.
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/mach_broker_mac.h b/chromium/content/browser/mach_broker_mac.h
index dede40068eb..9088ca70265 100644
--- a/chromium/content/browser/mach_broker_mac.h
+++ b/chromium/content/browser/mach_broker_mac.h
@@ -44,10 +44,6 @@ class CONTENT_EXPORT MachBroker : public base::ProcessMetrics::PortProvider,
// and false if otherwise.
static bool ChildSendTaskPortToParent();
- // Returns the Mach port name to use when sending or receiving messages.
- // Does the Right Thing in the browser and in child processes.
- static std::string GetMachPortName();
-
// Returns the global MachBroker.
static MachBroker* GetInstance();
@@ -68,25 +64,25 @@ class CONTENT_EXPORT MachBroker : public base::ProcessMetrics::PortProvider,
void AddPlaceholderForPid(base::ProcessHandle pid);
// Implement |ProcessMetrics::PortProvider|.
- virtual mach_port_t TaskForPid(base::ProcessHandle process) const OVERRIDE;
+ mach_port_t TaskForPid(base::ProcessHandle process) const override;
// Implement |BrowserChildProcessObserver|.
- virtual void BrowserChildProcessHostDisconnected(
- const ChildProcessData& data) OVERRIDE;
- virtual void BrowserChildProcessCrashed(
- const ChildProcessData& data) OVERRIDE;
+ void BrowserChildProcessHostDisconnected(
+ const ChildProcessData& data) override;
+ void BrowserChildProcessCrashed(const ChildProcessData& data) override;
// Implement |NotificationObserver|.
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
+
private:
friend class MachBrokerTest;
friend class MachListenerThreadDelegate;
friend struct DefaultSingletonTraits<MachBroker>;
MachBroker();
- virtual ~MachBroker();
+ ~MachBroker() override;
// Updates the mapping for |pid| to include the given |mach_info|. Does
// nothing if PlaceholderForPid() has not already been called for the given
@@ -97,6 +93,9 @@ class CONTENT_EXPORT MachBroker : public base::ProcessMetrics::PortProvider,
// Removes all mappings belonging to |pid| from the broker.
void InvalidatePid(base::ProcessHandle pid);
+ // Returns the Mach port name to use when sending or receiving messages.
+ // Does the Right Thing in the browser and in child processes.
+ static std::string GetMachPortName();
// Callback used to register notifications on the UI thread.
void RegisterNotifications();
diff --git a/chromium/content/browser/mach_broker_mac.mm b/chromium/content/browser/mach_broker_mac.mm
index 1c9e6e55bd8..f2e5f985c32 100644
--- a/chromium/content/browser/mach_broker_mac.mm
+++ b/chromium/content/browser/mach_broker_mac.mm
@@ -85,7 +85,7 @@ class MachListenerThreadDelegate : public base::PlatformThread::Delegate {
}
// Implement |PlatformThread::Delegate|.
- virtual void ThreadMain() OVERRIDE {
+ void ThreadMain() override {
MachBroker_ParentRecvMsg msg;
bzero(&msg, sizeof(msg));
msg.header.msgh_size = sizeof(msg);
@@ -132,7 +132,6 @@ class MachListenerThreadDelegate : public base::PlatformThread::Delegate {
DISALLOW_COPY_AND_ASSIGN(MachListenerThreadDelegate);
};
-// static
bool MachBroker::ChildSendTaskPortToParent() {
// Look up the named MachBroker port that's been registered with the
// bootstrap server.
@@ -168,17 +167,6 @@ bool MachBroker::ChildSendTaskPortToParent() {
return true;
}
-// static
-std::string MachBroker::GetMachPortName() {
- const CommandLine* command_line = 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);
-}
-
-// static
MachBroker* MachBroker::GetInstance() {
return Singleton<MachBroker, LeakySingletonTraits<MachBroker> >::get();
}
@@ -286,6 +274,17 @@ void MachBroker::InvalidatePid(base::ProcessHandle pid) {
mach_map_.erase(it);
}
+// static
+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);
+}
+
void MachBroker::RegisterNotifications() {
registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
NotificationService::AllBrowserContextsAndSources());
diff --git a/chromium/content/browser/manifest/OWNERS b/chromium/content/browser/manifest/OWNERS
new file mode 100644
index 00000000000..2d282460822
--- /dev/null
+++ b/chromium/content/browser/manifest/OWNERS
@@ -0,0 +1 @@
+mlamouri@chromium.org
diff --git a/chromium/content/browser/manifest/manifest_browsertest.cc b/chromium/content/browser/manifest/manifest_browsertest.cc
new file mode 100644
index 00000000000..8eaca0a9445
--- /dev/null
+++ b/chromium/content/browser/manifest/manifest_browsertest.cc
@@ -0,0 +1,202 @@
+// 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 "base/command_line.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/manifest.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 "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace content {
+
+class ManifestBrowserTest : public ContentBrowserTest {
+ protected:
+ ManifestBrowserTest() {}
+ ~ManifestBrowserTest() override {}
+
+ void GetManifestAndWait() {
+ shell()->web_contents()->GetManifest(
+ base::Bind(&ManifestBrowserTest::OnGetManifest,
+ base::Unretained(this)));
+
+ message_loop_runner_ = new MessageLoopRunner();
+ message_loop_runner_->Run();
+ }
+
+ void OnGetManifest(const Manifest& manifest) {
+ manifest_ = manifest;
+ message_loop_runner_->Quit();
+ }
+
+ const Manifest& manifest() const {
+ return manifest_;
+ }
+
+ private:
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+ Manifest manifest_;
+
+ DISALLOW_COPY_AND_ASSIGN(ManifestBrowserTest);
+};
+
+// If a page has no manifest, requesting a manifest should return the empty
+// manifest.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, NoManifest) {
+ GURL test_url = GetTestUrl("manifest", "no-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+}
+
+// If a page manifest points to a 404 URL, requesting the manifest should return
+// the empty manifest.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, 404Manifest) {
+ GURL test_url = GetTestUrl("manifest", "404-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+}
+
+// If a page has an empty manifest, requesting the manifest should return the
+// empty manifest.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, EmptyManifest) {
+ GURL test_url = GetTestUrl("manifest", "empty-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+}
+
+// If a page's manifest can't be parsed correctly, requesting the manifest
+// should return an empty manifest.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, ParseErrorManifest) {
+ GURL test_url = GetTestUrl("manifest", "parse-error-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+}
+
+// If a page has a manifest that can be fetched and parsed, requesting the
+// manifest should return a properly filled manifest.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, DummyManifest) {
+ GURL test_url = GetTestUrl("manifest", "dummy-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ GetManifestAndWait();
+ EXPECT_FALSE(manifest().IsEmpty());
+}
+
+// If a page changes manifest during its life-time, requesting the manifest
+// should return the current manifest.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, DynamicManifest) {
+ GURL test_url = GetTestUrl("manifest", "dynamic-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ {
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+ }
+
+ {
+ std::string manifest_url =
+ GetTestUrl("manifest", "dummy-manifest.json").spec();
+ ASSERT_TRUE(content::ExecuteScript(
+ shell()->web_contents(), "setManifestTo('" + manifest_url + "')"));
+
+ GetManifestAndWait();
+ EXPECT_FALSE(manifest().IsEmpty());
+ }
+
+ {
+ std::string manifest_url =
+ GetTestUrl("manifest", "empty-manifest.json").spec();
+ ASSERT_TRUE(content::ExecuteScript(
+ shell()->web_contents(), "setManifestTo('" + manifest_url + "')"));
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+ }
+}
+
+// If a page's manifest lives in a different origin, it should follow the CORS
+// rules and requesting the manifest should return an empty manifest (unless the
+// response contains CORS headers).
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, CORSManifest) {
+ scoped_ptr<net::test_server::EmbeddedTestServer> cors_embedded_test_server(
+ new net::test_server::EmbeddedTestServer);
+
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ ASSERT_TRUE(cors_embedded_test_server->InitializeAndWaitUntilReady());
+ ASSERT_NE(embedded_test_server()->port(), cors_embedded_test_server->port());
+
+ GURL test_url =
+ embedded_test_server()->GetURL("/manifest/dynamic-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ std::string manifest_url =
+ cors_embedded_test_server->GetURL("/manifest/dummy-manifest.json").spec();
+ ASSERT_TRUE(content::ExecuteScript(shell()->web_contents(),
+ "setManifestTo('" + manifest_url + "')"));
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+}
+
+// If a page's manifest is in an unsecure origin while the page is in a secure
+// origin, requesting the manifest should return the empty manifest.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, MixedContentManifest) {
+ scoped_ptr<net::SpawnedTestServer> https_server(new net::SpawnedTestServer(
+ net::SpawnedTestServer::TYPE_HTTPS,
+ net::BaseTestServer::SSLOptions(net::BaseTestServer::SSLOptions::CERT_OK),
+ base::FilePath(FILE_PATH_LITERAL("content/test/data"))));
+
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ ASSERT_TRUE(https_server->Start());
+
+ GURL test_url =
+ embedded_test_server()->GetURL("/manifest/dynamic-manifest.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+
+ std::string manifest_url =
+ https_server->GetURL("/manifest/dummy-manifest.json").spec();
+ ASSERT_TRUE(content::ExecuteScript(shell()->web_contents(),
+ "setManifestTo('" + manifest_url + "')"));
+
+ GetManifestAndWait();
+ EXPECT_TRUE(manifest().IsEmpty());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/manifest/manifest_manager_host.cc b/chromium/content/browser/manifest/manifest_manager_host.cc
new file mode 100644
index 00000000000..50b3ecade66
--- /dev/null
+++ b/chromium/content/browser/manifest/manifest_manager_host.cc
@@ -0,0 +1,138 @@
+// 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/manifest/manifest_manager_host.h"
+
+#include "content/common/manifest_manager_messages.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/manifest.h"
+#include "content/public/common/result_codes.h"
+
+namespace content {
+
+namespace {
+
+void KillRenderer(RenderFrameHost* render_frame_host) {
+ base::ProcessHandle process_handle =
+ render_frame_host->GetProcess()->GetHandle();
+ if (process_handle == base::kNullProcessHandle)
+ return;
+ base::KillProcess(process_handle, RESULT_CODE_KILLED_BAD_MESSAGE, false);
+}
+
+} // anonymous namespace
+
+ManifestManagerHost::ManifestManagerHost(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
+}
+
+ManifestManagerHost::~ManifestManagerHost() {
+}
+
+ManifestManagerHost::CallbackMap* ManifestManagerHost::GetCallbackMapForFrame(
+ RenderFrameHost* render_frame_host) {
+ FrameCallbackMap::iterator it = pending_callbacks_.find(render_frame_host);
+ return it != pending_callbacks_.end() ? it->second : 0;
+}
+
+void ManifestManagerHost::RenderFrameDeleted(
+ RenderFrameHost* render_frame_host) {
+ CallbackMap* callbacks = GetCallbackMapForFrame(render_frame_host);
+ if (!callbacks)
+ return;
+
+ // Before deleting the callbacks, make sure they are called with a failure
+ // state. Do this in a block so the iterator is destroyed before |callbacks|.
+ {
+ CallbackMap::const_iterator it(callbacks);
+ for (; !it.IsAtEnd(); it.Advance())
+ it.GetCurrentValue()->Run(Manifest());
+ }
+
+ delete callbacks;
+ pending_callbacks_.erase(render_frame_host);
+}
+
+void ManifestManagerHost::GetManifest(RenderFrameHost* render_frame_host,
+ const GetManifestCallback& callback) {
+ CallbackMap* callbacks = GetCallbackMapForFrame(render_frame_host);
+ if (!callbacks) {
+ callbacks = new CallbackMap();
+ pending_callbacks_[render_frame_host] = callbacks;
+ }
+
+ int request_id = callbacks->Add(new GetManifestCallback(callback));
+
+ render_frame_host->Send(new ManifestManagerMsg_RequestManifest(
+ render_frame_host->GetRoutingID(), request_id));
+}
+
+bool ManifestManagerHost::OnMessageReceived(
+ const IPC::Message& message, RenderFrameHost* render_frame_host) {
+ bool handled = true;
+
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ManifestManagerHost, message,
+ render_frame_host)
+ IPC_MESSAGE_HANDLER(ManifestManagerHostMsg_RequestManifestResponse,
+ OnRequestManifestResponse)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void ManifestManagerHost::OnRequestManifestResponse(
+ RenderFrameHost* render_frame_host,
+ int request_id,
+ const Manifest& insecure_manifest) {
+ CallbackMap* callbacks = GetCallbackMapForFrame(render_frame_host);
+ if (!callbacks) {
+ DVLOG(1) << "Unexpected RequestManifestResponse to from renderer. "
+ "Killing renderer.";
+ KillRenderer(render_frame_host);
+ return;
+ }
+
+ GetManifestCallback* callback = callbacks->Lookup(request_id);
+ if (!callback) {
+ DVLOG(1) << "Received a request_id (" << request_id << ") from renderer "
+ "with no associated callback. Killing renderer.";
+ KillRenderer(render_frame_host);
+ return;
+ }
+
+ // When receiving a Manifest, the browser process can't trust that it is
+ // coming from a known and secure source. It must be processed accordingly.
+ Manifest manifest = insecure_manifest;
+ manifest.name = base::NullableString16(
+ manifest.name.string().substr(0, Manifest::kMaxIPCStringLength),
+ manifest.name.is_null());
+ manifest.short_name = base::NullableString16(
+ manifest.short_name.string().substr(0, Manifest::kMaxIPCStringLength),
+ manifest.short_name.is_null());
+ if (!manifest.start_url.is_valid())
+ manifest.start_url = GURL();
+ for (size_t i = 0; i < manifest.icons.size(); ++i) {
+ if (!manifest.icons[i].src.is_valid())
+ manifest.icons[i].src = GURL();
+ manifest.icons[i].type = base::NullableString16(
+ manifest.icons[i].type.string().substr(0,
+ Manifest::kMaxIPCStringLength),
+ manifest.icons[i].type.is_null());
+ }
+ manifest.gcm_sender_id = base::NullableString16(
+ manifest.gcm_sender_id.string().substr(
+ 0, Manifest::kMaxIPCStringLength),
+ manifest.gcm_sender_id.is_null());
+
+ callback->Run(manifest);
+ callbacks->Remove(request_id);
+ if (callbacks->IsEmpty()) {
+ delete callbacks;
+ pending_callbacks_.erase(render_frame_host);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/manifest/manifest_manager_host.h b/chromium/content/browser/manifest/manifest_manager_host.h
new file mode 100644
index 00000000000..aea980f0ba6
--- /dev/null
+++ b/chromium/content/browser/manifest/manifest_manager_host.h
@@ -0,0 +1,54 @@
+// 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_RENDERER_MANIFEST_MANIFEST_MANAGER_HOST_H_
+#define CONTENT_RENDERER_MANIFEST_MANIFEST_MANAGER_HOST_H_
+
+#include "base/callback_forward.h"
+#include "base/id_map.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+
+class RenderFrameHost;
+class WebContents;
+struct Manifest;
+
+// ManifestManagerHost is a helper class that allows callers to get the Manifest
+// associated with a frame. It handles the IPC messaging with the child process.
+// TODO(mlamouri): keep a cached version and a dirty bit here.
+class ManifestManagerHost : public WebContentsObserver {
+ public:
+ explicit ManifestManagerHost(WebContents* web_contents);
+ ~ManifestManagerHost() override;
+
+ typedef base::Callback<void(const Manifest&)> GetManifestCallback;
+
+ // Calls the given callback with the manifest associated with the
+ // given RenderFrameHost. If the frame has no manifest or if getting it failed
+ // the callback will have an empty manifest.
+ void GetManifest(RenderFrameHost*, const GetManifestCallback&);
+
+ // WebContentsObserver
+ bool OnMessageReceived(const IPC::Message&, RenderFrameHost*) override;
+ void RenderFrameDeleted(RenderFrameHost*) override;
+
+ private:
+ typedef IDMap<GetManifestCallback, IDMapOwnPointer> CallbackMap;
+ typedef base::hash_map<RenderFrameHost*, CallbackMap*> FrameCallbackMap;
+
+ void OnRequestManifestResponse(
+ RenderFrameHost*, int request_id, const Manifest&);
+
+ // Returns the CallbackMap associated with the given RenderFrameHost, or null.
+ CallbackMap* GetCallbackMapForFrame(RenderFrameHost*);
+
+ FrameCallbackMap pending_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(ManifestManagerHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_MANAGER_HOST_H_
diff --git a/chromium/content/browser/media/OWNERS b/chromium/content/browser/media/OWNERS
index b1afdbbadb8..2e3d17b05b9 100644
--- a/chromium/content/browser/media/OWNERS
+++ b/chromium/content/browser/media/OWNERS
@@ -1,12 +1,9 @@
-acolwell@chromium.org
dalecurtis@chromium.org
ddorwin@chromium.org
perkj@chromium.org
scherkus@chromium.org
-shadi@chromium.org
tommi@chromium.org
vrk@chromium.org
-wjia@chromium.org
xhwang@chromium.org
xians@chromium.org
@@ -14,3 +11,8 @@ per-file cast_*=hclam@chromium.org
per-file cast_*=hubbe@chromium.org
per-file cast_*=mikhal@chromium.org
per-file cast_*=pwestin@google.com
+
+per-file midi_*=toyoshim@chromium.org
+
+# For changes related to the tab media indicators.
+per-file audio_stream_monitor*=miu@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 197895261d7..a0cf7f7d738 100644
--- a/chromium/content/browser/media/android/browser_demuxer_android.cc
+++ b/chromium/content/browser/media/android/browser_demuxer_android.cc
@@ -21,12 +21,12 @@ class BrowserDemuxerAndroid::Internal : public media::DemuxerAndroid {
}
// media::DemuxerAndroid implementation.
- virtual void Initialize(media::DemuxerAndroidClient* client) OVERRIDE {
+ virtual void Initialize(media::DemuxerAndroidClient* client) override {
DCHECK(!ClientIDExists()) << demuxer_client_id_;
demuxer_->AddDemuxerClient(demuxer_client_id_, client);
}
- virtual void RequestDemuxerData(media::DemuxerStream::Type type) OVERRIDE {
+ virtual void RequestDemuxerData(media::DemuxerStream::Type type) override {
DCHECK(ClientIDExists()) << demuxer_client_id_;
demuxer_->Send(new MediaPlayerMsg_ReadFromDemuxer(
demuxer_client_id_, type));
@@ -34,7 +34,7 @@ class BrowserDemuxerAndroid::Internal : public media::DemuxerAndroid {
virtual void RequestDemuxerSeek(
const base::TimeDelta& time_to_seek,
- bool is_browser_seek) OVERRIDE {
+ bool is_browser_seek) override {
DCHECK(ClientIDExists()) << demuxer_client_id_;
demuxer_->Send(new MediaPlayerMsg_DemuxerSeekRequest(
demuxer_client_id_, time_to_seek, is_browser_seek));
diff --git a/chromium/content/browser/media/android/browser_demuxer_android.h b/chromium/content/browser/media/android/browser_demuxer_android.h
index 4ab7c8d84c2..1e7f799e68a 100644
--- a/chromium/content/browser/media/android/browser_demuxer_android.h
+++ b/chromium/content/browser/media/android/browser_demuxer_android.h
@@ -22,8 +22,8 @@ class CONTENT_EXPORT BrowserDemuxerAndroid : public BrowserMessageFilter {
// BrowserMessageFilter overrides.
virtual void OverrideThreadForMessage(const IPC::Message& message,
- BrowserThread::ID* thread) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ BrowserThread::ID* thread) override;
+ virtual bool OnMessageReceived(const IPC::Message& message) override;
// Returns an uninitialized demuxer implementation associated with
// |demuxer_client_id|, which can be used to communicate with the real demuxer
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 5df9016f7b7..b8016b471f4 100644
--- a/chromium/content/browser/media/android/browser_media_player_manager.cc
+++ b/chromium/content/browser/media/android/browser_media_player_manager.cc
@@ -26,6 +26,7 @@
#include "content/public/common/content_switches.h"
#include "media/base/android/media_player_bridge.h"
#include "media/base/android/media_source_player.h"
+#include "media/base/android/media_url_interceptor.h"
#include "media/base/media_switches.h"
using media::MediaPlayerAndroid;
@@ -40,6 +41,7 @@ namespace content {
const int kMediaPlayerThreshold = 1;
static BrowserMediaPlayerManager::Factory g_factory = NULL;
+static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
// static
void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
@@ -47,6 +49,12 @@ void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
}
// static
+void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
+ media::MediaUrlInterceptor* media_url_interceptor) {
+ media_url_interceptor_ = media_url_interceptor;
+}
+
+// static
BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
RenderFrameHost* rfh) {
if (g_factory)
@@ -75,9 +83,8 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
manager,
base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
- weak_ptr_factory_.GetWeakPtr()),
- media_player_params.frame_url);
+ media_player_params.frame_url,
+ media_player_params.allow_credentials);
BrowserMediaPlayerManager* browser_media_player_manager =
static_cast<BrowserMediaPlayerManager*>(manager);
ContentViewCoreImpl* content_view_core_impl =
@@ -103,8 +110,6 @@ MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
manager,
base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
- weak_ptr_factory_.GetWeakPtr()),
demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
media_player_params.frame_url);
}
@@ -164,15 +169,12 @@ void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
}
void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOverlayFullscreenVideoSubtitle)) {
- if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
- delegate->ToggleFullscreenModeForTab(web_contents_, false);
- if (RenderWidgetHostViewAndroid* view_android =
- static_cast<RenderWidgetHostViewAndroid*>(
- web_contents_->GetRenderWidgetHostView())) {
- view_android->SetOverlayVideoMode(false);
- }
+ if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
+ delegate->ToggleFullscreenModeForTab(web_contents_, false);
+ if (RenderWidgetHostViewAndroid* view_android =
+ static_cast<RenderWidgetHostViewAndroid*>(
+ web_contents_->GetRenderWidgetHostView())) {
+ view_android->SetOverlayVideoMode(false);
}
Send(
@@ -188,10 +190,12 @@ void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
player->SetVideoSurface(gfx::ScopedJavaSurface());
}
-void BrowserMediaPlayerManager::OnTimeUpdate(int player_id,
- base::TimeDelta current_time) {
- Send(
- new MediaPlayerMsg_MediaTimeUpdate(RoutingID(), player_id, current_time));
+void BrowserMediaPlayerManager::OnTimeUpdate(
+ int player_id,
+ base::TimeDelta current_timestamp,
+ base::TimeTicks current_time_ticks) {
+ Send(new MediaPlayerMsg_MediaTimeUpdate(
+ RoutingID(), player_id, current_timestamp, current_time_ticks));
}
void BrowserMediaPlayerManager::SetVideoSurface(
@@ -206,17 +210,11 @@ void BrowserMediaPlayerManager::SetVideoSurface(
return;
Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player->player_id()));
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOverlayFullscreenVideoSubtitle)) {
- return;
- }
if (RenderWidgetHostViewAndroid* view_android =
static_cast<RenderWidgetHostViewAndroid*>(
web_contents_->GetRenderWidgetHostView())) {
view_android->SetOverlayVideoMode(true);
}
- if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
- delegate->ToggleFullscreenModeForTab(web_contents_, true);
}
void BrowserMediaPlayerManager::OnMediaMetadataChanged(
@@ -254,8 +252,13 @@ void BrowserMediaPlayerManager::OnSeekRequest(
Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
}
-void BrowserMediaPlayerManager::PauseVideo() {
- Send(new MediaPlayerMsg_PauseVideo(RoutingID()));
+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(
@@ -284,7 +287,7 @@ BrowserMediaPlayerManager::GetMediaResourceGetter() {
RenderProcessHost* host = web_contents()->GetRenderProcessHost();
BrowserContext* context = host->GetBrowserContext();
StoragePartition* partition = host->GetStoragePartition();
- fileapi::FileSystemContext* file_system_context =
+ storage::FileSystemContext* file_system_context =
partition ? partition->GetFileSystemContext() : NULL;
// Eventually this needs to be fixed to pass the correct frame rather
// than just using the main frame.
@@ -297,6 +300,11 @@ BrowserMediaPlayerManager::GetMediaResourceGetter() {
return media_resource_getter_.get();
}
+media::MediaUrlInterceptor*
+BrowserMediaPlayerManager::GetMediaUrlInterceptor() {
+ return media_url_interceptor_;
+}
+
MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
return GetPlayer(fullscreen_player_id_);
}
@@ -435,11 +443,12 @@ void BrowserMediaPlayerManager::OnInitialize(
RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
web_contents()->GetRenderProcessHost());
- MediaPlayerAndroid* player = CreateMediaPlayer(
- media_player_params,
+ MediaPlayerAndroid* player =
+ CreateMediaPlayer(media_player_params,
- host->GetBrowserContext()->IsOffTheRecord(), this,
- host->browser_demuxer_android());
+ host->GetBrowserContext()->IsOffTheRecord(),
+ this,
+ host->browser_demuxer_android().get());
if (!player)
return;
@@ -487,7 +496,7 @@ void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (player)
- player->Release();
+ ReleasePlayer(player);
if (player_id == fullscreen_player_id_)
fullscreen_player_is_released_ = true;
}
@@ -498,6 +507,15 @@ void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
fullscreen_player_id_ = -1;
}
+void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) {
+ // Does nothing if we don't have a remote player
+}
+
+void BrowserMediaPlayerManager::OnRequestRemotePlaybackControl(
+ int /* player_id */) {
+ // Does nothing if we don't have a remote player
+}
+
void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
DCHECK(!GetPlayer(player->player_id()));
players_.push_back(player);
@@ -506,8 +524,8 @@ void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
it != players_.end(); ++it) {
- MediaPlayerAndroid* player = *it;
- if (player->player_id() == player_id) {
+ if ((*it)->player_id() == player_id) {
+ ReleaseMediaResources(player_id);
players_.erase(it);
break;
}
@@ -521,6 +539,7 @@ scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
it != players_.end(); ++it) {
if ((*it)->player_id() == player_id) {
previous_player = *it;
+ ReleaseMediaResources(player_id);
players_.weak_erase(it);
players_.push_back(player);
break;
@@ -539,7 +558,7 @@ bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
MediaPlayerAndroid* player) {
- player->Release();
+ ReleasePlayer(player);
}
void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
@@ -563,21 +582,23 @@ void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
for (it = players_.begin(); it != players_.end(); ++it) {
if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
fullscreen_player_id_ != (*it)->player_id()) {
- (*it)->Release();
+ ReleasePlayer(*it);
Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
(*it)->player_id()));
}
}
}
-void BrowserMediaPlayerManager::OnMediaResourcesReleased(int player_id) {
+void BrowserMediaPlayerManager::ReleaseMediaResources(int player_id) {
#if defined(VIDEO_HOLE)
- MediaPlayerAndroid* player = GetPlayer(player_id);
- if (player && player->IsSurfaceInUse())
- return;
if (external_video_surface_container_)
external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
#endif // defined(VIDEO_HOLE)
}
+void BrowserMediaPlayerManager::ReleasePlayer(MediaPlayerAndroid* player) {
+ player->Release();
+ ReleaseMediaResources(player->player_id());
+}
+
} // namespace content
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 4c533885bf6..36506cd8241 100644
--- a/chromium/content/browser/media/android/browser_media_player_manager.h
+++ b/chromium/content/browser/media/android/browser_media_player_manager.h
@@ -16,6 +16,7 @@
#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/rect_f.h"
#include "url/gurl.h"
@@ -44,6 +45,10 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*);
static void RegisterFactory(Factory factory);
+ // Permits embedders to handle custom urls.
+ static void RegisterMediaUrlInterceptor(
+ media::MediaUrlInterceptor* media_url_interceptor);
+
// Returns a new instance using the registered factory if available.
static BrowserMediaPlayerManager* Create(RenderFrameHost* rfh);
@@ -62,33 +67,36 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
// Any actual seek started by renderer will be handled by browser in OnSeek().
void OnSeekRequest(int player_id, const base::TimeDelta& time_to_seek);
- // Pauses all video players manages by this class.
- void PauseVideo();
+ // Stops and releases every media managed by this class.
+ void ReleaseAllMediaPlayers();
// media::MediaPlayerManager overrides.
virtual void OnTimeUpdate(
- int player_id, base::TimeDelta current_time) OVERRIDE;
+ int player_id,
+ base::TimeDelta current_timestamp,
+ base::TimeTicks current_time_ticks) override;
virtual void OnMediaMetadataChanged(
int player_id,
base::TimeDelta duration,
int width,
int height,
- bool success) OVERRIDE;
- virtual void OnPlaybackComplete(int player_id) OVERRIDE;
- virtual void OnMediaInterrupted(int player_id) OVERRIDE;
- virtual void OnBufferingUpdate(int player_id, int percentage) OVERRIDE;
+ bool success) override;
+ virtual void OnPlaybackComplete(int player_id) override;
+ virtual void OnMediaInterrupted(int player_id) override;
+ virtual void OnBufferingUpdate(int player_id, int percentage) override;
virtual void OnSeekComplete(
int player_id,
- const base::TimeDelta& current_time) OVERRIDE;
- virtual void OnError(int player_id, int error) OVERRIDE;
+ const base::TimeDelta& current_time) override;
+ virtual void OnError(int player_id, int error) override;
virtual void OnVideoSizeChanged(
- int player_id, int width, int height) OVERRIDE;
- virtual media::MediaResourceGetter* GetMediaResourceGetter() OVERRIDE;
- virtual media::MediaPlayerAndroid* GetFullscreenPlayer() OVERRIDE;
- virtual media::MediaPlayerAndroid* GetPlayer(int player_id) OVERRIDE;
- virtual void RequestFullScreen(int player_id) OVERRIDE;
+ int player_id, int width, int height) override;
+ virtual media::MediaResourceGetter* GetMediaResourceGetter() override;
+ virtual media::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
+ virtual media::MediaPlayerAndroid* GetFullscreenPlayer() override;
+ virtual media::MediaPlayerAndroid* GetPlayer(int player_id) override;
+ virtual void RequestFullScreen(int player_id) override;
#if defined(VIDEO_HOLE)
- virtual bool ShouldUseVideoOverlayForEmbeddedEncryptedVideo() OVERRIDE;
+ virtual bool ShouldUseVideoOverlayForEmbeddedEncryptedVideo() override;
void AttachExternalVideoSurface(int player_id, jobject surface);
void DetachExternalVideoSurface(int player_id);
@@ -107,6 +115,8 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
virtual void OnSetPoster(int player_id, const GURL& poster);
virtual void OnReleaseResources(int player_id);
virtual void OnDestroyPlayer(int player_id);
+ virtual void OnRequestRemotePlayback(int player_id);
+ virtual void OnRequestRemotePlaybackControl(int player_id);
virtual void ReleaseFullscreenPlayer(media::MediaPlayerAndroid* player);
#if defined(VIDEO_HOLE)
void OnNotifyExternalSurface(
@@ -152,9 +162,11 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
// constrained by hardware and memory limits.
virtual void OnMediaResourcesRequested(int player_id);
- // Similar to the above call, MediaPlayerAndroid must call this method when
- // releasing all the decoding resources.
- virtual void OnMediaResourcesReleased(int player_id);
+ // Called when a player releases all decoding resources.
+ void ReleaseMediaResources(int player_id);
+
+ // Releases the player. However, don't remove it from |players_|.
+ void ReleasePlayer(media::MediaPlayerAndroid* player);
#if defined(VIDEO_HOLE)
void OnRequestExternalSurface(int player_id, const gfx::RectF& rect);
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 bcf293d9252..686e01c331c 100644
--- a/chromium/content/browser/media/android/media_resource_getter_impl.cc
+++ b/chromium/content/browser/media/android/media_resource_getter_impl.cc
@@ -12,19 +12,24 @@
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/browser/resource_context_impl.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/common/content_client.h"
#include "content/public/common/url_constants.h"
#include "jni/MediaResourceGetter_jni.h"
+#include "media/base/android/media_url_interceptor.h"
+#include "net/base/auth.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
+#include "net/http/http_auth.h"
+#include "net/http/http_transaction_factory.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
#include "url/gurl.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/blob/blob_storage_context.h"
using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;
@@ -40,15 +45,27 @@ static void ReturnResultOnUIThread(
static void RequestPlatformPathFromBlobURL(
const GURL& url,
- BrowserContext* browser_context,
+ ResourceContext* resource_context,
const base::Callback<void(const std::string&)>& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ChromeBlobStorageContext* context =
- ChromeBlobStorageContext::GetFor(browser_context);
- scoped_ptr<webkit_blob::BlobDataHandle> handle =
- context->context()->GetBlobDataFromPublicURL(url);
- const std::vector<webkit_blob::BlobData::Item> items =
- handle->data()->items();
+ ChromeBlobStorageContext* blob_storage_context =
+ GetChromeBlobStorageContextForResourceContext(resource_context);
+
+ scoped_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
+ // when JS has aready revoked the given blob URL via URL.revokeObjectURL
+ ReturnResultOnUIThread(callback, std::string());
+ return;
+ }
+ storage::BlobData* data = handle->data();
+ if (!data) {
+ ReturnResultOnUIThread(callback, std::string());
+ NOTREACHED();
+ return;
+ }
+ const std::vector<storage::BlobData::Item> items = data->items();
// TODO(qinmin): handle the case when the blob data is not a single file.
DLOG_IF(WARNING, items.size() != 1u)
@@ -59,7 +76,7 @@ static void RequestPlatformPathFromBlobURL(
static void RequestPlaformPathFromFileSystemURL(
const GURL& url,
int render_process_id,
- scoped_refptr<fileapi::FileSystemContext> file_system_context,
+ scoped_refptr<storage::FileSystemContext> file_system_context,
const base::Callback<void(const std::string&)>& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::FilePath platform_path;
@@ -75,7 +92,21 @@ static void RequestPlaformPathFromFileSystemURL(
ReturnResultOnUIThread(callback, std::string());
}
-// Get the metadata from a media URL. When finished, a task is posted to the UI
+// Posts a task to the UI thread to run the callback function.
+static void PostMediaMetadataCallbackTask(
+ const media::MediaResourceGetter::ExtractMediaMetadataCB& callback,
+ JNIEnv* env, ScopedJavaLocalRef<jobject>& j_metadata) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(callback, base::TimeDelta::FromMilliseconds(
+ Java_MediaMetadata_getDurationInMilliseconds(
+ env, j_metadata.obj())),
+ Java_MediaMetadata_getWidth(env, j_metadata.obj()),
+ Java_MediaMetadata_getHeight(env, j_metadata.obj()),
+ Java_MediaMetadata_isSuccess(env, j_metadata.obj())));
+}
+
+// Gets the metadata from a media URL. When finished, a task is posted to the UI
// thread to run the callback function.
static void GetMediaMetadata(
const std::string& url, const std::string& cookies,
@@ -94,40 +125,52 @@ static void GetMediaMetadata(
j_url_string.obj(),
j_cookies.obj(),
j_user_agent.obj());
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(callback, base::TimeDelta::FromMilliseconds(
- Java_MediaMetadata_getDurationInMilliseconds(
- env, j_metadata.obj())),
- Java_MediaMetadata_getWidth(env, j_metadata.obj()),
- Java_MediaMetadata_getHeight(env, j_metadata.obj()),
- Java_MediaMetadata_isSuccess(env, j_metadata.obj())));
+
+ PostMediaMetadataCallbackTask(callback, env, j_metadata);
+}
+
+// Gets the metadata from a file descriptor. When finished, a task is posted to
+// the UI thread to run the callback function.
+static void GetMediaMetadataFromFd(
+ const int fd, const int64 offset, const int64 size,
+ const media::MediaResourceGetter::ExtractMediaMetadataCB& callback) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+
+ ScopedJavaLocalRef<jobject> j_metadata =
+ Java_MediaResourceGetter_extractMediaMetadataFromFd(
+ env, fd, offset, size);
+
+ PostMediaMetadataCallbackTask(callback, env, j_metadata);
}
-// The task object that retrieves cookie on the IO thread.
+// The task object that retrieves media resources on the IO thread.
// TODO(qinmin): refactor this class to make the code reusable by others as
// there are lots of duplicated functionalities elsewhere.
-class CookieGetterTask
- : public base::RefCountedThreadSafe<CookieGetterTask> {
+// http://crbug.com/395762.
+class MediaResourceGetterTask
+ : public base::RefCountedThreadSafe<MediaResourceGetterTask> {
public:
- CookieGetterTask(BrowserContext* browser_context,
- int render_process_id, int render_frame_id);
+ MediaResourceGetterTask(BrowserContext* browser_context,
+ int render_process_id, int render_frame_id);
- // Called by CookieGetterImpl to start getting cookies for a URL.
+ // Called by MediaResourceGetterImpl to start getting auth credentials.
+ net::AuthCredentials RequestAuthCredentials(const GURL& url) const;
+
+ // Called by MediaResourceGetterImpl to start getting cookies for a URL.
void RequestCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback);
private:
- friend class base::RefCountedThreadSafe<CookieGetterTask>;
- virtual ~CookieGetterTask();
+ friend class base::RefCountedThreadSafe<MediaResourceGetterTask>;
+ virtual ~MediaResourceGetterTask();
void CheckPolicyForCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback,
const net::CookieList& cookie_list);
- // Context getter used to get the CookieStore.
+ // Context getter used to get the CookieStore and auth cache.
net::URLRequestContextGetter* context_getter_;
// Resource context for checking cookie policies.
@@ -139,10 +182,10 @@ class CookieGetterTask
// Render frame id, used to check tab specific cookie policy.
int render_frame_id_;
- DISALLOW_COPY_AND_ASSIGN(CookieGetterTask);
+ DISALLOW_COPY_AND_ASSIGN(MediaResourceGetterTask);
};
-CookieGetterTask::CookieGetterTask(
+MediaResourceGetterTask::MediaResourceGetterTask(
BrowserContext* browser_context, int render_process_id, int render_frame_id)
: context_getter_(browser_context->GetRequestContext()),
resource_context_(browser_context->GetResourceContext()),
@@ -150,9 +193,32 @@ CookieGetterTask::CookieGetterTask(
render_frame_id_(render_frame_id) {
}
-CookieGetterTask::~CookieGetterTask() {}
+MediaResourceGetterTask::~MediaResourceGetterTask() {}
-void CookieGetterTask::RequestCookies(
+net::AuthCredentials MediaResourceGetterTask::RequestAuthCredentials(
+ const GURL& url) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ net::HttpTransactionFactory* factory =
+ context_getter_->GetURLRequestContext()->http_transaction_factory();
+ if (!factory)
+ return net::AuthCredentials();
+
+ net::HttpAuthCache* auth_cache =
+ factory->GetSession()->http_auth_cache();
+ if (!auth_cache)
+ return net::AuthCredentials();
+
+ net::HttpAuthCache::Entry* entry =
+ auth_cache->LookupByPath(url.GetOrigin(), url.path());
+
+ // TODO(qinmin): handle other auth schemes. See http://crbug.com/395219.
+ if (entry && entry->scheme() == net::HttpAuth::AUTH_SCHEME_BASIC)
+ return entry->credentials();
+ else
+ return net::AuthCredentials();
+}
+
+void MediaResourceGetterTask::RequestCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -173,14 +239,14 @@ void CookieGetterTask::RequestCookies(
net::CookieMonster* cookie_monster = cookie_store->GetCookieMonster();
if (cookie_monster) {
cookie_monster->GetAllCookiesForURLAsync(url, base::Bind(
- &CookieGetterTask::CheckPolicyForCookies, this,
+ &MediaResourceGetterTask::CheckPolicyForCookies, this,
url, first_party_for_cookies, callback));
} else {
callback.Run(std::string());
}
}
-void CookieGetterTask::CheckPolicyForCookies(
+void MediaResourceGetterTask::CheckPolicyForCookies(
const GURL& url, const GURL& first_party_for_cookies,
const media::MediaResourceGetter::GetCookieCB& callback,
const net::CookieList& cookie_list) {
@@ -190,8 +256,9 @@ void CookieGetterTask::CheckPolicyForCookies(
resource_context_, render_process_id_, render_frame_id_)) {
net::CookieStore* cookie_store =
context_getter_->GetURLRequestContext()->cookie_store();
- cookie_store->GetCookiesWithOptionsAsync(
- url, net::CookieOptions(), callback);
+ net::CookieOptions options;
+ options.set_include_httponly();
+ cookie_store->GetCookiesWithOptionsAsync(url, options, callback);
} else {
callback.Run(std::string());
}
@@ -199,22 +266,37 @@ void CookieGetterTask::CheckPolicyForCookies(
MediaResourceGetterImpl::MediaResourceGetterImpl(
BrowserContext* browser_context,
- fileapi::FileSystemContext* file_system_context,
+ storage::FileSystemContext* file_system_context,
int render_process_id,
int render_frame_id)
: browser_context_(browser_context),
file_system_context_(file_system_context),
render_process_id_(render_process_id),
render_frame_id_(render_frame_id),
- weak_factory_(this) {}
+ weak_factory_(this) {
+}
MediaResourceGetterImpl::~MediaResourceGetterImpl() {}
+void MediaResourceGetterImpl::GetAuthCredentials(
+ const GURL& url, const GetAuthCredentialsCB& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ scoped_refptr<MediaResourceGetterTask> task = new MediaResourceGetterTask(
+ browser_context_, 0, 0);
+
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&MediaResourceGetterTask::RequestAuthCredentials, task, url),
+ base::Bind(&MediaResourceGetterImpl::GetAuthCredentialsCallback,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
void MediaResourceGetterImpl::GetCookies(
const GURL& url, const GURL& first_party_for_cookies,
const GetCookieCB& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- scoped_refptr<CookieGetterTask> task = new CookieGetterTask(
+ scoped_refptr<MediaResourceGetterTask> task = new MediaResourceGetterTask(
browser_context_, render_process_id_, render_frame_id_);
GetCookieCB cb = base::Bind(&MediaResourceGetterImpl::GetCookiesCallback,
@@ -223,11 +305,18 @@ void MediaResourceGetterImpl::GetCookies(
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
- base::Bind(&CookieGetterTask::RequestCookies,
+ base::Bind(&MediaResourceGetterTask::RequestCookies,
task, url, first_party_for_cookies,
base::Bind(&ReturnResultOnUIThread, cb)));
}
+void MediaResourceGetterImpl::GetAuthCredentialsCallback(
+ const GetAuthCredentialsCB& callback,
+ const net::AuthCredentials& credentials) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ callback.Run(credentials.username(), credentials.password());
+}
+
void MediaResourceGetterImpl::GetCookiesCallback(
const GetCookieCB& callback, const std::string& cookies) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -248,11 +337,12 @@ void MediaResourceGetterImpl::GetPlatformPathFromURL(
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
- base::Bind(&RequestPlatformPathFromBlobURL, url, browser_context_, cb));
+ base::Bind(&RequestPlatformPathFromBlobURL, url,
+ browser_context_->GetResourceContext(), cb));
return;
}
- scoped_refptr<fileapi::FileSystemContext> context(file_system_context_);
+ scoped_refptr<storage::FileSystemContext> context(file_system_context_);
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
@@ -276,6 +366,16 @@ void MediaResourceGetterImpl::ExtractMediaMetadata(
base::Bind(&GetMediaMetadata, url, cookies, user_agent, callback));
}
+void MediaResourceGetterImpl::ExtractMediaMetadata(
+ const int fd, const int64 offset, const int64 size,
+ const ExtractMediaMetadataCB& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
+ pool->PostWorkerTask(
+ FROM_HERE,
+ base::Bind(&GetMediaMetadataFromFd, fd, offset, size, callback));
+}
+
// static
bool MediaResourceGetterImpl::RegisterMediaResourceGetter(JNIEnv* env) {
return RegisterNativesImpl(env);
diff --git a/chromium/content/browser/media/android/media_resource_getter_impl.h b/chromium/content/browser/media/android/media_resource_getter_impl.h
index c1ed4b97b36..4f0d2e81af8 100644
--- a/chromium/content/browser/media/android/media_resource_getter_impl.h
+++ b/chromium/content/browser/media/android/media_resource_getter_impl.h
@@ -12,9 +12,11 @@
#include "base/memory/weak_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "media/base/android/media_resource_getter.h"
+#include "media/base/android/media_url_interceptor.h"
+#include "net/base/auth.h"
#include "net/cookies/canonical_cookie.h"
-namespace fileapi {
+namespace storage {
class FileSystemContext;
}
@@ -35,26 +37,42 @@ class MediaResourceGetterImpl : public media::MediaResourceGetter {
// |render_process_id| are passed to retrieve the CookieStore.
// |file_system_context| are used to get the platform path.
MediaResourceGetterImpl(BrowserContext* browser_context,
- fileapi::FileSystemContext* file_system_context,
- int render_process_id, int render_frame_id);
+ storage::FileSystemContext* file_system_context,
+ int render_process_id,
+ int render_frame_id);
virtual ~MediaResourceGetterImpl();
// media::MediaResourceGetter implementation.
// Must be called on the UI thread.
- virtual void GetCookies(const GURL& url,
- const GURL& first_party_for_cookies,
- const GetCookieCB& callback) OVERRIDE;
+ virtual void GetAuthCredentials(
+ const GURL& url,
+ const GetAuthCredentialsCB& callback) override;
+ virtual void GetCookies(
+ const GURL& url,
+ const GURL& first_party_for_cookies,
+ const GetCookieCB& callback) override;
virtual void GetPlatformPathFromURL(
const GURL& url,
- const GetPlatformPathCB& callback) OVERRIDE;
+ const GetPlatformPathCB& callback) override;
virtual void ExtractMediaMetadata(
- const std::string& url, const std::string& cookies,
+ const std::string& url,
+ const std::string& cookies,
const std::string& user_agent,
- const ExtractMediaMetadataCB& callback) OVERRIDE;
+ const ExtractMediaMetadataCB& callback) override;
+ virtual void ExtractMediaMetadata(
+ const int fd,
+ const int64 offset,
+ const int64 size,
+ const ExtractMediaMetadataCB& callback) override;
static bool RegisterMediaResourceGetter(JNIEnv* env);
private:
+ // Called when GetAuthCredentials() finishes.
+ void GetAuthCredentialsCallback(
+ const GetAuthCredentialsCB& callback,
+ const net::AuthCredentials& credentials);
+
// Called when GetCookies() finishes.
void GetCookiesCallback(
const GetCookieCB& callback, const std::string& cookies);
@@ -67,7 +85,7 @@ class MediaResourceGetterImpl : public media::MediaResourceGetter {
BrowserContext* browser_context_;
// FileSystemContext to be used on FILE thread.
- fileapi::FileSystemContext* file_system_context_;
+ storage::FileSystemContext* file_system_context_;
// Render process id, used to check whether the process can access cookies.
int render_process_id_;
diff --git a/chromium/content/browser/media/audio_stream_monitor.cc b/chromium/content/browser/media/audio_stream_monitor.cc
new file mode 100644
index 00000000000..1d2f76f7f2c
--- /dev/null
+++ b/chromium/content/browser/media/audio_stream_monitor.cc
@@ -0,0 +1,162 @@
+// 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/media/audio_stream_monitor.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/invalidate_type.h"
+#include "content/public/browser/render_frame_host.h"
+
+namespace content {
+
+namespace {
+
+AudioStreamMonitor* AudioStreamMonitorFromRenderFrame(int render_process_id,
+ int render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ WebContentsImpl* const web_contents =
+ static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(
+ RenderFrameHost::FromID(render_process_id, render_frame_id)));
+ return web_contents ? web_contents->audio_stream_monitor() : NULL;
+}
+
+} // namespace
+
+AudioStreamMonitor::AudioStreamMonitor(WebContents* contents)
+ : web_contents_(contents),
+ clock_(&default_tick_clock_),
+ was_recently_audible_(false) {
+ DCHECK(web_contents_);
+}
+
+AudioStreamMonitor::~AudioStreamMonitor() {}
+
+bool AudioStreamMonitor::WasRecentlyAudible() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return was_recently_audible_;
+}
+
+// static
+void AudioStreamMonitor::StartMonitoringStream(
+ int render_process_id,
+ int render_frame_id,
+ int stream_id,
+ const ReadPowerAndClipCallback& read_power_callback) {
+ if (!monitoring_available())
+ return;
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&StartMonitoringHelper,
+ render_process_id,
+ render_frame_id,
+ stream_id,
+ read_power_callback));
+}
+
+// static
+void AudioStreamMonitor::StopMonitoringStream(int render_process_id,
+ int render_frame_id,
+ int stream_id) {
+ if (!monitoring_available())
+ return;
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&StopMonitoringHelper,
+ render_process_id,
+ render_frame_id,
+ stream_id));
+}
+
+// static
+void AudioStreamMonitor::StartMonitoringHelper(
+ int render_process_id,
+ int render_frame_id,
+ int stream_id,
+ const ReadPowerAndClipCallback& read_power_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ AudioStreamMonitor* const monitor =
+ AudioStreamMonitorFromRenderFrame(render_process_id, render_frame_id);
+ if (monitor) {
+ monitor->StartMonitoringStreamOnUIThread(
+ render_process_id, stream_id, read_power_callback);
+ }
+}
+
+// static
+void AudioStreamMonitor::StopMonitoringHelper(int render_process_id,
+ int render_frame_id,
+ int stream_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ AudioStreamMonitor* const monitor =
+ AudioStreamMonitorFromRenderFrame(render_process_id, render_frame_id);
+ if (monitor)
+ monitor->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
+}
+
+void AudioStreamMonitor::StartMonitoringStreamOnUIThread(
+ int render_process_id,
+ int stream_id,
+ const ReadPowerAndClipCallback& read_power_callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!read_power_callback.is_null());
+ poll_callbacks_[StreamID(render_process_id, stream_id)] = read_power_callback;
+ if (!poll_timer_.IsRunning()) {
+ poll_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond,
+ base::Bind(&AudioStreamMonitor::Poll, base::Unretained(this)));
+ }
+}
+
+void AudioStreamMonitor::StopMonitoringStreamOnUIThread(int render_process_id,
+ int stream_id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ poll_callbacks_.erase(StreamID(render_process_id, stream_id));
+ if (poll_callbacks_.empty())
+ poll_timer_.Stop();
+}
+
+void AudioStreamMonitor::Poll() {
+ for (StreamPollCallbackMap::const_iterator it = poll_callbacks_.begin();
+ it != poll_callbacks_.end();
+ ++it) {
+ // TODO(miu): A new UI for delivering specific power level and clipping
+ // information is still in the works. For now, we throw away all
+ // information except for "is it audible?"
+ const float power_dbfs = it->second.Run().first;
+ const float kSilenceThresholdDBFS = -72.24719896f;
+ if (power_dbfs >= kSilenceThresholdDBFS) {
+ last_blurt_time_ = clock_->NowTicks();
+ MaybeToggle();
+ break; // No need to poll remaining streams.
+ }
+ }
+}
+
+void AudioStreamMonitor::MaybeToggle() {
+ const bool indicator_was_on = was_recently_audible_;
+ const base::TimeTicks off_time =
+ last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds);
+ const base::TimeTicks now = clock_->NowTicks();
+ const bool should_indicator_be_on = now < off_time;
+
+ if (should_indicator_be_on != indicator_was_on) {
+ was_recently_audible_ = should_indicator_be_on;
+ web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+ }
+
+ if (!should_indicator_be_on) {
+ off_timer_.Stop();
+ } else if (!off_timer_.IsRunning()) {
+ off_timer_.Start(
+ FROM_HERE,
+ off_time - now,
+ base::Bind(&AudioStreamMonitor::MaybeToggle, base::Unretained(this)));
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/audio_stream_monitor.h b/chromium/content/browser/media/audio_stream_monitor.h
new file mode 100644
index 00000000000..d1a32d5f857
--- /dev/null
+++ b/chromium/content/browser/media/audio_stream_monitor.h
@@ -0,0 +1,153 @@
+// 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_MEDIA_AUDIO_STREAM_MONITOR_H_
+#define CONTENT_BROWSER_MEDIA_AUDIO_STREAM_MONITOR_H_
+
+#include <map>
+#include <utility>
+
+#include "base/callback_forward.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "build/build_config.h"
+#include "content/common/content_export.h"
+#include "media/audio/audio_output_controller.h"
+
+namespace base {
+class TickClock;
+}
+
+namespace content {
+class WebContents;
+
+// Repeatedly polls audio streams for their power levels, and "debounces" the
+// information into a simple, binary "was recently audible" result for the audio
+// indicators in the tab UI. The debouncing logic is to: 1) Turn on immediately
+// when sound is audible; and 2) Hold on for X amount of time after sound has
+// gone silent, then turn off. Said another way, we don't want tab indicators
+// to turn on/off repeatedly and annoy the user. AudioStreamMonitor sends UI
+// update notifications only when needed, but may be queried at any time.
+//
+// Each WebContentsImpl owns an AudioStreamMonitor.
+class CONTENT_EXPORT AudioStreamMonitor {
+ public:
+ explicit AudioStreamMonitor(WebContents* contents);
+ ~AudioStreamMonitor();
+
+ // Indicates if audio stream monitoring is available. It's only available if
+ // AudioOutputController can and will monitor output power levels.
+ static bool monitoring_available() {
+ return media::AudioOutputController::will_monitor_audio_levels();
+ }
+
+ // Returns true if audio has recently been audible from the tab. This is
+ // usually called whenever the tab data model is refreshed; but there are
+ // other use cases as well (e.g., the OOM killer uses this to de-prioritize
+ // the killing of tabs making sounds).
+ bool WasRecentlyAudible() const;
+
+ // Starts or stops audio level monitoring respectively for the stream owned by
+ // the specified renderer. Safe to call from any thread.
+ //
+ // The callback returns the current power level (in dBFS units) and the clip
+ // status (true if any part of the audio signal has clipped since the last
+ // callback run). |stream_id| must be unique within a |render_process_id|.
+ typedef base::Callback<std::pair<float, bool>()> ReadPowerAndClipCallback;
+ static void StartMonitoringStream(
+ int render_process_id,
+ int render_frame_id,
+ int stream_id,
+ const ReadPowerAndClipCallback& read_power_callback);
+ static void StopMonitoringStream(int render_process_id,
+ int render_frame_id,
+ int stream_id);
+
+ void set_was_recently_audible_for_testing(bool value) {
+ was_recently_audible_ = value;
+ }
+
+ private:
+ friend class AudioStreamMonitorTest;
+
+ enum {
+ // Desired polling frequency. Note: If this is set too low, short-duration
+ // "blip" sounds won't be detected. http://crbug.com/339133#c4
+ kPowerMeasurementsPerSecond = 15,
+
+ // Amount of time to hold a tab indicator on after its last blurt.
+ kHoldOnMilliseconds = 2000
+ };
+
+ // Helper methods for starting and stopping monitoring which lookup the
+ // identified renderer and forward calls to the correct AudioStreamMonitor.
+ static void StartMonitoringHelper(
+ int render_process_id,
+ int render_frame_id,
+ int stream_id,
+ const ReadPowerAndClipCallback& read_power_callback);
+ static void StopMonitoringHelper(int render_process_id,
+ int render_frame_id,
+ int stream_id);
+
+ // Starts polling the stream for audio stream power levels using |callback|.
+ void StartMonitoringStreamOnUIThread(
+ int render_process_id,
+ int stream_id,
+ const ReadPowerAndClipCallback& callback);
+
+ // Stops polling the stream, discarding the internal copy of the |callback|
+ // provided in the call to StartMonitoringStream().
+ void StopMonitoringStreamOnUIThread(int render_process_id, int stream_id);
+
+ // Called by |poll_timer_| to sample the power levels from each of the streams
+ // playing in the tab.
+ void Poll();
+
+ // Compares last known indicator state with what it should be, and triggers UI
+ // updates through |web_contents_| if needed. When the indicator is turned
+ // on, |off_timer_| is started to re-invoke this method in the future.
+ void MaybeToggle();
+
+ // The WebContents instance instance to receive indicator toggle
+ // notifications. This pointer should be valid for the lifetime of
+ // AudioStreamMonitor.
+ WebContents* const web_contents_;
+
+ // Note: |clock_| is always |&default_tick_clock_|, except during unit
+ // testing.
+ base::DefaultTickClock default_tick_clock_;
+ base::TickClock* const clock_;
+
+ // Confirms single-threaded access in debug builds.
+ base::ThreadChecker thread_checker_;
+
+ // The callbacks to read power levels for each stream. Only playing (i.e.,
+ // not paused) streams will have an entry in this map.
+ typedef std::pair<int, int> StreamID;
+ typedef std::map<StreamID, ReadPowerAndClipCallback> StreamPollCallbackMap;
+ StreamPollCallbackMap poll_callbacks_;
+
+ // Records the last time at which sound was audible from any stream.
+ base::TimeTicks last_blurt_time_;
+
+ // Set to true if the last call to MaybeToggle() determined the indicator
+ // should be turned on.
+ bool was_recently_audible_;
+
+ // Calls Poll() at regular intervals while |poll_callbacks_| is non-empty.
+ base::RepeatingTimer<AudioStreamMonitor> poll_timer_;
+
+ // Started only when an indicator is toggled on, to turn it off again in the
+ // future.
+ base::OneShotTimer<AudioStreamMonitor> off_timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioStreamMonitor);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_AUDIO_STREAM_MONITOR_H_
diff --git a/chromium/content/browser/media/audio_stream_monitor_unittest.cc b/chromium/content/browser/media/audio_stream_monitor_unittest.cc
new file mode 100644
index 00000000000..2b36d877bcc
--- /dev/null
+++ b/chromium/content/browser/media/audio_stream_monitor_unittest.cc
@@ -0,0 +1,297 @@
+// 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/media/audio_stream_monitor.h"
+
+#include <map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.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"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/test/test_renderer_host.h"
+#include "media/audio/audio_power_monitor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InvokeWithoutArgs;
+
+namespace content {
+
+namespace {
+
+const int kRenderProcessId = 1;
+const int kAnotherRenderProcessId = 2;
+const int kStreamId = 3;
+const int kAnotherStreamId = 6;
+
+// Used to confirm audio indicator state changes occur at the correct times.
+class MockWebContentsDelegate : public WebContentsDelegate {
+ public:
+ MOCK_METHOD2(NavigationStateChanged,
+ void(const WebContents* source, InvalidateTypes changed_flags));
+};
+
+} // namespace
+
+class AudioStreamMonitorTest : public RenderViewHostTestHarness {
+ public:
+ AudioStreamMonitorTest() {
+ // Start |clock_| at non-zero.
+ clock_.Advance(base::TimeDelta::FromSeconds(1000000));
+ }
+
+ void SetUp() override {
+ RenderViewHostTestHarness::SetUp();
+
+ WebContentsImpl* web_contents = reinterpret_cast<WebContentsImpl*>(
+ RenderViewHostTestHarness::web_contents());
+ web_contents->SetDelegate(&mock_web_contents_delegate_);
+ monitor_ = web_contents->audio_stream_monitor();
+ const_cast<base::TickClock*&>(monitor_->clock_) = &clock_;
+ }
+
+ base::TimeTicks GetTestClockTime() { return clock_.NowTicks(); }
+
+ void AdvanceClock(const base::TimeDelta& delta) { clock_.Advance(delta); }
+
+ AudioStreamMonitor::ReadPowerAndClipCallback CreatePollCallback(
+ int stream_id) {
+ return base::Bind(
+ &AudioStreamMonitorTest::ReadPower, base::Unretained(this), stream_id);
+ }
+
+ void SetStreamPower(int stream_id, float power) {
+ current_power_[stream_id] = power;
+ }
+
+ void SimulatePollTimerFired() { monitor_->Poll(); }
+
+ void SimulateOffTimerFired() { monitor_->MaybeToggle(); }
+
+ void ExpectIsPolling(int render_process_id, int stream_id, bool is_polling) {
+ const AudioStreamMonitor::StreamID key(render_process_id, stream_id);
+ EXPECT_EQ(
+ is_polling,
+ monitor_->poll_callbacks_.find(key) != monitor_->poll_callbacks_.end());
+ EXPECT_EQ(!monitor_->poll_callbacks_.empty(),
+ monitor_->poll_timer_.IsRunning());
+ }
+
+ void ExpectTabWasRecentlyAudible(bool was_audible,
+ const base::TimeTicks& last_blurt_time) {
+ EXPECT_EQ(was_audible, monitor_->was_recently_audible_);
+ EXPECT_EQ(last_blurt_time, monitor_->last_blurt_time_);
+ EXPECT_EQ(monitor_->was_recently_audible_,
+ monitor_->off_timer_.IsRunning());
+ }
+
+ void ExpectWebContentsWillBeNotifiedOnce(bool should_be_audible) {
+ EXPECT_CALL(
+ mock_web_contents_delegate_,
+ NavigationStateChanged(RenderViewHostTestHarness::web_contents(),
+ INVALIDATE_TYPE_TAB))
+ .WillOnce(InvokeWithoutArgs(
+ this,
+ should_be_audible
+ ? &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOn
+ : &AudioStreamMonitorTest::ExpectIsNotifyingForToggleOff))
+ .RetiresOnSaturation();
+ }
+
+ static base::TimeDelta one_polling_interval() {
+ return base::TimeDelta::FromSeconds(1) /
+ AudioStreamMonitor::kPowerMeasurementsPerSecond;
+ }
+
+ static base::TimeDelta holding_period() {
+ return base::TimeDelta::FromMilliseconds(
+ AudioStreamMonitor::kHoldOnMilliseconds);
+ }
+
+ void StartMonitoring(
+ int render_process_id,
+ int stream_id,
+ const AudioStreamMonitor::ReadPowerAndClipCallback& callback) {
+ monitor_->StartMonitoringStreamOnUIThread(
+ render_process_id, stream_id, callback);
+ }
+
+ void StopMonitoring(int render_process_id, int stream_id) {
+ monitor_->StopMonitoringStreamOnUIThread(render_process_id, stream_id);
+ }
+
+ protected:
+ AudioStreamMonitor* monitor_;
+
+ private:
+ std::pair<float, bool> ReadPower(int stream_id) {
+ return std::make_pair(current_power_[stream_id], false);
+ }
+
+ void ExpectIsNotifyingForToggleOn() {
+ EXPECT_TRUE(monitor_->WasRecentlyAudible());
+ }
+
+ void ExpectIsNotifyingForToggleOff() {
+ EXPECT_FALSE(monitor_->WasRecentlyAudible());
+ }
+
+ MockWebContentsDelegate mock_web_contents_delegate_;
+ base::SimpleTestTickClock clock_;
+ std::map<int, float> current_power_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioStreamMonitorTest);
+};
+
+// Tests that AudioStreamMonitor is polling while it has a
+// ReadPowerAndClipCallback, and is not polling at other times.
+TEST_F(AudioStreamMonitorTest, PollsWhenProvidedACallback) {
+ EXPECT_FALSE(monitor_->WasRecentlyAudible());
+ ExpectIsPolling(kRenderProcessId, kStreamId, false);
+
+ StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+ EXPECT_FALSE(monitor_->WasRecentlyAudible());
+ ExpectIsPolling(kRenderProcessId, kStreamId, true);
+
+ StopMonitoring(kRenderProcessId, kStreamId);
+ EXPECT_FALSE(monitor_->WasRecentlyAudible());
+ ExpectIsPolling(kRenderProcessId, kStreamId, false);
+}
+
+// Tests that AudioStreamMonitor debounces the power level readings it's taking,
+// which could be fluctuating rapidly between the audible versus silence
+// threshold. See comments in audio_stream_monitor.h for expected behavior.
+TEST_F(AudioStreamMonitorTest,
+ ImpulsesKeepIndicatorOnUntilHoldingPeriodHasPassed) {
+ StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+
+ // Expect WebContents will get one call form AudioStreamMonitor to toggle the
+ // indicator on upon the very first poll.
+ ExpectWebContentsWillBeNotifiedOnce(true);
+
+ // Loop, each time testing a slightly longer period of polled silence. The
+ // indicator should remain on throughout.
+ int num_silence_polls = 0;
+ base::TimeTicks last_blurt_time;
+ do {
+ // Poll an audible signal, and expect tab indicator state is on.
+ SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
+ last_blurt_time = GetTestClockTime();
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+ AdvanceClock(one_polling_interval());
+
+ // Poll a silent signal repeatedly, ensuring that the indicator is being
+ // held on during the holding period.
+ SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
+ for (int i = 0; i < num_silence_polls; ++i) {
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+ // Note: Redundant off timer firings should not have any effect.
+ SimulateOffTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+ AdvanceClock(one_polling_interval());
+ }
+
+ ++num_silence_polls;
+ } while (GetTestClockTime() < last_blurt_time + holding_period());
+
+ // At this point, the clock has just advanced to beyond the holding period, so
+ // the next firing of the off timer should turn off the tab indicator. Also,
+ // make sure it stays off for several cycles thereafter.
+ ExpectWebContentsWillBeNotifiedOnce(false);
+ for (int i = 0; i < 10; ++i) {
+ SimulateOffTimerFired();
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+ AdvanceClock(one_polling_interval());
+ }
+}
+
+// Tests that the AudioStreamMonitor correctly processes the blurts from two
+// different streams in the same tab.
+TEST_F(AudioStreamMonitorTest, HandlesMultipleStreamsBlurting) {
+ StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+ StartMonitoring(
+ kRenderProcessId, kAnotherStreamId, CreatePollCallback(kAnotherStreamId));
+
+ base::TimeTicks last_blurt_time;
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+
+ // Measure audible sound from the first stream and silence from the second.
+ // The indicator turns on (i.e., tab was recently audible).
+ ExpectWebContentsWillBeNotifiedOnce(true);
+ SetStreamPower(kStreamId, media::AudioPowerMonitor::max_power());
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
+ last_blurt_time = GetTestClockTime();
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+
+ // Halfway through the holding period, the second stream joins in. The
+ // indicator stays on.
+ AdvanceClock(holding_period() / 2);
+ SimulateOffTimerFired();
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
+ last_blurt_time = GetTestClockTime();
+ SimulatePollTimerFired(); // Restarts holding period.
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+
+ // Now, measure silence from both streams. After an entire holding period
+ // has passed (since the second stream joined in), the indicator should turn
+ // off.
+ ExpectWebContentsWillBeNotifiedOnce(false);
+ AdvanceClock(holding_period());
+ SimulateOffTimerFired();
+ SetStreamPower(kStreamId, media::AudioPowerMonitor::zero_power());
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+
+ // Now, measure silence from the first stream and audible sound from the
+ // second. The indicator turns back on.
+ ExpectWebContentsWillBeNotifiedOnce(true);
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::max_power());
+ last_blurt_time = GetTestClockTime();
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+
+ // From here onwards, both streams are silent. Halfway through the holding
+ // period, the indicator should not have changed.
+ SetStreamPower(kAnotherStreamId, media::AudioPowerMonitor::zero_power());
+ AdvanceClock(holding_period() / 2);
+ SimulatePollTimerFired();
+ SimulateOffTimerFired();
+ ExpectTabWasRecentlyAudible(true, last_blurt_time);
+
+ // Just past the holding period, the indicator should be turned off.
+ ExpectWebContentsWillBeNotifiedOnce(false);
+ AdvanceClock(holding_period() - (GetTestClockTime() - last_blurt_time));
+ SimulateOffTimerFired();
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+
+ // Polling should not turn the indicator back while both streams are remaining
+ // silent.
+ for (int i = 0; i < 100; ++i) {
+ AdvanceClock(one_polling_interval());
+ SimulatePollTimerFired();
+ ExpectTabWasRecentlyAudible(false, last_blurt_time);
+ }
+}
+
+TEST_F(AudioStreamMonitorTest, MultipleRendererProcesses) {
+ StartMonitoring(kRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+ StartMonitoring(
+ kAnotherRenderProcessId, kStreamId, CreatePollCallback(kStreamId));
+ ExpectIsPolling(kRenderProcessId, kStreamId, true);
+ ExpectIsPolling(kAnotherRenderProcessId, kStreamId, true);
+ StopMonitoring(kAnotherRenderProcessId, kStreamId);
+ ExpectIsPolling(kRenderProcessId, kStreamId, true);
+ ExpectIsPolling(kAnotherRenderProcessId, kStreamId, false);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/audio_mirroring_manager.cc b/chromium/content/browser/media/capture/audio_mirroring_manager.cc
index b8051fa73d0..a75eb3c6476 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager.cc
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager.cc
@@ -4,161 +4,211 @@
#include "content/browser/media/capture/audio_mirroring_manager.h"
-#include "content/public/browser/browser_thread.h"
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
namespace content {
namespace {
-// Debug utility to make sure methods of AudioMirroringManager are not invoked
-// more than once in a single call stack. In release builds, this compiles to
-// nothing and gets completely optimized out.
-class ReentrancyGuard {
- public:
-#ifdef NDEBUG
- ReentrancyGuard() {}
- ~ReentrancyGuard() {}
-#else
- ReentrancyGuard() {
- DCHECK(!inside_a_method_);
- inside_a_method_ = true;
- }
- ~ReentrancyGuard() {
- inside_a_method_ = false;
- }
-
- static bool inside_a_method_; // Safe to be static, since AMM is a singleton.
-#endif
-};
-
-#ifndef NDEBUG
-bool ReentrancyGuard::inside_a_method_ = false;
-#endif
+base::LazyInstance<AudioMirroringManager>::Leaky g_audio_mirroring_manager =
+ LAZY_INSTANCE_INITIALIZER;
} // namespace
-AudioMirroringManager::AudioMirroringManager() {}
+// static
+AudioMirroringManager* AudioMirroringManager::GetInstance() {
+ return g_audio_mirroring_manager.Pointer();
+}
-AudioMirroringManager::~AudioMirroringManager() {
- DCHECK(diverters_.empty());
- DCHECK(sessions_.empty());
+AudioMirroringManager::AudioMirroringManager() {
+ // Only *after* construction, check that AudioMirroringManager is being
+ // invoked on the same single thread.
+ thread_checker_.DetachFromThread();
}
+AudioMirroringManager::~AudioMirroringManager() {}
+
void AudioMirroringManager::AddDiverter(
- int render_process_id, int render_view_id, Diverter* diverter) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ReentrancyGuard guard;
+ int render_process_id, int render_frame_id, Diverter* diverter) {
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(diverter);
- // DCHECK(diverter not already in diverters_ under any key)
+ // DCHECK(diverter not already in routes_)
#ifndef NDEBUG
- for (DiverterMap::const_iterator it = diverters_.begin();
- it != diverters_.end(); ++it) {
- DCHECK_NE(diverter, it->second);
+ for (StreamRoutes::const_iterator it = routes_.begin();
+ it != routes_.end(); ++it) {
+ DCHECK_NE(diverter, it->diverter);
}
#endif
-
- // Add the diverter to the set of active diverters.
- const Target target(render_process_id, render_view_id);
- diverters_.insert(std::make_pair(target, diverter));
-
- // If a mirroring session is active, start diverting the audio stream
- // immediately.
- SessionMap::iterator session_it = sessions_.find(target);
- if (session_it != sessions_.end()) {
- diverter->StartDiverting(
- session_it->second->AddInput(diverter->GetAudioParameters()));
- }
+ routes_.push_back(StreamRoutingState(
+ SourceFrameRef(render_process_id, render_frame_id),
+ diverter));
+
+ // Query existing destinations to see whether to immediately start diverting
+ // the stream.
+ std::set<SourceFrameRef> candidates;
+ candidates.insert(routes_.back().source_render_frame);
+ InitiateQueriesToFindNewDestination(NULL, candidates);
}
-void AudioMirroringManager::RemoveDiverter(
- int render_process_id, int render_view_id, Diverter* diverter) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ReentrancyGuard guard;
-
- // Stop diverting the audio stream if a mirroring session is active.
- const Target target(render_process_id, render_view_id);
- SessionMap::iterator session_it = sessions_.find(target);
- if (session_it != sessions_.end())
- diverter->StopDiverting();
-
- // Remove the diverter from the set of active diverters.
- for (DiverterMap::iterator it = diverters_.lower_bound(target);
- it != diverters_.end() && it->first == target; ++it) {
- if (it->second == diverter) {
- diverters_.erase(it);
- break;
+void AudioMirroringManager::RemoveDiverter(Diverter* diverter) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Find and remove the entry from the routing table. If the stream is being
+ // diverted, it is stopped.
+ for (StreamRoutes::iterator it = routes_.begin(); it != routes_.end(); ++it) {
+ if (it->diverter == diverter) {
+ ChangeRoute(&(*it), NULL);
+ routes_.erase(it);
+ return;
}
}
+ NOTREACHED();
}
-void AudioMirroringManager::StartMirroring(
- int render_process_id, int render_view_id,
- MirroringDestination* destination) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ReentrancyGuard guard;
+void AudioMirroringManager::StartMirroring(MirroringDestination* destination) {
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(destination);
- // Insert an entry into the set of active mirroring sessions. If a mirroring
- // session is already active for |render_process_id| + |render_view_id|,
- // replace the entry.
- const Target target(render_process_id, render_view_id);
- SessionMap::iterator session_it = sessions_.find(target);
- MirroringDestination* old_destination;
- if (session_it == sessions_.end()) {
- old_destination = NULL;
- sessions_.insert(std::make_pair(target, destination));
-
- DVLOG(1) << "Start mirroring render_process_id:render_view_id="
- << render_process_id << ':' << render_view_id
- << " --> MirroringDestination@" << destination;
- } else {
- old_destination = session_it->second;
- session_it->second = destination;
-
- DVLOG(1) << "Switch mirroring of render_process_id:render_view_id="
- << render_process_id << ':' << render_view_id
- << " MirroringDestination@" << old_destination
- << " --> MirroringDestination@" << destination;
+ // Insert an entry into the set of active mirroring sessions, if this is a
+ // previously-unknown destination.
+ if (std::find(sessions_.begin(), sessions_.end(), destination) ==
+ sessions_.end()) {
+ sessions_.push_back(destination);
}
- // Divert audio streams coming from |target| to |destination|. If streams
- // were already diverted to the |old_destination|, remove them.
- for (DiverterMap::iterator it = diverters_.lower_bound(target);
- it != diverters_.end() && it->first == target; ++it) {
- Diverter* const diverter = it->second;
- if (old_destination)
- diverter->StopDiverting();
- diverter->StartDiverting(
- destination->AddInput(diverter->GetAudioParameters()));
+ // Query the MirroringDestination to see which of the audio streams should be
+ // diverted.
+ std::set<SourceFrameRef> candidates;
+ for (StreamRoutes::const_iterator it = routes_.begin(); it != routes_.end();
+ ++it) {
+ if (!it->destination || it->destination == destination)
+ candidates.insert(it->source_render_frame);
+ }
+ if (!candidates.empty()) {
+ destination->QueryForMatches(
+ candidates,
+ base::Bind(&AudioMirroringManager::UpdateRoutesToDestination,
+ base::Unretained(this),
+ destination,
+ false));
}
}
-void AudioMirroringManager::StopMirroring(
- int render_process_id, int render_view_id,
- MirroringDestination* destination) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- ReentrancyGuard guard;
-
- // Stop mirroring if there is an active session *and* the destination
- // matches.
- const Target target(render_process_id, render_view_id);
- SessionMap::iterator session_it = sessions_.find(target);
- if (session_it == sessions_.end() || destination != session_it->second)
- return;
-
- DVLOG(1) << "Stop mirroring render_process_id:render_view_id="
- << render_process_id << ':' << render_view_id
- << " --> MirroringDestination@" << destination;
+void AudioMirroringManager::StopMirroring(MirroringDestination* destination) {
+ DCHECK(thread_checker_.CalledOnValidThread());
// Stop diverting each audio stream in the mirroring session being stopped.
- for (DiverterMap::iterator it = diverters_.lower_bound(target);
- it != diverters_.end() && it->first == target; ++it) {
- it->second->StopDiverting();
+ // Each stopped stream becomes a candidate to be diverted to another
+ // destination.
+ std::set<SourceFrameRef> redivert_candidates;
+ for (StreamRoutes::iterator it = routes_.begin(); it != routes_.end(); ++it) {
+ if (it->destination == destination) {
+ ChangeRoute(&(*it), NULL);
+ redivert_candidates.insert(it->source_render_frame);
+ }
}
+ if (!redivert_candidates.empty())
+ InitiateQueriesToFindNewDestination(destination, redivert_candidates);
// Remove the entry from the set of active mirroring sessions.
- sessions_.erase(session_it);
+ const Destinations::iterator dest_it =
+ std::find(sessions_.begin(), sessions_.end(), destination);
+ if (dest_it == sessions_.end()) {
+ NOTREACHED();
+ return;
+ }
+ sessions_.erase(dest_it);
+}
+
+void AudioMirroringManager::InitiateQueriesToFindNewDestination(
+ MirroringDestination* old_destination,
+ const std::set<SourceFrameRef>& candidates) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ for (Destinations::const_iterator it = sessions_.begin();
+ it != sessions_.end(); ++it) {
+ if (*it != old_destination) {
+ (*it)->QueryForMatches(
+ candidates,
+ base::Bind(&AudioMirroringManager::UpdateRoutesToDestination,
+ base::Unretained(this),
+ *it,
+ true));
+ }
+ }
}
+void AudioMirroringManager::UpdateRoutesToDestination(
+ MirroringDestination* destination,
+ bool add_only,
+ const std::set<SourceFrameRef>& matches) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (std::find(sessions_.begin(), sessions_.end(), destination) ==
+ sessions_.end()) {
+ return; // Query result callback invoked after StopMirroring().
+ }
+
+ DVLOG(1) << (add_only ? "Add " : "Replace with ") << matches.size()
+ << " routes to MirroringDestination@" << destination;
+
+ // Start/stop diverting based on |matches|. Any stopped stream becomes a
+ // candidate to be diverted to another destination.
+ std::set<SourceFrameRef> redivert_candidates;
+ for (StreamRoutes::iterator it = routes_.begin(); it != routes_.end(); ++it) {
+ if (matches.find(it->source_render_frame) != matches.end()) {
+ // Only change the route if the stream is not already being diverted.
+ if (!it->destination)
+ ChangeRoute(&(*it), destination);
+ } else if (!add_only) {
+ // Only stop diverting if the stream is currently routed to |destination|.
+ if (it->destination == destination) {
+ ChangeRoute(&(*it), NULL);
+ redivert_candidates.insert(it->source_render_frame);
+ }
+ }
+ }
+ if (!redivert_candidates.empty())
+ InitiateQueriesToFindNewDestination(destination, redivert_candidates);
+}
+
+// static
+void AudioMirroringManager::ChangeRoute(
+ StreamRoutingState* route, MirroringDestination* new_destination) {
+ if (route->destination == new_destination)
+ return; // No change.
+
+ if (route->destination) {
+ DVLOG(1) << "Stop diverting render_process_id:render_frame_id="
+ << route->source_render_frame.first << ':'
+ << route->source_render_frame.second
+ << " --> MirroringDestination@" << route->destination;
+ route->diverter->StopDiverting();
+ route->destination = NULL;
+ }
+
+ if (new_destination) {
+ DVLOG(1) << "Start diverting of render_process_id:render_frame_id="
+ << route->source_render_frame.first << ':'
+ << route->source_render_frame.second
+ << " --> MirroringDestination@" << new_destination;
+ route->diverter->StartDiverting(
+ new_destination->AddInput(route->diverter->GetAudioParameters()));
+ route->destination = new_destination;
+ }
+}
+
+AudioMirroringManager::StreamRoutingState::StreamRoutingState(
+ const SourceFrameRef& source_frame, Diverter* stream_diverter)
+ : source_render_frame(source_frame),
+ diverter(stream_diverter),
+ destination(NULL) {}
+
+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 fe7db7ad52e..441c884ad92 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager.h
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager.h
@@ -5,32 +5,40 @@
// AudioMirroringManager is a singleton object that maintains a set of active
// audio mirroring destinations and auto-connects/disconnects audio streams
// to/from those destinations. It is meant to be used exclusively on the IO
-// BrowserThread.
+// thread.
//
// How it works:
//
// 1. AudioRendererHost gets a CreateStream message from the render process
// and, among other things, creates an AudioOutputController to control the
-// audio data flow between the render and browser processes.
-// 2. At some point, AudioRendererHost receives an "associate with render
-// view" message. Among other actions, it registers the
-// AudioOutputController with AudioMirroringManager (as a Diverter).
-// 3. A user request to mirror all the audio for a single RenderView is made.
-// A MirroringDestination is created, and StartMirroring() is called to
-// begin the mirroring session. This causes AudioMirroringManager to
-// instruct any matching Diverters to divert their audio data to the
-// MirroringDestination.
-//
-// #2 and #3 above may occur in any order, as it is the job of
-// AudioMirroringManager to realize when the players can be "matched up."
+// audio data flow between the render and browser processes. More
+// importantly, it registers the AudioOutputController with
+// AudioMirroringManager (as a Diverter).
+// 2. A user request to mirror all the audio for a WebContents is made. A
+// MirroringDestination is created, and StartMirroring() is called to begin
+// the mirroring session. The MirroringDestination is queried to determine
+// which of all the known Diverters will re-route their audio to it.
+// 3a. During a mirroring session, AudioMirroringManager may encounter new
+// Diverters, and will query all the MirroringDestinations to determine
+// which is a match, if any.
+// 3b. During a mirroring session, a call to StartMirroring() can be made to
+// request a "refresh" query on a MirroringDestination, and this will
+// result in AudioMirroringManager starting/stopping only those Diverters
+// that are not correctly routed to the destination.
+// 3c. When a mirroring session is stopped, the remaining destinations will be
+// queried to determine whether diverting should continue to a different
+// destination.
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_AUDIO_MIRRORING_MANAGER_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_AUDIO_MIRRORING_MANAGER_H_
-#include <map>
+#include <set>
#include <utility>
+#include <vector>
#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/threading/thread_checker.h"
#include "content/common/content_export.h"
#include "media/audio/audio_source_diverter.h"
@@ -45,10 +53,25 @@ class CONTENT_EXPORT AudioMirroringManager {
// Interface for diverting audio data to an alternative AudioOutputStream.
typedef media::AudioSourceDiverter Diverter;
+ // A SourceFrameRef is a RenderFrameHost identified by a <render_process_id,
+ // render_frame_id> pair.
+ typedef std::pair<int, int> SourceFrameRef;
+
// Interface to be implemented by audio mirroring destinations. See comments
// for StartMirroring() and StopMirroring() below.
class MirroringDestination {
public:
+ // Asynchronously query whether this MirroringDestination wants to consume
+ // audio sourced from each of the |candidates|. |results_callback| is run
+ // to indicate which of them (or none) should have audio routed to this
+ // MirroringDestination. |results_callback| must be run on the same thread
+ // as the one that called QueryForMatches().
+ typedef base::Callback<void(const std::set<SourceFrameRef>&)>
+ MatchesCallback;
+ virtual void QueryForMatches(
+ const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback) = 0;
+
// Create a consumer of audio data in the format specified by |params|, and
// connect it as an input to mirroring. When Close() is called on the
// returned AudioOutputStream, the input is disconnected and the object
@@ -60,45 +83,78 @@ class CONTENT_EXPORT AudioMirroringManager {
virtual ~MirroringDestination() {}
};
+ // Note: Use GetInstance() for non-test code.
AudioMirroringManager();
-
virtual ~AudioMirroringManager();
- // Add/Remove a diverter for an audio stream with a known RenderView target
- // (represented by |render_process_id| + |render_view_id|). Multiple
- // diverters may be added for the same target. |diverter| must live until
- // after RemoveDiverter() is called.
- //
- // Re-entrancy warning: These methods should not be called by a Diverter
- // during a Start/StopDiverting() invocation.
- virtual void AddDiverter(int render_process_id, int render_view_id,
+ // Returns the global instance.
+ static AudioMirroringManager* GetInstance();
+
+ // Add/Remove a diverter for an audio stream with a known RenderFrame source
+ // (represented by |render_process_id| + |render_frame_id|). Multiple
+ // diverters may be added for the same source frame, but never the same
+ // diverter. |diverter| must live until after RemoveDiverter() is called.
+ virtual void AddDiverter(int render_process_id, int render_frame_id,
Diverter* diverter);
- virtual void RemoveDiverter(int render_process_id, int render_view_id,
- Diverter* diverter);
-
- // Start/stop mirroring all audio output streams associated with a RenderView
- // target (represented by |render_process_id| + |render_view_id|) to
- // |destination|. |destination| must live until after StopMirroring() is
- // called.
- virtual void StartMirroring(int render_process_id, int render_view_id,
- MirroringDestination* destination);
- virtual void StopMirroring(int render_process_id, int render_view_id,
- MirroringDestination* destination);
+ virtual void RemoveDiverter(Diverter* diverter);
+
+ // (Re-)Start/Stop mirroring to the given |destination|. |destination| must
+ // live until after StopMirroring() is called. A client may request a
+ // re-start by calling StartMirroring() again; and this will cause
+ // AudioMirroringManager to query |destination| and only re-route those
+ // diverters that are missing/new to the returned set of matches.
+ virtual void StartMirroring(MirroringDestination* destination);
+ virtual void StopMirroring(MirroringDestination* destination);
private:
- // A mirroring target is a RenderView identified by a
- // <render_process_id, render_view_id> pair.
- typedef std::pair<int, int> Target;
+ friend class AudioMirroringManagerTest;
+
+ struct StreamRoutingState {
+ // The source render frame associated with the audio stream.
+ SourceFrameRef source_render_frame;
+
+ // The diverter for re-routing the audio stream.
+ Diverter* diverter;
+
+ // If not NULL, the audio stream is currently being diverted to this
+ // destination.
+ MirroringDestination* destination;
+
+ StreamRoutingState(const SourceFrameRef& source_frame,
+ Diverter* stream_diverter);
+ ~StreamRoutingState();
+ };
+
+ typedef std::vector<StreamRoutingState> StreamRoutes;
+ typedef std::vector<MirroringDestination*> Destinations;
+
+ // Helper to find a destination other than |old_destination| for the given
+ // |candidates| to be diverted to.
+ void InitiateQueriesToFindNewDestination(
+ MirroringDestination* old_destination,
+ const std::set<SourceFrameRef>& candidates);
+
+ // MirroringDestination query callback. |matches| contains all RenderFrame
+ // sources that will be diverted to |destination|. If |add_only| is false,
+ // then any Diverters currently routed to |destination| but not found in
+ // |matches| will be stopped.
+ void UpdateRoutesToDestination(MirroringDestination* destination,
+ bool add_only,
+ const std::set<SourceFrameRef>& matches);
+
+ // Starts diverting audio to the |new_destination|, if not NULL. Otherwise,
+ // stops diverting audio.
+ static void ChangeRoute(StreamRoutingState* route,
+ MirroringDestination* new_destination);
- // Note: Objects in these maps are not owned.
- typedef std::multimap<Target, Diverter*> DiverterMap;
- typedef std::map<Target, MirroringDestination*> SessionMap;
+ // Routing table. Contains one entry for each Diverter.
+ StreamRoutes routes_;
- // Currently-active divertable audio streams.
- DiverterMap diverters_;
+ // All active mirroring sessions.
+ Destinations sessions_;
- // Currently-active mirroring sessions.
- SessionMap sessions_;
+ // Used to check that all AudioMirroringManager code runs on the same thread.
+ base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(AudioMirroringManager);
};
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 cd197769aa5..6fece29c09f 100644
--- a/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager_unittest.cc
@@ -5,6 +5,7 @@
#include "content/browser/media/capture/audio_mirroring_manager.h"
#include <map>
+#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -18,6 +19,7 @@
using media::AudioOutputStream;
using media::AudioParameters;
using testing::_;
+using testing::Invoke;
using testing::NotNull;
using testing::Ref;
using testing::Return;
@@ -37,14 +39,56 @@ class MockDiverter : public AudioMirroringManager::Diverter {
class MockMirroringDestination
: public AudioMirroringManager::MirroringDestination {
public:
+ typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
+
+ MockMirroringDestination(int render_process_id, int render_frame_id)
+ : render_process_id_(render_process_id),
+ render_frame_id_(render_frame_id),
+ query_count_(0) {}
+
+ MOCK_METHOD2(QueryForMatches,
+ void(const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback));
MOCK_METHOD1(AddInput,
media::AudioOutputStream*(const media::AudioParameters& params));
+
+ void SimulateQuery(const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback) {
+ ++query_count_;
+
+ std::set<SourceFrameRef> result;
+ if (candidates.find(SourceFrameRef(render_process_id_, render_frame_id_)) !=
+ candidates.end()) {
+ result.insert(SourceFrameRef(render_process_id_, render_frame_id_));
+ }
+ results_callback.Run(result);
+ }
+
+ media::AudioOutputStream* SimulateAddInput(
+ const media::AudioParameters& params) {
+ static AudioOutputStream* const kNonNullPointer =
+ reinterpret_cast<AudioOutputStream*>(0x11111110);
+ return kNonNullPointer;
+ }
+
+ int query_count() const {
+ return query_count_;
+ }
+
+ private:
+ const int render_process_id_;
+ const int render_frame_id_;
+ int query_count_;
};
} // namespace
class AudioMirroringManagerTest : public testing::Test {
public:
+ typedef AudioMirroringManager::Diverter Diverter;
+ typedef AudioMirroringManager::MirroringDestination MirroringDestination;
+ typedef AudioMirroringManager::StreamRoutes StreamRoutes;
+
AudioMirroringManagerTest()
: io_thread_(BrowserThread::IO, &message_loop_),
params_(AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO,
@@ -52,7 +96,7 @@ class AudioMirroringManagerTest : public testing::Test {
AudioParameters::kAudioCDSampleRate / 10) {}
MockDiverter* CreateStream(
- int render_process_id, int render_view_id, int expected_times_diverted) {
+ int render_process_id, int render_frame_id, int expected_times_diverted) {
MockDiverter* const diverter = new MockDiverter();
if (expected_times_diverted > 0) {
EXPECT_CALL(*diverter, GetAudioParameters())
@@ -64,41 +108,52 @@ class AudioMirroringManagerTest : public testing::Test {
.Times(expected_times_diverted);
}
- mirroring_manager_.AddDiverter(render_process_id, render_view_id, diverter);
+ mirroring_manager_.AddDiverter(
+ render_process_id, render_frame_id, diverter);
return diverter;
}
- void KillStream(
- int render_process_id, int render_view_id, MockDiverter* diverter) {
- mirroring_manager_.RemoveDiverter(
- render_process_id, render_view_id, diverter);
-
+ void KillStream(MockDiverter* diverter) {
+ mirroring_manager_.RemoveDiverter(diverter);
delete diverter;
}
- MockMirroringDestination* StartMirroringTo(
- int render_process_id, int render_view_id, int expected_inputs_added) {
- MockMirroringDestination* const dest = new MockMirroringDestination();
+ void StartMirroringTo(const scoped_ptr<MockMirroringDestination>& dest,
+ int expected_inputs_added) {
+ EXPECT_CALL(*dest, QueryForMatches(_, _))
+ .WillRepeatedly(Invoke(dest.get(),
+ &MockMirroringDestination::SimulateQuery));
if (expected_inputs_added > 0) {
- static AudioOutputStream* const kNonNullPointer =
- reinterpret_cast<AudioOutputStream*>(0x11111110);
EXPECT_CALL(*dest, AddInput(Ref(params_)))
.Times(expected_inputs_added)
- .WillRepeatedly(Return(kNonNullPointer));
+ .WillRepeatedly(Invoke(dest.get(),
+ &MockMirroringDestination::SimulateAddInput))
+ .RetiresOnSaturation();
}
- mirroring_manager_.StartMirroring(render_process_id, render_view_id, dest);
+ mirroring_manager_.StartMirroring(dest.get());
+ }
- return dest;
+ void StopMirroringTo(const scoped_ptr<MockMirroringDestination>& dest) {
+ mirroring_manager_.StopMirroring(dest.get());
}
- void StopMirroringTo(int render_process_id, int render_view_id,
- MockMirroringDestination* dest) {
- mirroring_manager_.StopMirroring(render_process_id, render_view_id, dest);
+ int CountStreamsDivertedTo(
+ const scoped_ptr<MockMirroringDestination>& dest) const {
+ int count = 0;
+ for (StreamRoutes::const_iterator it = mirroring_manager_.routes_.begin();
+ it != mirroring_manager_.routes_.end(); ++it) {
+ if (it->destination == dest.get())
+ ++count;
+ }
+ return count;
+ }
- delete dest;
-}
+ void ExpectNoLongerManagingAnything() const {
+ EXPECT_TRUE(mirroring_manager_.routes_.empty());
+ EXPECT_TRUE(mirroring_manager_.sessions_.empty());
+ }
private:
base::MessageLoopForIO message_loop_;
@@ -111,123 +166,389 @@ class AudioMirroringManagerTest : public testing::Test {
namespace {
const int kRenderProcessId = 123;
-const int kRenderViewId = 456;
+const int kRenderFrameId = 456;
const int kAnotherRenderProcessId = 789;
-const int kAnotherRenderViewId = 1234;
+const int kAnotherRenderFrameId = 1234;
const int kYetAnotherRenderProcessId = 4560;
-const int kYetAnotherRenderViewId = 7890;
+const int kYetAnotherRenderFrameId = 7890;
}
TEST_F(AudioMirroringManagerTest, MirroringSessionOfNothing) {
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 0);
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
+ const scoped_ptr<MockMirroringDestination> destination(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(destination, 0);
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(0, destination->query_count());
+
+ ExpectNoLongerManagingAnything();
}
TEST_F(AudioMirroringManagerTest, TwoMirroringSessionsOfNothing) {
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 0);
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
-
- MockMirroringDestination* const another_destination =
- StartMirroringTo(kAnotherRenderProcessId, kAnotherRenderViewId, 0);
- StopMirroringTo(kAnotherRenderProcessId, kAnotherRenderViewId,
- another_destination);
-}
+ const scoped_ptr<MockMirroringDestination> destination(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(destination, 0);
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(0, destination->query_count());
-TEST_F(AudioMirroringManagerTest, SwitchMirroringDestinationNoStreams) {
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 0);
- MockMirroringDestination* const new_destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 0);
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
- StopMirroringTo(kRenderProcessId, kRenderViewId, new_destination);
+ const scoped_ptr<MockMirroringDestination> another_destination(
+ new MockMirroringDestination(kAnotherRenderProcessId,
+ kAnotherRenderFrameId));
+ StartMirroringTo(another_destination, 0);
+ EXPECT_EQ(0, CountStreamsDivertedTo(another_destination));
+
+ StopMirroringTo(another_destination);
+ EXPECT_EQ(0, another_destination->query_count());
+
+ ExpectNoLongerManagingAnything();
}
+// Tests that a mirroring session starts after, and ends before, a stream that
+// will be diverted to it.
TEST_F(AudioMirroringManagerTest, StreamLifetimeAroundMirroringSession) {
- MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderViewId, 1);
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 1);
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
- KillStream(kRenderProcessId, kRenderViewId, stream);
+ MockDiverter* const stream =
+ CreateStream(kRenderProcessId, kRenderFrameId, 1);
+ const scoped_ptr<MockMirroringDestination> destination(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(destination, 1);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ KillStream(stream);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ ExpectNoLongerManagingAnything();
}
+// Tests that a mirroring session starts before, and ends after, a stream that
+// will be diverted to it.
TEST_F(AudioMirroringManagerTest, StreamLifetimeWithinMirroringSession) {
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 1);
- MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderViewId, 1);
- KillStream(kRenderProcessId, kRenderViewId, stream);
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
+ const scoped_ptr<MockMirroringDestination> destination(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(destination, 1);
+ EXPECT_EQ(0, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ MockDiverter* const stream =
+ CreateStream(kRenderProcessId, kRenderFrameId, 1);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+
+ KillStream(stream);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ ExpectNoLongerManagingAnything();
}
-TEST_F(AudioMirroringManagerTest, StreamLifetimeAroundTwoMirroringSessions) {
- MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderViewId, 2);
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 1);
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
- MockMirroringDestination* const new_destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 1);
- StopMirroringTo(kRenderProcessId, kRenderViewId, new_destination);
- KillStream(kRenderProcessId, kRenderViewId, stream);
+// Tests that a stream is diverted correctly as two mirroring sessions come and
+// go.
+TEST_F(AudioMirroringManagerTest, StreamLifetimeAcrossTwoMirroringSessions) {
+ MockDiverter* const stream =
+ CreateStream(kRenderProcessId, kRenderFrameId, 2);
+
+ const scoped_ptr<MockMirroringDestination> destination(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(destination, 1);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ const scoped_ptr<MockMirroringDestination> second_destination(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(second_destination, 1);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, second_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(second_destination));
+
+ StopMirroringTo(second_destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, second_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(second_destination));
+
+ KillStream(stream);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, second_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(second_destination));
+
+ ExpectNoLongerManagingAnything();
}
-TEST_F(AudioMirroringManagerTest, StreamLifetimeWithinTwoMirroringSessions) {
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 1);
- MockDiverter* const stream = CreateStream(kRenderProcessId, kRenderViewId, 2);
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
- MockMirroringDestination* const new_destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 1);
- KillStream(kRenderProcessId, kRenderViewId, stream);
- StopMirroringTo(kRenderProcessId, kRenderViewId, new_destination);
+// Tests that a stream does not flip-flop between two destinations that are a
+// match for it.
+TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_1) {
+ MockDiverter* const stream =
+ CreateStream(kRenderProcessId, kRenderFrameId, 2);
+
+ const scoped_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(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(replacement_destination, 1);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(0, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, replacement_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(replacement_destination));
+
+ StopMirroringTo(replacement_destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ KillStream(stream);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ ExpectNoLongerManagingAnything();
+}
+
+// Same as StreamDivertingStickyToOneDestination_1, with a different order of
+// operations that should have the same effects.
+TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_2) {
+ MockDiverter* const stream =
+ CreateStream(kRenderProcessId, kRenderFrameId, 2);
+
+ const scoped_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(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(replacement_destination, 1);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(0, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, replacement_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(replacement_destination));
+
+ KillStream(stream);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ StopMirroringTo(replacement_destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ ExpectNoLongerManagingAnything();
+}
+
+// Same as StreamDivertingStickyToOneDestination_1, except that the stream is
+// killed before the first destination is stopped. Therefore, the second
+// destination should never see the stream.
+TEST_F(AudioMirroringManagerTest, StreamDivertingStickyToOneDestination_3) {
+ MockDiverter* const stream =
+ CreateStream(kRenderProcessId, kRenderFrameId, 1);
+
+ const scoped_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(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(replacement_destination, 0);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(0, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ KillStream(stream);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(0, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(0, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ StopMirroringTo(replacement_destination);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(0, replacement_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(replacement_destination));
+
+ ExpectNoLongerManagingAnything();
}
+// Tests that multiple streams are diverted/mixed to one destination.
TEST_F(AudioMirroringManagerTest, MultipleStreamsInOneMirroringSession) {
MockDiverter* const stream1 =
- CreateStream(kRenderProcessId, kRenderViewId, 1);
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 3);
+ CreateStream(kRenderProcessId, kRenderFrameId, 1);
+
+ const scoped_ptr<MockMirroringDestination> destination(
+ new MockMirroringDestination(kRenderProcessId, kRenderFrameId));
+ StartMirroringTo(destination, 3);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+
MockDiverter* const stream2 =
- CreateStream(kRenderProcessId, kRenderViewId, 1);
+ CreateStream(kRenderProcessId, kRenderFrameId, 1);
+ EXPECT_EQ(2, destination->query_count());
+ EXPECT_EQ(2, CountStreamsDivertedTo(destination));
+
MockDiverter* const stream3 =
- CreateStream(kRenderProcessId, kRenderViewId, 1);
- KillStream(kRenderProcessId, kRenderViewId, stream2);
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
- KillStream(kRenderProcessId, kRenderViewId, stream3);
- KillStream(kRenderProcessId, kRenderViewId, stream1);
+ CreateStream(kRenderProcessId, kRenderFrameId, 1);
+ EXPECT_EQ(3, destination->query_count());
+ EXPECT_EQ(3, CountStreamsDivertedTo(destination));
+
+ KillStream(stream2);
+ EXPECT_EQ(3, destination->query_count());
+ EXPECT_EQ(2, CountStreamsDivertedTo(destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(3, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ KillStream(stream3);
+ EXPECT_EQ(3, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ KillStream(stream1);
+ EXPECT_EQ(3, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+
+ ExpectNoLongerManagingAnything();
}
// A random interleaving of operations for three separate targets, each of which
// has one stream mirrored to one destination.
TEST_F(AudioMirroringManagerTest, ThreeSeparateMirroringSessions) {
MockDiverter* const stream =
- CreateStream(kRenderProcessId, kRenderViewId, 1);
- MockMirroringDestination* const destination =
- StartMirroringTo(kRenderProcessId, kRenderViewId, 1);
+ CreateStream(kRenderProcessId, kRenderFrameId, 1);
+
+ const scoped_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(
+ new MockMirroringDestination(kAnotherRenderProcessId,
+ kAnotherRenderFrameId));
+ StartMirroringTo(another_destination, 1);
+ EXPECT_EQ(1, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(0, another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(another_destination));
- MockMirroringDestination* const another_destination =
- StartMirroringTo(kAnotherRenderProcessId, kAnotherRenderViewId, 1);
MockDiverter* const another_stream =
- CreateStream(kAnotherRenderProcessId, kAnotherRenderViewId, 1);
-
- KillStream(kRenderProcessId, kRenderViewId, stream);
+ CreateStream(kAnotherRenderProcessId, kAnotherRenderFrameId, 1);
+ EXPECT_EQ(2, destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, another_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(another_destination));
+
+ KillStream(stream);
+ EXPECT_EQ(2, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(1, another_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(another_destination));
MockDiverter* const yet_another_stream =
- CreateStream(kYetAnotherRenderProcessId, kYetAnotherRenderViewId, 1);
- MockMirroringDestination* const yet_another_destination =
- StartMirroringTo(kYetAnotherRenderProcessId, kYetAnotherRenderViewId, 1);
-
- StopMirroringTo(kAnotherRenderProcessId, kAnotherRenderViewId,
- another_destination);
-
- StopMirroringTo(kYetAnotherRenderProcessId, kYetAnotherRenderViewId,
- yet_another_destination);
-
- StopMirroringTo(kRenderProcessId, kRenderViewId, destination);
-
- KillStream(kAnotherRenderProcessId, kAnotherRenderViewId, another_stream);
- KillStream(kYetAnotherRenderProcessId, kYetAnotherRenderViewId,
- yet_another_stream);
+ CreateStream(kYetAnotherRenderProcessId, kYetAnotherRenderFrameId, 1);
+ EXPECT_EQ(3, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(2, another_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(another_destination));
+
+ const scoped_ptr<MockMirroringDestination> yet_another_destination(
+ new MockMirroringDestination(kYetAnotherRenderProcessId,
+ kYetAnotherRenderFrameId));
+ StartMirroringTo(yet_another_destination, 1);
+ EXPECT_EQ(3, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(2, another_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(another_destination));
+ EXPECT_EQ(1, yet_another_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(yet_another_destination));
+
+ StopMirroringTo(another_destination);
+ EXPECT_EQ(4, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(2, another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(another_destination));
+ EXPECT_EQ(2, yet_another_destination->query_count());
+ EXPECT_EQ(1, CountStreamsDivertedTo(yet_another_destination));
+
+ StopMirroringTo(yet_another_destination);
+ EXPECT_EQ(5, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(2, another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(another_destination));
+ EXPECT_EQ(2, yet_another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(yet_another_destination));
+
+ StopMirroringTo(destination);
+ EXPECT_EQ(5, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(2, another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(another_destination));
+ EXPECT_EQ(2, yet_another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(yet_another_destination));
+
+ KillStream(another_stream);
+ EXPECT_EQ(5, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(2, another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(another_destination));
+ EXPECT_EQ(2, yet_another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(yet_another_destination));
+
+ KillStream(yet_another_stream);
+ EXPECT_EQ(5, destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(destination));
+ EXPECT_EQ(2, another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(another_destination));
+ EXPECT_EQ(2, yet_another_destination->query_count());
+ EXPECT_EQ(0, CountStreamsDivertedTo(yet_another_destination));
+
+ ExpectNoLongerManagingAnything();
}
} // namespace content
diff --git a/chromium/content/browser/media/capture/content_video_capture_device_core.cc b/chromium/content/browser/media/capture/content_video_capture_device_core.cc
index 6878652de07..f0499a23c22 100644
--- a/chromium/content/browser/media/capture/content_video_capture_device_core.cc
+++ b/chromium/content/browser/media/capture/content_video_capture_device_core.cc
@@ -66,6 +66,7 @@ ThreadSafeCaptureOracle::~ThreadSafeCaptureOracle() {}
bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
VideoCaptureOracle::Event event,
+ const gfx::Rect& damage_rect,
base::TimeTicks event_time,
scoped_refptr<media::VideoFrame>* storage,
CaptureFrameCallback* callback) {
@@ -74,11 +75,16 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
if (!client_)
return false; // Capture is stopped.
+ // Always round up the coded size to multiple of 16 pixels.
+ // See http://crbug.com/402151.
+ const gfx::Size visible_size = params_.requested_format.frame_size;
+ const gfx::Size coded_size((visible_size.width() + 15) & ~15,
+ (visible_size.height() + 15) & ~15);
+
scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer =
- client_->ReserveOutputBuffer(video_frame_format_,
- params_.requested_format.frame_size);
+ client_->ReserveOutputBuffer(video_frame_format_, coded_size);
const bool should_capture =
- oracle_->ObserveEventAndDecideCapture(event, event_time);
+ oracle_->ObserveEventAndDecideCapture(event, damage_rect, event_time);
const bool content_is_dirty =
(event == VideoCaptureOracle::kCompositorUpdate ||
event == VideoCaptureOracle::kSoftwarePaint);
@@ -88,14 +94,14 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
"paint"));
// Consider the various reasons not to initiate a capture.
- if (should_capture && !output_buffer) {
+ if (should_capture && !output_buffer.get()) {
TRACE_EVENT_INSTANT1("mirroring",
- "EncodeLimited",
+ "PipelineLimited",
TRACE_EVENT_SCOPE_THREAD,
"trigger",
event_name);
return false;
- } else if (!should_capture && output_buffer) {
+ } else if (!should_capture && output_buffer.get()) {
if (content_is_dirty) {
// This is a normal and acceptable way to drop a frame. We've hit our
// capture rate limit: for example, the content is animating at 60fps but
@@ -105,10 +111,10 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
"trigger", event_name);
}
return false;
- } else if (!should_capture && !output_buffer) {
+ } else if (!should_capture && !output_buffer.get()) {
// We decided not to capture, but we wouldn't have been able to if we wanted
// to because no output buffer was available.
- TRACE_EVENT_INSTANT1("mirroring", "NearlyEncodeLimited",
+ TRACE_EVENT_INSTANT1("mirroring", "NearlyPipelineLimited",
TRACE_EVENT_SCOPE_THREAD,
"trigger", event_name);
return false;
@@ -122,9 +128,9 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
if (video_frame_format_ != media::VideoFrame::NATIVE_TEXTURE) {
*storage = media::VideoFrame::WrapExternalPackedMemory(
video_frame_format_,
- params_.requested_format.frame_size,
- gfx::Rect(params_.requested_format.frame_size),
- params_.requested_format.frame_size,
+ coded_size,
+ gfx::Rect(visible_size),
+ visible_size,
static_cast<uint8*>(output_buffer->data()),
output_buffer->size(),
base::SharedMemory::NULLHandle(),
@@ -149,7 +155,8 @@ void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) {
// If this is the first call to UpdateCaptureSize(), or the receiver supports
// variable resolution, then determine the capture size by treating the
// requested width and height as maxima.
- if (!capture_size_updated_ || params_.allow_resolution_change) {
+ if (!capture_size_updated_ || params_.resolution_change_policy ==
+ media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT) {
// The capture resolution should not exceed the source frame size.
// In other words it should downscale the image but not upscale it.
if (source_size.width() > params_.requested_format.frame_size.width() ||
@@ -192,7 +199,7 @@ void ThreadSafeCaptureOracle::DidCaptureFrame(
return; // Capture is stopped.
if (success) {
- if (oracle_->CompleteCapture(frame_number, timestamp)) {
+ if (oracle_->CompleteCapture(frame_number, &timestamp)) {
media::VideoCaptureFormat format = params_.requested_format;
format.frame_size = frame->coded_size();
client_->OnIncomingCapturedVideoFrame(buffer, format, frame, timestamp);
@@ -296,9 +303,13 @@ void ContentVideoCaptureDeviceCore::CaptureStarted(bool success) {
ContentVideoCaptureDeviceCore::ContentVideoCaptureDeviceCore(
scoped_ptr<VideoCaptureMachine> capture_machine)
: state_(kIdle),
- capture_machine_(capture_machine.Pass()) {}
+ capture_machine_(capture_machine.Pass()) {
+ DCHECK(capture_machine_.get());
+}
ContentVideoCaptureDeviceCore::~ContentVideoCaptureDeviceCore() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_NE(state_, kCapturing);
// If capture_machine is not NULL, then we need to return to the UI thread to
// safely stop the capture machine.
if (capture_machine_) {
@@ -333,7 +344,7 @@ void ContentVideoCaptureDeviceCore::Error(const std::string& reason) {
if (state_ == kIdle)
return;
- if (oracle_proxy_)
+ if (oracle_proxy_.get())
oracle_proxy_->ReportError(reason);
StopAndDeAllocate();
diff --git a/chromium/content/browser/media/capture/content_video_capture_device_core.h b/chromium/content/browser/media/capture/content_video_capture_device_core.h
index 3a7e6974ae7..c86bb6c883a 100644
--- a/chromium/content/browser/media/capture/content_video_capture_device_core.h
+++ b/chromium/content/browser/media/capture/content_video_capture_device_core.h
@@ -62,12 +62,13 @@ class ThreadSafeCaptureOracle
bool success)> CaptureFrameCallback;
bool ObserveEventAndDecideCapture(VideoCaptureOracle::Event event,
+ const gfx::Rect& damage_rect,
base::TimeTicks event_time,
scoped_refptr<media::VideoFrame>* storage,
CaptureFrameCallback* callback);
- base::TimeDelta capture_period() const {
- return oracle_->capture_period();
+ base::TimeDelta min_capture_period() const {
+ return oracle_->min_capture_period();
}
// Returns the current capture resolution.
@@ -118,12 +119,9 @@ class ThreadSafeCaptureOracle
// UI BrowserThread.
class VideoCaptureMachine {
public:
- VideoCaptureMachine() : started_(false) {}
+ VideoCaptureMachine() {}
virtual ~VideoCaptureMachine() {}
- // This should only be checked on the UI thread.
- bool started() const { return started_; }
-
// Starts capturing. Returns true if succeeded.
// Must be run on the UI BrowserThread.
virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
@@ -133,9 +131,6 @@ class VideoCaptureMachine {
// |callback| is invoked after the capturing has stopped.
virtual void Stop(const base::Closure& callback) = 0;
- protected:
- bool started_;
-
private:
DISALLOW_COPY_AND_ASSIGN(VideoCaptureMachine);
};
@@ -144,7 +139,7 @@ class VideoCaptureMachine {
//
// Separating this from the "shell classes" WebContentsVideoCaptureDevice and
// DesktopCaptureDeviceAura allows safe destruction without needing to block any
-// threads (e.g., the IO BrowserThread), as well as code sharing.
+// threads, as well as code sharing.
//
// ContentVideoCaptureDeviceCore manages a simple state machine and the pipeline
// (see notes at top of this file). It times the start of successive captures
@@ -172,8 +167,8 @@ class CONTENT_EXPORT ContentVideoCaptureDeviceCore
void TransitionStateTo(State next_state);
- // Called on the IO thread in response to StartCaptureMachine().
- // |success| is true if capture machine succeeded to start.
+ // Called back in response to StartCaptureMachine(). |success| is true if
+ // capture machine succeeded to start.
void CaptureStarted(bool success);
// Stops capturing and notifies client_ of an error state.
@@ -192,7 +187,7 @@ class CONTENT_EXPORT ContentVideoCaptureDeviceCore
// Our thread-safe capture oracle which serves as the gateway to the video
// capture pipeline. Besides the VideoCaptureDevice itself, it is the only
- // component of the/ system with direct access to |client_|.
+ // component of the system with direct access to |client_|.
scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
DISALLOW_COPY_AND_ASSIGN(ContentVideoCaptureDeviceCore);
diff --git a/chromium/content/browser/media/capture/desktop_capture_device.cc b/chromium/content/browser/media/capture/desktop_capture_device.cc
index cf180c9db26..c77ee0cc4c3 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device.cc
@@ -7,16 +7,15 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
-#include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
-#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread.h"
+#include "base/timer/timer.h"
#include "content/browser/media/capture/desktop_capture_device_uma_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/power_save_blocker.h"
#include "media/base/video_util.h"
#include "third_party/libyuv/include/libyuv/scale_argb.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_and_cursor_composer.h"
@@ -49,35 +48,24 @@ webrtc::DesktopRect ComputeLetterboxRect(
} // namespace
-class DesktopCaptureDevice::Core
- : public base::RefCountedThreadSafe<Core>,
- public webrtc::DesktopCapturer::Callback {
+class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
public:
- Core(scoped_refptr<base::SequencedTaskRunner> task_runner,
- scoped_ptr<base::Thread> thread,
+ Core(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
scoped_ptr<webrtc::DesktopCapturer> capturer,
DesktopMediaID::Type type);
+ ~Core() override;
// Implementation of VideoCaptureDevice methods.
void AllocateAndStart(const media::VideoCaptureParams& params,
scoped_ptr<Client> client);
- void StopAndDeAllocate();
void SetNotificationWindowId(gfx::NativeViewId window_id);
private:
- friend class base::RefCountedThreadSafe<Core>;
- virtual ~Core();
// webrtc::DesktopCapturer::Callback interface
- virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE;
- virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE;
-
- // Helper methods that run on the |task_runner_|. Posted from the
- // corresponding public methods.
- void DoAllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<Client> client);
- void DoStopAndDeAllocate();
+ webrtc::SharedMemory* CreateSharedMemory(size_t size) override;
+ void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
// Chooses new output properties based on the supplied source size and the
// properties requested to Allocate(), and dispatches OnFrameInfo[Changed]
@@ -94,13 +82,8 @@ class DesktopCaptureDevice::Core
// Captures a single frame.
void DoCapture();
- void DoSetNotificationWindowId(gfx::NativeViewId window_id);
-
// Task runner used for capturing operations.
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
- // The thread on which the capturer is running.
- scoped_ptr<base::Thread> thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// The underlying DesktopCapturer instance used to capture frames.
scoped_ptr<webrtc::DesktopCapturer> desktop_capturer_;
@@ -127,9 +110,8 @@ class DesktopCaptureDevice::Core
// and/or letterboxed.
webrtc::DesktopRect output_rect_;
- // True when we have delayed OnCaptureTimer() task posted on
- // |task_runner_|.
- bool capture_task_posted_;
+ // Timer used to capture the frame.
+ base::OneShotTimer<Core> capture_timer_;
// True when waiting for |desktop_capturer_| to capture current frame.
bool capture_in_progress_;
@@ -143,50 +125,64 @@ class DesktopCaptureDevice::Core
scoped_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_;
+
DISALLOW_COPY_AND_ASSIGN(Core);
};
DesktopCaptureDevice::Core::Core(
- scoped_refptr<base::SequencedTaskRunner> task_runner,
- scoped_ptr<base::Thread> thread,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
scoped_ptr<webrtc::DesktopCapturer> capturer,
DesktopMediaID::Type type)
: task_runner_(task_runner),
- thread_(thread.Pass()),
desktop_capturer_(capturer.Pass()),
- capture_task_posted_(false),
capture_in_progress_(false),
first_capture_returned_(false),
capturer_type_(type) {
- DCHECK(!task_runner_.get() || !thread_.get());
- if (thread_.get())
- task_runner_ = thread_->message_loop_proxy();
}
DesktopCaptureDevice::Core::~Core() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ client_.reset();
+ output_frame_.reset();
+ previous_frame_size_.set(0, 0);
+ desktop_capturer_.reset();
}
void DesktopCaptureDevice::Core::AllocateAndStart(
const media::VideoCaptureParams& params,
scoped_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());
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(
- &Core::DoAllocateAndStart, this, params, base::Passed(&client)));
-}
+ client_ = client.Pass();
+ requested_params_ = params;
-void DesktopCaptureDevice::Core::StopAndDeAllocate() {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&Core::DoStopAndDeAllocate, this));
+ capture_format_ = requested_params_.requested_format;
+
+ // This capturer always outputs ARGB, non-interlaced.
+ capture_format_.pixel_format = media::PIXEL_FORMAT_ARGB;
+
+ power_save_blocker_.reset(PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+ "DesktopCaptureDevice is running").release());
+
+ desktop_capturer_->Start(this);
+
+ CaptureFrameAndScheduleNext();
}
void DesktopCaptureDevice::Core::SetNotificationWindowId(
gfx::NativeViewId window_id) {
- task_runner_->PostTask(
- FROM_HERE, base::Bind(&Core::DoSetNotificationWindowId, this, window_id));
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK(window_id);
+ desktop_capturer_->SetExcludedWindow(window_id);
}
webrtc::SharedMemory*
@@ -196,7 +192,7 @@ DesktopCaptureDevice::Core::CreateSharedMemory(size_t size) {
void DesktopCaptureDevice::Core::OnCaptureCompleted(
webrtc::DesktopFrame* frame) {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(capture_in_progress_);
if (!first_capture_returned_) {
@@ -224,10 +220,14 @@ void DesktopCaptureDevice::Core::OnCaptureCompleted(
base::TimeDelta capture_time(
base::TimeDelta::FromMilliseconds(frame->capture_time_ms()));
- UMA_HISTOGRAM_TIMES(
- capturer_type_ == DesktopMediaID::TYPE_SCREEN ? kUmaScreenCaptureTime
- : kUmaWindowCaptureTime,
- capture_time);
+
+ // The two UMA_ blocks must be put in its own scope since it creates a static
+ // variable which expected constant histogram name.
+ if (capturer_type_ == DesktopMediaID::TYPE_SCREEN) {
+ UMA_HISTOGRAM_TIMES(kUmaScreenCaptureTime, capture_time);
+ } else {
+ UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time);
+ }
scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
@@ -309,35 +309,6 @@ void DesktopCaptureDevice::Core::OnCaptureCompleted(
output_data, output_bytes, capture_format_, 0, base::TimeTicks::Now());
}
-void DesktopCaptureDevice::Core::DoAllocateAndStart(
- const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
- DCHECK(desktop_capturer_);
- DCHECK(client.get());
- DCHECK(!client_.get());
-
- client_ = client.Pass();
- requested_params_ = params;
-
- capture_format_ = requested_params_.requested_format;
-
- // This capturer always outputs ARGB, non-interlaced.
- capture_format_.pixel_format = media::PIXEL_FORMAT_ARGB;
-
- desktop_capturer_->Start(this);
-
- CaptureFrameAndScheduleNext();
-}
-
-void DesktopCaptureDevice::Core::DoStopAndDeAllocate() {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
- client_.reset();
- output_frame_.reset();
- previous_frame_size_.set(0, 0);
- desktop_capturer_.reset();
-}
-
void DesktopCaptureDevice::Core::RefreshCaptureFormat(
const webrtc::DesktopSize& frame_size) {
if (previous_frame_size_.equals(frame_size))
@@ -348,7 +319,8 @@ void DesktopCaptureDevice::Core::RefreshCaptureFormat(
output_frame_.reset();
if (previous_frame_size_.is_empty() ||
- requested_params_.allow_resolution_change) {
+ requested_params_.resolution_change_policy ==
+ media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT) {
// If this is the first frame, or the receiver supports variable resolution
// then determine the output size by treating the requested width & height
// as maxima.
@@ -380,8 +352,7 @@ void DesktopCaptureDevice::Core::RefreshCaptureFormat(
}
void DesktopCaptureDevice::Core::OnCaptureTimer() {
- DCHECK(capture_task_posted_);
- capture_task_posted_ = false;
+ DCHECK(task_runner_->BelongsToCurrentThread());
if (!client_)
return;
@@ -390,8 +361,7 @@ void DesktopCaptureDevice::Core::OnCaptureTimer() {
}
void DesktopCaptureDevice::Core::CaptureFrameAndScheduleNext() {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
- DCHECK(!capture_task_posted_);
+ DCHECK(task_runner_->BelongsToCurrentThread());
base::TimeTicks started_time = base::TimeTicks::Now();
DoCapture();
@@ -403,14 +373,12 @@ void DesktopCaptureDevice::Core::CaptureFrameAndScheduleNext() {
base::TimeDelta::FromSeconds(1) / capture_format_.frame_rate);
// Schedule a task for the next frame.
- capture_task_posted_ = true;
- task_runner_->PostDelayedTask(
- FROM_HERE, base::Bind(&Core::OnCaptureTimer, this),
- capture_period - last_capture_duration);
+ capture_timer_.Start(FROM_HERE, capture_period - last_capture_duration,
+ this, &Core::OnCaptureTimer);
}
void DesktopCaptureDevice::Core::DoCapture() {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(!capture_in_progress_);
capture_in_progress_ = true;
@@ -421,18 +389,9 @@ void DesktopCaptureDevice::Core::DoCapture() {
DCHECK(!capture_in_progress_);
}
-void DesktopCaptureDevice::Core::DoSetNotificationWindowId(
- gfx::NativeViewId window_id) {
- DCHECK(task_runner_->RunsTasksOnCurrentThread());
- DCHECK(window_id);
- desktop_capturer_->SetExcludedWindow(window_id);
-}
-
// static
scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
const DesktopMediaID& source) {
- scoped_ptr<base::Thread> ui_thread;
-
webrtc::DesktopCaptureOptions options =
webrtc::DesktopCaptureOptions::CreateDefault();
// Leave desktop effects enabled during WebRTC captures.
@@ -442,24 +401,11 @@ scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
switch (source.type) {
case DesktopMediaID::TYPE_SCREEN: {
- scoped_ptr<webrtc::ScreenCapturer> screen_capturer;
-
#if defined(OS_WIN)
- bool magnification_allowed =
- base::FieldTrialList::FindFullName("ScreenCaptureUseMagnification") ==
- "Enabled";
-
- if (magnification_allowed) {
- // The magnification capturer requires running on a dedicated UI thread.
- ui_thread.reset(new base::Thread("screenCaptureUIThread"));
- base::Thread::Options thread_options(base::MessageLoop::TYPE_UI, 0);
- ui_thread->StartWithOptions(thread_options);
-
- options.set_allow_use_magnification_api(true);
- }
+ options.set_allow_use_magnification_api(true);
#endif
-
- screen_capturer.reset(webrtc::ScreenCapturer::Create(options));
+ 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(),
@@ -477,7 +423,7 @@ scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
capturer.reset(new webrtc::DesktopAndCursorComposer(
window_capturer.release(),
webrtc::MouseCursorMonitor::CreateForWindow(options, source.id)));
- IncrementDesktopCaptureCounter(WINDOW_CATPTURER_CREATED);
+ IncrementDesktopCaptureCounter(WINDOW_CAPTURER_CREATED);
}
break;
}
@@ -488,46 +434,54 @@ scoped_ptr<media::VideoCaptureDevice> DesktopCaptureDevice::Create(
}
scoped_ptr<media::VideoCaptureDevice> result;
- if (capturer) {
- scoped_refptr<base::SequencedTaskRunner> task_runner;
- if (!ui_thread.get()) {
- scoped_refptr<base::SequencedWorkerPool> blocking_pool =
- BrowserThread::GetBlockingPool();
- task_runner = blocking_pool->GetSequencedTaskRunner(
- blocking_pool->GetSequenceToken());
- }
- result.reset(new DesktopCaptureDevice(
- task_runner, ui_thread.Pass(), capturer.Pass(), source.type));
- }
+ if (capturer)
+ result.reset(new DesktopCaptureDevice(capturer.Pass(), source.type));
return result.Pass();
}
DesktopCaptureDevice::~DesktopCaptureDevice() {
- StopAndDeAllocate();
+ DCHECK(!core_);
}
void DesktopCaptureDevice::AllocateAndStart(
const media::VideoCaptureParams& params,
scoped_ptr<Client> client) {
- core_->AllocateAndStart(params, client.Pass());
+ thread_.message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&Core::AllocateAndStart, base::Unretained(core_.get()), params,
+ base::Passed(&client)));
}
void DesktopCaptureDevice::StopAndDeAllocate() {
- core_->StopAndDeAllocate();
+ if (core_) {
+ thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, core_.release());
+ thread_.Stop();
+ }
}
void DesktopCaptureDevice::SetNotificationWindowId(
gfx::NativeViewId window_id) {
- core_->SetNotificationWindowId(window_id);
+ thread_.message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&Core::SetNotificationWindowId, base::Unretained(core_.get()),
+ window_id));
}
DesktopCaptureDevice::DesktopCaptureDevice(
- scoped_refptr<base::SequencedTaskRunner> task_runner,
- scoped_ptr<base::Thread> thread,
scoped_ptr<webrtc::DesktopCapturer> capturer,
DesktopMediaID::Type type)
- : core_(new Core(task_runner, thread.Pass(), capturer.Pass(), type)) {
+ : thread_("desktopCaptureThread") {
+#if defined(OS_WIN)
+ // On Windows the thread must be a UI thread.
+ base::MessageLoop::Type thread_type = base::MessageLoop::TYPE_UI;
+#else
+ base::MessageLoop::Type thread_type = base::MessageLoop::TYPE_DEFAULT;
+#endif
+
+ thread_.StartWithOptions(base::Thread::Options(thread_type, 0));
+
+ core_.reset(new Core(thread_.message_loop_proxy(), capturer.Pass(), type));
}
} // namespace content
diff --git a/chromium/content/browser/media/capture/desktop_capture_device.h b/chromium/content/browser/media/capture/desktop_capture_device.h
index 9fb8ca419fa..a9c3f000b3c 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device.h
+++ b/chromium/content/browser/media/capture/desktop_capture_device.h
@@ -7,13 +7,14 @@
#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"
#include "media/video/capture/video_capture_device.h"
#include "ui/gfx/native_widget_types.h"
namespace base {
-class SequencedTaskRunner;
+class SingleThreadTaskRunner;
class Thread;
} // namespace base
@@ -34,12 +35,12 @@ class CONTENT_EXPORT DesktopCaptureDevice : public media::VideoCaptureDevice {
static scoped_ptr<media::VideoCaptureDevice> Create(
const DesktopMediaID& source);
- virtual ~DesktopCaptureDevice();
+ ~DesktopCaptureDevice() override;
// VideoCaptureDevice interface.
- virtual void AllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) OVERRIDE;
- virtual void StopAndDeAllocate() OVERRIDE;
+ void AllocateAndStart(const media::VideoCaptureParams& params,
+ scoped_ptr<Client> client) override;
+ void StopAndDeAllocate() override;
// Set the platform-dependent window id for the notification window.
void SetNotificationWindowId(gfx::NativeViewId window_id);
@@ -48,13 +49,11 @@ class CONTENT_EXPORT DesktopCaptureDevice : public media::VideoCaptureDevice {
friend class DesktopCaptureDeviceTest;
class Core;
- // Either |task_runner| or |thread| should be non-NULL, but not both.
- DesktopCaptureDevice(scoped_refptr<base::SequencedTaskRunner> task_runner,
- scoped_ptr<base::Thread> thread,
- scoped_ptr<webrtc::DesktopCapturer> desktop_capturer,
+ DesktopCaptureDevice(scoped_ptr<webrtc::DesktopCapturer> desktop_capturer,
DesktopMediaID::Type type);
- scoped_refptr<Core> core_;
+ base::Thread thread_;
+ scoped_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 08aec1eba2e..6b6557f1844 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_aura.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device_aura.cc
@@ -14,7 +14,7 @@
#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 "media/base/bind_to_current_loop.h"
+#include "content/public/browser/power_save_blocker.h"
#include "media/base/video_util.h"
#include "media/video/capture/video_capture_types.h"
#include "skia/ext/image_operations.h"
@@ -47,7 +47,7 @@ void RenderCursorOnVideoFrame(
const scoped_refptr<media::VideoFrame>& target,
const SkBitmap& cursor_bitmap,
const gfx::Point& cursor_position) {
- DCHECK(target);
+ DCHECK(target.get());
DCHECK(!cursor_bitmap.isNull());
gfx::Rect rect = gfx::IntersectRects(
@@ -96,30 +96,29 @@ class DesktopVideoCaptureMachine
public base::SupportsWeakPtr<DesktopVideoCaptureMachine> {
public:
DesktopVideoCaptureMachine(const DesktopMediaID& source);
- virtual ~DesktopVideoCaptureMachine();
+ ~DesktopVideoCaptureMachine() override;
// VideoCaptureFrameSource overrides.
- virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
- const media::VideoCaptureParams& params) OVERRIDE;
- virtual void Stop(const base::Closure& callback) OVERRIDE;
+ bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
+ const media::VideoCaptureParams& params) override;
+ void Stop(const base::Closure& callback) override;
// Implements aura::WindowObserver.
- virtual void OnWindowBoundsChanged(aura::Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) OVERRIDE;
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
- virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE;
- virtual void OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) OVERRIDE;
+ void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) override;
+ void OnWindowDestroyed(aura::Window* window) override;
+ void OnWindowAddedToRootWindow(aura::Window* window) override;
+ void OnWindowRemovingFromRootWindow(aura::Window* window,
+ aura::Window* new_root) override;
// Implements ui::CompositorObserver.
- virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE {}
- virtual void OnCompositingStarted(ui::Compositor* compositor,
- base::TimeTicks start_time) OVERRIDE {}
- virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE;
- virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE {}
- virtual void OnCompositingLockStateChanged(
- ui::Compositor* compositor) OVERRIDE {}
+ 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 {}
private:
// Captures a frame.
@@ -175,6 +174,10 @@ class DesktopVideoCaptureMachine
gfx::Point cursor_hot_point_;
SkBitmap scaled_cursor_bitmap_;
+ // 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_;
+
DISALLOW_COPY_AND_ASSIGN(DesktopVideoCaptureMachine);
};
@@ -214,17 +217,21 @@ bool DesktopVideoCaptureMachine::Start(
if (desktop_window_->GetHost())
desktop_window_->GetHost()->compositor()->AddObserver(this);
+ power_save_blocker_.reset(PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+ "DesktopCaptureDevice is running").release());
+
// Starts timer.
- timer_.Start(FROM_HERE, oracle_proxy_->capture_period(),
+ timer_.Start(FROM_HERE, oracle_proxy_->min_capture_period(),
base::Bind(&DesktopVideoCaptureMachine::Capture, AsWeakPtr(),
false));
- started_ = true;
return true;
}
void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ power_save_blocker_.reset();
// Stop observing compositor and window events.
if (desktop_window_) {
@@ -237,17 +244,15 @@ void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) {
// Stop timer.
timer_.Stop();
- started_ = false;
-
callback.Run();
}
void DesktopVideoCaptureMachine::UpdateCaptureSize() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (oracle_proxy_ && desktop_window_) {
- ui::Layer* layer = desktop_window_->layer();
- oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel(
- layer, layer->bounds().size()));
+ if (oracle_proxy_.get() && desktop_window_) {
+ ui::Layer* layer = desktop_window_->layer();
+ oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel(
+ layer, layer->bounds().size()));
}
ClearCursorState();
}
@@ -267,15 +272,13 @@ void DesktopVideoCaptureMachine::Capture(bool dirty) {
dirty ? VideoCaptureOracle::kCompositorUpdate
: VideoCaptureOracle::kTimerPoll;
if (oracle_proxy_->ObserveEventAndDecideCapture(
- event, start_time, &frame, &capture_frame_cb)) {
+ event, gfx::Rect(), start_time, &frame, &capture_frame_cb)) {
scoped_ptr<cc::CopyOutputRequest> request =
cc::CopyOutputRequest::CreateRequest(
base::Bind(&DesktopVideoCaptureMachine::DidCopyOutput,
AsWeakPtr(), frame, start_time, capture_frame_cb));
- gfx::Rect window_rect =
- ui::ConvertRectToPixel(desktop_window_->layer(),
- gfx::Rect(desktop_window_->bounds().width(),
- desktop_window_->bounds().height()));
+ gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(),
+ desktop_window_->bounds().height());
request->set_area(window_rect);
desktop_window_->layer()->RequestCopyOfOutput(request.Pass());
}
@@ -296,14 +299,8 @@ void CopyOutputFinishedForVideo(
}
void RunSingleReleaseCallback(scoped_ptr<cc::SingleReleaseCallback> cb,
- const std::vector<uint32>& sync_points) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
- DCHECK(gl_helper);
- for (unsigned i = 0; i < sync_points.size(); i++)
- gl_helper->WaitSyncPoint(sync_points[i]);
- uint32 new_sync_point = gl_helper->InsertSyncPoint();
- cb->Run(new_sync_point, false);
+ uint32 sync_point) {
+ cb->Run(sync_point, false);
}
void DesktopVideoCaptureMachine::DidCopyOutput(
@@ -317,10 +314,14 @@ void DesktopVideoCaptureMachine::DidCopyOutput(
video_frame, start_time, capture_frame_cb, result.Pass());
base::TimeDelta capture_time = base::TimeTicks::Now() - start_time;
- UMA_HISTOGRAM_TIMES(
- window_id_.type == DesktopMediaID::TYPE_SCREEN ? kUmaScreenCaptureTime
- : kUmaWindowCaptureTime,
- capture_time);
+
+ // The two UMA_ blocks must be put in its own scope since it creates a static
+ // variable which expected constant histogram name.
+ if (window_id_.type == DesktopMediaID::TYPE_SCREEN) {
+ UMA_HISTOGRAM_TIMES(kUmaScreenCaptureTime, capture_time);
+ } else {
+ UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time);
+ }
if (first_call) {
first_call = false;
@@ -330,7 +331,7 @@ void DesktopVideoCaptureMachine::DidCopyOutput(
} else {
IncrementDesktopCaptureCounter(succeeded
? FIRST_WINDOW_CAPTURE_SUCCEEDED
- : FIRST_WINDOW_CAPTURE_SUCCEEDED);
+ : FIRST_WINDOW_CAPTURE_FAILED);
}
}
}
@@ -346,7 +347,7 @@ bool DesktopVideoCaptureMachine::ProcessCopyOutputResponse(
if (capture_params_.requested_format.pixel_format ==
media::PIXEL_FORMAT_TEXTURE) {
- DCHECK(!video_frame);
+ DCHECK(!video_frame.get());
cc::TextureMailbox texture_mailbox;
scoped_ptr<cc::SingleReleaseCallback> release_callback;
result->TakeTexture(&texture_mailbox, &release_callback);
@@ -357,8 +358,7 @@ bool DesktopVideoCaptureMachine::ProcessCopyOutputResponse(
make_scoped_ptr(new gpu::MailboxHolder(texture_mailbox.mailbox(),
texture_mailbox.target(),
texture_mailbox.sync_point())),
- media::BindToCurrentLoop(base::Bind(&RunSingleReleaseCallback,
- base::Passed(&release_callback))),
+ base::Bind(&RunSingleReleaseCallback, base::Passed(&release_callback)),
result->size(),
gfx::Rect(result->size()),
result->size(),
@@ -523,7 +523,7 @@ media::VideoCaptureDevice* DesktopCaptureDeviceAura::Create(
const DesktopMediaID& source) {
IncrementDesktopCaptureCounter(source.type == DesktopMediaID::TYPE_SCREEN
? SCREEN_CAPTURER_CREATED
- : WINDOW_CATPTURER_CREATED);
+ : WINDOW_CAPTURER_CREATED);
return new DesktopCaptureDeviceAura(source);
}
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 997b3ce3a00..8f3540a7fd6 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_aura.h
+++ b/chromium/content/browser/media/capture/desktop_capture_device_aura.h
@@ -27,12 +27,12 @@ class CONTENT_EXPORT DesktopCaptureDeviceAura
// Creates a VideoCaptureDevice for the Aura desktop.
static media::VideoCaptureDevice* Create(const DesktopMediaID& source);
- virtual ~DesktopCaptureDeviceAura();
+ ~DesktopCaptureDeviceAura() override;
// VideoCaptureDevice implementation.
- virtual void AllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) OVERRIDE;
- virtual void StopAndDeAllocate() OVERRIDE;
+ void AllocateAndStart(const media::VideoCaptureParams& params,
+ scoped_ptr<Client> client) override;
+ void StopAndDeAllocate() override;
private:
DesktopCaptureDeviceAura(const DesktopMediaID& source);
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 3cfccf0de54..81cbd15b20e 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,7 +60,7 @@ class DesktopCaptureDeviceAuraTest : public testing::Test {
virtual ~DesktopCaptureDeviceAuraTest() {}
protected:
- virtual void SetUp() OVERRIDE {
+ virtual void SetUp() override {
// The ContextFactory must exist before any Compositors are created.
bool enable_pixel_output = false;
ui::ContextFactory* context_factory =
@@ -82,7 +82,7 @@ class DesktopCaptureDeviceAuraTest : public testing::Test {
desktop_window_->Show();
}
- virtual void TearDown() OVERRIDE {
+ virtual void TearDown() override {
helper_->RunAllPendingInMessageLoop();
root_window()->RemoveChild(desktop_window_.get());
desktop_window_.reset();
@@ -115,9 +115,7 @@ TEST_F(DesktopCaptureDeviceAuraTest, StartAndStop) {
capture_params.requested_format.frame_size.SetSize(640, 480);
capture_params.requested_format.frame_rate = kFrameRate;
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
- capture_params.allow_resolution_change = false;
- capture_device->AllocateAndStart(
- capture_params, client.PassAs<media::VideoCaptureDevice::Client>());
+ capture_device->AllocateAndStart(capture_params, client.Pass());
capture_device->StopAndDeAllocate();
}
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 0994fcd3150..0058e9121ec 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
@@ -12,7 +12,7 @@ namespace content {
// DESKTOP_CAPTURE_COUNTER_BOUNDARY.
enum DesktopCaptureCounters {
SCREEN_CAPTURER_CREATED,
- WINDOW_CATPTURER_CREATED,
+ WINDOW_CAPTURER_CREATED,
FIRST_SCREEN_CAPTURE_SUCCEEDED,
FIRST_SCREEN_CAPTURE_FAILED,
FIRST_WINDOW_CAPTURE_SUCCEEDED,
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 0c1a360e292..0388043642f 100644
--- a/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
+++ b/chromium/content/browser/media/capture/desktop_capture_device_unittest.cc
@@ -4,13 +4,13 @@
#include "content/browser/media/capture/desktop_capture_device.h"
+#include <string>
+
#include "base/basictypes.h"
-#include "base/sequenced_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_timeouts.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "base/threading/thread.h"
#include "base/time/time.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
@@ -63,9 +63,10 @@ class MockDeviceClient : public media::VideoCaptureDevice::Client {
class InvertedDesktopFrame : public webrtc::DesktopFrame {
public:
// Takes ownership of |frame|.
- InvertedDesktopFrame(webrtc::DesktopFrame* frame)
+ explicit InvertedDesktopFrame(webrtc::DesktopFrame* frame)
: webrtc::DesktopFrame(
- frame->size(), -frame->stride(),
+ frame->size(),
+ -frame->stride(),
frame->data() + (frame->size().height() - 1) * frame->stride(),
frame->shared_memory()),
original_frame_(frame) {
@@ -73,7 +74,7 @@ class InvertedDesktopFrame : public webrtc::DesktopFrame {
set_capture_time_ms(frame->capture_time_ms());
mutable_updated_region()->Swap(frame->mutable_updated_region());
}
- virtual ~InvertedDesktopFrame() {}
+ ~InvertedDesktopFrame() override {}
private:
scoped_ptr<webrtc::DesktopFrame> original_frame_;
@@ -89,18 +90,16 @@ class FakeScreenCapturer : public webrtc::ScreenCapturer {
frame_index_(0),
generate_inverted_frames_(false) {
}
- virtual ~FakeScreenCapturer() {}
+ ~FakeScreenCapturer() override {}
void set_generate_inverted_frames(bool generate_inverted_frames) {
generate_inverted_frames_ = generate_inverted_frames;
}
// VideoFrameCapturer interface.
- virtual void Start(Callback* callback) OVERRIDE {
- callback_ = callback;
- }
+ void Start(Callback* callback) override { callback_ = callback; }
- virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
+ void Capture(const webrtc::DesktopRegion& region) override {
webrtc::DesktopSize size;
if (frame_index_ % 2 == 0) {
size = webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1);
@@ -115,17 +114,12 @@ class FakeScreenCapturer : public webrtc::ScreenCapturer {
callback_->OnCaptureCompleted(frame);
}
- virtual void SetMouseShapeObserver(
- MouseShapeObserver* mouse_shape_observer) OVERRIDE {
- }
+ void SetMouseShapeObserver(
+ MouseShapeObserver* mouse_shape_observer) override {}
- virtual bool GetScreenList(ScreenList* screens) OVERRIDE {
- return false;
- }
+ bool GetScreenList(ScreenList* screens) override { return false; }
- virtual bool SelectScreen(webrtc::ScreenId id) OVERRIDE {
- return false;
- }
+ bool SelectScreen(webrtc::ScreenId id) override { return false; }
private:
Callback* callback_;
@@ -137,21 +131,12 @@ class FakeScreenCapturer : public webrtc::ScreenCapturer {
class DesktopCaptureDeviceTest : public testing::Test {
public:
- virtual void SetUp() OVERRIDE {
- worker_pool_ = new base::SequencedWorkerPool(3, "TestCaptureThread");
- }
-
void CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer> capturer) {
- capture_device_.reset(new DesktopCaptureDevice(
- worker_pool_->GetSequencedTaskRunner(worker_pool_->GetSequenceToken()),
- thread_.Pass(),
- capturer.Pass(),
- DesktopMediaID::TYPE_SCREEN));
+ capture_device_.reset(
+ new DesktopCaptureDevice(capturer.Pass(), DesktopMediaID::TYPE_SCREEN));
}
protected:
- scoped_refptr<base::SequencedWorkerPool> worker_pool_;
- scoped_ptr<base::Thread> thread_;
scoped_ptr<DesktopCaptureDevice> capture_device_;
};
@@ -183,9 +168,7 @@ TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
capture_params.requested_format.frame_size.SetSize(640, 480);
capture_params.requested_format.frame_rate = kFrameRate;
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
- capture_params.allow_resolution_change = false;
- capture_device_->AllocateAndStart(
- capture_params, client.PassAs<media::VideoCaptureDevice::Client>());
+ capture_device_->AllocateAndStart(capture_params, client.Pass());
EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
capture_device_->StopAndDeAllocate();
@@ -195,7 +178,6 @@ TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
- worker_pool_->FlushForTesting();
}
// Test that screen capturer behaves correctly if the source frame size changes
@@ -221,10 +203,8 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
kTestFrameHeight1);
capture_params.requested_format.frame_rate = kFrameRate;
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
- capture_params.allow_resolution_change = false;
- capture_device_->AllocateAndStart(
- capture_params, client.PassAs<media::VideoCaptureDevice::Client>());
+ capture_device_->AllocateAndStart(capture_params, client.Pass());
// Capture at least two frames, to ensure that the source frame size has
// changed while capturing.
@@ -240,7 +220,6 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
- worker_pool_->FlushForTesting();
}
// Test that screen capturer behaves correctly if the source frame size changes
@@ -264,10 +243,9 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
kTestFrameHeight2);
capture_params.requested_format.frame_rate = kFrameRate;
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
- capture_params.allow_resolution_change = false;
capture_device_->AllocateAndStart(
- capture_params, client.PassAs<media::VideoCaptureDevice::Client>());
+ capture_params, client.Pass());
// Capture at least three frames, to ensure that the source frame size has
// changed at least twice while capturing.
@@ -283,7 +261,6 @@ TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
EXPECT_EQ(kFrameRate, format.frame_rate);
EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
- worker_pool_->FlushForTesting();
}
} // namespace content
diff --git a/chromium/content/browser/media/capture/video_capture_oracle.cc b/chromium/content/browser/media/capture/video_capture_oracle.cc
index c41e5e7e0b1..142bfe604c5 100644
--- a/chromium/content/browser/media/capture/video_capture_oracle.cc
+++ b/chromium/content/browser/media/capture/video_capture_oracle.cc
@@ -4,7 +4,11 @@
#include "content/browser/media/capture/video_capture_oracle.h"
+#include <algorithm>
+
#include "base/debug/trace_event.h"
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
namespace content {
@@ -21,75 +25,167 @@ namespace {
// further into the WebRTC encoding stack.
const int kNumRedundantCapturesOfStaticContent = 200;
+// These specify the minimum/maximum amount of recent event history to examine
+// to detect animated content. If the values are too low, there is a greater
+// risk of false-positive detections and low accuracy. If they are too high,
+// the the implementation will be slow to lock-in/out, and also will not react
+// well to mildly-variable frame rate content (e.g., 25 +/- 1 FPS).
+//
+// These values were established by experimenting with a wide variety of
+// scenarios, including 24/25/30 FPS videos, 60 FPS WebGL demos, and the
+// transitions between static and animated content.
+const int kMinObservationWindowMillis = 1000;
+const int kMaxObservationWindowMillis = 2000;
+
+// The maximum amount of time that can elapse before declaring two subsequent
+// events as "not animating." This is the same value found in
+// cc::FrameRateCounter.
+const int kNonAnimatingThresholdMillis = 250; // 4 FPS
+
+// The slowest that content can be animating in order for AnimatedContentSampler
+// to lock-in. This is the threshold at which the "smoothness" problem is no
+// longer relevant.
+const int kMaxLockInPeriodMicros = 83333; // 12 FPS
+
+// The amount of time over which to fully correct the drift of the rewritten
+// frame timestamps from the presentation event timestamps. The lower the
+// value, the higher the variance in frame timestamps.
+const int kDriftCorrectionMillis = 6000;
+
+// Given the amount of time between frames, compare to the expected amount of
+// time between frames at |frame_rate| and return the fractional difference.
+double FractionFromExpectedFrameRate(base::TimeDelta delta, int frame_rate) {
+ DCHECK_GT(frame_rate, 0);
+ const base::TimeDelta expected_delta =
+ base::TimeDelta::FromSeconds(1) / frame_rate;
+ return (delta - expected_delta).InMillisecondsF() /
+ expected_delta.InMillisecondsF();
+}
+
} // anonymous namespace
-VideoCaptureOracle::VideoCaptureOracle(base::TimeDelta capture_period,
+VideoCaptureOracle::VideoCaptureOracle(base::TimeDelta min_capture_period,
bool events_are_reliable)
- : capture_period_(capture_period),
- frame_number_(0),
- last_delivered_frame_number_(0),
- sampler_(capture_period_,
- events_are_reliable,
- kNumRedundantCapturesOfStaticContent) {}
+ : frame_number_(0),
+ last_delivered_frame_number_(-1),
+ smoothing_sampler_(min_capture_period,
+ events_are_reliable,
+ kNumRedundantCapturesOfStaticContent),
+ content_sampler_(min_capture_period) {
+}
+
+VideoCaptureOracle::~VideoCaptureOracle() {}
bool VideoCaptureOracle::ObserveEventAndDecideCapture(
Event event,
+ const gfx::Rect& damage_rect,
base::TimeTicks event_time) {
- // Record |event| and decide whether it's a good time to capture.
- const bool content_is_dirty = (event == kCompositorUpdate ||
- event == kSoftwarePaint);
+ DCHECK_GE(event, 0);
+ DCHECK_LT(event, kNumEvents);
+ if (event_time < last_event_time_[event]) {
+ LOG(WARNING) << "Event time is not monotonically non-decreasing. "
+ << "Deciding not to capture this frame.";
+ return false;
+ }
+ last_event_time_[event] = event_time;
+
bool should_sample;
- if (content_is_dirty) {
- frame_number_++;
- should_sample = sampler_.AddEventAndConsiderSampling(event_time);
- } else {
- should_sample = sampler_.IsOverdueForSamplingAt(event_time);
+ switch (event) {
+ case kCompositorUpdate:
+ case kSoftwarePaint:
+ smoothing_sampler_.ConsiderPresentationEvent(event_time);
+ content_sampler_.ConsiderPresentationEvent(damage_rect, event_time);
+ if (content_sampler_.HasProposal()) {
+ should_sample = content_sampler_.ShouldSample();
+ if (should_sample)
+ event_time = content_sampler_.frame_timestamp();
+ } else {
+ should_sample = smoothing_sampler_.ShouldSample();
+ }
+ break;
+ default:
+ should_sample = smoothing_sampler_.IsOverdueForSamplingAt(event_time);
+ break;
}
+
+ SetFrameTimestamp(frame_number_, event_time);
return should_sample;
}
int VideoCaptureOracle::RecordCapture() {
- sampler_.RecordSample();
- return frame_number_;
+ smoothing_sampler_.RecordSample();
+ content_sampler_.RecordSample(GetFrameTimestamp(frame_number_));
+ return frame_number_++;
}
bool VideoCaptureOracle::CompleteCapture(int frame_number,
- base::TimeTicks timestamp) {
- // Drop frame if previous frame number is higher or we're trying to deliver
- // a frame with the same timestamp.
- if (last_delivered_frame_number_ > frame_number ||
- last_delivered_frame_timestamp_ == timestamp) {
- LOG(ERROR) << "Frame with same timestamp or out of order delivery. "
- << "Dropping frame.";
+ base::TimeTicks* frame_timestamp) {
+ // Drop frame if previous frame number is higher.
+ if (last_delivered_frame_number_ > frame_number) {
+ LOG(WARNING) << "Out of order frame delivery detected. Dropping frame.";
return false;
}
+ last_delivered_frame_number_ = frame_number;
+
+ *frame_timestamp = GetFrameTimestamp(frame_number);
- if (last_delivered_frame_timestamp_ > timestamp) {
- // We should not get here unless time was adjusted backwards.
- LOG(ERROR) << "Frame with past timestamp (" << timestamp.ToInternalValue()
- << ") was delivered";
+ // If enabled, log a measurement of how this frame timestamp has incremented
+ // in relation to an ideal increment.
+ if (VLOG_IS_ON(2) && frame_number > 0) {
+ const base::TimeDelta delta =
+ *frame_timestamp - GetFrameTimestamp(frame_number - 1);
+ if (content_sampler_.HasProposal()) {
+ const double estimated_frame_rate =
+ 1000000.0 / content_sampler_.detected_period().InMicroseconds();
+ const int rounded_frame_rate =
+ static_cast<int>(estimated_frame_rate + 0.5);
+ VLOG(2) << base::StringPrintf(
+ "Captured #%d: delta=%" PRId64 " usec"
+ ", now locked into {%s}, %+0.1f%% slower than %d FPS",
+ frame_number,
+ delta.InMicroseconds(),
+ content_sampler_.detected_region().ToString().c_str(),
+ 100.0 * FractionFromExpectedFrameRate(delta, rounded_frame_rate),
+ rounded_frame_rate);
+ } else {
+ VLOG(2) << base::StringPrintf(
+ "Captured #%d: delta=%" PRId64 " usec"
+ ", d/30fps=%+0.1f%%, d/25fps=%+0.1f%%, d/24fps=%+0.1f%%",
+ frame_number,
+ delta.InMicroseconds(),
+ 100.0 * FractionFromExpectedFrameRate(delta, 30),
+ 100.0 * FractionFromExpectedFrameRate(delta, 25),
+ 100.0 * FractionFromExpectedFrameRate(delta, 24));
+ }
}
- last_delivered_frame_number_ = frame_number;
- last_delivered_frame_timestamp_ = timestamp;
+ return !frame_timestamp->is_null();
+}
- return true;
+base::TimeTicks VideoCaptureOracle::GetFrameTimestamp(int frame_number) const {
+ DCHECK_LE(frame_number, frame_number_);
+ DCHECK_LT(frame_number_ - frame_number, kMaxFrameTimestamps);
+ return frame_timestamps_[frame_number % kMaxFrameTimestamps];
}
-SmoothEventSampler::SmoothEventSampler(base::TimeDelta capture_period,
+void VideoCaptureOracle::SetFrameTimestamp(int frame_number,
+ base::TimeTicks timestamp) {
+ frame_timestamps_[frame_number % kMaxFrameTimestamps] = timestamp;
+}
+
+SmoothEventSampler::SmoothEventSampler(base::TimeDelta min_capture_period,
bool events_are_reliable,
int redundant_capture_goal)
: events_are_reliable_(events_are_reliable),
- capture_period_(capture_period),
+ min_capture_period_(min_capture_period),
redundant_capture_goal_(redundant_capture_goal),
- token_bucket_capacity_(capture_period + capture_period / 2),
+ token_bucket_capacity_(min_capture_period + min_capture_period / 2),
overdue_sample_count_(0),
token_bucket_(token_bucket_capacity_) {
- DCHECK_GT(capture_period_.InMicroseconds(), 0);
+ DCHECK_GT(min_capture_period_.InMicroseconds(), 0);
}
-bool SmoothEventSampler::AddEventAndConsiderSampling(
- base::TimeTicks event_time) {
+void SmoothEventSampler::ConsiderPresentationEvent(base::TimeTicks event_time) {
DCHECK(!event_time.is_null());
// Add tokens to the bucket based on advancement in time. Then, re-bound the
@@ -104,40 +200,31 @@ bool SmoothEventSampler::AddEventAndConsiderSampling(
if (token_bucket_ > token_bucket_capacity_)
token_bucket_ = token_bucket_capacity_;
}
- // Side note: If the system clock is reset, causing |current_event_| to be
- // greater than |event_time|, everything here will simply gracefully adjust.
- if (token_bucket_ < base::TimeDelta())
- token_bucket_ = base::TimeDelta();
TRACE_COUNTER1("mirroring",
"MirroringTokenBucketUsec",
std::max<int64>(0, token_bucket_.InMicroseconds()));
}
current_event_ = event_time;
+}
- // Return true if one capture period's worth of tokens are in the bucket.
- return token_bucket_ >= capture_period_;
+bool SmoothEventSampler::ShouldSample() const {
+ return token_bucket_ >= min_capture_period_;
}
void SmoothEventSampler::RecordSample() {
- token_bucket_ -= capture_period_;
+ token_bucket_ -= min_capture_period_;
+ if (token_bucket_ < base::TimeDelta())
+ token_bucket_ = base::TimeDelta();
TRACE_COUNTER1("mirroring",
"MirroringTokenBucketUsec",
std::max<int64>(0, token_bucket_.InMicroseconds()));
- bool was_paused = overdue_sample_count_ == redundant_capture_goal_;
if (HasUnrecordedEvent()) {
last_sample_ = current_event_;
overdue_sample_count_ = 0;
} else {
++overdue_sample_count_;
}
- bool is_paused = overdue_sample_count_ == redundant_capture_goal_;
-
- VLOG_IF(0, !was_paused && is_paused)
- << "Tab content unchanged for " << redundant_capture_goal_
- << " frames; capture will halt until content changes.";
- VLOG_IF(0, was_paused && !is_paused)
- << "Content changed; capture will resume.";
}
bool SmoothEventSampler::IsOverdueForSamplingAt(base::TimeTicks event_time)
@@ -159,14 +246,191 @@ bool SmoothEventSampler::IsOverdueForSamplingAt(base::TimeTicks event_time)
// If we're dirty but not yet old, then we've recently gotten updates, so we
// won't request a sample just yet.
base::TimeDelta dirty_interval = event_time - last_sample_;
- if (dirty_interval < capture_period_ * 4)
- return false;
- else
- return true;
+ return dirty_interval >=
+ base::TimeDelta::FromMilliseconds(kNonAnimatingThresholdMillis);
}
bool SmoothEventSampler::HasUnrecordedEvent() const {
return !current_event_.is_null() && current_event_ != last_sample_;
}
+AnimatedContentSampler::AnimatedContentSampler(
+ base::TimeDelta min_capture_period)
+ : min_capture_period_(min_capture_period) {}
+
+AnimatedContentSampler::~AnimatedContentSampler() {}
+
+void AnimatedContentSampler::ConsiderPresentationEvent(
+ const gfx::Rect& damage_rect, base::TimeTicks event_time) {
+ AddObservation(damage_rect, event_time);
+
+ if (AnalyzeObservations(event_time, &detected_region_, &detected_period_) &&
+ detected_period_ > base::TimeDelta() &&
+ detected_period_ <=
+ base::TimeDelta::FromMicroseconds(kMaxLockInPeriodMicros)) {
+ if (damage_rect == detected_region_)
+ UpdateFrameTimestamp(event_time);
+ else
+ frame_timestamp_ = base::TimeTicks();
+ } else {
+ detected_region_ = gfx::Rect();
+ detected_period_ = base::TimeDelta();
+ frame_timestamp_ = base::TimeTicks();
+ }
+}
+
+bool AnimatedContentSampler::HasProposal() const {
+ return detected_period_ > base::TimeDelta();
+}
+
+bool AnimatedContentSampler::ShouldSample() const {
+ return !frame_timestamp_.is_null();
+}
+
+void AnimatedContentSampler::RecordSample(base::TimeTicks frame_timestamp) {
+ recorded_frame_timestamp_ = frame_timestamp;
+ sequence_offset_ = base::TimeDelta();
+}
+
+void AnimatedContentSampler::AddObservation(const gfx::Rect& damage_rect,
+ base::TimeTicks event_time) {
+ if (damage_rect.IsEmpty())
+ return; // Useless observation.
+
+ // Add the observation to the FIFO queue.
+ if (!observations_.empty() && observations_.back().event_time > event_time)
+ return; // The implementation assumes chronological order.
+ observations_.push_back(Observation(damage_rect, event_time));
+
+ // Prune-out old observations.
+ const base::TimeDelta threshold =
+ base::TimeDelta::FromMilliseconds(kMaxObservationWindowMillis);
+ while ((event_time - observations_.front().event_time) > threshold)
+ observations_.pop_front();
+}
+
+gfx::Rect AnimatedContentSampler::ElectMajorityDamageRect() const {
+ // This is an derivative of the Boyer-Moore Majority Vote Algorithm where each
+ // pixel in a candidate gets one vote, as opposed to each candidate getting
+ // one vote.
+ const gfx::Rect* candidate = NULL;
+ int64 votes = 0;
+ for (ObservationFifo::const_iterator i = observations_.begin();
+ i != observations_.end(); ++i) {
+ DCHECK_GT(i->damage_rect.size().GetArea(), 0);
+ if (votes == 0) {
+ candidate = &(i->damage_rect);
+ votes = candidate->size().GetArea();
+ } else if (i->damage_rect == *candidate) {
+ votes += i->damage_rect.size().GetArea();
+ } else {
+ votes -= i->damage_rect.size().GetArea();
+ if (votes < 0) {
+ candidate = &(i->damage_rect);
+ votes = -votes;
+ }
+ }
+ }
+ return (votes > 0) ? *candidate : gfx::Rect();
+}
+
+bool AnimatedContentSampler::AnalyzeObservations(
+ base::TimeTicks event_time,
+ gfx::Rect* rect,
+ base::TimeDelta* period) const {
+ const gfx::Rect elected_rect = ElectMajorityDamageRect();
+ if (elected_rect.IsEmpty())
+ return false; // There is no regular animation present.
+
+ // Scan |observations_|, gathering metrics about the ones having a damage Rect
+ // equivalent to the |elected_rect|. Along the way, break early whenever the
+ // event times reveal a non-animating period.
+ int64 num_pixels_damaged_in_all = 0;
+ int64 num_pixels_damaged_in_chosen = 0;
+ base::TimeDelta sum_frame_durations;
+ size_t count_frame_durations = 0;
+ base::TimeTicks first_event_time;
+ base::TimeTicks last_event_time;
+ for (ObservationFifo::const_reverse_iterator i = observations_.rbegin();
+ i != observations_.rend(); ++i) {
+ const int area = i->damage_rect.size().GetArea();
+ num_pixels_damaged_in_all += area;
+ if (i->damage_rect != elected_rect)
+ continue;
+ num_pixels_damaged_in_chosen += area;
+ if (last_event_time.is_null()) {
+ last_event_time = i->event_time;
+ if ((event_time - last_event_time) >=
+ base::TimeDelta::FromMilliseconds(kNonAnimatingThresholdMillis)) {
+ return false; // Content animation has recently ended.
+ }
+ } else {
+ const base::TimeDelta frame_duration = first_event_time - i->event_time;
+ if (frame_duration >=
+ base::TimeDelta::FromMilliseconds(kNonAnimatingThresholdMillis)) {
+ break; // Content not animating before this point.
+ }
+ sum_frame_durations += frame_duration;
+ ++count_frame_durations;
+ }
+ first_event_time = i->event_time;
+ }
+
+ if ((last_event_time - first_event_time) <
+ base::TimeDelta::FromMilliseconds(kMinObservationWindowMillis)) {
+ return false; // Content has not animated for long enough for accuracy.
+ }
+ if (num_pixels_damaged_in_chosen <= (num_pixels_damaged_in_all * 2 / 3))
+ return false; // Animation is not damaging a supermajority of pixels.
+
+ *rect = elected_rect;
+ DCHECK_GT(count_frame_durations, 0u);
+ *period = sum_frame_durations / count_frame_durations;
+ return true;
+}
+
+void AnimatedContentSampler::UpdateFrameTimestamp(base::TimeTicks event_time) {
+ // This is how much time to advance from the last frame timestamp. Never
+ // advance by less than |min_capture_period_| because the downstream consumer
+ // cannot handle the higher frame rate. If |detected_period_| is less than
+ // |min_capture_period_|, excess frames should be dropped.
+ const base::TimeDelta advancement =
+ std::max(detected_period_, min_capture_period_);
+
+ // Compute the |timebase| upon which to determine the |frame_timestamp_|.
+ // Ideally, this would always equal the timestamp of the last recorded frame
+ // sampling. Determine how much drift from the ideal is present, then adjust
+ // the timebase by a small amount to spread out the entire correction over
+ // many frame timestamps.
+ //
+ // This accounts for two main sources of drift: 1) The clock drift of the
+ // system clock relative to the video hardware, which affects the event times;
+ // and 2) The small error introduced by this frame timestamp rewriting, as it
+ // is based on averaging over recent events.
+ base::TimeTicks timebase = event_time - sequence_offset_ - advancement;
+ if (!recorded_frame_timestamp_.is_null()) {
+ const base::TimeDelta drift = recorded_frame_timestamp_ - timebase;
+ const int64 correct_over_num_frames =
+ base::TimeDelta::FromMilliseconds(kDriftCorrectionMillis) /
+ detected_period_;
+ DCHECK_GT(correct_over_num_frames, 0);
+ timebase = recorded_frame_timestamp_ - (drift / correct_over_num_frames);
+ }
+
+ // Compute |frame_timestamp_|. Whenever |detected_period_| is less than
+ // |min_capture_period_|, some extra time is "borrowed" to be able to advance
+ // by the full |min_capture_period_|. Then, whenever the total amount of
+ // borrowed time reaches a full |min_capture_period_|, drop a frame. Note
+ // that when |detected_period_| is greater or equal to |min_capture_period_|,
+ // this logic is effectively disabled.
+ borrowed_time_ += advancement - detected_period_;
+ if (borrowed_time_ >= min_capture_period_) {
+ borrowed_time_ -= min_capture_period_;
+ frame_timestamp_ = base::TimeTicks();
+ } else {
+ sequence_offset_ += advancement;
+ frame_timestamp_ = timebase + sequence_offset_;
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/media/capture/video_capture_oracle.h b/chromium/content/browser/media/capture/video_capture_oracle.h
index 6242b6a29a8..32e7baff4da 100644
--- a/chromium/content/browser/media/capture/video_capture_oracle.h
+++ b/chromium/content/browser/media/capture/video_capture_oracle.h
@@ -5,26 +5,34 @@
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_ORACLE_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_ORACLE_H_
+#include <deque>
+
#include "base/callback_forward.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
// Filters a sequence of events to achieve a target frequency.
class CONTENT_EXPORT SmoothEventSampler {
public:
- explicit SmoothEventSampler(base::TimeDelta capture_period,
- bool events_are_reliable,
- int redundant_capture_goal);
+ SmoothEventSampler(base::TimeDelta min_capture_period,
+ bool events_are_reliable,
+ int redundant_capture_goal);
+
+ base::TimeDelta min_capture_period() const { return min_capture_period_; }
+
+ // Add a new event to the event history, and consider whether it ought to be
+ // sampled. The event is not recorded as a sample until RecordSample() is
+ // called.
+ void ConsiderPresentationEvent(base::TimeTicks event_time);
- // Add a new event to the event history, and return whether it ought to be
- // sampled based on the desired |capture_period|. The event is not recorded as
- // a sample until RecordSample() is called.
- bool AddEventAndConsiderSampling(base::TimeTicks event_time);
+ // Returns true if the last event considered should be sampled.
+ bool ShouldSample() const;
- // Operates on the last event added by AddEventAndConsiderSampling(), marking
+ // Operates on the last event added by ConsiderPresentationEvent(), marking
// it as sampled. After this point we are current in the stream of events, as
// we have sampled the most recent event.
void RecordSample();
@@ -33,13 +41,13 @@ class CONTENT_EXPORT SmoothEventSampler {
// much time will have passed relative to the last event and/or sample.
bool IsOverdueForSamplingAt(base::TimeTicks event_time) const;
- // Returns true if AddEventAndConsiderSampling() has been called since the
- // last call to RecordSample().
+ // Returns true if ConsiderPresentationEvent() has been called since the last
+ // call to RecordSample().
bool HasUnrecordedEvent() const;
private:
const bool events_are_reliable_;
- const base::TimeDelta capture_period_;
+ const base::TimeDelta min_capture_period_;
const int redundant_capture_goal_;
const base::TimeDelta token_bucket_capacity_;
@@ -51,6 +59,115 @@ class CONTENT_EXPORT SmoothEventSampler {
DISALLOW_COPY_AND_ASSIGN(SmoothEventSampler);
};
+// Analyzes a sequence of events to detect the presence of constant frame rate
+// animated content. In the case where there are multiple regions of animated
+// content, AnimatedContentSampler will propose sampling the one having the
+// largest "smoothness" impact, according to human perception (e.g., a 24 FPS
+// video versus a 60 FPS busy spinner).
+//
+// In addition, AnimatedContentSampler will provide rewritten frame timestamps,
+// for downstream consumers, that are "truer" to the source content than to the
+// local presentation hardware.
+class CONTENT_EXPORT AnimatedContentSampler {
+ public:
+ explicit AnimatedContentSampler(base::TimeDelta min_capture_period);
+ ~AnimatedContentSampler();
+
+ // Examines the given presentation event metadata, along with recent history,
+ // to detect animated content, updating the state of this sampler.
+ // |damage_rect| is the region of a frame about to be drawn, while
+ // |event_time| refers to the frame's estimated presentation time.
+ void ConsiderPresentationEvent(const gfx::Rect& damage_rect,
+ base::TimeTicks event_time);
+
+ // Returns true if animated content has been detected and a decision has been
+ // made about whether to sample the last event.
+ bool HasProposal() const;
+
+ // Returns true if the last event considered should be sampled.
+ bool ShouldSample() const;
+
+ // Returns a frame timestamp to provide to consumers of the sampled frame.
+ // Only valid when should_sample() returns true.
+ base::TimeTicks frame_timestamp() const { return frame_timestamp_; }
+
+ // Accessors to currently-detected animating region/period, for logging.
+ const gfx::Rect& detected_region() const { return detected_region_; }
+ base::TimeDelta detected_period() const { return detected_period_; }
+
+ // Records that a frame with the given |frame_timestamp| was sampled. This
+ // method should be called when *any* sampling is taken, even if it was not
+ // proposed by AnimatedContentSampler.
+ void RecordSample(base::TimeTicks frame_timestamp);
+
+ private:
+ friend class AnimatedContentSamplerTest;
+
+ // Data structure for efficient online analysis of recent event history.
+ struct Observation {
+ gfx::Rect damage_rect;
+ base::TimeTicks event_time;
+
+ Observation(const gfx::Rect& d, base::TimeTicks e)
+ : damage_rect(d), event_time(e) {}
+ };
+ typedef std::deque<Observation> ObservationFifo;
+
+ // Adds an observation to |observations_|, and prunes-out the old ones.
+ void AddObservation(const gfx::Rect& damage_rect, base::TimeTicks event_time);
+
+ // Returns the damage Rect that is responsible for the majority of the pixel
+ // damage in recent event history, if there is such a Rect. If there isn't,
+ // this method could still return any Rect, so the caller must confirm the
+ // returned Rect really is responsible for the majority of pixel damage.
+ gfx::Rect ElectMajorityDamageRect() const;
+
+ // Analyzes the observations relative to the current |event_time| to detect
+ // stable animating content. If detected, returns true and sets the output
+ // arguments to the region of the animating content and its mean frame
+ // duration.
+ bool AnalyzeObservations(base::TimeTicks event_time,
+ gfx::Rect* rect,
+ base::TimeDelta* period) const;
+
+ // Called by ConsiderPresentationEvent() when the current event is part of a
+ // detected animation, to update |frame_timestamp_|.
+ void UpdateFrameTimestamp(base::TimeTicks event_time);
+
+ // The client expects frame timestamps to be at least this far apart.
+ const base::TimeDelta min_capture_period_;
+
+ // A recent history of observations in chronological order, maintained by
+ // AddObservation().
+ ObservationFifo observations_;
+
+ // The region of currently-detected animated content. If empty, that means
+ // "not detected."
+ gfx::Rect detected_region_;
+
+ // The mean frame duration of currently-detected animated content. If zero,
+ // that means "not detected."
+ base::TimeDelta detected_period_;
+
+ // The rewritten frame timestamp for the latest event.
+ base::TimeTicks frame_timestamp_;
+
+ // The frame timestamp provided in the last call to RecordSample(). This
+ // timestamp may or may not have been one proposed by AnimatedContentSampler.
+ base::TimeTicks recorded_frame_timestamp_;
+
+ // Accumulates all the time advancements since the last call to
+ // RecordSample(). When this is greater than zero, there have been one or
+ // more events proposed for sampling, but not yet recorded. This accounts for
+ // the cases where AnimatedContentSampler indicates a frame should be sampled,
+ // but the client chooses not to do so.
+ base::TimeDelta sequence_offset_;
+
+ // A token bucket that is used to decide which frames to drop whenever
+ // |detected_period_| is less than |min_capture_period_|.
+ base::TimeDelta borrowed_time_;
+};
+
// VideoCaptureOracle manages the producer-side throttling of captured frames
// from a video capture device. It is informed of every update by the device;
// this empowers it to look into the future and decide if a particular frame
@@ -61,43 +178,61 @@ class CONTENT_EXPORT VideoCaptureOracle {
kTimerPoll,
kCompositorUpdate,
kSoftwarePaint,
+ kNumEvents,
};
- VideoCaptureOracle(base::TimeDelta capture_period,
+ VideoCaptureOracle(base::TimeDelta min_capture_period,
bool events_are_reliable);
- virtual ~VideoCaptureOracle() {}
+ virtual ~VideoCaptureOracle();
- // Record an event of type |event|, and decide whether the caller should do a
- // frame capture immediately. Decisions of the oracle are final: the caller
- // must do what it is told.
- bool ObserveEventAndDecideCapture(Event event, base::TimeTicks event_time);
+ // Record a event of type |event|, and decide whether the caller should do a
+ // frame capture. |damage_rect| is the region of a frame about to be drawn,
+ // and may be an empty Rect, if this is not known. If the caller accepts the
+ // oracle's proposal, it should call RecordCapture() to indicate this.
+ bool ObserveEventAndDecideCapture(Event event,
+ const gfx::Rect& damage_rect,
+ base::TimeTicks event_time);
// Record the start of a capture. Returns a frame_number to be used with
// CompleteCapture().
int RecordCapture();
- // Record the completion of a capture. Returns true iff the captured frame
- // should be delivered.
- bool CompleteCapture(int frame_number, base::TimeTicks timestamp);
+ // Notify of the completion of a capture. Returns true iff the captured frame
+ // should be delivered. |frame_timestamp| is set to the timestamp that should
+ // be provided to the consumer of the frame.
+ bool CompleteCapture(int frame_number, base::TimeTicks* frame_timestamp);
- base::TimeDelta capture_period() const { return capture_period_; }
+ base::TimeDelta min_capture_period() const {
+ return smoothing_sampler_.min_capture_period();
+ }
private:
-
- // Time between frames.
- const base::TimeDelta capture_period_;
+ // Retrieve/Assign a frame timestamp by capture |frame_number|.
+ base::TimeTicks GetFrameTimestamp(int frame_number) const;
+ void SetFrameTimestamp(int frame_number, base::TimeTicks timestamp);
// Incremented every time a paint or update event occurs.
int frame_number_;
+ // Stores the last |event_time| from the last observation/decision. Used to
+ // sanity-check that event times are monotonically non-decreasing.
+ base::TimeTicks last_event_time_[kNumEvents];
+
// Stores the frame number from the last delivered frame.
int last_delivered_frame_number_;
- // Stores the timestamp of the last delivered frame.
- base::TimeTicks last_delivered_frame_timestamp_;
-
- // Tracks present/paint history.
- SmoothEventSampler sampler_;
+ // These track present/paint history and propose whether to sample each event
+ // for capture. |smoothing_sampler_| uses a "works for all" heuristic, while
+ // |content_sampler_| specifically detects animated content (e.g., video
+ // playback) and decides which events to sample to "lock into" that content.
+ SmoothEventSampler smoothing_sampler_;
+ AnimatedContentSampler content_sampler_;
+
+ // Recent history of frame timestamps proposed by VideoCaptureOracle. This is
+ // a ring-buffer, and should only be accessed by the Get/SetFrameTimestamp()
+ // methods.
+ enum { kMaxFrameTimestamps = 16 };
+ base::TimeTicks frame_timestamps_[kMaxFrameTimestamps];
};
} // namespace content
diff --git a/chromium/content/browser/media/capture/video_capture_oracle_unittest.cc b/chromium/content/browser/media/capture/video_capture_oracle_unittest.cc
index dff8e97de7f..1a4222ac4d5 100644
--- a/chromium/content/browser/media/capture/video_capture_oracle_unittest.cc
+++ b/chromium/content/browser/media/capture/video_capture_oracle_unittest.cc
@@ -4,17 +4,29 @@
#include "content/browser/media/capture/video_capture_oracle.h"
+#include <cstdlib>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
namespace content {
namespace {
+bool AddEventAndConsiderSampling(SmoothEventSampler* sampler,
+ base::TimeTicks event_time) {
+ sampler->ConsiderPresentationEvent(event_time);
+ return sampler->ShouldSample();
+}
+
void SteadyStateSampleAndAdvance(base::TimeDelta vsync,
SmoothEventSampler* sampler,
base::TimeTicks* t) {
- ASSERT_TRUE(sampler->AddEventAndConsiderSampling(*t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t));
ASSERT_TRUE(sampler->HasUnrecordedEvent());
sampler->RecordSample();
ASSERT_FALSE(sampler->HasUnrecordedEvent());
@@ -26,17 +38,15 @@ void SteadyStateSampleAndAdvance(base::TimeDelta vsync,
void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync,
SmoothEventSampler* sampler,
base::TimeTicks* t) {
- ASSERT_FALSE(sampler->AddEventAndConsiderSampling(*t));
+ ASSERT_FALSE(AddEventAndConsiderSampling(sampler, *t));
ASSERT_TRUE(sampler->HasUnrecordedEvent());
ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
*t += vsync;
ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
}
-void TimeTicksFromString(const char* string, base::TimeTicks* t) {
- base::Time time;
- ASSERT_TRUE(base::Time::FromString(string, &time));
- *t = base::TimeTicks::UnixEpoch() + (time - base::Time::UnixEpoch());
+base::TimeTicks InitialTestTimeTicks() {
+ return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
}
void TestRedundantCaptureStrategy(base::TimeDelta capture_period,
@@ -48,15 +58,15 @@ void TestRedundantCaptureStrategy(base::TimeDelta capture_period,
// Consider the first event. We want to sample that.
ASSERT_FALSE(sampler->HasUnrecordedEvent());
- ASSERT_TRUE(sampler->AddEventAndConsiderSampling(*t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(sampler, *t));
ASSERT_TRUE(sampler->HasUnrecordedEvent());
sampler->RecordSample();
ASSERT_FALSE(sampler->HasUnrecordedEvent());
- // After more than one capture period has passed without considering an event,
- // we should repeatedly be overdue for sampling. However, once the redundant
- // capture goal is achieved, we should no longer be overdue for sampling.
- *t += capture_period * 4;
+ // After more than 250 ms has passed without considering an event, we should
+ // repeatedly be overdue for sampling. However, once the redundant capture
+ // goal is achieved, we should no longer be overdue for sampling.
+ *t += base::TimeDelta::FromMilliseconds(250);
for (int i = 0; i < redundant_capture_goal; i++) {
SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
ASSERT_FALSE(sampler->HasUnrecordedEvent());
@@ -69,6 +79,8 @@ void TestRedundantCaptureStrategy(base::TimeDelta capture_period,
<< "Should not be overdue once redundant capture goal achieved.";
}
+} // namespace
+
// 60Hz sampled at 30Hz should produce 30Hz. In addition, this test contains
// much more comprehensive before/after/edge-case scenarios than the others.
TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) {
@@ -77,8 +89,7 @@ TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) {
const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60;
SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t;
- TimeTicksFromString("Sat, 23 Mar 2013 1:21:08 GMT", &t);
+ base::TimeTicks t = InitialTestTimeTicks();
TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
&sampler, &t);
@@ -94,8 +105,8 @@ TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) {
// case we are adding events but not sampling them.
for (int i = 0; i < 20; i++) {
SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
+ ASSERT_EQ(i >= 14, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
ASSERT_TRUE(sampler.HasUnrecordedEvent());
t += vsync;
}
@@ -117,8 +128,7 @@ TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) {
const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50;
SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t;
- TimeTicksFromString("Sat, 23 Mar 2013 1:21:08 GMT", &t);
+ base::TimeTicks t = InitialTestTimeTicks();
TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
&sampler, &t);
@@ -136,10 +146,10 @@ TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) {
// Now pretend we're limited by backpressure in the pipeline. In this scenario
// case we are adding events but not sampling them.
- for (int i = 0; i < 12; i++) {
+ for (int i = 0; i < 20; i++) {
SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 5, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
+ ASSERT_EQ(i >= 11, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
t += vsync;
}
@@ -163,8 +173,7 @@ TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) {
const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75;
SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t;
- TimeTicksFromString("Sat, 23 Mar 2013 1:21:08 GMT", &t);
+ base::TimeTicks t = InitialTestTimeTicks();
TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
&sampler, &t);
@@ -186,8 +195,8 @@ TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) {
// case we are adding events but not sampling them.
for (int i = 0; i < 20; i++) {
SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 8, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
+ ASSERT_EQ(i >= 16, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
t += vsync;
}
@@ -213,8 +222,7 @@ TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) {
const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30;
SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t;
- TimeTicksFromString("Sat, 23 Mar 2013 1:21:08 GMT", &t);
+ base::TimeTicks t = InitialTestTimeTicks();
TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
&sampler, &t);
@@ -227,10 +235,10 @@ TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) {
// Now pretend we're limited by backpressure in the pipeline. In this scenario
// case we are adding events but not sampling them.
- for (int i = 0; i < 7; i++) {
+ for (int i = 0; i < 10; i++) {
SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 3, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
+ ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
t += vsync;
}
@@ -249,8 +257,7 @@ TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) {
const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24;
SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
- base::TimeTicks t;
- TimeTicksFromString("Sat, 23 Mar 2013 1:21:08 GMT", &t);
+ base::TimeTicks t = InitialTestTimeTicks();
TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
&sampler, &t);
@@ -263,10 +270,10 @@ TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) {
// Now pretend we're limited by backpressure in the pipeline. In this scenario
// case we are adding events but not sampling them.
- for (int i = 0; i < 7; i++) {
+ for (int i = 0; i < 10; i++) {
SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
- ASSERT_EQ(i >= 3, sampler.IsOverdueForSamplingAt(t));
- ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
+ ASSERT_EQ(i >= 6, sampler.IsOverdueForSamplingAt(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
t += vsync;
}
@@ -283,19 +290,18 @@ TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) {
const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1);
SmoothEventSampler sampler(capture_period, true, 1);
- base::TimeTicks t;
- TimeTicksFromString("Sat, 23 Mar 2013 1:21:08 GMT", &t);
+ base::TimeTicks t = InitialTestTimeTicks();
- ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
sampler.RecordSample();
ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t))
<< "Sampled last event; should not be dirty.";
t += overdue_period;
// Now simulate 2 events with the same clock value.
- ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&sampler, t));
sampler.RecordSample();
- ASSERT_FALSE(sampler.AddEventAndConsiderSampling(t))
+ ASSERT_FALSE(AddEventAndConsiderSampling(&sampler, t))
<< "Two events at same time -- expected second not to be sampled.";
ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t + overdue_period))
<< "Second event should dirty the capture state.";
@@ -308,18 +314,20 @@ TEST(SmoothEventSamplerTest, FallbackToPollingIfUpdatesUnreliable) {
SmoothEventSampler should_not_poll(timer_interval, true, 1);
SmoothEventSampler should_poll(timer_interval, false, 1);
- base::TimeTicks t;
- TimeTicksFromString("Sat, 23 Mar 2013 1:21:08 GMT", &t);
+ base::TimeTicks t = InitialTestTimeTicks();
// Do one round of the "happy case" where an event was received and
// RecordSample() was called by the client.
- ASSERT_TRUE(should_not_poll.AddEventAndConsiderSampling(t));
- ASSERT_TRUE(should_poll.AddEventAndConsiderSampling(t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&should_not_poll, t));
+ ASSERT_TRUE(AddEventAndConsiderSampling(&should_poll, t));
should_not_poll.RecordSample();
should_poll.RecordSample();
- // One time period ahead, neither sampler says we're overdue.
- for (int i = 0; i < 3; i++) {
+ // For the following time period, before 250 ms has elapsed, neither sampler
+ // says we're overdue.
+ const int non_overdue_intervals = static_cast<int>(
+ base::TimeDelta::FromMilliseconds(250) / timer_interval);
+ for (int i = 0; i < non_overdue_intervals; i++) {
t += timer_interval;
ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
<< "Sampled last event; should not be dirty.";
@@ -330,7 +338,7 @@ TEST(SmoothEventSamplerTest, FallbackToPollingIfUpdatesUnreliable) {
// Next time period ahead, both samplers say we're overdue. The non-polling
// sampler is returning true here because it has been configured to allow one
// redundant capture.
- t += timer_interval;
+ t += timer_interval; // Step past the 250 ms threshold.
ASSERT_TRUE(should_not_poll.IsOverdueForSamplingAt(t))
<< "Sampled last event; is dirty one time only to meet redundancy goal.";
ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
@@ -356,6 +364,8 @@ TEST(SmoothEventSamplerTest, FallbackToPollingIfUpdatesUnreliable) {
should_poll.RecordSample();
}
+namespace {
+
struct DataPoint {
bool should_capture;
double increment_ms;
@@ -364,19 +374,20 @@ struct DataPoint {
void ReplayCheckingSamplerDecisions(const DataPoint* data_points,
size_t num_data_points,
SmoothEventSampler* sampler) {
- base::TimeTicks t;
- TimeTicksFromString("Sat, 23 Mar 2013 1:21:08 GMT", &t);
+ base::TimeTicks t = InitialTestTimeTicks();
for (size_t i = 0; i < num_data_points; ++i) {
t += base::TimeDelta::FromMicroseconds(
static_cast<int64>(data_points[i].increment_ms * 1000));
ASSERT_EQ(data_points[i].should_capture,
- sampler->AddEventAndConsiderSampling(t))
+ AddEventAndConsiderSampling(sampler, t))
<< "at data_points[" << i << ']';
if (data_points[i].should_capture)
sampler->RecordSample();
}
}
+} // namespace
+
TEST(SmoothEventSamplerTest, DrawingAt24FpsWith60HzVsyncSampledAt30Hertz) {
// Actual capturing of timing data: Initial instability as a 24 FPS video was
// started from a still screen, then clearly followed by steady-state.
@@ -483,5 +494,768 @@ TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) {
ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
}
+class AnimatedContentSamplerTest : public ::testing::Test {
+ public:
+ AnimatedContentSamplerTest() {}
+ ~AnimatedContentSamplerTest() override {}
+
+ void SetUp() override {
+ const base::TimeDelta since_epoch =
+ InitialTestTimeTicks() - base::TimeTicks::UnixEpoch();
+ rand_seed_ = abs(static_cast<int>(since_epoch.InMicroseconds()));
+ sampler_.reset(new AnimatedContentSampler(GetMinCapturePeriod()));
+ }
+
+ protected:
+ // Overridden by subclass for parameterized tests.
+ virtual base::TimeDelta GetMinCapturePeriod() const {
+ return base::TimeDelta::FromSeconds(1) / 30;
+ }
+
+ AnimatedContentSampler* sampler() const {
+ return sampler_.get();
+ }
+
+ int GetRandomInRange(int begin, int end) {
+ const int len = end - begin;
+ const int rand_offset = (len == 0) ? 0 : (NextRandomInt() % (end - begin));
+ return begin + rand_offset;
+ }
+
+ gfx::Rect GetRandomDamageRect() {
+ return gfx::Rect(0, 0, GetRandomInRange(1, 100), GetRandomInRange(1, 100));
+ }
+
+ gfx::Rect GetContentDamageRect() {
+ // This must be distinct from anything GetRandomDamageRect() could return.
+ return gfx::Rect(0, 0, 1280, 720);
+ }
+
+ // Directly inject an observation. Only used to test
+ // ElectMajorityDamageRect().
+ void ObserveDamageRect(const gfx::Rect& damage_rect) {
+ sampler_->observations_.push_back(
+ AnimatedContentSampler::Observation(damage_rect, base::TimeTicks()));
+ }
+
+ gfx::Rect ElectMajorityDamageRect() const {
+ return sampler_->ElectMajorityDamageRect();
+ }
+
+ private:
+ // Note: Not using base::RandInt() because it is horribly slow on debug
+ // builds. The following is a very simple, deterministic LCG:
+ int NextRandomInt() {
+ rand_seed_ = (1103515245 * rand_seed_ + 12345) % (1 << 31);
+ return rand_seed_;
+ }
+
+ int rand_seed_;
+ scoped_ptr<AnimatedContentSampler> sampler_;
+};
+
+TEST_F(AnimatedContentSamplerTest, ElectsNoneFromZeroDamageRects) {
+ EXPECT_EQ(gfx::Rect(), ElectMajorityDamageRect());
+}
+
+TEST_F(AnimatedContentSamplerTest, ElectsMajorityFromOneDamageRect) {
+ const gfx::Rect the_one_rect(0, 0, 1, 1);
+ ObserveDamageRect(the_one_rect);
+ EXPECT_EQ(the_one_rect, ElectMajorityDamageRect());
+}
+
+TEST_F(AnimatedContentSamplerTest, ElectsNoneFromTwoDamageRectsOfSameArea) {
+ const gfx::Rect one_rect(0, 0, 1, 1);
+ const gfx::Rect another_rect(1, 1, 1, 1);
+ ObserveDamageRect(one_rect);
+ ObserveDamageRect(another_rect);
+ EXPECT_EQ(gfx::Rect(), ElectMajorityDamageRect());
+}
+
+TEST_F(AnimatedContentSamplerTest, ElectsLargerOfTwoDamageRects_1) {
+ const gfx::Rect one_rect(0, 0, 1, 1);
+ const gfx::Rect another_rect(0, 0, 2, 2);
+ ObserveDamageRect(one_rect);
+ ObserveDamageRect(another_rect);
+ EXPECT_EQ(another_rect, ElectMajorityDamageRect());
+}
+
+TEST_F(AnimatedContentSamplerTest, ElectsLargerOfTwoDamageRects_2) {
+ const gfx::Rect one_rect(0, 0, 2, 2);
+ const gfx::Rect another_rect(0, 0, 1, 1);
+ ObserveDamageRect(one_rect);
+ ObserveDamageRect(another_rect);
+ EXPECT_EQ(one_rect, ElectMajorityDamageRect());
+}
+
+TEST_F(AnimatedContentSamplerTest, ElectsSameAsMooreDemonstration) {
+ // A more complex sequence (from Moore's web site): Three different Rects with
+ // the same area, but occurring a different number of times. C should win the
+ // vote.
+ const gfx::Rect rect_a(0, 0, 1, 4);
+ const gfx::Rect rect_b(1, 1, 4, 1);
+ const gfx::Rect rect_c(2, 2, 2, 2);
+ for (int i = 0; i < 3; ++i)
+ ObserveDamageRect(rect_a);
+ for (int i = 0; i < 2; ++i)
+ ObserveDamageRect(rect_c);
+ for (int i = 0; i < 2; ++i)
+ ObserveDamageRect(rect_b);
+ for (int i = 0; i < 3; ++i)
+ ObserveDamageRect(rect_c);
+ ObserveDamageRect(rect_b);
+ for (int i = 0; i < 2; ++i)
+ ObserveDamageRect(rect_c);
+ EXPECT_EQ(rect_c, ElectMajorityDamageRect());
+}
+
+TEST_F(AnimatedContentSamplerTest, Elects24FpsVideoInsteadOf48FpsSpinner) {
+ // Scenario: 24 FPS 720x480 Video versus 48 FPS 96x96 "Busy Spinner"
+ const gfx::Rect video_rect(100, 100, 720, 480);
+ const gfx::Rect spinner_rect(360, 0, 96, 96);
+ for (int i = 0; i < 100; ++i) {
+ // |video_rect| occurs once for every two |spinner_rect|. Vary the order
+ // of events between the two:
+ ObserveDamageRect(video_rect);
+ ObserveDamageRect(spinner_rect);
+ ObserveDamageRect(spinner_rect);
+ ObserveDamageRect(video_rect);
+ ObserveDamageRect(spinner_rect);
+ ObserveDamageRect(spinner_rect);
+ ObserveDamageRect(spinner_rect);
+ ObserveDamageRect(video_rect);
+ ObserveDamageRect(spinner_rect);
+ ObserveDamageRect(spinner_rect);
+ ObserveDamageRect(video_rect);
+ ObserveDamageRect(spinner_rect);
+ }
+ EXPECT_EQ(video_rect, ElectMajorityDamageRect());
+}
+
+namespace {
+
+// A test scenario for AnimatedContentSamplerParameterizedTest.
+struct Scenario {
+ base::TimeDelta vsync_interval; // Reflects compositor's update rate.
+ base::TimeDelta min_capture_period; // Reflects maximum capture rate.
+ base::TimeDelta content_period; // Reflects content animation rate.
+
+ Scenario(base::TimeDelta v, base::TimeDelta m, base::TimeDelta c)
+ : vsync_interval(v), min_capture_period(m), content_period(c) {
+ CHECK(content_period >= vsync_interval)
+ << "Bad test params: Impossible to animate faster than the compositor.";
+ }
+};
+
+// Value printer for Scenario.
+::std::ostream& operator<<(::std::ostream& os, const Scenario& s) {
+ return os << "{ vsync_interval=" << s.vsync_interval.InMicroseconds()
+ << ", min_capture_period=" << s.min_capture_period.InMicroseconds()
+ << ", content_period=" << s.content_period.InMicroseconds()
+ << " }";
+}
+
+base::TimeDelta FpsAsPeriod(int frame_rate) {
+ return base::TimeDelta::FromSeconds(1) / frame_rate;
+}
+
} // namespace
+
+class AnimatedContentSamplerParameterizedTest
+ : public AnimatedContentSamplerTest,
+ public ::testing::WithParamInterface<Scenario> {
+ public:
+ AnimatedContentSamplerParameterizedTest()
+ : count_dropped_frames_(0), count_sampled_frames_(0) {}
+ virtual ~AnimatedContentSamplerParameterizedTest() {}
+
+ protected:
+ typedef std::pair<gfx::Rect, base::TimeTicks> Event;
+
+ base::TimeDelta GetMinCapturePeriod() const override {
+ return GetParam().min_capture_period;
+ }
+
+ // Generate a sequence of events from the compositor pipeline. The event
+ // times will all be at compositor vsync boundaries.
+ std::vector<Event> GenerateEventSequence(base::TimeTicks begin,
+ base::TimeTicks end,
+ bool include_content_frame_events,
+ bool include_random_events) {
+ DCHECK(GetParam().content_period >= GetParam().vsync_interval);
+ base::TimeTicks next_content_time = begin - GetParam().content_period;
+ std::vector<Event> events;
+ for (base::TimeTicks compositor_time = begin; compositor_time < end;
+ compositor_time += GetParam().vsync_interval) {
+ if (include_content_frame_events && next_content_time < compositor_time) {
+ events.push_back(Event(GetContentDamageRect(), compositor_time));
+ next_content_time += GetParam().content_period;
+ } else if (include_random_events && GetRandomInRange(0, 1) == 0) {
+ events.push_back(Event(GetRandomDamageRect(), compositor_time));
+ }
+ }
+
+ DCHECK(!events.empty());
+ return events;
+ }
+
+ // Feed |events| through the sampler, and detect whether the expected
+ // lock-in/out transition occurs. Also, track and measure the frame drop
+ // ratio and check it against the expected drop rate.
+ void RunEventSequence(const std::vector<Event> events,
+ bool was_detecting_before,
+ bool is_detecting_after,
+ bool simulate_pipeline_back_pressure) {
+ gfx::Rect first_detected_region;
+
+ EXPECT_EQ(was_detecting_before, sampler()->HasProposal());
+ bool has_detection_switched = false;
+ ResetFrameCounters();
+ for (std::vector<Event>::const_iterator i = events.begin();
+ i != events.end(); ++i) {
+ sampler()->ConsiderPresentationEvent(i->first, i->second);
+
+ // Detect when the sampler locks in/out, and that it stays that way for
+ // all further iterations of this loop.
+ if (!has_detection_switched &&
+ was_detecting_before != sampler()->HasProposal()) {
+ has_detection_switched = true;
+ }
+ ASSERT_EQ(
+ has_detection_switched ? is_detecting_after : was_detecting_before,
+ sampler()->HasProposal());
+
+ if (sampler()->HasProposal()) {
+ // Make sure the sampler doesn't flip-flop and keep proposing sampling
+ // based on locking into different regions.
+ if (first_detected_region.IsEmpty()) {
+ first_detected_region = sampler()->detected_region();
+ ASSERT_FALSE(first_detected_region.IsEmpty());
+ } else {
+ EXPECT_EQ(first_detected_region, sampler()->detected_region());
+ }
+
+ if (simulate_pipeline_back_pressure && GetRandomInRange(0, 2) == 0)
+ ClientCannotSampleFrame(*i);
+ else
+ ClientDoesWhatSamplerProposes(*i);
+ } else {
+ EXPECT_FALSE(sampler()->ShouldSample());
+ if (!simulate_pipeline_back_pressure || GetRandomInRange(0, 2) == 1)
+ sampler()->RecordSample(i->second);
+ }
+ }
+ EXPECT_EQ(is_detecting_after, sampler()->HasProposal());
+ ExpectFrameDropRatioIsCorrect();
+ }
+
+ void ResetFrameCounters() {
+ count_dropped_frames_ = 0;
+ count_sampled_frames_ = 0;
+ }
+
+ // Keep track what the sampler is proposing, and call RecordSample() if it
+ // proposes sampling |event|.
+ void ClientDoesWhatSamplerProposes(const Event& event) {
+ if (sampler()->ShouldSample()) {
+ EXPECT_EQ(GetContentDamageRect(), event.first);
+ sampler()->RecordSample(sampler()->frame_timestamp());
+ ++count_sampled_frames_;
+ } else if (event.first == GetContentDamageRect()) {
+ ++count_dropped_frames_;
+ }
+ }
+
+ // RecordSample() is not called, but for testing, keep track of what the
+ // sampler is proposing for |event|.
+ void ClientCannotSampleFrame(const Event& event) {
+ if (sampler()->ShouldSample()) {
+ EXPECT_EQ(GetContentDamageRect(), event.first);
+ ++count_sampled_frames_;
+ } else if (event.first == GetContentDamageRect()) {
+ ++count_dropped_frames_;
+ }
+ }
+
+ // Confirm the AnimatedContentSampler is not dropping more frames than
+ // expected, given current test parameters.
+ void ExpectFrameDropRatioIsCorrect() {
+ if (count_sampled_frames_ == 0) {
+ EXPECT_EQ(0, count_dropped_frames_);
+ return;
+ }
+ const double content_framerate =
+ 1000000.0 / GetParam().content_period.InMicroseconds();
+ const double capture_framerate =
+ 1000000.0 / GetParam().min_capture_period.InMicroseconds();
+ const double expected_drop_rate = std::max(
+ 0.0, (content_framerate - capture_framerate) / capture_framerate);
+ const double actual_drop_rate =
+ static_cast<double>(count_dropped_frames_) / count_sampled_frames_;
+ EXPECT_NEAR(expected_drop_rate, actual_drop_rate, 0.015);
+ }
+
+ private:
+ // These counters only include the frames with the desired content.
+ int count_dropped_frames_;
+ int count_sampled_frames_;
+};
+
+// Tests that the implementation locks in/out of frames containing stable
+// animated content, whether or not random events are also simultaneously
+// present.
+TEST_P(AnimatedContentSamplerParameterizedTest, DetectsAnimatedContent) {
+ // |begin| refers to the start of an event sequence in terms of the
+ // Compositor's clock.
+ base::TimeTicks begin = InitialTestTimeTicks();
+
+ // Provide random events and expect no lock-in.
+ base::TimeTicks end = begin + base::TimeDelta::FromSeconds(5);
+ RunEventSequence(GenerateEventSequence(begin, end, false, true),
+ false,
+ false,
+ false);
+ begin = end;
+
+ // Provide content frame events with some random events mixed-in, and expect
+ // the sampler to lock-in.
+ end = begin + base::TimeDelta::FromSeconds(5);
+ RunEventSequence(GenerateEventSequence(begin, end, true, true),
+ false,
+ true,
+ false);
+ begin = end;
+
+ // Continue providing content frame events without the random events mixed-in
+ // and expect the lock-in to hold.
+ end = begin + base::TimeDelta::FromSeconds(5);
+ RunEventSequence(GenerateEventSequence(begin, end, true, false),
+ true,
+ true,
+ false);
+ begin = end;
+
+ // Continue providing just content frame events and expect the lock-in to
+ // hold. Also simulate the capture pipeline experiencing back pressure.
+ end = begin + base::TimeDelta::FromSeconds(20);
+ RunEventSequence(GenerateEventSequence(begin, end, true, false),
+ true,
+ true,
+ true);
+ begin = end;
+
+ // Provide a half-second of random events only, and expect the lock-in to be
+ // broken.
+ end = begin + base::TimeDelta::FromMilliseconds(500);
+ RunEventSequence(GenerateEventSequence(begin, end, false, true),
+ true,
+ false,
+ false);
+ begin = end;
+
+ // Now, go back to providing content frame events, and expect the sampler to
+ // lock-in once again.
+ end = begin + base::TimeDelta::FromSeconds(5);
+ RunEventSequence(GenerateEventSequence(begin, end, true, false),
+ false,
+ true,
+ false);
+ begin = end;
+}
+
+// Tests that AnimatedContentSampler won't lock in to, nor flip-flop between,
+// two animations of the same pixel change rate. VideoCaptureOracle should
+// revert to using the SmoothEventSampler for these kinds of situations, as
+// there is no "right answer" as to which animation to lock into.
+TEST_P(AnimatedContentSamplerParameterizedTest,
+ DoesNotLockInToTwoCompetingAnimations) {
+ // Don't test when the event stream cannot indicate two separate content
+ // animations under the current test parameters.
+ if (GetParam().content_period < 2 * GetParam().vsync_interval)
+ return;
+
+ // Start the first animation and run for a bit, and expect the sampler to
+ // lock-in.
+ base::TimeTicks begin = InitialTestTimeTicks();
+ base::TimeTicks end = begin + base::TimeDelta::FromSeconds(5);
+ RunEventSequence(GenerateEventSequence(begin, end, true, false),
+ false,
+ true,
+ false);
+ begin = end;
+
+ // Now, keep the first animation and blend in an second animation of the same
+ // size and frame rate, but at a different position. This will should cause
+ // the sampler to enter an "undetected" state since it's unclear which
+ // animation should be locked into.
+ end = begin + base::TimeDelta::FromSeconds(20);
+ std::vector<Event> first_animation_events =
+ GenerateEventSequence(begin, end, true, false);
+ gfx::Rect second_animation_rect(
+ gfx::Point(0, GetContentDamageRect().height()),
+ GetContentDamageRect().size());
+ std::vector<Event> both_animations_events;
+ base::TimeDelta second_animation_offset = GetParam().vsync_interval;
+ for (std::vector<Event>::const_iterator i = first_animation_events.begin();
+ i != first_animation_events.end(); ++i) {
+ both_animations_events.push_back(*i);
+ both_animations_events.push_back(
+ Event(second_animation_rect, i->second + second_animation_offset));
+ }
+ RunEventSequence(both_animations_events, true, false, false);
+ begin = end;
+
+ // Now, run just the first animation, and expect the sampler to lock-in once
+ // again.
+ end = begin + base::TimeDelta::FromSeconds(5);
+ RunEventSequence(GenerateEventSequence(begin, end, true, false),
+ false,
+ true,
+ false);
+ begin = end;
+
+ // Now, blend in the second animation again, but it has half the frame rate of
+ // the first animation and damage Rects with twice the area. This will should
+ // cause the sampler to enter an "undetected" state again. This tests that
+ // pixel-weighting is being accounted for in the sampler's logic.
+ end = begin + base::TimeDelta::FromSeconds(20);
+ first_animation_events = GenerateEventSequence(begin, end, true, false);
+ second_animation_rect.set_width(second_animation_rect.width() * 2);
+ both_animations_events.clear();
+ bool include_second_animation_frame = true;
+ for (std::vector<Event>::const_iterator i = first_animation_events.begin();
+ i != first_animation_events.end(); ++i) {
+ both_animations_events.push_back(*i);
+ if (include_second_animation_frame) {
+ both_animations_events.push_back(
+ Event(second_animation_rect, i->second + second_animation_offset));
+ }
+ include_second_animation_frame = !include_second_animation_frame;
+ }
+ RunEventSequence(both_animations_events, true, false, false);
+ begin = end;
+}
+
+// Tests that the frame timestamps are smooth; meaning, that when run through a
+// simulated compositor, each frame is held displayed for the right number of
+// v-sync intervals.
+TEST_P(AnimatedContentSamplerParameterizedTest, FrameTimestampsAreSmooth) {
+ // Generate 30 seconds of animated content events, run the events through
+ // AnimatedContentSampler, and record all frame timestamps being proposed
+ // once lock-in is continuous.
+ base::TimeTicks begin = InitialTestTimeTicks();
+ std::vector<Event> events = GenerateEventSequence(
+ begin,
+ begin + base::TimeDelta::FromSeconds(20),
+ true,
+ false);
+ typedef std::vector<base::TimeTicks> Timestamps;
+ Timestamps frame_timestamps;
+ for (std::vector<Event>::const_iterator i = events.begin(); i != events.end();
+ ++i) {
+ sampler()->ConsiderPresentationEvent(i->first, i->second);
+ if (sampler()->HasProposal()) {
+ if (sampler()->ShouldSample()) {
+ frame_timestamps.push_back(sampler()->frame_timestamp());
+ sampler()->RecordSample(sampler()->frame_timestamp());
+ }
+ } else {
+ frame_timestamps.clear(); // Reset until continuous lock-in.
+ }
+ }
+ ASSERT_LE(2u, frame_timestamps.size());
+
+ // Iterate through the |frame_timestamps|, building a histogram counting the
+ // number of times each frame was displayed k times. For example, 10 frames
+ // of 30 Hz content on a 60 Hz v-sync interval should result in
+ // display_counts[2] == 10. Quit early if any one frame was obviously
+ // repeated too many times.
+ const int64 max_expected_repeats_per_frame = 1 +
+ std::max(GetParam().min_capture_period, GetParam().content_period) /
+ GetParam().vsync_interval;
+ std::vector<size_t> display_counts(max_expected_repeats_per_frame + 1, 0);
+ base::TimeTicks last_present_time = frame_timestamps.front();
+ for (Timestamps::const_iterator i = frame_timestamps.begin() + 1;
+ i != frame_timestamps.end(); ++i) {
+ const size_t num_vsync_intervals = static_cast<size_t>(
+ (*i - last_present_time) / GetParam().vsync_interval);
+ ASSERT_LT(0u, num_vsync_intervals);
+ ASSERT_GT(display_counts.size(), num_vsync_intervals); // Quit early.
+ ++display_counts[num_vsync_intervals];
+ last_present_time += num_vsync_intervals * GetParam().vsync_interval;
+ }
+
+ // Analyze the histogram for an expected result pattern. If the frame
+ // timestamps are smooth, there should only be one or two buckets with
+ // non-zero counts and they should be next to each other. Because the clock
+ // precision for the event_times provided to the sampler is very granular
+ // (i.e., the vsync_interval), it's okay if other buckets have a tiny "stray"
+ // count in this test.
+ size_t highest_count = 0;
+ size_t second_highest_count = 0;
+ for (size_t repeats = 1; repeats < display_counts.size(); ++repeats) {
+ DVLOG(1) << "display_counts[" << repeats << "] is "
+ << display_counts[repeats];
+ if (display_counts[repeats] >= highest_count) {
+ second_highest_count = highest_count;
+ highest_count = display_counts[repeats];
+ } else if (display_counts[repeats] > second_highest_count) {
+ second_highest_count = display_counts[repeats];
+ }
+ }
+ size_t stray_count_remaining =
+ (frame_timestamps.size() - 1) - (highest_count + second_highest_count);
+ // Expect no more than 0.75% of frames fall outside the two main buckets.
+ EXPECT_GT(frame_timestamps.size() * 75 / 10000, stray_count_remaining);
+ for (size_t repeats = 1; repeats < display_counts.size() - 1; ++repeats) {
+ if (display_counts[repeats] == highest_count) {
+ EXPECT_EQ(second_highest_count, display_counts[repeats + 1]);
+ ++repeats;
+ } else if (display_counts[repeats] == second_highest_count) {
+ EXPECT_EQ(highest_count, display_counts[repeats + 1]);
+ ++repeats;
+ } else {
+ EXPECT_GE(stray_count_remaining, display_counts[repeats]);
+ stray_count_remaining -= display_counts[repeats];
+ }
+ }
+}
+
+// Tests that frame timestamps are "lightly pushed" back towards the original
+// presentation event times, which tells us the AnimatedContentSampler can
+// account for sources of timestamp drift and correct the drift.
+TEST_P(AnimatedContentSamplerParameterizedTest,
+ FrameTimestampsConvergeTowardsEventTimes) {
+ const int max_drift_increment_millis = 3;
+
+ // Generate a full minute of events.
+ const base::TimeTicks begin = InitialTestTimeTicks();
+ const base::TimeTicks end = begin + base::TimeDelta::FromMinutes(1);
+ std::vector<Event> events = GenerateEventSequence(begin, end, true, false);
+
+ // Modify the event sequence so that 1-3 ms of additional drift is suddenly
+ // present every 100 events. This is meant to simulate that, external to
+ // AnimatedContentSampler, the video hardware vsync timebase is being
+ // refreshed and is showing severe drift from the system clock.
+ base::TimeDelta accumulated_drift;
+ for (size_t i = 1; i < events.size(); ++i) {
+ if (i % 100 == 0) {
+ accumulated_drift += base::TimeDelta::FromMilliseconds(
+ GetRandomInRange(1, max_drift_increment_millis + 1));
+ }
+ events[i].second += accumulated_drift;
+ }
+
+ // Run all the events through the sampler and track the last rewritten frame
+ // timestamp.
+ base::TimeTicks last_frame_timestamp;
+ for (std::vector<Event>::const_iterator i = events.begin(); i != events.end();
+ ++i) {
+ sampler()->ConsiderPresentationEvent(i->first, i->second);
+ if (sampler()->ShouldSample())
+ last_frame_timestamp = sampler()->frame_timestamp();
+ }
+
+ // If drift was accounted for, the |last_frame_timestamp| should be close to
+ // the last event's timestamp.
+ const base::TimeDelta total_error =
+ events.back().second - last_frame_timestamp;
+ const base::TimeDelta max_acceptable_error = GetParam().min_capture_period +
+ base::TimeDelta::FromMilliseconds(max_drift_increment_millis);
+ EXPECT_NEAR(0.0,
+ total_error.InMicroseconds(),
+ max_acceptable_error.InMicroseconds());
+}
+
+INSTANTIATE_TEST_CASE_P(
+ ,
+ AnimatedContentSamplerParameterizedTest,
+ ::testing::Values(
+ // Typical frame rate content: Compositor runs at 60 Hz, capture at 30
+ // Hz, and content video animates at 30, 25, or 24 Hz.
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(30)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(25)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(24)),
+
+ // High frame rate content that leverages the Compositor's
+ // capabilities, but capture is still at 30 Hz.
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(60)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(50)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(48)),
+
+ // High frame rate content that leverages the Compositor's
+ // capabilities, and capture is also a buttery 60 Hz.
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(60), FpsAsPeriod(60)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(60), FpsAsPeriod(50)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(60), FpsAsPeriod(48)),
+
+ // On some platforms, the Compositor runs at 50 Hz.
+ Scenario(FpsAsPeriod(50), FpsAsPeriod(30), FpsAsPeriod(30)),
+ Scenario(FpsAsPeriod(50), FpsAsPeriod(30), FpsAsPeriod(25)),
+ Scenario(FpsAsPeriod(50), FpsAsPeriod(30), FpsAsPeriod(24)),
+ Scenario(FpsAsPeriod(50), FpsAsPeriod(30), FpsAsPeriod(50)),
+ Scenario(FpsAsPeriod(50), FpsAsPeriod(30), FpsAsPeriod(48)),
+
+ // Stable, but non-standard content frame rates.
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(16)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(20)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(23)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(26)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(27)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(28)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(29)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(31)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(32)),
+ Scenario(FpsAsPeriod(60), FpsAsPeriod(30), FpsAsPeriod(33))));
+
+// Tests that VideoCaptureOracle filters out events whose timestamps are
+// decreasing.
+TEST(VideoCaptureOracleTest, EnforcesEventTimeMonotonicity) {
+ const base::TimeDelta min_capture_period =
+ base::TimeDelta::FromSeconds(1) / 30;
+ const gfx::Rect damage_rect(0, 0, 1280, 720);
+ const base::TimeDelta event_increment = min_capture_period * 2;
+
+ VideoCaptureOracle oracle(min_capture_period, true);
+
+ base::TimeTicks t = InitialTestTimeTicks();
+ for (int i = 0; i < 10; ++i) {
+ t += event_increment;
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ damage_rect, t));
+ }
+
+ base::TimeTicks furthest_event_time = t;
+ for (int i = 0; i < 10; ++i) {
+ t -= event_increment;
+ ASSERT_FALSE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ damage_rect, t));
+ }
+
+ t = furthest_event_time;
+ for (int i = 0; i < 10; ++i) {
+ t += event_increment;
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ damage_rect, t));
+ }
+}
+
+// Tests that VideoCaptureOracle is enforcing the requirement that captured
+// frames are delivered in order. Otherwise, downstream consumers could be
+// tripped-up by out-of-order frames or frame timestamps.
+TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
+ const base::TimeDelta min_capture_period =
+ base::TimeDelta::FromSeconds(1) / 30;
+ const gfx::Rect damage_rect(0, 0, 1280, 720);
+ const base::TimeDelta event_increment = min_capture_period * 2;
+
+ VideoCaptureOracle oracle(min_capture_period, true);
+
+ // Most basic scenario: Frames delivered one at a time, with no additional
+ // captures in-between deliveries.
+ base::TimeTicks t = InitialTestTimeTicks();
+ int last_frame_number;
+ base::TimeTicks ignored;
+ for (int i = 0; i < 10; ++i) {
+ t += event_increment;
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ damage_rect, t));
+ last_frame_number = oracle.RecordCapture();
+ ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, &ignored));
+ }
+
+ // Basic pipelined scenario: More than one frame in-flight at delivery points.
+ for (int i = 0; i < 50; ++i) {
+ const int num_in_flight = 1 + i % 3;
+ for (int j = 0; j < num_in_flight; ++j) {
+ t += event_increment;
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ damage_rect, t));
+ last_frame_number = oracle.RecordCapture();
+ }
+ for (int j = num_in_flight - 1; j >= 0; --j) {
+ ASSERT_TRUE(oracle.CompleteCapture(last_frame_number - j, &ignored));
+ }
+ }
+
+ // Pipelined scenario with out-of-order delivery attempts rejected.
+ for (int i = 0; i < 50; ++i) {
+ const int num_in_flight = 1 + i % 3;
+ for (int j = 0; j < num_in_flight; ++j) {
+ t += event_increment;
+ ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ damage_rect, t));
+ last_frame_number = oracle.RecordCapture();
+ }
+ ASSERT_TRUE(oracle.CompleteCapture(last_frame_number, &ignored));
+ for (int j = 1; j < num_in_flight; ++j) {
+ ASSERT_FALSE(oracle.CompleteCapture(last_frame_number - j, &ignored));
+ }
+ }
+}
+
+// Tests that VideoCaptureOracle transitions between using its two samplers in a
+// way that does not introduce severe jank, pauses, etc.
+TEST(VideoCaptureOracleTest, TransitionsSmoothlyBetweenSamplers) {
+ const base::TimeDelta min_capture_period =
+ base::TimeDelta::FromSeconds(1) / 30;
+ const gfx::Rect animation_damage_rect(0, 0, 1280, 720);
+ const base::TimeDelta event_increment = min_capture_period * 2;
+
+ VideoCaptureOracle oracle(min_capture_period, true);
+
+ // Run sequences of animation events and non-animation events through the
+ // oracle. As the oracle transitions between each sampler, make sure the
+ // frame timestamps won't trip-up downstream consumers.
+ base::TimeTicks t = InitialTestTimeTicks();
+ base::TimeTicks last_frame_timestamp;
+ for (int i = 0; i < 1000; ++i) {
+ t += event_increment;
+
+ // For every 100 events, provide 50 that will cause the
+ // AnimatedContentSampler to lock-in, followed by 50 that will cause it to
+ // lock-out (i.e., the oracle will use the SmoothEventSampler instead).
+ const bool provide_animated_content_event =
+ (i % 100) >= 25 && (i % 100) < 75;
+
+ // Only the few events that trigger the lock-out transition should be
+ // dropped, because the AnimatedContentSampler doesn't yet realize the
+ // animation ended. Otherwise, the oracle should always decide to sample
+ // because one of its samplers says to.
+ const bool require_oracle_says_sample = (i % 100) < 75 || (i % 100) >= 78;
+ const bool oracle_says_sample = oracle.ObserveEventAndDecideCapture(
+ VideoCaptureOracle::kCompositorUpdate,
+ provide_animated_content_event ? animation_damage_rect : gfx::Rect(),
+ t);
+ if (require_oracle_says_sample)
+ ASSERT_TRUE(oracle_says_sample);
+ if (!oracle_says_sample)
+ continue;
+
+ const int frame_number = oracle.RecordCapture();
+
+ base::TimeTicks frame_timestamp;
+ ASSERT_TRUE(oracle.CompleteCapture(frame_number, &frame_timestamp));
+ ASSERT_FALSE(frame_timestamp.is_null());
+ if (!last_frame_timestamp.is_null()) {
+ const base::TimeDelta delta = frame_timestamp - last_frame_timestamp;
+ EXPECT_LE(event_increment.InMicroseconds(), delta.InMicroseconds());
+ // Right after the AnimatedContentSampler lock-out transition, there were
+ // a few frames dropped, so allow a gap in the timestamps. Otherwise, the
+ // delta between frame timestamps should never be more than 2X the
+ // |event_increment|.
+ const base::TimeDelta max_acceptable_delta = (i % 100) == 78 ?
+ event_increment * 5 : event_increment * 2;
+ EXPECT_GE(max_acceptable_delta.InMicroseconds(), delta.InMicroseconds());
+ }
+ last_frame_timestamp = frame_timestamp;
+ }
+}
+
} // namespace content
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 ad5a33f6923..605124dd308 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
@@ -15,8 +15,11 @@
#include "content/browser/media/capture/web_contents_capture_util.h"
#include "content/browser/media/capture/web_contents_tracker.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
#include "media/audio/virtual_audio_input_stream.h"
#include "media/audio/virtual_audio_output_stream.h"
+#include "media/base/bind_to_current_loop.h"
namespace content {
@@ -25,7 +28,7 @@ class WebContentsAudioInputStream::Impl
public AudioMirroringManager::MirroringDestination {
public:
// Takes ownership of |mixer_stream|. The rest outlive this instance.
- Impl(int render_process_id, int render_view_id,
+ Impl(int render_process_id, int main_render_frame_id,
AudioMirroringManager* mirroring_manager,
const scoped_refptr<WebContentsTracker>& tracker,
media::VirtualAudioInputStream* mixer_stream);
@@ -52,6 +55,8 @@ class WebContentsAudioInputStream::Impl
private:
friend class base::RefCountedThreadSafe<WebContentsAudioInputStream::Impl>;
+ typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
+
enum State {
CONSTRUCTED,
OPENED,
@@ -59,31 +64,38 @@ class WebContentsAudioInputStream::Impl
CLOSED
};
- virtual ~Impl();
-
- // Returns true if the mirroring target has been permanently lost.
- bool IsTargetLost() const;
+ ~Impl() override;
// Notifies the consumer callback that the stream is now dead.
void ReportError();
- // Start/Stop mirroring by posting a call to AudioMirroringManager on the IO
- // BrowserThread.
+ // (Re-)Start/Stop mirroring by posting a call to AudioMirroringManager on the
+ // IO BrowserThread.
void StartMirroring();
void StopMirroring();
+ // Invoked on the UI thread to make sure WebContents muting is turned off for
+ // successful audio capture.
+ void UnmuteWebContentsAudio();
+
// AudioMirroringManager::MirroringDestination implementation
- virtual media::AudioOutputStream* AddInput(
- const media::AudioParameters& params) OVERRIDE;
+ void QueryForMatches(const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback) override;
+ void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback);
+ media::AudioOutputStream* AddInput(
+ const media::AudioParameters& params) override;
// Callback which is run when |stream| is closed. Deletes |stream|.
void ReleaseInput(media::VirtualAudioOutputStream* stream);
// Called by WebContentsTracker when the target of the audio mirroring has
// changed.
- void OnTargetChanged(int render_process_id, int render_view_id);
+ void OnTargetChanged(RenderWidgetHost* target);
// Injected dependencies.
+ const int initial_render_process_id_;
+ const int initial_main_render_frame_id_;
AudioMirroringManager* const mirroring_manager_;
const scoped_refptr<WebContentsTracker> tracker_;
// The AudioInputStream implementation that handles the audio conversion and
@@ -92,9 +104,9 @@ class WebContentsAudioInputStream::Impl
State state_;
- // Current audio mirroring target.
- int target_render_process_id_;
- int target_render_view_id_;
+ // Set to true if |tracker_| reports a NULL target, which indicates the target
+ // is permanently lost.
+ bool is_target_lost_;
// Current callback used to consume the resulting mixed audio data.
AudioInputCallback* callback_;
@@ -105,14 +117,17 @@ class WebContentsAudioInputStream::Impl
};
WebContentsAudioInputStream::Impl::Impl(
- int render_process_id, int render_view_id,
+ int render_process_id, int main_render_frame_id,
AudioMirroringManager* mirroring_manager,
const scoped_refptr<WebContentsTracker>& tracker,
media::VirtualAudioInputStream* mixer_stream)
- : mirroring_manager_(mirroring_manager),
- tracker_(tracker), mixer_stream_(mixer_stream), state_(CONSTRUCTED),
- target_render_process_id_(render_process_id),
- target_render_view_id_(render_view_id),
+ : initial_render_process_id_(render_process_id),
+ initial_main_render_frame_id_(main_render_frame_id),
+ mirroring_manager_(mirroring_manager),
+ tracker_(tracker),
+ mixer_stream_(mixer_stream),
+ state_(CONSTRUCTED),
+ is_target_lost_(false),
callback_(NULL) {
DCHECK(mirroring_manager_);
DCHECK(tracker_.get());
@@ -138,7 +153,7 @@ bool WebContentsAudioInputStream::Impl::Open() {
state_ = OPENED;
tracker_->Start(
- target_render_process_id_, target_render_view_id_,
+ initial_render_process_id_, initial_main_render_frame_id_,
base::Bind(&Impl::OnTargetChanged, this));
return true;
@@ -152,7 +167,7 @@ void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) {
return;
callback_ = callback;
- if (IsTargetLost()) {
+ if (is_target_lost_) {
ReportError();
callback_ = NULL;
return;
@@ -162,6 +177,14 @@ void WebContentsAudioInputStream::Impl::Start(AudioInputCallback* callback) {
mixer_stream_->Start(callback);
StartMirroring();
+
+ // WebContents audio muting is implemented as audio capture to nowhere.
+ // Unmuting will stop that audio capture, allowing AudioMirroringManager to
+ // divert audio capture to here.
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&Impl::UnmuteWebContentsAudio, this));
}
void WebContentsAudioInputStream::Impl::Stop() {
@@ -175,8 +198,7 @@ void WebContentsAudioInputStream::Impl::Stop() {
mixer_stream_->Stop();
callback_ = NULL;
- if (!IsTargetLost())
- StopMirroring();
+ StopMirroring();
}
void WebContentsAudioInputStream::Impl::Close() {
@@ -194,12 +216,6 @@ void WebContentsAudioInputStream::Impl::Close() {
state_ = CLOSED;
}
-bool WebContentsAudioInputStream::Impl::IsTargetLost() const {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- return target_render_process_id_ <= 0 || target_render_view_id_ <= 0;
-}
-
void WebContentsAudioInputStream::Impl::ReportError() {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -216,7 +232,6 @@ void WebContentsAudioInputStream::Impl::StartMirroring() {
FROM_HERE,
base::Bind(&AudioMirroringManager::StartMirroring,
base::Unretained(mirroring_manager_),
- target_render_process_id_, target_render_view_id_,
make_scoped_refptr(this)));
}
@@ -228,10 +243,52 @@ void WebContentsAudioInputStream::Impl::StopMirroring() {
FROM_HERE,
base::Bind(&AudioMirroringManager::StopMirroring,
base::Unretained(mirroring_manager_),
- target_render_process_id_, target_render_view_id_,
make_scoped_refptr(this)));
}
+void WebContentsAudioInputStream::Impl::UnmuteWebContentsAudio() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ WebContents* const contents = tracker_->web_contents();
+ if (contents)
+ contents->SetAudioMuted(false);
+}
+
+void WebContentsAudioInputStream::Impl::QueryForMatches(
+ const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&Impl::QueryForMatchesOnUIThread,
+ this,
+ candidates,
+ media::BindToCurrentLoop(results_callback)));
+}
+
+void WebContentsAudioInputStream::Impl::QueryForMatchesOnUIThread(
+ const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ std::set<SourceFrameRef> matches;
+ WebContents* const contents = tracker_->web_contents();
+ if (contents) {
+ // Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
+ // currently-tracked WebContents.
+ for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
+ i != candidates.end(); ++i) {
+ WebContents* const contents_containing_frame =
+ WebContents::FromRenderFrameHost(
+ RenderFrameHost::FromID(i->first, i->second));
+ if (contents_containing_frame == contents)
+ matches.insert(*i);
+ }
+ }
+
+ results_callback.Run(matches);
+}
+
media::AudioOutputStream* WebContentsAudioInputStream::Impl::AddInput(
const media::AudioParameters& params) {
// Note: The closure created here holds a reference to "this," which will
@@ -248,27 +305,14 @@ void WebContentsAudioInputStream::Impl::ReleaseInput(
delete stream;
}
-void WebContentsAudioInputStream::Impl::OnTargetChanged(int render_process_id,
- int render_view_id) {
+void WebContentsAudioInputStream::Impl::OnTargetChanged(
+ RenderWidgetHost* target) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (target_render_process_id_ == render_process_id &&
- target_render_view_id_ == render_view_id) {
- return;
- }
-
- DVLOG(1) << "Target RenderView has changed from "
- << target_render_process_id_ << ':' << target_render_view_id_
- << " to " << render_process_id << ':' << render_view_id;
-
- if (state_ == MIRRORING)
- StopMirroring();
-
- target_render_process_id_ = render_process_id;
- target_render_view_id_ = render_view_id;
+ is_target_lost_ = !target;
if (state_ == MIRRORING) {
- if (IsTargetLost()) {
+ if (is_target_lost_) {
ReportError();
Stop();
} else {
@@ -284,27 +328,27 @@ WebContentsAudioInputStream* WebContentsAudioInputStream::Create(
const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
AudioMirroringManager* audio_mirroring_manager) {
int render_process_id;
- int render_view_id;
+ int main_render_frame_id;
if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(
- device_id, &render_process_id, &render_view_id)) {
+ device_id, &render_process_id, &main_render_frame_id)) {
return NULL;
}
return new WebContentsAudioInputStream(
- render_process_id, render_view_id,
+ render_process_id, main_render_frame_id,
audio_mirroring_manager,
- new WebContentsTracker(),
+ new WebContentsTracker(false),
new media::VirtualAudioInputStream(
params, worker_task_runner,
media::VirtualAudioInputStream::AfterCloseCallback()));
}
WebContentsAudioInputStream::WebContentsAudioInputStream(
- int render_process_id, int render_view_id,
+ int render_process_id, int main_render_frame_id,
AudioMirroringManager* mirroring_manager,
const scoped_refptr<WebContentsTracker>& tracker,
media::VirtualAudioInputStream* mixer_stream)
- : impl_(new Impl(render_process_id, render_view_id,
+ : impl_(new Impl(render_process_id, main_render_frame_id,
mirroring_manager, tracker, mixer_stream)) {}
WebContentsAudioInputStream::~WebContentsAudioInputStream() {}
@@ -346,4 +390,8 @@ bool WebContentsAudioInputStream::GetAutomaticGainControl() {
return impl_->mixer_stream()->GetAutomaticGainControl();
}
+bool WebContentsAudioInputStream::IsMuted() {
+ return false;
+}
+
} // namespace content
diff --git a/chromium/content/browser/media/capture/web_contents_audio_input_stream.h b/chromium/content/browser/media/capture/web_contents_audio_input_stream.h
index c0a2c6afd7f..d66d27004b5 100644
--- a/chromium/content/browser/media/capture/web_contents_audio_input_stream.h
+++ b/chromium/content/browser/media/capture/web_contents_audio_input_stream.h
@@ -3,15 +3,12 @@
// found in the LICENSE file.
//
// An AudioInputStream which provides a loop-back of all audio output generated
-// by the RenderView associated with a WebContents instance. The single stream
-// of data is produced by format-converting and mixing all audio output from a
-// RenderView. In other words, WebContentsAudioInputStream provides tab-level
+// by the entire RenderFrame tree associated with a WebContents instance. The
+// single stream of data is produced by format-converting and mixing all audio
+// output streams. As the RenderFrameHost tree mutates (e.g., due to page
+// navigations, or crashes/reloads), the stream will continue without
+// interruption. In other words, WebContentsAudioInputStream provides tab-level
// audio mirroring.
-//
-// The implementation observes a WebContents instance (which represents a
-// browser tab) so that it can track the replacement of RenderViews due to
-// navigation, crash/reload, etc. events; and take appropriate actions to
-// provide a seamless, uninterrupted mirroring experience.
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_AUDIO_INPUT_STREAM_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_AUDIO_INPUT_STREAM_H_
@@ -40,15 +37,16 @@ class CONTENT_EXPORT WebContentsAudioInputStream
: NON_EXPORTED_BASE(public media::AudioInputStream) {
public:
// media::AudioInputStream implementation
- virtual bool Open() OVERRIDE;
- virtual void Start(AudioInputCallback* callback) OVERRIDE;
- virtual void Stop() OVERRIDE;
- virtual void Close() OVERRIDE;
- virtual double GetMaxVolume() OVERRIDE;
- virtual void SetVolume(double volume) OVERRIDE;
- virtual double GetVolume() OVERRIDE;
- virtual void SetAutomaticGainControl(bool enabled) OVERRIDE;
- virtual bool GetAutomaticGainControl() OVERRIDE;
+ bool Open() override;
+ void Start(AudioInputCallback* callback) override;
+ void Stop() override;
+ void Close() override;
+ double GetMaxVolume() override;
+ void SetVolume(double volume) override;
+ double GetVolume() override;
+ void SetAutomaticGainControl(bool enabled) override;
+ bool GetAutomaticGainControl() override;
+ bool IsMuted() override;
// Create a new audio mirroring session, or return NULL on error. |device_id|
// should be in the format accepted by
@@ -75,12 +73,12 @@ class CONTENT_EXPORT WebContentsAudioInputStream
class Impl;
WebContentsAudioInputStream(
- int render_process_id, int render_view_id,
+ int render_process_id, int main_render_frame_id,
AudioMirroringManager* mirroring_manager,
const scoped_refptr<WebContentsTracker>& tracker,
media::VirtualAudioInputStream* mixer_stream);
- virtual ~WebContentsAudioInputStream();
+ ~WebContentsAudioInputStream() override;
scoped_refptr<Impl> impl_;
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 72f6109029d..9772c9457ce 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
@@ -11,9 +11,10 @@
#include "base/message_loop/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
-#include "content/browser/browser_thread_impl.h"
#include "content/browser/media/capture/audio_mirroring_manager.h"
#include "content/browser/media/capture/web_contents_tracker.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "media/audio/simple_sources.h"
#include "media/audio/virtual_audio_input_stream.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -40,9 +41,9 @@ namespace content {
namespace {
const int kRenderProcessId = 123;
-const int kRenderViewId = 456;
+const int kRenderFrameId = 456;
const int kAnotherRenderProcessId = 789;
-const int kAnotherRenderViewId = 1;
+const int kAnotherRenderFrameId = 1;
const AudioParameters& TestAudioParameters() {
static const AudioParameters params(
@@ -58,12 +59,8 @@ class MockAudioMirroringManager : public AudioMirroringManager {
MockAudioMirroringManager() : AudioMirroringManager() {}
virtual ~MockAudioMirroringManager() {}
- MOCK_METHOD3(StartMirroring,
- void(int render_process_id, int render_view_id,
- MirroringDestination* destination));
- MOCK_METHOD3(StopMirroring,
- void(int render_process_id, int render_view_id,
- MirroringDestination* destination));
+ MOCK_METHOD1(StartMirroring, void(MirroringDestination* destination));
+ MOCK_METHOD1(StopMirroring, void(MirroringDestination* destination));
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager);
@@ -71,10 +68,10 @@ class MockAudioMirroringManager : public AudioMirroringManager {
class MockWebContentsTracker : public WebContentsTracker {
public:
- MockWebContentsTracker() : WebContentsTracker() {}
+ MockWebContentsTracker() : WebContentsTracker(false) {}
MOCK_METHOD3(Start,
- void(int render_process_id, int render_view_id,
+ void(int render_process_id, int render_frame_id,
const ChangeCallback& callback));
MOCK_METHOD0(Stop, void());
@@ -177,23 +174,23 @@ class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
class WebContentsAudioInputStreamTest : public testing::Test {
public:
WebContentsAudioInputStreamTest()
- : audio_thread_("Audio thread"),
- io_thread_(BrowserThread::IO),
+ : thread_bundle_(new TestBrowserThreadBundle(
+ TestBrowserThreadBundle::REAL_IO_THREAD)),
+ audio_thread_("Audio thread"),
mock_mirroring_manager_(new MockAudioMirroringManager()),
mock_tracker_(new MockWebContentsTracker()),
mock_vais_(NULL),
wcais_(NULL),
destination_(NULL),
current_render_process_id_(kRenderProcessId),
- current_render_view_id_(kRenderViewId),
+ current_render_frame_id_(kRenderFrameId),
on_data_event_(false, false) {
audio_thread_.Start();
- io_thread_.Start();
}
- virtual ~WebContentsAudioInputStreamTest() {
+ ~WebContentsAudioInputStreamTest() override {
audio_thread_.Stop();
- io_thread_.Stop();
+ thread_bundle_.reset();
DCHECK(!mock_vais_);
DCHECK(!wcais_);
@@ -209,16 +206,19 @@ class WebContentsAudioInputStreamTest : public testing::Test {
EXPECT_CALL(*mock_vais_, Close()); // At Close() time.
ASSERT_EQ(kRenderProcessId, current_render_process_id_);
- ASSERT_EQ(kRenderViewId, current_render_view_id_);
- EXPECT_CALL(*mock_tracker_.get(), Start(kRenderProcessId, kRenderViewId, _))
+ ASSERT_EQ(kRenderFrameId, current_render_frame_id_);
+ EXPECT_CALL(*mock_tracker_.get(),
+ Start(kRenderProcessId, kRenderFrameId, _))
.WillOnce(DoAll(
SaveArg<2>(&change_callback_),
- WithArgs<0, 1>(Invoke(&change_callback_,
- &WebContentsTracker::ChangeCallback::Run))));
+ WithArgs<0, 1>(Invoke(this,
+ &WebContentsAudioInputStreamTest::
+ SimulateChangeCallback))));
+
EXPECT_CALL(*mock_tracker_.get(), Stop()); // At Close() time.
wcais_ = new WebContentsAudioInputStream(
- current_render_process_id_, current_render_view_id_,
+ current_render_process_id_, current_render_frame_id_,
mock_mirroring_manager_.get(),
mock_tracker_, mock_vais_);
wcais_->Open();
@@ -228,13 +228,11 @@ class WebContentsAudioInputStreamTest : public testing::Test {
EXPECT_CALL(*mock_vais_, Start(&mock_input_callback_));
EXPECT_CALL(*mock_vais_, Stop()); // At Stop() time.
- EXPECT_CALL(*mock_mirroring_manager_,
- StartMirroring(kRenderProcessId, kRenderViewId, NotNull()))
- .WillOnce(SaveArg<2>(&destination_))
+ EXPECT_CALL(*mock_mirroring_manager_, StartMirroring(NotNull()))
+ .WillOnce(SaveArg<0>(&destination_))
.RetiresOnSaturation();
// At Stop() time, or when the mirroring target changes:
- EXPECT_CALL(*mock_mirroring_manager_,
- StopMirroring(kRenderProcessId, kRenderViewId, NotNull()))
+ EXPECT_CALL(*mock_mirroring_manager_, StopMirroring(NotNull()))
.WillOnce(Assign(
&destination_,
static_cast<AudioMirroringManager::MirroringDestination*>(NULL)))
@@ -308,38 +306,24 @@ class WebContentsAudioInputStreamTest : public testing::Test {
const int next_render_process_id =
current_render_process_id_ == kRenderProcessId ?
kAnotherRenderProcessId : kRenderProcessId;
- const int next_render_view_id =
- current_render_view_id_ == kRenderViewId ?
- kAnotherRenderViewId : kRenderViewId;
-
- EXPECT_CALL(*mock_mirroring_manager_,
- StartMirroring(next_render_process_id, next_render_view_id,
- NotNull()))
- .WillOnce(SaveArg<2>(&destination_))
- .RetiresOnSaturation();
- // At Stop() time, or when the mirroring target changes:
- EXPECT_CALL(*mock_mirroring_manager_,
- StopMirroring(next_render_process_id, next_render_view_id,
- NotNull()))
- .WillOnce(Assign(
- &destination_,
- static_cast<AudioMirroringManager::MirroringDestination*>(NULL)))
+ const int next_render_frame_id =
+ current_render_frame_id_ == kRenderFrameId ?
+ kAnotherRenderFrameId : kRenderFrameId;
+
+ EXPECT_CALL(*mock_mirroring_manager_, StartMirroring(NotNull()))
+ .WillOnce(SaveArg<0>(&destination_))
.RetiresOnSaturation();
- // Simulate OnTargetChange() callback from WebContentsTracker.
- EXPECT_FALSE(change_callback_.is_null());
- change_callback_.Run(next_render_process_id, next_render_view_id);
+ SimulateChangeCallback(next_render_process_id, next_render_frame_id);
current_render_process_id_ = next_render_process_id;
- current_render_view_id_ = next_render_view_id;
+ current_render_frame_id_ = next_render_frame_id;
}
void LoseMirroringTarget() {
EXPECT_CALL(mock_input_callback_, OnError(_));
- // Simulate OnTargetChange() callback from WebContentsTracker.
- EXPECT_FALSE(change_callback_.is_null());
- change_callback_.Run(-1, -1);
+ SimulateChangeCallback(-1, -1);
}
void Stop() {
@@ -369,8 +353,19 @@ class WebContentsAudioInputStreamTest : public testing::Test {
}
private:
+ void SimulateChangeCallback(int render_process_id, int render_frame_id) {
+ ASSERT_FALSE(change_callback_.is_null());
+ if (render_process_id == -1 || render_frame_id == -1) {
+ change_callback_.Run(NULL);
+ } else {
+ // For our tests, any non-NULL value will suffice since it will not be
+ // dereferenced.
+ change_callback_.Run(reinterpret_cast<RenderWidgetHost*>(0xdeadbee5));
+ }
+ }
+
+ scoped_ptr<TestBrowserThreadBundle> thread_bundle_;
base::Thread audio_thread_;
- BrowserThreadImpl io_thread_;
scoped_ptr<MockAudioMirroringManager> mock_mirroring_manager_;
scoped_refptr<MockWebContentsTracker> mock_tracker_;
@@ -391,9 +386,9 @@ class WebContentsAudioInputStreamTest : public testing::Test {
// to simulate: 1) calls to AddInput(); and 2) diverting audio data.
AudioMirroringManager::MirroringDestination* destination_;
- // Current target RenderView. These get flipped in ChangedMirroringTarget().
+ // Current target RenderFrame. These get flipped in ChangedMirroringTarget().
int current_render_process_id_;
- int current_render_view_id_;
+ int current_render_frame_id_;
// Streams provided by calls to WebContentsAudioInputStream::AddInput(). Each
// is started with a simulated source of audio data.
diff --git a/chromium/content/browser/media/capture/web_contents_audio_muter.cc b/chromium/content/browser/media/capture/web_contents_audio_muter.cc
new file mode 100644
index 00000000000..4d321927a4f
--- /dev/null
+++ b/chromium/content/browser/media/capture/web_contents_audio_muter.cc
@@ -0,0 +1,152 @@
+// 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/media/capture/web_contents_audio_muter.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "content/browser/media/capture/audio_mirroring_manager.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "media/audio/audio_io.h"
+#include "media/audio/audio_manager.h"
+#include "media/audio/fake_audio_consumer.h"
+#include "media/base/bind_to_current_loop.h"
+
+namespace content {
+
+namespace {
+
+// An AudioOutputStream that pumps audio data, but does nothing with it.
+// Pumping the audio data is necessary because video playback is synchronized to
+// the audio stream and will freeze otherwise.
+//
+// TODO(miu): media::FakeAudioOutputStream does pretty much the same thing as
+// this class, but requires construction/destruction via media::AudioManagerBase
+// on the audio thread. Once that's fixed, this class will no longer be needed.
+// http://crbug.com/416278
+class AudioDiscarder : public media::AudioOutputStream {
+ public:
+ explicit AudioDiscarder(const media::AudioParameters& params)
+ : consumer_(media::AudioManager::Get()->GetWorkerTaskRunner(), params) {}
+
+ // AudioOutputStream implementation.
+ bool Open() override { return true; }
+ void Start(AudioSourceCallback* callback) override {
+ consumer_.Start(base::Bind(&AudioDiscarder::FetchAudioData, callback));
+ }
+ void Stop() override { consumer_.Stop(); }
+ void SetVolume(double volume) override {}
+ void GetVolume(double* volume) override { *volume = 0; }
+ void Close() override { delete this; }
+
+ private:
+ ~AudioDiscarder() override {}
+
+ static void FetchAudioData(AudioSourceCallback* callback,
+ media::AudioBus* audio_bus) {
+ callback->OnMoreData(audio_bus, 0);
+ }
+
+ // Calls FetchAudioData() at regular intervals and discards the data.
+ media::FakeAudioConsumer consumer_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioDiscarder);
+};
+
+} // namespace
+
+// A simple AudioMirroringManager::MirroringDestination implementation that
+// identifies the audio streams rendered by a WebContents and provides
+// AudioDiscarders to AudioMirroringManager.
+class WebContentsAudioMuter::MuteDestination
+ : public base::RefCountedThreadSafe<MuteDestination>,
+ public AudioMirroringManager::MirroringDestination {
+ public:
+ explicit MuteDestination(WebContents* web_contents)
+ : web_contents_(web_contents) {}
+
+ private:
+ friend class base::RefCountedThreadSafe<MuteDestination>;
+
+ typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
+
+ ~MuteDestination() override {}
+
+ void QueryForMatches(const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback) override {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&MuteDestination::QueryForMatchesOnUIThread,
+ this,
+ candidates,
+ media::BindToCurrentLoop(results_callback)));
+ }
+
+ void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
+ const MatchesCallback& results_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ std::set<SourceFrameRef> matches;
+ // Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
+ // WebContents being muted.
+ for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
+ i != candidates.end(); ++i) {
+ WebContents* const contents_containing_frame =
+ WebContents::FromRenderFrameHost(
+ RenderFrameHost::FromID(i->first, i->second));
+ if (contents_containing_frame == web_contents_)
+ matches.insert(*i);
+ }
+ results_callback.Run(matches);
+ }
+
+ media::AudioOutputStream* AddInput(
+ const media::AudioParameters& params) override {
+ return new AudioDiscarder(params);
+ }
+
+ WebContents* const web_contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(MuteDestination);
+};
+
+WebContentsAudioMuter::WebContentsAudioMuter(WebContents* web_contents)
+ : destination_(new MuteDestination(web_contents)), is_muting_(false) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+WebContentsAudioMuter::~WebContentsAudioMuter() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ StopMuting();
+}
+
+void WebContentsAudioMuter::StartMuting() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (is_muting_)
+ return;
+ is_muting_ = true;
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&AudioMirroringManager::StartMirroring,
+ base::Unretained(AudioMirroringManager::GetInstance()),
+ destination_));
+}
+
+void WebContentsAudioMuter::StopMuting() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!is_muting_)
+ return;
+ is_muting_ = false;
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&AudioMirroringManager::StopMirroring,
+ base::Unretained(AudioMirroringManager::GetInstance()),
+ destination_));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/capture/web_contents_audio_muter.h b/chromium/content/browser/media/capture/web_contents_audio_muter.h
new file mode 100644
index 00000000000..d9c5f2fcbb2
--- /dev/null
+++ b/chromium/content/browser/media/capture/web_contents_audio_muter.h
@@ -0,0 +1,43 @@
+// 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_MEDIA_CAPTURE_WEB_CONTENTS_AUDIO_MUTER_H_
+#define CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_AUDIO_MUTER_H_
+
+#include "base/memory/ref_counted.h"
+
+namespace content {
+
+class WebContents;
+
+// Mutes all audio output from a WebContents. Internally, this is accomplished
+// by providing a MirroringDestination implementation, similar to that found in
+// WebContentsAudioInputStream for audio capture/mirroring. However, the
+// WebContentsAudioMuter::MuteDestination only pumps the audio data and discards
+// it.
+class WebContentsAudioMuter {
+ public:
+ explicit WebContentsAudioMuter(WebContents* web_contents);
+ ~WebContentsAudioMuter();
+
+ bool is_muting() const { return is_muting_; }
+
+ void StartMuting();
+ void StopMuting();
+
+ private:
+ // AudioMirroringManager::MirroringDestination implementation which is
+ // ref-counted so it remains alive as tasks referencing it are posted on both
+ // the UI and IO threads.
+ class MuteDestination;
+ const scoped_refptr<MuteDestination> destination_;
+
+ bool is_muting_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebContentsAudioMuter);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_AUDIO_MUTER_H_
diff --git a/chromium/content/browser/media/capture/web_contents_capture_util.cc b/chromium/content/browser/media/capture/web_contents_capture_util.cc
index 57b636a8960..e1c5d52351f 100644
--- a/chromium/content/browser/media/capture/web_contents_capture_util.cc
+++ b/chromium/content/browser/media/capture/web_contents_capture_util.cc
@@ -9,40 +9,24 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
-namespace {
-
-const char kVirtualDeviceScheme[] = "virtual-media-stream://";
-
-} // namespace
-
namespace content {
-std::string WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
- const std::string& device_id) {
- return kVirtualDeviceScheme + device_id;
-}
-
-std::string WebContentsCaptureUtil::StripWebContentsDeviceScheme(
- const std::string& device_id) {
- return (IsWebContentsDeviceId(device_id) ?
- device_id.substr(arraysize(kVirtualDeviceScheme) - 1) :
- device_id);
-}
-
bool WebContentsCaptureUtil::IsWebContentsDeviceId(
const std::string& device_id) {
- return StartsWithASCII(device_id, kVirtualDeviceScheme, true);
+ int ignored;
+ return ExtractTabCaptureTarget(device_id, &ignored, &ignored);
}
bool WebContentsCaptureUtil::ExtractTabCaptureTarget(
const std::string& device_id_param,
int* render_process_id,
- int* render_view_id) {
- if (!IsWebContentsDeviceId(device_id_param))
+ int* main_render_frame_id) {
+ static const char kDeviceScheme[] = "web-contents-media-stream://";
+ if (!StartsWithASCII(device_id_param, kDeviceScheme, true))
return false;
const std::string device_id = device_id_param.substr(
- arraysize(kVirtualDeviceScheme) - 1);
+ arraysize(kDeviceScheme) - 1);
const size_t sep_pos = device_id.find(':');
if (sep_pos == std::string::npos)
@@ -53,7 +37,7 @@ bool WebContentsCaptureUtil::ExtractTabCaptureTarget(
device_id.length() - sep_pos - 1);
return (base::StringToInt(component1, render_process_id) &&
- base::StringToInt(component2, render_view_id));
+ base::StringToInt(component2, main_render_frame_id));
}
} // namespace content
diff --git a/chromium/content/browser/media/capture/web_contents_capture_util.h b/chromium/content/browser/media/capture/web_contents_capture_util.h
index 5f43f423b8b..60a9113f23d 100644
--- a/chromium/content/browser/media/capture/web_contents_capture_util.h
+++ b/chromium/content/browser/media/capture/web_contents_capture_util.h
@@ -13,21 +13,14 @@ namespace content {
class CONTENT_EXPORT WebContentsCaptureUtil {
public:
- // Returns a new id after appending the device id scheme for virtual streams.
- static std::string AppendWebContentsDeviceScheme(
- const std::string& device_id_param);
-
- static std::string StripWebContentsDeviceScheme(
- const std::string& device_id_param);
-
// Check whether the device id indicates that this is a web contents stream.
static bool IsWebContentsDeviceId(const std::string& device_id);
- // Function to extract the target renderer id's from a tab media stream
+ // Function to extract the target render frame id's from a media stream
// request's device id.
static bool ExtractTabCaptureTarget(const std::string& device_id,
int* render_process_id,
- int* render_view_id);
+ int* main_render_frame_id);
};
} // 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 07653310128..6810ac097aa 100644
--- a/chromium/content/browser/media/capture/web_contents_tracker.cc
+++ b/chromium/content/browser/media/capture/web_contents_tracker.cc
@@ -5,20 +5,24 @@
#include "content/browser/media/capture/web_contents_tracker.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
namespace content {
-WebContentsTracker::WebContentsTracker() {}
+WebContentsTracker::WebContentsTracker(bool track_fullscreen_rwh)
+ : track_fullscreen_rwh_(track_fullscreen_rwh),
+ last_target_(NULL) {}
WebContentsTracker::~WebContentsTracker() {
DCHECK(!web_contents()) << "BUG: Still observering!";
}
-void WebContentsTracker::Start(int render_process_id, int render_view_id,
+void WebContentsTracker::Start(int render_process_id, int main_render_frame_id,
const ChangeCallback& callback) {
DCHECK(!message_loop_.get() || message_loop_->BelongsToCurrentThread());
@@ -26,10 +30,14 @@ void WebContentsTracker::Start(int render_process_id, int render_view_id,
DCHECK(message_loop_.get());
callback_ = callback;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&WebContentsTracker::LookUpAndObserveWebContents, this,
- render_process_id, render_view_id));
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ StartObservingWebContents(render_process_id, main_render_frame_id);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&WebContentsTracker::StartObservingWebContents, this,
+ render_process_id, main_render_frame_id));
+ }
}
void WebContentsTracker::Stop() {
@@ -37,66 +45,100 @@ void WebContentsTracker::Stop() {
callback_.Reset();
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&WebContentsTracker::Observe, this,
- static_cast<WebContents*>(NULL)));
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ WebContentsObserver::Observe(NULL);
+ } else {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&WebContentsTracker::Observe, this,
+ static_cast<WebContents*>(NULL)));
+ }
}
-void WebContentsTracker::OnWebContentsChangeEvent() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+RenderWidgetHost* WebContentsTracker::GetTargetRenderWidgetHost() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
WebContents* const wc = web_contents();
- RenderViewHost* const rvh = wc ? wc->GetRenderViewHost() : NULL;
- RenderProcessHost* const rph = rvh ? rvh->GetProcess() : NULL;
-
- const int render_process_id = rph ? rph->GetID() : MSG_ROUTING_NONE;
- const int render_view_id = rvh ? rvh->GetRoutingID() : MSG_ROUTING_NONE;
+ if (!wc)
+ return NULL;
+
+ RenderWidgetHost* rwh = NULL;
+ if (track_fullscreen_rwh_) {
+ RenderWidgetHostView* const view = wc->GetFullscreenRenderWidgetHostView();
+ if (view)
+ rwh = view->GetRenderWidgetHost();
+ }
+ if (!rwh) {
+ RenderFrameHostImpl* const rfh =
+ static_cast<RenderFrameHostImpl*>(wc->GetMainFrame());
+ if (rfh)
+ rwh = rfh->GetRenderWidgetHost();
+ }
+
+ return rwh;
+}
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&WebContentsTracker::MaybeDoCallback, this,
- render_process_id, render_view_id));
+void WebContentsTracker::OnPossibleTargetChange(bool force_callback_run) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ RenderWidgetHost* const rwh = GetTargetRenderWidgetHost();
+ if (rwh == last_target_ && !force_callback_run)
+ return;
+ DVLOG(1) << "Will report target change from RenderWidgetHost@" << last_target_
+ << " to RenderWidgetHost@" << rwh;
+ last_target_ = rwh;
+
+ if (message_loop_->BelongsToCurrentThread()) {
+ MaybeDoCallback(rwh);
+ } else {
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&WebContentsTracker::MaybeDoCallback, this, rwh));
+ }
}
-void WebContentsTracker::MaybeDoCallback(int render_process_id,
- int render_view_id) {
+void WebContentsTracker::MaybeDoCallback(RenderWidgetHost* rwh) {
DCHECK(message_loop_->BelongsToCurrentThread());
if (!callback_.is_null())
- callback_.Run(render_process_id, render_view_id);
+ callback_.Run(rwh);
}
-void WebContentsTracker::LookUpAndObserveWebContents(int render_process_id,
- int render_view_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+void WebContentsTracker::StartObservingWebContents(int render_process_id,
+ int main_render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- RenderViewHost* const rvh =
- RenderViewHost::FromID(render_process_id, render_view_id);
- DVLOG_IF(1, !rvh) << "RenderViewHost::FromID("
- << render_process_id << ", " << render_view_id
- << ") returned NULL.";
- Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL);
+ Observe(WebContents::FromRenderFrameHost(RenderFrameHost::FromID(
+ render_process_id, main_render_frame_id)));
DVLOG_IF(1, !web_contents())
- << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL.";
+ << "Could not find WebContents associated with main RenderFrameHost "
+ << "referenced by render_process_id=" << render_process_id
+ << ", routing_id=" << main_render_frame_id;
+
+ OnPossibleTargetChange(true);
+}
- OnWebContentsChangeEvent();
+void WebContentsTracker::RenderFrameDeleted(
+ RenderFrameHost* render_frame_host) {
+ OnPossibleTargetChange(false);
}
-void WebContentsTracker::RenderViewReady() {
- OnWebContentsChangeEvent();
+void WebContentsTracker::RenderFrameHostChanged(RenderFrameHost* old_host,
+ RenderFrameHost* new_host) {
+ OnPossibleTargetChange(false);
}
-void WebContentsTracker::AboutToNavigateRenderView(RenderViewHost* rvh) {
- OnWebContentsChangeEvent();
+void WebContentsTracker::WebContentsDestroyed() {
+ Observe(NULL);
+ OnPossibleTargetChange(false);
}
-void WebContentsTracker::DidNavigateMainFrame(
- const LoadCommittedDetails& details, const FrameNavigateParams& params) {
- OnWebContentsChangeEvent();
+void WebContentsTracker::DidShowFullscreenWidget(int routing_id) {
+ OnPossibleTargetChange(false);
}
-void WebContentsTracker::WebContentsDestroyed() {
- OnWebContentsChangeEvent();
+void WebContentsTracker::DidDestroyFullscreenWidget(int routing_id) {
+ OnPossibleTargetChange(false);
}
} // namespace content
diff --git a/chromium/content/browser/media/capture/web_contents_tracker.h b/chromium/content/browser/media/capture/web_contents_tracker.h
index f8957f3f839..f124eaa47e8 100644
--- a/chromium/content/browser/media/capture/web_contents_tracker.h
+++ b/chromium/content/browser/media/capture/web_contents_tracker.h
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Given a starting render_process_id and render_view_id, the WebContentsTracker
-// tracks RenderViewHost instance swapping during the lifetime of a WebContents
-// instance. This is used when mirroring tab video and audio so that user
-// navigations, crashes, etc., during a tab's lifetime allow the capturing code
-// to remain active on the current/latest RenderView.
+// Given a starting render_process_id and main_render_frame_id, the
+// WebContentsTracker tracks changes to the active RenderFrameHost tree during
+// the lifetime of a WebContents instance. This is used when mirroring tab
+// video and audio so that user navigations, crashes, iframes, etc., during a
+// tab's lifetime allow the capturing code to remain active on the
+// current/latest render frame tree.
//
// Threading issues: Start(), Stop() and the ChangeCallback are invoked on the
// same thread. This can be any thread, and the decision is locked-in by
@@ -26,58 +27,88 @@ class MessageLoopProxy;
namespace content {
+class RenderWidgetHost;
+
class CONTENT_EXPORT WebContentsTracker
: public base::RefCountedThreadSafe<WebContentsTracker>,
public WebContentsObserver {
public:
- WebContentsTracker();
-
- // Callback for whenever the target is swapped. The callback is also invoked
- // with both arguments set to MSG_ROUTING_NONE to indicate tracking will not
- // continue (i.e., the WebContents instance was not found or has been
- // destroyed).
- typedef base::Callback<void(int render_process_id, int render_view_id)>
- ChangeCallback;
-
- // Start tracking. The last-known |render_process_id| and |render_view_id|
- // are provided, and the given callback is invoked asynchronously one or more
- // times. The callback will be invoked on the same thread calling Start().
- virtual void Start(int render_process_id, int render_view_id,
+ // If |track_fullscreen_rwh| is true, the ChangeCallback will be run when a
+ // WebContents shows/destroys a fullscreen RenderWidgetHost view. If false,
+ // fullscreen events are ignored. Specify true for video tab capture and
+ // false for audio tab capture.
+ explicit WebContentsTracker(bool track_fullscreen_rwh);
+
+ // Callback to indicate a new RenderWidgetHost should be targeted for capture.
+ // This is also invoked with NULL to indicate tracking will not continue
+ // (i.e., the WebContents instance was not found or has been destroyed).
+ typedef base::Callback<void(RenderWidgetHost* rwh)> ChangeCallback;
+
+ // Start tracking. The last-known |render_process_id| and
+ // |main_render_frame_id| are provided, and |callback| will be run once to
+ // indicate the current capture target (this may occur during the invocation
+ // of Start(), or in the future). The callback will be invoked on the same
+ // thread calling Start().
+ virtual void Start(int render_process_id, int main_render_frame_id,
const ChangeCallback& callback);
// Stop tracking. Once this method returns, the callback is guaranteed not to
// be invoked again.
virtual void Stop();
+ // Current target. This must only be called on the UI BrowserThread.
+ RenderWidgetHost* GetTargetRenderWidgetHost() const;
+
protected:
friend class base::RefCountedThreadSafe<WebContentsTracker>;
- virtual ~WebContentsTracker();
+ ~WebContentsTracker() override;
private:
- // Reads the render_process_id/render_view_id from the current WebContents
- // instance and then invokes the callback.
- void OnWebContentsChangeEvent();
+ // Determine the target RenderWidgetHost and, if different from that last
+ // reported, runs the ChangeCallback on the appropriate thread. If
+ // |force_callback_run| is true, the ChangeCallback is run even if the
+ // RenderWidgetHost has not changed.
+ void OnPossibleTargetChange(bool force_callback_run);
- // Called on the thread that Start()/Stop() are called on, check whether the
- // callback is still valid and, if so, invoke it.
- void MaybeDoCallback(int render_process_id, int render_view_id);
+ // Called on the thread that Start()/Stop() are called on. Checks whether the
+ // callback is still valid and, if so, runs it.
+ void MaybeDoCallback(RenderWidgetHost* rwh);
// Look-up the current WebContents instance associated with the given
- // |render_process_id| and |render_view_id| and begin observing it.
- void LookUpAndObserveWebContents(int render_process_id,
- int render_view_id);
-
- // WebContentsObserver overrides to react to events of interest.
- virtual void RenderViewReady() OVERRIDE;
- virtual void AboutToNavigateRenderView(RenderViewHost* render_view_host)
- OVERRIDE;
- virtual void DidNavigateMainFrame(const LoadCommittedDetails& details,
- const FrameNavigateParams& params) OVERRIDE;
- virtual void WebContentsDestroyed() OVERRIDE;
-
+ // |render_process_id| and |main_render_frame_id| and begin observing it.
+ void StartObservingWebContents(int render_process_id,
+ int main_render_frame_id);
+
+ // WebContentsObserver overrides: According to web_contents_observer.h, these
+ // two method overrides are all that is necessary to track the set of active
+ // RenderFrameHosts.
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+ void RenderFrameHostChanged(RenderFrameHost* old_host,
+ RenderFrameHost* new_host) override;
+
+ // WebContentsObserver override to notify the client that the capture target
+ // has been permanently lost.
+ void WebContentsDestroyed() override;
+
+ // WebContentsObserver overrides to notify the client that the capture target
+ // may have changed due to a separate fullscreen widget shown/destroyed.
+ void DidShowFullscreenWidget(int routing_id) override;
+ void DidDestroyFullscreenWidget(int routing_id) override;
+
+ // If true, the client is interested in the showing/destruction of fullscreen
+ // RenderWidgetHosts.
+ const bool track_fullscreen_rwh_;
+
+ // MessageLoop corresponding to the thread that called Start().
scoped_refptr<base::MessageLoopProxy> message_loop_;
+
+ // Callback to run when the target RenderWidgetHost has changed.
ChangeCallback callback_;
+ // Pointer to the RenderWidgetHost provided in the last run of |callback_|.
+ // This is used to eliminate duplicate callback runs.
+ RenderWidgetHost* last_target_;
+
DISALLOW_COPY_AND_ASSIGN(WebContentsTracker);
};
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 8a8474c2782..4a931fc54b0 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
@@ -13,7 +13,7 @@
// video encoder -- is the performance bottleneck, and that the rate of
// frame capture should be throttled back.
//
-// 2. Capture: A bitmap is snapshotted/copied from the RenderView's backing
+// 2. Capture: A bitmap is snapshotted/copied from the RenderWidget's backing
// store. This is initiated on the UI BrowserThread, and often occurs
// asynchronously. Where supported, the GPU scales and color converts
// frames to our desired size, and the readback happens directly into the
@@ -65,21 +65,27 @@
#include "content/browser/media/capture/content_video_capture_device_core.h"
#include "content/browser/media/capture/video_capture_oracle.h"
#include "content/browser/media/capture/web_contents_capture_util.h"
+#include "content/browser/media/capture/web_contents_tracker.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/public/browser/browser_thread.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host.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"
-#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents.h"
#include "media/base/video_util.h"
#include "media/video/capture/video_capture_types.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/screen.h"
namespace content {
@@ -136,11 +142,12 @@ class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
oracle_proxy_(oracle),
delivery_log_(delivery_log) {}
- virtual bool ShouldCaptureFrame(
+ bool ShouldCaptureFrame(
+ const gfx::Rect& damage_rect,
base::TimeTicks present_time,
scoped_refptr<media::VideoFrame>* storage,
RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback*
- deliver_frame_cb) OVERRIDE;
+ deliver_frame_cb) override;
private:
const VideoCaptureOracle::Event event_type_;
@@ -178,18 +185,21 @@ class ContentCaptureSubscription : public content::NotificationObserver {
const RenderWidgetHost& source,
const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
const CaptureCallback& capture_callback);
- virtual ~ContentCaptureSubscription();
+ ~ContentCaptureSubscription() override;
// content::NotificationObserver implementation.
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) override;
private:
void OnTimer();
+ // Maintain a weak reference to the RenderWidgetHost (via its routing ID),
+ // since the instance could be destroyed externally during the lifetime of
+ // |this|.
const int render_process_id_;
- const int render_view_id_;
+ const int render_widget_id_;
VideoFrameDeliveryLog delivery_log_;
FrameSubscriber paint_subscriber_;
@@ -214,24 +224,17 @@ void RenderVideoFrame(const SkBitmap& input,
const scoped_refptr<media::VideoFrame>& output,
const base::Callback<void(bool)>& done_cb);
-// Keeps track of the RenderView to be sourced, and executes copying of the
-// backing store on the UI BrowserThread.
-//
-// TODO(nick): It would be nice to merge this with WebContentsTracker, but its
-// implementation is currently asynchronous -- in our case, the "rvh changed"
-// notification would get posted back to the UI thread and processed later, and
-// this seems disadvantageous.
-class WebContentsCaptureMachine
- : public VideoCaptureMachine,
- public WebContentsObserver {
+// Renews capture subscriptions based on feedback from WebContentsTracker, and
+// also executes copying of the backing store on the UI BrowserThread.
+class WebContentsCaptureMachine : public VideoCaptureMachine {
public:
- WebContentsCaptureMachine(int render_process_id, int render_view_id);
- virtual ~WebContentsCaptureMachine();
+ WebContentsCaptureMachine(int render_process_id, int main_render_frame_id);
+ ~WebContentsCaptureMachine() override;
// VideoCaptureMachine overrides.
- virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
- const media::VideoCaptureParams& params) OVERRIDE;
- virtual void Stop(const base::Closure& callback) OVERRIDE;
+ bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
+ const media::VideoCaptureParams& params) override;
+ void Stop(const base::Closure& callback) 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
@@ -243,40 +246,11 @@ class WebContentsCaptureMachine
const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
deliver_frame_cb);
- // content::WebContentsObserver implementation.
- virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE {
- fullscreen_widget_id_ = routing_id;
- RenewFrameSubscription();
- }
-
- virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE {
- DCHECK_EQ(fullscreen_widget_id_, routing_id);
- fullscreen_widget_id_ = MSG_ROUTING_NONE;
- RenewFrameSubscription();
- }
-
- virtual void RenderViewReady() OVERRIDE {
- RenewFrameSubscription();
- }
-
- virtual void AboutToNavigateRenderView(RenderViewHost* rvh) OVERRIDE {
- RenewFrameSubscription();
- }
-
- virtual void DidNavigateMainFrame(
- const LoadCommittedDetails& details,
- const FrameNavigateParams& params) OVERRIDE {
- RenewFrameSubscription();
- }
-
- virtual void WebContentsDestroyed() OVERRIDE;
-
private:
- // Starts observing the web contents, returning false if lookup fails.
- bool StartObservingWebContents();
+ bool IsStarted() const;
- // Helper function to determine the view that we are currently tracking.
- RenderWidgetHost* GetTarget();
+ // Computes the preferred size of the target RenderWidget for optimal capture.
+ gfx::Size ComputeOptimalTargetSize() const;
// Response callback for RenderWidgetHost::CopyFromBackingStore().
void DidCopyFromBackingStore(
@@ -294,14 +268,16 @@ class WebContentsCaptureMachine
deliver_frame_cb,
bool success);
- // Remove the old subscription, and start a new one. This should be called
- // after any change to the WebContents that affects the RenderWidgetHost or
- // attached views.
- void RenewFrameSubscription();
+ // Remove the old subscription, and start a new one if |rwh| is not NULL.
+ void RenewFrameSubscription(RenderWidgetHost* rwh);
// Parameters saved in constructor.
const int initial_render_process_id_;
- const int initial_render_view_id_;
+ const int initial_main_render_frame_id_;
+
+ // Tracks events and calls back to RenewFrameSubscription() to maintain
+ // capture on the correct RenderWidgetHost.
+ const scoped_refptr<WebContentsTracker> tracker_;
// A dedicated worker thread on which SkBitmap->VideoFrame conversion will
// occur. Only used when this activity cannot be done on the GPU.
@@ -313,10 +289,6 @@ class WebContentsCaptureMachine
// Video capture parameters that this machine is started with.
media::VideoCaptureParams capture_params_;
- // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE
- // otherwise.
- int fullscreen_widget_id_;
-
// Last known RenderView size.
gfx::Size last_view_size_;
@@ -332,6 +304,7 @@ class WebContentsCaptureMachine
};
bool FrameSubscriber::ShouldCaptureFrame(
+ const gfx::Rect& damage_rect,
base::TimeTicks present_time,
scoped_refptr<media::VideoFrame>* storage,
DeliverFrameCallback* deliver_frame_cb) {
@@ -340,7 +313,7 @@ bool FrameSubscriber::ShouldCaptureFrame(
ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture(
- event_type_, present_time, storage, &capture_frame_cb);
+ event_type_, damage_rect, present_time, storage, &capture_frame_cb);
if (!capture_frame_cb.is_null())
*deliver_frame_cb = base::Bind(capture_frame_cb, *storage);
@@ -354,7 +327,7 @@ ContentCaptureSubscription::ContentCaptureSubscription(
const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
const CaptureCallback& capture_callback)
: render_process_id_(source.GetProcess()->GetID()),
- render_view_id_(source.GetRoutingID()),
+ render_widget_id_(source.GetRoutingID()),
delivery_log_(),
paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy,
&delivery_log_),
@@ -362,10 +335,9 @@ ContentCaptureSubscription::ContentCaptureSubscription(
&delivery_log_),
capture_callback_(capture_callback),
timer_(true, true) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
- source.GetView());
+ RenderWidgetHostView* const view = source.GetView();
// Subscribe to accelerated presents. These will be serviced directly by the
// oracle.
@@ -384,22 +356,25 @@ ContentCaptureSubscription::ContentCaptureSubscription(
Source<RenderWidgetHost>(&source));
// Subscribe to timer events. This instance will service these as well.
- timer_.Start(FROM_HERE, oracle_proxy->capture_period(),
+ timer_.Start(FROM_HERE, oracle_proxy->min_capture_period(),
base::Bind(&ContentCaptureSubscription::OnTimer,
base::Unretained(this)));
}
ContentCaptureSubscription::~ContentCaptureSubscription() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // If the BrowserThreads have been torn down, then the browser is in the final
+ // stages of exiting and it is dangerous to take any further action. We must
+ // return early. http://crbug.com/396413
+ if (!BrowserThread::IsMessageLoopValid(BrowserThread::UI))
+ return;
+
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (kAcceleratedSubscriberIsSupported) {
- RenderViewHost* source = RenderViewHost::FromID(render_process_id_,
- render_view_id_);
- if (source) {
- RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
- source->GetView());
- if (view)
- view->EndFrameSubscription();
- }
+ RenderWidgetHost* const source =
+ RenderWidgetHost::FromID(render_process_id_, render_widget_id_);
+ RenderWidgetHostView* const view = source ? source->GetView() : NULL;
+ if (view)
+ view->EndFrameSubscription();
}
}
@@ -407,7 +382,7 @@ void ContentCaptureSubscription::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type);
RenderWidgetHostImpl* rwh =
@@ -433,7 +408,8 @@ void ContentCaptureSubscription::Observe(
scoped_refptr<media::VideoFrame> frame;
RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
const base::TimeTicks start_time = base::TimeTicks::Now();
- if (paint_subscriber_.ShouldCaptureFrame(start_time,
+ if (paint_subscriber_.ShouldCaptureFrame(gfx::Rect(),
+ start_time,
&frame,
&deliver_frame_cb)) {
// This message happens just before paint. If we post a task to do the copy,
@@ -445,14 +421,15 @@ void ContentCaptureSubscription::Observe(
}
void ContentCaptureSubscription::OnTimer() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
TRACE_EVENT0("mirroring", "ContentCaptureSubscription::OnTimer");
scoped_refptr<media::VideoFrame> frame;
RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
const base::TimeTicks start_time = base::TimeTicks::Now();
- if (timer_subscriber_.ShouldCaptureFrame(start_time,
+ if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(),
+ start_time,
&frame,
&deliver_frame_cb)) {
capture_callback_.Run(start_time, frame, deliver_frame_cb);
@@ -469,12 +446,12 @@ void RenderVideoFrame(const SkBitmap& input,
// Sanity-check the captured bitmap.
if (input.empty() ||
!input.readyToDraw() ||
- input.config() != SkBitmap::kARGB_8888_Config ||
+ input.colorType() != kN32_SkColorType ||
input.width() < 2 || input.height() < 2) {
DVLOG(1) << "input unacceptable (size="
<< input.getSize()
<< ", ready=" << input.readyToDraw()
- << ", config=" << input.config() << ')';
+ << ", colorType=" << input.colorType() << ')';
return;
}
@@ -558,24 +535,24 @@ void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) {
}
WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id,
- int render_view_id)
+ int main_render_frame_id)
: initial_render_process_id_(render_process_id),
- initial_render_view_id_(render_view_id),
- fullscreen_widget_id_(MSG_ROUTING_NONE),
+ initial_main_render_frame_id_(main_render_frame_id),
+ tracker_(new WebContentsTracker(true)),
weak_ptr_factory_(this) {}
-WebContentsCaptureMachine::~WebContentsCaptureMachine() {
- BrowserThread::PostBlockingPoolTask(
- FROM_HERE,
- base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
- base::Bind(&base::DoNothing)));
+WebContentsCaptureMachine::~WebContentsCaptureMachine() {}
+
+bool WebContentsCaptureMachine::IsStarted() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return weak_ptr_factory_.HasWeakPtrs();
}
bool WebContentsCaptureMachine::Start(
const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
const media::VideoCaptureParams& params) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(!started_);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!IsStarted());
DCHECK(oracle_proxy.get());
oracle_proxy_ = oracle_proxy;
@@ -588,36 +565,40 @@ bool WebContentsCaptureMachine::Start(
return false;
}
- if (!StartObservingWebContents()) {
- DVLOG(1) << "Failed to observe web contents.";
- render_thread_.reset();
- return false;
- }
+ // Note: Creation of the first WeakPtr in the following statement will cause
+ // IsStarted() to return true from now on.
+ tracker_->Start(initial_render_process_id_, initial_main_render_frame_id_,
+ base::Bind(&WebContentsCaptureMachine::RenewFrameSubscription,
+ weak_ptr_factory_.GetWeakPtr()));
- started_ = true;
return true;
}
void WebContentsCaptureMachine::Stop(const base::Closure& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- subscription_.reset();
- if (web_contents()) {
- web_contents()->DecrementCapturerCount();
- Observe(NULL);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (!IsStarted()) {
+ callback.Run();
+ return;
}
- // Any callback that intend to use render_thread_ will not work after it is
- // passed.
+ // The following cancels any outstanding callbacks and causes IsStarted() to
+ // return false from here onward.
weak_ptr_factory_.InvalidateWeakPtrs();
+ // Note: RenewFrameSubscription() must be called before stopping |tracker_| so
+ // the web_contents() can be notified that the capturing is ending.
+ RenewFrameSubscription(NULL);
+ tracker_->Stop();
+
// The render thread cannot be stopped on the UI thread, so post a message
// to the thread pool used for blocking operations.
- BrowserThread::PostBlockingPoolTask(
- FROM_HERE,
- base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
- callback));
-
- started_ = false;
+ if (render_thread_.get()) {
+ BrowserThread::PostBlockingPoolTask(
+ FROM_HERE,
+ base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
+ callback));
+ }
}
void WebContentsCaptureMachine::Capture(
@@ -625,12 +606,12 @@ void WebContentsCaptureMachine::Capture(
const scoped_refptr<media::VideoFrame>& target,
const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
deliver_frame_cb) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- RenderWidgetHost* rwh = GetTarget();
+ RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost();
RenderWidgetHostViewBase* view =
rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL;
- if (!view || !rwh) {
+ if (!view) {
deliver_frame_cb.Run(base::TimeTicks(), false);
return;
}
@@ -667,63 +648,37 @@ void WebContentsCaptureMachine::Capture(
start_time,
target,
deliver_frame_cb),
- SkBitmap::kARGB_8888_Config);
- }
-}
-
-bool WebContentsCaptureMachine::StartObservingWebContents() {
- // Look-up the RenderViewHost and, from that, the WebContents that wraps it.
- // If successful, begin observing the WebContents instance.
- //
- // Why this can be unsuccessful: The request for mirroring originates in a
- // render process, and this request is based on the current RenderView
- // associated with a tab. However, by the time we get up-and-running here,
- // there have been multiple back-and-forth IPCs between processes, as well as
- // a bit of indirection across threads. It's easily possible that, in the
- // meantime, the original RenderView may have gone away.
- RenderViewHost* const rvh =
- RenderViewHost::FromID(initial_render_process_id_,
- initial_render_view_id_);
- DVLOG_IF(1, !rvh) << "RenderViewHost::FromID("
- << initial_render_process_id_ << ", "
- << initial_render_view_id_ << ") returned NULL.";
- Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL);
-
- WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents());
- if (contents) {
- contents->IncrementCapturerCount(oracle_proxy_->GetCaptureSize());
- fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID();
- RenewFrameSubscription();
- return true;
+ kN32_SkColorType);
}
-
- DVLOG(1) << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL.";
- return false;
}
-void WebContentsCaptureMachine::WebContentsDestroyed() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- subscription_.reset();
- web_contents()->DecrementCapturerCount();
- oracle_proxy_->ReportError("WebContentsDestroyed()");
-}
-
-RenderWidgetHost* WebContentsCaptureMachine::GetTarget() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!web_contents())
- return NULL;
-
- RenderWidgetHost* rwh = NULL;
- if (fullscreen_widget_id_ != MSG_ROUTING_NONE) {
- RenderProcessHost* process = web_contents()->GetRenderProcessHost();
- if (process)
- rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_);
- } else {
- rwh = web_contents()->GetRenderViewHost();
+gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ gfx::Size optimal_size = oracle_proxy_->GetCaptureSize();
+
+ // If the ratio between physical and logical pixels is greater than 1:1,
+ // shrink |optimal_size| by that amount. Then, when external code resizes the
+ // render widget to the "preferred size," the widget will be physically
+ // rendered at the exact capture size, thereby eliminating unnecessary scaling
+ // operations in the graphics pipeline.
+ RenderWidgetHost* const rwh = tracker_->GetTargetRenderWidgetHost();
+ RenderWidgetHostView* const rwhv = rwh ? rwh->GetView() : NULL;
+ if (rwhv) {
+ const gfx::NativeView view = rwhv->GetNativeView();
+ gfx::Screen* const screen = gfx::Screen::GetScreenFor(view);
+ const gfx::Display display = screen->GetDisplayNearestWindow(view);
+ const float scale = display.device_scale_factor();
+ if (scale > 1.0f) {
+ const gfx::Size shrunk_size(
+ gfx::ToFlooredSize(gfx::ScaleSize(optimal_size, 1.0f / scale)));
+ if (shrunk_size.width() > 0 && shrunk_size.height() > 0)
+ optimal_size = shrunk_size;
+ }
}
- return rwh;
+ VLOG(1) << "Computed optimal target size: " << optimal_size.ToString();
+ return optimal_size;
}
void WebContentsCaptureMachine::DidCopyFromBackingStore(
@@ -733,7 +688,7 @@ void WebContentsCaptureMachine::DidCopyFromBackingStore(
deliver_frame_cb,
bool success,
const SkBitmap& bitmap) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::TimeTicks now = base::TimeTicks::Now();
DCHECK(render_thread_.get());
@@ -756,7 +711,7 @@ void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
deliver_frame_cb,
bool success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::TimeTicks now = base::TimeTicks::Now();
if (success) {
@@ -768,15 +723,31 @@ void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
deliver_frame_cb.Run(start_time, success);
}
-void WebContentsCaptureMachine::RenewFrameSubscription() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+void WebContentsCaptureMachine::RenewFrameSubscription(RenderWidgetHost* rwh) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Always destroy the old subscription before creating a new one.
+ const bool had_subscription = !!subscription_;
subscription_.reset();
- RenderWidgetHost* rwh = GetTarget();
- if (!rwh || !rwh->GetView())
+ DVLOG(1) << "Renewing frame subscription to RWH@" << rwh
+ << ", had_subscription=" << had_subscription;
+
+ if (!rwh) {
+ if (had_subscription && tracker_->web_contents())
+ tracker_->web_contents()->DecrementCapturerCount();
+ if (IsStarted()) {
+ // Tracking of WebContents and/or its main frame has failed before Stop()
+ // was called, so report this as an error:
+ oracle_proxy_->ReportError("WebContents and/or main frame are gone.");
+ }
return;
+ }
+
+ if (!had_subscription && tracker_->web_contents()) {
+ tracker_->web_contents()->IncrementCapturerCount(
+ ComputeOptimalTargetSize());
+ }
subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_,
base::Bind(&WebContentsCaptureMachine::Capture,
@@ -786,9 +757,10 @@ void WebContentsCaptureMachine::RenewFrameSubscription() {
} // namespace
WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
- int render_process_id, int render_view_id)
+ int render_process_id, int main_render_frame_id)
: core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>(
- new WebContentsCaptureMachine(render_process_id, render_view_id)))) {}
+ new WebContentsCaptureMachine(
+ render_process_id, main_render_frame_id)))) {}
WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() {
DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying.";
@@ -797,15 +769,16 @@ WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() {
// static
media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create(
const std::string& device_id) {
- // Parse device_id into render_process_id and render_view_id.
+ // Parse device_id into render_process_id and main_render_frame_id.
int render_process_id = -1;
- int render_view_id = -1;
+ int main_render_frame_id = -1;
if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(
- device_id, &render_process_id, &render_view_id)) {
+ device_id, &render_process_id, &main_render_frame_id)) {
return NULL;
}
- return new WebContentsVideoCaptureDevice(render_process_id, render_view_id);
+ return new WebContentsVideoCaptureDevice(
+ render_process_id, main_render_frame_id);
}
void WebContentsVideoCaptureDevice::AllocateAndStart(
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 16c7b09f8e1..d385a2b5302 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
@@ -16,36 +16,32 @@ namespace content {
class ContentVideoCaptureDeviceCore;
// A virtualized VideoCaptureDevice that mirrors the displayed contents of a
-// tab (accessed via its associated WebContents instance), producing a stream of
-// video frames.
+// WebContents (i.e., the composition of an entire render frame tree), producing
+// a stream of video frames.
//
-// An instance is created by providing a device_id. The device_id contains the
-// routing ID for a RenderViewHost, and from the RenderViewHost instance, a
-// reference to its associated WebContents instance is acquired. From then on,
-// WebContentsVideoCaptureDevice will capture from whatever render view is
-// currently associated with that WebContents instance. This allows the
-// underlying render view to be swapped out (e.g., due to navigation or
-// crashes/reloads), without any interruption in capturing.
+// An instance is created by providing a device_id. The device_id contains
+// information necessary for finding a WebContents instance. From then on,
+// WebContentsVideoCaptureDevice will capture from the RenderWidgetHost that
+// encompasses the currently active RenderFrameHost tree for that that
+// WebContents instance. As the RenderFrameHost tree mutates (e.g., due to page
+// navigations, or crashes/reloads), capture will continue without interruption.
class CONTENT_EXPORT WebContentsVideoCaptureDevice
: public media::VideoCaptureDevice {
public:
- // Construct from a |device_id| string of the form:
- // "virtual-media-stream://render_process_id:render_view_id", where
- // |render_process_id| and |render_view_id| are decimal integers.
- // |destroy_cb| is invoked on an outside thread once all outstanding objects
- // are completely destroyed -- this will be some time after the
- // WebContentsVideoCaptureDevice is itself deleted.
+ // Create a WebContentsVideoCaptureDevice instance from the given
+ // |device_id|. Returns NULL if |device_id| is invalid.
static media::VideoCaptureDevice* Create(const std::string& device_id);
- virtual ~WebContentsVideoCaptureDevice();
+ ~WebContentsVideoCaptureDevice() override;
// VideoCaptureDevice implementation.
- virtual void AllocateAndStart(const media::VideoCaptureParams& params,
- scoped_ptr<Client> client) OVERRIDE;
- virtual void StopAndDeAllocate() OVERRIDE;
+ void AllocateAndStart(const media::VideoCaptureParams& params,
+ scoped_ptr<Client> client) override;
+ void StopAndDeAllocate() override;
private:
- WebContentsVideoCaptureDevice(int render_process_id, int render_view_id);
+ WebContentsVideoCaptureDevice(
+ int render_process_id, int main_render_frame_id);
const scoped_ptr<ContentVideoCaptureDeviceCore> core_;
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 dc1bd5a54d9..09f84454f60 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
@@ -32,6 +32,8 @@
#include "skia/ext/platform_canvas.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/screen.h"
namespace content {
namespace {
@@ -39,6 +41,7 @@ namespace {
const int kTestWidth = 320;
const int kTestHeight = 240;
const int kTestFramesPerSecond = 20;
+const float kTestDeviceScaleFactor = 2.0f;
const SkColor kNothingYet = 0xdeadbeef;
const SkColor kNotInterested = ~kNothingYet;
@@ -160,21 +163,21 @@ class CaptureTestView : public TestRenderWidgetHostView {
: TestRenderWidgetHostView(rwh),
controller_(controller) {}
- virtual ~CaptureTestView() {}
+ ~CaptureTestView() override {}
// TestRenderWidgetHostView overrides.
- virtual gfx::Rect GetViewBounds() const OVERRIDE {
+ gfx::Rect GetViewBounds() const override {
return gfx::Rect(100, 100, 100 + kTestWidth, 100 + kTestHeight);
}
- virtual bool CanCopyToVideoFrame() const OVERRIDE {
+ bool CanCopyToVideoFrame() const override {
return controller_->CanCopyToVideoFrame();
}
- virtual void CopyFromCompositingSurfaceToVideoFrame(
+ void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) OVERRIDE {
+ const base::Callback<void(bool)>& callback) override {
SkColor c = ConvertRgbToYuv(controller_->GetSolidColor());
media::FillYUV(
target.get(), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
@@ -182,22 +185,20 @@ class CaptureTestView : public TestRenderWidgetHostView {
controller_->SignalCopy();
}
- virtual void BeginFrameSubscription(
- scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) OVERRIDE {
+ void BeginFrameSubscription(
+ scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) override {
subscriber_.reset(subscriber.release());
}
- virtual void EndFrameSubscription() OVERRIDE {
- subscriber_.reset();
- }
+ void EndFrameSubscription() override { subscriber_.reset(); }
// Simulate a compositor paint event for our subscriber.
void SimulateUpdate() {
const base::TimeTicks present_time = base::TimeTicks::Now();
RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
scoped_refptr<media::VideoFrame> target;
- if (subscriber_ && subscriber_->ShouldCaptureFrame(present_time,
- &target, &callback)) {
+ if (subscriber_ && subscriber_->ShouldCaptureFrame(
+ gfx::Rect(), present_time, &target, &callback)) {
SkColor c = ConvertRgbToYuv(controller_->GetSolidColor());
media::FillYUV(
target.get(), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
@@ -245,11 +246,11 @@ class CaptureTestRenderViewHost : public TestRenderViewHost {
}
// TestRenderViewHost overrides.
- virtual void CopyFromBackingStore(
+ void CopyFromBackingStore(
const gfx::Rect& src_rect,
const gfx::Size& accelerated_dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config& bitmap_config) OVERRIDE {
+ const SkColorType color_type) override {
gfx::Size size = controller_->GetCopyResultSize();
SkColor color = controller_->GetSolidColor();
@@ -283,18 +284,16 @@ class CaptureTestRenderViewHostFactory : public RenderViewHostFactory {
RegisterFactory(this);
}
- virtual ~CaptureTestRenderViewHostFactory() {
- UnregisterFactory();
- }
+ ~CaptureTestRenderViewHostFactory() override { UnregisterFactory(); }
// RenderViewHostFactory implementation.
- virtual RenderViewHost* CreateRenderViewHost(
+ RenderViewHost* CreateRenderViewHost(
SiteInstance* instance,
RenderViewHostDelegate* delegate,
RenderWidgetHostDelegate* widget_delegate,
int routing_id,
int main_frame_routing_id,
- bool swapped_out) OVERRIDE {
+ bool swapped_out) override {
return new CaptureTestRenderViewHost(instance, delegate, widget_delegate,
routing_id, main_frame_routing_id,
swapped_out, controller_);
@@ -315,11 +314,11 @@ class StubClient : public media::VideoCaptureDevice::Client {
error_callback_(error_callback) {
buffer_pool_ = new VideoCaptureBufferPool(2);
}
- virtual ~StubClient() {}
+ ~StubClient() override {}
- virtual scoped_refptr<media::VideoCaptureDevice::Client::Buffer>
- ReserveOutputBuffer(media::VideoFrame::Format format,
- const gfx::Size& dimensions) OVERRIDE {
+ scoped_refptr<media::VideoCaptureDevice::Client::Buffer> ReserveOutputBuffer(
+ media::VideoFrame::Format format,
+ const gfx::Size& dimensions) override {
CHECK_EQ(format, media::VideoFrame::I420);
const size_t frame_bytes =
media::VideoFrame::AllocationSize(media::VideoFrame::I420, dimensions);
@@ -335,20 +334,19 @@ class StubClient : public media::VideoCaptureDevice::Client {
new PoolBuffer(buffer_pool_, buffer_id, data, size));
}
- virtual void OnIncomingCapturedData(
- const uint8* data,
- int length,
- const media::VideoCaptureFormat& frame_format,
- int rotation,
- base::TimeTicks timestamp) OVERRIDE {
+ void OnIncomingCapturedData(const uint8* data,
+ int length,
+ const media::VideoCaptureFormat& frame_format,
+ int rotation,
+ base::TimeTicks timestamp) override {
FAIL();
}
- virtual void OnIncomingCapturedVideoFrame(
+ void OnIncomingCapturedVideoFrame(
const scoped_refptr<Buffer>& buffer,
const media::VideoCaptureFormat& buffer_format,
const scoped_refptr<media::VideoFrame>& frame,
- base::TimeTicks timestamp) OVERRIDE {
+ base::TimeTicks timestamp) override {
EXPECT_EQ(gfx::Size(kTestWidth, kTestHeight), buffer_format.frame_size);
EXPECT_EQ(media::PIXEL_FORMAT_I420, buffer_format.pixel_format);
EXPECT_EQ(media::VideoFrame::I420, frame->format());
@@ -361,9 +359,7 @@ class StubClient : public media::VideoCaptureDevice::Client {
color_callback_.Run((SkColorSetRGB(yuv[0], yuv[1], yuv[2])));
}
- virtual void OnError(const std::string& reason) OVERRIDE {
- error_callback_.Run();
- }
+ void OnError(const std::string& reason) override { error_callback_.Run(); }
private:
class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer {
@@ -375,7 +371,7 @@ class StubClient : public media::VideoCaptureDevice::Client {
: Buffer(buffer_id, data, size), pool_(pool) {}
private:
- virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(id()); }
+ ~PoolBuffer() override { pool_->RelinquishProducerReservation(id()); }
const scoped_refptr<VideoCaptureBufferPool> pool_;
};
@@ -399,7 +395,7 @@ class StubClientObserver {
virtual ~StubClientObserver() {}
scoped_ptr<media::VideoCaptureDevice::Client> PassClient() {
- return client_.PassAs<media::VideoCaptureDevice::Client>();
+ return client_.Pass();
}
void QuitIfConditionMet(SkColor color) {
@@ -466,6 +462,44 @@ class StubClientObserver {
DISALLOW_COPY_AND_ASSIGN(StubClientObserver);
};
+// A dummy implementation of gfx::Screen, since WebContentsVideoCaptureDevice
+// needs access to a gfx::Display's device scale factor.
+class FakeScreen : public gfx::Screen {
+ public:
+ FakeScreen() : the_one_display_(0x1337, gfx::Rect(0, 0, 2560, 1440)) {
+ the_one_display_.set_device_scale_factor(kTestDeviceScaleFactor);
+ }
+ ~FakeScreen() override {}
+
+ // gfx::Screen implementation (only what's needed for testing).
+ gfx::Point GetCursorScreenPoint() override { return gfx::Point(); }
+ gfx::NativeWindow GetWindowUnderCursor() override { return NULL; }
+ gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override {
+ return NULL;
+ }
+ int GetNumDisplays() const override { return 1; }
+ std::vector<gfx::Display> GetAllDisplays() const override {
+ return std::vector<gfx::Display>(1, the_one_display_);
+ }
+ gfx::Display GetDisplayNearestWindow(gfx::NativeView view) const override {
+ return the_one_display_;
+ }
+ gfx::Display GetDisplayNearestPoint(const gfx::Point& point) const override {
+ return the_one_display_;
+ }
+ gfx::Display GetDisplayMatching(const gfx::Rect& match_rect) const override {
+ return the_one_display_;
+ }
+ gfx::Display GetPrimaryDisplay() const override { return the_one_display_; }
+ void AddObserver(gfx::DisplayObserver* observer) override {}
+ void RemoveObserver(gfx::DisplayObserver* observer) override {}
+
+ private:
+ gfx::Display the_one_display_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeScreen);
+};
+
// Test harness that sets up a minimal environment with necessary stubs.
class WebContentsVideoCaptureDeviceTest : public testing::Test {
public:
@@ -476,7 +510,10 @@ class WebContentsVideoCaptureDeviceTest : public testing::Test {
}
protected:
- virtual void SetUp() {
+ void SetUp() override {
+ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, &fake_screen_);
+ ASSERT_EQ(&fake_screen_, gfx::Screen::GetNativeScreen());
+
// TODO(nick): Sadness and woe! Much "mock-the-world" boilerplate could be
// eliminated here, if only we could use RenderViewHostTestHarness. The
// catch is that we need our TestRenderViewHost to support a
@@ -499,22 +536,16 @@ class WebContentsVideoCaptureDeviceTest : public testing::Test {
render_process_host_factory_.get());
web_contents_.reset(
TestWebContents::Create(browser_context_.get(), site_instance.get()));
-
- // This is actually a CaptureTestRenderViewHost.
- RenderWidgetHostImpl* rwh =
- RenderWidgetHostImpl::From(web_contents_->GetRenderViewHost());
-
- std::string device_id =
- WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
- base::StringPrintf("%d:%d", rwh->GetProcess()->GetID(),
- rwh->GetRoutingID()));
-
- device_.reset(WebContentsVideoCaptureDevice::Create(device_id));
+ RenderFrameHost* const main_frame = web_contents_->GetMainFrame();
+ device_.reset(WebContentsVideoCaptureDevice::Create(
+ base::StringPrintf("web-contents-media-stream://%d:%d",
+ main_frame->GetProcess()->GetID(),
+ main_frame->GetRoutingID())));
base::RunLoop().RunUntilIdle();
}
- virtual void TearDown() {
+ void TearDown() override {
// Tear down in opposite order of set-up.
// The device is destroyed asynchronously, and will notify the
@@ -536,10 +567,13 @@ class WebContentsVideoCaptureDeviceTest : public testing::Test {
SiteInstanceImpl::set_render_process_host_factory(NULL);
render_view_host_factory_.reset();
render_process_host_factory_.reset();
+
+ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, NULL);
}
// Accessors.
CaptureTestSourceController* source() { return &controller_; }
+ WebContents* web_contents() const { return web_contents_.get(); }
media::VideoCaptureDevice* device() { return device_.get(); }
void SimulateDrawEvent() {
@@ -564,6 +598,8 @@ class WebContentsVideoCaptureDeviceTest : public testing::Test {
}
private:
+ FakeScreen fake_screen_;
+
StubClientObserver client_observer_;
// The controller controls which pixel patterns to produce.
@@ -596,20 +632,23 @@ TEST_F(WebContentsVideoCaptureDeviceTest, InvalidInitialWebContentsError) {
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;
- capture_params.allow_resolution_change = false;
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
ASSERT_NO_FATAL_FAILURE(client_observer()->WaitForError());
device()->StopAndDeAllocate();
}
TEST_F(WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) {
+ const gfx::Size capture_preferred_size(
+ static_cast<int>(kTestWidth / kTestDeviceScaleFactor),
+ static_cast<int>(kTestHeight / kTestDeviceScaleFactor));
+ ASSERT_NE(capture_preferred_size, web_contents()->GetPreferredSize());
+
// We'll simulate the tab being closed after the capture pipeline is up and
// running.
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;
- capture_params.allow_resolution_change = false;
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
// Do one capture to prove
source()->SetSolidColor(SK_ColorRED);
@@ -618,6 +657,10 @@ TEST_F(WebContentsVideoCaptureDeviceTest, WebContentsDestroyed) {
base::RunLoop().RunUntilIdle();
+ // Check that the preferred size of the WebContents matches the one provided
+ // by WebContentsVideoCaptureDevice.
+ EXPECT_EQ(capture_preferred_size, web_contents()->GetPreferredSize());
+
// Post a task to close the tab. We should see an error reported to the
// consumer.
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
@@ -633,7 +676,6 @@ TEST_F(WebContentsVideoCaptureDeviceTest,
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;
- capture_params.allow_resolution_change = false;
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
// Make a point of not running the UI messageloop here.
@@ -655,7 +697,6 @@ TEST_F(WebContentsVideoCaptureDeviceTest, StopWithRendererWorkToDo) {
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;
- capture_params.allow_resolution_change = false;
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
base::RunLoop().RunUntilIdle();
@@ -675,7 +716,6 @@ TEST_F(WebContentsVideoCaptureDeviceTest, DeviceRestart) {
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;
- capture_params.allow_resolution_change = false;
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
base::RunLoop().RunUntilIdle();
source()->SetSolidColor(SK_ColorRED);
@@ -714,7 +754,6 @@ TEST_F(WebContentsVideoCaptureDeviceTest, GoesThroughAllTheMotions) {
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;
- capture_params.allow_resolution_change = false;
device()->AllocateAndStart(capture_params, client_observer()->PassClient());
for (int i = 0; i < 6; i++) {
@@ -765,7 +804,6 @@ TEST_F(WebContentsVideoCaptureDeviceTest, RejectsInvalidAllocateParams) {
capture_params.requested_format.frame_size.SetSize(1280, 720);
capture_params.requested_format.frame_rate = -2;
capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
- capture_params.allow_resolution_change = false;
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -787,7 +825,6 @@ TEST_F(WebContentsVideoCaptureDeviceTest, BadFramesGoodFrames) {
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;
- capture_params.allow_resolution_change = false;
// 1x1 is too small to process; we intend for this to result in an error.
source()->SetCopyResultSize(1, 1);
source()->SetSolidColor(SK_ColorRED);
diff --git a/chromium/content/browser/media/cdm/browser_cdm_manager.cc b/chromium/content/browser/media/cdm/browser_cdm_manager.cc
index a71bfafbd5f..d3d4630cb08 100644
--- a/chromium/content/browser/media/cdm/browser_cdm_manager.cc
+++ b/chromium/content/browser/media/cdm/browser_cdm_manager.cc
@@ -4,8 +4,12 @@
#include "content/browser/media/cdm/browser_cdm_manager.h"
+#include "base/bind.h"
#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/task_runner.h"
#include "content/common/media/cdm_messages.h"
+#include "content/public/browser/browser_thread.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"
@@ -28,41 +32,121 @@ const size_t kMaxInitDataLength = 64 * 1024; // 64 KB
const size_t kMaxSessionResponseLength = 64 * 1024; // 64 KB
const size_t kMaxKeySystemLength = 256;
-// static
-BrowserCdmManager* BrowserCdmManager::Create(RenderFrameHost* rfh) {
- return new BrowserCdmManager(rfh);
+// The ID used in this class is a concatenation of |render_frame_id| and
+// |cdm_id|, i.e. (render_frame_id << 32) + cdm_id.
+
+static uint64 GetId(int render_frame_id, int cdm_id) {
+ return (static_cast<uint64>(render_frame_id) << 32) +
+ static_cast<uint64>(cdm_id);
+}
+
+static bool IdBelongsToFrame(uint64 id, int render_frame_id) {
+ return (id >> 32) == static_cast<uint64>(render_frame_id);
+}
+
+// Render process ID to BrowserCdmManager map.
+typedef std::map<int, BrowserCdmManager*> BrowserCdmManagerMap;
+base::LazyInstance<BrowserCdmManagerMap> g_browser_cdm_manager_map =
+ LAZY_INSTANCE_INITIALIZER;
+
+BrowserCdmManager* BrowserCdmManager::FromProcess(int render_process_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (!g_browser_cdm_manager_map.Get().count(render_process_id))
+ return NULL;
+
+ return g_browser_cdm_manager_map.Get()[render_process_id];
}
-BrowserCdmManager::BrowserCdmManager(RenderFrameHost* render_frame_host)
- : render_frame_host_(render_frame_host),
- web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
- weak_ptr_factory_(this) {
+BrowserCdmManager::BrowserCdmManager(
+ int render_process_id,
+ const scoped_refptr<base::TaskRunner>& task_runner)
+ : BrowserMessageFilter(CdmMsgStart),
+ render_process_id_(render_process_id),
+ task_runner_(task_runner) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (!task_runner_.get()) {
+ task_runner_ =
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
+ }
+
+ // This may overwrite an existing entry of |render_process_id| if the
+ // previous process crashed and didn't cleanup its child frames. For example,
+ // see FrameTreeBrowserTest.FrameTreeAfterCrash test.
+ g_browser_cdm_manager_map.Get()[render_process_id] = this;
}
BrowserCdmManager::~BrowserCdmManager() {
- // During the tear down process, OnDestroyCdm() may or may not be called
- // (e.g. WebContents may be destroyed before the render process is killed). So
- // we cannot DCHECK(cdm_map_.empty()) here. Instead, all CDMs in |cdm_map_|
- // will be destroyed here because they are owned by BrowserCdmManager.
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(g_browser_cdm_manager_map.Get().count(render_process_id_));
+
+ g_browser_cdm_manager_map.Get().erase(render_process_id_);
}
-BrowserCdm* BrowserCdmManager::GetCdm(int cdm_id) {
- return cdm_map_.get(cdm_id);
+// Makes sure BrowserCdmManager is always deleted on the Browser UI thread.
+void BrowserCdmManager::OnDestruct() const {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ delete this;
+ } else {
+ BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
+ }
}
-void BrowserCdmManager::OnSessionCreated(
- int cdm_id,
- uint32 session_id,
- const std::string& web_session_id) {
+base::TaskRunner* BrowserCdmManager::OverrideTaskRunnerForMessage(
+ const IPC::Message& message) {
+ // Only handles CDM messages.
+ if (IPC_MESSAGE_CLASS(message) != CdmMsgStart)
+ return NULL;
+
+ return task_runner_.get();
+}
+
+bool BrowserCdmManager::OnMessageReceived(const IPC::Message& msg) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(BrowserCdmManager, msg)
+ IPC_MESSAGE_HANDLER(CdmHostMsg_InitializeCdm, OnInitializeCdm)
+ IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSession, OnCreateSession)
+ IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession, OnUpdateSession)
+ IPC_MESSAGE_HANDLER(CdmHostMsg_ReleaseSession, OnReleaseSession)
+ IPC_MESSAGE_HANDLER(CdmHostMsg_DestroyCdm, OnDestroyCdm)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+media::BrowserCdm* BrowserCdmManager::GetCdm(int render_frame_id, int cdm_id) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ return cdm_map_.get(GetId(render_frame_id, cdm_id));
+}
+
+void BrowserCdmManager::RenderFrameDeleted(int render_frame_id) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+
+ std::vector<uint64> ids_to_remove;
+ for (CdmMap::iterator it = cdm_map_.begin(); it != cdm_map_.end(); ++it) {
+ if (IdBelongsToFrame(it->first, render_frame_id))
+ ids_to_remove.push_back(it->first);
+ }
+
+ for (size_t i = 0; i < ids_to_remove.size(); ++i)
+ RemoveCdm(ids_to_remove[i]);
+}
+
+void BrowserCdmManager::OnSessionCreated(int render_frame_id,
+ int cdm_id,
+ uint32 session_id,
+ const std::string& web_session_id) {
Send(new CdmMsg_SessionCreated(
- RoutingID(), cdm_id, session_id, web_session_id));
+ render_frame_id, cdm_id, session_id, web_session_id));
}
-void BrowserCdmManager::OnSessionMessage(
- int cdm_id,
- uint32 session_id,
- const std::vector<uint8>& message,
- const GURL& destination_url) {
+void BrowserCdmManager::OnSessionMessage(int render_frame_id,
+ int cdm_id,
+ uint32 session_id,
+ const std::vector<uint8>& message,
+ const GURL& destination_url) {
GURL verified_gurl = destination_url;
if (!verified_gurl.is_valid() && !verified_gurl.is_empty()) {
DLOG(WARNING) << "SessionMessage destination_url is invalid : "
@@ -71,28 +155,34 @@ void BrowserCdmManager::OnSessionMessage(
}
Send(new CdmMsg_SessionMessage(
- RoutingID(), cdm_id, session_id, message, verified_gurl));
+ render_frame_id, cdm_id, session_id, message, verified_gurl));
}
-void BrowserCdmManager::OnSessionReady(int cdm_id, uint32 session_id) {
- Send(new CdmMsg_SessionReady(RoutingID(), cdm_id, session_id));
+void BrowserCdmManager::OnSessionReady(int render_frame_id,
+ int cdm_id,
+ uint32 session_id) {
+ Send(new CdmMsg_SessionReady(render_frame_id, cdm_id, session_id));
}
-void BrowserCdmManager::OnSessionClosed(int cdm_id, uint32 session_id) {
- Send(new CdmMsg_SessionClosed(RoutingID(), cdm_id, session_id));
+void BrowserCdmManager::OnSessionClosed(int render_frame_id,
+ int cdm_id,
+ uint32 session_id) {
+ Send(new CdmMsg_SessionClosed(render_frame_id, cdm_id, session_id));
}
-void BrowserCdmManager::OnSessionError(int cdm_id,
+void BrowserCdmManager::OnSessionError(int render_frame_id,
+ int cdm_id,
uint32 session_id,
MediaKeys::KeyError error_code,
uint32 system_code) {
Send(new CdmMsg_SessionError(
- RoutingID(), cdm_id, session_id, error_code, system_code));
+ render_frame_id, cdm_id, session_id, error_code, system_code));
}
-void BrowserCdmManager::OnInitializeCdm(int cdm_id,
- const std::string& key_system,
- const GURL& security_origin) {
+void BrowserCdmManager::OnInitializeCdm(int render_frame_id,
+ int cdm_id,
+ const std::string& key_system,
+ const GURL& security_origin) {
if (key_system.size() > kMaxKeySystemLength) {
// This failure will be discovered and reported by OnCreateSession()
// as GetCdm() will return null.
@@ -100,10 +190,11 @@ void BrowserCdmManager::OnInitializeCdm(int cdm_id,
return;
}
- AddCdm(cdm_id, key_system, security_origin);
+ AddCdm(render_frame_id, cdm_id, key_system, security_origin);
}
void BrowserCdmManager::OnCreateSession(
+ int render_frame_id,
int cdm_id,
uint32 session_id,
CdmHostMsg_CreateSession_ContentType content_type,
@@ -111,7 +202,7 @@ void BrowserCdmManager::OnCreateSession(
if (init_data.size() > kMaxInitDataLength) {
LOG(WARNING) << "InitData for ID: " << cdm_id
<< " too long: " << init_data.size();
- OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
+ SendSessionError(render_frame_id, cdm_id, session_id);
return;
}
@@ -135,101 +226,112 @@ void BrowserCdmManager::OnCreateSession(
#if defined(OS_ANDROID)
if (CommandLine::ForCurrentProcess()
->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier)) {
- CreateSessionIfPermitted(cdm_id, session_id, mime_type, init_data, true);
+ CreateSessionIfPermitted(
+ render_frame_id, cdm_id, session_id, mime_type, init_data, true);
return;
}
#endif
- BrowserCdm* cdm = GetCdm(cdm_id);
+ BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
- DLOG(WARNING) << "No CDM for ID " << cdm_id << " found";
- OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
+ DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
+ SendSessionError(render_frame_id, cdm_id, session_id);
return;
}
- std::map<int, GURL>::const_iterator iter =
- cdm_security_origin_map_.find(cdm_id);
+ std::map<uint64, GURL>::const_iterator iter =
+ cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id));
if (iter == cdm_security_origin_map_.end()) {
NOTREACHED();
- OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
+ SendSessionError(render_frame_id, cdm_id, session_id);
return;
}
-
- base::Closure cancel_callback;
- GetContentClient()->browser()->RequestProtectedMediaIdentifierPermission(
- web_contents_,
- iter->second,
+ GURL security_origin = iter->second;
+
+ RenderFrameHost* rfh =
+ RenderFrameHost::FromID(render_process_id_, render_frame_id);
+ WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
+ DCHECK(web_contents);
+ GetContentClient()->browser()->RequestPermission(
+ content::PERMISSION_PROTECTED_MEDIA,
+ web_contents,
+ 0, // bridge id
+ security_origin,
+ // Only implemented for Android infobars which do not support
+ // user gestures.
+ true,
base::Bind(&BrowserCdmManager::CreateSessionIfPermitted,
- weak_ptr_factory_.GetWeakPtr(),
+ this,
+ render_frame_id,
cdm_id,
session_id,
mime_type,
- init_data),
- &cancel_callback);
- if (!cancel_callback.is_null())
- cdm_cancel_permision_map_[cdm_id] = cancel_callback;
+ init_data));
}
void BrowserCdmManager::OnUpdateSession(
+ int render_frame_id,
int cdm_id,
uint32 session_id,
const std::vector<uint8>& response) {
- BrowserCdm* cdm = GetCdm(cdm_id);
+ BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
- DLOG(WARNING) << "No CDM for ID " << cdm_id << " found";
- OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
+ DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
+ SendSessionError(render_frame_id, cdm_id, session_id);
return;
}
if (response.size() > kMaxSessionResponseLength) {
LOG(WARNING) << "Response for ID " << cdm_id
<< " is too long: " << response.size();
- OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
+ SendSessionError(render_frame_id, cdm_id, session_id);
return;
}
cdm->UpdateSession(session_id, &response[0], response.size());
}
-void BrowserCdmManager::OnReleaseSession(int cdm_id, uint32 session_id) {
- BrowserCdm* cdm = GetCdm(cdm_id);
+void BrowserCdmManager::OnReleaseSession(int render_frame_id,
+ int cdm_id,
+ uint32 session_id) {
+ BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
- DLOG(WARNING) << "No CDM for ID " << cdm_id << " found";
- OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
+ DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
+ SendSessionError(render_frame_id, cdm_id, session_id);
return;
}
cdm->ReleaseSession(session_id);
}
-void BrowserCdmManager::OnDestroyCdm(int cdm_id) {
- BrowserCdm* cdm = GetCdm(cdm_id);
- if (!cdm)
- return;
-
- CancelAllPendingSessionCreations(cdm_id);
- RemoveCdm(cdm_id);
+void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) {
+ RemoveCdm(GetId(render_frame_id, cdm_id));
}
-void BrowserCdmManager::CancelAllPendingSessionCreations(int cdm_id) {
- if (cdm_cancel_permision_map_.count(cdm_id)) {
- cdm_cancel_permision_map_[cdm_id].Run();
- cdm_cancel_permision_map_.erase(cdm_id);
- }
+void BrowserCdmManager::SendSessionError(int render_frame_id,
+ int cdm_id,
+ uint32 session_id) {
+ OnSessionError(
+ render_frame_id, cdm_id, session_id, MediaKeys::kUnknownError, 0);
}
-void BrowserCdmManager::AddCdm(int cdm_id,
+#define BROWSER_CDM_MANAGER_CB(func) \
+ base::Bind(&BrowserCdmManager::func, this, render_frame_id, cdm_id)
+
+void BrowserCdmManager::AddCdm(int render_frame_id,
+ int cdm_id,
const std::string& key_system,
const GURL& security_origin) {
- DCHECK(!GetCdm(cdm_id));
- base::WeakPtr<BrowserCdmManager> weak_this = weak_ptr_factory_.GetWeakPtr();
- scoped_ptr<BrowserCdm> cdm(media::CreateBrowserCdm(
- key_system,
- base::Bind(&BrowserCdmManager::OnSessionCreated, weak_this, cdm_id),
- base::Bind(&BrowserCdmManager::OnSessionMessage, weak_this, cdm_id),
- base::Bind(&BrowserCdmManager::OnSessionReady, weak_this, cdm_id),
- base::Bind(&BrowserCdmManager::OnSessionClosed, weak_this, cdm_id),
- base::Bind(&BrowserCdmManager::OnSessionError, weak_this, cdm_id)));
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
+ DCHECK(!GetCdm(render_frame_id, cdm_id));
+
+ scoped_ptr<BrowserCdm> cdm(
+ media::CreateBrowserCdm(key_system,
+ BROWSER_CDM_MANAGER_CB(OnSessionCreated),
+ BROWSER_CDM_MANAGER_CB(OnSessionMessage),
+ BROWSER_CDM_MANAGER_CB(OnSessionReady),
+ BROWSER_CDM_MANAGER_CB(OnSessionClosed),
+ BROWSER_CDM_MANAGER_CB(OnSessionError)));
if (!cdm) {
// This failure will be discovered and reported by OnCreateSession()
@@ -238,44 +340,39 @@ void BrowserCdmManager::AddCdm(int cdm_id,
return;
}
- cdm_map_.add(cdm_id, cdm.Pass());
- cdm_security_origin_map_[cdm_id] = security_origin;
+ uint64 id = GetId(render_frame_id, cdm_id);
+ cdm_map_.add(id, cdm.Pass());
+ cdm_security_origin_map_[id] = security_origin;
}
-void BrowserCdmManager::RemoveCdm(int cdm_id) {
- // TODO(xhwang): Detach CDM from the player it's set to. In prefixed
- // EME implementation the current code is fine because we always destroy the
- // player before we destroy the DrmBridge. This will not always be the case
- // in unprefixed EME implementation.
- cdm_map_.erase(cdm_id);
- cdm_security_origin_map_.erase(cdm_id);
- cdm_cancel_permision_map_.erase(cdm_id);
-}
-
-int BrowserCdmManager::RoutingID() {
- return render_frame_host_->GetRoutingID();
-}
+void BrowserCdmManager::RemoveCdm(uint64 id) {
+ DCHECK(task_runner_->RunsTasksOnCurrentThread());
-bool BrowserCdmManager::Send(IPC::Message* msg) {
- return render_frame_host_->Send(msg);
+ cdm_map_.erase(id);
+ cdm_security_origin_map_.erase(id);
+ if (cdm_cancel_permission_map_.count(id)) {
+ cdm_cancel_permission_map_[id].Run();
+ cdm_cancel_permission_map_.erase(id);
+ }
}
void BrowserCdmManager::CreateSessionIfPermitted(
+ int render_frame_id,
int cdm_id,
uint32 session_id,
const std::string& content_type,
const std::vector<uint8>& init_data,
bool permitted) {
- cdm_cancel_permision_map_.erase(cdm_id);
+ cdm_cancel_permission_map_.erase(GetId(render_frame_id, cdm_id));
if (!permitted) {
- OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
+ SendSessionError(render_frame_id, cdm_id, session_id);
return;
}
- BrowserCdm* cdm = GetCdm(cdm_id);
+ BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
if (!cdm) {
- DLOG(WARNING) << "No CDM for ID: " << cdm_id << " found";
- OnSessionError(cdm_id, session_id, MediaKeys::kUnknownError, 0);
+ DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
+ SendSessionError(render_frame_id, cdm_id, session_id);
return;
}
diff --git a/chromium/content/browser/media/cdm/browser_cdm_manager.h b/chromium/content/browser/media/cdm/browser_cdm_manager.h
index 85be4c182a5..27fb5c93e83 100644
--- a/chromium/content/browser/media/cdm/browser_cdm_manager.h
+++ b/chromium/content/browser/media/cdm/browser_cdm_manager.h
@@ -15,6 +15,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
#include "content/common/media/cdm_messages_enums.h"
+#include "content/public/browser/browser_message_filter.h"
#include "ipc/ipc_message.h"
// TODO(xhwang): Drop this when KeyError is moved to a common header.
#include "media/base/media_keys.h"
@@ -26,99 +27,120 @@ class BrowserCdm;
namespace content {
-class RenderFrameHost;
-class WebContents;
-
// This class manages all CDM objects. It receives control operations from the
// the render process, and forwards them to corresponding CDM object. Callbacks
// from CDM objects are converted to IPCs and then sent to the render process.
-class CONTENT_EXPORT BrowserCdmManager {
+class CONTENT_EXPORT BrowserCdmManager : public BrowserMessageFilter {
public:
- // Creates a new BrowserCdmManager for |rfh|.
- static BrowserCdmManager* Create(RenderFrameHost* rfh);
-
- ~BrowserCdmManager();
-
- media::BrowserCdm* GetCdm(int cdm_id);
+ // Returns the BrowserCdmManager associated with the |render_process_id|.
+ // Returns NULL if no BrowserCdmManager is associated.
+ static BrowserCdmManager* FromProcess(int render_process_id);
+
+ // Constructs the BrowserCdmManager for |render_process_id| which runs on
+ // |task_runner|.
+ // If |task_runner| is not NULL, all CDM messages are posted to it. Otherwise,
+ // all messages are posted to the browser UI thread.
+ BrowserCdmManager(int render_process_id,
+ const scoped_refptr<base::TaskRunner>& task_runner);
+
+ // BrowserMessageFilter implementations.
+ virtual void OnDestruct() const override;
+ virtual base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+ virtual bool OnMessageReceived(const IPC::Message& message) override;
+
+ media::BrowserCdm* GetCdm(int render_frame_id, int cdm_id);
+
+ // Notifies that the render frame has been deleted so that all CDMs belongs
+ // to this render frame needs to be destroyed as well. This is needed because
+ // in some cases (e.g. fast termination of the renderer), the message to
+ // destroy the CDM will not be received.
+ void RenderFrameDeleted(int render_frame_id);
+
+ protected:
+ friend class base::RefCountedThreadSafe<BrowserCdmManager>;
+ friend class base::DeleteHelper<BrowserCdmManager>;
+ virtual ~BrowserCdmManager();
+ private:
// CDM callbacks.
- void OnSessionCreated(int cdm_id,
+ void OnSessionCreated(int render_frame_id,
+ int cdm_id,
uint32 session_id,
const std::string& web_session_id);
- void OnSessionMessage(int cdm_id,
+ void OnSessionMessage(int render_frame_id,
+ int cdm_id,
uint32 session_id,
const std::vector<uint8>& message,
const GURL& destination_url);
- void OnSessionReady(int cdm_id, uint32 session_id);
- void OnSessionClosed(int cdm_id, uint32 session_id);
- void OnSessionError(int cdm_id,
+ void OnSessionReady(int render_frame_id, int cdm_id, uint32 session_id);
+ void OnSessionClosed(int render_frame_id, int cdm_id, uint32 session_id);
+ void OnSessionError(int render_frame_id,
+ int cdm_id,
uint32 session_id,
media::MediaKeys::KeyError error_code,
uint32 system_code);
// Message handlers.
- void OnInitializeCdm(int cdm_id,
+ void OnInitializeCdm(int render_frame_id,
+ int cdm_id,
const std::string& key_system,
const GURL& frame_url);
- void OnCreateSession(int cdm_id,
+ void OnCreateSession(int render_frame_id,
+ int cdm_id,
uint32 session_id,
CdmHostMsg_CreateSession_ContentType content_type,
const std::vector<uint8>& init_data);
- void OnUpdateSession(int cdm_id,
+ void OnUpdateSession(int render_frame_id,
+ int cdm_id,
uint32 session_id,
const std::vector<uint8>& response);
- void OnReleaseSession(int cdm_id, uint32 session_id);
- void OnSetCdm(int player_id, int cdm_id);
- void OnDestroyCdm(int cdm_id);
-
- private:
- // Clients must use Create() or subclass constructor.
- explicit BrowserCdmManager(RenderFrameHost* render_frame_host);
+ void OnReleaseSession(int render_frame_id,
+ int cdm_id, uint32 session_id);
+ void OnDestroyCdm(int render_frame_id, int cdm_id);
- // Cancels all pending session creations associated with |cdm_id|.
- void CancelAllPendingSessionCreations(int cdm_id);
+ void SendSessionError(int render_frame_id, int cdm_id, uint32 session_id);
// Adds a new CDM identified by |cdm_id| for the given |key_system| and
// |security_origin|.
- void AddCdm(int cdm_id,
+ void AddCdm(int render_frame_id,
+ int cdm_id,
const std::string& key_system,
const GURL& security_origin);
// Removes the CDM with the specified id.
- void RemoveCdm(int cdm_id);
-
- int RoutingID();
-
- // Helper function to send messages to RenderFrameObserver.
- bool Send(IPC::Message* msg);
+ void RemoveCdm(uint64 id);
// If |permitted| is false, it does nothing but send
// |CdmMsg_SessionError| IPC message.
// The primary use case is infobar permission callback, i.e., when infobar
// can decide user's intention either from interacting with the actual info
// bar or from the saved preference.
- void CreateSessionIfPermitted(int cdm_id,
+ void CreateSessionIfPermitted(int render_frame_id,
+ int cdm_id,
uint32 session_id,
const std::string& content_type,
const std::vector<uint8>& init_data,
bool permitted);
- RenderFrameHost* const render_frame_host_;
+ const int render_process_id_;
- WebContents* const web_contents_;
+ // TaskRunner to dispatch all CDM messages to. If it's NULL, all messages are
+ // dispatched to the browser UI thread.
+ scoped_refptr<base::TaskRunner> task_runner_;
- // A map from CDM IDs to managed CDMs.
- typedef base::ScopedPtrHashMap<int, media::BrowserCdm> CdmMap;
- CdmMap cdm_map_;
+ // The key in the following maps is a combination of |render_frame_id| and
+ // |cdm_id|.
- // Map from CDM ID to CDM's security origin.
- std::map<int, GURL> cdm_security_origin_map_;
+ // Map of managed BrowserCdms.
+ typedef base::ScopedPtrHashMap<uint64, media::BrowserCdm> CdmMap;
+ CdmMap cdm_map_;
- // Map from CDM ID to a callback to cancel the permission request.
- std::map<int, base::Closure> cdm_cancel_permision_map_;
+ // Map of CDM's security origin.
+ std::map<uint64, GURL> cdm_security_origin_map_;
- // NOTE: Weak pointers must be invalidated before all other member variables.
- base::WeakPtrFactory<BrowserCdmManager> weak_ptr_factory_;
+ // Map of callbacks to cancel the permission request.
+ std::map<uint64, base::Closure> cdm_cancel_permission_map_;
DISALLOW_COPY_AND_ASSIGN(BrowserCdmManager);
};
diff --git a/chromium/content/browser/media/encrypted_media_browsertest.cc b/chromium/content/browser/media/encrypted_media_browsertest.cc
index 9c0dbac6351..3d561424107 100644
--- a/chromium/content/browser/media/encrypted_media_browsertest.cc
+++ b/chromium/content/browser/media/encrypted_media_browsertest.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "base/command_line.h"
-#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h"
#include "content/browser/media/media_browsertest.h"
@@ -26,6 +25,8 @@ const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\"";
const char kEmeKeyError[] = "KEYERROR";
const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
+const char kDefaultEmePlayer[] = "eme_player.html";
+
// The type of video src used to load media.
enum SrcType {
SRC,
@@ -52,7 +53,7 @@ class EncryptedMediaTest : public content::MediaBrowserTest,
public testing::WithParamInterface<std::tr1::tuple<const char*, SrcType> > {
public:
// Can only be used in parameterized (*_P) tests.
- const char* CurrentKeySystem() {
+ const std::string CurrentKeySystem() {
return std::tr1::get<0>(GetParam());
}
@@ -61,14 +62,15 @@ class EncryptedMediaTest : public content::MediaBrowserTest,
return std::tr1::get<1>(GetParam());
}
- void TestSimplePlayback(const char* encrypted_media, const char* media_type) {
+ void TestSimplePlayback(const std::string& encrypted_media,
+ const std::string& media_type) {
RunSimpleEncryptedMediaTest(
encrypted_media, media_type, CurrentKeySystem(), CurrentSourceType());
}
void TestFrameSizeChange() {
RunEncryptedMediaTest("encrypted_frame_size_change.html",
- "frame_size_change-av-enc-v.webm", kWebMAudioVideo,
+ "frame_size_change-av_enc-v.webm", kWebMAudioVideo,
CurrentKeySystem(), CurrentSourceType(), kEnded);
}
@@ -78,50 +80,56 @@ class EncryptedMediaTest : public content::MediaBrowserTest,
return;
}
- std::vector<StringPair> query_params;
- query_params.push_back(std::make_pair("keysystem", CurrentKeySystem()));
- query_params.push_back(std::make_pair("runencrypted", "1"));
- RunMediaTestPage("mse_config_change.html", &query_params, kEnded, true);
+ base::StringPairs query_params;
+ query_params.push_back(std::make_pair("keySystem", CurrentKeySystem()));
+ query_params.push_back(std::make_pair("runEncrypted", "1"));
+ query_params.push_back(std::make_pair("usePrefixedEME", "1"));
+ RunMediaTestPage("mse_config_change.html", query_params, kEnded, true);
}
- void RunEncryptedMediaTest(const char* html_page,
- const char* media_file,
- const char* media_type,
- const char* key_system,
+ void RunEncryptedMediaTest(const std::string& html_page,
+ const std::string& media_file,
+ const std::string& media_type,
+ const std::string& key_system,
SrcType src_type,
- const char* expectation) {
+ const std::string& expectation) {
if (src_type == MSE && !IsMSESupported()) {
VLOG(0) << "Skipping test - MSE not supported.";
return;
}
- std::vector<StringPair> query_params;
- query_params.push_back(std::make_pair("mediafile", media_file));
- query_params.push_back(std::make_pair("mediatype", media_type));
- query_params.push_back(std::make_pair("keysystem", key_system));
+ base::StringPairs query_params;
+ query_params.push_back(std::make_pair("mediaFile", media_file));
+ query_params.push_back(std::make_pair("mediaType", media_type));
+ query_params.push_back(std::make_pair("keySystem", key_system));
if (src_type == MSE)
- query_params.push_back(std::make_pair("usemse", "1"));
- RunMediaTestPage(html_page, &query_params, expectation, true);
+ query_params.push_back(std::make_pair("useMSE", "1"));
+ query_params.push_back(std::make_pair("usePrefixedEME", "1"));
+ RunMediaTestPage(html_page, query_params, expectation, true);
}
- void RunSimpleEncryptedMediaTest(const char* media_file,
- const char* media_type,
- const char* key_system,
+ void RunSimpleEncryptedMediaTest(const std::string& media_file,
+ const std::string& media_type,
+ const std::string& key_system,
SrcType src_type) {
- RunEncryptedMediaTest("encrypted_media_player.html", media_file,
- media_type, key_system, src_type, kEnded);
+ RunEncryptedMediaTest(kDefaultEmePlayer,
+ media_file,
+ media_type,
+ key_system,
+ src_type,
+ kEnded);
}
protected:
// We want to fail quickly when a test fails because an error is encountered.
- virtual void AddWaitForTitles(content::TitleWatcher* title_watcher) OVERRIDE {
+ void AddWaitForTitles(content::TitleWatcher* title_watcher) override {
MediaBrowserTest::AddWaitForTitles(title_watcher);
title_watcher->AlsoWaitForTitle(base::ASCIIToUTF16(kEmeNotSupportedError));
title_watcher->AlsoWaitForTitle(base::ASCIIToUTF16(kEmeKeyError));
}
#if defined(OS_ANDROID)
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ virtual void SetUpCommandLine(CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kDisableGestureRequirementForMediaPlayback);
}
@@ -141,23 +149,23 @@ INSTANTIATE_TEST_CASE_P(MSE_ClearKey, EncryptedMediaTest,
Combine(Values(kClearKeyKeySystem), Values(MSE)));
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) {
- TestSimplePlayback("bear-a-enc_a.webm", kWebMAudioOnly);
+ TestSimplePlayback("bear-a_enc-a.webm", kWebMAudioOnly);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) {
- TestSimplePlayback("bear-320x240-av-enc_a.webm", kWebMAudioVideo);
+ TestSimplePlayback("bear-320x240-av_enc-a.webm", kWebMAudioVideo);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {
- TestSimplePlayback("bear-320x240-av-enc_av.webm", kWebMAudioVideo);
+ TestSimplePlayback("bear-320x240-av_enc-av.webm", kWebMAudioVideo);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM) {
- TestSimplePlayback("bear-320x240-v-enc_v.webm", kWebMVideoOnly);
+ TestSimplePlayback("bear-320x240-v_enc-v.webm", kWebMVideoOnly);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
- TestSimplePlayback("bear-320x240-av-enc_v.webm", kWebMAudioVideo);
+ TestSimplePlayback("bear-320x240-av_enc-v.webm", kWebMAudioVideo);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo) {
@@ -174,8 +182,11 @@ IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
}
IN_PROC_BROWSER_TEST_F(EncryptedMediaTest, UnknownKeySystemThrowsException) {
- RunEncryptedMediaTest("encrypted_media_player.html", "bear-a-enc_a.webm",
- kWebMAudioOnly, "com.example.foo", MSE,
+ RunEncryptedMediaTest(kDefaultEmePlayer,
+ "bear-a_enc-a.webm",
+ kWebMAudioOnly,
+ "com.example.foo",
+ MSE,
kEmeNotSupportedError);
}
diff --git a/chromium/content/browser/media/media_browsertest.cc b/chromium/content/browser/media/media_browsertest.cc
index bdd77096bc3..46f7a49b618 100644
--- a/chromium/content/browser/media/media_browsertest.cc
+++ b/chromium/content/browser/media/media_browsertest.cc
@@ -4,13 +4,14 @@
#include "content/browser/media/media_browsertest.h"
-#include "base/strings/stringprintf.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/web_contents.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/shell/browser/shell.h"
+#include "media/base/test_data_util.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
// TODO(wolenetz): Fix Media.YUV* tests on MSVS 2012 x64. crbug.com/180074
#if defined(OS_WIN) && defined(ARCH_CPU_X86_64) && _MSC_VER == 1700
@@ -26,39 +27,37 @@ const char MediaBrowserTest::kEnded[] = "ENDED";
const char MediaBrowserTest::kError[] = "ERROR";
const char MediaBrowserTest::kFailed[] = "FAILED";
-void MediaBrowserTest::RunMediaTestPage(
- const char* html_page, std::vector<StringPair>* query_params,
- const char* expected, bool http) {
+void MediaBrowserTest::RunMediaTestPage(const std::string& html_page,
+ const base::StringPairs& query_params,
+ const std::string& expected_title,
+ bool http) {
GURL gurl;
- std::string query = "";
- if (query_params != NULL && !query_params->empty()) {
- std::vector<StringPair>::const_iterator itr = query_params->begin();
- query = base::StringPrintf("%s=%s", itr->first, itr->second);
- ++itr;
- for (; itr != query_params->end(); ++itr) {
- query.append(base::StringPrintf("&%s=%s", itr->first, itr->second));
- }
- }
+ std::string query = media::GetURLQueryString(query_params);
+ scoped_ptr<net::SpawnedTestServer> http_test_server;
if (http) {
- ASSERT_TRUE(test_server()->Start());
- gurl = test_server()->GetURL(
- base::StringPrintf("files/media/%s?%s", html_page, query.c_str()));
+ http_test_server.reset(
+ new net::SpawnedTestServer(net::SpawnedTestServer::TYPE_HTTP,
+ net::SpawnedTestServer::kLocalhost,
+ media::GetTestDataPath()));
+ CHECK(http_test_server->Start());
+ gurl = http_test_server->GetURL("files/" + html_page + "?" + query);
} else {
- base::FilePath test_file_path = GetTestFilePath("media", html_page);
- gurl = GetFileUrlWithQuery(test_file_path, query);
+ gurl = content::GetFileUrlWithQuery(media::GetTestDataFilePath(html_page),
+ query);
}
- RunTest(gurl, expected);
+ std::string final_title = RunTest(gurl, expected_title);
+ EXPECT_EQ(expected_title, final_title);
}
-void MediaBrowserTest::RunTest(const GURL& gurl, const char* expected) {
- const base::string16 expected_title = base::ASCIIToUTF16(expected);
- DVLOG(1) << "Running test URL: " << gurl;
- TitleWatcher title_watcher(shell()->web_contents(), expected_title);
+std::string MediaBrowserTest::RunTest(const GURL& gurl,
+ const std::string& expected_title) {
+ VLOG(0) << "Running test URL: " << gurl;
+ TitleWatcher title_watcher(shell()->web_contents(),
+ base::ASCIIToUTF16(expected_title));
AddWaitForTitles(&title_watcher);
NavigateToURL(shell(), gurl);
-
- base::string16 final_title = title_watcher.WaitAndGetTitle();
- EXPECT_EQ(expected_title, final_title);
+ base::string16 result = title_watcher.WaitAndGetTitle();
+ return base::UTF16ToASCII(result);
}
void MediaBrowserTest::AddWaitForTitles(content::TitleWatcher* title_watcher) {
@@ -75,25 +74,39 @@ class MediaTest : public testing::WithParamInterface<bool>,
public MediaBrowserTest {
public:
// Play specified audio over http:// or file:// depending on |http| setting.
- void PlayAudio(const char* media_file, bool http) {
+ void PlayAudio(const std::string& media_file, bool http) {
PlayMedia("audio", media_file, http);
}
// Play specified video over http:// or file:// depending on |http| setting.
- void PlayVideo(const char* media_file, bool http) {
+ void PlayVideo(const std::string& media_file, bool http) {
PlayMedia("video", media_file, http);
}
// Run specified color format test with the expected result.
- void RunColorFormatTest(const char* media_file, const char* expected) {
- base::FilePath test_file_path = GetTestFilePath("media", "blackwhite.html");
+ void RunColorFormatTest(const std::string& media_file,
+ const std::string& expected) {
+ base::FilePath test_file_path =
+ media::GetTestDataFilePath("blackwhite.html");
RunTest(GetFileUrlWithQuery(test_file_path, media_file), expected);
}
- void PlayMedia(const char* tag, const char* media_file, bool http) {
- std::vector<StringPair> query_params;
+ void PlayMedia(const std::string& tag,
+ const std::string& media_file,
+ bool http) {
+ base::StringPairs query_params;
query_params.push_back(std::make_pair(tag, media_file));
- RunMediaTestPage("player.html", &query_params, kEnded, http);
+ RunMediaTestPage("player.html", query_params, kEnded, http);
+ }
+
+ void RunVideoSizeTest(const char* media_file, int width, int height) {
+ std::string expected;
+ expected += base::IntToString(width);
+ expected += " ";
+ expected += base::IntToString(height);
+ base::StringPairs query_params;
+ query_params.push_back(std::make_pair("video", media_file));
+ RunMediaTestPage("player.html", query_params, expected, false);
}
};
@@ -140,7 +153,23 @@ IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMovPcmS16be) {
IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMovPcmS24be) {
PlayVideo("bear_pcm_s24be.mov", GetParam());
}
-#endif
+
+IN_PROC_BROWSER_TEST_F(MediaTest, VideoBearRotated0) {
+ RunVideoSizeTest("bear_rotate_0.mp4", 1280, 720);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaTest, VideoBearRotated90) {
+ RunVideoSizeTest("bear_rotate_90.mp4", 720, 1280);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaTest, VideoBearRotated180) {
+ RunVideoSizeTest("bear_rotate_180.mp4", 1280, 720);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaTest, VideoBearRotated270) {
+ RunVideoSizeTest("bear_rotate_270.mp4", 720, 1280);
+}
+#endif // defined(USE_PROPRIETARY_CODECS)
#if defined(OS_CHROMEOS)
#if defined(USE_PROPRIETARY_CODECS)
@@ -171,8 +200,9 @@ IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearWavGsmms) {
IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearFlac) {
PlayAudio("bear.flac", GetParam());
}
-#endif
-#endif
+#endif // defined(USE_PROPRIETARY_CODECS)
+#endif // defined(OS_CHROMEOS)
+
IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearWavAlaw) {
PlayAudio("bear_alaw.wav", GetParam());
@@ -209,19 +239,19 @@ INSTANTIATE_TEST_CASE_P(File, MediaTest, ::testing::Values(false));
INSTANTIATE_TEST_CASE_P(Http, MediaTest, ::testing::Values(true));
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv420pTheora)) {
- RunColorFormatTest("yuv420p.ogv", "ENDED");
+ RunColorFormatTest("yuv420p.ogv", kEnded);
}
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv422pTheora)) {
- RunColorFormatTest("yuv422p.ogv", "ENDED");
+ RunColorFormatTest("yuv422p.ogv", kEnded);
}
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv444pTheora)) {
- RunColorFormatTest("yuv444p.ogv", "ENDED");
+ RunColorFormatTest("yuv444p.ogv", kEnded);
}
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv420pVp8)) {
- RunColorFormatTest("yuv420p.webm", "ENDED");
+ RunColorFormatTest("yuv420p.webm", kEnded);
}
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv444pVp9)) {
@@ -230,24 +260,24 @@ IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv444pVp9)) {
#if defined(USE_PROPRIETARY_CODECS)
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv420pH264)) {
- RunColorFormatTest("yuv420p.mp4", "ENDED");
+ RunColorFormatTest("yuv420p.mp4", kEnded);
}
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuvj420pH264)) {
- RunColorFormatTest("yuvj420p.mp4", "ENDED");
+ RunColorFormatTest("yuvj420p.mp4", kEnded);
}
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv422pH264)) {
- RunColorFormatTest("yuv422p.mp4", "ENDED");
+ RunColorFormatTest("yuv422p.mp4", kEnded);
}
IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv444pH264)) {
- RunColorFormatTest("yuv444p.mp4", "ENDED");
+ RunColorFormatTest("yuv444p.mp4", kEnded);
}
#if defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(MediaTest, Yuv420pMpeg4) {
- RunColorFormatTest("yuv420p.avi", "ENDED");
+ RunColorFormatTest("yuv420p.avi", kEnded);
}
#endif // defined(OS_CHROMEOS)
#endif // defined(USE_PROPRIETARY_CODECS)
diff --git a/chromium/content/browser/media/media_browsertest.h b/chromium/content/browser/media/media_browsertest.h
index b242db30259..caf5d147c76 100644
--- a/chromium/content/browser/media/media_browsertest.h
+++ b/chromium/content/browser/media/media_browsertest.h
@@ -5,10 +5,10 @@
#ifndef CONTENT_BROWSER_MEDIA_MEDIA_BROWSERTEST_H_
#define CONTENT_BROWSER_MEDIA_MEDIA_BROWSERTEST_H_
-#include <utility>
-#include <vector>
+#include <string>
#include "content/public/test/content_browser_test.h"
+#include "media/base/test_data_util.h"
namespace content {
@@ -19,8 +19,6 @@ class TitleWatcher;
// the test http server.
class MediaBrowserTest : public ContentBrowserTest {
public:
- typedef std::pair<const char*, const char*> StringPair;
-
// Common test results.
static const char kEnded[];
static const char kError[];
@@ -30,17 +28,18 @@ class MediaBrowserTest : public ContentBrowserTest {
// If http is true, the test starts a local http test server to load the test
// page, otherwise a local file URL is loaded inside the content shell.
// It uses RunTest() to check for expected test output.
- void RunMediaTestPage(const char* html_page,
- std::vector<StringPair>* query_params,
- const char* expected, bool http);
+ void RunMediaTestPage(const std::string& html_page,
+ const base::StringPairs& query_params,
+ const std::string& expected,
+ bool http);
// Opens a URL and waits for the document title to match either one of the
- // default strings or the expected string.
- void RunTest(const GURL& gurl, const char* expected);
+ // default strings or the expected string. Returns the matching title value.
+ std::string RunTest(const GURL& gurl, const std::string& expected);
virtual void AddWaitForTitles(content::TitleWatcher* title_watcher);
};
-} // namespace content
+} // namespace content
#endif // CONTENT_BROWSER_MEDIA_MEDIA_BROWSERTEST_H_
diff --git a/chromium/content/browser/media/media_canplaytype_browsertest.cc b/chromium/content/browser/media/media_canplaytype_browsertest.cc
index cfcfd5ae2c5..e454de461ec 100644
--- a/chromium/content/browser/media/media_canplaytype_browsertest.cc
+++ b/chromium/content/browser/media/media_canplaytype_browsertest.cc
@@ -32,20 +32,11 @@ const char kOggVideoProbably[] = "probably";
const char kOggVideoMaybe[] = "maybe";
const char kTheoraProbably[] = "probably";
const char kOpusProbably[] = "probably";
-#if defined(USE_PROPRIETARY_CODECS)
-const char kTheoraAndPropProbably[] = "probably";
-const char kOpusAndPropProbably[] = "probably";
-#else
-const char kTheoraAndPropProbably[] = "";
-const char kOpusAndPropProbably[] = "";
-#endif // USE_PROPRIETARY_CODECS
#else
const char kOggVideoProbably[] = "";
const char kOggVideoMaybe[] = "";
const char kTheoraProbably[] = "";
const char kOpusProbably[] = "";
-const char kTheoraAndPropProbably[] = "maybe";
-const char kOpusAndPropProbably[] = "maybe";
#endif // !OS_ANDROID
namespace content {
@@ -54,9 +45,7 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
public:
MediaCanPlayTypeTest() : url_("about:blank") { }
- virtual void SetUpOnMainThread() OVERRIDE {
- NavigateToURL(shell(), url_);
- }
+ void SetUpOnMainThread() override { NavigateToURL(shell(), url_); }
std::string CanPlay(const std::string& type) {
std::string command("document.createElement('video').canPlayType(");
@@ -71,6 +60,177 @@ public:
return result;
}
+ void TestMPEGUnacceptableCombinations(std::string mime) {
+ // Codecs must be followed by valid hexadecimal number.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.unknown\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.unknown\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.unknown\"'"));
+
+ // Codecs must not end with a dot.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.40.\"'"));
+
+ // Codecs not belonging to MPEG container.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E, vorbis\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F, vorbis\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1.4D401E, opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3.64001F, opus\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9\"'"));
+ 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, mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp9, mp4a.40.2\"'"));
+
+ 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\"'"));
+
+ // Codecs are case sensitive.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"AVC1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"AVC1.4d401e\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"AVC3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"AVC3.64001f\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"MP4A\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"MP4A.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"AVC1, MP4\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"AVC3, MP4\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'" + mime + "; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'" + mime + "; codecs=\", AVC3.64001F, MP4.40.2\"'"));
+
+ // Unknown codecs.
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc4\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc1x\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3x\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4ax\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"unknown\"'"));
+ }
+
+ void TestOGGUnacceptableCombinations(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, 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=\"mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, mp4a.40.2\"'"));
+
+ 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\"'"));
+
+ // Unknown codecs.
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
+ }
+
+ void TestWEBMUnacceptableCombinations(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, 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=\"mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
+ 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\"'"));
+
+ // 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\"'"));
+
+ // Unknown codec.
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
+ }
+
+ void TestWAVUnacceptableCombinations(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, 1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"avc3, 1\"'"));
+
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
+
+ // Unknown codec.
+ EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
+ }
+
private:
GURL url_;
DISALLOW_COPY_AND_ASSIGN(MediaCanPlayTypeTest);
@@ -80,60 +240,12 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_wav) {
EXPECT_EQ(kMaybe, CanPlay("'audio/wav'"));
EXPECT_EQ(kProbably, CanPlay("'audio/wav; codecs=\"1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"theora\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"vp9.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"opus\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"mp4a.40.5\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"1, mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"1, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"1, theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"1, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"opus, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"opus, theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"vorbis, mp4a\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/wav; codecs=\"unknown\"'"));
+ TestWAVUnacceptableCombinations("audio/wav");
EXPECT_EQ(kMaybe, CanPlay("'audio/x-wav'"));
EXPECT_EQ(kProbably, CanPlay("'audio/x-wav; codecs=\"1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"theora\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"vp9.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"opus\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"mp4a.40.5\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"1, mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"1, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"1, theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"1, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"opus, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"opus, theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"vorbis, mp4a\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-wav; codecs=\"unknown\"'"));
+ TestWAVUnacceptableCombinations("audio/x-wav");
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_webm) {
@@ -164,41 +276,8 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_webm) {
EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp8, vp9\"'"));
EXPECT_EQ(VP9Probably, CanPlay("'video/webm; codecs=\"vp8.0, vp9.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp8, theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp8, avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp9, avc3\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp8, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp8.0, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp8, mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp8.0, mp4a.40.2\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp9, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp9.0, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp9, mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp9.0, mp4a.40.2\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"1\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"mp4a.40.2\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"VP8\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"VP8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"VP9\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"Vp9.0\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"VP8, Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp8, Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"VP9, Opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"vp9, Opus\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/webm; codecs=\"unknown\"'"));
+
+ TestWEBMUnacceptableCombinations("video/webm");
EXPECT_EQ(kMaybe, CanPlay("'audio/webm'"));
EXPECT_EQ(kProbably, CanPlay("'audio/webm; codecs=\"vorbis\"'"));
@@ -219,19 +298,7 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_webm) {
EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"vp9, opus\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"vp9.0, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"1, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"1, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"vorbis, mp4a\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"mp4a.40.2\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/webm; codecs=\"unknown\"'"));
+ TestWEBMUnacceptableCombinations("audio/webm");
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_ogg) {
@@ -244,37 +311,7 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_ogg) {
EXPECT_EQ(kOggVideoProbably,
CanPlay("'video/ogg; codecs=\"opus, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"vp9.0\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc1, mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc1, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc3, mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc3, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc1, vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc3, vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc1, avc3\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"mp4a.4.02\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc1.4D401E, mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc3.64001F, mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc1.4D401E, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"avc3.64001F, vorbis\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"Theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"Opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"Theora, Opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"Theora, Vorbis\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'video/ogg; codecs=\"unknown\"'"));
+ TestOGGUnacceptableCombinations("video/ogg");
EXPECT_EQ(kMaybe, CanPlay("'audio/ogg'"));
EXPECT_EQ(kProbably, CanPlay("'audio/ogg; codecs=\"vorbis\"'"));
@@ -282,30 +319,10 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_ogg) {
EXPECT_EQ(kOpusProbably, CanPlay("'audio/ogg; codecs=\"vorbis, opus\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"theora, vorbis\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"theora, opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"opus, 1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"vorbis, 1\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"vp9.0\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"mp4a.40.2\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"Theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"Opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"Theora, Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"Theora, Opus\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"theora, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/ogg; codecs=\"unknown\"'"));
+ TestOGGUnacceptableCombinations("audio/ogg");
EXPECT_EQ(kMaybe, CanPlay("'application/ogg'"));
EXPECT_EQ(kProbably, CanPlay("'application/ogg; codecs=\"vorbis\"'"));
@@ -318,39 +335,7 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_ogg) {
EXPECT_EQ(kOpusProbably,
CanPlay("'application/ogg; codecs=\"opus, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"vp9.0\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc1\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc3\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc1, mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc1, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc3, mp4a\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc3, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc1, vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc3, vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc1, avc3\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(kNot,
- CanPlay("'application/ogg; codecs=\"avc1.4D401E, mp4a.40.2\"'"));
- EXPECT_EQ(kNot,
- CanPlay("'application/ogg; codecs=\"avc3.64001F, mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc1.4D401E, vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"avc3.64001F, vorbis\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"Theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"Opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"Theora, Vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"Theora, Opus\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'application/ogg; codecs=\"unknown\"'"));
+ TestOGGUnacceptableCombinations("application/ogg");
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
@@ -374,41 +359,7 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.unknown\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc1.\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc3.\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"vp9.0\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"AVC1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"AVC3\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"MP4A\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"AVC3, MP4\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\", AVC3.64001F, MP4.40.2\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc4\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc1x\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc3x\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4ax\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"unknown\"'"));
+ TestMPEGUnacceptableCombinations("audio/mpeg");
// audio/mp3 does not allow any codecs parameter
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp3'"));
@@ -422,41 +373,7 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.unknown\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc1.\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc3.\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4a.\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"vp9.0\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"AVC1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"AVC3\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"MP4A\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"AVC3, MP4\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\", AVC3.64001F, MP4.40.2\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc4\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc1x\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc3x\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp4ax\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"unknown\"'"));
+ TestMPEGUnacceptableCombinations("audio/mp3");
// audio/x-mp3 does not allow any codecs parameter
EXPECT_EQ(kPropProbably, CanPlay("'audio/x-mp3'"));
@@ -470,596 +387,212 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp3) {
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4a.unknown\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"vorbis\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"opus\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"theora\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"vp8\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"vp8.0\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"vp9\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"vp9.0\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"AVC1\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"AVC3\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"MP4A\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"AVC3, MP4\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\", AVC3.64001F, MP4.40.2\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc2\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc4\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc1x\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc3x\"'"));
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"mp4ax\"'"));
-
- EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"unknown\"'"));
+ TestMPEGUnacceptableCombinations("audio/x-mp3");
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
- // TODO(amogh.bihani): Change this expectation when bug 53193 is fixed.
- std::string PropAndVP9Probably = "";
-#if defined (OS_ANDROID)
- if (base::android::BuildInfo::GetInstance()->sdk_int() < 19)
- PropAndVP9Probably = "maybe";
- else
- PropAndVP9Probably = "probably";
-#else
-#if defined(USE_PROPRIETARY_CODECS)
- PropAndVP9Probably = "probably";
-#endif // USE_PROPRIETARY_CODECS
-#endif // OS_ANDROID
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1, avc3\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'video/mp4; codecs=\"avc1.4D401E, mp4a.40.2\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'video/mp4; codecs=\"avc3.64001F, mp4a.40.5\"'"));
-
- // TODO(amogh.bihani): Change these tests when bug 53193 is fixed.
- // http://crbug.com/53193 ----------------------------------------------------
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.unknown\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, mp4a.40\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3, mp4a.40\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, avc3\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3.\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42E01E\"'"));
+ 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(kPropProbably, CanPlay("'video/mp4; codecs=\"vp8\"'"));
- EXPECT_EQ(PropAndVP9Probably, CanPlay("'video/mp4; codecs=\"vp9\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42E11E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1.42701E\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.42F01E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"vorbis\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1, vorbis\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc3, vorbis\"'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably,
- CanPlay("'video/mp4; codecs=\"avc1.4D401E, vorbis\"'"));
+ CanPlay("'video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably,
- CanPlay("'video/mp4; codecs=\"avc3.64001F, vorbis\"'"));
-
- EXPECT_EQ(kOpusAndPropProbably, CanPlay("'video/mp4; codecs=\"opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably, CanPlay("'video/mp4; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably, CanPlay("'video/mp4; codecs=\"vp9, opus\"'"));
-
- EXPECT_EQ(kTheoraAndPropProbably, CanPlay("'video/mp4; codecs=\"theora\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/mp4; codecs=\"theora, vorbis\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/mp4; codecs=\"theora, mp4a\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/mp4; codecs=\"theora, mp4a.40.2\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/mp4; codecs=\"theora, avc1\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/mp4; codecs=\"theora, avc3\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/mp4; codecs=\"theora, avc1.4D401E\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/mp4; codecs=\"theora, avc3.64001F\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"AVC1\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"AVC3\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"MP4A\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"AVC3, MP4\"'"));
+ CanPlay("'video/mp4; codecs=\"avc3.42E01E, mp4a.40.5\"'"));
+
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, mp4a.40.2\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3, mp4a.40.2\"'"));
EXPECT_EQ(kPropMaybe,
- CanPlay("'video/mp4; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
+ CanPlay("'video/mp4; codecs=\"avc1.42E01E, mp4a.40\"'"));
EXPECT_EQ(kPropMaybe,
- CanPlay("'video/mp4; codecs=\", AVC3.64001F, MP4.40.2\"'"));
+ CanPlay("'video/mp4; codecs=\"avc3.42E01E, mp4a.40\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc2\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc4\"'"));
+ TestMPEGUnacceptableCombinations("video/mp4");
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1x\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3x\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"mp4ax\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"unknown\"'"));
- // ---------------------------------------------------------------------------
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc3\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1, mp4a.40\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc3, mp4a.40\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1, avc3\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v'"));
+ EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.42E01E\"'"));
+ 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(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1, avc3\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1.42E11E\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(kPropMaybe, 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=\"avc1.4D401E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3.64001F\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably,
- CanPlay("'video/x-m4v; codecs=\"avc1.4D401E, mp4a.40.2\"'"));
+ CanPlay("'video/x-m4v; codecs=\"avc1.42E01E, mp4a.40.2\"'"));
EXPECT_EQ(kPropProbably,
- CanPlay("'video/x-m4v; codecs=\"avc3.64001F, mp4a.40.5\"'"));
-
- // TODO(amogh.bihani): Change these tests when bug 53193 is fixed.
- // http://crbug.com/53193 ----------------------------------------------------
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.unknown\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1.\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3.\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"mp4a.\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"vp8\"'"));
- EXPECT_EQ(PropAndVP9Probably, CanPlay("'video/x-m4v; codecs=\"vp9\"'"));
+ CanPlay("'video/x-m4v; codecs=\"avc3.42E01E, mp4a.40.5\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"vorbis\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc1, vorbis\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'video/x-m4v; codecs=\"avc3, vorbis\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'video/x-m4v; codecs=\"avc1.4D401E, vorbis\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'video/x-m4v; codecs=\"avc3.64001F, vorbis\"'"));
-
- EXPECT_EQ(kOpusAndPropProbably, CanPlay("'video/x-m4v; codecs=\"opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"vp9, opus\"'"));
-
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"theora\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"theora, vorbis\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"theora, mp4a\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"theora, mp4a.40.2\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"theora, avc1\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"theora, avc3\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"theora, avc1.4D401E\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'video/x-m4v; codecs=\"theora, avc3.64001F\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"AVC1\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"AVC3\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"MP4A\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"AVC3, MP4\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1, mp4a.40.2\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc3, mp4a.40.2\"'"));
EXPECT_EQ(kPropMaybe,
- CanPlay("'video/x-m4v; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
+ CanPlay("'video/x-m4v; codecs=\"avc1.42E01E, mp4a.40\"'"));
EXPECT_EQ(kPropMaybe,
- CanPlay("'video/x-m4v; codecs=\", AVC3.64001F, MP4.40.2\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc2\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc4\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc1x\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"avc3x\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"mp4ax\"'"));
+ CanPlay("'video/x-m4v; codecs=\"avc3.42E01E, mp4a.40\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v; codecs=\"unknown\"'"));
- // ---------------------------------------------------------------------------
+ TestMPEGUnacceptableCombinations("video/x-m4v");
EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.2\"'"));
- // TODO(amogh.bihani): Change these tests when bug 53193 is fixed.
- // http://crbug.com/53193 ----------------------------------------------------
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc1\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc3\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc1, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc3, mp4a\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc1, mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc3, mp4a.40\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc3.64001F\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.unknown\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc1.\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc3.\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.\"'"));
-
- EXPECT_EQ(kPropProbably,
- CanPlay("'audio/mp4; codecs=\"avc1.4D401E, mp4a.40.2\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'audio/mp4; codecs=\"avc3.64001F mp4a.40.2\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'audio/mp4; codecs=\"mp4a, vorbis\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'audio/mp4; codecs=\"mp4a.40.2, vorbis\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"vorbis\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"vp8\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"vp8.0\"'"));
- EXPECT_EQ(PropAndVP9Probably, CanPlay("'audio/mp4; codecs=\"vp9\"'"));
- EXPECT_EQ(PropAndVP9Probably, CanPlay("'audio/mp4; codecs=\"vp9.0\"'"));
-
- EXPECT_EQ(kOpusAndPropProbably, CanPlay("'audio/mp4; codecs=\"opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably,
- CanPlay("'audio/mp4; codecs=\"mp4a, opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably,
- CanPlay("'audio/mp4; codecs=\"vorbis, opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably, CanPlay("'audio/mp4; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably, CanPlay("'audio/mp4; codecs=\"vp9, opus\"'"));
-
- EXPECT_EQ(kTheoraAndPropProbably, CanPlay("'audio/mp4; codecs=\"theora\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'audio/mp4; codecs=\"theora, vorbis\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'audio/mp4; codecs=\"theora, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"avc1, vorbis\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"AVC1\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"AVC3\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"MP4A\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"AVC3, MP4\"'"));
- EXPECT_EQ(kPropMaybe,
- CanPlay("'audio/mp4; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
- EXPECT_EQ(kPropMaybe,
- CanPlay("'audio/mp4; codecs=\", AVC3.64001F, MP4.40.2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc1.4D401E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"avc2\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"avc4\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"avc1x\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"avc3x\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"mp4ax\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"unknown\"'"));
- // ---------------------------------------------------------------------------
+ TestMPEGUnacceptableCombinations("audio/mp4");
EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a\"'"));
+ EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"mp4a.40\"'"));
EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.40.2\"'"));
- // TODO(amogh.bihani): Change these tests when bug 53193 is fixed.
- // http://crbug.com/53193 ----------------------------------------------------
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc1\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc3\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc1, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc3, mp4a\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc3.64001F\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc1, mp4a\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc3, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.unknown\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc1.4D401E\"'"));
+ EXPECT_EQ(kNot, CanPlay("'audio/x-m4a; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc1.\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc3.\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"mp4a.\"'"));
-
- EXPECT_EQ(kPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"avc1.4D401E, mp4a.40.2\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"avc3.64001F mp4a.40.2\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"mp4a, vorbis\"'"));
- EXPECT_EQ(kPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"mp4a.40.2, vorbis\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"vorbis\"'"));
-
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"vp8\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"vp8.0\"'"));
- EXPECT_EQ(PropAndVP9Probably, CanPlay("'audio/x-m4a; codecs=\"vp9\"'"));
- EXPECT_EQ(PropAndVP9Probably, CanPlay("'audio/x-m4a; codecs=\"vp9.0\"'"));
-
- EXPECT_EQ(kOpusAndPropProbably, CanPlay("'audio/x-m4a; codecs=\"opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"mp4a, opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"vorbis, opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(kOpusAndPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"vp9, opus\"'"));
-
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"theora\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"theora, vorbis\"'"));
- EXPECT_EQ(kTheoraAndPropProbably,
- CanPlay("'audio/x-m4a; codecs=\"theora, mp4a\"'"));
- EXPECT_EQ(kPropProbably, CanPlay("'audio/x-m4a; codecs=\"avc1, vorbis\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"AVC1\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"AVC3\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"MP4A\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"AVC3, MP4\"'"));
- EXPECT_EQ(kPropMaybe,
- CanPlay("'audio/x-m4a; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
- EXPECT_EQ(kPropMaybe,
- CanPlay("'audio/x-m4a; codecs=\", AVC3.64001F, MP4.40.2\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"avc2\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"avc4\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"avc1x\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"avc3x\"'"));
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"mp4ax\"'"));
-
- EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a; codecs=\"unknown\"'"));
- // ---------------------------------------------------------------------------
+ TestMPEGUnacceptableCombinations("audio/x-m4a");
}
IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
// HLS are supported only on Android IceCreamSandwich and above (API level 14)
- std::string HLSProbably = "";
- std::string HLSMaybe = "";
- std::string HLSAndVP9Probably = "";
+ std::string probablyCanPlayHLS = kNot;
+ std::string maybeCanPlayHLS = kNot;
#if defined(OS_ANDROID)
- int sdk = base::android::BuildInfo::GetInstance()->sdk_int();
- if (sdk > 13) {
- HLSProbably = "probably";
- HLSMaybe = "maybe";
- if (sdk < 19)
- HLSAndVP9Probably = "maybe";
- else
- HLSAndVP9Probably = "probably";
+ if (base::android::BuildInfo::GetInstance()->sdk_int() > 13) {
+ probablyCanPlayHLS = kProbably;
+ maybeCanPlayHLS = kMaybe;
}
#endif
- EXPECT_EQ(HLSMaybe, CanPlay("'application/x-mpegurl'"));
+ EXPECT_EQ(maybeCanPlayHLS, CanPlay("'application/x-mpegurl'"));
- EXPECT_EQ(HLSProbably,
+ EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc1\"'"));
- EXPECT_EQ(HLSProbably,
+ EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc3\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"mp4a\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc3, mp4a\"'"));
-
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(HLSProbably,
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a.40\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3, mp4a.40\"'"));
+
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3.42801E\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3.42C01E\"'"));
+
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42E11E\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42701E\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42F01E\"'"));
+
+ EXPECT_EQ(probablyCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"mp4a.40.2\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc1.4D401E, mp4a.40.2\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc3.64001F, mp4a.40.5\"'"));
-
- // TODO(amogh.bihani): Change these tests when bug 53193 is fixed.
- // http://crbug.com/53193 ----------------------------------------------------
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"mp4a.unknown\"'"));
-
- EXPECT_EQ(HLSProbably, CanPlay("'application/x-mpegurl; codecs=\"avc1.\"'"));
- EXPECT_EQ(HLSProbably, CanPlay("'application/x-mpegurl; codecs=\"avc3.\"'"));
- EXPECT_EQ(HLSProbably, CanPlay("'application/x-mpegurl; codecs=\"mp4a.\"'"));
-
- EXPECT_EQ(HLSProbably, CanPlay("'application/x-mpegurl; codecs=\"vp8\"'"));
- EXPECT_EQ(HLSAndVP9Probably,
- CanPlay("'application/x-mpegurl; codecs=\"vp9\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"vorbis\"'"));
-
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc1, vorbis\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc3, vorbis\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc1.4D401E, vorbis\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/x-mpegurl; codecs=\"avc3.64001F, vorbis\"'"));
-
- EXPECT_EQ(HLSMaybe, CanPlay("'application/x-mpegurl; codecs=\"opus\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"vp9, opus\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"theora\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"theora, vorbis\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"theora, mp4a\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"theora, mp4a.40.2\"'"));
-
- EXPECT_EQ(HLSMaybe, CanPlay("'application/x-mpegurl; codecs=\"AVC1\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(HLSMaybe, CanPlay("'application/x-mpegurl; codecs=\"AVC3\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(HLSMaybe, CanPlay("'application/x-mpegurl; codecs=\"MP4A\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"AVC3, MP4\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\", AVC1.4D401E, MP4.40.2\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\", AVC3.64001F, MP4.40.2\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"avc2\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"avc4\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"avc1x\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"avc3x\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"mp4ax\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/x-mpegurl; codecs=\"unknown\"'"));
- // ---------------------------------------------------------------------------
-
- EXPECT_EQ(HLSMaybe, CanPlay("'application/vnd.apple.mpegurl'"));
-
- EXPECT_EQ(HLSProbably,
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E, mp4a.40.2\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40.5\"'"));
+
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a.40.2\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3, mp4a.40.2\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc1.42E01E, mp4a.40\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/x-mpegurl; codecs=\"avc3.42E01E, mp4a.40\"'"));
+
+ TestMPEGUnacceptableCombinations("application/x-mpegurl");
+
+ EXPECT_EQ(maybeCanPlayHLS, CanPlay("'application/vnd.apple.mpegurl'"));
+
+ EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1\"'"));
- EXPECT_EQ(HLSProbably,
+ EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, mp4a\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, mp4a\"'"));
-
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.4D401E\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.64001F\"'"));
- EXPECT_EQ(HLSProbably,
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, mp4a.40\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, mp4a.40\"'"));
+
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42E01E\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.42E01E\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.42801E\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.42C01E\"'"));
+
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42E11E\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42101E\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42701E\"'"));
+ EXPECT_EQ(probablyCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.42F01E\"'"));
+
+ EXPECT_EQ(probablyCanPlayHLS,
CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.40.2\"'"));
- // TODO(amogh.bihani): Change these tests when bug 53193 is fixed.
- // http://crbug.com/53193 ----------------------------------------------------
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.unknown\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.unknown\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.unknown\"'"));
-
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.\"'"));
-
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"vp8\"'"));
- EXPECT_EQ(HLSAndVP9Probably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"vp9\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"vorbis\"'"));
-
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, vorbis\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, vorbis\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1.4D401E, vorbis\"'"));
- EXPECT_EQ(HLSProbably,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3.64001F, vorbis\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"opus\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"vp8, opus\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"vp9, opus\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"theora\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"theora, vorbis\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"theora, mp4a\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"theora, mp4a.40.2\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"AVC1\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"AVC1.4d401e\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"AVC3\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"AVC3.64001f\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"MP4A\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"MP4A.40.2\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"AVC1, MP4\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"AVC3, MP4\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; "
- "codecs=\", AVC1.4D401E, MP4.40.2\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; "
- "codecs=\", AVC3.64001F, MP4.40.2\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc2\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc4\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1x\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3x\"'"));
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4ax\"'"));
-
- EXPECT_EQ(HLSMaybe,
- CanPlay("'application/vnd.apple.mpegurl; codecs=\"unknown\"'"));
- // ---------------------------------------------------------------------------
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc1, mp4a.40.2\"'"));
+ EXPECT_EQ(maybeCanPlayHLS,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"avc3, mp4a.40.2\"'"));
+ 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\"'"));
+
+ TestMPEGUnacceptableCombinations("application/vnd.apple.mpegurl");
}
} // namespace content
diff --git a/chromium/content/browser/media/media_internals.cc b/chromium/content/browser/media/media_internals.cc
index 1d3f4b4c09d..4d600851783 100644
--- a/chromium/content/browser/media/media_internals.cc
+++ b/chromium/content/browser/media/media_internals.cc
@@ -38,7 +38,7 @@ std::string EffectsToString(int effects) {
};
std::string ret;
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(flags); ++i) {
+ for (size_t i = 0; i < arraysize(flags); ++i) {
if (effects & flags[i].flag) {
if (!ret.empty())
ret += " | ";
@@ -68,16 +68,16 @@ class AudioLogImpl : public media::AudioLog {
AudioLogImpl(int owner_id,
media::AudioLogFactory::AudioComponent component,
content::MediaInternals* media_internals);
- virtual ~AudioLogImpl();
+ ~AudioLogImpl() override;
- virtual void OnCreated(int component_id,
- const media::AudioParameters& params,
- const std::string& device_id) OVERRIDE;
- virtual void OnStarted(int component_id) OVERRIDE;
- virtual void OnStopped(int component_id) OVERRIDE;
- virtual void OnClosed(int component_id) OVERRIDE;
- virtual void OnError(int component_id) OVERRIDE;
- virtual void OnSetVolume(int component_id, double volume) OVERRIDE;
+ void OnCreated(int component_id,
+ const media::AudioParameters& params,
+ const std::string& device_id) override;
+ void OnStarted(int component_id) override;
+ void OnStopped(int component_id) override;
+ void OnClosed(int component_id) override;
+ void OnError(int component_id) override;
+ void OnSetVolume(int component_id, double volume) override;
private:
void SendSingleStringUpdate(int component_id,
@@ -110,7 +110,6 @@ void AudioLogImpl::OnCreated(int component_id,
dict.SetString(kAudioLogStatusKey, "created");
dict.SetString("device_id", device_id);
- dict.SetInteger("input_channels", params.input_channels());
dict.SetInteger("frames_per_buffer", params.frames_per_buffer());
dict.SetInteger("sample_rate", params.sample_rate());
dict.SetInteger("channels", params.channels());
@@ -118,7 +117,7 @@ void AudioLogImpl::OnCreated(int component_id,
ChannelLayoutToString(params.channel_layout()));
dict.SetString("effects", EffectsToString(params.effects()));
- media_internals_->SendUpdateAndCache(
+ media_internals_->SendUpdateAndCacheAudioStreamKey(
FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
}
@@ -134,7 +133,7 @@ void AudioLogImpl::OnClosed(int component_id) {
base::DictionaryValue dict;
StoreComponentMetadata(component_id, &dict);
dict.SetString(kAudioLogStatusKey, "closed");
- media_internals_->SendUpdateAndPurgeCache(
+ media_internals_->SendUpdateAndPurgeAudioStreamCache(
FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
}
@@ -146,7 +145,7 @@ void AudioLogImpl::OnSetVolume(int component_id, double volume) {
base::DictionaryValue dict;
StoreComponentMetadata(component_id, &dict);
dict.SetDouble("volume", volume);
- media_internals_->SendUpdateAndCache(
+ media_internals_->SendUpdateAndCacheAudioStreamKey(
FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
}
@@ -160,7 +159,7 @@ void AudioLogImpl::SendSingleStringUpdate(int component_id,
base::DictionaryValue dict;
StoreComponentMetadata(component_id, &dict);
dict.SetString(key, value);
- media_internals_->SendUpdateAndCache(
+ media_internals_->SendUpdateAndCacheAudioStreamKey(
FormatCacheKey(component_id), kAudioLogUpdateFunction, &dict);
}
@@ -215,14 +214,54 @@ void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) {
NOTREACHED();
}
-void MediaInternals::SendEverything() {
- base::string16 everything_update;
+void MediaInternals::SendAudioStreamData() {
+ base::string16 audio_stream_update;
{
base::AutoLock auto_lock(lock_);
- everything_update = SerializeUpdate(
- "media.onReceiveEverything", &cached_data_);
+ audio_stream_update = SerializeUpdate(
+ "media.onReceiveAudioStreamData", &audio_streams_cached_data_);
}
- SendUpdate(everything_update);
+ SendUpdate(audio_stream_update);
+}
+
+void MediaInternals::SendVideoCaptureDeviceCapabilities() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ SendUpdate(SerializeUpdate("media.onReceiveVideoCaptureCapabilities",
+ &video_capture_capabilities_cached_data_));
+}
+
+void MediaInternals::UpdateVideoCaptureDeviceCapabilities(
+ const media::VideoCaptureDeviceInfos& video_capture_device_infos) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ video_capture_capabilities_cached_data_.Clear();
+
+ for (const auto& video_capture_device_info : video_capture_device_infos) {
+ base::ListValue* format_list = new base::ListValue();
+ for (const auto& format : video_capture_device_info.supported_formats)
+ format_list->AppendString(format.ToString());
+
+ base::DictionaryValue* device_dict = new base::DictionaryValue();
+ device_dict->SetString("id", video_capture_device_info.name.id());
+ device_dict->SetString(
+ "name", video_capture_device_info.name.GetNameAndModel());
+ device_dict->Set("formats", format_list);
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ device_dict->SetString(
+ "captureApi",
+ video_capture_device_info.name.GetCaptureApiTypeString());
+#endif
+ video_capture_capabilities_cached_data_.Append(device_dict);
+ }
+
+ if (update_callbacks_.size() > 0)
+ SendVideoCaptureDeviceCapabilities();
+}
+
+scoped_ptr<media::AudioLog> MediaInternals::CreateAudioLog(
+ AudioComponent component) {
+ base::AutoLock auto_lock(lock_);
+ return scoped_ptr<media::AudioLog>(new AudioLogImpl(
+ owner_ids_[component]++, component, this));
}
void MediaInternals::SendUpdate(const base::string16& update) {
@@ -239,30 +278,24 @@ void MediaInternals::SendUpdate(const base::string16& update) {
update_callbacks_[i].Run(update);
}
-scoped_ptr<media::AudioLog> MediaInternals::CreateAudioLog(
- AudioComponent component) {
- base::AutoLock auto_lock(lock_);
- return scoped_ptr<media::AudioLog>(new AudioLogImpl(
- owner_ids_[component]++, component, this));
-}
-
-void MediaInternals::SendUpdateAndCache(const std::string& cache_key,
- const std::string& function,
- const base::DictionaryValue* value) {
+void MediaInternals::SendUpdateAndCacheAudioStreamKey(
+ const std::string& cache_key,
+ const std::string& function,
+ const base::DictionaryValue* value) {
SendUpdate(SerializeUpdate(function, value));
base::AutoLock auto_lock(lock_);
- if (!cached_data_.HasKey(cache_key)) {
- cached_data_.Set(cache_key, value->DeepCopy());
+ if (!audio_streams_cached_data_.HasKey(cache_key)) {
+ audio_streams_cached_data_.Set(cache_key, value->DeepCopy());
return;
}
base::DictionaryValue* existing_dict = NULL;
- CHECK(cached_data_.GetDictionary(cache_key, &existing_dict));
+ CHECK(audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict));
existing_dict->MergeDictionary(value);
}
-void MediaInternals::SendUpdateAndPurgeCache(
+void MediaInternals::SendUpdateAndPurgeAudioStreamCache(
const std::string& cache_key,
const std::string& function,
const base::DictionaryValue* value) {
@@ -270,7 +303,7 @@ void MediaInternals::SendUpdateAndPurgeCache(
base::AutoLock auto_lock(lock_);
scoped_ptr<base::Value> out_value;
- CHECK(cached_data_.Remove(cache_key, &out_value));
+ CHECK(audio_streams_cached_data_.Remove(cache_key, &out_value));
}
} // namespace content
diff --git a/chromium/content/browser/media/media_internals.h b/chromium/content/browser/media/media_internals.h
index c0f144a5b8b..4c1b2ed2ed6 100644
--- a/chromium/content/browser/media/media_internals.h
+++ b/chromium/content/browser/media/media_internals.h
@@ -16,6 +16,7 @@
#include "base/values.h"
#include "content/common/content_export.h"
#include "media/audio/audio_logging.h"
+#include "media/video/capture/video_capture_device_info.h"
namespace media {
class AudioParameters;
@@ -28,27 +29,34 @@ namespace content {
class CONTENT_EXPORT MediaInternals
: NON_EXPORTED_BASE(public media::AudioLogFactory) {
public:
+ // Called with the update string.
+ typedef base::Callback<void(const base::string16&)> UpdateCallback;
+
static MediaInternals* GetInstance();
- virtual ~MediaInternals();
+ ~MediaInternals() override;
// Called when a MediaEvent occurs.
void OnMediaEvents(int render_process_id,
const std::vector<media::MediaLogEvent>& events);
- // Called with the update string.
- typedef base::Callback<void(const base::string16&)> UpdateCallback;
-
// Add/remove update callbacks (see above). Must be called on the IO thread.
void AddUpdateCallback(const UpdateCallback& callback);
void RemoveUpdateCallback(const UpdateCallback& callback);
- // Sends all cached data to each registered UpdateCallback.
- void SendEverything();
+ // Sends all audio cached data to each registered UpdateCallback.
+ void SendAudioStreamData();
+
+ // Sends all video capture capabilities cached data to each registered
+ // UpdateCallback.
+ void SendVideoCaptureDeviceCapabilities();
+
+ // Called to inform of the capabilities enumerated for video devices.
+ void UpdateVideoCaptureDeviceCapabilities(
+ const media::VideoCaptureDeviceInfos& video_capture_device_infos);
// AudioLogFactory implementation. Safe to call from any thread.
- virtual scoped_ptr<media::AudioLog> CreateAudioLog(
- AudioComponent component) OVERRIDE;
+ scoped_ptr<media::AudioLog> CreateAudioLog(AudioComponent component) override;
private:
friend class AudioLogImpl;
@@ -61,22 +69,24 @@ class CONTENT_EXPORT MediaInternals
// thread, but will forward to the IO thread.
void SendUpdate(const base::string16& update);
- // Caches |value| under |cache_key| so that future SendEverything() calls will
- // include the current data. Calls JavaScript |function|(|value|) for each
- // registered UpdateCallback. SendUpdateAndPurgeCache() is similar but purges
- // the cache entry after completion instead.
- void SendUpdateAndCache(const std::string& cache_key,
- const std::string& function,
- const base::DictionaryValue* value);
- void SendUpdateAndPurgeCache(const std::string& cache_key,
- const std::string& function,
- const base::DictionaryValue* value);
+ // Caches |value| under |cache_key| so that future SendAudioStreamData() calls
+ // will include the current data. Calls JavaScript |function|(|value|) for
+ // each registered UpdateCallback. SendUpdateAndPurgeCache() is similar but
+ // purges the cache entry after completion instead.
+ void SendUpdateAndCacheAudioStreamKey(const std::string& cache_key,
+ const std::string& function,
+ const base::DictionaryValue* value);
+ void SendUpdateAndPurgeAudioStreamCache(const std::string& cache_key,
+ const std::string& function,
+ const base::DictionaryValue* value);
+
// Must only be accessed on the IO thread.
std::vector<UpdateCallback> update_callbacks_;
+ base::ListValue video_capture_capabilities_cached_data_;
// All variables below must be accessed under |lock_|.
base::Lock lock_;
- base::DictionaryValue cached_data_;
+ base::DictionaryValue audio_streams_cached_data_;
int owner_ids_[AUDIO_COMPONENT_MAX];
DISALLOW_COPY_AND_ASSIGN(MediaInternals);
diff --git a/chromium/content/browser/media/media_internals_handler.h b/chromium/content/browser/media/media_internals_handler.h
index 265c1224d7e..d984a96d1a2 100644
--- a/chromium/content/browser/media/media_internals_handler.h
+++ b/chromium/content/browser/media/media_internals_handler.h
@@ -21,10 +21,10 @@ class MediaInternalsProxy;
class MediaInternalsMessageHandler : public WebUIMessageHandler {
public:
MediaInternalsMessageHandler();
- virtual ~MediaInternalsMessageHandler();
+ ~MediaInternalsMessageHandler() override;
// WebUIMessageHandler implementation.
- virtual void RegisterMessages() OVERRIDE;
+ void RegisterMessages() override;
// Javascript message handlers.
void OnGetEverything(const base::ListValue* list);
diff --git a/chromium/content/browser/media/media_internals_proxy.cc b/chromium/content/browser/media/media_internals_proxy.cc
index 49456ab498a..4193a834812 100644
--- a/chromium/content/browser/media/media_internals_proxy.cc
+++ b/chromium/content/browser/media/media_internals_proxy.cc
@@ -137,7 +137,8 @@ void MediaInternalsProxy::StopObservingMediaInternalsOnIOThread() {
void MediaInternalsProxy::GetEverythingOnIOThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- MediaInternals::GetInstance()->SendEverything();
+ MediaInternals::GetInstance()->SendAudioStreamData();
+ MediaInternals::GetInstance()->SendVideoCaptureDeviceCapabilities();
}
void MediaInternalsProxy::UpdateUIOnUIThread(const base::string16& update) {
diff --git a/chromium/content/browser/media/media_internals_proxy.h b/chromium/content/browser/media/media_internals_proxy.h
index b737b858a3e..c2672f09d45 100644
--- a/chromium/content/browser/media/media_internals_proxy.h
+++ b/chromium/content/browser/media/media_internals_proxy.h
@@ -35,9 +35,9 @@ class MediaInternalsProxy
MediaInternalsProxy();
// NotificationObserver implementation.
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
// Register a Handler and start receiving callbacks from MediaInternals.
void Attach(MediaInternalsMessageHandler* handler);
@@ -52,12 +52,12 @@ class MediaInternalsProxy
void OnUpdate(const base::string16& update);
// net::NetLog::ThreadSafeObserver implementation. Callable from any thread:
- virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE;
+ void OnAddEntry(const net::NetLog::Entry& entry) override;
private:
friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
friend class base::DeleteHelper<MediaInternalsProxy>;
- virtual ~MediaInternalsProxy();
+ ~MediaInternalsProxy() override;
// Build a dictionary mapping constant names to values.
base::Value* GetConstants();
diff --git a/chromium/content/browser/media/media_internals_ui.cc b/chromium/content/browser/media/media_internals_ui.cc
index f185bdca23e..3a5ac605234 100644
--- a/chromium/content/browser/media/media_internals_ui.cc
+++ b/chromium/content/browser/media/media_internals_ui.cc
@@ -6,12 +6,12 @@
#include "base/command_line.h"
#include "content/browser/media/media_internals_handler.h"
+#include "content/grit/content_resources.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/content_switches.h"
#include "content/public/common/url_constants.h"
-#include "grit/content_resources.h"
namespace content {
namespace {
diff --git a/chromium/content/browser/media/media_internals_unittest.cc b/chromium/content/browser/media/media_internals_unittest.cc
index b9208c8dfd1..da8e2c51eb3 100644
--- a/chromium/content/browser/media/media_internals_unittest.cc
+++ b/chromium/content/browser/media/media_internals_unittest.cc
@@ -8,48 +8,36 @@
#include "base/bind_helpers.h"
#include "base/json/json_reader.h"
#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "media/audio/audio_parameters.h"
#include "media/base/channel_layout.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
namespace {
const int kTestComponentID = 0;
const char kTestDeviceID[] = "test-device-id";
-} // namespace
-
-namespace content {
-class MediaInternalsTest
- : public testing::TestWithParam<media::AudioLogFactory::AudioComponent> {
+// This class encapsulates a MediaInternals reference. It also has some useful
+// methods to receive a callback, deserialize its associated data and expect
+// integer/string values.
+class MediaInternalsTestBase {
public:
- MediaInternalsTest()
- : media_internals_(MediaInternals::GetInstance()),
- update_cb_(base::Bind(&MediaInternalsTest::UpdateCallbackImpl,
- base::Unretained(this))),
- test_params_(media::AudioParameters::AUDIO_PCM_LINEAR,
- media::CHANNEL_LAYOUT_MONO,
- 0,
- 48000,
- 16,
- 128,
- media::AudioParameters::ECHO_CANCELLER |
- media::AudioParameters::DUCKING),
- test_component_(GetParam()),
- audio_log_(media_internals_->CreateAudioLog(test_component_)) {
- media_internals_->AddUpdateCallback(update_cb_);
- }
-
- virtual ~MediaInternalsTest() {
- media_internals_->RemoveUpdateCallback(update_cb_);
+ MediaInternalsTestBase()
+ : media_internals_(content::MediaInternals::GetInstance()) {
}
+ virtual ~MediaInternalsTestBase() {}
protected:
// Extracts and deserializes the JSON update data; merges into |update_data_|.
void UpdateCallbackImpl(const base::string16& update) {
- // Each update string looks like "<JavaScript Function Name>({<JSON>});", to
- // use the JSON reader we need to strip out the JavaScript code.
+ // Each update string looks like "<JavaScript Function Name>({<JSON>});"
+ // or for video capabilities: "<JavaScript Function Name>([{<JSON>}]);".
+ // In the second case we will be able to extract the dictionary if it is the
+ // only member of the list.
+ // To use the JSON reader we need to strip out the JS function name and ().
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('}');
@@ -62,34 +50,191 @@ class MediaInternalsTest
update_data_.MergeDictionary(output_dict);
}
- void ExpectInt(const std::string& key, int expected_value) {
+ void ExpectInt(const std::string& key, int expected_value) const {
int actual_value = 0;
ASSERT_TRUE(update_data_.GetInteger(key, &actual_value));
EXPECT_EQ(expected_value, actual_value);
}
- void ExpectString(const std::string& key, const std::string& expected_value) {
+ void ExpectString(const std::string& key,
+ const std::string& expected_value) const {
std::string actual_value;
ASSERT_TRUE(update_data_.GetString(key, &actual_value));
EXPECT_EQ(expected_value, actual_value);
}
- void ExpectStatus(const std::string& expected_value) {
+ void ExpectStatus(const std::string& expected_value) const {
ExpectString("status", expected_value);
}
- TestBrowserThreadBundle thread_bundle_;
- MediaInternals* const media_internals_;
- MediaInternals::UpdateCallback update_cb_;
+ void ExpectListOfStrings(const std::string& key,
+ const base::ListValue& expected_list) const {
+ const base::ListValue* actual_list;
+ ASSERT_TRUE(update_data_.GetList(key, &actual_list));
+ const size_t expected_size = expected_list.GetSize();
+ const size_t actual_size = actual_list->GetSize();
+ ASSERT_EQ(expected_size, actual_size);
+ for (size_t i = 0; i < expected_size; ++i) {
+ std::string expected_value, actual_value;
+ ASSERT_TRUE(expected_list.GetString(i, &expected_value));
+ ASSERT_TRUE(actual_list->GetString(i, &actual_value));
+ EXPECT_EQ(expected_value, actual_value);
+ }
+ }
+
+ const content::TestBrowserThreadBundle thread_bundle_;
base::DictionaryValue update_data_;
+ content::MediaInternals* const media_internals_;
+};
+
+} // namespace
+
+namespace content {
+
+class MediaInternalsVideoCaptureDeviceTest : public testing::Test,
+ public MediaInternalsTestBase {
+ public:
+ MediaInternalsVideoCaptureDeviceTest()
+ : update_cb_(base::Bind(
+ &MediaInternalsVideoCaptureDeviceTest::UpdateCallbackImpl,
+ base::Unretained(this))) {
+ media_internals_->AddUpdateCallback(update_cb_);
+ }
+
+ ~MediaInternalsVideoCaptureDeviceTest() override {
+ media_internals_->RemoveUpdateCallback(update_cb_);
+ }
+
+ protected:
+ MediaInternals::UpdateCallback update_cb_;
+};
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+TEST_F(MediaInternalsVideoCaptureDeviceTest,
+ AllCaptureApiTypesHaveProperStringRepresentation) {
+ typedef media::VideoCaptureDevice::Name VideoCaptureDeviceName;
+ typedef std::map<VideoCaptureDeviceName::CaptureApiType, std::string>
+ CaptureApiTypeStringMap;
+ CaptureApiTypeStringMap m;
+#if defined(OS_WIN)
+ m[VideoCaptureDeviceName::MEDIA_FOUNDATION] = "Media Foundation";
+ m[VideoCaptureDeviceName::DIRECT_SHOW] = "Direct Show";
+ m[VideoCaptureDeviceName::DIRECT_SHOW_WDM_CROSSBAR] =
+ "Direct Show WDM Crossbar";
+#elif defined(OS_MACOSX)
+ m[VideoCaptureDeviceName::AVFOUNDATION] = "AV Foundation";
+ m[VideoCaptureDeviceName::QTKIT] = "QTKit";
+ m[VideoCaptureDeviceName::DECKLINK] = "DeckLink";
+#endif
+ EXPECT_EQ(media::VideoCaptureDevice::Name::API_TYPE_UNKNOWN, m.size());
+ for (CaptureApiTypeStringMap::iterator it = m.begin(); it != m.end(); ++it) {
+ const VideoCaptureDeviceName device_name("dummy", "dummy", it->first);
+ EXPECT_EQ(it->second, device_name.GetCaptureApiTypeString());
+ }
+}
+#endif
+
+TEST_F(MediaInternalsVideoCaptureDeviceTest,
+ VideoCaptureFormatStringIsInExpectedFormat) {
+ // Since media internals will send video capture capabilities to JavaScript in
+ // an expected format and there are no public methods for accessing the
+ // resolutions, frame rates or pixel formats, this test checks that the format
+ // has not changed. If the test fails because of the changed format, it should
+ // be updated at the same time as the media internals JS files.
+ const float kFrameRate = 30.0f;
+ const gfx::Size kFrameSize(1280, 720);
+ const media::VideoPixelFormat kPixelFormat = media::PIXEL_FORMAT_I420;
+ const media::VideoCaptureFormat capture_format(
+ kFrameSize, kFrameRate, kPixelFormat);
+ const std::string expected_string =
+ base::StringPrintf("resolution: %s, fps: %f, pixel format: %s",
+ kFrameSize.ToString().c_str(),
+ kFrameRate,
+ media::VideoCaptureFormat::PixelFormatToString(
+ kPixelFormat).c_str());
+ EXPECT_EQ(expected_string, capture_format.ToString());
+}
+
+TEST_F(MediaInternalsVideoCaptureDeviceTest,
+ NotifyVideoCaptureDeviceCapabilitiesEnumerated) {
+ const int kWidth = 1280;
+ const int kHeight = 720;
+ const float kFrameRate = 30.0f;
+ const media::VideoPixelFormat kPixelFormat = media::PIXEL_FORMAT_I420;
+ const media::VideoCaptureFormat format_hd({kWidth, kHeight},
+ kFrameRate, kPixelFormat);
+ media::VideoCaptureFormats formats{};
+ formats.push_back(format_hd);
+ const media::VideoCaptureDeviceInfo device_info(
+#if defined(OS_MACOSX)
+ media::VideoCaptureDevice::Name("dummy", "dummy",
+ media::VideoCaptureDevice::Name::QTKIT),
+#elif defined(OS_WIN)
+ media::VideoCaptureDevice::Name("dummy", "dummy",
+ media::VideoCaptureDevice::Name::DIRECT_SHOW),
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+ media::VideoCaptureDevice::Name("dummy", "/dev/dummy"),
+#else
+ media::VideoCaptureDevice::Name("dummy", "dummy"),
+#endif
+ formats);
+ media::VideoCaptureDeviceInfos device_infos{};
+ device_infos.push_back(device_info);
+
+ // When updating video capture capabilities, the update will serialize
+ // a JSON array of objects to string. So here, the |UpdateCallbackImpl| will
+ // deserialize the first object in the array. This means we have to have
+ // exactly one device_info in the |device_infos|.
+ media_internals_->UpdateVideoCaptureDeviceCapabilities(device_infos);
+
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+ ExpectString("id", "/dev/dummy");
+#else
+ ExpectString("id", "dummy");
+#endif
+ ExpectString("name", "dummy");
+ base::ListValue expected_list;
+ expected_list.AppendString(format_hd.ToString());
+ ExpectListOfStrings("formats", expected_list);
+#if defined(OS_MACOSX)
+ ExpectString("captureApi", "QTKit");
+#elif defined(OS_WIN)
+ ExpectString("captureApi", "Direct Show");
+#endif
+}
+
+class MediaInternalsAudioLogTest
+ : public MediaInternalsTestBase,
+ public testing::TestWithParam<media::AudioLogFactory::AudioComponent> {
+ public:
+ MediaInternalsAudioLogTest() :
+ update_cb_(base::Bind(&MediaInternalsAudioLogTest::UpdateCallbackImpl,
+ base::Unretained(this))),
+ test_params_(media::AudioParameters::AUDIO_PCM_LINEAR,
+ media::CHANNEL_LAYOUT_MONO,
+ 48000,
+ 16,
+ 128,
+ media::AudioParameters::ECHO_CANCELLER |
+ media::AudioParameters::DUCKING),
+ test_component_(GetParam()),
+ audio_log_(media_internals_->CreateAudioLog(test_component_)) {
+ media_internals_->AddUpdateCallback(update_cb_);
+ }
+
+ virtual ~MediaInternalsAudioLogTest() {
+ media_internals_->RemoveUpdateCallback(update_cb_);
+ }
+
+ protected:
+ MediaInternals::UpdateCallback update_cb_;
const media::AudioParameters test_params_;
const media::AudioLogFactory::AudioComponent test_component_;
scoped_ptr<media::AudioLog> audio_log_;
};
-TEST_P(MediaInternalsTest, AudioLogCreateStartStopErrorClose) {
- audio_log_->OnCreated(
- kTestComponentID, test_params_, kTestDeviceID);
+TEST_P(MediaInternalsAudioLogTest, AudioLogCreateStartStopErrorClose) {
+ audio_log_->OnCreated(kTestComponentID, test_params_, kTestDeviceID);
base::RunLoop().RunUntilIdle();
ExpectString("channel_layout",
@@ -97,7 +242,6 @@ TEST_P(MediaInternalsTest, AudioLogCreateStartStopErrorClose) {
ExpectInt("sample_rate", test_params_.sample_rate());
ExpectInt("frames_per_buffer", test_params_.frames_per_buffer());
ExpectInt("channels", test_params_.channels());
- ExpectInt("input_channels", test_params_.input_channels());
ExpectString("effects", "ECHO_CANCELLER | DUCKING");
ExpectString("device_id", kTestDeviceID);
ExpectInt("component_id", kTestComponentID);
@@ -128,9 +272,8 @@ TEST_P(MediaInternalsTest, AudioLogCreateStartStopErrorClose) {
ExpectStatus("closed");
}
-TEST_P(MediaInternalsTest, AudioLogCreateClose) {
- audio_log_->OnCreated(
- kTestComponentID, test_params_, kTestDeviceID);
+TEST_P(MediaInternalsAudioLogTest, AudioLogCreateClose) {
+ audio_log_->OnCreated(kTestComponentID, test_params_, kTestDeviceID);
base::RunLoop().RunUntilIdle();
ExpectStatus("created");
@@ -140,7 +283,7 @@ TEST_P(MediaInternalsTest, AudioLogCreateClose) {
}
INSTANTIATE_TEST_CASE_P(
- MediaInternalsTest, MediaInternalsTest, testing::Values(
+ MediaInternalsAudioLogTest, MediaInternalsAudioLogTest, testing::Values(
media::AudioLogFactory::AUDIO_INPUT_CONTROLLER,
media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER,
media::AudioLogFactory::AUDIO_OUTPUT_STREAM));
diff --git a/chromium/content/browser/media/media_source_browsertest.cc b/chromium/content/browser/media/media_source_browsertest.cc
index d5d86154637..684b37d6505 100644
--- a/chromium/content/browser/media/media_source_browsertest.cc
+++ b/chromium/content/browser/media/media_source_browsertest.cc
@@ -32,22 +32,24 @@ static bool IsMSESupported() {
class MediaSourceTest : public content::MediaBrowserTest {
public:
- void TestSimplePlayback(const char* media_file, const char* media_type,
- const char* expectation) {
+ void TestSimplePlayback(const std::string& media_file,
+ const std::string& media_type,
+ const std::string& expectation) {
if (!IsMSESupported()) {
VLOG(0) << "Skipping test - MSE not supported.";
return;
}
- std::vector<StringPair> query_params;
- query_params.push_back(std::make_pair("mediafile", media_file));
- query_params.push_back(std::make_pair("mediatype", media_type));
- RunMediaTestPage("media_source_player.html", &query_params, expectation,
+ base::StringPairs query_params;
+ query_params.push_back(std::make_pair("mediaFile", media_file));
+ query_params.push_back(std::make_pair("mediaType", media_type));
+ query_params.push_back(std::make_pair("usePrefixedEME", "1"));
+ RunMediaTestPage("media_source_player.html", query_params, expectation,
true);
}
#if defined(OS_ANDROID)
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ virtual void SetUpCommandLine(CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kDisableGestureRequirementForMediaPlayback);
}
@@ -84,7 +86,9 @@ IN_PROC_BROWSER_TEST_F(MediaSourceTest, ConfigChangeVideo) {
VLOG(0) << "Skipping test - MSE not supported.";
return;
}
- RunMediaTestPage("mse_config_change.html", NULL, kEnded, true);
+ base::StringPairs query_params;
+ query_params.push_back(std::make_pair("usePrefixedEME", "1"));
+ RunMediaTestPage("mse_config_change.html", query_params, kEnded, true);
}
} // namespace content
diff --git a/chromium/content/browser/media/media_web_contents_observer.cc b/chromium/content/browser/media/media_web_contents_observer.cc
index 0214eb52f68..7f9e2b65564 100644
--- a/chromium/content/browser/media/media_web_contents_observer.cc
+++ b/chromium/content/browser/media/media_web_contents_observer.cc
@@ -7,7 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "content/browser/media/cdm/browser_cdm_manager.h"
-#include "content/common/media/cdm_messages.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message_macros.h"
@@ -36,64 +36,31 @@ void MediaWebContentsObserver::RenderFrameDeleted(
#if defined(OS_ANDROID)
media_player_managers_.erase(key);
#endif
- cdm_managers_.erase(key);
+ // TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager
+ // and BrowserCdmManager all run on browser UI thread. So this call is okay.
+ // In the future we need to support the case where MediaWebContentsObserver
+ // get notified on browser UI thread, but BrowserMediaPlayerManager and
+ // BrowserCdmManager run on a different thread.
+ BrowserCdmManager* browser_cdm_manager =
+ BrowserCdmManager::FromProcess(render_frame_host->GetProcess()->GetID());
+ if (browser_cdm_manager)
+ browser_cdm_manager->RenderFrameDeleted(render_frame_host->GetRoutingID());
}
+#if defined(OS_ANDROID)
+
bool MediaWebContentsObserver::OnMessageReceived(
const IPC::Message& msg,
RenderFrameHost* render_frame_host) {
-#if defined(OS_ANDROID)
- // Handles MediaPlayer messages first because MediaPlayers messages are much
- // more frequent than CDM messages.
if (OnMediaPlayerMessageReceived(msg, render_frame_host))
return true;
if (OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host))
return true;
-#endif // defined(OS_ANDROID)
-
- if (OnCdmMessageReceived(msg, render_frame_host))
- return true;
return false;
}
-bool MediaWebContentsObserver::OnCdmMessageReceived(
- const IPC::Message& msg,
- RenderFrameHost* render_frame_host) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserver, msg)
- IPC_MESSAGE_FORWARD(CdmHostMsg_InitializeCdm,
- GetCdmManager(render_frame_host),
- BrowserCdmManager::OnInitializeCdm)
- IPC_MESSAGE_FORWARD(CdmHostMsg_CreateSession,
- GetCdmManager(render_frame_host),
- BrowserCdmManager::OnCreateSession)
- IPC_MESSAGE_FORWARD(CdmHostMsg_UpdateSession,
- GetCdmManager(render_frame_host),
- BrowserCdmManager::OnUpdateSession)
- IPC_MESSAGE_FORWARD(CdmHostMsg_ReleaseSession,
- GetCdmManager(render_frame_host),
- BrowserCdmManager::OnReleaseSession)
- IPC_MESSAGE_FORWARD(CdmHostMsg_DestroyCdm,
- GetCdmManager(render_frame_host),
- BrowserCdmManager::OnDestroyCdm)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-BrowserCdmManager* MediaWebContentsObserver::GetCdmManager(
- RenderFrameHost* render_frame_host) {
- uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host);
- if (!cdm_managers_.contains(key)) {
- cdm_managers_.set(
- key, make_scoped_ptr(BrowserCdmManager::Create(render_frame_host)));
- }
- return cdm_managers_.get(key);
-}
-
-#if defined(OS_ANDROID)
bool MediaWebContentsObserver::OnMediaPlayerMessageReceived(
const IPC::Message& msg,
RenderFrameHost* render_frame_host) {
@@ -129,6 +96,13 @@ bool MediaWebContentsObserver::OnMediaPlayerMessageReceived(
IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_DestroyMediaPlayer,
GetMediaPlayerManager(render_frame_host),
BrowserMediaPlayerManager::OnDestroyPlayer)
+ IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_RequestRemotePlayback,
+ GetMediaPlayerManager(render_frame_host),
+ BrowserMediaPlayerManager::OnRequestRemotePlayback)
+ IPC_MESSAGE_FORWARD(
+ MediaPlayerHostMsg_RequestRemotePlaybackControl,
+ GetMediaPlayerManager(render_frame_host),
+ BrowserMediaPlayerManager::OnRequestRemotePlaybackControl)
#if defined(VIDEO_HOLE)
IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_NotifyExternalSurface,
GetMediaPlayerManager(render_frame_host),
@@ -161,7 +135,16 @@ void MediaWebContentsObserver::OnSetCdm(RenderFrameHost* render_frame_host,
return;
}
- media::BrowserCdm* cdm = GetCdmManager(render_frame_host)->GetCdm(cdm_id);
+ // MediaPlayerAndroid runs on the same thread as BrowserCdmManager.
+ BrowserCdmManager* browser_cdm_manager =
+ BrowserCdmManager::FromProcess(render_frame_host->GetProcess()->GetID());
+ if (!browser_cdm_manager) {
+ NOTREACHED() << "OnSetCdm: CDM not found for " << cdm_id;
+ return;
+ }
+
+ media::BrowserCdm* cdm =
+ browser_cdm_manager->GetCdm(render_frame_host->GetRoutingID(), cdm_id);
if (!cdm) {
NOTREACHED() << "OnSetCdm: CDM not found for " << cdm_id;
return;
@@ -183,14 +166,6 @@ BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager(
return media_player_managers_.get(key);
}
-void MediaWebContentsObserver::PauseVideo() {
- for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin();
- iter != media_player_managers_.end(); ++iter) {
- BrowserMediaPlayerManager* manager = iter->second;
- manager->PauseVideo();
- }
-}
-
#if defined(VIDEO_HOLE)
void MediaWebContentsObserver::OnFrameInfoUpdated() {
for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin();
diff --git a/chromium/content/browser/media/media_web_contents_observer.h b/chromium/content/browser/media/media_web_contents_observer.h
index 8ed89932057..d79e1ce930e 100644
--- a/chromium/content/browser/media/media_web_contents_observer.h
+++ b/chromium/content/browser/media/media_web_contents_observer.h
@@ -13,9 +13,7 @@
namespace content {
class BrowserCdmManager;
-#if defined(OS_ANDROID)
class BrowserMediaPlayerManager;
-#endif // defined(OS_ANDROID)
class RenderViewHost;
// This class manages all RenderFrame based media related managers at the
@@ -28,20 +26,12 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
virtual ~MediaWebContentsObserver();
// WebContentsObserver implementations.
- virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message,
- RenderFrameHost* render_frame_host) OVERRIDE;
-
- // Helper function to handle CDM IPC messages. Returns whether the |message|
- // is handled in the function.
- bool OnCdmMessageReceived(const IPC::Message& message,
- RenderFrameHost* render_frame_host);
-
- // Gets the CDM manager associated with |render_frame_host|. Creates
- // a new one if it doesn't exist. The caller doesn't own the returned pointer.
- BrowserCdmManager* GetCdmManager(RenderFrameHost* render_frame_host);
+ virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
#if defined(OS_ANDROID)
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) override;
+
// Helper functions to handle media player IPC messages. Returns whether the
// |message| is handled in the function.
bool OnMediaPlayerMessageReceived(const IPC::Message& message,
@@ -56,27 +46,18 @@ class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver {
void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id);
- // Pauses all media player.
- void PauseVideo();
-
#if defined(VIDEO_HOLE)
void OnFrameInfoUpdated();
#endif // defined(VIDEO_HOLE)
-#endif // defined(OS_ANDROID)
-
private:
- // Map from RenderFrameHost* to BrowserCdmManager.
- typedef base::ScopedPtrHashMap<uintptr_t, BrowserCdmManager> CdmManagerMap;
- CdmManagerMap cdm_managers_;
-
-#if defined(OS_ANDROID)
// Map from RenderFrameHost* to BrowserMediaPlayerManager.
typedef base::ScopedPtrHashMap<uintptr_t, BrowserMediaPlayerManager>
MediaPlayerManagerMap;
MediaPlayerManagerMap media_player_managers_;
#endif // defined(OS_ANDROID)
+ private:
DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserver);
};
diff --git a/chromium/content/browser/media/midi_dispatcher_host.cc b/chromium/content/browser/media/midi_dispatcher_host.cc
index 9b6faa1c585..944dae51d8d 100644
--- a/chromium/content/browser/media/midi_dispatcher_host.cc
+++ b/chromium/content/browser/media/midi_dispatcher_host.cc
@@ -11,6 +11,7 @@
#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_details.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
@@ -38,6 +39,21 @@ MidiDispatcherHost::MidiDispatcherHost(WebContents* web_contents)
MidiDispatcherHost::~MidiDispatcherHost() {
}
+void MidiDispatcherHost::RenderFrameDeleted(
+ RenderFrameHost* render_frame_host) {
+ CancelPermissionRequestsForFrame(render_frame_host);
+}
+
+void MidiDispatcherHost::DidNavigateAnyFrame(
+ RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) {
+ if (details.is_in_page)
+ return;
+
+ CancelPermissionRequestsForFrame(render_frame_host);
+}
+
bool MidiDispatcherHost::OnMessageReceived(const IPC::Message& message,
RenderFrameHost* render_frame_host) {
bool handled = true;
@@ -45,8 +61,6 @@ bool MidiDispatcherHost::OnMessageReceived(const IPC::Message& message,
render_frame_host)
IPC_MESSAGE_HANDLER(MidiHostMsg_RequestSysExPermission,
OnRequestSysExPermission)
- IPC_MESSAGE_HANDLER(MidiHostMsg_CancelSysExPermissionRequest,
- OnCancelSysExPermissionRequest)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -64,30 +78,33 @@ void MidiDispatcherHost::OnRequestSysExPermission(
render_process_id, render_frame_id, bridge_id);
pending_permissions_.push_back(pending_permission);
- GetContentClient()->browser()->RequestMidiSysExPermission(
+ GetContentClient()->browser()->RequestPermission(
+ PERMISSION_MIDI_SYSEX,
web_contents(),
bridge_id,
origin,
user_gesture,
base::Bind(&MidiDispatcherHost::WasSysExPermissionGranted,
weak_factory_.GetWeakPtr(),
- render_process_id, render_frame_id, bridge_id),
- &pending_permissions_.back().cancel);
+ render_process_id,
+ render_frame_id,
+ bridge_id));
}
-void MidiDispatcherHost::OnCancelSysExPermissionRequest(
- RenderFrameHost* render_frame_host,
- int bridge_id,
- const GURL& requesting_frame) {
+void MidiDispatcherHost::CancelPermissionRequestsForFrame(
+ RenderFrameHost* render_frame_host) {
int render_process_id = render_frame_host->GetProcess()->GetID();
int render_frame_id = render_frame_host->GetRoutingID();
for (size_t i = 0; i < pending_permissions_.size(); ++i) {
if (pending_permissions_[i].render_process_id == render_process_id &&
- pending_permissions_[i].render_frame_id == render_frame_id &&
- pending_permissions_[i].bridge_id == bridge_id) {
- if (!pending_permissions_[i].cancel.is_null())
- pending_permissions_[i].cancel.Run();
+ pending_permissions_[i].render_frame_id == render_frame_id) {
+ GetContentClient()->browser()->CancelPermissionRequest(
+ PERMISSION_MIDI_SYSEX,
+ web_contents(),
+ pending_permissions_[i].bridge_id,
+ render_frame_host->GetLastCommittedURL());
+
pending_permissions_.erase(pending_permissions_.begin() + i);
return;
}
diff --git a/chromium/content/browser/media/midi_dispatcher_host.h b/chromium/content/browser/media/midi_dispatcher_host.h
index 87b7b1df776..a487178851d 100644
--- a/chromium/content/browser/media/midi_dispatcher_host.h
+++ b/chromium/content/browser/media/midi_dispatcher_host.h
@@ -19,11 +19,15 @@ class BrowserContext;
class MidiDispatcherHost : public WebContentsObserver {
public:
explicit MidiDispatcherHost(WebContents* web_contents);
- virtual ~MidiDispatcherHost();
+ ~MidiDispatcherHost() override;
// WebContentsObserver implementation.
- virtual bool OnMessageReceived(const IPC::Message& message,
- RenderFrameHost* render_frame_host) OVERRIDE;
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+ void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) override;
private:
void OnRequestSysExPermission(RenderFrameHost* render_frame_host,
@@ -37,6 +41,7 @@ class MidiDispatcherHost : public WebContentsObserver {
int render_frame_id,
int bridge_id,
bool is_allowed);
+ void CancelPermissionRequestsForFrame(RenderFrameHost* render_frame_host);
struct PendingPermission {
PendingPermission(int render_process_id,
@@ -46,7 +51,6 @@ class MidiDispatcherHost : public WebContentsObserver {
int render_process_id;
int render_frame_id;
int bridge_id;
- base::Closure cancel;
};
std::vector<PendingPermission> pending_permissions_;
diff --git a/chromium/content/browser/media/midi_host.cc b/chromium/content/browser/media/midi_host.cc
index 950cf48e0a9..2fc01478575 100644
--- a/chromium/content/browser/media/midi_host.cc
+++ b/chromium/content/browser/media/midi_host.cc
@@ -52,13 +52,16 @@ MidiHost::MidiHost(int renderer_process_id, media::MidiManager* midi_manager)
: BrowserMessageFilter(MidiMsgStart),
renderer_process_id_(renderer_process_id),
has_sys_ex_permission_(false),
+ is_session_requested_(false),
midi_manager_(midi_manager),
sent_bytes_in_flight_(0),
bytes_sent_since_last_acknowledgement_(0) {
+ CHECK(midi_manager_);
}
MidiHost::~MidiHost() {
- if (midi_manager_)
+ // Close an open session, or abort opening a session.
+ if (is_session_requested_)
midi_manager_->EndSession(this);
}
@@ -72,23 +75,21 @@ bool MidiHost::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(MidiHost, message)
IPC_MESSAGE_HANDLER(MidiHostMsg_StartSession, OnStartSession)
IPC_MESSAGE_HANDLER(MidiHostMsg_SendData, OnSendData)
+ IPC_MESSAGE_HANDLER(MidiHostMsg_EndSession, OnEndSession)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void MidiHost::OnStartSession(int client_id) {
- if (midi_manager_)
- midi_manager_->StartSession(this, client_id);
+void MidiHost::OnStartSession() {
+ is_session_requested_ = true;
+ midi_manager_->StartSession(this);
}
void MidiHost::OnSendData(uint32 port,
const std::vector<uint8>& data,
double timestamp) {
- if (!midi_manager_)
- return;
-
if (data.empty())
return;
@@ -117,25 +118,31 @@ void MidiHost::OnSendData(uint32 port,
midi_manager_->DispatchSendMidiData(this, port, data, timestamp);
}
-void MidiHost::CompleteStartSession(int client_id, media::MidiResult result) {
- MidiPortInfoList input_ports;
- MidiPortInfoList output_ports;
+void MidiHost::OnEndSession() {
+ is_session_requested_ = false;
+ midi_manager_->EndSession(this);
+}
+void MidiHost::CompleteStartSession(media::MidiResult result) {
+ DCHECK(is_session_requested_);
if (result == media::MIDI_OK) {
- input_ports = midi_manager_->input_ports();
- output_ports = midi_manager_->output_ports();
- received_messages_queues_.clear();
- received_messages_queues_.resize(input_ports.size());
// ChildSecurityPolicy is set just before OnStartSession by
// MidiDispatcherHost. So we can safely cache the policy.
has_sys_ex_permission_ = ChildProcessSecurityPolicyImpl::GetInstance()->
CanSendMidiSysExMessage(renderer_process_id_);
}
+ Send(new MidiMsg_SessionStarted(result));
+}
+
+void MidiHost::AddInputPort(const media::MidiPortInfo& info) {
+ base::AutoLock auto_lock(messages_queues_lock_);
+ // MidiMessageQueue is created later in ReceiveMidiData().
+ received_messages_queues_.push_back(nullptr);
+ Send(new MidiMsg_AddInputPort(info));
+}
- Send(new MidiMsg_SessionStarted(client_id,
- result,
- input_ports,
- output_ports));
+void MidiHost::AddOutputPort(const media::MidiPortInfo& info) {
+ Send(new MidiMsg_AddOutputPort(info));
}
void MidiHost::ReceiveMidiData(
@@ -145,11 +152,12 @@ void MidiHost::ReceiveMidiData(
double timestamp) {
TRACE_EVENT0("midi", "MidiHost::ReceiveMidiData");
+ base::AutoLock auto_lock(messages_queues_lock_);
if (received_messages_queues_.size() <= port)
return;
// Lazy initialization
- if (received_messages_queues_[port] == NULL)
+ if (received_messages_queues_[port] == nullptr)
received_messages_queues_[port] = new media::MidiMessageQueue(true);
received_messages_queues_[port]->Add(data, length);
diff --git a/chromium/content/browser/media/midi_host.h b/chromium/content/browser/media/midi_host.h
index 8be45d8218f..3a469bf93b9 100644
--- a/chromium/content/browser/media/midi_host.h
+++ b/chromium/content/browser/media/midi_host.h
@@ -11,6 +11,7 @@
#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"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
@@ -31,32 +32,35 @@ class CONTENT_EXPORT MidiHost
MidiHost(int renderer_process_id, media::MidiManager* midi_manager);
// BrowserMessageFilter implementation.
- virtual void OnDestruct() const OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// MidiManagerClient implementation.
- virtual void CompleteStartSession(int client_id,
- media::MidiResult result) OVERRIDE;
- virtual void ReceiveMidiData(uint32 port,
- const uint8* data,
- size_t length,
- double timestamp) OVERRIDE;
- virtual void AccumulateMidiBytesSent(size_t n) OVERRIDE;
+ void CompleteStartSession(media::MidiResult result) override;
+ void AddInputPort(const media::MidiPortInfo& info) override;
+ void AddOutputPort(const media::MidiPortInfo& info) override;
+ void ReceiveMidiData(uint32 port,
+ const uint8* data,
+ size_t length,
+ double timestamp) override;
+ void AccumulateMidiBytesSent(size_t n) override;
// Start session to access MIDI hardware.
- void OnStartSession(int client_id);
+ void OnStartSession();
// Data to be sent to a MIDI output port.
void OnSendData(uint32 port,
const std::vector<uint8>& data,
double timestamp);
+ void OnEndSession();
+
private:
FRIEND_TEST_ALL_PREFIXES(MidiHostTest, IsValidWebMIDIData);
friend class base::DeleteHelper<MidiHost>;
friend class BrowserThread;
- virtual ~MidiHost();
+ ~MidiHost() override;
// Returns true if |data| fulfills the requirements of MidiOutput.send API
// defined in the WebMIDI spec.
@@ -71,6 +75,9 @@ class CONTENT_EXPORT MidiHost
// messages.
bool has_sys_ex_permission_;
+ // Represents if a session is requested to start.
+ bool is_session_requested_;
+
// |midi_manager_| talks to the platform-specific MIDI APIs.
// It can be NULL if the platform (or our current implementation)
// does not support MIDI. If not supported then a call to
@@ -81,6 +88,9 @@ class CONTENT_EXPORT MidiHost
// Buffers where data sent from each MIDI input port is stored.
ScopedVector<media::MidiMessageQueue> received_messages_queues_;
+ // Protects access to |received_messages_queues_|;
+ base::Lock messages_queues_lock_;
+
// The number of bytes sent to the platform-specific MIDI sending
// system, but not yet completed.
size_t sent_bytes_in_flight_;
diff --git a/chromium/content/browser/media/webrtc_aecdump_browsertest.cc b/chromium/content/browser/media/webrtc_aecdump_browsertest.cc
new file mode 100644
index 00000000000..bdeed59bea7
--- /dev/null
+++ b/chromium/content/browser/media/webrtc_aecdump_browsertest.cc
@@ -0,0 +1,233 @@
+// 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 "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/media/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"
+#include "content/shell/browser/shell.h"
+#include "content/test/webrtc_content_browsertest_base.h"
+#include "media/audio/audio_manager.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace {
+
+const int kExpectedConsumerId = 0;
+
+// Get the ID for the render process host when there should only be one.
+bool GetRenderProcessHostId(base::ProcessId* id) {
+ content::RenderProcessHost::iterator it(
+ content::RenderProcessHost::AllHostsIterator());
+ *id = base::GetProcId(it.GetCurrentValue()->GetHandle());
+ EXPECT_NE(base::kNullProcessId, *id);
+ if (*id == base::kNullProcessId)
+ return false;
+ it.Advance();
+ EXPECT_TRUE(it.IsAtEnd());
+ return it.IsAtEnd();
+}
+
+} // namespace
+
+namespace content {
+
+class WebRtcAecDumpBrowserTest : public WebRtcContentBrowserTest {
+ public:
+ WebRtcAecDumpBrowserTest() {}
+ ~WebRtcAecDumpBrowserTest() override {}
+};
+
+#if defined(OS_WIN)
+#define IntToStringType base::IntToString16
+#else
+#define IntToStringType base::IntToString
+#endif
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
+// Timing out on ARM linux bot: http://crbug.com/238490
+#define MAYBE_CallWithAecDump DISABLED_CallWithAecDump
+#elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+// Renderer crashes under Android ASAN: https://crbug.com/408496.
+#define MAYBE_CallWithAecDump DISABLED_CallWithAecDump
+#else
+#define MAYBE_CallWithAecDump CallWithAecDump
+#endif
+
+// This tests will make a complete PeerConnection-based call, verify that
+// video is playing for the call, and verify that a non-empty AEC dump file
+// exists. The AEC dump is enabled through webrtc-internals. The HTML and
+// Javascript is bypassed since it would trigger a file picker dialog. Instead,
+// the dialog callback FileSelected() is invoked directly. In fact, there's
+// never a webrtc-internals page opened at all since that's not needed.
+IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest, MAYBE_CallWithAecDump) {
+ if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
+ LOG(INFO) << "Missing output devices: skipping test...";
+ return;
+ }
+
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ // We must navigate somewhere first so that the render process is created.
+ NavigateToURL(shell(), GURL(""));
+
+ base::FilePath dump_file;
+ ASSERT_TRUE(CreateTemporaryFile(&dump_file));
+ base::DeleteFile(dump_file, false);
+
+ // This fakes the behavior of another open tab with webrtc-internals, and
+ // enabling AEC dump in that tab.
+ WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL);
+
+ GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
+ NavigateToURL(shell(), url);
+ DisableOpusIfOnAndroid();
+ ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
+
+ EXPECT_FALSE(base::PathExists(dump_file));
+
+ // Add file extensions that we expect to be added. The dump name will be
+ // <temporary path>.<render process id>.<consumer id>, for example
+ // "/tmp/.com.google.Chrome.Z6UC3P.12345.0".
+ base::ProcessId render_process_id = base::kNullProcessId;
+ EXPECT_TRUE(GetRenderProcessHostId(&render_process_id));
+ dump_file = dump_file.AddExtension(IntToStringType(render_process_id))
+ .AddExtension(IntToStringType(kExpectedConsumerId));
+
+ EXPECT_TRUE(base::PathExists(dump_file));
+ int64 file_size = 0;
+ EXPECT_TRUE(base::GetFileSize(dump_file, &file_size));
+ EXPECT_GT(file_size, 0);
+
+ base::DeleteFile(dump_file, false);
+}
+
+// TODO(grunell): Add test for multiple dumps when re-use of
+// MediaStreamAudioProcessor in AudioCapturer has been removed.
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
+// Timing out on ARM linux bot: http://crbug.com/238490
+#define MAYBE_CallWithAecDumpEnabledThenDisabled DISABLED_CallWithAecDumpEnabledThenDisabled
+#elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+// Renderer crashes under Android ASAN: https://crbug.com/408496.
+#define MAYBE_CallWithAecDumpEnabledThenDisabled DISABLED_CallWithAecDumpEnabledThenDisabled
+#else
+#define MAYBE_CallWithAecDumpEnabledThenDisabled CallWithAecDumpEnabledThenDisabled
+#endif
+
+// As above, but enable and disable dump before starting a call. The file should
+// be created, but should be empty.
+IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest,
+ MAYBE_CallWithAecDumpEnabledThenDisabled) {
+ if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
+ LOG(INFO) << "Missing output devices: skipping test...";
+ return;
+ }
+
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ // We must navigate somewhere first so that the render process is created.
+ NavigateToURL(shell(), GURL(""));
+
+ base::FilePath dump_file;
+ ASSERT_TRUE(CreateTemporaryFile(&dump_file));
+ base::DeleteFile(dump_file, false);
+
+ // This fakes the behavior of another open tab with webrtc-internals, and
+ // enabling AEC dump in that tab, then disabling it.
+ WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL);
+ WebRTCInternals::GetInstance()->DisableAecDump();
+
+ GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
+ NavigateToURL(shell(), url);
+ DisableOpusIfOnAndroid();
+ ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
+
+ // Add file extensions that we expect to be added.
+ base::ProcessId render_process_id = base::kNullProcessId;
+ EXPECT_TRUE(GetRenderProcessHostId(&render_process_id));
+ dump_file = dump_file.AddExtension(IntToStringType(render_process_id))
+ .AddExtension(IntToStringType(kExpectedConsumerId));
+
+ EXPECT_FALSE(base::PathExists(dump_file));
+
+ base::DeleteFile(dump_file, false);
+}
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
+// Timing out on ARM linux bot: http://crbug.com/238490
+#define MAYBE_TwoCallsWithAecDump DISABLED_TwoCallsWithAecDump
+#elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+// Renderer crashes under Android ASAN: https://crbug.com/408496.
+#define MAYBE_TwoCallsWithAecDump DISABLED_TwoCallsWithAecDump
+#else
+#define MAYBE_TwoCallsWithAecDump TwoCallsWithAecDump
+#endif
+
+IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest, MAYBE_TwoCallsWithAecDump) {
+ if (OnWinXp()) {
+ // http://crbug.com/425034.
+ LOG(INFO) << "Disabled on Win XP: skipping test...";
+ return;
+ }
+ if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
+ LOG(INFO) << "Missing output devices: skipping test...";
+ return;
+ }
+
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ // We must navigate somewhere first so that the render process is created.
+ NavigateToURL(shell(), GURL(""));
+
+ // Create a second window.
+ Shell* shell2 = CreateBrowser();
+ NavigateToURL(shell2, GURL(""));
+
+ base::FilePath dump_file;
+ ASSERT_TRUE(CreateTemporaryFile(&dump_file));
+ base::DeleteFile(dump_file, false);
+
+ // This fakes the behavior of another open tab with webrtc-internals, and
+ // enabling AEC dump in that tab.
+ WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL);
+
+ GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
+
+ NavigateToURL(shell(), url);
+ NavigateToURL(shell2, url);
+ ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
+ std::string result;
+ EXPECT_TRUE(ExecuteScriptAndExtractString(
+ shell2->web_contents(),
+ "call({video: true, audio: true});",
+ &result));
+ ASSERT_STREQ("OK", result.c_str());
+
+ EXPECT_FALSE(base::PathExists(dump_file));
+
+ RenderProcessHost::iterator it =
+ content::RenderProcessHost::AllHostsIterator();
+ for (; !it.IsAtEnd(); it.Advance()) {
+ base::ProcessId render_process_id =
+ base::GetProcId(it.GetCurrentValue()->GetHandle());
+ EXPECT_NE(base::kNullProcessId, render_process_id);
+
+ // Add file extensions that we expect to be added.
+ base::FilePath unique_dump_file =
+ dump_file.AddExtension(IntToStringType(render_process_id))
+ .AddExtension(IntToStringType(kExpectedConsumerId));
+
+ EXPECT_TRUE(base::PathExists(unique_dump_file));
+ int64 file_size = 0;
+ EXPECT_TRUE(base::GetFileSize(unique_dump_file, &file_size));
+ EXPECT_GT(file_size, 0);
+
+ base::DeleteFile(unique_dump_file, false);
+ }
+}
+
+} // namespace content
diff --git a/chromium/content/browser/media/webrtc_browsertest.cc b/chromium/content/browser/media/webrtc_browsertest.cc
index f5bb216ead0..45c3623550a 100644
--- a/chromium/content/browser/media/webrtc_browsertest.cc
+++ b/chromium/content/browser/media/webrtc_browsertest.cc
@@ -3,50 +3,47 @@
// found in the LICENSE file.
#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/strings/string_number_conversions.h"
+#include "base/files/file_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
-#include "base/values.h"
-#include "content/browser/media/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"
#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/webrtc_content_browsertest_base.h"
#include "media/audio/audio_manager.h"
#include "media/base/media_switches.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
+namespace {
#if defined (OS_ANDROID) || defined(THREAD_SANITIZER)
// Just do the bare minimum of audio checking on Android and under TSAN since
// it's a bit sensitive to device performance.
-static const char kUseLenientAudioChecking[] = "true";
+const char kUseLenientAudioChecking[] = "true";
#else
-static const char kUseLenientAudioChecking[] = "false";
+const char kUseLenientAudioChecking[] = "false";
#endif
-namespace content {
+} // namespace
-class WebRtcBrowserTest : public WebRtcContentBrowserTest,
- public testing::WithParamInterface<bool> {
- public:
- WebRtcBrowserTest() {}
- virtual ~WebRtcBrowserTest() {}
+namespace content {
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
- WebRtcContentBrowserTest::SetUpCommandLine(command_line);
+#if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
+// Renderer crashes under Android ASAN: https://crbug.com/408496.
+#define MAYBE_WebRtcBrowserTest DISABLED_WebRtcBrowserTest
+#elif defined(OS_ANDROID) && defined(__aarch64__)
+// Failures on ARM64 Android: http://crbug.com/408179.
+#define MAYBE_WebRtcBrowserTest DISABLED_WebRtcBrowserTest
+#else
+#define MAYBE_WebRtcBrowserTest WebRtcBrowserTest
+#endif
- bool enable_audio_track_processing = GetParam();
- if (!enable_audio_track_processing)
- command_line->AppendSwitch(switches::kDisableAudioTrackProcessing);
- }
+class MAYBE_WebRtcBrowserTest : public WebRtcContentBrowserTest {
+ public:
+ MAYBE_WebRtcBrowserTest() {}
+ ~MAYBE_WebRtcBrowserTest() override {}
// Convenience function since most peerconnection-call.html tests just load
// the page, kick off some javascript and wait for the title to change to OK.
@@ -73,65 +70,100 @@ class WebRtcBrowserTest : public WebRtcContentBrowserTest,
return;
}
- ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
+ ASSERT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseFakeDeviceForMediaStream))
<< "Must run with fake devices since the test will explicitly look "
<< "for the fake device signal.";
MakeTypicalPeerConnectionCall(javascript);
}
-
- void DisableOpusIfOnAndroid() {
-#if defined(OS_ANDROID)
- // Always force iSAC 16K on Android for now (Opus is broken).
- EXPECT_EQ("isac-forced",
- ExecuteJavascriptAndReturnResult("forceIsac16KInSdp();"));
-#endif
- }
};
-static const bool kRunTestsWithFlag[] = { false, true };
-INSTANTIATE_TEST_CASE_P(WebRtcBrowserTests,
- WebRtcBrowserTest,
- testing::ValuesIn(kRunTestsWithFlag));
-
#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
// Timing out on ARM linux bot: http://crbug.com/238490
#define MAYBE_CanSetupDefaultVideoCall DISABLED_CanSetupDefaultVideoCall
+// Flaky on TSAN v2. http://crbug.com/408006
+#elif defined(THREAD_SANITIZER)
+#define MAYBE_CanSetupDefaultVideoCall DISABLED_CanSetupDefaultVideoCall
#else
#define MAYBE_CanSetupDefaultVideoCall CanSetupDefaultVideoCall
#endif
// These tests will make a complete PeerConnection-based call and verify that
// video is playing for the call.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanSetupDefaultVideoCall) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CanSetupDefaultVideoCall) {
MakeTypicalPeerConnectionCall(
"callAndExpectResolution({video: true}, 640, 480);");
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CanSetupVideoCallWith1To1AspecRatio) {
+// Flaky on TSAN v2. http://crbug.com/408006
+#if defined(THREAD_SANITIZER)
+#define MAYBE_CanSetupVideoCallWith1To1AspectRatio \
+ DISABLED_CanSetupVideoCallWith1To1AspectRatio
+#else
+#define MAYBE_CanSetupVideoCallWith1To1AspectRatio \
+ CanSetupVideoCallWith1To1AspectRatio
+#endif
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CanSetupVideoCallWith1To1AspectRatio) {
const std::string javascript =
"callAndExpectResolution({video: {mandatory: {minWidth: 320,"
" maxWidth: 320, minHeight: 320, maxHeight: 320}}}, 320, 320);";
MakeTypicalPeerConnectionCall(javascript);
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
- CanSetupVideoCallWith16To9AspecRatio) {
+#if defined(OS_ANDROID) && defined(ARCH_CPU_ARM64)
+// Failing on ARM64 Android bot: http://crbug.com/408179
+#define MAYBE_CanSetupVideoCallWith16To9AspectRatio \
+ DISABLED_CanSetupVideoCallWith16To9AspectRatio
+// Flaky on TSAN v2. http://crbug.com/408006
+#elif defined(THREAD_SANITIZER)
+#define MAYBE_CanSetupVideoCallWith16To9AspectRatio \
+ DISABLED_CanSetupVideoCallWith16To9AspectRatio
+#else
+#define MAYBE_CanSetupVideoCallWith16To9AspectRatio \
+ CanSetupVideoCallWith16To9AspectRatio
+#endif
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CanSetupVideoCallWith16To9AspectRatio) {
const std::string javascript =
"callAndExpectResolution({video: {mandatory: {minWidth: 640,"
" maxWidth: 640, minAspectRatio: 1.777}}}, 640, 360);";
MakeTypicalPeerConnectionCall(javascript);
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
- CanSetupVideoCallWith4To3AspecRatio) {
+// Flaky on TSAN v2. http://crbug.com/408006
+#if defined(THREAD_SANITIZER)
+#define MAYBE_CanSetupVideoCallWith4To3AspectRatio \
+ DISABLED_CanSetupVideoCallWith4To3AspectRatio
+#else
+#define MAYBE_CanSetupVideoCallWith4To3AspectRatio \
+ CanSetupVideoCallWith4To3AspectRatio
+#endif
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CanSetupVideoCallWith4To3AspectRatio) {
const std::string javascript =
"callAndExpectResolution({video: {mandatory: {minWidth: 960,"
"maxAspectRatio: 1.333}}}, 960, 720);";
MakeTypicalPeerConnectionCall(javascript);
}
+// Flaky on TSAN v2. http://crbug.com/408006
+#if defined(THREAD_SANITIZER)
+#define MAYBE_CanSetupVideoCallAndDisableLocalVideo \
+ DISABLED_CanSetupVideoCallAndDisableLocalVideo
+#else
+#define MAYBE_CanSetupVideoCallAndDisableLocalVideo \
+ CanSetupVideoCallAndDisableLocalVideo
+#endif
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CanSetupVideoCallAndDisableLocalVideo) {
+ const std::string javascript =
+ "callAndDisableLocalVideo({video: true});";
+ MakeTypicalPeerConnectionCall(javascript);
+}
+
#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
// Timing out on ARM linux, see http://crbug.com/240376
#define MAYBE_CanSetupAudioAndVideoCall DISABLED_CanSetupAudioAndVideoCall
@@ -139,18 +171,20 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
#define MAYBE_CanSetupAudioAndVideoCall CanSetupAudioAndVideoCall
#endif
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanSetupAudioAndVideoCall) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CanSetupAudioAndVideoCall) {
MakeTypicalPeerConnectionCall("call({video: true, audio: true});");
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MANUAL_CanSetupCallAndSendDtmf) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MANUAL_CanSetupCallAndSendDtmf) {
MakeTypicalPeerConnectionCall("callAndSendDtmf(\'123,abc\');");
}
// TODO(phoglund): this test fails because the peer connection state will be
// stable in the second negotiation round rather than have-local-offer.
// http://crbug.com/293125.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
DISABLED_CanMakeEmptyCallThenAddStreamsAndRenegotiate) {
const char* kJavascript =
"callEmptyThenAddOneStreamAndRenegotiate({video: true, audio: true});";
@@ -163,37 +197,33 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
// The stream sent from pc3 to pc4 is the stream received on pc1.
// The stream sent from pc4 to pc3 is cloned from stream the stream received
// on pc2.
-// Flaky on win xp. http://crbug.com/304775
-#if defined(OS_WIN)
+#if defined(THREAD_SANITIZER)
+// Flaky on TSAN v2. http://crbug.com/373637
#define MAYBE_CanForwardRemoteStream DISABLED_CanForwardRemoteStream
#define MAYBE_CanForwardRemoteStream720p DISABLED_CanForwardRemoteStream720p
#else
#define MAYBE_CanForwardRemoteStream CanForwardRemoteStream
-// Flaky on TSAN v2. http://crbug.com/373637
-#if defined(THREAD_SANITIZER)
-#define MAYBE_CanForwardRemoteStream720p DISABLED_CanForwardRemoteStream720p
-#else
#define MAYBE_CanForwardRemoteStream720p CanForwardRemoteStream720p
#endif
-#endif
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanForwardRemoteStream) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, MAYBE_CanForwardRemoteStream) {
#if defined (OS_ANDROID)
// This test fails on Nexus 5 devices.
// TODO(henrika): see http://crbug.com/362437 and http://crbug.com/359389
// for details.
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kDisableWebRtcHWDecoding);
#endif
MakeTypicalPeerConnectionCall(
"callAndForwardRemoteStream({video: true, audio: false});");
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanForwardRemoteStream720p) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CanForwardRemoteStream720p) {
#if defined (OS_ANDROID)
// This test fails on Nexus 5 devices.
// TODO(henrika): see http://crbug.com/362437 and http://crbug.com/359389
// for details.
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kDisableWebRtcHWDecoding);
#endif
const std::string javascript = GenerateGetUserMediaCall(
@@ -201,6 +231,11 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanForwardRemoteStream720p) {
MakeTypicalPeerConnectionCall(javascript);
}
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ NoCrashWhenConnectChromiumSinkToRemoteTrack) {
+ MakeTypicalPeerConnectionCall("ConnectChromiumSinkToRemoteAudioTrack();");
+}
+
// This test will make a complete PeerConnection-based call but remove the
// MSID and bundle attribute from the initial offer to verify that
// video is playing for the call even if the initiating client don't support
@@ -213,26 +248,27 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanForwardRemoteStream720p) {
#define MAYBE_CanSetupAudioAndVideoCallWithoutMsidAndBundle\
CanSetupAudioAndVideoCallWithoutMsidAndBundle
#endif
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
MAYBE_CanSetupAudioAndVideoCallWithoutMsidAndBundle) {
MakeTypicalPeerConnectionCall("callWithoutMsidAndBundle();");
}
// This test will modify the SDP offer to an unsupported codec, which should
// cause SetLocalDescription to fail.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, NegotiateUnsupportedVideoCodec) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ NegotiateUnsupportedVideoCodec) {
MakeTypicalPeerConnectionCall("negotiateUnsupportedVideoCodec();");
}
// This test will modify the SDP offer to use no encryption, which should
// cause SetLocalDescription to fail.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, NegotiateNonCryptoCall) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, NegotiateNonCryptoCall) {
MakeTypicalPeerConnectionCall("negotiateNonCryptoCall();");
}
// This test can negotiate an SDP offer that includes a b=AS:xx to control
// the bandwidth for audio and video
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, NegotiateOfferWithBLine) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, NegotiateOfferWithBLine) {
MakeTypicalPeerConnectionCall("negotiateOfferWithBLine();");
}
@@ -245,18 +281,24 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, NegotiateOfferWithBLine) {
#define MAYBE_CanSetupLegacyCall CanSetupLegacyCall
#endif
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanSetupLegacyCall) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, MAYBE_CanSetupLegacyCall) {
MakeTypicalPeerConnectionCall("callWithLegacySdp();");
}
// This test will make a PeerConnection-based call and test an unreliable text
// dataChannel.
// TODO(mallinath) - Remove this test after rtp based data channel is disabled.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CallWithDataOnly) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CallWithDataOnly) {
MakeTypicalPeerConnectionCall("callWithDataOnly();");
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CallWithSctpDataOnly) {
+#if defined(MEMORY_SANITIZER)
+// Fails under MemorySanitizer: http://crbug.com/405951
+#define MAYBE_CallWithSctpDataOnly DISABLED_CallWithSctpDataOnly
+#else
+#define MAYBE_CallWithSctpDataOnly CallWithSctpDataOnly
+#endif
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, MAYBE_CallWithSctpDataOnly) {
MakeTypicalPeerConnectionCall("callWithSctpDataOnly();");
}
@@ -270,19 +312,21 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CallWithSctpDataOnly) {
// This test will make a PeerConnection-based call and test an unreliable text
// dataChannel and audio and video tracks.
// TODO(mallinath) - Remove this test after rtp based data channel is disabled.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, DISABLED_CallWithDataAndMedia) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, MAYBE_CallWithDataAndMedia) {
MakeTypicalPeerConnectionCall("callWithDataAndMedia();");
}
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
+#if (defined(OS_LINUX) && !defined(OS_CHROMEOS) && \
+ defined(ARCH_CPU_ARM_FAMILY)) || defined(MEMORY_SANITIZER)
// Timing out on ARM linux bot: http://crbug.com/238490
+// Fails under MemorySanitizer: http://crbug.com/405951
#define MAYBE_CallWithSctpDataAndMedia DISABLED_CallWithSctpDataAndMedia
#else
#define MAYBE_CallWithSctpDataAndMedia CallWithSctpDataAndMedia
#endif
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
MAYBE_CallWithSctpDataAndMedia) {
MakeTypicalPeerConnectionCall("callWithSctpDataAndMedia();");
}
@@ -297,7 +341,8 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
// This test will make a PeerConnection-based call and test an unreliable text
// dataChannel and later add an audio and video track.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CallWithDataAndLaterAddMedia) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CallWithDataAndLaterAddMedia) {
MakeTypicalPeerConnectionCall("callWithDataAndLaterAddMedia();");
}
@@ -311,7 +356,8 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CallWithDataAndLaterAddMedia) {
// This test will make a PeerConnection-based call and send a new Video
// MediaStream that has been created based on a MediaStream created with
// getUserMedia.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CallWithNewVideoMediaStream) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ MAYBE_CallWithNewVideoMediaStream) {
MakeTypicalPeerConnectionCall("callWithNewVideoMediaStream();");
}
@@ -321,33 +367,55 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CallWithNewVideoMediaStream) {
// AudioTrack is added instead.
// TODO(phoglund): This test is manual since not all buildbots has an audio
// input.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MANUAL_CallAndModifyStream) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, MANUAL_CallAndModifyStream) {
MakeTypicalPeerConnectionCall(
"callWithNewVideoMediaStreamLaterSwitchToAudio();");
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, AddTwoMediaStreamsToOnePC) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, AddTwoMediaStreamsToOnePC) {
MakeTypicalPeerConnectionCall("addTwoMediaStreamsToOneConnection();");
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
EstablishAudioVideoCallAndEnsureAudioIsPlaying) {
MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
"callAndEnsureAudioIsPlaying(%s, {audio:true, video:true});",
kUseLenientAudioChecking));
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
EstablishAudioOnlyCallAndEnsureAudioIsPlaying) {
MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
"callAndEnsureAudioIsPlaying(%s, {audio:true});",
kUseLenientAudioChecking));
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
- EstablishAudioVideoCallAndVerifyMutingWorks) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ EstablishAudioVideoCallAndVerifyRemoteMutingWorks) {
MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
- "callAndEnsureAudioTrackMutingWorks(%s);", kUseLenientAudioChecking));
+ "callAndEnsureRemoteAudioTrackMutingWorks(%s);",
+ kUseLenientAudioChecking));
+}
+
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ EstablishAudioVideoCallAndVerifyLocalMutingWorks) {
+ MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
+ "callAndEnsureLocalAudioTrackMutingWorks(%s);",
+ kUseLenientAudioChecking));
+}
+
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ EnsureLocalVideoMuteDoesntMuteAudio) {
+ MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
+ "callAndEnsureLocalVideoMutingDoesntMuteAudio(%s);",
+ kUseLenientAudioChecking));
+}
+
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
+ EnsureRemoteVideoMuteDoesntMuteAudio) {
+ MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
+ "callAndEnsureRemoteVideoMutingDoesntMuteAudio(%s);",
+ kUseLenientAudioChecking));
}
// Flaky on TSAN v2: http://crbug.com/373637
@@ -358,110 +426,18 @@ IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
#define MAYBE_EstablishAudioVideoCallAndVerifyUnmutingWorks\
EstablishAudioVideoCallAndVerifyUnmutingWorks
#endif
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
MAYBE_EstablishAudioVideoCallAndVerifyUnmutingWorks) {
MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
"callAndEnsureAudioTrackUnmutingWorks(%s);", kUseLenientAudioChecking));
}
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CallAndVerifyVideoMutingWorks) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CallAndVerifyVideoMutingWorks) {
MakeTypicalPeerConnectionCall("callAndEnsureVideoTrackMutingWorks();");
}
-#if defined(OS_WIN)
-#define IntToStringType base::IntToString16
-#else
-#define IntToStringType base::IntToString
-#endif
-
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
-// Timing out on ARM linux bot: http://crbug.com/238490
-#define MAYBE_CallWithAecDump DISABLED_CallWithAecDump
-#else
-#define MAYBE_CallWithAecDump CallWithAecDump
-#endif
-
-// This tests will make a complete PeerConnection-based call, verify that
-// video is playing for the call, and verify that a non-empty AEC dump file
-// exists. The AEC dump is enabled through webrtc-internals. The HTML and
-// Javascript is bypassed since it would trigger a file picker dialog. Instead,
-// the dialog callback FileSelected() is invoked directly. In fact, there's
-// never a webrtc-internals page opened at all since that's not needed.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CallWithAecDump) {
- ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
-
- // We must navigate somewhere first so that the render process is created.
- NavigateToURL(shell(), GURL(""));
-
- base::FilePath dump_file;
- ASSERT_TRUE(CreateTemporaryFile(&dump_file));
-
- // This fakes the behavior of another open tab with webrtc-internals, and
- // enabling AEC dump in that tab.
- WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL);
-
- GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
- NavigateToURL(shell(), url);
- DisableOpusIfOnAndroid();
- ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
-
- // Get the ID for the render process host. There should only be one.
- RenderProcessHost::iterator it(
- content::RenderProcessHost::AllHostsIterator());
- int render_process_host_id = it.GetCurrentValue()->GetID();
- EXPECT_GE(render_process_host_id, 0);
-
- // Add file extensions that we expect to be added.
- static const int kExpectedConsumerId = 0;
- dump_file = dump_file.AddExtension(IntToStringType(render_process_host_id))
- .AddExtension(IntToStringType(kExpectedConsumerId));
-
- EXPECT_TRUE(base::PathExists(dump_file));
- int64 file_size = 0;
- EXPECT_TRUE(base::GetFileSize(dump_file, &file_size));
- EXPECT_GT(file_size, 0);
-
- base::DeleteFile(dump_file, false);
-}
-
-// TODO(grunell): Add test for multiple dumps when re-use of
-// MediaStreamAudioProcessor in AudioCapturer has been removed.
-
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
-// Timing out on ARM linux bot: http://crbug.com/238490
-#define MAYBE_CallWithAecDumpEnabledThenDisabled DISABLED_CallWithAecDumpEnabledThenDisabled
-#else
-#define MAYBE_CallWithAecDumpEnabledThenDisabled CallWithAecDumpEnabledThenDisabled
-#endif
-
-// As above, but enable and disable dump before starting a call. The file should
-// be created, but should be empty.
-IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest,
- MAYBE_CallWithAecDumpEnabledThenDisabled) {
- ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
-
- // We must navigate somewhere first so that the render process is created.
- NavigateToURL(shell(), GURL(""));
-
- base::FilePath dump_file;
- ASSERT_TRUE(CreateTemporaryFile(&dump_file));
-
- // This fakes the behavior of another open tab with webrtc-internals, and
- // enabling AEC dump in that tab, then disabling it.
- WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL);
- WebRTCInternals::GetInstance()->DisableAecDump();
-
- GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
- NavigateToURL(shell(), url);
- DisableOpusIfOnAndroid();
- ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
-
- EXPECT_TRUE(base::PathExists(dump_file));
- int64 file_size = 0;
- EXPECT_TRUE(base::GetFileSize(dump_file, &file_size));
- EXPECT_EQ(0, file_size);
-
- base::DeleteFile(dump_file, false);
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CreateOfferWithOfferOptions) {
+ MakeTypicalPeerConnectionCall("testCreateOfferOptions();");
}
} // namespace content
diff --git a/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc b/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc
index c7e1b4214e5..8c8bf2dba09 100644
--- a/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc
+++ b/chromium/content/browser/media/webrtc_getusermedia_browsertest.cc
@@ -75,32 +75,26 @@ std::string GenerateGetUserMediaWithOptionalSourceID(
namespace content {
-class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest,
- public testing::WithParamInterface<bool> {
+class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest {
public:
WebRtcGetUserMediaBrowserTest() : trace_log_(NULL) {}
- virtual ~WebRtcGetUserMediaBrowserTest() {}
-
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
- WebRtcContentBrowserTest::SetUpCommandLine(command_line);
-
- bool enable_audio_track_processing = GetParam();
- if (!enable_audio_track_processing)
- command_line->AppendSwitch(switches::kDisableAudioTrackProcessing);
- }
+ ~WebRtcGetUserMediaBrowserTest() override {}
void StartTracing() {
CHECK(trace_log_ == NULL) << "Can only can start tracing once";
trace_log_ = base::debug::TraceLog::GetInstance();
+ base::debug::TraceOptions trace_options(base::debug::RECORD_UNTIL_FULL);
+ trace_options.enable_sampling = true;
trace_log_->SetEnabled(base::debug::CategoryFilter("video"),
base::debug::TraceLog::RECORDING_MODE,
- base::debug::TraceLog::ENABLE_SAMPLING);
+ trace_options);
// Check that we are indeed recording.
EXPECT_EQ(trace_log_->GetNumTracesRecorded(), 1);
}
void StopTracing() {
- CHECK(message_loop_runner_ == NULL) << "Calling StopTracing more than once";
+ CHECK(message_loop_runner_.get() == NULL)
+ << "Calling StopTracing more than once";
trace_log_->SetDisabled();
message_loop_runner_ = new MessageLoopRunner;
trace_log_->Flush(base::Bind(
@@ -132,15 +126,15 @@ class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest,
// Put getUserMedia to work and let it run for a couple of seconds.
DCHECK(time_to_sample_secs);
ExecuteJavascriptAndWaitForOk(
- base::StringPrintf("%s({video: true});",
+ base::StringPrintf("%s({video: true}, 'myStreamName');",
kGetUserMediaAndGetStreamUp));
// Now the stream is up and running, start collecting traces.
StartTracing();
- // Let the stream run for a while in javascript.
ExecuteJavascriptAndWaitForOk(
- base::StringPrintf("waitAndStopVideoTrack(%d);", time_to_sample_secs));
+ base::StringPrintf("waitAndStopVideoTrack(window['myStreamName'], %d);",
+ time_to_sample_secs));
// Wait until the page title changes to "OK". Do not sleep() here since that
// would stop both this code and the browser underneath.
@@ -177,6 +171,7 @@ class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest,
graph_name, "", "interarrival_time", interarrival_us, "us", true);
}
+ // Runs the JavaScript twoGetUserMedia with |constraints1| and |constraint2|.
void RunTwoGetTwoGetUserMediaWithDifferentContraints(
const std::string& constraints1,
const std::string& constraints2,
@@ -241,15 +236,10 @@ class WebRtcGetUserMediaBrowserTest: public WebRtcContentBrowserTest,
scoped_refptr<MessageLoopRunner> message_loop_runner_;
};
-static const bool kRunTestsWithFlag[] = { false, true };
-INSTANTIATE_TEST_CASE_P(WebRtcGetUserMediaBrowserTests,
- WebRtcGetUserMediaBrowserTest,
- testing::ValuesIn(kRunTestsWithFlag));
-
// These tests will all make a getUserMedia call with different constraints and
// see that the success callback is called. If the error callback is called or
// none of the callbacks are called the tests will simply time out and fail.
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) {
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
@@ -259,7 +249,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, GetVideoStreamAndStop) {
base::StringPrintf("%s({video: true});", kGetUserMediaAndStop));
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
RenderSameTrackMediastreamAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -271,7 +261,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
kRenderSameTrackMediastreamAndStop));
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
RenderClonedMediastreamAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -284,7 +274,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
kRenderClonedMediastreamAndStop));
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
kRenderClonedTrackMediastreamAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -296,7 +286,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
kRenderClonedTrackMediastreamAndStop));
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
kRenderDuplicatedMediastreamAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -308,7 +298,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
kRenderDuplicatedMediastreamAndStop));
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
GetAudioAndVideoStreamAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -319,7 +309,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
"%s({video: true, audio: true});", kGetUserMediaAndStop));
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
GetAudioAndVideoStreamAndClone) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -329,7 +319,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
ExecuteJavascriptAndWaitForOk("getUserMediaAndClone();");
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
RenderVideoTrackInMultipleTagsAndPause) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -341,7 +331,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
GetUserMediaWithMandatorySourceID) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -366,7 +356,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
}
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
GetUserMediaWithInvalidMandatorySourceID) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -399,7 +389,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
video_ids[0])));
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
GetUserMediaWithInvalidOptionalSourceID) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -432,7 +422,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
video_ids[0])));
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, TwoGetUserMediaAndStop) {
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest, TwoGetUserMediaAndStop) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
@@ -442,7 +432,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest, TwoGetUserMediaAndStop) {
"twoGetUserMediaAndStop({video: true, audio: true});");
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
TwoGetUserMediaWithEqualConstraints) {
std::string constraints1 = "{video: true, audio: true}";
const std::string& constraints2 = constraints1;
@@ -452,7 +442,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
expected_result);
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
TwoGetUserMediaWithSecondVideoCropped) {
std::string constraints1 = "{video: true}";
std::string constraints2 = "{video: {mandatory: {maxHeight: 360}}}";
@@ -461,7 +451,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
expected_result);
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
TwoGetUserMediaWithFirstHdSecondVga) {
std::string constraints1 =
"{video: {mandatory: {minWidth:1280 , minHeight: 720}}}";
@@ -472,7 +462,26 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
expected_result);
}
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+ TwoGetUserMediaAndVerifyFrameRate) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+ NavigateToURL(shell(), url);
+
+ std::string constraints1 =
+ "{video: {mandatory: {minWidth:640 , minHeight: 480, "
+ "minFrameRate : 15, maxFrameRate : 15}}}";
+ std::string constraints2 =
+ "{video: {mandatory: {maxWidth:320 , maxHeight: 240,"
+ "minFrameRate : 7, maxFrameRate : 7}}}";
+
+ std::string command = "twoGetUserMediaAndVerifyFrameRate(" +
+ constraints1 + ',' + constraints2 + ", 15, 7)";
+ ExecuteJavascriptAndWaitForOk(command);
+}
+
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
GetUserMediaWithTooHighVideoConstraintsValues) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -488,15 +497,45 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
large_value);
NavigateToURL(shell(), url);
- // TODO(perkj): A proper error code should be returned by gUM.
- EXPECT_EQ("TrackStartError", ExecuteJavascriptAndReturnResult(call));
+ EXPECT_EQ("ConstraintNotSatisfiedError",
+ ExecuteJavascriptAndReturnResult(call));
+}
+
+// This test makes two getUserMedia requests, one with impossible constraints
+// that should trigger an error, and one with valid constraints. The test
+// verifies getUserMedia can succeed after being given impossible constraints.
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
+ TwoGetUserMediaAndCheckCallbackAfterFailure) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+ NavigateToURL(shell(), url);
+
+ int large_value = 99999;
+ const std::string gum_with_impossible_constraints =
+ GenerateGetUserMediaCall(kGetUserMediaAndExpectFailure,
+ large_value,
+ large_value,
+ large_value,
+ large_value,
+ large_value,
+ large_value);
+ const std::string gum_with_vga_constraints =
+ GenerateGetUserMediaCall(kGetUserMediaAndAnalyseAndStop,
+ 640, 640, 480, 480, 10, 30);
+
+ ASSERT_EQ("ConstraintNotSatisfiedError",
+ ExecuteJavascriptAndReturnResult(gum_with_impossible_constraints));
+
+ ASSERT_EQ("w=640:h=480",
+ ExecuteJavascriptAndReturnResult(gum_with_vga_constraints));
}
// This test will make a simple getUserMedia page, verify that video is playing
// in a simple local <video>, and for a couple of seconds, collect some
// performance traces from VideoCaptureController colorspace conversion and
// potential resizing.
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
WebRtcGetUserMediaBrowserTest,
TraceVideoCaptureControllerPerformanceDuringGetUserMedia) {
RunGetUserMediaAndCollectMeasures(
@@ -506,7 +545,7 @@ IN_PROC_BROWSER_TEST_P(
}
// This test calls getUserMedia and checks for aspect ratio behavior.
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
TestGetUserMediaAspectRatio4To3) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -521,7 +560,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
}
// This test calls getUserMedia and checks for aspect ratio behavior.
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
TestGetUserMediaAspectRatio16To9) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -536,7 +575,7 @@ IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
}
// This test calls getUserMedia and checks for aspect ratio behavior.
-IN_PROC_BROWSER_TEST_P(WebRtcGetUserMediaBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
TestGetUserMediaAspectRatio1To1) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
diff --git a/chromium/content/browser/media/webrtc_identity_store.cc b/chromium/content/browser/media/webrtc_identity_store.cc
index 4a02b71efa0..419cb96ab7c 100644
--- a/chromium/content/browser/media/webrtc_identity_store.cc
+++ b/chromium/content/browser/media/webrtc_identity_store.cc
@@ -171,7 +171,7 @@ class WebRTCIdentityRequestHandle {
};
WebRTCIdentityStore::WebRTCIdentityStore(const base::FilePath& path,
- quota::SpecialStoragePolicy* policy)
+ storage::SpecialStoragePolicy* policy)
: validity_period_(base::TimeDelta::FromDays(30)),
task_runner_(base::WorkerPool::GetTaskRunner(true)),
backend_(new WebRTCIdentityStoreBackend(path, policy, validity_period_)) {
diff --git a/chromium/content/browser/media/webrtc_identity_store.h b/chromium/content/browser/media/webrtc_identity_store.h
index 3602b7028cd..6bf10fe61a2 100644
--- a/chromium/content/browser/media/webrtc_identity_store.h
+++ b/chromium/content/browser/media/webrtc_identity_store.h
@@ -19,9 +19,9 @@ class FilePath;
class TaskRunner;
} // namespace base
-namespace quota {
+namespace storage {
class SpecialStoragePolicy;
-} // namespace quota
+} // namespace storage
namespace content {
class WebRTCIdentityRequest;
@@ -43,7 +43,7 @@ class CONTENT_EXPORT WebRTCIdentityStore
// If |path| is empty, nothing will be saved to disk.
WebRTCIdentityStore(const base::FilePath& path,
- quota::SpecialStoragePolicy* policy);
+ storage::SpecialStoragePolicy* policy);
// Retrieve the cached DTLS private key and certificate, i.e. identity, for
// the |origin| and |identity_name| pair, or generate a new identity using
diff --git a/chromium/content/browser/media/webrtc_identity_store_backend.cc b/chromium/content/browser/media/webrtc_identity_store_backend.cc
index 57a0b04f058..f6ecbad5c20 100644
--- a/chromium/content/browser/media/webrtc_identity_store_backend.cc
+++ b/chromium/content/browser/media/webrtc_identity_store_backend.cc
@@ -4,8 +4,8 @@
#include "content/browser/media/webrtc_identity_store_backend.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/memory/scoped_vector.h"
#include "base/strings/string_util.h"
#include "content/public/browser/browser_thread.h"
@@ -13,12 +13,12 @@
#include "sql/error_delegate_util.h"
#include "sql/statement.h"
#include "sql/transaction.h"
+#include "storage/browser/quota/special_storage_policy.h"
#include "url/gurl.h"
-#include "webkit/browser/quota/special_storage_policy.h"
namespace content {
-static const char* kWebRTCIdentityStoreDBName = "webrtc_identity_store";
+static const char kWebRTCIdentityStoreDBName[] = "webrtc_identity_store";
static const base::FilePath::CharType kWebRTCIdentityStoreDirectory[] =
FILE_PATH_LITERAL("WebRTCIdentityStore");
@@ -112,7 +112,7 @@ class WebRTCIdentityStoreBackend::SqlLiteStorage
public:
SqlLiteStorage(base::TimeDelta validity_period,
const base::FilePath& path,
- quota::SpecialStoragePolicy* policy)
+ storage::SpecialStoragePolicy* policy)
: validity_period_(validity_period), special_storage_policy_(policy) {
if (!path.empty())
path_ = path.Append(kWebRTCIdentityStoreDirectory);
@@ -169,7 +169,7 @@ class WebRTCIdentityStoreBackend::SqlLiteStorage
base::TimeDelta validity_period_;
// The file path of the DB. Empty if temporary.
base::FilePath path_;
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
scoped_ptr<sql::Connection> db_;
// Batched DB operations pending to commit.
PendingOperationList pending_operations_;
@@ -179,11 +179,12 @@ class WebRTCIdentityStoreBackend::SqlLiteStorage
WebRTCIdentityStoreBackend::WebRTCIdentityStoreBackend(
const base::FilePath& path,
- quota::SpecialStoragePolicy* policy,
+ storage::SpecialStoragePolicy* policy,
base::TimeDelta validity_period)
: validity_period_(validity_period),
state_(NOT_STARTED),
- sql_lite_storage_(new SqlLiteStorage(validity_period, path, policy)) {}
+ sql_lite_storage_(new SqlLiteStorage(validity_period, path, policy)) {
+}
bool WebRTCIdentityStoreBackend::FindIdentity(
const GURL& origin,
diff --git a/chromium/content/browser/media/webrtc_identity_store_backend.h b/chromium/content/browser/media/webrtc_identity_store_backend.h
index 92b68b62d67..81919746741 100644
--- a/chromium/content/browser/media/webrtc_identity_store_backend.h
+++ b/chromium/content/browser/media/webrtc_identity_store_backend.h
@@ -18,9 +18,9 @@ namespace base {
class FilePath;
} // namespace base
-namespace quota {
+namespace storage {
class SpecialStoragePolicy;
-} // namespace quota
+} // namespace storage
namespace content {
@@ -38,7 +38,7 @@ class WebRTCIdentityStoreBackend
// No data is saved on disk if |path| is empty. Identites older than
// |validity_period| will be removed lazily.
WebRTCIdentityStoreBackend(const base::FilePath& path,
- quota::SpecialStoragePolicy* policy,
+ storage::SpecialStoragePolicy* policy,
base::TimeDelta validity_period);
// Finds the identity with |origin|, |identity_name|, and |common_name| from
diff --git a/chromium/content/browser/media/webrtc_identity_store_unittest.cc b/chromium/content/browser/media/webrtc_identity_store_unittest.cc
index 586559f2c05..9078f1a19ac 100644
--- a/chromium/content/browser/media/webrtc_identity_store_unittest.cc
+++ b/chromium/content/browser/media/webrtc_identity_store_unittest.cc
@@ -17,11 +17,11 @@
namespace content {
-static const char* kFakeOrigin = "http://foo.com";
-static const char* kFakeIdentityName1 = "name1";
-static const char* kFakeIdentityName2 = "name2";
-static const char* kFakeCommonName1 = "cname1";
-static const char* kFakeCommonName2 = "cname2";
+static const char kFakeOrigin[] = "http://foo.com";
+static const char kFakeIdentityName1[] = "name1";
+static const char kFakeIdentityName2[] = "name2";
+static const char kFakeCommonName1[] = "cname1";
+static const char kFakeCommonName2[] = "cname2";
static void OnRequestCompleted(bool* completed,
std::string* out_cert,
@@ -49,9 +49,7 @@ class WebRTCIdentityStoreTest : public testing::Test {
webrtc_identity_store_->SetTaskRunnerForTesting(pool_owner_->pool());
}
- virtual ~WebRTCIdentityStoreTest() {
- pool_owner_->pool()->Shutdown();
- }
+ ~WebRTCIdentityStoreTest() override { pool_owner_->pool()->Shutdown(); }
void SetValidityPeriod(base::TimeDelta validity_period) {
webrtc_identity_store_->SetValidityPeriodForTesting(validity_period);
diff --git a/chromium/content/browser/media/webrtc_internals.cc b/chromium/content/browser/media/webrtc_internals.cc
index 892f0378d2e..56078a109ef 100644
--- a/chromium/content/browser/media/webrtc_internals.cc
+++ b/chromium/content/browser/media/webrtc_internals.cc
@@ -4,13 +4,14 @@
#include "content/browser/media/webrtc_internals.h"
-#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
#include "content/browser/media/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"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
+#include "content/public/browser/power_save_blocker.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
@@ -20,6 +21,10 @@ using std::string;
namespace content {
namespace {
+
+static base::LazyInstance<WebRTCInternals>::Leaky g_webrtc_internals =
+ LAZY_INSTANCE_INITIALIZER;
+
// Makes sure that |dict| has a ListValue under path "log".
static base::ListValue* EnsureLogList(base::DictionaryValue* dict) {
base::ListValue* log = NULL;
@@ -59,14 +64,14 @@ WebRTCInternals::~WebRTCInternals() {
}
WebRTCInternals* WebRTCInternals::GetInstance() {
- return Singleton<WebRTCInternals>::get();
+ return g_webrtc_internals.Pointer();
}
void WebRTCInternals::OnAddPeerConnection(int render_process_id,
ProcessId pid,
int lid,
const string& url,
- const string& servers,
+ const string& rtc_configuration,
const string& constraints) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -77,10 +82,11 @@ void WebRTCInternals::OnAddPeerConnection(int render_process_id,
dict->SetInteger("rid", render_process_id);
dict->SetInteger("pid", static_cast<int>(pid));
dict->SetInteger("lid", lid);
- dict->SetString("servers", servers);
+ dict->SetString("rtcConfiguration", rtc_configuration);
dict->SetString("constraints", constraints);
dict->SetString("url", url);
peer_connection_data_.Append(dict);
+ CreateOrReleasePowerSaveBlocker();
if (observers_.might_have_observers())
SendUpdate("addPeerConnection", dict);
@@ -101,6 +107,7 @@ void WebRTCInternals::OnRemovePeerConnection(ProcessId pid, int lid) {
continue;
peer_connection_data_.Remove(i, NULL);
+ CreateOrReleasePowerSaveBlocker();
if (observers_.might_have_observers()) {
base::DictionaryValue id;
@@ -136,6 +143,9 @@ void WebRTCInternals::OnUpdatePeerConnection(
if (!log_entry)
return;
+ double epoch_time = base::Time::Now().ToJsTime();
+ string time = base::DoubleToString(epoch_time);
+ log_entry->SetString("time", time);
log_entry->SetString("type", type);
log_entry->SetString("value", value);
log->Append(log_entry);
@@ -144,8 +154,7 @@ void WebRTCInternals::OnUpdatePeerConnection(
base::DictionaryValue update;
update.SetInteger("pid", static_cast<int>(pid));
update.SetInteger("lid", lid);
- update.SetString("type", type);
- update.SetString("value", value);
+ update.MergeDictionary(log_entry);
SendUpdate("updatePeerConnection", &update);
}
@@ -260,6 +269,7 @@ void WebRTCInternals::ResetForTesting() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
observers_.Clear();
peer_connection_data_.Clear();
+ CreateOrReleasePowerSaveBlocker();
get_user_media_requests_.Clear();
aec_dump_enabled_ = false;
}
@@ -296,6 +306,8 @@ void WebRTCInternals::FileSelectionCanceled(void* params) {
}
void WebRTCInternals::OnRendererExit(int render_process_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
// Iterates from the end of the list to remove the PeerConnections created
// by the exitting renderer.
for (int i = peer_connection_data_.GetSize() - 1; i >= 0; --i) {
@@ -319,6 +331,7 @@ void WebRTCInternals::OnRendererExit(int render_process_id) {
peer_connection_data_.Remove(i, NULL);
}
}
+ CreateOrReleasePowerSaveBlocker();
bool found_any = false;
// Iterates from the end of the list to remove the getUserMedia requests
@@ -354,4 +367,20 @@ void WebRTCInternals::EnableAecDumpOnAllRenderProcessHosts() {
}
#endif
+void WebRTCInternals::CreateOrReleasePowerSaveBlocker() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (peer_connection_data_.empty() && power_save_blocker_) {
+ DVLOG(1) << ("Releasing the block on application suspension since no "
+ "PeerConnections are active anymore.");
+ power_save_blocker_.reset();
+ } else if (!peer_connection_data_.empty() && !power_save_blocker_) {
+ DVLOG(1) << ("Preventing the application from being suspended while one or "
+ "more PeerConnections are active.");
+ power_save_blocker_ = content::PowerSaveBlocker::Create(
+ content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+ "WebRTC has active PeerConnections.").Pass();
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/media/webrtc_internals.h b/chromium/content/browser/media/webrtc_internals.h
index 7ff95b9bca9..db8693ab3eb 100644
--- a/chromium/content/browser/media/webrtc_internals.h
+++ b/chromium/content/browser/media/webrtc_internals.h
@@ -6,7 +6,8 @@
#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_H_
#include "base/gtest_prod_util.h"
-#include "base/memory/singleton.h"
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/process/process.h"
#include "base/values.h"
@@ -16,6 +17,8 @@
#include "ui/shell_dialogs/select_file_dialog.h"
namespace content {
+
+class PowerSaveBlocker;
class WebContents;
class WebRTCInternalsUIObserver;
@@ -34,13 +37,14 @@ class CONTENT_EXPORT WebRTCInternals : public NotificationObserver,
// render process terminates and we want to clean up.
// |pid| is the renderer process id, |lid| is the renderer local id used to
// identify a PeerConnection, |url| is the url of the tab owning the
- // PeerConnection, |servers| is the servers configuration, |constraints| is
- // the media constraints used to initialize the PeerConnection.
+ // PeerConnection, |rtc_configuration| is the serialized RTCConfiguration,
+ // |constraints| is the media constraints used to initialize the
+ // PeerConnection.
void OnAddPeerConnection(int render_process_id,
base::ProcessId pid,
int lid,
const std::string& url,
- const std::string& servers,
+ const std::string& rtc_configuration,
const std::string& constraints);
// This method is called when PeerConnection is destroyed.
@@ -98,28 +102,29 @@ class CONTENT_EXPORT WebRTCInternals : public NotificationObserver,
void ResetForTesting();
private:
- friend struct DefaultSingletonTraits<WebRTCInternals>;
- FRIEND_TEST_ALL_PREFIXES(WebRtcBrowserTest, CallWithAecDump);
- FRIEND_TEST_ALL_PREFIXES(WebRtcBrowserTest,
+ friend struct base::DefaultLazyInstanceTraits<WebRTCInternals>;
+ FRIEND_TEST_ALL_PREFIXES(WebRtcAecDumpBrowserTest, CallWithAecDump);
+ FRIEND_TEST_ALL_PREFIXES(WebRtcAecDumpBrowserTest,
CallWithAecDumpEnabledThenDisabled);
+ FRIEND_TEST_ALL_PREFIXES(WebRtcAecDumpBrowserTest, TwoCallsWithAecDump);
FRIEND_TEST_ALL_PREFIXES(WebRTCInternalsTest,
AecRecordingFileSelectionCanceled);
WebRTCInternals();
- virtual ~WebRTCInternals();
+ ~WebRTCInternals() override;
void SendUpdate(const std::string& command, base::Value* value);
// NotificationObserver implementation.
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
// ui::SelectFileDialog::Listener implementation.
- virtual void FileSelected(const base::FilePath& path,
- int index,
- void* unused_params) OVERRIDE;
- virtual void FileSelectionCanceled(void* params) OVERRIDE;
+ void FileSelected(const base::FilePath& path,
+ int index,
+ void* unused_params) override;
+ void FileSelectionCanceled(void* params) override;
// Called when a renderer exits (including crashes).
void OnRendererExit(int render_process_id);
@@ -129,6 +134,11 @@ class CONTENT_EXPORT WebRTCInternals : public NotificationObserver,
void EnableAecDumpOnAllRenderProcessHosts();
#endif
+ // Called whenever an element is added to or removed from
+ // |peer_connection_data_| to impose/release a block on suspending the current
+ // application for power-saving.
+ void CreateOrReleasePowerSaveBlocker();
+
ObserverList<WebRTCInternalsUIObserver> observers_;
// |peer_connection_data_| is a list containing all the PeerConnection
@@ -142,8 +152,9 @@ class CONTENT_EXPORT WebRTCInternals : public NotificationObserver,
// "servers" and "constraints" -- server configuration and media constraints
// used to initialize the PeerConnection respectively.
// "log" -- a ListValue contains all the updates for the PeerConnection. Each
- // list item is a DictionaryValue containing "type" and "value", both of which
- // are strings.
+ // list item is a DictionaryValue containing "time", which is the number of
+ // milliseconds since epoch as a string, and "type" and "value", both of which
+ // are strings representing the event.
base::ListValue peer_connection_data_;
// A list of getUserMedia requests. Each item is a DictionaryValue that
@@ -163,6 +174,11 @@ class CONTENT_EXPORT WebRTCInternals : public NotificationObserver,
// AEC dump (diagnostic echo canceller recording) state.
bool aec_dump_enabled_;
base::FilePath aec_dump_file_path_;
+
+ // 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_;
};
} // namespace content
diff --git a/chromium/content/browser/media/webrtc_internals_browsertest.cc b/chromium/content/browser/media/webrtc_internals_browsertest.cc
index 7b352d66b24..e9f1e611407 100644
--- a/chromium/content/browser/media/webrtc_internals_browsertest.cc
+++ b/chromium/content/browser/media/webrtc_internals_browsertest.cc
@@ -149,15 +149,14 @@ static const int64 FAKE_TIME_STAMP = 3600000;
class MAYBE_WebRtcInternalsBrowserTest: public ContentBrowserTest {
public:
MAYBE_WebRtcInternalsBrowserTest() {}
- virtual ~MAYBE_WebRtcInternalsBrowserTest() {}
+ ~MAYBE_WebRtcInternalsBrowserTest() override {}
- virtual void SetUpOnMainThread() OVERRIDE {
- // We need fake devices in this test since we want to run on naked VMs. We
- // assume these switches are set by default in content_browsertests.
- ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseFakeDeviceForMediaStream));
+ void SetUpOnMainThread() override {
+ // Assume this is set by the content test launcher.
ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseFakeUIForMediaStream));
+ ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kUseFakeDeviceForMediaStream));
}
protected:
@@ -175,7 +174,7 @@ class MAYBE_WebRtcInternalsBrowserTest: public ContentBrowserTest {
void ExecuteAddPeerConnectionJs(const PeerConnectionEntry& pc) {
std::stringstream ss;
ss << "{pid:" << pc.pid_ <<", lid:" << pc.lid_ << ", " <<
- "url:'u', servers:'s', constraints:'c'}";
+ "url:'u', rtcConfiguration:'s', constraints:'c'}";
ASSERT_TRUE(ExecuteJavascript("addPeerConnection(" + ss.str() + ");"));
}
@@ -232,7 +231,7 @@ class MAYBE_WebRtcInternalsBrowserTest: public ContentBrowserTest {
ASSERT_TRUE(ExecuteScriptAndExtractString(
shell()->web_contents(),
"window.domAutomationController.send("
- "JSON.stringify(userMediaRequests));",
+ "JSON.stringify(userMediaRequests));",
&json_requests));
scoped_ptr<base::Value> value_requests;
value_requests.reset(base::JSONReader::Read(json_requests));
@@ -259,6 +258,24 @@ class MAYBE_WebRtcInternalsBrowserTest: public ContentBrowserTest {
EXPECT_EQ(requests[i].audio_constraints, audio);
EXPECT_EQ(requests[i].video_constraints, video);
}
+
+ bool user_media_tab_existed = false;
+ ASSERT_TRUE(ExecuteScriptAndExtractBool(
+ shell()->web_contents(),
+ "window.domAutomationController.send("
+ "$('user-media-tab-id') != null);",
+ &user_media_tab_existed));
+ EXPECT_EQ(!requests.empty(), user_media_tab_existed);
+
+ if (user_media_tab_existed) {
+ int user_media_request_count = -1;
+ ASSERT_TRUE(ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "window.domAutomationController.send("
+ "$('user-media-tab-id').childNodes.length);",
+ &user_media_request_count));
+ ASSERT_EQ(requests.size(), static_cast<size_t>(user_media_request_count));
+ }
}
// Verifies that DOM for |pc| is correctly created with the right content.
diff --git a/chromium/content/browser/media/webrtc_internals_message_handler.h b/chromium/content/browser/media/webrtc_internals_message_handler.h
index 8c5f10ca401..b27e7f0abb6 100644
--- a/chromium/content/browser/media/webrtc_internals_message_handler.h
+++ b/chromium/content/browser/media/webrtc_internals_message_handler.h
@@ -21,14 +21,13 @@ class WebRTCInternalsMessageHandler : public WebUIMessageHandler,
public WebRTCInternalsUIObserver{
public:
WebRTCInternalsMessageHandler();
- virtual ~WebRTCInternalsMessageHandler();
+ ~WebRTCInternalsMessageHandler() override;
// WebUIMessageHandler implementation.
- virtual void RegisterMessages() OVERRIDE;
+ void RegisterMessages() override;
// WebRTCInternalsUIObserver override.
- virtual void OnUpdate(const std::string& command,
- const base::Value* args) OVERRIDE;
+ void OnUpdate(const std::string& command, const base::Value* args) override;
private:
// Javascript message handler.
diff --git a/chromium/content/browser/media/webrtc_internals_ui.cc b/chromium/content/browser/media/webrtc_internals_ui.cc
index 5c4adc591a9..67970305741 100644
--- a/chromium/content/browser/media/webrtc_internals_ui.cc
+++ b/chromium/content/browser/media/webrtc_internals_ui.cc
@@ -5,11 +5,11 @@
#include "content/browser/media/webrtc_internals_ui.h"
#include "content/browser/media/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"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/common/url_constants.h"
-#include "grit/content_resources.h"
namespace content {
namespace {
diff --git a/chromium/content/browser/media/webrtc_internals_unittest.cc b/chromium/content/browser/media/webrtc_internals_unittest.cc
index e4b0531fa54..afe3587db5e 100644
--- a/chromium/content/browser/media/webrtc_internals_unittest.cc
+++ b/chromium/content/browser/media/webrtc_internals_unittest.cc
@@ -15,13 +15,12 @@ namespace content {
namespace {
static const std::string kContraints = "c";
-static const std::string kServers = "s";
+static const std::string kRtcConfiguration = "r";
static const std::string kUrl = "u";
class MockWebRTCInternalsProxy : public WebRTCInternalsUIObserver {
public:
- virtual void OnUpdate(const std::string& command,
- const base::Value* value) OVERRIDE {
+ void OnUpdate(const std::string& command, const base::Value* value) override {
command_ = command;
if (value)
value_.reset(value->DeepCopy());
@@ -99,7 +98,7 @@ TEST_F(WebRTCInternalsTest, AddRemoveObserver) {
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
- 0, 3, 4, kUrl, kServers, kContraints);
+ 0, 3, 4, kUrl, kRtcConfiguration, kContraints);
EXPECT_EQ("", observer->command());
WebRTCInternals::GetInstance()->OnRemovePeerConnection(3, 4);
@@ -110,7 +109,7 @@ TEST_F(WebRTCInternalsTest, SendAddPeerConnectionUpdate) {
new MockWebRTCInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
- 0, 1, 2, kUrl, kServers, kContraints);
+ 0, 1, 2, kUrl, kRtcConfiguration, kContraints);
EXPECT_EQ("addPeerConnection", observer->command());
base::DictionaryValue* dict = NULL;
@@ -119,7 +118,7 @@ TEST_F(WebRTCInternalsTest, SendAddPeerConnectionUpdate) {
VerifyInt(dict, "pid", 1);
VerifyInt(dict, "lid", 2);
VerifyString(dict, "url", kUrl);
- VerifyString(dict, "servers", kServers);
+ VerifyString(dict, "rtcConfiguration", kRtcConfiguration);
VerifyString(dict, "constraints", kContraints);
WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
@@ -131,7 +130,7 @@ TEST_F(WebRTCInternalsTest, SendRemovePeerConnectionUpdate) {
new MockWebRTCInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
- 0, 1, 2, kUrl, kServers, kContraints);
+ 0, 1, 2, kUrl, kRtcConfiguration, kContraints);
WebRTCInternals::GetInstance()->OnRemovePeerConnection(1, 2);
EXPECT_EQ("removePeerConnection", observer->command());
@@ -149,7 +148,7 @@ TEST_F(WebRTCInternalsTest, SendUpdatePeerConnectionUpdate) {
new MockWebRTCInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
- 0, 1, 2, kUrl, kServers, kContraints);
+ 0, 1, 2, kUrl, kRtcConfiguration, kContraints);
const std::string update_type = "fakeType";
const std::string update_value = "fakeValue";
@@ -166,6 +165,10 @@ TEST_F(WebRTCInternalsTest, SendUpdatePeerConnectionUpdate) {
VerifyString(dict, "type", update_type);
VerifyString(dict, "value", update_value);
+ std::string time;
+ EXPECT_TRUE(dict->GetString("time", &time));
+ EXPECT_FALSE(time.empty());
+
WebRTCInternals::GetInstance()->OnRemovePeerConnection(1, 2);
WebRTCInternals::GetInstance()->RemoveObserver(observer.get());
}
@@ -216,7 +219,7 @@ TEST_F(WebRTCInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
const std::string update_value = "fakeValue";
WebRTCInternals::GetInstance()->OnAddPeerConnection(
- rid, pid, lid, kUrl, kServers, kContraints);
+ rid, pid, lid, kUrl, kRtcConfiguration, kContraints);
WebRTCInternals::GetInstance()->OnUpdatePeerConnection(
pid, lid, update_type, update_value);
@@ -238,7 +241,7 @@ TEST_F(WebRTCInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
VerifyInt(dict, "pid", pid);
VerifyInt(dict, "lid", lid);
VerifyString(dict, "url", kUrl);
- VerifyString(dict, "servers", kServers);
+ VerifyString(dict, "rtcConfiguration", kRtcConfiguration);
VerifyString(dict, "constraints", kContraints);
base::ListValue* log = NULL;
@@ -248,6 +251,9 @@ TEST_F(WebRTCInternalsTest, SendAllUpdatesWithPeerConnectionUpdate) {
EXPECT_TRUE((*log->begin())->GetAsDictionary(&dict));
VerifyString(dict, "type", update_type);
VerifyString(dict, "value", update_value);
+ std::string time;
+ EXPECT_TRUE(dict->GetString("time", &time));
+ EXPECT_FALSE(time.empty());
}
TEST_F(WebRTCInternalsTest, OnAddStats) {
@@ -255,7 +261,7 @@ TEST_F(WebRTCInternalsTest, OnAddStats) {
scoped_ptr<MockWebRTCInternalsProxy> observer(new MockWebRTCInternalsProxy());
WebRTCInternals::GetInstance()->AddObserver(observer.get());
WebRTCInternals::GetInstance()->OnAddPeerConnection(
- rid, pid, lid, kUrl, kServers, kContraints);
+ rid, pid, lid, kUrl, kRtcConfiguration, kContraints);
base::ListValue list;
list.AppendString("xxx");
diff --git a/chromium/content/browser/media/webrtc_webcam_browsertest.cc b/chromium/content/browser/media/webrtc_webcam_browsertest.cc
new file mode 100644
index 00000000000..1be6ee51045
--- /dev/null
+++ b/chromium/content/browser/media/webrtc_webcam_browsertest.cc
@@ -0,0 +1,102 @@
+// 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 "base/command_line.h"
+#include "base/strings/utf_string_conversions.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_utils.h"
+#include "content/shell/browser/shell.h"
+#include "media/base/media_switches.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace {
+
+const base::CommandLine::StringType FAKE_DEVICE_FLAG =
+#if defined(OS_WIN)
+ base::ASCIIToUTF16(switches::kUseFakeDeviceForMediaStream);
+#else
+ switches::kUseFakeDeviceForMediaStream;
+#endif
+
+bool IsUseFakeDeviceForMediaStream(const base::CommandLine::StringType& arg) {
+ return arg.find(FAKE_DEVICE_FLAG) != std::string::npos;
+}
+
+void RemoveFakeDeviceFromCommandLine(base::CommandLine* command_line) {
+ CommandLine::StringVector argv = command_line->argv();
+ argv.erase(std::remove_if(argv.begin(), argv.end(),
+ IsUseFakeDeviceForMediaStream),
+ argv.end());
+ command_line->InitFromArgv(argv);
+}
+
+} // namespace
+
+namespace content {
+
+// This class doesn't inherit from WebRtcContentBrowserTestBase like the others
+// since we want it to actually acquire the real webcam on the system (if there
+// is one).
+class WebRtcWebcamBrowserTest: public ContentBrowserTest {
+ public:
+ ~WebRtcWebcamBrowserTest() override {}
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ ASSERT_TRUE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream));
+
+ // The content_browsertests run with this flag by default, and this test is
+ // the only current exception to that rule, so just remove the flag
+ // --use-fake-device-for-media-stream here. We could also have all tests
+ // involving media streams add this flag explicitly, but it will be really
+ // unintuitive for developers to write tests involving media stream and have
+ // them fail on what looks like random bots, so running with fake devices
+ // is really a reasonable default.
+ RemoveFakeDeviceFromCommandLine(command_line);
+ }
+
+ void SetUp() override {
+ EnablePixelOutput();
+ ContentBrowserTest::SetUp();
+ }
+};
+
+// The test is tagged as MANUAL since the webcam is a system-level resource; we
+// only want it to run on bots where we can ensure sequential execution. The
+// Android bots will run the test since they ignore MANUAL, but that's what we
+// want here since the bot runs tests sequentially on the device.
+IN_PROC_BROWSER_TEST_F(WebRtcWebcamBrowserTest,
+ MANUAL_CanAcquireVgaOnRealWebcam) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ GURL url(embedded_test_server()->GetURL(
+ "/media/getusermedia-real-webcam.html"));
+ NavigateToURL(shell(), url);
+
+ std::string result;
+ ASSERT_TRUE(ExecuteScriptAndExtractString(shell()->web_contents(),
+ "hasVideoInputDeviceOnSystem()",
+ &result));
+ if (result != "has-video-input-device") {
+ VLOG(0) << "No video device; skipping test...";
+ return;
+ }
+
+ // GetUserMedia should acquire VGA by default.
+ ASSERT_TRUE(ExecuteScriptAndExtractString(
+ shell()->web_contents(),
+ "getUserMediaAndReturnVideoDimensions({video: true})",
+ &result));
+
+ if (result == "640x480" || result == "480x640") {
+ // Don't care if the device happens to be in landscape or portrait mode
+ // since we don't know how it is oriented in the lab :)
+ return;
+ }
+ FAIL() << "Expected resolution to be 640x480 or 480x640, got" << result;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/message_port_message_filter.h b/chromium/content/browser/message_port_message_filter.h
index 64d07d6c328..21bfbb24e17 100644
--- a/chromium/content/browser/message_port_message_filter.h
+++ b/chromium/content/browser/message_port_message_filter.h
@@ -22,9 +22,9 @@ class CONTENT_EXPORT MessagePortMessageFilter : public BrowserMessageFilter {
explicit MessagePortMessageFilter(const NextRoutingIDCallback& callback);
// BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
+ void OnChannelClosing() override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnDestruct() const override;
int GetNextRoutingID();
@@ -36,7 +36,7 @@ class CONTENT_EXPORT MessagePortMessageFilter : public BrowserMessageFilter {
protected:
// This is protected, so we can define sub classes for testing.
- virtual ~MessagePortMessageFilter();
+ ~MessagePortMessageFilter() override;
private:
friend class BrowserThread;
diff --git a/chromium/content/browser/mime_registry_message_filter.h b/chromium/content/browser/mime_registry_message_filter.h
index 4237f508e74..c4b110e98a2 100644
--- a/chromium/content/browser/mime_registry_message_filter.h
+++ b/chromium/content/browser/mime_registry_message_filter.h
@@ -14,13 +14,12 @@ class MimeRegistryMessageFilter : public BrowserMessageFilter {
public:
MimeRegistryMessageFilter();
- virtual void OverrideThreadForMessage(
- const IPC::Message& message,
- BrowserThread::ID* thread) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
- virtual ~MimeRegistryMessageFilter();
+ ~MimeRegistryMessageFilter() override;
void OnGetMimeTypeFromExtension(const base::FilePath::StringType& ext,
std::string* mime_type);
diff --git a/chromium/content/browser/mojo/mojo_application_host.cc b/chromium/content/browser/mojo/mojo_application_host.cc
index 90187b9b92f..18219676a3e 100644
--- a/chromium/content/browser/mojo/mojo_application_host.cc
+++ b/chromium/content/browser/mojo/mojo_application_host.cc
@@ -7,7 +7,7 @@
#include "content/common/mojo/mojo_messages.h"
#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_sender.h"
-#include "mojo/embedder/platform_channel_pair.h"
+#include "mojo/edk/embedder/platform_channel_pair.h"
namespace content {
namespace {
@@ -24,13 +24,17 @@ base::PlatformFile PlatformFileFromScopedPlatformHandle(
} // namespace
MojoApplicationHost::MojoApplicationHost() : did_activate_(false) {
+#if defined(OS_ANDROID)
+ service_registry_android_.reset(
+ new ServiceRegistryAndroid(&service_registry_));
+#endif
}
MojoApplicationHost::~MojoApplicationHost() {
}
bool MojoApplicationHost::Init() {
- DCHECK(!child_service_provider_.get()) << "Already initialized!";
+ DCHECK(!client_handle_.is_valid()) << "Already initialized!";
mojo::embedder::PlatformChannelPair channel_pair;
@@ -43,12 +47,11 @@ bool MojoApplicationHost::Init() {
// Forward this to the client once we know its process handle.
client_handle_ = channel_pair.PassClientHandle();
- child_service_provider_.reset(
- BindToPipe(new ServiceProviderImpl(), message_pipe.Pass()));
+ service_registry_.BindRemoteServiceProvider(message_pipe.Pass());
return true;
}
-bool MojoApplicationHost::Activate(IPC::Sender* sender,
+void MojoApplicationHost::Activate(IPC::Sender* sender,
base::ProcessHandle process_handle) {
DCHECK(!did_activate_);
DCHECK(client_handle_.is_valid());
@@ -57,15 +60,10 @@ bool MojoApplicationHost::Activate(IPC::Sender* sender,
PlatformFileFromScopedPlatformHandle(client_handle_.Pass());
did_activate_ = sender->Send(new MojoMsg_Activate(
IPC::GetFileHandleForProcess(client_file, process_handle, true)));
- return did_activate_;
}
-void MojoApplicationHost::ServiceProviderImpl::ConnectToService(
- const mojo::String& service_url,
- const mojo::String& service_name,
- mojo::ScopedMessagePipeHandle handle,
- const mojo::String& requestor_url) {
- // TODO(darin): Provide something meaningful here.
+void MojoApplicationHost::WillDestroySoon() {
+ channel_init_.WillDestroySoon();
}
} // namespace content
diff --git a/chromium/content/browser/mojo/mojo_application_host.h b/chromium/content/browser/mojo/mojo_application_host.h
index f5913269d72..1825b3eab55 100644
--- a/chromium/content/browser/mojo/mojo_application_host.h
+++ b/chromium/content/browser/mojo/mojo_application_host.h
@@ -5,10 +5,15 @@
#ifndef CONTENT_BROWSER_MOJO_MOJO_APPLICATION_HOST_H_
#define CONTENT_BROWSER_MOJO_MOJO_APPLICATION_HOST_H_
+#include "base/memory/scoped_ptr.h"
#include "base/process/process_handle.h"
-#include "mojo/embedder/channel_init.h"
-#include "mojo/embedder/scoped_platform_handle.h"
-#include "mojo/public/interfaces/service_provider/service_provider.mojom.h"
+#include "content/common/mojo/service_registry_impl.h"
+#include "mojo/edk/embedder/channel_init.h"
+#include "mojo/edk/embedder/scoped_platform_handle.h"
+
+#if defined(OS_ANDROID)
+#include "content/browser/mojo/service_registry_android.h"
+#endif
namespace IPC {
class Sender;
@@ -19,49 +24,35 @@ namespace content {
// MojoApplicationHost represents the code needed on the browser side to setup
// a child process as a Mojo application via Chrome IPC. The child process
// should use MojoApplication to handle messages generated by an instance of
-// MojoApplicationHost. MojoApplicationHost makes the mojo::ShellClient
-// interface available so that child-provided services can be invoked.
+// MojoApplicationHost. MojoApplicationHost makes the ServiceRegistry interface
+// available so that child-provided services can be invoked.
class MojoApplicationHost {
public:
MojoApplicationHost();
virtual ~MojoApplicationHost();
// Two-phase initialization:
- // 1- Init makes the shell_client() available synchronously.
+ // 1- Init makes service_registry() available synchronously.
// 2- Activate establishes the actual connection to the peer process.
bool Init();
- bool Activate(IPC::Sender* sender, base::ProcessHandle process_handle);
+ void Activate(IPC::Sender* sender, base::ProcessHandle process_handle);
- bool did_activate() const { return did_activate_; }
+ void WillDestroySoon();
- mojo::ServiceProvider* service_provider() {
- DCHECK(child_service_provider_.get());
- return child_service_provider_->client();
- }
+ ServiceRegistry* service_registry() { return &service_registry_; }
private:
- class ServiceProviderImpl
- : public mojo::InterfaceImpl<mojo::ServiceProvider> {
- public:
- virtual void OnConnectionError() OVERRIDE {
- // TODO(darin): How should we handle this error?
- }
-
- // mojo::ServiceProvider methods:
- virtual void ConnectToService(
- const mojo::String& service_url,
- const mojo::String& service_name,
- mojo::ScopedMessagePipeHandle handle,
- const mojo::String& requestor_url) OVERRIDE;
- };
-
mojo::embedder::ChannelInit channel_init_;
mojo::embedder::ScopedPlatformHandle client_handle_;
- scoped_ptr<ServiceProviderImpl> child_service_provider_;
-
bool did_activate_;
+ ServiceRegistryImpl service_registry_;
+
+#if defined(OS_ANDROID)
+ scoped_ptr<ServiceRegistryAndroid> service_registry_android_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(MojoApplicationHost);
};
diff --git a/chromium/content/browser/mojo/service_registry_android.cc b/chromium/content/browser/mojo/service_registry_android.cc
new file mode 100644
index 00000000000..269c8be61f4
--- /dev/null
+++ b/chromium/content/browser/mojo/service_registry_android.cc
@@ -0,0 +1,97 @@
+// 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/mojo/service_registry_android.h"
+
+#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 "jni/ServiceRegistry_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ScopedJavaGlobalRef;
+
+namespace content {
+
+namespace {
+
+// Callback passed to the wrapped ServiceRegistry upon AddService(). The
+// ServiceRegistry will call it to create a registered Java service
+void CreateImplAndAttach(
+ const ScopedJavaGlobalRef<jobject>& j_scoped_service_registry,
+ const ScopedJavaGlobalRef<jobject>& j_scoped_manager,
+ 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());
+}
+
+} // namespace
+
+// static
+bool ServiceRegistryAndroid::Register(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+// Constructor and destructor call into Java.
+ServiceRegistryAndroid::ServiceRegistryAndroid(
+ ServiceRegistryImpl* service_registry)
+ : service_registry_(service_registry) {
+ JNIEnv* env = AttachCurrentThread();
+ obj_.Reset(
+ env,
+ Java_ServiceRegistry_create(env, reinterpret_cast<intptr_t>(this)).obj());
+}
+
+ServiceRegistryAndroid::~ServiceRegistryAndroid() {
+ Java_ServiceRegistry_destroy(AttachCurrentThread(), obj_.obj());
+}
+
+// Methods called from Java.
+void ServiceRegistryAndroid::AddService(JNIEnv* env,
+ jobject j_service_registry,
+ jobject j_manager,
+ jobject j_factory,
+ jstring j_name) {
+ std::string name(ConvertJavaStringToUTF8(env, j_name));
+
+ ScopedJavaGlobalRef<jobject> j_scoped_service_registry;
+ j_scoped_service_registry.Reset(env, j_service_registry);
+
+ ScopedJavaGlobalRef<jobject> j_scoped_manager;
+ j_scoped_manager.Reset(env, j_manager);
+
+ 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));
+}
+
+void ServiceRegistryAndroid::RemoveService(JNIEnv* env,
+ jobject j_service_registry,
+ jstring j_name) {
+ std::string name(ConvertJavaStringToUTF8(env, j_name));
+ service_registry_->RemoveService(name);
+}
+
+void ServiceRegistryAndroid::ConnectToRemoteService(JNIEnv* env,
+ jobject j_service_registry,
+ jstring j_name,
+ jint j_handle) {
+ std::string name(ConvertJavaStringToUTF8(env, j_name));
+ mojo::ScopedMessagePipeHandle handle((mojo::MessagePipeHandle(j_handle)));
+ service_registry_->ConnectToRemoteService(name, handle.Pass());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/mojo/service_registry_android.h b/chromium/content/browser/mojo/service_registry_android.h
new file mode 100644
index 00000000000..0873531be25
--- /dev/null
+++ b/chromium/content/browser/mojo/service_registry_android.h
@@ -0,0 +1,53 @@
+// 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,
+ jobject j_service_registry,
+ jobject j_manager,
+ jobject j_factory,
+ jstring j_name);
+ void RemoveService(JNIEnv* env, jobject j_service_registry, jstring j_name);
+ void ConnectToRemoteService(JNIEnv* env,
+ jobject j_service_registry,
+ jstring j_name,
+ jint handle);
+
+ const base::android::ScopedJavaGlobalRef<jobject>& GetObjForTesting() {
+ 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/net/browser_online_state_observer.h b/chromium/content/browser/net/browser_online_state_observer.h
index fbb0db4bf71..13d9e3d303a 100644
--- a/chromium/content/browser/net/browser_online_state_observer.h
+++ b/chromium/content/browser/net/browser_online_state_observer.h
@@ -16,11 +16,11 @@ class BrowserOnlineStateObserver
: public net::NetworkChangeNotifier::ConnectionTypeObserver {
public:
BrowserOnlineStateObserver();
- virtual ~BrowserOnlineStateObserver();
+ ~BrowserOnlineStateObserver() override;
// ConnectionTypeObserver implementation.
- virtual void OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
+ void OnConnectionTypeChanged(
+ net::NetworkChangeNotifier::ConnectionType type) override;
private:
DISALLOW_COPY_AND_ASSIGN(BrowserOnlineStateObserver);
diff --git a/chromium/content/browser/net/sqlite_persistent_cookie_store.cc b/chromium/content/browser/net/sqlite_persistent_cookie_store.cc
index 967101f4dbb..1009d29c626 100644
--- a/chromium/content/browser/net/sqlite_persistent_cookie_store.cc
+++ b/chromium/content/browser/net/sqlite_persistent_cookie_store.cc
@@ -13,8 +13,8 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
@@ -38,9 +38,9 @@
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
+#include "storage/browser/quota/special_storage_policy.h"
#include "third_party/sqlite/sqlite3.h"
#include "url/gurl.h"
-#include "webkit/browser/quota/special_storage_policy.h"
using base::Time;
@@ -76,7 +76,7 @@ class SQLitePersistentCookieStore::Backend
const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
- quota::SpecialStoragePolicy* special_storage_policy,
+ storage::SpecialStoragePolicy* special_storage_policy,
CookieCryptoDelegate* crypto_delegate)
: path_(path),
num_pending_(0),
@@ -249,7 +249,7 @@ class SQLitePersistentCookieStore::Backend
bool restore_old_session_cookies_;
// Policy defining what data is deleted on shutdown.
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
// The cumulative time spent loading the cookies on the background runner.
// Incremented and reported from the background runner.
@@ -1205,7 +1205,7 @@ SQLitePersistentCookieStore::SQLitePersistentCookieStore(
const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
- quota::SpecialStoragePolicy* special_storage_policy,
+ storage::SpecialStoragePolicy* special_storage_policy,
CookieCryptoDelegate* crypto_delegate)
: backend_(new Backend(path,
client_task_runner,
@@ -1259,15 +1259,15 @@ CookieStoreConfig::CookieStoreConfig()
}
CookieStoreConfig::CookieStoreConfig(
- const base::FilePath& path,
+ const base::FilePath& path,
SessionCookieMode session_cookie_mode,
- quota::SpecialStoragePolicy* storage_policy,
+ storage::SpecialStoragePolicy* storage_policy,
net::CookieMonsterDelegate* cookie_delegate)
- : path(path),
- session_cookie_mode(session_cookie_mode),
- storage_policy(storage_policy),
- cookie_delegate(cookie_delegate),
- crypto_delegate(NULL) {
+ : path(path),
+ session_cookie_mode(session_cookie_mode),
+ storage_policy(storage_policy),
+ cookie_delegate(cookie_delegate),
+ crypto_delegate(NULL) {
CHECK(!path.empty() || session_cookie_mode == EPHEMERAL_SESSION_COOKIES);
}
@@ -1279,19 +1279,19 @@ net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) {
if (config.path.empty()) {
// Empty path means in-memory store.
- cookie_monster = new net::CookieMonster(NULL, config.cookie_delegate);
+ cookie_monster = new net::CookieMonster(NULL, config.cookie_delegate.get());
} else {
scoped_refptr<base::SequencedTaskRunner> client_task_runner =
config.client_task_runner;
scoped_refptr<base::SequencedTaskRunner> background_task_runner =
config.background_task_runner;
- if (!client_task_runner) {
+ if (!client_task_runner.get()) {
client_task_runner =
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
}
- if (!background_task_runner) {
+ if (!background_task_runner.get()) {
background_task_runner =
BrowserThread::GetBlockingPool()->GetSequencedTaskRunner(
BrowserThread::GetBlockingPool()->GetSequenceToken());
@@ -1304,11 +1304,11 @@ net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) {
background_task_runner,
(config.session_cookie_mode ==
CookieStoreConfig::RESTORED_SESSION_COOKIES),
- config.storage_policy,
+ config.storage_policy.get(),
config.crypto_delegate);
cookie_monster =
- new net::CookieMonster(persistent_store, config.cookie_delegate);
+ new net::CookieMonster(persistent_store, config.cookie_delegate.get());
if ((config.session_cookie_mode ==
CookieStoreConfig::PERSISTANT_SESSION_COOKIES) ||
(config.session_cookie_mode ==
@@ -1317,16 +1317,7 @@ net::CookieStore* CreateCookieStore(const CookieStoreConfig& config) {
}
}
- // In the case of Android WebView, the cookie store may be created
- // before the browser process fully initializes -- certainly before
- // the main loop ever runs. In this situation, the CommandLine singleton
- // will not have been set up. Android tests do not need file cookies
- // so always ignore them here.
- //
- // TODO(ajwong): Remove the InitializedForCurrentProcess() check
- // once http://crbug.com/331424 is resolved.
- if (CommandLine::InitializedForCurrentProcess() &&
- CommandLine::ForCurrentProcess()->HasSwitch(
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableFileCookies)) {
cookie_monster->SetEnableFileScheme(true);
}
diff --git a/chromium/content/browser/net/sqlite_persistent_cookie_store.h b/chromium/content/browser/net/sqlite_persistent_cookie_store.h
index 5773de186a3..786b6b6725a 100644
--- a/chromium/content/browser/net/sqlite_persistent_cookie_store.h
+++ b/chromium/content/browser/net/sqlite_persistent_cookie_store.h
@@ -27,7 +27,7 @@ namespace net {
class CanonicalCookie;
}
-namespace quota {
+namespace storage {
class SpecialStoragePolicy;
}
@@ -50,21 +50,21 @@ class CONTENT_EXPORT SQLitePersistentCookieStore
const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
bool restore_old_session_cookies,
- quota::SpecialStoragePolicy* special_storage_policy,
+ storage::SpecialStoragePolicy* special_storage_policy,
CookieCryptoDelegate* crypto_delegate);
// net::CookieMonster::PersistentCookieStore:
- virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
- virtual void LoadCookiesForKey(const std::string& key,
- const LoadedCallback& callback) OVERRIDE;
- virtual void AddCookie(const net::CanonicalCookie& cc) OVERRIDE;
- virtual void UpdateCookieAccessTime(const net::CanonicalCookie& cc) OVERRIDE;
- virtual void DeleteCookie(const net::CanonicalCookie& cc) OVERRIDE;
- virtual void SetForceKeepSessionState() OVERRIDE;
- virtual void Flush(const base::Closure& callback) OVERRIDE;
+ void Load(const LoadedCallback& loaded_callback) override;
+ void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& callback) override;
+ void AddCookie(const net::CanonicalCookie& cc) override;
+ void UpdateCookieAccessTime(const net::CanonicalCookie& cc) override;
+ void DeleteCookie(const net::CanonicalCookie& cc) override;
+ void SetForceKeepSessionState() override;
+ void Flush(const base::Closure& callback) override;
protected:
- virtual ~SQLitePersistentCookieStore();
+ ~SQLitePersistentCookieStore() override;
private:
class Backend;
diff --git a/chromium/content/browser/net/sqlite_persistent_cookie_store_perftest.cc b/chromium/content/browser/net/sqlite_persistent_cookie_store_perftest.cc
index 7092aa28efa..21f3c85d8f5 100644
--- a/chromium/content/browser/net/sqlite_persistent_cookie_store_perftest.cc
+++ b/chromium/content/browser/net/sqlite_persistent_cookie_store_perftest.cc
@@ -61,7 +61,7 @@ class SQLitePersistentCookieStorePerfTest : public testing::Test {
pool_owner_->pool()->GetNamedSequenceToken("client"));
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
store_ = new SQLitePersistentCookieStore(
temp_dir_.path().Append(cookie_filename),
@@ -101,7 +101,7 @@ class SQLitePersistentCookieStorePerfTest : public testing::Test {
false, NULL, NULL);
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
store_ = NULL;
pool_owner_->pool()->Shutdown();
}
diff --git a/chromium/content/browser/net/sqlite_persistent_cookie_store_unittest.cc b/chromium/content/browser/net/sqlite_persistent_cookie_store_unittest.cc
index d6e30a6587e..47590d7274b 100644
--- a/chromium/content/browser/net/sqlite_persistent_cookie_store_unittest.cc
+++ b/chromium/content/browser/net/sqlite_persistent_cookie_store_unittest.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
@@ -40,10 +40,10 @@ const base::FilePath::CharType kCookieFilename[] = FILE_PATH_LITERAL("Cookies");
class CookieCryptor : public content::CookieCryptoDelegate {
public:
CookieCryptor();
- virtual bool EncryptString(const std::string& plaintext,
- std::string* ciphertext) OVERRIDE;
- virtual bool DecryptString(const std::string& ciphertext,
- std::string* plaintext) OVERRIDE;
+ bool EncryptString(const std::string& plaintext,
+ std::string* ciphertext) override;
+ bool DecryptString(const std::string& ciphertext,
+ std::string* plaintext) override;
private:
scoped_ptr<crypto::SymmetricKey> key_;
@@ -173,11 +173,9 @@ class SQLitePersistentCookieStoreTest : public testing::Test {
return contents;
}
- virtual void SetUp() OVERRIDE {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- }
+ void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
DestroyStore();
pool_owner_->pool()->Shutdown();
}
diff --git a/chromium/content/browser/net/view_blob_internals_job_factory.cc b/chromium/content/browser/net/view_blob_internals_job_factory.cc
index 984763d45c9..d15c59f84fd 100644
--- a/chromium/content/browser/net/view_blob_internals_job_factory.cc
+++ b/chromium/content/browser/net/view_blob_internals_job_factory.cc
@@ -7,7 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "content/public/common/url_constants.h"
-#include "webkit/browser/blob/view_blob_internals_job.h"
+#include "storage/browser/blob/view_blob_internals_job.h"
namespace content {
@@ -21,8 +21,8 @@ bool ViewBlobInternalsJobFactory::IsSupportedURL(const GURL& url) {
net::URLRequestJob* ViewBlobInternalsJobFactory::CreateJobForRequest(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
- webkit_blob::BlobStorageContext* blob_storage_context) {
- return new webkit_blob::ViewBlobInternalsJob(
+ storage::BlobStorageContext* blob_storage_context) {
+ return new storage::ViewBlobInternalsJob(
request, network_delegate, blob_storage_context);
}
diff --git a/chromium/content/browser/net/view_blob_internals_job_factory.h b/chromium/content/browser/net/view_blob_internals_job_factory.h
index 4d4b60abf4c..cc8bd14242f 100644
--- a/chromium/content/browser/net/view_blob_internals_job_factory.h
+++ b/chromium/content/browser/net/view_blob_internals_job_factory.h
@@ -9,10 +9,11 @@ namespace net {
class NetworkDelegate;
class URLRequest;
class URLRequestJob;
-} // namespace net
-namespace webkit_blob {
+}
+
+namespace storage {
class BlobStorageContext;
-} // webkit_blob
+}
class GURL;
@@ -24,7 +25,7 @@ class ViewBlobInternalsJobFactory {
static net::URLRequestJob* CreateJobForRequest(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
- webkit_blob::BlobStorageContext* blob_storage_context);
+ storage::BlobStorageContext* blob_storage_context);
};
} // namespace content
diff --git a/chromium/content/browser/net/view_http_cache_job_factory.cc b/chromium/content/browser/net/view_http_cache_job_factory.cc
index a0cce463d74..e80cac725e7 100644
--- a/chromium/content/browser/net/view_http_cache_job_factory.cc
+++ b/chromium/content/browser/net/view_http_cache_job_factory.cc
@@ -28,22 +28,21 @@ class ViewHttpCacheJob : public net::URLRequestJob {
net::NetworkDelegate* network_delegate)
: net::URLRequestJob(request, network_delegate),
core_(new Core),
- weak_factory_(this),
callback_(base::Bind(&ViewHttpCacheJob::OnStartCompleted,
- base::Unretained(this))) {
+ base::Unretained(this))),
+ weak_factory_(this) {
}
// net::URLRequestJob implementation.
- virtual void Start() OVERRIDE;
- virtual void Kill() OVERRIDE;
- virtual bool GetMimeType(std::string* mime_type) const OVERRIDE{
+ void Start() override;
+ void Kill() override;
+ bool GetMimeType(std::string* mime_type) const override {
return core_->GetMimeType(mime_type);
}
- virtual bool GetCharset(std::string* charset) OVERRIDE{
+ bool GetCharset(std::string* charset) override {
return core_->GetCharset(charset);
}
- virtual bool ReadRawData(net::IOBuffer* buf,
- int buf_size, int *bytes_read) OVERRIDE{
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override {
return core_->ReadRawData(buf, buf_size, bytes_read);
}
@@ -83,15 +82,16 @@ class ViewHttpCacheJob : public net::URLRequestJob {
DISALLOW_COPY_AND_ASSIGN(Core);
};
- virtual ~ViewHttpCacheJob() {}
+ ~ViewHttpCacheJob() override {}
void StartAsync();
void OnStartCompleted();
scoped_refptr<Core> core_;
- base::WeakPtrFactory<ViewHttpCacheJob> weak_factory_;
base::Closure callback_;
+ base::WeakPtrFactory<ViewHttpCacheJob> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ViewHttpCacheJob);
};
diff --git a/chromium/content/browser/net_info_browsertest.cc b/chromium/content/browser/net_info_browsertest.cc
new file mode 100644
index 00000000000..cea69620487
--- /dev/null
+++ b/chromium/content/browser/net_info_browsertest.cc
@@ -0,0 +1,80 @@
+// 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 "base/command_line.h"
+#include "base/run_loop.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"
+#include "net/base/network_change_notifier.h"
+#include "net/base/network_change_notifier_factory.h"
+
+class NetInfoBrowserTest : public content::ContentBrowserTest {
+ protected:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ // TODO(jkarlin): Once NetInfo is enabled on all platforms remove this
+ // switch.
+ command_line->AppendSwitch(switches::kEnableNetworkInformation);
+ }
+
+#if defined(OS_CHROMEOS)
+ virtual void SetUp() override {
+ // ChromeOS's NetworkChangeNotifier isn't known to content and therefore
+ // doesn't get created in content_browsertests. Insert a mock
+ // NetworkChangeNotifier.
+ net::NetworkChangeNotifier::CreateMock();
+ content::ContentBrowserTest::SetUp();
+ }
+#endif
+
+ void SetUpOnMainThread() override {
+ net::NetworkChangeNotifier::SetTestNotificationsOnly(true);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ static void SetConnectionType(
+ net::NetworkChangeNotifier::ConnectionType type) {
+ net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
+ type);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ std::string RunScriptExtractString(const std::string& script) {
+ std::string data;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractString(shell()->web_contents(), script, &data));
+ return data;
+ }
+
+ bool RunScriptExtractBool(const std::string& script) {
+ bool data;
+ EXPECT_TRUE(
+ ExecuteScriptAndExtractBool(shell()->web_contents(), script, &data));
+ return data;
+ }
+};
+
+// Make sure that type changes in the browser make their way to
+// navigator.connection.type.
+IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkChangePlumbsToNavigator) {
+ NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"));
+ SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_EQ("wifi", RunScriptExtractString("getType()"));
+ SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+ EXPECT_EQ("ethernet", RunScriptExtractString("getType()"));
+}
+
+// Make sure that type changes in the browser make their way to
+// navigator.isOnline.
+IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, IsOnline) {
+ NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"));
+ SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+ EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
+ SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_FALSE(RunScriptExtractBool("getOnLine()"));
+ SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
+}
diff --git a/chromium/content/browser/notification_service_impl.h b/chromium/content/browser/notification_service_impl.h
index c9dce92cb60..2df369a6d0f 100644
--- a/chromium/content/browser/notification_service_impl.h
+++ b/chromium/content/browser/notification_service_impl.h
@@ -23,12 +23,12 @@ class CONTENT_EXPORT NotificationServiceImpl : public NotificationService {
// Normally instantiated when the thread is created. Not all threads have
// a NotificationService. Only one instance should be created per thread.
NotificationServiceImpl();
- virtual ~NotificationServiceImpl();
+ ~NotificationServiceImpl() override;
// NotificationService:
- virtual void Notify(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Notify(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
private:
friend class NotificationRegistrar;
diff --git a/chromium/content/browser/notification_service_impl_unittest.cc b/chromium/content/browser/notification_service_impl_unittest.cc
index 1317e4a4e7e..1e71e64251d 100644
--- a/chromium/content/browser/notification_service_impl_unittest.cc
+++ b/chromium/content/browser/notification_service_impl_unittest.cc
@@ -22,9 +22,9 @@ class TestObserver : public NotificationObserver {
int notification_count() const { return notification_count_; }
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE {
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override {
++notification_count_;
}
diff --git a/chromium/content/browser/notifications/OWNERS b/chromium/content/browser/notifications/OWNERS
new file mode 100644
index 00000000000..2fca67fdfda
--- /dev/null
+++ b/chromium/content/browser/notifications/OWNERS
@@ -0,0 +1 @@
+peter@chromium.org \ No newline at end of file
diff --git a/chromium/content/browser/notifications/notification_message_filter.cc b/chromium/content/browser/notifications/notification_message_filter.cc
new file mode 100644
index 00000000000..fecd0730b77
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_message_filter.cc
@@ -0,0 +1,89 @@
+// 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/notifications/notification_message_filter.h"
+
+#include "base/callback.h"
+#include "content/browser/notifications/page_notification_delegate.h"
+#include "content/common/platform_notification_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/desktop_notification_delegate.h"
+#include "content/public/common/content_client.h"
+
+namespace content {
+
+NotificationMessageFilter::NotificationMessageFilter(
+ int process_id,
+ ResourceContext* resource_context,
+ BrowserContext* browser_context)
+ : BrowserMessageFilter(PlatformNotificationMsgStart),
+ process_id_(process_id),
+ resource_context_(resource_context),
+ browser_context_(browser_context) {}
+
+NotificationMessageFilter::~NotificationMessageFilter() {}
+
+void NotificationMessageFilter::DidCloseNotification(int notification_id) {
+ close_closures_.erase(notification_id);
+}
+
+bool NotificationMessageFilter::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(NotificationMessageFilter, message)
+ IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_CheckPermission,
+ OnCheckNotificationPermission)
+ IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_Show,
+ OnShowPlatformNotification)
+ IPC_MESSAGE_HANDLER(PlatformNotificationHostMsg_Close,
+ OnClosePlatformNotification)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void NotificationMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message, content::BrowserThread::ID* thread) {
+ if (message.type() == PlatformNotificationHostMsg_Show::ID ||
+ message.type() == PlatformNotificationHostMsg_Close::ID)
+ *thread = BrowserThread::UI;
+}
+
+void NotificationMessageFilter::OnCheckNotificationPermission(
+ const GURL& origin, blink::WebNotificationPermission* permission) {
+ *permission =
+ GetContentClient()->browser()->CheckDesktopNotificationPermission(
+ origin,
+ resource_context_,
+ process_id_);
+}
+
+void NotificationMessageFilter::OnShowPlatformNotification(
+ int notification_id, const ShowDesktopNotificationHostMsgParams& params) {
+ scoped_ptr<DesktopNotificationDelegate> delegate(
+ new PageNotificationDelegate(process_id_, notification_id));
+
+ base::Closure close_closure;
+ GetContentClient()->browser()->ShowDesktopNotification(params,
+ browser_context_,
+ process_id_,
+ delegate.Pass(),
+ &close_closure);
+
+ if (!close_closure.is_null())
+ close_closures_[notification_id] = close_closure;
+}
+
+void NotificationMessageFilter::OnClosePlatformNotification(
+ int notification_id) {
+ if (!close_closures_.count(notification_id))
+ return;
+
+ close_closures_[notification_id].Run();
+ close_closures_.erase(notification_id);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/notification_message_filter.h b/chromium/content/browser/notifications/notification_message_filter.h
new file mode 100644
index 00000000000..0b5159b18b7
--- /dev/null
+++ b/chromium/content/browser/notifications/notification_message_filter.h
@@ -0,0 +1,58 @@
+// 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_NOTIFICATIONS_NOTIFICATION_MESSAGE_FILTER_H_
+#define CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_MESSAGE_FILTER_H_
+
+#include <map>
+
+#include "base/callback_forward.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "third_party/WebKit/public/platform/WebNotificationPermission.h"
+
+class GURL;
+
+namespace content {
+
+class BrowserContext;
+class ResourceContext;
+struct ShowDesktopNotificationHostMsgParams;
+
+class NotificationMessageFilter : public BrowserMessageFilter {
+ public:
+ NotificationMessageFilter(
+ int process_id,
+ ResourceContext* resource_context,
+ BrowserContext* browser_context);
+
+ // To be called by the notification's delegate when it has closed, so that
+ // the close closure associated with that notification can be removed.
+ void DidCloseNotification(int notification_id);
+
+ // BrowserMessageFilter implementation. Called on the UI thread.
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OverrideThreadForMessage(
+ const IPC::Message& message, content::BrowserThread::ID* thread) override;
+
+ protected:
+ ~NotificationMessageFilter() override;
+
+ private:
+ void OnCheckNotificationPermission(
+ const GURL& origin, blink::WebNotificationPermission* permission);
+ void OnShowPlatformNotification(
+ int notification_id, const ShowDesktopNotificationHostMsgParams& params);
+ void OnClosePlatformNotification(int notification_id);
+
+ int process_id_;
+ ResourceContext* resource_context_;
+ BrowserContext* browser_context_;
+
+ // Map mapping notification ids to their associated close closures.
+ std::map<int, base::Closure> close_closures_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/notifications/page_notification_delegate.cc b/chromium/content/browser/notifications/page_notification_delegate.cc
new file mode 100644
index 00000000000..dacfffbfd22
--- /dev/null
+++ b/chromium/content/browser/notifications/page_notification_delegate.cc
@@ -0,0 +1,48 @@
+// 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/notifications/page_notification_delegate.h"
+
+#include "content/browser/notifications/notification_message_filter.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/common/platform_notification_messages.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+
+PageNotificationDelegate::PageNotificationDelegate(int render_process_id,
+ int notification_id)
+ : render_process_id_(render_process_id),
+ notification_id_(notification_id) {}
+
+PageNotificationDelegate::~PageNotificationDelegate() {}
+
+void PageNotificationDelegate::NotificationDisplayed() {
+ RenderProcessHost* sender = RenderProcessHost::FromID(render_process_id_);
+ if (!sender)
+ return;
+
+ sender->Send(new PlatformNotificationMsg_DidShow(notification_id_));
+}
+
+// TODO(peter): Remove |by_user| since we're not using that anywhere.
+void PageNotificationDelegate::NotificationClosed(bool by_user) {
+ RenderProcessHost* sender = RenderProcessHost::FromID(render_process_id_);
+ if (!sender)
+ return;
+
+ sender->Send(new PlatformNotificationMsg_DidClose(notification_id_));
+ static_cast<RenderProcessHostImpl*>(sender)
+ ->notification_message_filter()->DidCloseNotification(notification_id_);
+}
+
+void PageNotificationDelegate::NotificationClick() {
+ RenderProcessHost* sender = RenderProcessHost::FromID(render_process_id_);
+ if (!sender)
+ return;
+
+ sender->Send(new PlatformNotificationMsg_DidClick(notification_id_));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/notifications/page_notification_delegate.h b/chromium/content/browser/notifications/page_notification_delegate.h
new file mode 100644
index 00000000000..dd3422f2c4e
--- /dev/null
+++ b/chromium/content/browser/notifications/page_notification_delegate.h
@@ -0,0 +1,32 @@
+// 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_NOTIFICATIONS_PAGE_NOTIFICATION_DELEGATE_H_
+#define CONTENT_BROWSER_NOTIFICATIONS_PAGE_NOTIFICATION_DELEGATE_H_
+
+#include "content/public/browser/desktop_notification_delegate.h"
+
+namespace content {
+
+// A delegate used by the notification service to report the results of platform
+// notification interactions to Web Notifications whose lifetime is tied to
+// that of the page displaying them.
+class PageNotificationDelegate : public DesktopNotificationDelegate {
+ public:
+ PageNotificationDelegate(int render_process_id, int notification_id);
+ ~PageNotificationDelegate() override;
+
+ // DesktopNotificationDelegate implementation.
+ void NotificationDisplayed() override;
+ void NotificationClosed(bool by_user) override;
+ void NotificationClick() override;
+
+ private:
+ int render_process_id_;
+ int notification_id_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_NOTIFICATIONS_PAGE_NOTIFICATION_DELEGATE_H_
diff --git a/chromium/content/browser/pepper_flash_settings_helper_impl.h b/chromium/content/browser/pepper_flash_settings_helper_impl.h
index 19584a8cec3..9a5887ba31f 100644
--- a/chromium/content/browser/pepper_flash_settings_helper_impl.h
+++ b/chromium/content/browser/pepper_flash_settings_helper_impl.h
@@ -19,20 +19,19 @@ class CONTENT_EXPORT PepperFlashSettingsHelperImpl
PepperFlashSettingsHelperImpl();
// PepperFlashSettingsHelper implementation.
- virtual void OpenChannelToBroker(
- const base::FilePath& path,
- const OpenChannelCallback& callback) OVERRIDE;
+ void OpenChannelToBroker(const base::FilePath& path,
+ const OpenChannelCallback& callback) override;
// PpapiPluginProcessHost::BrokerClient implementation.
- virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
- int* renderer_id) OVERRIDE;
- virtual void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle,
- base::ProcessId plugin_pid,
- int plugin_child_id) OVERRIDE;
- virtual bool OffTheRecord() OVERRIDE;
+ void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
+ int* renderer_id) override;
+ void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int plugin_child_id) override;
+ bool OffTheRecord() override;
protected:
- virtual ~PepperFlashSettingsHelperImpl();
+ ~PepperFlashSettingsHelperImpl() override;
private:
OpenChannelCallback callback_;
diff --git a/chromium/content/browser/plugin_browsertest.cc b/chromium/content/browser/plugin_browsertest.cc
index 2e4053385ca..a5ca6da74ea 100644
--- a/chromium/content/browser/plugin_browsertest.cc
+++ b/chromium/content/browser/plugin_browsertest.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "base/command_line.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -17,8 +17,8 @@
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/shell/common/shell_switches.h"
-#include "content/test/net/url_request_mock_http_job.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/url_request/url_request_mock_http_job.h"
#include "net/url_request/url_request.h"
#include "ui/gfx/rect.h"
@@ -39,7 +39,8 @@ namespace content {
namespace {
void SetUrlRequestMock(const base::FilePath& path) {
- URLRequestMockHTTPJob::AddUrlHandler(path);
+ net::URLRequestMockHTTPJob::AddUrlHandler(
+ path, content::BrowserThread::GetBlockingPool());
}
}
@@ -48,7 +49,7 @@ class PluginTest : public ContentBrowserTest {
protected:
PluginTest() {}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
// Some NPAPI tests schedule garbage collection to force object tear-down.
command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose_gc");
@@ -75,7 +76,7 @@ class PluginTest : public ContentBrowserTest {
#endif
}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
base::FilePath path = GetTestFilePath("", "");
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, base::Bind(&SetUrlRequestMock, path));
@@ -186,9 +187,9 @@ IN_PROC_BROWSER_TEST_F(PluginTest,
#endif
IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE_GetURLRequest404Response) {
- GURL url(URLRequestMockHTTPJob::GetMockUrl(
- base::FilePath().AppendASCII("npapi").
- AppendASCII("plugin_url_request_404.html")));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(
+ base::FilePath().AppendASCII("npapi").AppendASCII(
+ "plugin_url_request_404.html")));
LoadAndWait(url);
}
@@ -222,10 +223,12 @@ IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(ManyPlugins)) {
LoadAndWait(GetURL("many_plugins.html"));
}
+#if !defined(OS_MACOSX) // http://crbug.com/402164
// Test various calls to GetURL from a plugin.
IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(GetURL)) {
LoadAndWait(GetURL("geturl.html"));
}
+#endif
// Test various calls to GetURL for javascript URLs with
// non NULL targets from a plugin.
@@ -294,7 +297,8 @@ IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(VerifyPluginWindowRect)) {
// Tests that creating a new instance of a plugin while another one is handling
// a paint message doesn't cause deadlock.
-IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(CreateInstanceInPaint)) {
+// http://crbug.com/406184
+IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_CreateInstanceInPaint) {
LoadAndWait(GetURL("create_instance_in_paint.html"));
}
@@ -306,7 +310,8 @@ IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_AlertInWindowMessage) {
WaitForAppModalDialog(shell());
}
-IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(VerifyNPObjectLifetimeTest)) {
+// http://crbug.com/406184
+IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_VerifyNPObjectLifetimeTest) {
LoadAndWait(GetURL("npobject_lifetime_test.html"));
}
@@ -354,6 +359,7 @@ IN_PROC_BROWSER_TEST_F(PluginTest, PluginSingleRangeRequest) {
LoadAndWait(GetURL("plugin_single_range_request.html"));
}
+#if !defined(OS_WIN) // http://crbug.com/396373
// Test checking the privacy mode is on.
// If this flakes on Linux, use http://crbug.com/104380
IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(PrivateEnabled)) {
@@ -361,24 +367,27 @@ IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(PrivateEnabled)) {
url = GURL(url.spec() + "?private");
LoadAndWaitInWindow(CreateOffTheRecordBrowser(), url);
}
+#endif
-#if defined(OS_WIN) || defined(OS_MACOSX)
+// These used to run on Windows: http://crbug.com/396373
+#if defined(OS_MACOSX)
// Test a browser hang due to special case of multiple
// plugin instances indulged in sync calls across renderer.
IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(MultipleInstancesSyncCalls)) {
LoadAndWait(GetURL("multiple_instances_sync_calls.html"));
}
-#endif
IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(GetURLRequestFailWrite)) {
- GURL url(URLRequestMockHTTPJob::GetMockUrl(
- base::FilePath().AppendASCII("npapi").
- AppendASCII("plugin_url_request_fail_write.html")));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(
+ base::FilePath().AppendASCII("npapi").AppendASCII(
+ "plugin_url_request_fail_write.html")));
LoadAndWait(url);
}
+#endif
#if defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(EnsureScriptingWorksInDestroy)) {
+// Flaky on Windows x86. http://crbug.com/388245
+IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_EnsureScriptingWorksInDestroy) {
LoadAndWait(GetURL("ensure_scripting_works_in_destroy.html"));
}
@@ -394,9 +403,9 @@ IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(NoHangIfInitCrashes)) {
// If this flakes on Mac, use http://crbug.com/111508
IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(PluginReferrerTest)) {
- GURL url(URLRequestMockHTTPJob::GetMockUrl(
- base::FilePath().AppendASCII("npapi").
- AppendASCII("plugin_url_request_referrer_test.html")));
+ GURL url(net::URLRequestMockHTTPJob::GetMockUrl(
+ base::FilePath().AppendASCII("npapi").AppendASCII(
+ "plugin_url_request_referrer_test.html")));
LoadAndWait(url);
}
@@ -437,7 +446,7 @@ IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_FlashSecurity) {
// TODO(port) Port the following tests to platforms that have the required
// plugins.
// Flaky: http://crbug.com/55915
-IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(Quicktime)) {
+IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_Quicktime) {
TestPlugin("quicktime.html");
}
@@ -476,7 +485,8 @@ IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_Java) {
TestPlugin("Java.html");
}
-IN_PROC_BROWSER_TEST_F(PluginTest, MAYBE(Silverlight)) {
+// Flaky: http://crbug.com/55915
+IN_PROC_BROWSER_TEST_F(PluginTest, DISABLED_Silverlight) {
TestPlugin("silverlight.html");
}
#endif // defined(OS_WIN)
@@ -498,11 +508,10 @@ class TestResourceDispatcherHostDelegate
private:
// ResourceDispatcherHostDelegate implementation:
- virtual void OnResponseStarted(
- net::URLRequest* request,
- ResourceContext* resource_context,
- ResourceResponse* response,
- IPC::Sender* sender) OVERRIDE {
+ void OnResponseStarted(net::URLRequest* request,
+ ResourceContext* resource_context,
+ ResourceResponse* response,
+ IPC::Sender* sender) override {
// The URL below comes from plugin_geturl_test.cc.
if (!EndsWith(request->url().spec(),
"npapi/plugin_ref_target_page.html",
@@ -524,7 +533,7 @@ class TestResourceDispatcherHostDelegate
void GotCookie(bool found_cookie) {
found_cookie_ = found_cookie;
- if (runner_)
+ if (runner_.get())
runner_->QuitClosure().Run();
}
diff --git a/chromium/content/browser/plugin_content_origin_whitelist.cc b/chromium/content/browser/plugin_content_origin_whitelist.cc
new file mode 100644
index 00000000000..d10e703f117
--- /dev/null
+++ b/chromium/content/browser/plugin_content_origin_whitelist.cc
@@ -0,0 +1,61 @@
+// 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/plugin_content_origin_whitelist.h"
+
+#include "content/common/frame_messages.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+PluginContentOriginWhitelist::PluginContentOriginWhitelist(
+ WebContents* web_contents)
+ : WebContentsObserver(web_contents) {
+}
+
+PluginContentOriginWhitelist::~PluginContentOriginWhitelist() {
+}
+
+void PluginContentOriginWhitelist::RenderFrameCreated(
+ RenderFrameHost* render_frame_host) {
+ if (!whitelist_.empty()) {
+ Send(new FrameMsg_UpdatePluginContentOriginWhitelist(
+ render_frame_host->GetRoutingID(), whitelist_));
+ }
+}
+
+bool PluginContentOriginWhitelist::OnMessageReceived(
+ const IPC::Message& message,
+ RenderFrameHost* render_frame_host) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PluginContentOriginWhitelist, message)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_PluginContentOriginAllowed,
+ OnPluginContentOriginAllowed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void PluginContentOriginWhitelist::DidNavigateMainFrame(
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) {
+ if (details.is_navigation_to_different_page()) {
+ // We expect RenderFrames to clear their replicated whitelist independently.
+ whitelist_.clear();
+ }
+}
+
+void PluginContentOriginWhitelist::OnPluginContentOriginAllowed(
+ const GURL& content_origin) {
+ whitelist_.insert(content_origin);
+
+ web_contents()->SendToAllFrames(
+ new FrameMsg_UpdatePluginContentOriginWhitelist(
+ MSG_ROUTING_NONE, whitelist_));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/plugin_content_origin_whitelist.h b/chromium/content/browser/plugin_content_origin_whitelist.h
new file mode 100644
index 00000000000..25311d242eb
--- /dev/null
+++ b/chromium/content/browser/plugin_content_origin_whitelist.h
@@ -0,0 +1,51 @@
+// 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_PLUGIN_CONTENT_ORIGIN_WHITELIST_H_
+#define CONTENT_BROWSER_PLUGIN_CONTENT_ORIGIN_WHITELIST_H_
+
+#include <set>
+
+#include "content/public/browser/web_contents_observer.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class WebContents;
+
+// This class manages the tab-wide list of temporarily whitelisted plugin
+// content origins that are exempt from power saving.
+//
+// RenderFrames report content origins that should be whitelisted via IPC.
+// This class aggregates those origins and broadcasts the total list to all
+// RenderFrames owned by the tab (WebContents). This class also sends these
+// origins to any newly created RenderFrames.
+//
+// Tab-wide whitelists are cleared by top-level navigation. RenderFrames that
+// persist across top level navigations are responsible for clearing their own
+// whitelists.
+class PluginContentOriginWhitelist : public WebContentsObserver {
+ public:
+ explicit PluginContentOriginWhitelist(WebContents* web_contents);
+ ~PluginContentOriginWhitelist() override;
+
+ private:
+ // WebContentsObserver implementation.
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
+ bool OnMessageReceived(const IPC::Message& message,
+ RenderFrameHost* render_frame_host) override;
+ void DidNavigateMainFrame(
+ const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override;
+
+ void OnPluginContentOriginAllowed(const GURL& content_origin);
+
+ std::set<GURL> whitelist_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginContentOriginWhitelist);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_PLUGIN_CONTENT_ORIGIN_WHITELIST_H_
diff --git a/chromium/content/browser/plugin_data_remover_impl.cc b/chromium/content/browser/plugin_data_remover_impl.cc
index a318e724d4b..f74b37831b5 100644
--- a/chromium/content/browser/plugin_data_remover_impl.cc
+++ b/chromium/content/browser/plugin_data_remover_impl.cc
@@ -122,32 +122,28 @@ class PluginDataRemoverImpl::Context
}
// PluginProcessHost::Client methods.
- virtual int ID() OVERRIDE {
+ int ID() override {
// Generate a unique identifier for this PluginProcessHostClient.
return ChildProcessHostImpl::GenerateChildProcessUniqueId();
}
- virtual bool OffTheRecord() OVERRIDE {
- return false;
- }
+ bool OffTheRecord() override { return false; }
- virtual ResourceContext* GetResourceContext() OVERRIDE {
- return resource_context_;
- }
+ ResourceContext* GetResourceContext() override { return resource_context_; }
- virtual void SetPluginInfo(const WebPluginInfo& info) OVERRIDE {}
+ void SetPluginInfo(const WebPluginInfo& info) override {}
- virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {}
+ void OnFoundPluginProcessHost(PluginProcessHost* host) override {}
- virtual void OnSentPluginChannelRequest() OVERRIDE {}
+ void OnSentPluginChannelRequest() override {}
- virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
+ void OnChannelOpened(const IPC::ChannelHandle& handle) override {
ConnectToChannel(handle, false);
// Balancing the AddRef call.
Release();
}
- virtual void OnError() OVERRIDE {
+ void OnError() override {
LOG(ERROR) << "Couldn't open plugin channel";
SignalDone();
// Balancing the AddRef call.
@@ -155,16 +151,15 @@ class PluginDataRemoverImpl::Context
}
// PpapiPluginProcessHost::BrokerClient implementation.
- virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
- int* renderer_id) OVERRIDE {
+ void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
+ int* renderer_id) override {
*renderer_handle = base::kNullProcessHandle;
*renderer_id = 0;
}
- virtual void OnPpapiChannelOpened(
- const IPC::ChannelHandle& channel_handle,
- base::ProcessId /* peer_pid */,
- int /* child_id */) OVERRIDE {
+ void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle,
+ base::ProcessId /* peer_pid */,
+ int /* child_id */) override {
if (!channel_handle.name.empty())
ConnectToChannel(channel_handle, true);
@@ -173,7 +168,7 @@ class PluginDataRemoverImpl::Context
}
// IPC::Listener methods.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ bool OnMessageReceived(const IPC::Message& message) override {
IPC_BEGIN_MESSAGE_MAP(Context, message)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ClearSiteDataResult,
OnClearSiteDataResult)
@@ -185,7 +180,7 @@ class PluginDataRemoverImpl::Context
return true;
}
- virtual void OnChannelError() OVERRIDE {
+ void OnChannelError() override {
if (is_removing_) {
NOTREACHED() << "Channel error";
SignalDone();
@@ -197,7 +192,7 @@ class PluginDataRemoverImpl::Context
private:
friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
friend class base::DeleteHelper<Context>;
- virtual ~Context() {}
+ ~Context() override {}
IPC::Message* CreatePpapiClearSiteDataMsg(uint64 max_age) {
base::FilePath profile_path =
diff --git a/chromium/content/browser/plugin_data_remover_impl.h b/chromium/content/browser/plugin_data_remover_impl.h
index 6f4be32538a..704ebaaa637 100644
--- a/chromium/content/browser/plugin_data_remover_impl.h
+++ b/chromium/content/browser/plugin_data_remover_impl.h
@@ -17,10 +17,10 @@ namespace content {
class CONTENT_EXPORT PluginDataRemoverImpl : public PluginDataRemover {
public:
explicit PluginDataRemoverImpl(BrowserContext* browser_context);
- virtual ~PluginDataRemoverImpl();
+ ~PluginDataRemoverImpl() override;
// PluginDataRemover implementation:
- virtual base::WaitableEvent* StartRemoving(base::Time begin_time) OVERRIDE;
+ base::WaitableEvent* StartRemoving(base::Time begin_time) override;
// The plug-in whose data should be removed (usually Flash) is specified via
// its MIME type. This method sets a different MIME type in order to call a
diff --git a/chromium/content/browser/plugin_data_remover_impl_browsertest.cc b/chromium/content/browser/plugin_data_remover_impl_browsertest.cc
index 3dfe49285ba..97adba91bd0 100644
--- a/chromium/content/browser/plugin_data_remover_impl_browsertest.cc
+++ b/chromium/content/browser/plugin_data_remover_impl_browsertest.cc
@@ -28,7 +28,7 @@ class PluginDataRemoverTest : public ContentBrowserTest {
base::MessageLoop::current()->Quit();
}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
#if defined(OS_MACOSX)
base::FilePath browser_directory;
PathService::Get(base::DIR_MODULE, &browser_directory);
diff --git a/chromium/content/browser/plugin_loader_posix.cc b/chromium/content/browser/plugin_loader_posix.cc
index 7b278811343..22bc2b614c2 100644
--- a/chromium/content/browser/plugin_loader_posix.cc
+++ b/chromium/content/browser/plugin_loader_posix.cc
@@ -110,9 +110,9 @@ void PluginLoaderPosix::GetPluginsToLoad() {
base::Bind(&PluginLoaderPosix::LoadPluginsInternal,
make_scoped_refptr(this)));
- HISTOGRAM_TIMES("PluginLoaderPosix.GetPluginList",
- (base::TimeTicks::Now() - start_time) *
- base::Time::kMicrosecondsPerMillisecond);
+ LOCAL_HISTOGRAM_TIMES("PluginLoaderPosix.GetPluginList",
+ (base::TimeTicks::Now() - start_time) *
+ base::Time::kMicrosecondsPerMillisecond);
}
void PluginLoaderPosix::LoadPluginsInternal() {
@@ -209,9 +209,9 @@ bool PluginLoaderPosix::MaybeRunPendingCallbacks() {
}
callbacks_.clear();
- HISTOGRAM_TIMES("PluginLoaderPosix.LoadDone",
- (base::TimeTicks::Now() - load_start_time_)
- * base::Time::kMicrosecondsPerMillisecond);
+ LOCAL_HISTOGRAM_TIMES("PluginLoaderPosix.LoadDone",
+ (base::TimeTicks::Now() - load_start_time_) *
+ base::Time::kMicrosecondsPerMillisecond);
load_start_time_ = base::TimeTicks();
return true;
diff --git a/chromium/content/browser/plugin_loader_posix.h b/chromium/content/browser/plugin_loader_posix.h
index 42c6437bde2..5b1580c17fa 100644
--- a/chromium/content/browser/plugin_loader_posix.h
+++ b/chromium/content/browser/plugin_loader_posix.h
@@ -55,14 +55,14 @@ class CONTENT_EXPORT PluginLoaderPosix
void GetPlugins(const PluginService::GetPluginsCallback& callback);
// UtilityProcessHostClient:
- virtual void OnProcessCrashed(int exit_code) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnProcessCrashed(int exit_code) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// IPC::Sender:
- virtual bool Send(IPC::Message* msg) OVERRIDE;
+ bool Send(IPC::Message* msg) override;
private:
- virtual ~PluginLoaderPosix();
+ ~PluginLoaderPosix() override;
// Called on the FILE thread to get the list of plugin paths to probe.
void GetPluginsToLoad();
diff --git a/chromium/content/browser/plugin_loader_posix_unittest.cc b/chromium/content/browser/plugin_loader_posix_unittest.cc
index 542b2c6cbb4..59e30b1ddd3 100644
--- a/chromium/content/browser/plugin_loader_posix_unittest.cc
+++ b/chromium/content/browser/plugin_loader_posix_unittest.cc
@@ -77,9 +77,7 @@ class PluginLoaderPosixTest : public testing::Test {
plugin_loader_(new MockPluginLoaderPosix) {
}
- virtual void SetUp() OVERRIDE {
- PluginServiceImpl::GetInstance()->Init();
- }
+ void SetUp() override { PluginServiceImpl::GetInstance()->Init(); }
base::MessageLoop* message_loop() { return &message_loop_; }
MockPluginLoaderPosix* plugin_loader() { return plugin_loader_.get(); }
diff --git a/chromium/content/browser/plugin_process_host.cc b/chromium/content/browser/plugin_process_host.cc
index 6c65dbf3c92..dd969d3e6c7 100644
--- a/chromium/content/browser/plugin_process_host.cc
+++ b/chromium/content/browser/plugin_process_host.cc
@@ -16,12 +16,13 @@
#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/metrics/histogram.h"
-#include "base/path_service.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 "content/browser/browser_child_process_host_impl.h"
#include "content/browser/loader/resource_message_filter.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
@@ -46,7 +47,6 @@
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
-#include "content/common/plugin_carbon_interpose_constants_mac.h"
#include "ui/gfx/rect.h"
#endif
@@ -57,6 +57,24 @@
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
@@ -85,30 +103,29 @@ class PluginSandboxedProcessLauncherDelegate
#endif // OS_POSIX
{}
- virtual ~PluginSandboxedProcessLauncherDelegate() {}
+ ~PluginSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual bool ShouldSandbox() OVERRIDE {
+ virtual bool ShouldSandbox() override {
return false;
}
#elif defined(OS_POSIX)
- virtual int GetIpcFd() OVERRIDE {
- return ipc_fd_;
- }
+ base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); }
#endif // OS_WIN
private:
#if defined(OS_POSIX)
- int ipc_fd_;
+ 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)
+ , plugin_cursor_visible_(true)
#endif
{
process_.reset(new BrowserChildProcessHostImpl(PROCESS_TYPE_PLUGIN, this));
@@ -145,6 +162,11 @@ PluginProcessHost::~PluginProcessHost() {
#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) {
@@ -161,8 +183,9 @@ bool PluginProcessHost::Init(const WebPluginInfo& info) {
// 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 CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- CommandLine::StringType plugin_launcher =
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
+ base::CommandLine::StringType plugin_launcher =
browser_command_line.GetSwitchValueNative(switches::kPluginLauncher);
#if defined(OS_MACOSX)
@@ -181,7 +204,7 @@ bool PluginProcessHost::Init(const WebPluginInfo& info) {
if (exe_path.empty())
return false;
- CommandLine* cmd_line = new CommandLine(exe_path);
+ 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);
@@ -225,25 +248,6 @@ bool PluginProcessHost::Init(const WebPluginInfo& info) {
cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
-#if defined(OS_POSIX)
- base::EnvironmentMap env;
-#if defined(OS_MACOSX) && !defined(__LP64__)
- if (browser_command_line.HasSwitch(switches::kEnableCarbonInterposing)) {
- std::string interpose_list = GetContentClient()->GetCarbonInterposePath();
- if (!interpose_list.empty()) {
- // Add our interposing library for Carbon. This is stripped back out in
- // plugin_main.cc, so changes here should be reflected there.
- const char* existing_list = getenv(kDYLDInsertLibrariesKey);
- if (existing_list) {
- interpose_list.insert(0, ":");
- interpose_list.insert(0, existing_list);
- }
- }
- env[kDYLDInsertLibrariesKey] = interpose_list;
- }
-#endif
-#endif
-
process_->Launch(
new PluginSandboxedProcessLauncherDelegate(process_->GetHost()),
cmd_line);
@@ -284,8 +288,6 @@ bool PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
OnPluginWindowDestroyed)
#endif
#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginSelectWindow,
- OnPluginSelectWindow)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginShowWindow,
OnPluginShowWindow)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginHideWindow,
@@ -305,6 +307,12 @@ void PluginProcessHost::OnChannelConnected(int32 peer_pid) {
}
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() {
diff --git a/chromium/content/browser/plugin_process_host.h b/chromium/content/browser/plugin_process_host.h
index 71c758039ba..1e8b67812ac 100644
--- a/chromium/content/browser/plugin_process_host.h
+++ b/chromium/content/browser/plugin_process_host.h
@@ -16,14 +16,15 @@
#include "base/basictypes.h"
#include "base/compiler_specific.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"
-#include "webkit/common/resource_type.h"
struct ResourceHostMsg_Request;
@@ -74,10 +75,10 @@ class CONTENT_EXPORT PluginProcessHost : public BrowserChildProcessHostDelegate,
};
PluginProcessHost();
- virtual ~PluginProcessHost();
+ ~PluginProcessHost() override;
// IPC::Sender implementation:
- virtual bool Send(IPC::Message* message) OVERRIDE;
+ 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.
@@ -86,9 +87,9 @@ class CONTENT_EXPORT PluginProcessHost : public BrowserChildProcessHostDelegate,
// Force the plugin process to shutdown (cleanly).
void ForceShutdown();
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
- virtual void OnChannelError() OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void OnChannelConnected(int32 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,
@@ -120,6 +121,12 @@ class CONTENT_EXPORT PluginProcessHost : public BrowserChildProcessHostDelegate,
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.
@@ -134,16 +141,14 @@ class CONTENT_EXPORT PluginProcessHost : public BrowserChildProcessHostDelegate,
#endif
#if defined(OS_MACOSX)
- void OnPluginSelectWindow(uint32 window_id, gfx::Rect window_rect,
- bool modal);
void OnPluginShowWindow(uint32 window_id, gfx::Rect window_rect,
bool modal);
void OnPluginHideWindow(uint32 window_id, gfx::Rect window_rect);
void OnPluginSetCursorVisibility(bool visible);
#endif
- virtual bool CanShutdown() OVERRIDE;
- virtual void OnProcessCrashed(int exit_code) OVERRIDE;
+ bool CanShutdown() override;
+ void OnProcessCrashed(int exit_code) override;
void CancelRequests();
@@ -163,6 +168,9 @@ class CONTENT_EXPORT PluginProcessHost : public BrowserChildProcessHostDelegate,
// 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_;
diff --git a/chromium/content/browser/plugin_process_host_mac.cc b/chromium/content/browser/plugin_process_host_mac.cc
index 93503009f3d..f3ad53f217b 100644
--- a/chromium/content/browser/plugin_process_host_mac.cc
+++ b/chromium/content/browser/plugin_process_host_mac.cc
@@ -19,14 +19,6 @@
namespace content {
-void PluginProcessHost::OnPluginSelectWindow(uint32 window_id,
- gfx::Rect window_rect,
- bool modal) {
- plugin_visible_windows_set_.insert(window_id);
- if (modal)
- plugin_modal_windows_set_.insert(window_id);
-}
-
void PluginProcessHost::OnPluginShowWindow(uint32 window_id,
gfx::Rect window_rect,
bool modal) {
diff --git a/chromium/content/browser/plugin_service_impl.cc b/chromium/content/browser/plugin_service_impl.cc
index a2c3170baf5..49b66389dd3 100644
--- a/chromium/content/browser/plugin_service_impl.cc
+++ b/chromium/content/browser/plugin_service_impl.cc
@@ -11,7 +11,6 @@
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram.h"
-#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
@@ -157,15 +156,6 @@ PluginServiceImpl::PluginServiceImpl()
}
PluginServiceImpl::~PluginServiceImpl() {
-#if defined(OS_WIN)
- // Release the events since they're owned by RegKey, not WaitableEvent.
- hkcu_watcher_.StopWatching();
- hklm_watcher_.StopWatching();
- if (hkcu_event_)
- hkcu_event_->Release();
- if (hklm_event_)
- hklm_event_->Release();
-#endif
// Make sure no plugin channel requests have been leaked.
DCHECK(pending_plugin_clients_.empty());
}
@@ -178,7 +168,8 @@ void PluginServiceImpl::Init() {
RegisterPepperPlugins();
// Load any specified on the command line as well.
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
base::FilePath path =
command_line->GetSwitchValuePath(switches::kLoadPlugin);
if (!path.empty())
@@ -199,24 +190,18 @@ void PluginServiceImpl::StartWatchingPlugins() {
if (hkcu_key_.Create(HKEY_CURRENT_USER,
kRegistryMozillaPlugins,
KEY_NOTIFY) == ERROR_SUCCESS) {
- if (hkcu_key_.StartWatching() == ERROR_SUCCESS) {
- hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
- base::WaitableEventWatcher::EventCallback callback =
- base::Bind(&PluginServiceImpl::OnWaitableEventSignaled,
- base::Unretained(this));
- hkcu_watcher_.StartWatching(hkcu_event_.get(), callback);
- }
+ 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) {
- if (hklm_key_.StartWatching() == ERROR_SUCCESS) {
- hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
- base::WaitableEventWatcher::EventCallback callback =
- base::Bind(&PluginServiceImpl::OnWaitableEventSignaled,
- base::Unretained(this));
- hklm_watcher_.StartWatching(hklm_event_.get(), callback);
- }
+ 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)
@@ -633,7 +618,7 @@ void PluginServiceImpl::GetPluginsOnIOThread(
// 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_)
+ if (!plugin_loader_.get())
plugin_loader_ = new PluginLoaderPosix;
plugin_loader_->GetPlugins(
@@ -641,22 +626,16 @@ void PluginServiceImpl::GetPluginsOnIOThread(
}
#endif
-void PluginServiceImpl::OnWaitableEventSignaled(
- base::WaitableEvent* waitable_event) {
#if defined(OS_WIN)
- if (waitable_event == hkcu_event_) {
- hkcu_key_.StartWatching();
- } else {
- hklm_key_.StartWatching();
- }
+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);
-#else
- // This event should only get signaled on a Windows machine.
- NOTREACHED();
-#endif // defined(OS_WIN)
}
+#endif // defined(OS_WIN)
void PluginServiceImpl::RegisterPepperPlugins() {
ComputePepperPluginList(&ppapi_plugins_);
@@ -840,10 +819,15 @@ bool PluginServiceImpl::GetPluginInfoFromWindow(
if (!IsPluginWindow(window))
return false;
- GetPluginPropertyFromWindow(
- window, kPluginNameAtomProperty, plugin_name);
- GetPluginPropertyFromWindow(
- window, kPluginVersionAtomProperty, plugin_version);
+
+ 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;
}
diff --git a/chromium/content/browser/plugin_service_impl.h b/chromium/content/browser/plugin_service_impl.h
index 861889c7a36..8770974a973 100644
--- a/chromium/content/browser/plugin_service_impl.h
+++ b/chromium/content/browser/plugin_service_impl.h
@@ -8,6 +8,10 @@
#ifndef CONTENT_BROWSER_PLUGIN_SERVICE_IMPL_H_
#define CONTENT_BROWSER_PLUGIN_SERVICE_IMPL_H_
+#if !defined(ENABLE_PLUGINS)
+#error "Plugins should be enabled"
+#endif
+
#include <map>
#include <set>
#include <vector>
@@ -65,58 +69,56 @@ class CONTENT_EXPORT PluginServiceImpl
static PluginServiceImpl* GetInstance();
// PluginService implementation:
- virtual void Init() OVERRIDE;
- virtual void StartWatchingPlugins() OVERRIDE;
- virtual bool GetPluginInfoArray(
- const GURL& url,
- const std::string& mime_type,
- bool allow_wildcard,
- std::vector<WebPluginInfo>* info,
- std::vector<std::string>* actual_mime_types) OVERRIDE;
- virtual bool GetPluginInfo(int render_process_id,
- int render_frame_id,
- ResourceContext* context,
- const GURL& url,
- const GURL& page_url,
- const std::string& mime_type,
- bool allow_wildcard,
- bool* is_stale,
- WebPluginInfo* info,
- std::string* actual_mime_type) OVERRIDE;
- virtual bool GetPluginInfoByPath(const base::FilePath& plugin_path,
- WebPluginInfo* info) OVERRIDE;
- virtual base::string16 GetPluginDisplayNameByPath(
- const base::FilePath& path) OVERRIDE;
- virtual void GetPlugins(const GetPluginsCallback& callback) OVERRIDE;
- virtual PepperPluginInfo* GetRegisteredPpapiPluginInfo(
- const base::FilePath& plugin_path) OVERRIDE;
- virtual void SetFilter(PluginServiceFilter* filter) OVERRIDE;
- virtual PluginServiceFilter* GetFilter() OVERRIDE;
- virtual void ForcePluginShutdown(const base::FilePath& plugin_path) OVERRIDE;
- virtual bool IsPluginUnstable(const base::FilePath& plugin_path) OVERRIDE;
- virtual void RefreshPlugins() OVERRIDE;
- virtual void AddExtraPluginPath(const base::FilePath& path) OVERRIDE;
- virtual void RemoveExtraPluginPath(const base::FilePath& path) OVERRIDE;
- virtual void AddExtraPluginDir(const base::FilePath& path) OVERRIDE;
- virtual void RegisterInternalPlugin(
- const WebPluginInfo& info, bool add_at_beginning) OVERRIDE;
- virtual void UnregisterInternalPlugin(const base::FilePath& path) OVERRIDE;
- virtual void GetInternalPlugins(
- std::vector<WebPluginInfo>* plugins) OVERRIDE;
- virtual bool NPAPIPluginsSupported() OVERRIDE;
- virtual void DisablePluginsDiscoveryForTesting() OVERRIDE;
+ void Init() override;
+ void StartWatchingPlugins() override;
+ bool GetPluginInfoArray(const GURL& url,
+ const std::string& mime_type,
+ bool allow_wildcard,
+ std::vector<WebPluginInfo>* info,
+ std::vector<std::string>* actual_mime_types) override;
+ bool GetPluginInfo(int render_process_id,
+ int render_frame_id,
+ ResourceContext* context,
+ const GURL& url,
+ const GURL& page_url,
+ const std::string& mime_type,
+ bool allow_wildcard,
+ bool* is_stale,
+ WebPluginInfo* info,
+ std::string* actual_mime_type) override;
+ bool GetPluginInfoByPath(const base::FilePath& plugin_path,
+ WebPluginInfo* info) override;
+ base::string16 GetPluginDisplayNameByPath(
+ const base::FilePath& path) override;
+ void GetPlugins(const GetPluginsCallback& callback) override;
+ PepperPluginInfo* GetRegisteredPpapiPluginInfo(
+ 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)
- virtual void AppActivated() OVERRIDE;
+ void AppActivated() override;
#elif defined(OS_WIN)
virtual bool GetPluginInfoFromWindow(HWND window,
base::string16* plugin_name,
- base::string16* plugin_version) OVERRIDE;
+ base::string16* plugin_version) override;
// Returns true iff the given HWND is a plugin.
bool IsPluginWindow(HWND window);
#endif
- virtual bool PpapiDevChannelSupported(BrowserContext* browser_context,
- const GURL& document_url) OVERRIDE;
+ bool PpapiDevChannelSupported(BrowserContext* browser_context,
+ const GURL& document_url) override;
// Returns the plugin process host corresponding to the plugin process that
// has been started by this service. This will start a process to host the
@@ -160,9 +162,11 @@ class CONTENT_EXPORT PluginServiceImpl
// Creates the PluginServiceImpl object, but doesn't actually build the plugin
// list yet. It's generated lazily.
PluginServiceImpl();
- virtual ~PluginServiceImpl();
+ ~PluginServiceImpl() override;
- void OnWaitableEventSignaled(base::WaitableEvent* waitable_event);
+#if defined(OS_WIN)
+ void OnKeyChanged(base::win::RegKey* key);
+#endif
// Returns the plugin process host corresponding to the plugin process that
// has been started by this service. Returns NULL if no process has been
@@ -220,10 +224,6 @@ class CONTENT_EXPORT PluginServiceImpl
// Registry keys for getting notifications when new plugins are installed.
base::win::RegKey hkcu_key_;
base::win::RegKey hklm_key_;
- scoped_ptr<base::WaitableEvent> hkcu_event_;
- scoped_ptr<base::WaitableEvent> hklm_event_;
- base::WaitableEventWatcher hkcu_watcher_;
- base::WaitableEventWatcher hklm_watcher_;
#endif
#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
diff --git a/chromium/content/browser/plugin_service_impl_browsertest.cc b/chromium/content/browser/plugin_service_impl_browsertest.cc
index 7a3271e6c78..b8a3dfb2248 100644
--- a/chromium/content/browser/plugin_service_impl_browsertest.cc
+++ b/chromium/content/browser/plugin_service_impl_browsertest.cc
@@ -42,21 +42,19 @@ class MockPluginProcessHostClient : public PluginProcessHost::Client,
expect_fail_(expect_fail) {
}
- virtual ~MockPluginProcessHostClient() {
+ ~MockPluginProcessHostClient() override {
if (channel_)
BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
}
// PluginProcessHost::Client implementation.
- virtual int ID() OVERRIDE { return 42; }
- virtual bool OffTheRecord() OVERRIDE { return false; }
- virtual ResourceContext* GetResourceContext() OVERRIDE {
- return context_;
- }
- virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {}
- virtual void OnSentPluginChannelRequest() OVERRIDE {}
+ int ID() override { return 42; }
+ bool OffTheRecord() override { return false; }
+ ResourceContext* GetResourceContext() override { return context_; }
+ void OnFoundPluginProcessHost(PluginProcessHost* host) override {}
+ void OnSentPluginChannelRequest() override {}
- virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
+ void OnChannelOpened(const IPC::ChannelHandle& handle) override {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
ASSERT_TRUE(set_plugin_info_called_);
ASSERT_TRUE(!channel_);
@@ -64,36 +62,28 @@ class MockPluginProcessHostClient : public PluginProcessHost::Client,
ASSERT_TRUE(channel_->Connect());
}
- virtual void SetPluginInfo(const WebPluginInfo& info) OVERRIDE {
+ void SetPluginInfo(const WebPluginInfo& info) override {
ASSERT_TRUE(info.mime_types.size());
ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
set_plugin_info_called_ = true;
}
- virtual void OnError() OVERRIDE {
- Fail();
- }
+ void OnError() override { Fail(); }
// IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ bool OnMessageReceived(const IPC::Message& message) override {
Fail();
return false;
}
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
+ void OnChannelConnected(int32 peer_pid) override {
if (expect_fail_)
FAIL();
QuitMessageLoop();
}
- virtual void OnChannelError() OVERRIDE {
- Fail();
- }
+ void OnChannelError() override { Fail(); }
#if defined(OS_POSIX)
- virtual void OnChannelDenied() OVERRIDE {
- Fail();
- }
- virtual void OnChannelListenError() OVERRIDE {
- Fail();
- }
+ void OnChannelDenied() override { Fail(); }
+ void OnChannelListenError() override { Fail(); }
#endif
private:
@@ -119,17 +109,19 @@ class MockPluginServiceFilter : public content::PluginServiceFilter {
public:
MockPluginServiceFilter() {}
- virtual bool IsPluginAvailable(
- int render_process_id,
- int render_view_id,
- const void* context,
- const GURL& url,
- const GURL& policy_url,
- WebPluginInfo* plugin) OVERRIDE { return true; }
-
- virtual bool CanLoadPlugin(
- int render_process_id,
- const base::FilePath& path) OVERRIDE { return false; }
+ bool IsPluginAvailable(int render_process_id,
+ int render_view_id,
+ const void* context,
+ const GURL& url,
+ const GURL& policy_url,
+ WebPluginInfo* plugin) override {
+ return true;
+ }
+
+ bool CanLoadPlugin(int render_process_id,
+ const base::FilePath& path) override {
+ return false;
+ }
};
class PluginServiceTest : public ContentBrowserTest {
@@ -140,7 +132,7 @@ class PluginServiceTest : public ContentBrowserTest {
return shell()->web_contents()->GetBrowserContext()->GetResourceContext();
}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
#if defined(OS_MACOSX)
base::FilePath browser_directory;
PathService::Get(base::DIR_MODULE, &browser_directory);
@@ -193,7 +185,7 @@ class MockCanceledPluginServiceClient : public PluginProcessHost::Client {
// Client implementation.
MOCK_METHOD0(ID, int());
- virtual ResourceContext* GetResourceContext() OVERRIDE {
+ virtual ResourceContext* GetResourceContext() override {
get_resource_context_called_ = true;
return context_;
}
@@ -254,16 +246,16 @@ class MockCanceledBeforeSentPluginProcessHostClient
on_found_plugin_process_host_called_(false),
host_(NULL) {}
- virtual ~MockCanceledBeforeSentPluginProcessHostClient() {}
+ ~MockCanceledBeforeSentPluginProcessHostClient() override {}
// Client implementation.
- virtual void SetPluginInfo(const WebPluginInfo& info) OVERRIDE {
+ void SetPluginInfo(const WebPluginInfo& info) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
ASSERT_TRUE(info.mime_types.size());
ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
set_plugin_info_called_ = true;
}
- virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
+ void OnFoundPluginProcessHost(PluginProcessHost* host) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
set_on_found_plugin_process_host_called();
set_host(host);
@@ -326,21 +318,21 @@ class MockCanceledAfterSentPluginProcessHostClient
ResourceContext* context)
: MockCanceledBeforeSentPluginProcessHostClient(context),
on_sent_plugin_channel_request_called_(false) {}
- virtual ~MockCanceledAfterSentPluginProcessHostClient() {}
+ ~MockCanceledAfterSentPluginProcessHostClient() override {}
// Client implementation.
- virtual int ID() OVERRIDE { return 42; }
- virtual bool OffTheRecord() OVERRIDE { return false; }
+ int ID() override { return 42; }
+ bool OffTheRecord() override { return false; }
// We override this guy again since we don't want to cancel yet.
- virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
+ void OnFoundPluginProcessHost(PluginProcessHost* host) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
set_on_found_plugin_process_host_called();
set_host(host);
}
- virtual void OnSentPluginChannelRequest() OVERRIDE {
+ void OnSentPluginChannelRequest() override {
on_sent_plugin_channel_request_called_ = true;
host()->CancelSentRequest(this);
BrowserThread::PostTask(
diff --git a/chromium/content/browser/power_monitor_message_broadcaster.cc b/chromium/content/browser/power_monitor_message_broadcaster.cc
index 23de161b05c..e862abbfe74 100644
--- a/chromium/content/browser/power_monitor_message_broadcaster.cc
+++ b/chromium/content/browser/power_monitor_message_broadcaster.cc
@@ -24,6 +24,13 @@ PowerMonitorMessageBroadcaster::~PowerMonitorMessageBroadcaster() {
power_monitor->RemoveObserver(this);
}
+void PowerMonitorMessageBroadcaster::Init() {
+ base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
+ // Unit tests does not initialize the PowerMonitor.
+ if (power_monitor)
+ OnPowerStateChange(power_monitor->IsOnBatteryPower());
+}
+
void PowerMonitorMessageBroadcaster::OnPowerStateChange(bool on_battery_power) {
sender_->Send(new PowerMonitorMsg_PowerStateChange(on_battery_power));
}
diff --git a/chromium/content/browser/power_monitor_message_broadcaster.h b/chromium/content/browser/power_monitor_message_broadcaster.h
index 082ba670bbd..3221fadc690 100644
--- a/chromium/content/browser/power_monitor_message_broadcaster.h
+++ b/chromium/content/browser/power_monitor_message_broadcaster.h
@@ -21,12 +21,14 @@ class CONTENT_EXPORT PowerMonitorMessageBroadcaster
: public base::PowerObserver {
public:
explicit PowerMonitorMessageBroadcaster(IPC::Sender* sender);
- virtual ~PowerMonitorMessageBroadcaster();
+ ~PowerMonitorMessageBroadcaster() override;
// Implement PowerObserver.
- virtual void OnPowerStateChange(bool on_battery_power) OVERRIDE;
- virtual void OnSuspend() OVERRIDE;
- virtual void OnResume() OVERRIDE;
+ void OnPowerStateChange(bool on_battery_power) override;
+ void OnSuspend() override;
+ void OnResume() override;
+
+ void Init();
private:
IPC::Sender* sender_;
diff --git a/chromium/content/browser/power_monitor_message_broadcaster_unittest.cc b/chromium/content/browser/power_monitor_message_broadcaster_unittest.cc
index 515508266cf..32deb1ea09b 100644
--- a/chromium/content/browser/power_monitor_message_broadcaster_unittest.cc
+++ b/chromium/content/browser/power_monitor_message_broadcaster_unittest.cc
@@ -17,9 +17,9 @@ class PowerMonitorMessageSender : public IPC::Sender {
suspends_(0),
resumes_(0) {
}
- virtual ~PowerMonitorMessageSender() {}
+ ~PowerMonitorMessageSender() override {}
- virtual bool Send(IPC::Message* msg) OVERRIDE {
+ bool Send(IPC::Message* msg) override {
switch (msg->type()) {
case PowerMonitorMsg_Suspend::ID:
suspends_++;
@@ -53,7 +53,7 @@ class PowerMonitorMessageBroadcasterTest : public testing::Test {
power_monitor_.reset(new base::PowerMonitor(
scoped_ptr<base::PowerMonitorSource>(power_monitor_source_)));
}
- virtual ~PowerMonitorMessageBroadcasterTest() {};
+ ~PowerMonitorMessageBroadcasterTest() override {}
base::PowerMonitorTestSource* source() { return power_monitor_source_; }
base::PowerMonitor* monitor() { return power_monitor_.get(); }
@@ -69,6 +69,10 @@ TEST_F(PowerMonitorMessageBroadcasterTest, PowerMessageBroadcast) {
PowerMonitorMessageSender sender;
PowerMonitorMessageBroadcaster broadcaster(&sender);
+ // Calling Init should invoke a power state change.
+ broadcaster.Init();
+ EXPECT_EQ(sender.power_state_changes(), 1);
+
// Sending resume when not suspended should have no effect.
source()->GenerateResumeEvent();
EXPECT_EQ(sender.resumes(), 0);
@@ -91,19 +95,19 @@ TEST_F(PowerMonitorMessageBroadcasterTest, PowerMessageBroadcast) {
// Pretend the device has gone on battery power
source()->GeneratePowerStateEvent(true);
- EXPECT_EQ(sender.power_state_changes(), 1);
+ EXPECT_EQ(sender.power_state_changes(), 2);
// Repeated indications the device is on battery power should be suppressed.
source()->GeneratePowerStateEvent(true);
- EXPECT_EQ(sender.power_state_changes(), 1);
+ EXPECT_EQ(sender.power_state_changes(), 2);
// Pretend the device has gone off battery power
source()->GeneratePowerStateEvent(false);
- EXPECT_EQ(sender.power_state_changes(), 2);
+ EXPECT_EQ(sender.power_state_changes(), 3);
// Repeated indications the device is off battery power should be suppressed.
source()->GeneratePowerStateEvent(false);
- EXPECT_EQ(sender.power_state_changes(), 2);
+ EXPECT_EQ(sender.power_state_changes(), 3);
}
} // namespace base
diff --git a/chromium/content/browser/power_profiler/power_data_provider.h b/chromium/content/browser/power_profiler/power_data_provider.h
index 85f67e7f5fb..897bc9b636c 100644
--- a/chromium/content/browser/power_profiler/power_data_provider.h
+++ b/chromium/content/browser/power_profiler/power_data_provider.h
@@ -21,6 +21,12 @@ typedef std::vector<PowerEvent> PowerEventVector;
// A class used to get power usage.
class PowerDataProvider {
public:
+ enum AccuracyLevel {
+ High,
+ Moderate,
+ Low
+ };
+
static scoped_ptr<PowerDataProvider> Create();
PowerDataProvider() {}
@@ -31,6 +37,9 @@ class PowerDataProvider {
// Returns sampling rate at which the provider can operate.
virtual base::TimeDelta GetSamplingRate() = 0;
+
+ // Returns accuracy level of the provider.
+ virtual AccuracyLevel GetAccuracyLevel() = 0;
};
} // namespace content
diff --git a/chromium/content/browser/power_profiler/power_data_provider_ia_win.h b/chromium/content/browser/power_profiler/power_data_provider_ia_win.h
index 2c7e489328d..427a5fa202a 100644
--- a/chromium/content/browser/power_profiler/power_data_provider_ia_win.h
+++ b/chromium/content/browser/power_profiler/power_data_provider_ia_win.h
@@ -18,8 +18,9 @@ class PowerDataProviderIA : public PowerDataProvider {
virtual ~PowerDataProviderIA();
bool Initialize();
- virtual PowerEventVector GetData() OVERRIDE;
- virtual base::TimeDelta GetSamplingRate() OVERRIDE;
+ virtual PowerEventVector GetData() override;
+ virtual base::TimeDelta GetSamplingRate() override;
+ virtual AccuracyLevel GetAccuracyLevel() override { return High; }
private:
CIntelPowerGadgetLib energy_lib_;
diff --git a/chromium/content/browser/power_profiler/power_profiler_service.cc b/chromium/content/browser/power_profiler/power_profiler_service.cc
index 026b42ab893..84ddb1bd15a 100644
--- a/chromium/content/browser/power_profiler/power_profiler_service.cc
+++ b/chromium/content/browser/power_profiler/power_profiler_service.cc
@@ -42,10 +42,23 @@ PowerProfilerService::PowerProfilerService(
PowerProfilerService::~PowerProfilerService() {
}
-bool PowerProfilerService::IsAvailable() {
+bool PowerProfilerService::IsAvailable() const {
return status_ != UNINITIALIZED;
}
+std::string PowerProfilerService::GetAccuracyLevel() const {
+ DCHECK(IsAvailable());
+ switch (data_provider_->GetAccuracyLevel()) {
+ case PowerDataProvider::High:
+ return "High";
+ case PowerDataProvider::Moderate:
+ return "Moderate";
+ case PowerDataProvider::Low:
+ return "Low";
+ }
+ return "";
+}
+
PowerProfilerService* PowerProfilerService::GetInstance() {
return Singleton<PowerProfilerService>::get();
}
diff --git a/chromium/content/browser/power_profiler/power_profiler_service.h b/chromium/content/browser/power_profiler/power_profiler_service.h
index 35f2f65cce3..4daae28f907 100644
--- a/chromium/content/browser/power_profiler/power_profiler_service.h
+++ b/chromium/content/browser/power_profiler/power_profiler_service.h
@@ -25,7 +25,8 @@ class CONTENT_EXPORT PowerProfilerService {
void AddObserver(PowerProfilerObserver* observer);
void RemoveObserver(PowerProfilerObserver* observer);
- bool IsAvailable();
+ bool IsAvailable() const;
+ std::string GetAccuracyLevel() const;
virtual ~PowerProfilerService();
diff --git a/chromium/content/browser/power_profiler/power_profiler_service_unittest.cc b/chromium/content/browser/power_profiler/power_profiler_service_unittest.cc
index f7f77dc82dd..3386b6f618c 100644
--- a/chromium/content/browser/power_profiler/power_profiler_service_unittest.cc
+++ b/chromium/content/browser/power_profiler/power_profiler_service_unittest.cc
@@ -19,9 +19,9 @@ const int kDefaultSamplePeriodMs = 50;
class TestPowerDataProvider : public PowerDataProvider {
public:
TestPowerDataProvider(int count) : num_events_to_send_(count) {}
- virtual ~TestPowerDataProvider() {}
+ ~TestPowerDataProvider() override {}
- virtual PowerEventVector GetData() OVERRIDE {
+ PowerEventVector GetData() override {
PowerEventVector events;
if (num_events_to_send_ == 0)
return events;
@@ -36,10 +36,12 @@ class TestPowerDataProvider : public PowerDataProvider {
return events;
}
- virtual base::TimeDelta GetSamplingRate() OVERRIDE {
+ base::TimeDelta GetSamplingRate() override {
return base::TimeDelta::FromMilliseconds(kDefaultSamplePeriodMs);
}
+ AccuracyLevel GetAccuracyLevel() override { return High; }
+
private:
int num_events_to_send_;
DISALLOW_COPY_AND_ASSIGN(TestPowerDataProvider);
@@ -50,9 +52,9 @@ class TestPowerProfilerObserver : public PowerProfilerObserver {
TestPowerProfilerObserver()
: valid_event_count_(0),
total_num_events_received_(0) {}
- virtual ~TestPowerProfilerObserver() {}
+ ~TestPowerProfilerObserver() override {}
- virtual void OnPowerEvent(const PowerEventVector& events) OVERRIDE {
+ void OnPowerEvent(const PowerEventVector& events) override {
if (IsValidEvent(events[0]))
++valid_event_count_;
@@ -109,7 +111,7 @@ class PowerProfilerServiceTest : public testing::Test {
protected:
PowerProfilerServiceTest() : ui_thread_(BrowserThread::UI, &message_loop_) {}
- virtual ~PowerProfilerServiceTest() {}
+ ~PowerProfilerServiceTest() override {}
void RegisterQuitClosure(base::Closure closure) {
observer_.set_quit_closure(closure);
diff --git a/chromium/content/browser/power_save_blocker_android.cc b/chromium/content/browser/power_save_blocker_android.cc
index 79da1a907ed..2f79ef99f27 100644
--- a/chromium/content/browser/power_save_blocker_android.cc
+++ b/chromium/content/browser/power_save_blocker_android.cc
@@ -62,7 +62,7 @@ PowerSaveBlockerImpl::PowerSaveBlockerImpl(PowerSaveBlockerType type,
}
PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
- if (delegate_) {
+ if (delegate_.get()) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&Delegate::RemoveBlock, delegate_));
diff --git a/chromium/content/browser/power_save_blocker_impl.h b/chromium/content/browser/power_save_blocker_impl.h
index 948aced4cb4..39ba8f24f8e 100644
--- a/chromium/content/browser/power_save_blocker_impl.h
+++ b/chromium/content/browser/power_save_blocker_impl.h
@@ -14,7 +14,7 @@ namespace content {
class PowerSaveBlockerImpl : public PowerSaveBlocker {
public:
PowerSaveBlockerImpl(PowerSaveBlockerType type, const std::string& reason);
- virtual ~PowerSaveBlockerImpl();
+ ~PowerSaveBlockerImpl() override;
#if defined(OS_ANDROID)
// In Android platform, the kPowerSaveBlockPreventDisplaySleep type of
diff --git a/chromium/content/browser/power_save_blocker_win.cc b/chromium/content/browser/power_save_blocker_win.cc
index 727600dff14..4cbecf4447a 100644
--- a/chromium/content/browser/power_save_blocker_win.cc
+++ b/chromium/content/browser/power_save_blocker_win.cc
@@ -49,7 +49,7 @@ HANDLE CreatePowerRequest(POWER_REQUEST_TYPE type, const std::string& reason) {
if (!handle.IsValid())
return INVALID_HANDLE_VALUE;
- if (PowerSetRequestFn(handle, type))
+ if (PowerSetRequestFn(handle.Get(), type))
return handle.Take();
// Something went wrong.
@@ -76,7 +76,7 @@ void DeletePowerRequest(POWER_REQUEST_TYPE type, HANDLE handle) {
if (!PowerClearRequestFn)
return;
- BOOL success = PowerClearRequestFn(request_handle, type);
+ BOOL success = PowerClearRequestFn(request_handle.Get(), type);
DCHECK(success);
}
diff --git a/chromium/content/browser/power_save_blocker_x11.cc b/chromium/content/browser/power_save_blocker_x11.cc
index e5fb4e5f3df..f1d028c7f45 100644
--- a/chromium/content/browser/power_save_blocker_x11.cc
+++ b/chromium/content/browser/power_save_blocker_x11.cc
@@ -200,7 +200,7 @@ void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
// reason: The reason for the inhibit
// flags: Flags that spefify what should be inhibited
message_writer->AppendString(
- CommandLine::ForCurrentProcess()->GetProgram().value());
+ base::CommandLine::ForCurrentProcess()->GetProgram().value());
message_writer->AppendUint32(0); // should be toplevel_xid
message_writer->AppendString(reason_);
{
@@ -228,7 +228,7 @@ void PowerSaveBlockerImpl::Delegate::ApplyBlock(DBusAPI api) {
// app_id: The application identifier
// reason: The reason for the inhibit
message_writer->AppendString(
- CommandLine::ForCurrentProcess()->GetProgram().value());
+ base::CommandLine::ForCurrentProcess()->GetProgram().value());
message_writer->AppendString(reason_);
break;
}
diff --git a/chromium/content/browser/ppapi_plugin_process_host.cc b/chromium/content/browser/ppapi_plugin_process_host.cc
index fc6a75ebed7..22b69ba76d2 100644
--- a/chromium/content/browser/ppapi_plugin_process_host.cc
+++ b/chromium/content/browser/ppapi_plugin_process_host.cc
@@ -48,10 +48,10 @@ class PpapiPluginSandboxedProcessLauncherDelegate
#endif // OS_POSIX
is_broker_(is_broker) {}
- virtual ~PpapiPluginSandboxedProcessLauncherDelegate() {}
+ ~PpapiPluginSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual bool ShouldSandbox() OVERRIDE {
+ virtual bool ShouldSandbox() override {
return !is_broker_;
}
@@ -69,21 +69,20 @@ class PpapiPluginSandboxedProcessLauncherDelegate
}
#elif defined(OS_POSIX)
- virtual bool ShouldUseZygote() OVERRIDE {
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- CommandLine::StringType plugin_launcher = browser_command_line
+ bool ShouldUseZygote() 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() && info_.is_sandboxed;
}
- virtual int GetIpcFd() OVERRIDE {
- return ipc_fd_;
- }
+ base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); }
#endif // OS_WIN
private:
#if defined(OS_POSIX)
const PepperPluginInfo& info_;
- int ipc_fd_;
+ base::ScopedFD ipc_fd_;
#endif // OS_POSIX
bool is_broker_;
@@ -100,13 +99,13 @@ class PpapiPluginProcessHost::PluginNetworkObserver
net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
}
- virtual ~PluginNetworkObserver() {
+ ~PluginNetworkObserver() override {
net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
}
// IPAddressObserver implementation.
- virtual void OnIPAddressChanged() OVERRIDE {
+ void OnIPAddressChanged() override {
// TODO(brettw) bug 90246: This doesn't seem correct. The online/offline
// notification seems like it should be sufficient, but I don't see that
// when I unplug and replug my network cable. Sending this notification when
@@ -117,8 +116,8 @@ class PpapiPluginProcessHost::PluginNetworkObserver
}
// ConnectionTypeObserver implementation.
- virtual void OnConnectionTypeChanged(
- net::NetworkChangeNotifier::ConnectionType type) OVERRIDE {
+ void OnConnectionTypeChanged(
+ net::NetworkChangeNotifier::ConnectionType type) override {
process_host_->Send(new PpapiMsg_SetNetworkState(
type != net::NetworkChangeNotifier::CONNECTION_NONE));
}
@@ -288,8 +287,9 @@ bool PpapiPluginProcessHost::Init(const PepperPluginInfo& info) {
return false;
}
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- CommandLine::StringType plugin_launcher =
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
+ base::CommandLine::StringType plugin_launcher =
browser_command_line.GetSwitchValueNative(switches::kPpapiPluginLauncher);
#if defined(OS_LINUX)
@@ -304,7 +304,7 @@ bool PpapiPluginProcessHost::Init(const PepperPluginInfo& info) {
return false;
}
- CommandLine* cmd_line = new CommandLine(exe_path);
+ base::CommandLine* cmd_line = new base::CommandLine(exe_path);
cmd_line->AppendSwitchASCII(switches::kProcessType,
is_broker_ ? switches::kPpapiBrokerProcess
: switches::kPpapiPluginProcess);
diff --git a/chromium/content/browser/ppapi_plugin_process_host.h b/chromium/content/browser/ppapi_plugin_process_host.h
index 594c12f6152..3f90d3025dc 100644
--- a/chromium/content/browser/ppapi_plugin_process_host.h
+++ b/chromium/content/browser/ppapi_plugin_process_host.h
@@ -60,15 +60,15 @@ class PpapiPluginProcessHost : public BrowserChildProcessHostDelegate,
virtual ResourceContext* GetResourceContext() = 0;
protected:
- virtual ~PluginClient() {}
+ ~PluginClient() override {}
};
class BrokerClient : public Client {
protected:
- virtual ~BrokerClient() {}
+ ~BrokerClient() override {}
};
- virtual ~PpapiPluginProcessHost();
+ ~PpapiPluginProcessHost() override;
static PpapiPluginProcessHost* CreatePluginHost(
const PepperPluginInfo& info,
@@ -96,7 +96,7 @@ class PpapiPluginProcessHost : public BrowserChildProcessHostDelegate,
std::vector<PpapiPluginProcessHost*>* hosts);
// IPC::Sender implementation:
- virtual bool Send(IPC::Message* message) OVERRIDE;
+ bool Send(IPC::Message* message) override;
// Opens a new channel to the plugin. The client will be notified when the
// channel is ready or if there's an error.
@@ -126,12 +126,12 @@ class PpapiPluginProcessHost : public BrowserChildProcessHostDelegate,
void RequestPluginChannel(Client* client);
- virtual void OnProcessLaunched() OVERRIDE;
+ void OnProcessLaunched() override;
- virtual void OnProcessCrashed(int exit_code) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
- virtual void OnChannelError() OVERRIDE;
+ void OnProcessCrashed(int exit_code) override;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void OnChannelConnected(int32 peer_pid) override;
+ void OnChannelError() override;
void CancelRequests();
diff --git a/chromium/content/browser/profiler_controller_impl.h b/chromium/content/browser/profiler_controller_impl.h
index 34c76ec56de..44e160c9a5d 100644
--- a/chromium/content/browser/profiler_controller_impl.h
+++ b/chromium/content/browser/profiler_controller_impl.h
@@ -25,7 +25,7 @@ class ProfilerControllerImpl : public ProfilerController {
// Normally instantiated when the child process is launched. Only one instance
// should be created per process.
ProfilerControllerImpl();
- virtual ~ProfilerControllerImpl();
+ ~ProfilerControllerImpl() override;
// Notify the |subscriber_| that it should expect at least |pending_processes|
// additional calls to OnProfilerDataCollected(). OnPendingProcess() may be
@@ -42,9 +42,9 @@ class ProfilerControllerImpl : public ProfilerController {
int process_type);
// ProfilerController implementation:
- virtual void Register(ProfilerSubscriber* subscriber) OVERRIDE;
- virtual void Unregister(const ProfilerSubscriber* subscriber) OVERRIDE;
- virtual void GetProfilerData(int sequence_number) OVERRIDE;
+ void Register(ProfilerSubscriber* subscriber) override;
+ void Unregister(const ProfilerSubscriber* subscriber) override;
+ void GetProfilerData(int sequence_number) override;
private:
friend struct DefaultSingletonTraits<ProfilerControllerImpl>;
diff --git a/chromium/content/browser/profiler_message_filter.h b/chromium/content/browser/profiler_message_filter.h
index 1575abcc6f2..df4ce53e061 100644
--- a/chromium/content/browser/profiler_message_filter.h
+++ b/chromium/content/browser/profiler_message_filter.h
@@ -21,13 +21,13 @@ class ProfilerMessageFilter : public BrowserMessageFilter {
explicit ProfilerMessageFilter(int process_type);
// BrowserMessageFilter implementation.
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
+ void OnChannelConnected(int32 peer_pid) override;
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
protected:
- virtual ~ProfilerMessageFilter();
+ ~ProfilerMessageFilter() override;
private:
// Message handlers.
diff --git a/chromium/content/browser/push_messaging/OWNERS b/chromium/content/browser/push_messaging/OWNERS
new file mode 100644
index 00000000000..de1f744c561
--- /dev/null
+++ b/chromium/content/browser/push_messaging/OWNERS
@@ -0,0 +1,2 @@
+mvanouwerkerk@chromium.org
+
diff --git a/chromium/content/browser/push_messaging/push_messaging_message_filter.cc b/chromium/content/browser/push_messaging/push_messaging_message_filter.cc
new file mode 100644
index 00000000000..ed9046f0565
--- /dev/null
+++ b/chromium/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -0,0 +1,183 @@
+// 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/push_messaging/push_messaging_message_filter.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/common/push_messaging_messages.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/push_messaging_service.h"
+#include "third_party/WebKit/public/platform/WebPushPermissionStatus.h"
+
+namespace content {
+namespace {
+
+void RecordRegistrationStatus(PushRegistrationStatus status) {
+ UMA_HISTOGRAM_ENUMERATION("PushMessaging.RegistrationStatus",
+ status,
+ PUSH_REGISTRATION_STATUS_LAST + 1);
+}
+
+} // namespace
+
+PushMessagingMessageFilter::PushMessagingMessageFilter(
+ int render_process_id,
+ ServiceWorkerContextWrapper* service_worker_context)
+ : BrowserMessageFilter(PushMessagingMsgStart),
+ render_process_id_(render_process_id),
+ service_worker_context_(service_worker_context),
+ service_(NULL),
+ weak_factory_(this) {
+}
+
+PushMessagingMessageFilter::~PushMessagingMessageFilter() {}
+
+bool PushMessagingMessageFilter::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PushMessagingMessageFilter, message)
+ IPC_MESSAGE_HANDLER(PushMessagingHostMsg_Register, OnRegister)
+ IPC_MESSAGE_HANDLER(PushMessagingHostMsg_PermissionStatus,
+ OnPermissionStatusRequest)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void PushMessagingMessageFilter::OnRegister(int render_frame_id,
+ int callbacks_id,
+ const std::string& sender_id,
+ bool user_gesture,
+ int service_worker_provider_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // TODO(mvanouwerkerk): Validate arguments?
+ ServiceWorkerProviderHost* service_worker_host =
+ service_worker_context_->context()->GetProviderHost(
+ render_process_id_, service_worker_provider_id);
+ if (!service_worker_host || !service_worker_host->active_version()) {
+ PushRegistrationStatus status =
+ PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER;
+ Send(new PushMessagingMsg_RegisterError(
+ render_frame_id,
+ callbacks_id,
+ status));
+ RecordRegistrationStatus(status);
+ return;
+ }
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::DoRegister,
+ weak_factory_.GetWeakPtr(),
+ render_frame_id,
+ callbacks_id,
+ sender_id,
+ user_gesture,
+ service_worker_host->active_version()->scope().GetOrigin(),
+ service_worker_host->active_version()->registration_id()));
+}
+
+void PushMessagingMessageFilter::OnPermissionStatusRequest(
+ int render_frame_id,
+ int service_worker_provider_id,
+ int permission_callback_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ServiceWorkerProviderHost* service_worker_host =
+ service_worker_context_->context()->GetProviderHost(
+ render_process_id_, service_worker_provider_id);
+
+ if (service_worker_host && service_worker_host->active_version()) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&PushMessagingMessageFilter::DoPermissionStatusRequest,
+ weak_factory_.GetWeakPtr(),
+ service_worker_host->active_version()->scope().GetOrigin(),
+ render_frame_id,
+ permission_callback_id));
+ } else {
+ Send(new PushMessagingMsg_PermissionStatusFailure(
+ render_frame_id, permission_callback_id));
+ }
+}
+
+void PushMessagingMessageFilter::DoRegister(
+ int render_frame_id,
+ int callbacks_id,
+ const std::string& sender_id,
+ bool user_gesture,
+ const GURL& origin,
+ int64 service_worker_registration_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!service()) {
+ PushRegistrationStatus status =
+ PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE;
+ Send(new PushMessagingMsg_RegisterError(
+ render_frame_id,
+ callbacks_id,
+ status));
+ RecordRegistrationStatus(status);
+ return;
+ }
+ service()->Register(origin,
+ service_worker_registration_id,
+ sender_id,
+ render_process_id_,
+ render_frame_id,
+ user_gesture,
+ base::Bind(&PushMessagingMessageFilter::DidRegister,
+ weak_factory_.GetWeakPtr(),
+ render_frame_id,
+ callbacks_id));
+}
+
+void PushMessagingMessageFilter::DoPermissionStatusRequest(
+ const GURL& requesting_origin,
+ int render_frame_id,
+ int callback_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ blink::WebPushPermissionStatus permission_value =
+ service()->GetPermissionStatus(
+ requesting_origin, render_process_id_, render_frame_id);
+
+ Send(new PushMessagingMsg_PermissionStatusResult(
+ render_frame_id, callback_id, permission_value));
+}
+
+void PushMessagingMessageFilter::DidRegister(
+ int render_frame_id,
+ int callbacks_id,
+ const GURL& push_endpoint,
+ const std::string& push_registration_id,
+ PushRegistrationStatus status) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (status == PUSH_REGISTRATION_STATUS_SUCCESS) {
+ Send(new PushMessagingMsg_RegisterSuccess(
+ render_frame_id, callbacks_id, push_endpoint, push_registration_id));
+ } else {
+ Send(new PushMessagingMsg_RegisterError(
+ render_frame_id, callbacks_id, status));
+ }
+ RecordRegistrationStatus(status);
+}
+
+PushMessagingService* PushMessagingMessageFilter::service() {
+ if (!service_) {
+ RenderProcessHost* process_host =
+ RenderProcessHost::FromID(render_process_id_);
+ if (!process_host)
+ return NULL;
+ service_ = process_host->GetBrowserContext()->GetPushMessagingService();
+ }
+ return service_;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/push_messaging/push_messaging_message_filter.h b/chromium/content/browser/push_messaging/push_messaging_message_filter.h
new file mode 100644
index 00000000000..4f9ebd9f994
--- /dev/null
+++ b/chromium/content/browser/push_messaging/push_messaging_message_filter.h
@@ -0,0 +1,76 @@
+// 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_PUSH_MESSAGING_PUSH_MESSAGING_MESSAGE_FILTER_H_
+#define CONTENT_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_MESSAGE_FILTER_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/browser_message_filter.h"
+#include "content/public/common/push_messaging_status.h"
+#include "url/gurl.h"
+
+class GURL;
+
+namespace content {
+
+class PushMessagingService;
+class ServiceWorkerContextWrapper;
+
+class PushMessagingMessageFilter : public BrowserMessageFilter {
+ public:
+ PushMessagingMessageFilter(
+ int render_process_id,
+ ServiceWorkerContextWrapper* service_worker_context);
+
+ private:
+ ~PushMessagingMessageFilter() override;
+
+ // BrowserMessageFilter implementation.
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ void OnRegister(int render_frame_id,
+ int callbacks_id,
+ const std::string& sender_id,
+ bool user_gesture,
+ int service_worker_provider_id);
+
+ void OnPermissionStatusRequest(int render_frame_id,
+ int service_worker_provider_id,
+ int permission_callback_id);
+
+ void DoRegister(int render_frame_id,
+ int callbacks_id,
+ const std::string& sender_id,
+ bool user_gesture,
+ const GURL& origin,
+ int64 service_worker_registration_id);
+
+ void DoPermissionStatusRequest(const GURL& requesting_origin,
+ int render_frame_id,
+ int callback_id);
+ void DidRegister(int render_frame_id,
+ int callbacks_id,
+ const GURL& push_endpoint,
+ const std::string& push_registration_id,
+ PushRegistrationStatus status);
+
+ PushMessagingService* service();
+
+ int render_process_id_;
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
+
+ // Owned by the content embedder's browsing context.
+ PushMessagingService* service_;
+
+ base::WeakPtrFactory<PushMessagingMessageFilter> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PushMessagingMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/push_messaging/push_messaging_router.cc b/chromium/content/browser/push_messaging/push_messaging_router.cc
new file mode 100644
index 00000000000..fc5218a8a2d
--- /dev/null
+++ b/chromium/content/browser/push_messaging/push_messaging_router.cc
@@ -0,0 +1,104 @@
+// 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/push_messaging/push_messaging_router.h"
+
+#include "base/bind.h"
+#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/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+
+namespace content {
+
+// static
+void PushMessagingRouter::DeliverMessage(
+ BrowserContext* browser_context,
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const std::string& data,
+ const DeliverMessageCallback& deliver_message_callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ StoragePartition* partition =
+ BrowserContext::GetStoragePartitionForSite(browser_context, origin);
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
+ static_cast<ServiceWorkerContextWrapper*>(
+ partition->GetServiceWorkerContext());
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&PushMessagingRouter::FindServiceWorkerRegistration,
+ origin,
+ service_worker_registration_id,
+ data,
+ deliver_message_callback,
+ service_worker_context));
+}
+
+// static
+void PushMessagingRouter::FindServiceWorkerRegistration(
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const std::string& data,
+ const DeliverMessageCallback& deliver_message_callback,
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Try to acquire the registration from storage. If it's already live we'll
+ // receive it right away. If not, it will be revived from storage.
+ service_worker_context->context()->storage()->FindRegistrationForId(
+ service_worker_registration_id,
+ origin,
+ base::Bind(&PushMessagingRouter::FindServiceWorkerRegistrationCallback,
+ data,
+ deliver_message_callback));
+}
+
+// static
+void PushMessagingRouter::FindServiceWorkerRegistrationCallback(
+ const std::string& data,
+ const DeliverMessageCallback& deliver_message_callback,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (service_worker_status == SERVICE_WORKER_OK) {
+ // Hold on to the service worker registration in the callback to keep it
+ // 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 =
+ base::Bind(&PushMessagingRouter::DeliverMessageEnd,
+ deliver_message_callback,
+ service_worker_registration);
+ service_worker_registration->active_version()->DispatchPushEvent(
+ dispatch_event_callback, data);
+ } else {
+ // TODO(mvanouwerkerk): UMA logging.
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(deliver_message_callback,
+ PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER));
+ }
+}
+
+// static
+void PushMessagingRouter::DeliverMessageEnd(
+ const DeliverMessageCallback& deliver_message_callback,
+ const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // TODO(mvanouwerkerk): UMA logging.
+ PushDeliveryStatus delivery_status =
+ service_worker_status == SERVICE_WORKER_OK
+ ? PUSH_DELIVERY_STATUS_SUCCESS
+ : PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR;
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(deliver_message_callback, delivery_status));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/push_messaging/push_messaging_router.h b/chromium/content/browser/push_messaging/push_messaging_router.h
new file mode 100644
index 00000000000..d9f25cc3868
--- /dev/null
+++ b/chromium/content/browser/push_messaging/push_messaging_router.h
@@ -0,0 +1,68 @@
+// 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_PUSH_MESSAGING_PUSH_MESSAGING_ROUTER_H_
+#define CONTENT_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_ROUTER_H_
+
+#include "base/memory/ref_counted.h"
+#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 "url/gurl.h"
+
+namespace content {
+
+class BrowserContext;
+class ServiceWorkerContextWrapper;
+class ServiceWorkerRegistration;
+
+class PushMessagingRouter {
+ public:
+ typedef base::Callback<void(PushDeliveryStatus)>
+ DeliverMessageCallback;
+
+ // Delivers a push message with |data| to the Service Worker identified by
+ // |origin| and |service_worker_registration_id|. Must be called on the UI
+ // thread.
+ static void DeliverMessage(
+ BrowserContext* browser_context,
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const std::string& data,
+ const DeliverMessageCallback& deliver_message_callback);
+
+ private:
+ // Attempts to find a Service Worker registration so that a push event can be
+ // dispatched. Must be called on the IO thread.
+ static void FindServiceWorkerRegistration(
+ const GURL& origin,
+ int64 service_worker_registration_id,
+ const std::string& data,
+ const DeliverMessageCallback& deliver_message_callback,
+ scoped_refptr<ServiceWorkerContextWrapper> service_worker_context);
+
+ // If a registration was successfully retrieved, dispatches a push event with
+ // |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 DeliverMessageCallback& deliver_message_callback,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration);
+
+ // Gets called asynchronously after the Service Worker has dispatched the push
+ // event. Must be called on the IO thread.
+ static void DeliverMessageEnd(
+ const DeliverMessageCallback& deliver_message_callback,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration,
+ ServiceWorkerStatusCode service_worker_status);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PushMessagingRouter);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_ROUTER_H_
diff --git a/chromium/content/browser/push_messaging_message_filter.cc b/chromium/content/browser/push_messaging_message_filter.cc
deleted file mode 100644
index 451c11253f6..00000000000
--- a/chromium/content/browser/push_messaging_message_filter.cc
+++ /dev/null
@@ -1,97 +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/push_messaging_message_filter.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "content/browser/renderer_host/render_process_host_impl.h"
-#include "content/common/push_messaging_messages.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/push_messaging_service.h"
-
-namespace content {
-
-PushMessagingMessageFilter::PushMessagingMessageFilter(int render_process_id)
- : BrowserMessageFilter(PushMessagingMsgStart),
- render_process_id_(render_process_id),
- service_(NULL),
- weak_factory_(this) {}
-
-PushMessagingMessageFilter::~PushMessagingMessageFilter() {}
-
-bool PushMessagingMessageFilter::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(PushMessagingMessageFilter, message)
- IPC_MESSAGE_HANDLER(PushMessagingHostMsg_Register, OnRegister)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void PushMessagingMessageFilter::OnRegister(int routing_id,
- int callbacks_id,
- const std::string& sender_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // TODO(mvanouwerkerk): Validate arguments?
- // TODO(mvanouwerkerk): A WebContentsObserver could avoid this PostTask
- // by receiving the IPC on the UI thread.
- BrowserThread::PostTask(BrowserThread::UI,
- FROM_HERE,
- base::Bind(&PushMessagingMessageFilter::DoRegister,
- weak_factory_.GetWeakPtr(),
- routing_id,
- callbacks_id,
- sender_id));
-}
-
-void PushMessagingMessageFilter::DoRegister(int routing_id,
- int callbacks_id,
- const std::string& sender_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!service()) {
- DidRegister(routing_id, callbacks_id, GURL(), "", false);
- return;
- }
- // TODO(mvanouwerkerk): Pass in a real app ID based on Service Worker ID.
- std::string app_id = "https://example.com 0";
- service_->Register(app_id,
- sender_id,
- base::Bind(&PushMessagingMessageFilter::DidRegister,
- weak_factory_.GetWeakPtr(),
- routing_id,
- callbacks_id));
-}
-
-void PushMessagingMessageFilter::DidRegister(int routing_id,
- int callbacks_id,
- const GURL& endpoint,
- const std::string& registration_id,
- bool success) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (success) {
- Send(new PushMessagingMsg_RegisterSuccess(routing_id,
- callbacks_id,
- endpoint,
- registration_id));
- } else {
- Send(new PushMessagingMsg_RegisterError(routing_id, callbacks_id));
- }
-}
-
-PushMessagingService* PushMessagingMessageFilter::service() {
- if (!service_) {
- RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
- RenderProcessHost::FromID(render_process_id_));
- if (!host)
- return NULL;
- service_ = host->GetBrowserContext()->GetPushMessagingService();
- }
- return service_;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/push_messaging_message_filter.h b/chromium/content/browser/push_messaging_message_filter.h
deleted file mode 100644
index abc02188873..00000000000
--- a/chromium/content/browser/push_messaging_message_filter.h
+++ /dev/null
@@ -1,54 +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_PUSH_MESSAGING_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_PUSH_MESSAGING_MESSAGE_FILTER_H_
-
-#include <string>
-
-#include "base/memory/weak_ptr.h"
-#include "content/public/browser/browser_message_filter.h"
-#include "url/gurl.h"
-
-namespace content {
-
-class PushMessagingService;
-
-class PushMessagingMessageFilter : public BrowserMessageFilter {
- public:
- explicit PushMessagingMessageFilter(int render_process_id);
-
- private:
- virtual ~PushMessagingMessageFilter();
-
- // BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- void OnRegister(int routing_id,
- int callbacks_id,
- const std::string& sender_id);
-
- void DoRegister(int routing_id,
- int callbacks_id,
- const std::string& sender_id);
-
- void DidRegister(int routing_id,
- int callbacks_id,
- const GURL& endpoint,
- const std::string& registration_id,
- bool success);
-
- PushMessagingService* service();
-
- int render_process_id_;
- PushMessagingService* service_; // Not owned.
-
- base::WeakPtrFactory<PushMessagingMessageFilter> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(PushMessagingMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_PUSH_MESSAGING_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/quota/mock_quota_manager.cc b/chromium/content/browser/quota/mock_quota_manager.cc
index 0343f39d01f..4884d0d7dfe 100644
--- a/chromium/content/browser/quota/mock_quota_manager.cc
+++ b/chromium/content/browser/quota/mock_quota_manager.cc
@@ -10,7 +10,7 @@
#include "base/single_thread_task_runner.h"
#include "url/gurl.h"
-using quota::kQuotaStatusOk;
+using storage::kQuotaStatusOk;
namespace content {
@@ -33,20 +33,23 @@ MockQuotaManager::StorageInfo::~StorageInfo() {}
MockQuotaManager::MockQuotaManager(
bool is_incognito,
const base::FilePath& profile_path,
- base::SingleThreadTaskRunner* io_thread,
- base::SequencedTaskRunner* db_thread,
- SpecialStoragePolicy* special_storage_policy)
- : QuotaManager(is_incognito, profile_path, io_thread, db_thread,
- special_storage_policy),
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_thread,
+ const scoped_refptr<base::SequencedTaskRunner>& db_thread,
+ const scoped_refptr<SpecialStoragePolicy>& special_storage_policy)
+ : QuotaManager(is_incognito,
+ profile_path,
+ io_thread,
+ db_thread,
+ special_storage_policy),
weak_factory_(this) {
}
void MockQuotaManager::GetUsageAndQuota(
const GURL& origin,
- quota::StorageType type,
+ storage::StorageType type,
const GetUsageAndQuotaCallback& callback) {
StorageInfo& info = usage_and_quota_map_[std::make_pair(origin, type)];
- callback.Run(quota::kQuotaStatusOk, info.usage, info.quota);
+ callback.Run(storage::kQuotaStatusOk, info.usage, info.quota);
}
void MockQuotaManager::SetQuota(const GURL& origin, StorageType type,
diff --git a/chromium/content/browser/quota/mock_quota_manager.h b/chromium/content/browser/quota/mock_quota_manager.h
index ded0b907904..a6bba10e985 100644
--- a/chromium/content/browser/quota/mock_quota_manager.h
+++ b/chromium/content/browser/quota/mock_quota_manager.h
@@ -11,19 +11,19 @@
#include <vector>
#include "base/memory/scoped_ptr.h"
+#include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_task.h"
+#include "storage/common/quota/quota_types.h"
#include "url/gurl.h"
-#include "webkit/browser/quota/quota_client.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/browser/quota/quota_task.h"
-#include "webkit/common/quota/quota_types.h"
-
-using quota::GetOriginsCallback;
-using quota::QuotaClient;
-using quota::QuotaManager;
-using quota::QuotaStatusCode;
-using quota::SpecialStoragePolicy;
-using quota::StatusCallback;
-using quota::StorageType;
+
+using storage::GetOriginsCallback;
+using storage::QuotaClient;
+using storage::QuotaManager;
+using storage::QuotaStatusCode;
+using storage::SpecialStoragePolicy;
+using storage::StatusCallback;
+using storage::StorageType;
namespace content {
@@ -40,28 +40,27 @@ namespace content {
// origin data stored in the profile.
class MockQuotaManager : public QuotaManager {
public:
- MockQuotaManager(bool is_incognito,
- const base::FilePath& profile_path,
- base::SingleThreadTaskRunner* io_thread,
- base::SequencedTaskRunner* db_thread,
- SpecialStoragePolicy* special_storage_policy);
+ MockQuotaManager(
+ bool is_incognito,
+ const base::FilePath& profile_path,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_thread,
+ const scoped_refptr<base::SequencedTaskRunner>& db_thread,
+ const scoped_refptr<SpecialStoragePolicy>& special_storage_policy);
// Overrides QuotaManager's implementation. The internal usage data is
// updated when MockQuotaManagerProxy::NotifyStorageModified() is
// called. The internal quota value can be updated by calling
// a helper method MockQuotaManagerProxy::SetQuota().
- virtual void GetUsageAndQuota(
- const GURL& origin,
- quota::StorageType type,
- const GetUsageAndQuotaCallback& callback) OVERRIDE;
+ void GetUsageAndQuota(const GURL& origin,
+ storage::StorageType type,
+ const GetUsageAndQuotaCallback& callback) override;
// Overrides QuotaManager's implementation with a canned implementation that
// allows clients to set up the origin database that should be queried. This
// method will only search through the origins added explicitly via AddOrigin.
- virtual void GetOriginsModifiedSince(
- StorageType type,
- base::Time modified_since,
- const GetOriginsCallback& callback) OVERRIDE;
+ void GetOriginsModifiedSince(StorageType type,
+ base::Time modified_since,
+ const GetOriginsCallback& callback) override;
// Removes an origin from the canned list of origins, but doesn't touch
// anything on disk. The caller must provide |quota_client_mask| which
@@ -69,10 +68,10 @@ class MockQuotaManager : public QuotaManager {
// origin as a bitmask built from QuotaClient::IDs. Setting the mask to
// QuotaClient::kAllClientsMask will remove all clients from the origin,
// regardless of type.
- virtual void DeleteOriginData(const GURL& origin,
- StorageType type,
- int quota_client_mask,
- const StatusCallback& callback) OVERRIDE;
+ void DeleteOriginData(const GURL& origin,
+ StorageType type,
+ int quota_client_mask,
+ const StatusCallback& callback) override;
// Helper method for updating internal quota info.
void SetQuota(const GURL& origin, StorageType type, int64 quota);
@@ -96,7 +95,7 @@ class MockQuotaManager : public QuotaManager {
QuotaClient::ID quota_client) const;
protected:
- virtual ~MockQuotaManager();
+ ~MockQuotaManager() override;
private:
friend class MockQuotaManagerProxy;
diff --git a/chromium/content/browser/quota/mock_quota_manager_proxy.cc b/chromium/content/browser/quota/mock_quota_manager_proxy.cc
index ddeef6a7b39..2e26e32c0f3 100644
--- a/chromium/content/browser/quota/mock_quota_manager_proxy.cc
+++ b/chromium/content/browser/quota/mock_quota_manager_proxy.cc
@@ -8,7 +8,7 @@
#include "base/single_thread_task_runner.h"
#include "url/gurl.h"
-using quota::kStorageTypeUnknown;
+using storage::kStorageTypeUnknown;
namespace content {
diff --git a/chromium/content/browser/quota/mock_quota_manager_proxy.h b/chromium/content/browser/quota/mock_quota_manager_proxy.h
index 9e8835fb08a..0f52f6dcc8e 100644
--- a/chromium/content/browser/quota/mock_quota_manager_proxy.h
+++ b/chromium/content/browser/quota/mock_quota_manager_proxy.h
@@ -6,12 +6,12 @@
#define CONTENT_BROWSER_QUOTA_MOCK_QUOTA_MANAGER_PROXY_H_
#include "content/browser/quota/mock_quota_manager.h"
+#include "storage/browser/quota/quota_client.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/quota/quota_types.h"
#include "url/gurl.h"
-#include "webkit/browser/quota/quota_client.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-#include "webkit/common/quota/quota_types.h"
-using quota::QuotaManagerProxy;
+using storage::QuotaManagerProxy;
namespace content {
@@ -23,39 +23,39 @@ class MockQuotaManagerProxy : public QuotaManagerProxy {
MockQuotaManagerProxy(MockQuotaManager* quota_manager,
base::SingleThreadTaskRunner* task_runner);
- virtual void RegisterClient(QuotaClient* client) OVERRIDE;
+ void RegisterClient(QuotaClient* client) override;
void SimulateQuotaManagerDestroyed();
// We don't mock them.
- virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
- virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
- virtual void SetUsageCacheEnabled(QuotaClient::ID client_id,
- const GURL& origin,
- StorageType type,
- bool enabled) OVERRIDE {}
- virtual void GetUsageAndQuota(
+ void NotifyOriginInUse(const GURL& origin) override {}
+ void NotifyOriginNoLongerInUse(const GURL& origin) override {}
+ void SetUsageCacheEnabled(QuotaClient::ID client_id,
+ const GURL& origin,
+ StorageType type,
+ bool enabled) override {}
+ void GetUsageAndQuota(
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().
// The also records the |origin| and |type| in last_notified_origin_ and
// last_notified_type_.
- virtual void NotifyStorageAccessed(QuotaClient::ID client_id,
- const GURL& origin,
- StorageType type) OVERRIDE;
+ void NotifyStorageAccessed(QuotaClient::ID client_id,
+ const GURL& origin,
+ StorageType type) override;
// Records the |origin|, |type| and |delta| as last_notified_origin_,
// last_notified_type_ and last_notified_delta_ respecitvely.
// If non-null MockQuotaManager is given to the constructor this also
// updates the manager's internal usage information.
- virtual void NotifyStorageModified(QuotaClient::ID client_id,
- const GURL& origin,
- StorageType type,
- int64 delta) OVERRIDE;
+ void NotifyStorageModified(QuotaClient::ID client_id,
+ const GURL& origin,
+ StorageType type,
+ int64 delta) override;
int notify_storage_accessed_count() const { return storage_accessed_count_; }
int notify_storage_modified_count() const { return storage_modified_count_; }
@@ -64,7 +64,7 @@ class MockQuotaManagerProxy : public QuotaManagerProxy {
int64 last_notified_delta() const { return last_notified_delta_; }
protected:
- virtual ~MockQuotaManagerProxy();
+ ~MockQuotaManagerProxy() override;
private:
MockQuotaManager* mock_manager() const {
diff --git a/chromium/content/browser/quota/mock_quota_manager_unittest.cc b/chromium/content/browser/quota/mock_quota_manager_unittest.cc
index e1885c4ff28..706ca821972 100644
--- a/chromium/content/browser/quota/mock_quota_manager_unittest.cc
+++ b/chromium/content/browser/quota/mock_quota_manager_unittest.cc
@@ -5,7 +5,7 @@
#include <set>
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
@@ -15,9 +15,9 @@
#include "content/public/test/mock_storage_client.h"
#include "testing/gtest/include/gtest/gtest.h"
-using quota::kQuotaStatusOk;
-using quota::kStorageTypePersistent;
-using quota::kStorageTypeTemporary;
+using storage::kQuotaStatusOk;
+using storage::kStorageTypePersistent;
+using storage::kStorageTypeTemporary;
namespace content {
@@ -42,7 +42,7 @@ class MockQuotaManagerTest : public testing::Test {
weak_factory_(this) {
}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
policy_ = new MockSpecialStoragePolicy;
manager_ = new MockQuotaManager(false /* is_incognito */,
@@ -52,7 +52,7 @@ class MockQuotaManagerTest : public testing::Test {
policy_.get());
}
- virtual void TearDown() {
+ void TearDown() override {
// Make sure the quota manager cleans up correctly.
manager_ = NULL;
base::RunLoop().RunUntilIdle();
@@ -223,4 +223,4 @@ TEST_F(MockQuotaManagerTest, ModifiedOrigins) {
EXPECT_EQ(0UL, origins().count(kOrigin1));
EXPECT_EQ(1UL, origins().count(kOrigin2));
}
-} // Namespace content
+} // namespace content
diff --git a/chromium/content/browser/quota/quota_backend_impl_unittest.cc b/chromium/content/browser/quota/quota_backend_impl_unittest.cc
index 201fab09375..2cf9f175774 100644
--- a/chromium/content/browser/quota/quota_backend_impl_unittest.cc
+++ b/chromium/content/browser/quota/quota_backend_impl_unittest.cc
@@ -2,23 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/quota/quota_backend_impl.h"
+#include "storage/browser/fileapi/quota/quota_backend_impl.h"
#include <string>
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
+#include "storage/browser/fileapi/file_system_usage_cache.h"
+#include "storage/browser/fileapi/obfuscated_file_util.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
#include "third_party/leveldatabase/src/include/leveldb/env.h"
-#include "webkit/browser/fileapi/file_system_usage_cache.h"
-#include "webkit/browser/fileapi/obfuscated_file_util.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-using fileapi::FileSystemUsageCache;
-using fileapi::ObfuscatedFileUtil;
-using fileapi::QuotaBackendImpl;
-using fileapi::SandboxFileSystemBackendDelegate;
+using storage::FileSystemUsageCache;
+using storage::ObfuscatedFileUtil;
+using storage::QuotaBackendImpl;
+using storage::SandboxFileSystemBackendDelegate;
namespace content {
@@ -38,7 +38,7 @@ bool DidReserveQuota(bool accepted,
return accepted;
}
-class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
+class MockQuotaManagerProxy : public storage::QuotaManagerProxy {
public:
MockQuotaManagerProxy()
: QuotaManagerProxy(NULL, NULL),
@@ -46,29 +46,27 @@ class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
usage_(0), quota_(0) {}
// We don't mock them.
- virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
- virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
- virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type,
- bool enabled) OVERRIDE {}
-
- virtual void NotifyStorageModified(
- quota::QuotaClient::ID client_id,
- const GURL& origin,
- quota::StorageType type,
- int64 delta) OVERRIDE {
+ void NotifyOriginInUse(const GURL& origin) override {}
+ void NotifyOriginNoLongerInUse(const GURL& origin) override {}
+ void SetUsageCacheEnabled(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type,
+ bool enabled) override {}
+
+ void NotifyStorageModified(storage::QuotaClient::ID client_id,
+ const GURL& origin,
+ storage::StorageType type,
+ int64 delta) override {
++storage_modified_count_;
usage_ += delta;
ASSERT_LE(usage_, quota_);
}
- virtual void GetUsageAndQuota(
- base::SequencedTaskRunner* original_task_runner,
- const GURL& origin,
- quota::StorageType type,
- const GetUsageAndQuotaCallback& callback) OVERRIDE {
- callback.Run(quota::kQuotaStatusOk, usage_, quota_);
+ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
+ const GURL& origin,
+ storage::StorageType type,
+ const GetUsageAndQuotaCallback& callback) override {
+ callback.Run(storage::kQuotaStatusOk, usage_, quota_);
}
int storage_modified_count() { return storage_modified_count_; }
@@ -77,7 +75,7 @@ class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
void set_quota(int64 quota) { quota_ = quota; }
protected:
- virtual ~MockQuotaManagerProxy() {}
+ ~MockQuotaManagerProxy() override {}
private:
int storage_modified_count_;
@@ -95,7 +93,7 @@ class QuotaBackendImplTest : public testing::Test {
: file_system_usage_cache_(file_task_runner()),
quota_manager_proxy_(new MockQuotaManagerProxy) {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
file_util_.reset(ObfuscatedFileUtil::CreateForTesting(
@@ -106,7 +104,7 @@ class QuotaBackendImplTest : public testing::Test {
quota_manager_proxy_.get()));
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
backend_.reset();
quota_manager_proxy_ = NULL;
file_util_.reset();
@@ -115,7 +113,7 @@ class QuotaBackendImplTest : public testing::Test {
protected:
void InitializeForOriginAndType(const GURL& origin,
- fileapi::FileSystemType type) {
+ storage::FileSystemType type) {
ASSERT_TRUE(file_util_->InitOriginDatabase(origin, true /* create */));
ASSERT_TRUE(file_util_->origin_database_ != NULL);
@@ -135,7 +133,7 @@ class QuotaBackendImplTest : public testing::Test {
}
base::FilePath GetUsageCachePath(const GURL& origin,
- fileapi::FileSystemType type) {
+ storage::FileSystemType type) {
base::FilePath path;
base::File::Error error =
backend_->GetUsageCachePath(origin, type, &path);
@@ -157,7 +155,7 @@ class QuotaBackendImplTest : public testing::Test {
};
TEST_F(QuotaBackendImplTest, ReserveQuota_Basic) {
- fileapi::FileSystemType type = fileapi::kFileSystemTypeTemporary;
+ storage::FileSystemType type = storage::kFileSystemTypeTemporary;
InitializeForOriginAndType(GURL(kOrigin), type);
quota_manager_proxy_->set_quota(10000);
@@ -183,7 +181,7 @@ TEST_F(QuotaBackendImplTest, ReserveQuota_Basic) {
}
TEST_F(QuotaBackendImplTest, ReserveQuota_NoSpace) {
- fileapi::FileSystemType type = fileapi::kFileSystemTypeTemporary;
+ storage::FileSystemType type = storage::kFileSystemTypeTemporary;
InitializeForOriginAndType(GURL(kOrigin), type);
quota_manager_proxy_->set_quota(100);
@@ -201,7 +199,7 @@ TEST_F(QuotaBackendImplTest, ReserveQuota_NoSpace) {
}
TEST_F(QuotaBackendImplTest, ReserveQuota_Revert) {
- fileapi::FileSystemType type = fileapi::kFileSystemTypeTemporary;
+ storage::FileSystemType type = storage::kFileSystemTypeTemporary;
InitializeForOriginAndType(GURL(kOrigin), type);
quota_manager_proxy_->set_quota(10000);
@@ -219,7 +217,7 @@ TEST_F(QuotaBackendImplTest, ReserveQuota_Revert) {
}
TEST_F(QuotaBackendImplTest, ReleaseReservedQuota) {
- fileapi::FileSystemType type = fileapi::kFileSystemTypeTemporary;
+ storage::FileSystemType type = storage::kFileSystemTypeTemporary;
InitializeForOriginAndType(GURL(kOrigin), type);
const int64 kInitialUsage = 2000;
quota_manager_proxy_->set_usage(kInitialUsage);
@@ -233,7 +231,7 @@ TEST_F(QuotaBackendImplTest, ReleaseReservedQuota) {
}
TEST_F(QuotaBackendImplTest, CommitQuotaUsage) {
- fileapi::FileSystemType type = fileapi::kFileSystemTypeTemporary;
+ storage::FileSystemType type = storage::kFileSystemTypeTemporary;
InitializeForOriginAndType(GURL(kOrigin), type);
quota_manager_proxy_->set_quota(10000);
base::FilePath path = GetUsageCachePath(GURL(kOrigin), type);
@@ -256,7 +254,7 @@ TEST_F(QuotaBackendImplTest, CommitQuotaUsage) {
}
TEST_F(QuotaBackendImplTest, DirtyCount) {
- fileapi::FileSystemType type = fileapi::kFileSystemTypeTemporary;
+ storage::FileSystemType type = storage::kFileSystemTypeTemporary;
InitializeForOriginAndType(GURL(kOrigin), type);
base::FilePath path = GetUsageCachePath(GURL(kOrigin), type);
diff --git a/chromium/content/browser/quota/quota_database_unittest.cc b/chromium/content/browser/quota/quota_database_unittest.cc
index 1415ed53f28..5b5b00e1454 100644
--- a/chromium/content/browser/quota/quota_database_unittest.cc
+++ b/chromium/content/browser/quota/quota_database_unittest.cc
@@ -8,7 +8,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "content/public/test/mock_special_storage_policy.h"
@@ -16,13 +16,13 @@
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
+#include "storage/browser/quota/quota_database.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/quota/quota_database.h"
-using quota::kStorageTypePersistent;
-using quota::kStorageTypeTemporary;
-using quota::QuotaDatabase;
+using storage::kStorageTypePersistent;
+using storage::kStorageTypeTemporary;
+using storage::QuotaDatabase;
namespace content {
namespace {
@@ -55,14 +55,14 @@ class QuotaDatabaseTest : public testing::Test {
QuotaTableEntry("c", kStorageTypePersistent, 3),
};
- CreateV2Database(kDbFile, entries, ARRAYSIZE_UNSAFE(entries));
+ CreateV2Database(kDbFile, entries, arraysize(entries));
QuotaDatabase db(kDbFile);
EXPECT_TRUE(db.LazyOpen(true));
EXPECT_TRUE(db.db_.get());
typedef EntryVerifier<QuotaTableEntry> Verifier;
- Verifier verifier(entries, entries + ARRAYSIZE_UNSAFE(entries));
+ Verifier verifier(entries, entries + arraysize(entries));
EXPECT_TRUE(db.DumpQuotaTable(
base::Bind(&Verifier::Run, base::Unretained(&verifier))));
EXPECT_TRUE(verifier.table.empty());
@@ -287,7 +287,7 @@ class QuotaDatabaseTest : public testing::Test {
GURL("http://a/"),
GURL("http://b/"),
GURL("http://c/") };
- std::set<GURL> origins(kOrigins, kOrigins + ARRAYSIZE_UNSAFE(kOrigins));
+ std::set<GURL> origins(kOrigins, kOrigins + arraysize(kOrigins));
EXPECT_TRUE(db.RegisterInitialOriginInfo(origins, kStorageTypeTemporary));
@@ -336,7 +336,7 @@ class QuotaDatabaseTest : public testing::Test {
QuotaTableEntry("http://gle/", kStorageTypePersistent, 3)
};
QuotaTableEntry* begin = kTableEntries;
- QuotaTableEntry* end = kTableEntries + ARRAYSIZE_UNSAFE(kTableEntries);
+ QuotaTableEntry* end = kTableEntries + arraysize(kTableEntries);
QuotaDatabase db(kDbFile);
EXPECT_TRUE(db.LazyOpen(true));
@@ -359,7 +359,7 @@ class QuotaDatabaseTest : public testing::Test {
Entry(GURL("http://gle/"), kStorageTypeTemporary, 1, now, now),
};
Entry* begin = kTableEntries;
- Entry* end = kTableEntries + ARRAYSIZE_UNSAFE(kTableEntries);
+ Entry* end = kTableEntries + arraysize(kTableEntries);
QuotaDatabase db(kDbFile);
EXPECT_TRUE(db.LazyOpen(true));
@@ -467,8 +467,8 @@ class QuotaDatabaseTest : public testing::Test {
EXPECT_TRUE(QuotaDatabase::CreateSchema(
db.get(), meta_table.get(),
kCurrentVersion, kCompatibleVersion,
- kTables, ARRAYSIZE_UNSAFE(kTables),
- kIndexes, ARRAYSIZE_UNSAFE(kIndexes)));
+ kTables, arraysize(kTables),
+ kIndexes, arraysize(kIndexes)));
// V2 and V3 QuotaTable are compatible, so we can simply use
// AssignQuotaTable to poplulate v2 database here.
diff --git a/chromium/content/browser/quota/quota_manager_unittest.cc b/chromium/content/browser/quota/quota_manager_unittest.cc
index 5baa025e859..1337bc389f4 100644
--- a/chromium/content/browser/quota/quota_manager_unittest.cc
+++ b/chromium/content/browser/quota/quota_manager_unittest.cc
@@ -8,7 +8,7 @@
#include <vector>
#include "base/bind.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
@@ -19,29 +19,29 @@
#include "base/time/time.h"
#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/mock_storage_client.h"
+#include "storage/browser/quota/quota_database.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#include "webkit/browser/quota/quota_database.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
using base::MessageLoopProxy;
-using quota::kQuotaErrorAbort;
-using quota::kQuotaErrorInvalidModification;
-using quota::kQuotaErrorNotSupported;
-using quota::kQuotaStatusOk;
-using quota::kQuotaStatusUnknown;
-using quota::kStorageTypePersistent;
-using quota::kStorageTypeSyncable;
-using quota::kStorageTypeTemporary;
-using quota::kStorageTypeUnknown;
-using quota::QuotaClient;
-using quota::QuotaManager;
-using quota::QuotaStatusCode;
-using quota::StorageType;
-using quota::UsageAndQuota;
-using quota::UsageInfo;
-using quota::UsageInfoEntries;
+using storage::kQuotaErrorAbort;
+using storage::kQuotaErrorInvalidModification;
+using storage::kQuotaErrorNotSupported;
+using storage::kQuotaStatusOk;
+using storage::kQuotaStatusUnknown;
+using storage::kStorageTypePersistent;
+using storage::kStorageTypeSyncable;
+using storage::kStorageTypeTemporary;
+using storage::kStorageTypeUnknown;
+using storage::QuotaClient;
+using storage::QuotaManager;
+using storage::QuotaStatusCode;
+using storage::StorageType;
+using storage::UsageAndQuota;
+using storage::UsageInfo;
+using storage::UsageInfoEntries;
namespace content {
@@ -78,13 +78,13 @@ class QuotaManagerTest : public testing::Test {
weak_factory_(this) {
}
- virtual void SetUp() {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
mock_special_storage_policy_ = new MockSpecialStoragePolicy;
ResetQuotaManager(false /* is_incognito */);
}
- virtual void TearDown() {
+ void TearDown() override {
// Make sure the quota manager cleans up correctly.
quota_manager_ = NULL;
base::RunLoop().RunUntilIdle();
@@ -469,9 +469,9 @@ TEST_F(QuotaManagerTest, GetUsageInfo) {
{ "http://bar.com/", kPerm, 40 },
{ "http://example.com/", kPerm, 40 },
};
- RegisterClient(CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ RegisterClient(CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem));
- RegisterClient(CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ RegisterClient(CreateClient(kData2, arraysize(kData2),
QuotaClient::kDatabase));
GetUsageInfo();
@@ -500,7 +500,7 @@ TEST_F(QuotaManagerTest, GetUsageAndQuota_Simple) {
{ "http://foo.com/", kTemp, 10 },
{ "http://foo.com/", kPerm, 80 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kPerm);
@@ -593,7 +593,7 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_MultiOrigins) {
{ "http://baz.com/", kTemp, 30 },
{ "http://foo.com/", kPerm, 40 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
// This time explicitly sets a temporary global quota.
@@ -636,9 +636,9 @@ TEST_F(QuotaManagerTest, GetUsage_MultipleClients) {
};
mock_special_storage_policy()->AddUnlimited(GURL("http://unlimited/"));
mock_special_storage_policy()->GrantQueryDiskSize(GURL("http://installed/"));
- RegisterClient(CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ RegisterClient(CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem));
- RegisterClient(CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ RegisterClient(CreateClient(kData2, arraysize(kData2),
QuotaClient::kDatabase));
const int64 kTempQuotaBase =
@@ -701,7 +701,7 @@ void QuotaManagerTest::GetUsage_WithModifyTestBody(const StorageType type) {
{ "http://foo.com/", type, 10 },
{ "http://foo.com:1/", type, 20 },
};
- MockStorageClient* client = CreateClient(data, ARRAYSIZE_UNSAFE(data),
+ MockStorageClient* client = CreateClient(data, arraysize(data),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -743,7 +743,7 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_WithAdditionalTasks) {
{ "http://bar.com/", kTemp, 13 },
{ "http://foo.com/", kPerm, 40 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
SetTemporaryGlobalQuota(100);
base::RunLoop().RunUntilIdle();
@@ -777,7 +777,7 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_NukeManager) {
{ "http://bar.com/", kTemp, 13 },
{ "http://foo.com/", kPerm, 40 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
SetTemporaryGlobalQuota(100);
base::RunLoop().RunUntilIdle();
@@ -804,7 +804,7 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_Overbudget) {
{ "http://usage10/", kTemp, 10 },
{ "http://usage200/", kTemp, 200 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
SetTemporaryGlobalQuota(100);
base::RunLoop().RunUntilIdle();
@@ -837,7 +837,7 @@ TEST_F(QuotaManagerTest, GetTemporaryUsageAndQuota_Unlimited) {
{ "http://unlimited/", kTemp, 4000 },
};
mock_special_storage_policy()->AddUnlimited(GURL("http://unlimited/"));
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1065,7 +1065,7 @@ TEST_F(QuotaManagerTest, GetPersistentUsageAndQuota_MultiOrigins) {
{ "http://baz.com/", kPerm, 30 },
{ "http://foo.com/", kTemp, 40 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
SetPersistentHostQuota("foo.com", 100);
@@ -1087,7 +1087,7 @@ TEST_F(QuotaManagerTest, GetPersistentUsageAndQuota_WithAdditionalTasks) {
{ "http://bar.com/", kPerm, 13 },
{ "http://foo.com/", kTemp, 40 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
SetPersistentHostQuota("foo.com", 100);
@@ -1117,7 +1117,7 @@ TEST_F(QuotaManagerTest, GetPersistentUsageAndQuota_NukeManager) {
{ "http://bar.com/", kPerm, 13 },
{ "http://foo.com/", kTemp, 40 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
SetPersistentHostQuota("foo.com", 100);
@@ -1142,7 +1142,7 @@ TEST_F(QuotaManagerTest, GetUsage_Simple) {
{ "http://bar.com:1/", kPerm, 600000 },
{ "http://foo.com/", kTemp, 7000000 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
GetGlobalUsage(kPerm);
@@ -1175,7 +1175,7 @@ TEST_F(QuotaManagerTest, GetUsage_WithModification) {
{ "http://foo.com/", kTemp, 7000000 },
};
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1224,7 +1224,7 @@ TEST_F(QuotaManagerTest, GetUsage_WithDeleteOrigin) {
{ "http://foo.com/", kPerm, 300 },
{ "http://bar.com/", kTemp, 4000 },
};
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1279,9 +1279,9 @@ TEST_F(QuotaManagerTest, EvictOriginData) {
{ "https://foo.com/", kTemp, 80 },
{ "http://bar.com/", kTemp, 9 },
};
- MockStorageClient* client1 = CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ MockStorageClient* client1 = CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem);
- MockStorageClient* client2 = CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ MockStorageClient* client2 = CreateClient(kData2, arraysize(kData2),
QuotaClient::kDatabase);
RegisterClient(client1);
RegisterClient(client2);
@@ -1298,10 +1298,10 @@ TEST_F(QuotaManagerTest, EvictOriginData) {
base::RunLoop().RunUntilIdle();
int64 predelete_host_pers = usage();
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kData1); ++i)
+ for (size_t i = 0; i < arraysize(kData1); ++i)
quota_manager()->NotifyStorageAccessed(QuotaClient::kUnknown,
GURL(kData1[i].origin), kData1[i].type);
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kData2); ++i)
+ for (size_t i = 0; i < arraysize(kData2); ++i)
quota_manager()->NotifyStorageAccessed(QuotaClient::kUnknown,
GURL(kData2[i].origin), kData2[i].type);
base::RunLoop().RunUntilIdle();
@@ -1341,7 +1341,7 @@ TEST_F(QuotaManagerTest, EvictOriginDataWithDeletionError) {
{ "http://bar.com/", kTemp, 4000 },
};
static const int kNumberOfTemporaryOrigins = 3;
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1357,7 +1357,7 @@ TEST_F(QuotaManagerTest, EvictOriginDataWithDeletionError) {
base::RunLoop().RunUntilIdle();
int64 predelete_host_pers = usage();
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kData); ++i)
+ for (size_t i = 0; i < arraysize(kData); ++i)
NotifyStorageAccessed(client, GURL(kData[i].origin), kData[i].type);
base::RunLoop().RunUntilIdle();
@@ -1427,7 +1427,7 @@ TEST_F(QuotaManagerTest, GetUsageAndQuotaForEviction) {
};
mock_special_storage_policy()->AddUnlimited(GURL("http://unlimited/"));
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1446,7 +1446,7 @@ TEST_F(QuotaManagerTest, DeleteHostDataSimple) {
static const MockOriginData kData[] = {
{ "http://foo.com/", kTemp, 1 },
};
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1509,9 +1509,9 @@ TEST_F(QuotaManagerTest, DeleteHostDataMultiple) {
{ "https://foo.com/", kTemp, 80 },
{ "http://bar.com/", kTemp, 9 },
};
- MockStorageClient* client1 = CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ MockStorageClient* client1 = CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem);
- MockStorageClient* client2 = CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ MockStorageClient* client2 = CreateClient(kData2, arraysize(kData2),
QuotaClient::kDatabase);
RegisterClient(client1);
RegisterClient(client2);
@@ -1597,9 +1597,9 @@ TEST_F(QuotaManagerTest, DeleteOriginDataMultiple) {
{ "https://foo.com/", kTemp, 80 },
{ "http://bar.com/", kTemp, 9 },
};
- MockStorageClient* client1 = CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ MockStorageClient* client1 = CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem);
- MockStorageClient* client2 = CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ MockStorageClient* client2 = CreateClient(kData2, arraysize(kData2),
QuotaClient::kDatabase);
RegisterClient(client1);
RegisterClient(client2);
@@ -1624,10 +1624,10 @@ TEST_F(QuotaManagerTest, DeleteOriginDataMultiple) {
base::RunLoop().RunUntilIdle();
const int64 predelete_bar_pers = usage();
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kData1); ++i)
+ for (size_t i = 0; i < arraysize(kData1); ++i)
quota_manager()->NotifyStorageAccessed(QuotaClient::kUnknown,
GURL(kData1[i].origin), kData1[i].type);
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kData2); ++i)
+ for (size_t i = 0; i < arraysize(kData2); ++i)
quota_manager()->NotifyStorageAccessed(QuotaClient::kUnknown,
GURL(kData2[i].origin), kData2[i].type);
base::RunLoop().RunUntilIdle();
@@ -1681,7 +1681,7 @@ TEST_F(QuotaManagerTest, GetCachedOrigins) {
{ "http://b.com/", kPerm, 300 },
{ "http://c.com/", kTemp, 4000 },
};
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1711,7 +1711,7 @@ TEST_F(QuotaManagerTest, GetCachedOrigins) {
GetCachedOrigins(kTemp, &origins);
EXPECT_EQ(3U, origins.size());
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kData); ++i) {
+ for (size_t i = 0; i < arraysize(kData); ++i) {
if (kData[i].type == kTemp)
EXPECT_TRUE(origins.find(GURL(kData[i].origin)) != origins.end());
}
@@ -1725,7 +1725,7 @@ TEST_F(QuotaManagerTest, NotifyAndLRUOrigin) {
{ "http://b.com/", kPerm, 0 }, // persistent
{ "http://c.com/", kTemp, 0 },
};
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1765,7 +1765,7 @@ TEST_F(QuotaManagerTest, GetLRUOriginWithOriginInUse) {
{ "http://b.com/", kPerm, 0 }, // persistent
{ "http://c.com/", kTemp, 0 },
};
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1820,7 +1820,7 @@ TEST_F(QuotaManagerTest, GetOriginsModifiedSince) {
{ "http://b.com/", kPerm, 0 }, // persistent
{ "http://c.com/", kTemp, 0 },
};
- MockStorageClient* client = CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ MockStorageClient* client = CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem);
RegisterClient(client);
@@ -1842,7 +1842,7 @@ TEST_F(QuotaManagerTest, GetOriginsModifiedSince) {
base::RunLoop().RunUntilIdle();
EXPECT_EQ(4U, modified_origins().size());
EXPECT_EQ(modified_origins_type(), kTemp);
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kData); ++i) {
+ for (size_t i = 0; i < arraysize(kData); ++i) {
if (kData[i].type == kTemp)
EXPECT_EQ(1U, modified_origins().count(GURL(kData[i].origin)));
}
@@ -1879,8 +1879,7 @@ TEST_F(QuotaManagerTest, DumpQuotaTable) {
QuotaTableEntry("example2.com", kPerm, 20),
QuotaTableEntry("example3.com", kPerm, 300),
};
- std::set<QuotaTableEntry> entries
- (kEntries, kEntries + ARRAYSIZE_UNSAFE(kEntries));
+ std::set<QuotaTableEntry> entries(kEntries, kEntries + arraysize(kEntries));
typedef QuotaTableEntries::const_iterator iterator;
for (iterator itr(quota_entries().begin()), end(quota_entries().end());
@@ -1919,8 +1918,7 @@ TEST_F(QuotaManagerTest, DumpOriginInfoTable) {
make_pair(make_pair(GURL("http://example.com/"), kTemp), 1),
make_pair(make_pair(GURL("http://example.com/"), kPerm), 2),
};
- std::set<Entry> entries
- (kEntries, kEntries + ARRAYSIZE_UNSAFE(kEntries));
+ std::set<Entry> entries(kEntries, kEntries + arraysize(kEntries));
typedef OriginInfoTableEntries::const_iterator iterator;
for (iterator itr(origin_info_entries().begin()),
@@ -1961,13 +1959,13 @@ TEST_F(QuotaManagerTest, DeleteSpecificClientTypeSingleOrigin) {
static const MockOriginData kData4[] = {
{ "http://foo.com/", kTemp, 8 },
};
- MockStorageClient* client1 = CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ MockStorageClient* client1 = CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem);
- MockStorageClient* client2 = CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ MockStorageClient* client2 = CreateClient(kData2, arraysize(kData2),
QuotaClient::kAppcache);
- MockStorageClient* client3 = CreateClient(kData3, ARRAYSIZE_UNSAFE(kData3),
+ MockStorageClient* client3 = CreateClient(kData3, arraysize(kData3),
QuotaClient::kDatabase);
- MockStorageClient* client4 = CreateClient(kData4, ARRAYSIZE_UNSAFE(kData4),
+ MockStorageClient* client4 = CreateClient(kData4, arraysize(kData4),
QuotaClient::kIndexedDatabase);
RegisterClient(client1);
RegisterClient(client2);
@@ -2017,13 +2015,13 @@ TEST_F(QuotaManagerTest, DeleteSpecificClientTypeSingleHost) {
static const MockOriginData kData4[] = {
{ "http://foo.com:4444/", kTemp, 8 },
};
- MockStorageClient* client1 = CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ MockStorageClient* client1 = CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem);
- MockStorageClient* client2 = CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ MockStorageClient* client2 = CreateClient(kData2, arraysize(kData2),
QuotaClient::kAppcache);
- MockStorageClient* client3 = CreateClient(kData3, ARRAYSIZE_UNSAFE(kData3),
+ MockStorageClient* client3 = CreateClient(kData3, arraysize(kData3),
QuotaClient::kDatabase);
- MockStorageClient* client4 = CreateClient(kData4, ARRAYSIZE_UNSAFE(kData4),
+ MockStorageClient* client4 = CreateClient(kData4, arraysize(kData4),
QuotaClient::kIndexedDatabase);
RegisterClient(client1);
RegisterClient(client2);
@@ -2072,13 +2070,13 @@ TEST_F(QuotaManagerTest, DeleteMultipleClientTypesSingleOrigin) {
static const MockOriginData kData4[] = {
{ "http://foo.com/", kTemp, 8 },
};
- MockStorageClient* client1 = CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ MockStorageClient* client1 = CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem);
- MockStorageClient* client2 = CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ MockStorageClient* client2 = CreateClient(kData2, arraysize(kData2),
QuotaClient::kAppcache);
- MockStorageClient* client3 = CreateClient(kData3, ARRAYSIZE_UNSAFE(kData3),
+ MockStorageClient* client3 = CreateClient(kData3, arraysize(kData3),
QuotaClient::kDatabase);
- MockStorageClient* client4 = CreateClient(kData4, ARRAYSIZE_UNSAFE(kData4),
+ MockStorageClient* client4 = CreateClient(kData4, arraysize(kData4),
QuotaClient::kIndexedDatabase);
RegisterClient(client1);
RegisterClient(client2);
@@ -2117,13 +2115,13 @@ TEST_F(QuotaManagerTest, DeleteMultipleClientTypesSingleHost) {
static const MockOriginData kData4[] = {
{ "http://foo.com:4444/", kTemp, 8 },
};
- MockStorageClient* client1 = CreateClient(kData1, ARRAYSIZE_UNSAFE(kData1),
+ MockStorageClient* client1 = CreateClient(kData1, arraysize(kData1),
QuotaClient::kFileSystem);
- MockStorageClient* client2 = CreateClient(kData2, ARRAYSIZE_UNSAFE(kData2),
+ MockStorageClient* client2 = CreateClient(kData2, arraysize(kData2),
QuotaClient::kAppcache);
- MockStorageClient* client3 = CreateClient(kData3, ARRAYSIZE_UNSAFE(kData3),
+ MockStorageClient* client3 = CreateClient(kData3, arraysize(kData3),
QuotaClient::kDatabase);
- MockStorageClient* client4 = CreateClient(kData4, ARRAYSIZE_UNSAFE(kData4),
+ MockStorageClient* client4 = CreateClient(kData4, arraysize(kData4),
QuotaClient::kIndexedDatabase);
RegisterClient(client1);
RegisterClient(client2);
@@ -2156,7 +2154,7 @@ TEST_F(QuotaManagerTest, GetUsageAndQuota_Incognito) {
{ "http://foo.com/", kTemp, 10 },
{ "http://foo.com/", kPerm, 80 },
};
- RegisterClient(CreateClient(kData, ARRAYSIZE_UNSAFE(kData),
+ RegisterClient(CreateClient(kData, arraysize(kData),
QuotaClient::kFileSystem));
GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kPerm);
diff --git a/chromium/content/browser/quota/quota_reservation_manager_unittest.cc b/chromium/content/browser/quota/quota_reservation_manager_unittest.cc
index 84caddcd0ed..61de3d574e8 100644
--- a/chromium/content/browser/quota/quota_reservation_manager_unittest.cc
+++ b/chromium/content/browser/quota/quota_reservation_manager_unittest.cc
@@ -2,30 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "webkit/browser/fileapi/quota/quota_reservation_manager.h"
+#include "storage/browser/fileapi/quota/quota_reservation_manager.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/file_util.h"
#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "storage/browser/fileapi/quota/open_file_handle.h"
+#include "storage/browser/fileapi/quota/quota_reservation.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/quota/open_file_handle.h"
-#include "webkit/browser/fileapi/quota/quota_reservation.h"
-using fileapi::kFileSystemTypeTemporary;
-using fileapi::OpenFileHandle;
-using fileapi::QuotaReservation;
-using fileapi::QuotaReservationManager;
+using storage::kFileSystemTypeTemporary;
+using storage::OpenFileHandle;
+using storage::QuotaReservation;
+using storage::QuotaReservationManager;
namespace content {
namespace {
const char kOrigin[] = "http://example.com";
-const fileapi::FileSystemType kType = kFileSystemTypeTemporary;
+const storage::FileSystemType kType = kFileSystemTypeTemporary;
const int64 kInitialFileSize = 1;
typedef QuotaReservationManager::ReserveQuotaCallback ReserveQuotaCallback;
@@ -47,12 +47,12 @@ class FakeBackend : public QuotaReservationManager::QuotaBackend {
FakeBackend()
: on_memory_usage_(kInitialFileSize),
on_disk_usage_(kInitialFileSize) {}
- virtual ~FakeBackend() {}
+ ~FakeBackend() override {}
- virtual void ReserveQuota(const GURL& origin,
- fileapi::FileSystemType type,
- int64 delta,
- const ReserveQuotaCallback& callback) OVERRIDE {
+ void ReserveQuota(const GURL& origin,
+ storage::FileSystemType type,
+ int64 delta,
+ const ReserveQuotaCallback& callback) override {
EXPECT_EQ(GURL(kOrigin), origin);
EXPECT_EQ(kType, type);
on_memory_usage_ += delta;
@@ -61,28 +61,28 @@ class FakeBackend : public QuotaReservationManager::QuotaBackend {
base::Bind(base::IgnoreResult(callback), base::File::FILE_OK, delta));
}
- virtual void ReleaseReservedQuota(const GURL& origin,
- fileapi::FileSystemType type,
- int64 size) OVERRIDE {
+ void ReleaseReservedQuota(const GURL& origin,
+ storage::FileSystemType type,
+ int64 size) override {
EXPECT_LE(0, size);
EXPECT_EQ(GURL(kOrigin), origin);
EXPECT_EQ(kType, type);
on_memory_usage_ -= size;
}
- virtual void CommitQuotaUsage(const GURL& origin,
- fileapi::FileSystemType type,
- int64 delta) OVERRIDE {
+ void CommitQuotaUsage(const GURL& origin,
+ storage::FileSystemType type,
+ int64 delta) override {
EXPECT_EQ(GURL(kOrigin), origin);
EXPECT_EQ(kType, type);
on_disk_usage_ += delta;
on_memory_usage_ += delta;
}
- virtual void IncrementDirtyCount(const GURL& origin,
- fileapi::FileSystemType type) OVERRIDE {}
- virtual void DecrementDirtyCount(const GURL& origin,
- fileapi::FileSystemType type) OVERRIDE {}
+ void IncrementDirtyCount(const GURL& origin,
+ storage::FileSystemType type) override {}
+ void DecrementDirtyCount(const GURL& origin,
+ storage::FileSystemType type) override {}
int64 on_memory_usage() { return on_memory_usage_; }
int64 on_disk_usage() { return on_disk_usage_; }
@@ -180,9 +180,9 @@ void RefreshReservation(QuotaReservation* reservation, int64 size) {
class QuotaReservationManagerTest : public testing::Test {
public:
QuotaReservationManagerTest() {}
- virtual ~QuotaReservationManagerTest() {}
+ ~QuotaReservationManagerTest() override {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(work_dir_.CreateUniqueTempDir());
file_path_ = work_dir_.path().Append(FILE_PATH_LITERAL("hoge"));
SetFileSize(file_path_, kInitialFileSize);
@@ -191,9 +191,7 @@ class QuotaReservationManagerTest : public testing::Test {
reservation_manager_.reset(new QuotaReservationManager(backend.Pass()));
}
- virtual void TearDown() OVERRIDE {
- reservation_manager_.reset();
- }
+ void TearDown() override { reservation_manager_.reset(); }
FakeBackend* fake_backend() {
return static_cast<FakeBackend*>(reservation_manager_->backend_.get());
@@ -294,12 +292,12 @@ TEST_F(QuotaReservationManagerTest, MultipleWriter) {
TEST_F(QuotaReservationManagerTest, MultipleClient) {
scoped_refptr<QuotaReservation> reservation1 =
reservation_manager()->CreateReservation(GURL(kOrigin), kType);
- RefreshReservation(reservation1, 10);
+ RefreshReservation(reservation1.get(), 10);
int64 cached_reserved_quota1 = reservation1->remaining_quota();
scoped_refptr<QuotaReservation> reservation2 =
reservation_manager()->CreateReservation(GURL(kOrigin), kType);
- RefreshReservation(reservation2, 20);
+ RefreshReservation(reservation2.get(), 20);
int64 cached_reserved_quota2 = reservation2->remaining_quota();
scoped_ptr<FakeWriter> writer1(
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 a9d93f6bb9d..6c00c0f877f 100644
--- a/chromium/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
+++ b/chromium/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
@@ -13,13 +13,13 @@
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "content/public/test/mock_storage_client.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_temporary_storage_evictor.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/browser/quota/quota_temporary_storage_evictor.h"
-using quota::QuotaTemporaryStorageEvictor;
-using quota::StorageType;
-using quota::UsageAndQuota;
+using storage::QuotaTemporaryStorageEvictor;
+using storage::StorageType;
+using storage::UsageAndQuota;
namespace content {
@@ -27,7 +27,7 @@ class QuotaTemporaryStorageEvictorTest;
namespace {
-class MockQuotaEvictionHandler : public quota::QuotaEvictionHandler {
+class MockQuotaEvictionHandler : public storage::QuotaEvictionHandler {
public:
explicit MockQuotaEvictionHandler(QuotaTemporaryStorageEvictorTest *test)
: quota_(0),
@@ -35,35 +35,33 @@ class MockQuotaEvictionHandler : public quota::QuotaEvictionHandler {
error_on_evict_origin_data_(false),
error_on_get_usage_and_quota_(false) {}
- virtual void EvictOriginData(
- const GURL& origin,
- StorageType type,
- const EvictOriginDataCallback& callback) OVERRIDE {
+ void EvictOriginData(const GURL& origin,
+ StorageType type,
+ const EvictOriginDataCallback& callback) override {
if (error_on_evict_origin_data_) {
- callback.Run(quota::kQuotaErrorInvalidModification);
+ callback.Run(storage::kQuotaErrorInvalidModification);
return;
}
int64 origin_usage = EnsureOriginRemoved(origin);
if (origin_usage >= 0)
available_space_ += origin_usage;
- callback.Run(quota::kQuotaStatusOk);
+ callback.Run(storage::kQuotaStatusOk);
}
- virtual void GetUsageAndQuotaForEviction(
- const UsageAndQuotaCallback& callback) OVERRIDE {
+ void GetUsageAndQuotaForEviction(
+ const UsageAndQuotaCallback& callback) override {
if (error_on_get_usage_and_quota_) {
- callback.Run(quota::kQuotaErrorInvalidAccess, UsageAndQuota());
+ callback.Run(storage::kQuotaErrorInvalidAccess, UsageAndQuota());
return;
}
if (!task_for_get_usage_and_quota_.is_null())
task_for_get_usage_and_quota_.Run();
UsageAndQuota quota_and_usage(-1, GetUsage(), quota_, available_space_);
- callback.Run(quota::kQuotaStatusOk, quota_and_usage);
+ callback.Run(storage::kQuotaStatusOk, quota_and_usage);
}
- virtual void GetLRUOrigin(
- StorageType type,
- const GetLRUOriginCallback& callback) OVERRIDE {
+ void GetLRUOrigin(StorageType type,
+ const GetLRUOriginCallback& callback) override {
if (origin_order_.empty())
callback.Run(GURL());
else
@@ -143,7 +141,7 @@ class QuotaTemporaryStorageEvictorTest : public testing::Test {
: num_get_usage_and_quota_for_eviction_(0),
weak_factory_(this) {}
- virtual void SetUp() {
+ void SetUp() override {
quota_eviction_handler_.reset(new MockQuotaEvictionHandler(this));
// Run multiple evictions in a single RunUntilIdle() when interval_ms == 0
@@ -151,7 +149,7 @@ class QuotaTemporaryStorageEvictorTest : public testing::Test {
quota_eviction_handler_.get(), 0));
}
- virtual void TearDown() {
+ void TearDown() override {
temporary_storage_evictor_.reset();
quota_eviction_handler_.reset();
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/quota/storage_monitor_unittest.cc b/chromium/content/browser/quota/storage_monitor_unittest.cc
index 5926e9ac1fd..78599de7472 100644
--- a/chromium/content/browser/quota/storage_monitor_unittest.cc
+++ b/chromium/content/browser/quota/storage_monitor_unittest.cc
@@ -11,26 +11,26 @@
#include "content/public/test/mock_special_storage_policy.h"
#include "content/public/test/mock_storage_client.h"
#include "net/base/net_util.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/browser/quota/storage_monitor.h"
+#include "storage/browser/quota/storage_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-#include "webkit/browser/quota/storage_monitor.h"
-#include "webkit/browser/quota/storage_observer.h"
-
-using quota::HostStorageObservers;
-using quota::kQuotaErrorNotSupported;
-using quota::kQuotaStatusOk;
-using quota::kStorageTypePersistent;
-using quota::kStorageTypeTemporary;
-using quota::QuotaClient;
-using quota::QuotaManager;
-using quota::QuotaStatusCode;
-using quota::SpecialStoragePolicy;
-using quota::StorageMonitor;
-using quota::StorageObserver;
-using quota::StorageObserverList;
-using quota::StorageType;
-using quota::StorageTypeObservers;
+
+using storage::HostStorageObservers;
+using storage::kQuotaErrorNotSupported;
+using storage::kQuotaStatusOk;
+using storage::kStorageTypePersistent;
+using storage::kStorageTypeTemporary;
+using storage::QuotaClient;
+using storage::QuotaManager;
+using storage::QuotaStatusCode;
+using storage::SpecialStoragePolicy;
+using storage::StorageMonitor;
+using storage::StorageObserver;
+using storage::StorageObserverList;
+using storage::StorageType;
+using storage::StorageTypeObservers;
namespace content {
@@ -51,7 +51,7 @@ class MockObserver : public StorageObserver {
}
// StorageObserver implementation:
- virtual void OnStorageEvent(const StorageObserver::Event& event) OVERRIDE {
+ void OnStorageEvent(const StorageObserver::Event& event) override {
events_.push_back(event);
}
@@ -86,10 +86,10 @@ class UsageMockQuotaManager : public QuotaManager {
delayed_callback_.Run(callback_status_, callback_usage_, callback_quota_);
}
- virtual void GetUsageAndQuotaForWebApps(
+ void GetUsageAndQuotaForWebApps(
const GURL& origin,
StorageType type,
- const GetUsageAndQuotaCallback& callback) OVERRIDE {
+ const GetUsageAndQuotaCallback& callback) override {
if (initialized_)
callback.Run(callback_status_, callback_usage_, callback_quota_);
else
@@ -97,7 +97,7 @@ class UsageMockQuotaManager : public QuotaManager {
}
protected:
- virtual ~UsageMockQuotaManager() {}
+ ~UsageMockQuotaManager() override {}
private:
int64 callback_usage_;
@@ -164,12 +164,12 @@ class StorageMonitorTestBase : public testing::Test {
class StorageTestWithManagerBase : public StorageMonitorTestBase {
public:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
storage_policy_ = new MockSpecialStoragePolicy();
quota_manager_ = new UsageMockQuotaManager(storage_policy_.get());
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// This ensures the quota manager is destroyed correctly.
quota_manager_ = NULL;
base::RunLoop().RunUntilIdle();
@@ -563,7 +563,7 @@ class StorageMonitorTest : public StorageTestWithManagerBase {
}
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
StorageTestWithManagerBase::SetUp();
storage_monitor_ = quota_manager_->storage_monitor_.get();
@@ -645,7 +645,7 @@ TEST_F(StorageMonitorTest, RemoveObserverForFilter) {
class StorageMonitorIntegrationTest : public testing::Test {
public:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
storage_policy_ = new MockSpecialStoragePolicy();
quota_manager_ = new QuotaManager(
@@ -663,7 +663,7 @@ class StorageMonitorIntegrationTest : public testing::Test {
quota_manager_->proxy()->RegisterClient(client_);
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// This ensures the quota manager is destroyed correctly.
quota_manager_ = NULL;
base::RunLoop().RunUntilIdle();
diff --git a/chromium/content/browser/quota/usage_tracker_unittest.cc b/chromium/content/browser/quota/usage_tracker_unittest.cc
index 3cba8bd4791..786146ab7d5 100644
--- a/chromium/content/browser/quota/usage_tracker_unittest.cc
+++ b/chromium/content/browser/quota/usage_tracker_unittest.cc
@@ -6,16 +6,16 @@
#include "base/run_loop.h"
#include "content/public/test/mock_special_storage_policy.h"
#include "net/base/net_util.h"
+#include "storage/browser/quota/usage_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/quota/usage_tracker.h"
-using quota::kQuotaStatusOk;
-using quota::kStorageTypeTemporary;
-using quota::QuotaClient;
-using quota::QuotaClientList;
-using quota::SpecialStoragePolicy;
-using quota::StorageType;
-using quota::UsageTracker;
+using storage::kQuotaStatusOk;
+using storage::kStorageTypeTemporary;
+using storage::QuotaClient;
+using storage::QuotaClientList;
+using storage::SpecialStoragePolicy;
+using storage::StorageType;
+using storage::UsageTracker;
namespace content {
@@ -45,25 +45,23 @@ void DidGetUsage(bool* done,
class MockQuotaClient : public QuotaClient {
public:
MockQuotaClient() {}
- virtual ~MockQuotaClient() {}
+ ~MockQuotaClient() override {}
- virtual ID id() const OVERRIDE {
- return kFileSystem;
- }
+ ID id() const override { return kFileSystem; }
- virtual void OnQuotaManagerDestroyed() OVERRIDE {}
+ void OnQuotaManagerDestroyed() override {}
- virtual void GetOriginUsage(const GURL& origin,
- StorageType type,
- const GetUsageCallback& callback) OVERRIDE {
+ void GetOriginUsage(const GURL& origin,
+ StorageType type,
+ const GetUsageCallback& callback) override {
EXPECT_EQ(kStorageTypeTemporary, type);
int64 usage = GetUsage(origin);
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(callback, usage));
}
- virtual void GetOriginsForType(StorageType type,
- const GetOriginsCallback& callback) OVERRIDE {
+ void GetOriginsForType(StorageType type,
+ const GetOriginsCallback& callback) override {
EXPECT_EQ(kStorageTypeTemporary, type);
std::set<GURL> origins;
for (UsageMap::const_iterator itr = usage_map_.begin();
@@ -74,9 +72,9 @@ class MockQuotaClient : public QuotaClient {
base::Bind(callback, origins));
}
- virtual void GetOriginsForHost(StorageType type,
- const std::string& host,
- const GetOriginsCallback& callback) OVERRIDE {
+ void GetOriginsForHost(StorageType type,
+ const std::string& host,
+ const GetOriginsCallback& callback) override {
EXPECT_EQ(kStorageTypeTemporary, type);
std::set<GURL> origins;
for (UsageMap::const_iterator itr = usage_map_.begin();
@@ -88,17 +86,17 @@ class MockQuotaClient : public QuotaClient {
base::Bind(callback, origins));
}
- virtual void DeleteOriginData(const GURL& origin,
- StorageType type,
- const DeletionCallback& callback) OVERRIDE {
+ void DeleteOriginData(const GURL& origin,
+ StorageType type,
+ const DeletionCallback& callback) override {
EXPECT_EQ(kStorageTypeTemporary, type);
usage_map_.erase(origin);
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, kQuotaStatusOk));
}
- virtual bool DoesSupport(quota::StorageType type) const OVERRIDE {
- return type == quota::kStorageTypeTemporary;
+ bool DoesSupport(storage::StorageType type) const override {
+ return type == storage::kStorageTypeTemporary;
}
int64 GetUsage(const GURL& origin) {
@@ -132,7 +130,7 @@ class UsageTrackerTest : public testing::Test {
storage_policy_.get(), NULL) {
}
- virtual ~UsageTrackerTest() {}
+ ~UsageTrackerTest() override {}
UsageTracker* usage_tracker() {
return &usage_tracker_;
diff --git a/chromium/content/browser/quota_dispatcher_host.cc b/chromium/content/browser/quota_dispatcher_host.cc
index fcee63396e5..2ea8a5ec9b5 100644
--- a/chromium/content/browser/quota_dispatcher_host.cc
+++ b/chromium/content/browser/quota_dispatcher_host.cc
@@ -10,13 +10,13 @@
#include "content/common/quota_messages.h"
#include "content/public/browser/quota_permission_context.h"
#include "net/base/net_util.h"
+#include "storage/browser/quota/quota_manager.h"
#include "url/gurl.h"
-#include "webkit/browser/quota/quota_manager.h"
-using quota::QuotaClient;
-using quota::QuotaManager;
-using quota::QuotaStatusCode;
-using quota::StorageType;
+using storage::QuotaClient;
+using storage::QuotaManager;
+using storage::QuotaStatusCode;
+using storage::StorageType;
namespace content {
@@ -44,7 +44,7 @@ class QuotaDispatcherHost::RequestDispatcher {
QuotaDispatcherHost* dispatcher_host() const {
return dispatcher_host_.get();
}
- quota::QuotaManager* quota_manager() const {
+ storage::QuotaManager* quota_manager() const {
return dispatcher_host_ ? dispatcher_host_->quota_manager_ : NULL;
}
QuotaPermissionContext* permission_context() const {
@@ -68,7 +68,7 @@ class QuotaDispatcherHost::QueryUsageAndQuotaDispatcher
int request_id)
: RequestDispatcher(dispatcher_host, request_id),
weak_factory_(this) {}
- virtual ~QueryUsageAndQuotaDispatcher() {}
+ ~QueryUsageAndQuotaDispatcher() override {}
void QueryStorageUsageAndQuota(const GURL& origin, StorageType type) {
quota_manager()->GetUsageAndQuotaForWebApps(
@@ -82,7 +82,7 @@ class QuotaDispatcherHost::QueryUsageAndQuotaDispatcher
QuotaStatusCode status, int64 usage, int64 quota) {
if (!dispatcher_host())
return;
- if (status != quota::kQuotaStatusOk) {
+ if (status != storage::kQuotaStatusOk) {
dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
} else {
dispatcher_host()->Send(new QuotaMsg_DidQueryStorageUsageAndQuota(
@@ -112,15 +112,15 @@ class QuotaDispatcherHost::RequestQuotaDispatcher
// TODO(nhiroki): The backend should accept uint64 values.
requested_quota_ = base::saturated_cast<int64>(params_.requested_size);
}
- virtual ~RequestQuotaDispatcher() {}
+ ~RequestQuotaDispatcher() override {}
void Start() {
DCHECK(dispatcher_host());
- DCHECK(params_.storage_type == quota::kStorageTypeTemporary ||
- params_.storage_type == quota::kStorageTypePersistent ||
- params_.storage_type == quota::kStorageTypeSyncable);
- if (params_.storage_type == quota::kStorageTypePersistent) {
+ DCHECK(params_.storage_type == storage::kStorageTypeTemporary ||
+ params_.storage_type == storage::kStorageTypePersistent ||
+ params_.storage_type == storage::kStorageTypeSyncable);
+ if (params_.storage_type == storage::kStorageTypePersistent) {
quota_manager()->GetUsageAndQuotaForWebApps(
params_.origin_url, params_.storage_type,
base::Bind(&self_type::DidGetPersistentUsageAndQuota,
@@ -139,7 +139,7 @@ class QuotaDispatcherHost::RequestQuotaDispatcher
int64 quota) {
if (!dispatcher_host())
return;
- if (status != quota::kQuotaStatusOk) {
+ if (status != storage::kQuotaStatusOk) {
DidFinish(status, 0, 0);
return;
}
@@ -148,7 +148,7 @@ class QuotaDispatcherHost::RequestQuotaDispatcher
params_.storage_type) ||
requested_quota_ <= quota) {
// Seems like we can just let it go.
- DidFinish(quota::kQuotaStatusOk, usage, params_.requested_size);
+ DidFinish(storage::kQuotaStatusOk, usage, params_.requested_size);
return;
}
current_usage_ = usage;
@@ -174,7 +174,7 @@ class QuotaDispatcherHost::RequestQuotaDispatcher
return;
if (response != QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW) {
// User didn't allow the new quota. Just returning the current quota.
- DidFinish(quota::kQuotaStatusOk, current_usage_, current_quota_);
+ DidFinish(storage::kQuotaStatusOk, current_usage_, current_quota_);
return;
}
// Now we're allowed to set the new quota.
@@ -193,7 +193,7 @@ class QuotaDispatcherHost::RequestQuotaDispatcher
if (!dispatcher_host())
return;
DCHECK(dispatcher_host());
- if (status != quota::kQuotaStatusOk) {
+ if (status != storage::kQuotaStatusOk) {
dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
} else {
dispatcher_host()->Send(new QuotaMsg_DidGrantStorageQuota(
@@ -245,11 +245,11 @@ void QuotaDispatcherHost::OnQueryStorageUsageAndQuota(
void QuotaDispatcherHost::OnRequestStorageQuota(
const StorageQuotaParams& params) {
- if (params.storage_type != quota::kStorageTypeTemporary &&
- params.storage_type != quota::kStorageTypePersistent) {
+ if (params.storage_type != storage::kStorageTypeTemporary &&
+ params.storage_type != storage::kStorageTypePersistent) {
// Unsupported storage types.
Send(new QuotaMsg_DidFail(params.request_id,
- quota::kQuotaErrorNotSupported));
+ storage::kQuotaErrorNotSupported));
return;
}
diff --git a/chromium/content/browser/quota_dispatcher_host.h b/chromium/content/browser/quota_dispatcher_host.h
index d241ab59c37..8a30f229f81 100644
--- a/chromium/content/browser/quota_dispatcher_host.h
+++ b/chromium/content/browser/quota_dispatcher_host.h
@@ -8,7 +8,7 @@
#include "base/basictypes.h"
#include "base/id_map.h"
#include "content/public/browser/browser_message_filter.h"
-#include "webkit/common/quota/quota_types.h"
+#include "storage/common/quota/quota_types.h"
class GURL;
@@ -16,7 +16,7 @@ namespace IPC {
class Message;
}
-namespace quota {
+namespace storage {
class QuotaManager;
}
@@ -27,30 +27,29 @@ struct StorageQuotaParams;
class QuotaDispatcherHost : public BrowserMessageFilter {
public:
QuotaDispatcherHost(int process_id,
- quota::QuotaManager* quota_manager,
+ storage::QuotaManager* quota_manager,
QuotaPermissionContext* permission_context);
// BrowserMessageFilter:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
protected:
- virtual ~QuotaDispatcherHost();
+ ~QuotaDispatcherHost() override;
private:
class RequestDispatcher;
class QueryUsageAndQuotaDispatcher;
class RequestQuotaDispatcher;
- void OnQueryStorageUsageAndQuota(
- int request_id,
- const GURL& origin_url,
- quota::StorageType type);
+ void OnQueryStorageUsageAndQuota(int request_id,
+ const GURL& origin_url,
+ storage::StorageType type);
void OnRequestStorageQuota(const StorageQuotaParams& params);
// The ID of this process.
int process_id_;
- quota::QuotaManager* quota_manager_;
+ storage::QuotaManager* quota_manager_;
scoped_refptr<QuotaPermissionContext> permission_context_;
IDMap<RequestDispatcher, IDMapOwnPointer> outstanding_requests_;
diff --git a/chromium/content/browser/renderer_host/DEPS b/chromium/content/browser/renderer_host/DEPS
index 55a8ec5f01d..3afe25bd977 100644
--- a/chromium/content/browser/renderer_host/DEPS
+++ b/chromium/content/browser/renderer_host/DEPS
@@ -15,7 +15,7 @@ include_rules = [
]
specific_include_rules = {
- ".*_(unit|browser)test\.cc": [
+ ".*_(unit|browser)test\.(cc|mm)": [
"+content/browser/frame_host",
"+content/browser/web_contents",
"+content/public/browser/web_contents.h",
diff --git a/chromium/content/browser/renderer_host/OWNERS b/chromium/content/browser/renderer_host/OWNERS
index 9d25787925e..2e48dfae455 100644
--- a/chromium/content/browser/renderer_host/OWNERS
+++ b/chromium/content/browser/renderer_host/OWNERS
@@ -1,8 +1,11 @@
# for *aura*
-per-file *aura*=ben@chromium.org
+per-file *aura*=sadrul@chromium.org
+
+# Windows.
+per-file *win*=ananta@chromium.org
# for *mac*
-thakis@chromium.org
+asvitkine@chromium.org
# for GPU-related stuff in *mac*
kbr@chromium.org
diff --git a/chromium/content/browser/renderer_host/clipboard_message_filter.h b/chromium/content/browser/renderer_host/clipboard_message_filter.h
index 3fcb94edc7a..792bfc5b774 100644
--- a/chromium/content/browser/renderer_host/clipboard_message_filter.h
+++ b/chromium/content/browser/renderer_host/clipboard_message_filter.h
@@ -21,12 +21,12 @@ class ClipboardMessageFilter : public BrowserMessageFilter {
public:
ClipboardMessageFilter();
- virtual void OverrideThreadForMessage(
- const IPC::Message& message,
- BrowserThread::ID* thread) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+
private:
- virtual ~ClipboardMessageFilter();
+ ~ClipboardMessageFilter() override;
void OnWriteObjectsAsync(const ui::Clipboard::ObjectMap& objects);
void OnWriteObjectsSync(const ui::Clipboard::ObjectMap& objects,
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_context_mac.h b/chromium/content/browser/renderer_host/compositing_iosurface_context_mac.h
deleted file mode 100644
index 52a98989293..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_context_mac.h
+++ /dev/null
@@ -1,88 +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_COMPOSITING_IOSURFACE_CONTEXT_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_CONTEXT_MAC_H_
-
-#import <AppKit/NSOpenGL.h>
-#include <OpenGL/OpenGL.h>
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/lazy_instance.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/gpu_data_manager_observer.h"
-#include "ui/gl/scoped_cgl.h"
-
-namespace content {
-
-class CompositingIOSurfaceShaderPrograms;
-
-class CompositingIOSurfaceContext
- : public base::RefCounted<CompositingIOSurfaceContext>,
- public content::GpuDataManagerObserver {
- public:
- enum {
- // The number used to look up the context used for async readback and for
- // initializing the IOSurface.
- kOffscreenContextWindowNumber = -2,
- // The number used to look up the context used by CAOpenGLLayers.
- kCALayerContextWindowNumber = -3,
- };
-
- // Get or create a GL context for the specified window with the specified
- // surface ordering. Share these GL contexts as much as possible because
- // creating and destroying them can be expensive
- // http://crbug.com/180463
- static scoped_refptr<CompositingIOSurfaceContext> Get(int window_number);
-
- // Mark that all the GL contexts in the same sharegroup as this context as
- // invalid, so they shouldn't be returned anymore by Get, but rather, new
- // contexts should be created. This is called as a precaution when unexpected
- // GL errors occur.
- void PoisonContextAndSharegroup();
- bool HasBeenPoisoned() const { return poisoned_; }
-
- CompositingIOSurfaceShaderPrograms* shader_program_cache() const {
- return shader_program_cache_.get();
- }
- CGLContextObj cgl_context() const { return cgl_context_; }
- bool is_vsync_disabled() const { return is_vsync_disabled_; }
- int window_number() const { return window_number_; }
-
- // content::GpuDataManagerObserver implementation.
- virtual void OnGpuSwitching() OVERRIDE;
-
- private:
- friend class base::RefCounted<CompositingIOSurfaceContext>;
-
- CompositingIOSurfaceContext(
- int window_number,
- base::ScopedTypeRef<CGLContextObj> clg_context_strong,
- CGLContextObj clg_context,
- bool is_vsync_disabled_,
- scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache);
- virtual ~CompositingIOSurfaceContext();
-
- int window_number_;
- base::ScopedTypeRef<CGLContextObj> cgl_context_strong_;
- // Weak, backed by |cgl_context_strong_|.
- CGLContextObj cgl_context_;
-
- bool is_vsync_disabled_;
- scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache_;
- bool poisoned_;
-
- // The global map from window number and window ordering to
- // context data.
- typedef std::map<int, CompositingIOSurfaceContext*> WindowMap;
- static base::LazyInstance<WindowMap> window_map_;
- static WindowMap* window_map();
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_CONTEXT_MAC_H_
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_context_mac.mm b/chromium/content/browser/renderer_host/compositing_iosurface_context_mac.mm
deleted file mode 100644
index a66bf5022d3..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_context_mac.mm
+++ /dev/null
@@ -1,170 +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/compositing_iosurface_context_mac.h"
-
-#include <OpenGL/gl.h>
-#include <OpenGL/OpenGL.h>
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/logging.h"
-#include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/gl/gl_switches.h"
-#include "ui/gl/gpu_switching_manager.h"
-
-namespace content {
-
-// static
-scoped_refptr<CompositingIOSurfaceContext>
-CompositingIOSurfaceContext::Get(int window_number) {
- TRACE_EVENT0("browser", "CompositingIOSurfaceContext::Get");
-
- // Return the context for this window_number, if it exists.
- WindowMap::iterator found = window_map()->find(window_number);
- if (found != window_map()->end()) {
- DCHECK(!found->second->poisoned_);
- return found->second;
- }
-
- static bool is_vsync_disabled =
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync);
-
- base::ScopedTypeRef<CGLContextObj> cgl_context_strong;
- CGLContextObj cgl_context = NULL;
- CGLError error = kCGLNoError;
-
- // Create the pixel format object for the context.
- std::vector<CGLPixelFormatAttribute> attribs;
- attribs.push_back(kCGLPFADepthSize);
- attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
- if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
- attribs.push_back(kCGLPFAAllowOfflineRenderers);
- attribs.push_back(static_cast<CGLPixelFormatAttribute>(1));
- }
- attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
- GLint number_virtual_screens = 0;
- base::ScopedTypeRef<CGLPixelFormatObj> pixel_format;
- error = CGLChoosePixelFormat(&attribs.front(),
- pixel_format.InitializeInto(),
- &number_virtual_screens);
- if (error != kCGLNoError) {
- LOG(ERROR) << "Failed to create pixel format object.";
- return NULL;
- }
-
- // Create all contexts in the same share group so that the textures don't
- // need to be recreated when transitioning contexts.
- CGLContextObj share_context = NULL;
- if (!window_map()->empty())
- share_context = window_map()->begin()->second->cgl_context();
- error = CGLCreateContext(
- pixel_format, share_context, cgl_context_strong.InitializeInto());
- if (error != kCGLNoError) {
- LOG(ERROR) << "Failed to create context object.";
- return NULL;
- }
- cgl_context = cgl_context_strong;
-
- // Note that VSync is ignored because CoreAnimation will automatically
- // rate limit draws.
-
- // Prepare the shader program cache. Precompile the shader programs
- // needed to draw the IO Surface for non-offscreen contexts.
- bool prepared = false;
- scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache;
- {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context);
- shader_program_cache.reset(new CompositingIOSurfaceShaderPrograms());
- if (window_number == kOffscreenContextWindowNumber) {
- prepared = true;
- } else {
- prepared = (
- shader_program_cache->UseBlitProgram() &&
- shader_program_cache->UseSolidWhiteProgram());
- }
- glUseProgram(0u);
- }
- if (!prepared) {
- LOG(ERROR) << "IOSurface failed to compile/link required shader programs.";
- return NULL;
- }
-
- return new CompositingIOSurfaceContext(
- window_number,
- cgl_context_strong,
- cgl_context,
- is_vsync_disabled,
- shader_program_cache.Pass());
-}
-
-void CompositingIOSurfaceContext::PoisonContextAndSharegroup() {
- if (poisoned_)
- return;
-
- for (WindowMap::iterator it = window_map()->begin();
- it != window_map()->end();
- ++it) {
- it->second->poisoned_ = true;
- }
- window_map()->clear();
-}
-
-CompositingIOSurfaceContext::CompositingIOSurfaceContext(
- int window_number,
- base::ScopedTypeRef<CGLContextObj> cgl_context_strong,
- CGLContextObj cgl_context,
- bool is_vsync_disabled,
- scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache)
- : window_number_(window_number),
- cgl_context_strong_(cgl_context_strong),
- cgl_context_(cgl_context),
- is_vsync_disabled_(is_vsync_disabled),
- shader_program_cache_(shader_program_cache.Pass()),
- poisoned_(false) {
- DCHECK(window_map()->find(window_number_) == window_map()->end());
- window_map()->insert(std::make_pair(window_number_, this));
-
- GpuDataManager::GetInstance()->AddObserver(this);
-}
-
-CompositingIOSurfaceContext::~CompositingIOSurfaceContext() {
- GpuDataManager::GetInstance()->RemoveObserver(this);
-
- {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_);
- shader_program_cache_->Reset();
- }
- if (!poisoned_) {
- DCHECK(window_map()->find(window_number_) != window_map()->end());
- DCHECK(window_map()->find(window_number_)->second == this);
- window_map()->erase(window_number_);
- } else {
- WindowMap::const_iterator found = window_map()->find(window_number_);
- if (found != window_map()->end())
- DCHECK(found->second != this);
- }
-}
-
-void CompositingIOSurfaceContext::OnGpuSwitching() {
- // Recreate all browser-side GL contexts whenever the GPU switches. If this
- // is not done, performance will suffer.
- // http://crbug.com/361493
- PoisonContextAndSharegroup();
-}
-
-// static
-CompositingIOSurfaceContext::WindowMap*
- CompositingIOSurfaceContext::window_map() {
- return window_map_.Pointer();
-}
-
-// static
-base::LazyInstance<CompositingIOSurfaceContext::WindowMap>
- CompositingIOSurfaceContext::window_map_;
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_layer_mac.h b/chromium/content/browser/renderer_host/compositing_iosurface_layer_mac.h
deleted file mode 100644
index 0449ae792c3..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_layer_mac.h
+++ /dev/null
@@ -1,71 +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.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_LAYER_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_LAYER_MAC_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_cftyperef.h"
-#include "base/memory/ref_counted.h"
-#include "base/timer/timer.h"
-
-namespace content {
-class CompositingIOSurfaceMac;
-class CompositingIOSurfaceContext;
-class CompositingIOSurfaceLayerHelper;
-
-class CompositingIOSurfaceLayerClient {
- public:
- virtual void AcceleratedLayerDidDrawFrame(bool succeeded) = 0;
-};
-
-} // namespace content
-
-// The CoreAnimation layer for drawing accelerated content.
-@interface CompositingIOSurfaceLayer : CAOpenGLLayer {
- @private
- content::CompositingIOSurfaceLayerClient* client_;
- scoped_refptr<content::CompositingIOSurfaceMac> iosurface_;
- scoped_refptr<content::CompositingIOSurfaceContext> context_;
-
- // The browser places back-pressure on the GPU by not acknowledging swap
- // calls until they appear on the screen. This can lead to hangs if the
- // view is moved offscreen (among other things). Prevent hangs by always
- // acknowledging the frame after timeout of 1/6th of a second has passed.
- scoped_ptr<content::CompositingIOSurfaceLayerHelper> helper_;
- scoped_ptr<base::DelayTimer<content::CompositingIOSurfaceLayerHelper>> timer_;
-
- // Used to track when canDrawInCGLContext should return YES. This can be
- // in response to receiving a new compositor frame, or from any of the events
- // that cause setNeedsDisplay to be called on the layer.
- BOOL needs_display_;
-
- // This is set when a frame is received, and un-set when the frame is drawn.
- BOOL has_pending_frame_;
-
- // Incremented every time that this layer is asked to draw but does not have
- // new content to draw.
- uint64 did_not_draw_counter_;
-}
-
-- (content::CompositingIOSurfaceMac*)iosurface;
-- (content::CompositingIOSurfaceContext*)context;
-
-- (id)initWithIOSurface:(scoped_refptr<content::CompositingIOSurfaceMac>)
- iosurface
- withScaleFactor:(float)scale_factor
- withClient:(content::CompositingIOSurfaceLayerClient*)client;
-
-// Mark that the client is no longer valid and cannot be called back into.
-- (void)resetClient;
-
-// Called when a new frame is received.
-- (void)gotNewFrame;
-
-- (void)setNeedsDisplayAndDisplayAndAck;
-- (void)displayIfNeededAndAck;
-@end
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_LAYER_MAC_H_
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_layer_mac.mm b/chromium/content/browser/renderer_host/compositing_iosurface_layer_mac.mm
deleted file mode 100644
index bda4c5fd9e4..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_layer_mac.mm
+++ /dev/null
@@ -1,234 +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.
-
-#include "content/browser/renderer_host/compositing_iosurface_layer_mac.h"
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <OpenGL/gl.h>
-
-#include "base/mac/mac_util.h"
-#include "base/mac/sdk_forward_declarations.h"
-#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/browser/renderer_host/render_widget_host_view_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_mac.h"
-#include "ui/base/cocoa/animation_utils.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gl/gpu_switching_manager.h"
-
-@interface CompositingIOSurfaceLayer(Private)
-- (void)ackPendingFrame:(bool)success;
-- (void)timerFired;
-@end
-
-namespace content {
-
-// The base::DelayTimer needs a C++ class to operate on, rather than Objective C
-// class. This helper class provides a bridge between the two.
-class CompositingIOSurfaceLayerHelper {
- public:
- CompositingIOSurfaceLayerHelper(CompositingIOSurfaceLayer* layer)
- : layer_(layer) {}
- void TimerFired() {
- [layer_ timerFired];
- }
- private:
- CompositingIOSurfaceLayer* layer_;
-};
-
-} // namespace content
-
-@implementation CompositingIOSurfaceLayer
-
-- (content::CompositingIOSurfaceMac*)iosurface {
- return iosurface_.get();
-}
-
-- (content::CompositingIOSurfaceContext*)context {
- return context_.get();
-}
-
-- (id)initWithIOSurface:(scoped_refptr<content::CompositingIOSurfaceMac>)
- iosurface
- withScaleFactor:(float)scale_factor
- withClient:(content::CompositingIOSurfaceLayerClient*)client {
- if (self = [super init]) {
- iosurface_ = iosurface;
- client_ = client;
- helper_.reset(new content::CompositingIOSurfaceLayerHelper(self));
- timer_.reset(new base::DelayTimer<content::CompositingIOSurfaceLayerHelper>(
- FROM_HERE,
- base::TimeDelta::FromSeconds(1) / 6,
- helper_.get(),
- &content::CompositingIOSurfaceLayerHelper::TimerFired));
-
- context_ = content::CompositingIOSurfaceContext::Get(
- content::CompositingIOSurfaceContext::kCALayerContextWindowNumber);
- DCHECK(context_);
- needs_display_ = NO;
- has_pending_frame_ = NO;
- did_not_draw_counter_ = 0;
-
- [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
- [self setAnchorPoint:CGPointMake(0, 0)];
- // Setting contents gravity is necessary to prevent the layer from being
- // scaled during dyanmic resizes (especially with devtools open).
- [self setContentsGravity:kCAGravityTopLeft];
- if ([self respondsToSelector:(@selector(setContentsScale:))]) {
- [self setContentsScale:scale_factor];
- }
- }
- return self;
-}
-
-- (void)resetClient {
- // Any acks that were waiting on this layer to draw will not occur, so ack
- // them now to prevent blocking the renderer.
- [self ackPendingFrame:true];
- client_ = NULL;
-}
-
-- (void)gotNewFrame {
- has_pending_frame_ = YES;
- timer_->Reset();
-
- // A trace value of 2 indicates that there is a pending swap ack. See
- // canDrawInCGLContext for other value meanings.
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, 2);
-
- if (context_ && context_->is_vsync_disabled()) {
- // If vsync is disabled, draw immediately and don't bother trying to use
- // the isAsynchronous property to ensure smooth animation.
- [self setNeedsDisplayAndDisplayAndAck];
- } else {
- needs_display_ = YES;
- if (![self isAsynchronous])
- [self setAsynchronous:YES];
- }
-}
-
-// Private methods:
-
-- (void)setNeedsDisplayAndDisplayAndAck {
- // Workaround for crbug.com/395827
- if ([self isAsynchronous])
- [self setAsynchronous:NO];
-
- [self setNeedsDisplay];
- [self displayIfNeededAndAck];
-}
-
-- (void)displayIfNeededAndAck {
- // Workaround for crbug.com/395827
- if ([self isAsynchronous])
- [self setAsynchronous:NO];
-
- [self displayIfNeeded];
-
- // Calls to setNeedsDisplay can sometimes be ignored, especially if issued
- // rapidly (e.g, with vsync off). This is unacceptable because the failure
- // to ack a single frame will hang the renderer. Ensure that the renderer
- // not be blocked by lying and claiming that we drew the frame.
- [self ackPendingFrame:true];
-}
-
-- (void)ackPendingFrame:(bool)success {
- if (!has_pending_frame_)
- return;
-
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, 0);
- has_pending_frame_ = NO;
- if (client_)
- client_->AcceleratedLayerDidDrawFrame(success);
-}
-
-- (void)timerFired {
- if (has_pending_frame_)
- [self setNeedsDisplayAndDisplayAndAck];
-}
-
-// The remaining methods implement the CAOpenGLLayer interface.
-
-- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
- if (!context_)
- return [super copyCGLPixelFormatForDisplayMask:mask];
- return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context()));
-}
-
-- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
- if (!context_)
- return [super copyCGLContextForPixelFormat:pixelFormat];
- return CGLRetainContext(context_->cgl_context());
-}
-
-- (void)setNeedsDisplay {
- needs_display_ = YES;
- [super setNeedsDisplay];
-}
-
-- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
- pixelFormat:(CGLPixelFormatObj)pixelFormat
- forLayerTime:(CFTimeInterval)timeInterval
- displayTime:(const CVTimeStamp*)timeStamp {
- // Add an instantaneous blip to the PendingSwapAck state to indicate
- // that CoreAnimation asked if a frame is ready. A blip up to to 3 (usually
- // from 2, indicating that a swap ack is pending) indicates that we requested
- // a draw. A blip up to 1 (usually from 0, indicating there is no pending swap
- // ack) indicates that we did not request a draw. This would be more natural
- // to do with a tracing pseudo-thread
- // http://crbug.com/366300
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, needs_display_ ? 3 : 1);
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", self,
- has_pending_frame_ ? 2 : 0);
-
- // If we return NO 30 times in a row, switch to being synchronous to avoid
- // burning CPU cycles on this callback.
- if (needs_display_) {
- did_not_draw_counter_ = 0;
- } else {
- did_not_draw_counter_ += 1;
- if (did_not_draw_counter_ > 30)
- [self setAsynchronous:NO];
- }
-
- return needs_display_;
-}
-
-- (void)drawInCGLContext:(CGLContextObj)glContext
- pixelFormat:(CGLPixelFormatObj)pixelFormat
- forLayerTime:(CFTimeInterval)timeInterval
- displayTime:(const CVTimeStamp*)timeStamp {
- TRACE_EVENT0("browser", "CompositingIOSurfaceLayer::drawInCGLContext");
-
- if (!iosurface_->HasIOSurface() || context_->cgl_context() != glContext) {
- glClearColor(1, 1, 1, 1);
- glClear(GL_COLOR_BUFFER_BIT);
- return;
- }
-
- // The correct viewport to cover the layer will be set up by the caller.
- // Transform this into a window size for DrawIOSurface, where it will be
- // transformed back into this viewport.
- GLint viewport[4];
- glGetIntegerv(GL_VIEWPORT, viewport);
- gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]);
- float window_scale_factor = 1.f;
- if ([self respondsToSelector:(@selector(contentsScale))])
- window_scale_factor = [self contentsScale];
- window_rect = ToNearestRect(
- gfx::ScaleRect(window_rect, 1.f/window_scale_factor));
-
- bool draw_succeeded = iosurface_->DrawIOSurface(
- context_, window_rect, window_scale_factor);
-
- [self ackPendingFrame:draw_succeeded];
- needs_display_ = NO;
-
- [super drawInCGLContext:glContext
- pixelFormat:pixelFormat
- forLayerTime:timeInterval
- displayTime:timeStamp];
-}
-
-@end
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_mac.h b/chromium/content/browser/renderer_host/compositing_iosurface_mac.h
deleted file mode 100644
index 08c3c74c286..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_mac.h
+++ /dev/null
@@ -1,331 +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_COMPOSITING_IOSURFACE_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
-
-#include <deque>
-#include <list>
-#include <vector>
-
-#import <Cocoa/Cocoa.h>
-#include <IOSurface/IOSurfaceAPI.h>
-#include <QuartzCore/QuartzCore.h>
-
-#include "base/callback.h"
-#include "base/lazy_instance.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "media/base/video_frame.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/size.h"
-
-class SkBitmap;
-
-namespace gfx {
-class Rect;
-}
-
-namespace content {
-
-class CompositingIOSurfaceContext;
-class CompositingIOSurfaceShaderPrograms;
-class CompositingIOSurfaceTransformer;
-class RenderWidgetHostViewFrameSubscriber;
-class RenderWidgetHostViewMac;
-
-// This class manages an OpenGL context and IOSurface for the accelerated
-// compositing code path. The GL context is attached to
-// RenderWidgetHostViewCocoa for blitting the IOSurface.
-class CompositingIOSurfaceMac
- : public base::RefCounted<CompositingIOSurfaceMac> {
- public:
- // Returns NULL if IOSurface or GL API calls fail.
- static scoped_refptr<CompositingIOSurfaceMac> Create();
-
- // Set IOSurface that will be drawn on the next NSView drawRect.
- bool SetIOSurfaceWithContextCurrent(
- scoped_refptr<CompositingIOSurfaceContext> current_context,
- IOSurfaceID io_surface_handle,
- const gfx::Size& size,
- float scale_factor) WARN_UNUSED_RESULT;
-
- // Get the CGL renderer ID currently associated with this context.
- int GetRendererID();
-
- // Blit the IOSurface to the rectangle specified by |window_rect| in DIPs,
- // with the origin in the lower left corner. If the window rect's size is
- // larger than the IOSurface, the remaining right and bottom edges will be
- // white. |window_scale_factor| is 1 in normal views, 2 in HiDPI views.
- bool DrawIOSurface(
- scoped_refptr<CompositingIOSurfaceContext> drawing_context,
- const gfx::Rect& window_rect,
- float window_scale_factor) WARN_UNUSED_RESULT;
-
- // Copy the data of the "live" OpenGL texture referring to this IOSurfaceRef
- // into |out|. The copied region is specified with |src_pixel_subrect| and
- // the data is transformed so that it fits in |dst_pixel_size|.
- // |src_pixel_subrect| and |dst_pixel_size| are not in DIP but in pixel.
- // Caller must ensure that |out| is allocated to dimensions that match
- // dst_pixel_size, with no additional padding.
- // |callback| is invoked when the operation is completed or failed.
- // Do no call this method again before |callback| is invoked.
- void CopyTo(const gfx::Rect& src_pixel_subrect,
- const gfx::Size& dst_pixel_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback);
-
- // Transfer the contents of the surface to an already-allocated YV12
- // VideoFrame, and invoke a callback to indicate success or failure.
- void CopyToVideoFrame(
- const gfx::Rect& src_subrect,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback);
-
- // Unref the IOSurface and delete the associated GL texture. If the GPU
- // process is no longer referencing it, this will delete the IOSurface.
- void UnrefIOSurface();
-
- bool HasIOSurface() { return !!io_surface_.get(); }
-
- const gfx::Size& pixel_io_surface_size() const {
- return pixel_io_surface_size_;
- }
- // In cocoa view units / DIPs.
- const gfx::Size& dip_io_surface_size() const { return dip_io_surface_size_; }
- float scale_factor() const { return scale_factor_; }
-
- // Returns true if asynchronous readback is supported on this system.
- bool IsAsynchronousReadbackSupported();
-
- // Scan the list of started asynchronous copies and test if each one has
- // completed. If |block_until_finished| is true, then block until all
- // pending copies are finished.
- void CheckIfAllCopiesAreFinished(bool block_until_finished);
-
- // Returns true if the offscreen context used by this surface has been
- // poisoned.
- bool HasBeenPoisoned() const;
-
- private:
- friend class base::RefCounted<CompositingIOSurfaceMac>;
-
- // Vertex structure for use in glDraw calls.
- struct SurfaceVertex {
- SurfaceVertex() : x_(0.0f), y_(0.0f), tx_(0.0f), ty_(0.0f) { }
- void set(float x, float y, float tx, float ty) {
- x_ = x;
- y_ = y;
- tx_ = tx;
- ty_ = ty;
- }
- void set_position(float x, float y) {
- x_ = x;
- y_ = y;
- }
- void set_texcoord(float tx, float ty) {
- tx_ = tx;
- ty_ = ty;
- }
- float x_;
- float y_;
- float tx_;
- float ty_;
- };
-
- // Counter-clockwise verts starting from upper-left corner (0, 0).
- struct SurfaceQuad {
- void set_size(gfx::Size vertex_size, gfx::Size texcoord_size) {
- // Texture coordinates are flipped vertically so they can be drawn on
- // a projection with a flipped y-axis (origin is top left).
- float vw = static_cast<float>(vertex_size.width());
- float vh = static_cast<float>(vertex_size.height());
- float tw = static_cast<float>(texcoord_size.width());
- float th = static_cast<float>(texcoord_size.height());
- verts_[0].set(0.0f, 0.0f, 0.0f, th);
- verts_[1].set(0.0f, vh, 0.0f, 0.0f);
- verts_[2].set(vw, vh, tw, 0.0f);
- verts_[3].set(vw, 0.0f, tw, th);
- }
- void set_rect(float x1, float y1, float x2, float y2) {
- verts_[0].set_position(x1, y1);
- verts_[1].set_position(x1, y2);
- verts_[2].set_position(x2, y2);
- verts_[3].set_position(x2, y1);
- }
- void set_texcoord_rect(float tx1, float ty1, float tx2, float ty2) {
- // Texture coordinates are flipped vertically so they can be drawn on
- // a projection with a flipped y-axis (origin is top left).
- verts_[0].set_texcoord(tx1, ty2);
- verts_[1].set_texcoord(tx1, ty1);
- verts_[2].set_texcoord(tx2, ty1);
- verts_[3].set_texcoord(tx2, ty2);
- }
- SurfaceVertex verts_[4];
- };
-
- // Keeps track of states and buffers for readback of IOSurface.
- //
- // TODO(miu): Major code refactoring is badly needed! To be done in a
- // soon-upcoming change. For now, we blatantly violate the style guide with
- // respect to struct vs. class usage:
- struct CopyContext {
- explicit CopyContext(const scoped_refptr<CompositingIOSurfaceContext>& ctx);
- ~CopyContext();
-
- // Delete any references to owned OpenGL objects. This must be called
- // within the OpenGL context just before destruction.
- void ReleaseCachedGLObjects();
-
- // The following two methods assume |num_outputs| has been set, and are
- // being called within the OpenGL context.
- void PrepareReadbackFramebuffers();
- void PrepareForAsynchronousReadback();
-
- const scoped_ptr<CompositingIOSurfaceTransformer> transformer;
- GLenum output_readback_format;
- int num_outputs;
- GLuint output_textures[3]; // Not owned.
- // Note: For YUV, the |output_texture_sizes| widths are in terms of 4-byte
- // quads, not pixels.
- gfx::Size output_texture_sizes[3];
- GLuint frame_buffers[3];
- GLuint pixel_buffers[3];
- GLuint fence; // When non-zero, doing an asynchronous copy.
- int cycles_elapsed;
- base::Callback<bool(const void*, int)> map_buffer_callback;
- base::Callback<void(bool)> done_callback;
- };
-
- CompositingIOSurfaceMac(
- const scoped_refptr<CompositingIOSurfaceContext>& context);
- ~CompositingIOSurfaceMac();
-
- // If this IOSurface has moved to a different window, use that window's
- // GL context (if multiple visible windows are using the same GL context
- // then call to setView call can stall and prevent reaching 60fps).
- void SwitchToContextOnNewWindow(NSView* view,
- int window_number);
-
- // Returns true if IOSurface is ready to render. False otherwise.
- bool MapIOSurfaceToTextureWithContextCurrent(
- const scoped_refptr<CompositingIOSurfaceContext>& current_context,
- const gfx::Size pixel_size,
- float scale_factor,
- IOSurfaceID io_surface_handle) WARN_UNUSED_RESULT;
-
- void UnrefIOSurfaceWithContextCurrent();
-
- void DrawQuad(const SurfaceQuad& quad);
-
- // Copy current frame to |target| video frame. This method must be called
- // within a CGL context. Returns a callback that should be called outside
- // of the CGL context.
- // If |called_within_draw| is true this method is called within a drawing
- // operations. This allow certain optimizations.
- base::Closure CopyToVideoFrameWithinContext(
- const gfx::Rect& src_subrect,
- bool called_within_draw,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback);
-
- // Common GPU-readback copy path. Only one of |bitmap_output| or
- // |video_frame_output| may be specified: Either ARGB is written to
- // |bitmap_output| or letter-boxed YV12 is written to |video_frame_output|.
- base::Closure CopyToSelectedOutputWithinContext(
- const gfx::Rect& src_pixel_subrect,
- const gfx::Rect& dst_pixel_rect,
- bool called_within_draw,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output,
- const base::Callback<void(bool)>& done_callback);
-
- // TODO(hclam): These two methods should be static.
- void AsynchronousReadbackForCopy(
- const gfx::Rect& dst_pixel_rect,
- bool called_within_draw,
- CopyContext* copy_context,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output);
- bool SynchronousReadbackForCopy(
- const gfx::Rect& dst_pixel_rect,
- CopyContext* copy_context,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output);
-
- void CheckIfAllCopiesAreFinishedWithinContext(
- bool block_until_finished,
- std::vector<base::Closure>* done_callbacks);
-
- void FailAllCopies();
- void DestroyAllCopyContextsWithinContext();
-
- // Check for GL errors and store the result in error_. Only return new
- // errors
- GLenum GetAndSaveGLError();
-
- gfx::Rect IntersectWithIOSurface(const gfx::Rect& rect) const;
-
- // Offscreen context used for all operations other than drawing to the
- // screen. This is in the same share group as the contexts used for
- // drawing, and is the same for all IOSurfaces in all windows.
- scoped_refptr<CompositingIOSurfaceContext> offscreen_context_;
-
- // IOSurface data.
- IOSurfaceID io_surface_handle_;
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
-
- // The width and height of the io surface.
- gfx::Size pixel_io_surface_size_; // In pixels.
- gfx::Size dip_io_surface_size_; // In view / density independent pixels.
- float scale_factor_;
-
- // The "live" OpenGL texture referring to this IOSurfaceRef. Note
- // that per the CGLTexImageIOSurface2D API we do not need to
- // explicitly update this texture's contents once created. All we
- // need to do is ensure it is re-bound before attempting to draw
- // with it.
- GLuint texture_;
-
- // A pool of CopyContexts with OpenGL objects ready for re-use. Prefer to
- // pull one from the pool before creating a new CopyContext.
- std::vector<CopyContext*> copy_context_pool_;
-
- // CopyContexts being used for in-flight copy operations.
- std::deque<CopyContext*> copy_requests_;
-
- // Timer for finishing a copy operation.
- base::Timer finish_copy_timer_;
-
- // Error saved by GetAndSaveGLError
- GLint gl_error_;
-
- // Aggressive IOSurface eviction logic. When using CoreAnimation, IOSurfaces
- // are used only transiently to transfer from the GPU process to the browser
- // process. Once the IOSurface has been drawn to its CALayer, the CALayer
- // will not need updating again until its view is hidden and re-shown.
- // Aggressively evict surfaces when more than 8 (the number allowed by the
- // memory manager for fast tab switching) are allocated.
- enum {
- kMaximumUnevictedSurfaces = 8,
- };
- typedef std::list<CompositingIOSurfaceMac*> EvictionQueue;
- void EvictionMarkUpdated();
- void EvictionMarkEvicted();
- EvictionQueue::iterator eviction_queue_iterator_;
- bool eviction_has_been_drawn_since_updated_;
-
- static void EvictionScheduleDoEvict();
- static void EvictionDoEvict();
- static base::LazyInstance<EvictionQueue> eviction_queue_;
- static bool eviction_scheduled_;
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_mac.mm b/chromium/content/browser/renderer_host/compositing_iosurface_mac.mm
deleted file mode 100644
index 3fd28545d2f..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_mac.mm
+++ /dev/null
@@ -1,970 +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/renderer_host/compositing_iosurface_mac.h"
-
-#include <OpenGL/CGLIOSurface.h>
-#include <OpenGL/CGLRenderers.h>
-#include <OpenGL/OpenGL.h>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/debug/trace_event.h"
-#include "base/logging.h"
-#include "base/mac/mac_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/platform_thread.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_transformer_mac.h"
-#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/browser/renderer_host/render_widget_host_view_mac.h"
-#include "content/common/content_constants_internal.h"
-#include "gpu/config/gpu_driver_bug_workaround_type.h"
-#include "media/base/video_util.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gl/gl_context.h"
-
-#ifdef NDEBUG
-#define CHECK_GL_ERROR()
-#define CHECK_AND_SAVE_GL_ERROR()
-#else
-#define CHECK_GL_ERROR() do { \
- GLenum gl_error = glGetError(); \
- LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \
- } while (0)
-#define CHECK_AND_SAVE_GL_ERROR() do { \
- GLenum gl_error = GetAndSaveGLError(); \
- LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \
- } while (0)
-#endif
-
-namespace content {
-namespace {
-
-// How many times to test if asynchronous copy has completed.
-// This value is chosen such that we allow at most 1 second to finish a copy.
-const int kFinishCopyRetryCycles = 100;
-
-// Time in milliseconds to allow asynchronous copy to finish.
-// This value is shorter than 16ms such that copy can complete within a vsync.
-const int kFinishCopyPollingPeriodMs = 10;
-
-bool HasAppleFenceExtension() {
- static bool initialized_has_fence = false;
- static bool has_fence = false;
-
- if (!initialized_has_fence) {
- has_fence =
- strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
- "GL_APPLE_fence") != NULL;
- initialized_has_fence = true;
- }
- return has_fence;
-}
-
-bool HasPixelBufferObjectExtension() {
- static bool initialized_has_pbo = false;
- static bool has_pbo = false;
-
- if (!initialized_has_pbo) {
- has_pbo =
- strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
- "GL_ARB_pixel_buffer_object") != NULL;
- initialized_has_pbo = true;
- }
- return has_pbo;
-}
-
-// Helper function to reverse the argument order. Also takes ownership of
-// |bitmap_output| for the life of the binding.
-void ReverseArgumentOrder(
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- scoped_ptr<SkBitmap> bitmap_output, bool success) {
- callback.Run(success, *bitmap_output);
-}
-
-// Called during an async GPU readback with a pointer to the pixel buffer. In
-// the snapshot path, we just memcpy the data into our output bitmap since the
-// width, height, and stride should all be equal.
-bool MapBufferToSkBitmap(const SkBitmap* output, const void* buf, int ignored) {
- TRACE_EVENT0("browser", "MapBufferToSkBitmap");
-
- if (buf) {
- SkAutoLockPixels output_lock(*output);
- memcpy(output->getPixels(), buf, output->getSize());
- }
- return buf != NULL;
-}
-
-// Copies tightly-packed scanlines from |buf| to |region_in_frame| in the given
-// |target| VideoFrame's |plane|. Assumption: |buf|'s width is
-// |region_in_frame.width()| and its stride is always in 4-byte alignment.
-//
-// TODO(miu): Refactor by moving this function into media/video_util.
-// http://crbug.com/219779
-bool MapBufferToVideoFrame(
- const scoped_refptr<media::VideoFrame>& target,
- const gfx::Rect& region_in_frame,
- const void* buf,
- int plane) {
- COMPILE_ASSERT(media::VideoFrame::kYPlane == 0, VideoFrame_kYPlane_mismatch);
- COMPILE_ASSERT(media::VideoFrame::kUPlane == 1, VideoFrame_kUPlane_mismatch);
- COMPILE_ASSERT(media::VideoFrame::kVPlane == 2, VideoFrame_kVPlane_mismatch);
-
- TRACE_EVENT1("browser", "MapBufferToVideoFrame", "plane", plane);
-
- // Apply black-out in the regions surrounding the view area (for
- // letterboxing/pillarboxing). Only do this once, since this is performed on
- // all planes in the VideoFrame here.
- if (plane == 0)
- media::LetterboxYUV(target.get(), region_in_frame);
-
- if (buf) {
- int packed_width = region_in_frame.width();
- int packed_height = region_in_frame.height();
- // For planes 1 and 2, the width and height are 1/2 size (rounded up).
- if (plane > 0) {
- packed_width = (packed_width + 1) / 2;
- packed_height = (packed_height + 1) / 2;
- }
- const uint8* src = reinterpret_cast<const uint8*>(buf);
- const int src_stride = (packed_width % 4 == 0 ?
- packed_width :
- (packed_width + 4 - (packed_width % 4)));
- const uint8* const src_end = src + packed_height * src_stride;
-
- // Calculate starting offset and stride into the destination buffer.
- const int dst_stride = target->stride(plane);
- uint8* dst = target->data(plane);
- if (plane == 0)
- dst += (region_in_frame.y() * dst_stride) + region_in_frame.x();
- else
- dst += (region_in_frame.y() / 2 * dst_stride) + (region_in_frame.x() / 2);
-
- // Copy each row, accounting for strides in the source and destination.
- for (; src < src_end; src += src_stride, dst += dst_stride)
- memcpy(dst, src, packed_width);
- }
- return buf != NULL;
-}
-
-} // namespace
-
-CompositingIOSurfaceMac::CopyContext::CopyContext(
- const scoped_refptr<CompositingIOSurfaceContext>& context)
- : transformer(new CompositingIOSurfaceTransformer(
- GL_TEXTURE_RECTANGLE_ARB, true, context->shader_program_cache())),
- output_readback_format(GL_BGRA),
- num_outputs(0),
- fence(0),
- cycles_elapsed(0) {
- memset(output_textures, 0, sizeof(output_textures));
- memset(frame_buffers, 0, sizeof(frame_buffers));
- memset(pixel_buffers, 0, sizeof(pixel_buffers));
-}
-
-CompositingIOSurfaceMac::CopyContext::~CopyContext() {
- DCHECK_EQ(frame_buffers[0], 0u) << "Failed to call ReleaseCachedGLObjects().";
-}
-
-void CompositingIOSurfaceMac::CopyContext::ReleaseCachedGLObjects() {
- // No outstanding callbacks should be pending.
- DCHECK(map_buffer_callback.is_null());
- DCHECK(done_callback.is_null());
-
- // For an asynchronous read-back, there are more objects to delete:
- if (fence) {
- glDeleteBuffers(arraysize(pixel_buffers), pixel_buffers); CHECK_GL_ERROR();
- memset(pixel_buffers, 0, sizeof(pixel_buffers));
- glDeleteFencesAPPLE(1, &fence); CHECK_GL_ERROR();
- fence = 0;
- }
-
- glDeleteFramebuffersEXT(arraysize(frame_buffers), frame_buffers);
- CHECK_GL_ERROR();
- memset(frame_buffers, 0, sizeof(frame_buffers));
-
- // Note: |output_textures| are owned by the transformer.
- if (transformer)
- transformer->ReleaseCachedGLObjects();
-}
-
-void CompositingIOSurfaceMac::CopyContext::PrepareReadbackFramebuffers() {
- for (int i = 0; i < num_outputs; ++i) {
- if (!frame_buffers[i]) {
- glGenFramebuffersEXT(1, &frame_buffers[i]); CHECK_GL_ERROR();
- }
- }
-}
-
-void CompositingIOSurfaceMac::CopyContext::PrepareForAsynchronousReadback() {
- PrepareReadbackFramebuffers();
- if (!fence) {
- glGenFencesAPPLE(1, &fence); CHECK_GL_ERROR();
- }
- for (int i = 0; i < num_outputs; ++i) {
- if (!pixel_buffers[i]) {
- glGenBuffersARB(1, &pixel_buffers[i]); CHECK_GL_ERROR();
- }
- }
-}
-
-
-// static
-scoped_refptr<CompositingIOSurfaceMac> CompositingIOSurfaceMac::Create() {
- scoped_refptr<CompositingIOSurfaceContext> offscreen_context =
- CompositingIOSurfaceContext::Get(
- CompositingIOSurfaceContext::kOffscreenContextWindowNumber);
- if (!offscreen_context) {
- LOG(ERROR) << "Failed to create context for offscreen operations";
- return NULL;
- }
-
- return new CompositingIOSurfaceMac(offscreen_context);
-}
-
-CompositingIOSurfaceMac::CompositingIOSurfaceMac(
- const scoped_refptr<CompositingIOSurfaceContext>& offscreen_context)
- : offscreen_context_(offscreen_context),
- io_surface_handle_(0),
- scale_factor_(1.f),
- texture_(0),
- finish_copy_timer_(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kFinishCopyPollingPeriodMs),
- base::Bind(&CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished,
- base::Unretained(this),
- false),
- true),
- gl_error_(GL_NO_ERROR),
- eviction_queue_iterator_(eviction_queue_.Get().end()),
- eviction_has_been_drawn_since_updated_(false) {
- CHECK(offscreen_context_);
-}
-
-CompositingIOSurfaceMac::~CompositingIOSurfaceMac() {
- FailAllCopies();
- {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- offscreen_context_->cgl_context());
- DestroyAllCopyContextsWithinContext();
- UnrefIOSurfaceWithContextCurrent();
- }
- offscreen_context_ = NULL;
- DCHECK(eviction_queue_iterator_ == eviction_queue_.Get().end());
-}
-
-bool CompositingIOSurfaceMac::SetIOSurfaceWithContextCurrent(
- scoped_refptr<CompositingIOSurfaceContext> current_context,
- IOSurfaceID io_surface_handle,
- const gfx::Size& size,
- float scale_factor) {
- bool result = MapIOSurfaceToTextureWithContextCurrent(
- current_context, size, scale_factor, io_surface_handle);
- EvictionMarkUpdated();
- return result;
-}
-
-int CompositingIOSurfaceMac::GetRendererID() {
- GLint current_renderer_id = -1;
- if (CGLGetParameter(offscreen_context_->cgl_context(),
- kCGLCPCurrentRendererID,
- &current_renderer_id) == kCGLNoError)
- return current_renderer_id & kCGLRendererIDMatchingMask;
- return -1;
-}
-
-bool CompositingIOSurfaceMac::DrawIOSurface(
- scoped_refptr<CompositingIOSurfaceContext> drawing_context,
- const gfx::Rect& window_rect,
- float window_scale_factor) {
- DCHECK_EQ(CGLGetCurrentContext(), drawing_context->cgl_context());
-
- bool has_io_surface = HasIOSurface();
- TRACE_EVENT1("browser", "CompositingIOSurfaceMac::DrawIOSurface",
- "has_io_surface", has_io_surface);
-
- gfx::Rect pixel_window_rect =
- ToNearestRect(gfx::ScaleRect(window_rect, window_scale_factor));
- glViewport(
- pixel_window_rect.x(), pixel_window_rect.y(),
- pixel_window_rect.width(), pixel_window_rect.height());
-
- SurfaceQuad quad;
- quad.set_size(dip_io_surface_size_, pixel_io_surface_size_);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
-
- // Note that the projection keeps things in view units, so the use of
- // window_rect / dip_io_surface_size_ (as opposed to the pixel_ variants)
- // below is correct.
- glOrtho(0, window_rect.width(), window_rect.height(), 0, -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
-
- if (has_io_surface) {
- drawing_context->shader_program_cache()->UseBlitProgram();
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
-
- DrawQuad(quad);
-
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
-
- // Fill the resize gutters with white.
- if (window_rect.width() > dip_io_surface_size_.width() ||
- window_rect.height() > dip_io_surface_size_.height()) {
- drawing_context->shader_program_cache()->UseSolidWhiteProgram();
- SurfaceQuad filler_quad;
- if (window_rect.width() > dip_io_surface_size_.width()) {
- // Draw right-side gutter down to the bottom of the window.
- filler_quad.set_rect(dip_io_surface_size_.width(), 0.0f,
- window_rect.width(), window_rect.height());
- DrawQuad(filler_quad);
- }
- if (window_rect.height() > dip_io_surface_size_.height()) {
- // Draw bottom gutter to the width of the IOSurface.
- filler_quad.set_rect(
- 0.0f, dip_io_surface_size_.height(),
- dip_io_surface_size_.width(), window_rect.height());
- DrawQuad(filler_quad);
- }
- }
-
- // Workaround for issue 158469. Issue a dummy draw call with texture_ not
- // bound to blit_rgb_sampler_location_, in order to shake all references
- // to the IOSurface out of the driver.
- glBegin(GL_TRIANGLES);
- glEnd();
-
- glUseProgram(0); CHECK_AND_SAVE_GL_ERROR();
- } else {
- // Should match the clear color of RenderWidgetHostViewMac.
- glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- }
-
- bool workaround_needed =
- GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
- gpu::FORCE_GL_FINISH_AFTER_COMPOSITING);
- if (workaround_needed) {
- TRACE_EVENT0("gpu", "glFinish");
- glFinish();
- }
-
- // Check if any of the drawing calls result in an error.
- GetAndSaveGLError();
- bool result = true;
- if (gl_error_ != GL_NO_ERROR) {
- LOG(ERROR) << "GL error in DrawIOSurface: " << gl_error_;
- result = false;
- // If there was an error, clear the screen to a light grey to avoid
- // rendering artifacts. If we're in a really bad way, this too may
- // generate an error. Clear the GL error afterwards just in case.
- glClearColor(0.8, 0.8, 0.8, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
- glGetError();
- }
-
- eviction_has_been_drawn_since_updated_ = true;
- return result;
-}
-
-void CompositingIOSurfaceMac::CopyTo(
- const gfx::Rect& src_pixel_subrect,
- const gfx::Size& dst_pixel_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback) {
- scoped_ptr<SkBitmap> output(new SkBitmap());
- output->setConfig(SkBitmap::kARGB_8888_Config,
- dst_pixel_size.width(),
- dst_pixel_size.height(),
- 0,
- kOpaque_SkAlphaType);
-
- if (!output->allocPixels()) {
- DLOG(ERROR) << "Failed to allocate SkBitmap pixels!";
- callback.Run(false, *output);
- return;
- }
- DCHECK_EQ(output->rowBytesAsPixels(), dst_pixel_size.width())
- << "Stride is required to be equal to width for GPU readback.";
-
- base::Closure copy_done_callback;
- {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- offscreen_context_->cgl_context());
- copy_done_callback = CopyToSelectedOutputWithinContext(
- src_pixel_subrect, gfx::Rect(dst_pixel_size), false,
- output.get(), NULL,
- base::Bind(&ReverseArgumentOrder, callback, base::Passed(&output)));
- }
- if (!copy_done_callback.is_null())
- copy_done_callback.Run();
-}
-
-void CompositingIOSurfaceMac::CopyToVideoFrame(
- const gfx::Rect& src_pixel_subrect,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) {
- base::Closure copy_done_callback;
- {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- offscreen_context_->cgl_context());
- copy_done_callback = CopyToVideoFrameWithinContext(
- src_pixel_subrect, false, target, callback);
- }
- if (!copy_done_callback.is_null())
- copy_done_callback.Run();
-}
-
-base::Closure CompositingIOSurfaceMac::CopyToVideoFrameWithinContext(
- const gfx::Rect& src_pixel_subrect,
- bool called_within_draw,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) {
- gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
- gfx::Rect(target->coded_size()), src_pixel_subrect.size());
- // Make coordinates and sizes even because we letterbox in YUV space right
- // now (see CopyRGBToVideoFrame). They need to be even for the UV samples to
- // line up correctly.
- 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);
- DCHECK_LE(region_in_frame.right(), target->coded_size().width());
- DCHECK_LE(region_in_frame.bottom(), target->coded_size().height());
-
- return CopyToSelectedOutputWithinContext(
- src_pixel_subrect, region_in_frame, called_within_draw,
- NULL, target, callback);
-}
-
-bool CompositingIOSurfaceMac::MapIOSurfaceToTextureWithContextCurrent(
- const scoped_refptr<CompositingIOSurfaceContext>& current_context,
- const gfx::Size pixel_size,
- float scale_factor,
- IOSurfaceID io_surface_handle) {
- TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture");
-
- if (!io_surface_ || io_surface_handle != io_surface_handle_)
- UnrefIOSurfaceWithContextCurrent();
-
- pixel_io_surface_size_ = pixel_size;
- scale_factor_ = scale_factor;
- dip_io_surface_size_ = gfx::ToFlooredSize(
- gfx::ScaleSize(pixel_io_surface_size_, 1.0 / scale_factor_));
-
- // Early-out if the IOSurface has not changed. Note that because IOSurface
- // sizes are rounded, the same IOSurface may have two different sizes
- // associated with it.
- if (io_surface_ && io_surface_handle == io_surface_handle_)
- return true;
-
- io_surface_.reset(IOSurfaceLookup(io_surface_handle));
- // Can fail if IOSurface with that ID was already released by the gpu
- // process.
- if (!io_surface_) {
- UnrefIOSurfaceWithContextCurrent();
- return false;
- }
-
- io_surface_handle_ = io_surface_handle;
-
- // Actual IOSurface size is rounded up to reduce reallocations during window
- // resize. Get the actual size to properly map the texture.
- gfx::Size rounded_size(IOSurfaceGetWidth(io_surface_),
- IOSurfaceGetHeight(io_surface_));
-
- glGenTextures(1, &texture_);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
- glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- CHECK_AND_SAVE_GL_ERROR();
- GLuint plane = 0;
- CGLError cgl_error = CGLTexImageIOSurface2D(
- current_context->cgl_context(),
- GL_TEXTURE_RECTANGLE_ARB,
- GL_RGBA,
- rounded_size.width(),
- rounded_size.height(),
- GL_BGRA,
- GL_UNSIGNED_INT_8_8_8_8_REV,
- io_surface_.get(),
- plane);
- glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
- if (cgl_error != kCGLNoError) {
- LOG(ERROR) << "CGLTexImageIOSurface2D: " << cgl_error;
- UnrefIOSurfaceWithContextCurrent();
- return false;
- }
- GetAndSaveGLError();
- if (gl_error_ != GL_NO_ERROR) {
- LOG(ERROR) << "GL error in MapIOSurfaceToTexture: " << gl_error_;
- UnrefIOSurfaceWithContextCurrent();
- return false;
- }
- return true;
-}
-
-void CompositingIOSurfaceMac::UnrefIOSurface() {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- offscreen_context_->cgl_context());
- UnrefIOSurfaceWithContextCurrent();
-}
-
-void CompositingIOSurfaceMac::DrawQuad(const SurfaceQuad& quad) {
- TRACE_EVENT0("gpu", "CompositingIOSurfaceMac::DrawQuad");
-
- glEnableClientState(GL_VERTEX_ARRAY); CHECK_AND_SAVE_GL_ERROR();
- glEnableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_AND_SAVE_GL_ERROR();
-
- glVertexPointer(2, GL_FLOAT, sizeof(SurfaceVertex), &quad.verts_[0].x_);
- glTexCoordPointer(2, GL_FLOAT, sizeof(SurfaceVertex), &quad.verts_[0].tx_);
- glDrawArrays(GL_QUADS, 0, 4); CHECK_AND_SAVE_GL_ERROR();
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
-
-void CompositingIOSurfaceMac::UnrefIOSurfaceWithContextCurrent() {
- if (texture_) {
- glDeleteTextures(1, &texture_);
- texture_ = 0;
- }
- pixel_io_surface_size_ = gfx::Size();
- scale_factor_ = 1;
- dip_io_surface_size_ = gfx::Size();
- io_surface_.reset();
-
- // Forget the ID, because even if it is still around when we want to use it
- // again, OSX may have reused the same ID for a new tab and we don't want to
- // blit random tab contents.
- io_surface_handle_ = 0;
-
- EvictionMarkEvicted();
-}
-
-bool CompositingIOSurfaceMac::IsAsynchronousReadbackSupported() {
- if (!HasAppleFenceExtension() && HasPixelBufferObjectExtension())
- return false;
- if (GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
- gpu::DISABLE_ASYNC_READPIXELS)) {
- return false;
- }
- return true;
-}
-
-bool CompositingIOSurfaceMac::HasBeenPoisoned() const {
- return offscreen_context_->HasBeenPoisoned();
-}
-
-base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
- const gfx::Rect& src_pixel_subrect,
- const gfx::Rect& dst_pixel_rect,
- bool called_within_draw,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output,
- const base::Callback<void(bool)>& done_callback) {
- DCHECK_NE(bitmap_output != NULL, video_frame_output.get() != NULL);
- DCHECK(!done_callback.is_null());
-
- // SWIZZLE_RGBA_FOR_ASYNC_READPIXELS workaround: Fall-back to synchronous
- // readback for SkBitmap output since the Blit shader program doesn't support
- // switchable output formats.
- const bool require_sync_copy_for_workaround = bitmap_output &&
- offscreen_context_->shader_program_cache()->rgb_to_yv12_output_format() ==
- GL_RGBA;
- const bool async_copy = !require_sync_copy_for_workaround &&
- IsAsynchronousReadbackSupported();
- TRACE_EVENT2(
- "browser", "CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext",
- "output", bitmap_output ? "SkBitmap (ARGB)" : "VideoFrame (YV12)",
- "async_readback", async_copy);
-
- const gfx::Rect src_rect = IntersectWithIOSurface(src_pixel_subrect);
- if (src_rect.IsEmpty() || dst_pixel_rect.IsEmpty())
- return base::Bind(done_callback, false);
-
- CopyContext* copy_context;
- if (copy_context_pool_.empty()) {
- // Limit the maximum number of simultaneous copies to two. Rationale:
- // Really, only one should ever be in-progress at a time, as we should
- // depend on the speed of the hardware to rate-limit the copying naturally.
- // In the asynchronous read-back case, the one currently in-flight copy is
- // highly likely to have finished by this point (i.e., it's just waiting for
- // us to make a glMapBuffer() call). Therefore, we allow a second copy to
- // be started here.
- if (copy_requests_.size() >= 2)
- return base::Bind(done_callback, false);
- copy_context = new CopyContext(offscreen_context_);
- } else {
- copy_context = copy_context_pool_.back();
- copy_context_pool_.pop_back();
- }
-
- if (!HasIOSurface())
- return base::Bind(done_callback, false);
-
- // Send transform commands to the GPU.
- copy_context->num_outputs = 0;
- if (bitmap_output) {
- if (copy_context->transformer->ResizeBilinear(
- texture_, src_rect, dst_pixel_rect.size(),
- &copy_context->output_textures[0])) {
- copy_context->output_readback_format = GL_BGRA;
- copy_context->num_outputs = 1;
- copy_context->output_texture_sizes[0] = dst_pixel_rect.size();
- }
- } else {
- if (copy_context->transformer->TransformRGBToYV12(
- texture_, src_rect, dst_pixel_rect.size(),
- &copy_context->output_textures[0],
- &copy_context->output_textures[1],
- &copy_context->output_textures[2],
- &copy_context->output_texture_sizes[0],
- &copy_context->output_texture_sizes[1])) {
- copy_context->output_readback_format =
- offscreen_context_->shader_program_cache()->
- rgb_to_yv12_output_format();
- copy_context->num_outputs = 3;
- copy_context->output_texture_sizes[2] =
- copy_context->output_texture_sizes[1];
- }
- }
- if (!copy_context->num_outputs)
- return base::Bind(done_callback, false);
-
- // In the asynchronous case, issue commands to the GPU and return a null
- // closure here. In the synchronous case, perform a blocking readback and
- // return a callback to be run outside the CGL context to indicate success.
- if (async_copy) {
- copy_context->done_callback = done_callback;
- AsynchronousReadbackForCopy(
- dst_pixel_rect, called_within_draw, copy_context, bitmap_output,
- video_frame_output);
- copy_requests_.push_back(copy_context);
- if (!finish_copy_timer_.IsRunning())
- finish_copy_timer_.Reset();
- return base::Closure();
- } else {
- const bool success = SynchronousReadbackForCopy(
- dst_pixel_rect, copy_context, bitmap_output, video_frame_output);
- return base::Bind(done_callback, success);
- }
-}
-
-void CompositingIOSurfaceMac::AsynchronousReadbackForCopy(
- const gfx::Rect& dst_pixel_rect,
- bool called_within_draw,
- CopyContext* copy_context,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output) {
- copy_context->PrepareForAsynchronousReadback();
-
- // Copy the textures to their corresponding PBO.
- for (int i = 0; i < copy_context->num_outputs; ++i) {
- TRACE_EVENT1(
- "browser", "CompositingIOSurfaceMac::AsynchronousReadbackForCopy",
- "plane", i);
-
- // Attach the output texture to the FBO.
- glBindFramebufferEXT(
- GL_READ_FRAMEBUFFER_EXT, copy_context->frame_buffers[i]);
- glFramebufferTexture2DEXT(
- GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_RECTANGLE_ARB, copy_context->output_textures[i], 0);
- DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
-
- // Create a PBO and issue an asynchronous read-back.
- glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context->pixel_buffers[i]);
- CHECK_AND_SAVE_GL_ERROR();
- glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
- copy_context->output_texture_sizes[i].GetArea() * 4,
- NULL, GL_STREAM_READ_ARB);
- CHECK_AND_SAVE_GL_ERROR();
- glReadPixels(0, 0,
- copy_context->output_texture_sizes[i].width(),
- copy_context->output_texture_sizes[i].height(),
- copy_context->output_readback_format,
- GL_UNSIGNED_INT_8_8_8_8_REV, 0);
- CHECK_AND_SAVE_GL_ERROR();
- }
-
- glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); CHECK_AND_SAVE_GL_ERROR();
-
- glSetFenceAPPLE(copy_context->fence); CHECK_GL_ERROR();
- copy_context->cycles_elapsed = 0;
-
- // When this asynchronous copy happens in a draw operaton there is no need
- // to explicitly flush because there will be a swap buffer and this flush
- // hurts performance.
- if (!called_within_draw) {
- glFlush(); CHECK_AND_SAVE_GL_ERROR();
- }
-
- copy_context->map_buffer_callback = bitmap_output ?
- base::Bind(&MapBufferToSkBitmap, bitmap_output) :
- base::Bind(&MapBufferToVideoFrame, video_frame_output, dst_pixel_rect);
-}
-
-void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished(
- bool block_until_finished) {
- if (copy_requests_.empty())
- return;
-
- std::vector<base::Closure> done_callbacks;
- {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- offscreen_context_->cgl_context());
- CheckIfAllCopiesAreFinishedWithinContext(
- block_until_finished, &done_callbacks);
- }
- for (size_t i = 0; i < done_callbacks.size(); ++i)
- done_callbacks[i].Run();
-}
-
-void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinishedWithinContext(
- bool block_until_finished,
- std::vector<base::Closure>* done_callbacks) {
- while (!copy_requests_.empty()) {
- CopyContext* const copy_context = copy_requests_.front();
-
- if (copy_context->fence && !glTestFenceAPPLE(copy_context->fence)) {
- CHECK_AND_SAVE_GL_ERROR();
- // Doing a glFinishFenceAPPLE can cause transparent window flashes when
- // switching tabs, so only do it when required.
- if (block_until_finished) {
- glFinishFenceAPPLE(copy_context->fence);
- CHECK_AND_SAVE_GL_ERROR();
- } else if (copy_context->cycles_elapsed < kFinishCopyRetryCycles) {
- ++copy_context->cycles_elapsed;
- // This copy has not completed there is no need to test subsequent
- // requests.
- break;
- }
- }
- CHECK_AND_SAVE_GL_ERROR();
-
- bool success = true;
- for (int i = 0; success && i < copy_context->num_outputs; ++i) {
- TRACE_EVENT1(
- "browser",
- "CompositingIOSurfaceMac::CheckIfAllCopiesAreFinishedWithinContext",
- "plane", i);
-
- glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context->pixel_buffers[i]);
- CHECK_AND_SAVE_GL_ERROR();
-
- void* buf = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
- CHECK_AND_SAVE_GL_ERROR();
- success &= copy_context->map_buffer_callback.Run(buf, i);
- glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); CHECK_AND_SAVE_GL_ERROR();
- }
- copy_context->map_buffer_callback.Reset();
- glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
-
- copy_requests_.pop_front();
- done_callbacks->push_back(base::Bind(copy_context->done_callback, success));
- copy_context->done_callback.Reset();
- copy_context_pool_.push_back(copy_context);
- }
- if (copy_requests_.empty())
- finish_copy_timer_.Stop();
-
- CHECK(copy_requests_.empty() || !block_until_finished);
-}
-
-bool CompositingIOSurfaceMac::SynchronousReadbackForCopy(
- const gfx::Rect& dst_pixel_rect,
- CopyContext* copy_context,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output) {
- bool success = true;
- copy_context->PrepareReadbackFramebuffers();
- for (int i = 0; i < copy_context->num_outputs; ++i) {
- TRACE_EVENT1(
- "browser", "CompositingIOSurfaceMac::SynchronousReadbackForCopy",
- "plane", i);
-
- // Attach the output texture to the FBO.
- glBindFramebufferEXT(
- GL_READ_FRAMEBUFFER_EXT, copy_context->frame_buffers[i]);
- glFramebufferTexture2DEXT(
- GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_RECTANGLE_ARB, copy_context->output_textures[i], 0);
- DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
-
- // Blocking read-back of pixels from textures.
- void* buf;
- // When data must be transferred into a VideoFrame one scanline at a time,
- // it is necessary to allocate a separate buffer for glReadPixels() that can
- // be populated one-shot.
- //
- // TODO(miu): Don't keep allocating/deleting this buffer for every frame.
- // Keep it cached, allocated on first use.
- scoped_ptr<uint32[]> temp_readback_buffer;
- if (bitmap_output) {
- // The entire SkBitmap is populated, never a region within. So, read the
- // texture directly into the bitmap's pixel memory.
- buf = bitmap_output->getPixels();
- } else {
- // Optimization: If the VideoFrame is letterboxed (not pillarboxed), and
- // its stride is equal to the stride of the data being read back, then
- // readback directly into the VideoFrame's buffer to save a round of
- // memcpy'ing.
- //
- // TODO(miu): Move these calculations into VideoFrame (need a CalcOffset()
- // method). http://crbug.com/219779
- const int src_stride = copy_context->output_texture_sizes[i].width() * 4;
- const int dst_stride = video_frame_output->stride(i);
- if (src_stride == dst_stride && dst_pixel_rect.x() == 0) {
- const int y_offset = dst_pixel_rect.y() / (i == 0 ? 1 : 2);
- buf = video_frame_output->data(i) + y_offset * dst_stride;
- } else {
- // Create and readback into a temporary buffer because the data must be
- // transferred to VideoFrame's pixel memory one scanline at a time.
- temp_readback_buffer.reset(
- new uint32[copy_context->output_texture_sizes[i].GetArea()]);
- buf = temp_readback_buffer.get();
- }
- }
- glReadPixels(0, 0,
- copy_context->output_texture_sizes[i].width(),
- copy_context->output_texture_sizes[i].height(),
- copy_context->output_readback_format,
- GL_UNSIGNED_INT_8_8_8_8_REV, buf);
- CHECK_AND_SAVE_GL_ERROR();
- if (video_frame_output.get()) {
- if (!temp_readback_buffer) {
- // Apply letterbox black-out around view region.
- media::LetterboxYUV(video_frame_output.get(), dst_pixel_rect);
- } else {
- // Copy from temporary buffer and fully render the VideoFrame.
- success &= MapBufferToVideoFrame(video_frame_output, dst_pixel_rect,
- temp_readback_buffer.get(), i);
- }
- }
- }
-
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); CHECK_AND_SAVE_GL_ERROR();
- copy_context_pool_.push_back(copy_context);
- return success;
-}
-
-void CompositingIOSurfaceMac::FailAllCopies() {
- for (size_t i = 0; i < copy_requests_.size(); ++i) {
- copy_requests_[i]->map_buffer_callback.Reset();
-
- base::Callback<void(bool)>& done_callback =
- copy_requests_[i]->done_callback;
- if (!done_callback.is_null()) {
- done_callback.Run(false);
- done_callback.Reset();
- }
- }
-}
-
-void CompositingIOSurfaceMac::DestroyAllCopyContextsWithinContext() {
- // Move all in-flight copies, if any, back into the pool. Then, destroy all
- // the CopyContexts in the pool.
- copy_context_pool_.insert(copy_context_pool_.end(),
- copy_requests_.begin(), copy_requests_.end());
- copy_requests_.clear();
- while (!copy_context_pool_.empty()) {
- scoped_ptr<CopyContext> copy_context(copy_context_pool_.back());
- copy_context_pool_.pop_back();
- copy_context->ReleaseCachedGLObjects();
- }
-}
-
-gfx::Rect CompositingIOSurfaceMac::IntersectWithIOSurface(
- const gfx::Rect& rect) const {
- return gfx::IntersectRects(rect,
- gfx::ToEnclosingRect(gfx::Rect(pixel_io_surface_size_)));
-}
-
-GLenum CompositingIOSurfaceMac::GetAndSaveGLError() {
- GLenum gl_error = glGetError();
- if (gl_error_ == GL_NO_ERROR)
- gl_error_ = gl_error;
- return gl_error;
-}
-
-void CompositingIOSurfaceMac::EvictionMarkUpdated() {
- EvictionMarkEvicted();
- eviction_queue_.Get().push_back(this);
- eviction_queue_iterator_ = --eviction_queue_.Get().end();
- eviction_has_been_drawn_since_updated_ = false;
- EvictionScheduleDoEvict();
-}
-
-void CompositingIOSurfaceMac::EvictionMarkEvicted() {
- if (eviction_queue_iterator_ == eviction_queue_.Get().end())
- return;
- eviction_queue_.Get().erase(eviction_queue_iterator_);
- eviction_queue_iterator_ = eviction_queue_.Get().end();
- eviction_has_been_drawn_since_updated_ = false;
-}
-
-// static
-void CompositingIOSurfaceMac::EvictionScheduleDoEvict() {
- if (eviction_scheduled_)
- return;
- if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
- return;
-
- eviction_scheduled_ = true;
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&CompositingIOSurfaceMac::EvictionDoEvict));
-}
-
-// static
-void CompositingIOSurfaceMac::EvictionDoEvict() {
- eviction_scheduled_ = false;
- // Walk the list of allocated surfaces from least recently used to most
- // recently used.
- for (EvictionQueue::iterator it = eviction_queue_.Get().begin();
- it != eviction_queue_.Get().end();) {
- CompositingIOSurfaceMac* surface = *it;
- ++it;
-
- // If the number of IOSurfaces allocated is less than the threshold,
- // stop walking the list of surfaces.
- if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
- break;
-
- // Don't evict anything that has not yet been drawn.
- if (!surface->eviction_has_been_drawn_since_updated_)
- continue;
-
- // Don't evict anything with pending copy requests.
- if (!surface->copy_requests_.empty())
- continue;
-
- // Evict the surface.
- surface->UnrefIOSurface();
- }
-}
-
-// static
-base::LazyInstance<CompositingIOSurfaceMac::EvictionQueue>
- CompositingIOSurfaceMac::eviction_queue_;
-
-// static
-bool CompositingIOSurfaceMac::eviction_scheduled_ = false;
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_shader_programs_mac.cc b/chromium/content/browser/renderer_host/compositing_iosurface_shader_programs_mac.cc
deleted file mode 100644
index 753c180dbf5..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_shader_programs_mac.cc
+++ /dev/null
@@ -1,448 +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/compositing_iosurface_shader_programs_mac.h"
-
-#include <string>
-#include <OpenGL/gl.h>
-
-#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/values.h"
-#include "content/browser/gpu/gpu_data_manager_impl.h"
-#include "gpu/config/gpu_driver_bug_workaround_type.h"
-
-namespace content {
-
-namespace {
-
-// Convenience macro allowing GLSL programs to be specified inline, and to be
-// automatically converted into string form by the C preprocessor.
-#define GLSL_PROGRAM_AS_STRING(shader_code) #shader_code
-
-// As required by the spec, add the version directive to the beginning of each
-// program to activate the expected syntax and built-in features. GLSL version
-// 1.2 is the latest version supported by MacOS 10.6.
-const char kVersionDirective[] = "#version 120\n";
-
-// Allow switchable output swizzling from RGBToYV12 fragment shaders (needed for
-// workaround; see comments in CompositingIOSurfaceShaderPrograms ctor).
-const char kOutputSwizzleMacroNormal[] = "#define OUTPUT_PIXEL_ORDERING bgra\n";
-const char kOutputSwizzleMacroSwapRB[] = "#define OUTPUT_PIXEL_ORDERING rgba\n";
-
-// Only the bare-bones calculations here for speed.
-const char kvsBlit[] = GLSL_PROGRAM_AS_STRING(
- varying vec2 texture_coord;
- void main() {
- gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
- texture_coord = gl_MultiTexCoord0.xy;
- }
-);
-
-// Just samples the texture.
-const char kfsBlit[] = GLSL_PROGRAM_AS_STRING(
- uniform sampler2DRect texture_;
- varying vec2 texture_coord;
- void main() {
- gl_FragColor = vec4(texture2DRect(texture_, texture_coord).rgb, 1.0);
- }
-);
-
-
-// Only calculates position.
-const char kvsSolidWhite[] = GLSL_PROGRAM_AS_STRING(
- void main() {
- gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
- }
-);
-
-// Always white.
-const char kfsSolidWhite[] = GLSL_PROGRAM_AS_STRING(
- void main() {
- gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
- }
-);
-
-
-///////////////////////////////////////////////////////////////////////
-// RGB24 to YV12 in two passes; writing two 8888 targets each pass.
-//
-// YV12 is full-resolution luma and half-resolution blue/red chroma.
-//
-// (original)
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// XRGB XRGB XRGB XRGB XRGB XRGB XRGB XRGB
-// |
-// | (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
-//
-///////////////////////////////////////////////////////////////////////
-
-// Phase one of RGB24->YV12 conversion: vsFetch4Pixels/fsConvertRGBtoY8UV44
-//
-// Writes four source pixels at a time to a full-size Y plane and a half-width
-// interleaved UV plane. After execution, the Y plane is complete but the UV
-// planes still need to be de-interleaved and vertically scaled.
-const char kRGBtoYV12_vsFetch4Pixels[] = GLSL_PROGRAM_AS_STRING(
- uniform float texel_scale_x_;
- varying vec2 texture_coord0;
- varying vec2 texture_coord1;
- varying vec2 texture_coord2;
- varying vec2 texture_coord3;
- void main() {
- gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
-
- vec2 texcoord_base = gl_MultiTexCoord0.xy;
- vec2 one_texel_x = vec2(texel_scale_x_, 0.0);
- texture_coord0 = texcoord_base - 1.5 * one_texel_x;
- texture_coord1 = texcoord_base - 0.5 * one_texel_x;
- texture_coord2 = texcoord_base + 0.5 * one_texel_x;
- texture_coord3 = texcoord_base + 1.5 * one_texel_x;
- }
-);
-
-const char kRGBtoYV12_fsConvertRGBtoY8UV44[] = GLSL_PROGRAM_AS_STRING(
- const vec3 rgb_to_y = vec3(0.257, 0.504, 0.098);
- const vec3 rgb_to_u = vec3(-0.148, -0.291, 0.439);
- const vec3 rgb_to_v = vec3(0.439, -0.368, -0.071);
- const float y_bias = 0.0625;
- const float uv_bias = 0.5;
- uniform sampler2DRect texture_;
- varying vec2 texture_coord0;
- varying vec2 texture_coord1;
- varying vec2 texture_coord2;
- varying vec2 texture_coord3;
- void main() {
- // Load the four texture samples.
- vec3 pixel0 = texture2DRect(texture_, texture_coord0).rgb;
- vec3 pixel1 = texture2DRect(texture_, texture_coord1).rgb;
- vec3 pixel2 = texture2DRect(texture_, texture_coord2).rgb;
- vec3 pixel3 = texture2DRect(texture_, texture_coord3).rgb;
-
- // RGB -> Y conversion (x4).
- vec4 yyyy = vec4(dot(pixel0, rgb_to_y),
- dot(pixel1, rgb_to_y),
- dot(pixel2, rgb_to_y),
- dot(pixel3, rgb_to_y)) + y_bias;
-
- // Average adjacent texture samples while converting RGB->UV. This is the
- // same as color converting then averaging, but slightly less math. These
- // values will be in the range [-0.439f, +0.439f] and still need to have
- // the bias term applied.
- vec3 blended_pixel0 = pixel0 + pixel1;
- vec3 blended_pixel1 = pixel2 + pixel3;
- vec2 uu = vec2(dot(blended_pixel0, rgb_to_u),
- dot(blended_pixel1, rgb_to_u)) / 2.0;
- vec2 vv = vec2(dot(blended_pixel0, rgb_to_v),
- dot(blended_pixel1, rgb_to_v)) / 2.0;
-
- gl_FragData[0] = yyyy.OUTPUT_PIXEL_ORDERING;
- gl_FragData[1] = vec4(uu, vv) + uv_bias;
- }
-);
-
-// Phase two of RGB24->YV12 conversion: vsFetch2Pixels/fsConvertUV44toU2V2
-//
-// Deals with UV only. Input is two UUVV quads. The pixels have already been
-// scaled horizontally prior to this point, and vertical scaling will now happen
-// via bilinear interpolation during texture sampling. Output is two color
-// planes U and V, packed four pixels to a "RGBA" quad.
-const char kRGBtoYV12_vsFetch2Pixels[] = GLSL_PROGRAM_AS_STRING(
- varying vec2 texture_coord0;
- varying vec2 texture_coord1;
- void main() {
- gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
-
- vec2 texcoord_base = gl_MultiTexCoord0.xy;
- texture_coord0 = texcoord_base - vec2(0.5, 0.0);
- texture_coord1 = texcoord_base + vec2(0.5, 0.0);
- }
-);
-
-const char kRGBtoYV12_fsConvertUV44toU2V2[] = GLSL_PROGRAM_AS_STRING(
- uniform sampler2DRect texture_;
- varying vec2 texture_coord0;
- varying vec2 texture_coord1;
- void main() {
- // 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.
- vec4 lo_uuvv = texture2DRect(texture_, texture_coord0);
- vec4 hi_uuvv = texture2DRect(texture_, texture_coord1);
- gl_FragData[0] = vec4(lo_uuvv.rg, hi_uuvv.rg).OUTPUT_PIXEL_ORDERING;
- gl_FragData[1] = vec4(lo_uuvv.ba, hi_uuvv.ba).OUTPUT_PIXEL_ORDERING;
- }
-);
-
-
-enum ShaderProgram {
- SHADER_PROGRAM_BLIT = 0,
- SHADER_PROGRAM_SOLID_WHITE,
- SHADER_PROGRAM_RGB_TO_YV12__1_OF_2,
- SHADER_PROGRAM_RGB_TO_YV12__2_OF_2,
- NUM_SHADER_PROGRAMS
-};
-
-// The code snippets that together make up an entire vertex shader program.
-const char* kVertexShaderSourceCodeMap[] = {
- // SHADER_PROGRAM_BLIT
- kvsBlit,
- // SHADER_PROGRAM_SOLID_WHITE
- kvsSolidWhite,
-
- // SHADER_PROGRAM_RGB_TO_YV12__1_OF_2
- kRGBtoYV12_vsFetch4Pixels,
- // SHADER_PROGRAM_RGB_TO_YV12__2_OF_2
- kRGBtoYV12_vsFetch2Pixels,
-};
-
-// The code snippets that together make up an entire fragment shader program.
-const char* kFragmentShaderSourceCodeMap[] = {
- // SHADER_PROGRAM_BLIT
- kfsBlit,
- // SHADER_PROGRAM_SOLID_WHITE
- kfsSolidWhite,
-
- // SHADER_PROGRAM_RGB_TO_YV12__1_OF_2
- kRGBtoYV12_fsConvertRGBtoY8UV44,
- // SHADER_PROGRAM_RGB_TO_YV12__2_OF_2
- kRGBtoYV12_fsConvertUV44toU2V2,
-};
-
-GLuint CompileShaderGLSL(ShaderProgram shader_program, GLenum shader_type,
- bool output_swap_rb) {
- TRACE_EVENT2("gpu", "CompileShaderGLSL",
- "program", shader_program,
- "type", shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment");
-
- DCHECK_GE(shader_program, 0);
- DCHECK_LT(shader_program, NUM_SHADER_PROGRAMS);
-
- const GLuint shader = glCreateShader(shader_type);
- DCHECK_NE(shader, 0u);
-
- // Select and compile the shader program source code.
- if (shader_type == GL_VERTEX_SHADER) {
- const GLchar* source_snippets[] = {
- kVersionDirective,
- kVertexShaderSourceCodeMap[shader_program],
- };
- glShaderSource(shader, arraysize(source_snippets), source_snippets, NULL);
- } else {
- DCHECK(shader_type == GL_FRAGMENT_SHADER);
- const GLchar* source_snippets[] = {
- kVersionDirective,
- output_swap_rb ? kOutputSwizzleMacroSwapRB : kOutputSwizzleMacroNormal,
- kFragmentShaderSourceCodeMap[shader_program],
- };
- glShaderSource(shader, arraysize(source_snippets), source_snippets, NULL);
- }
- glCompileShader(shader);
-
- // Check for successful compilation. On error in debug builds, pull the info
- // log and emit the compiler messages.
- GLint error;
- glGetShaderiv(shader, GL_COMPILE_STATUS, &error);
- if (error != GL_TRUE) {
-#ifndef NDEBUG
- static const int kMaxInfoLogLength = 8192;
- scoped_ptr<char[]> buffer(new char[kMaxInfoLogLength]);
- GLsizei length_returned = 0;
- glGetShaderInfoLog(shader, kMaxInfoLogLength - 1, &length_returned,
- buffer.get());
- buffer[kMaxInfoLogLength - 1] = '\0';
- DLOG(ERROR) << "Failed to compile "
- << (shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment")
- << " shader for program " << shader_program << ":\n"
- << buffer.get()
- << (length_returned >= kMaxInfoLogLength ?
- "\n*** TRUNCATED! ***" : "");
-#endif
- glDeleteShader(shader);
- return 0;
- }
-
- // Success!
- return shader;
-}
-
-GLuint CompileAndLinkProgram(ShaderProgram which, bool output_swap_rb) {
- TRACE_EVENT1("gpu", "CompileAndLinkProgram", "program", which);
-
- // Compile and link a new shader program.
- const GLuint vertex_shader =
- CompileShaderGLSL(which, GL_VERTEX_SHADER, false);
- const GLuint fragment_shader =
- CompileShaderGLSL(which, GL_FRAGMENT_SHADER, output_swap_rb);
- const GLuint program = glCreateProgram();
- DCHECK_NE(program, 0u);
- glAttachShader(program, vertex_shader);
- glAttachShader(program, fragment_shader);
- glLinkProgram(program);
-
- // Flag shaders for deletion so that they will be deleted automatically when
- // the program is later deleted.
- glDeleteShader(vertex_shader);
- glDeleteShader(fragment_shader);
-
- // Check that the program successfully linked.
- GLint error = GL_FALSE;
- glGetProgramiv(program, GL_LINK_STATUS, &error);
- if (error != GL_TRUE) {
- glDeleteProgram(program);
- return 0;
- }
- return program;
-}
-
-} // namespace
-
-
-CompositingIOSurfaceShaderPrograms::CompositingIOSurfaceShaderPrograms()
- : rgb_to_yv12_output_format_(GL_BGRA) {
- COMPILE_ASSERT(kNumShaderPrograms == NUM_SHADER_PROGRAMS,
- header_constant_disagrees_with_enum);
- COMPILE_ASSERT(arraysize(kVertexShaderSourceCodeMap) == NUM_SHADER_PROGRAMS,
- vertex_shader_source_code_map_incorrect_size);
- COMPILE_ASSERT(arraysize(kFragmentShaderSourceCodeMap) == NUM_SHADER_PROGRAMS,
- fragment_shader_source_code_map_incorrect_size);
-
- memset(shader_programs_, 0, sizeof(shader_programs_));
- for (size_t i = 0; i < arraysize(texture_var_locations_); ++i)
- texture_var_locations_[i] = -1;
- for (size_t i = 0; i < arraysize(texel_scale_x_var_locations_); ++i)
- texel_scale_x_var_locations_[i] = -1;
-
- // Look for the swizzle_rgba_for_async_readpixels driver bug workaround and
- // modify rgb_to_yv12_output_format_ if necessary.
- // See: http://crbug.com/265115
- GpuDataManagerImpl* const manager = GpuDataManagerImpl::GetInstance();
- if (manager) {
- base::ListValue workarounds;
- manager->GetDriverBugWorkarounds(&workarounds);
- base::ListValue::const_iterator it = workarounds.Find(
- base::StringValue(gpu::GpuDriverBugWorkaroundTypeToString(
- gpu::SWIZZLE_RGBA_FOR_ASYNC_READPIXELS)));
- if (it != workarounds.end())
- rgb_to_yv12_output_format_ = GL_RGBA;
- }
- DVLOG(1) << "Using RGBToYV12 fragment shader output format: "
- << (rgb_to_yv12_output_format_ == GL_BGRA ? "BGRA" : "RGBA");
-}
-
-CompositingIOSurfaceShaderPrograms::~CompositingIOSurfaceShaderPrograms() {
-#ifndef NDEBUG
- for (size_t i = 0; i < arraysize(shader_programs_); ++i)
- DCHECK_EQ(shader_programs_[i], 0u) << "Failed to call Reset().";
-#endif
-}
-
-void CompositingIOSurfaceShaderPrograms::Reset() {
- for (size_t i = 0; i < arraysize(shader_programs_); ++i) {
- if (shader_programs_[i] != 0u) {
- glDeleteProgram(shader_programs_[i]);
- shader_programs_[i] = 0u;
- }
- }
- for (size_t i = 0; i < arraysize(texture_var_locations_); ++i)
- texture_var_locations_[i] = -1;
- for (size_t i = 0; i < arraysize(texel_scale_x_var_locations_); ++i)
- texel_scale_x_var_locations_[i] = -1;
-}
-
-bool CompositingIOSurfaceShaderPrograms::UseBlitProgram() {
- const GLuint program = GetShaderProgram(SHADER_PROGRAM_BLIT);
- if (program == 0u)
- return false;
- glUseProgram(program);
- BindUniformTextureVariable(SHADER_PROGRAM_BLIT, 0);
- return true;
-}
-
-bool CompositingIOSurfaceShaderPrograms::UseSolidWhiteProgram() {
- const GLuint program = GetShaderProgram(SHADER_PROGRAM_SOLID_WHITE);
- if (program == 0u)
- return false;
- glUseProgram(program);
- return true;
-}
-
-bool CompositingIOSurfaceShaderPrograms::UseRGBToYV12Program(
- int pass_number, float texel_scale_x) {
- const int which = SHADER_PROGRAM_RGB_TO_YV12__1_OF_2 + pass_number - 1;
- DCHECK_GE(which, SHADER_PROGRAM_RGB_TO_YV12__1_OF_2);
- DCHECK_LE(which, SHADER_PROGRAM_RGB_TO_YV12__2_OF_2);
-
- const GLuint program = GetShaderProgram(which);
- if (program == 0u)
- return false;
- glUseProgram(program);
- BindUniformTextureVariable(which, 0);
- if (which == SHADER_PROGRAM_RGB_TO_YV12__1_OF_2) {
- BindUniformTexelScaleXVariable(which, texel_scale_x);
- } else {
- // The second pass doesn't have a texel_scale_x uniform variable since it's
- // never supposed to be doing any scaling (i.e., outside of the usual
- // 2x2-->1x1 that's already built into the process).
- DCHECK_EQ(texel_scale_x, 1.0f);
- }
- return true;
-}
-
-void CompositingIOSurfaceShaderPrograms::SetOutputFormatForTesting(
- GLenum format) {
- rgb_to_yv12_output_format_ = format;
- Reset();
-}
-
-GLuint CompositingIOSurfaceShaderPrograms::GetShaderProgram(int which) {
- if (shader_programs_[which] == 0u) {
- shader_programs_[which] =
- CompileAndLinkProgram(static_cast<ShaderProgram>(which),
- rgb_to_yv12_output_format_ == GL_RGBA);
- DCHECK_NE(shader_programs_[which], 0u)
- << "Failed to create ShaderProgram " << which;
- }
- return shader_programs_[which];
-}
-
-void CompositingIOSurfaceShaderPrograms::BindUniformTextureVariable(
- int which, int texture_unit_offset) {
- if (texture_var_locations_[which] == -1) {
- texture_var_locations_[which] =
- glGetUniformLocation(GetShaderProgram(which), "texture_");
- DCHECK_NE(texture_var_locations_[which], -1)
- << "Failed to find location of uniform variable: texture_";
- }
- glUniform1i(texture_var_locations_[which], texture_unit_offset);
-}
-
-void CompositingIOSurfaceShaderPrograms::BindUniformTexelScaleXVariable(
- int which, float texel_scale_x) {
- if (texel_scale_x_var_locations_[which] == -1) {
- texel_scale_x_var_locations_[which] =
- glGetUniformLocation(GetShaderProgram(which), "texel_scale_x_");
- DCHECK_NE(texel_scale_x_var_locations_[which], -1)
- << "Failed to find location of uniform variable: texel_scale_x_";
- }
- glUniform1f(texel_scale_x_var_locations_[which], texel_scale_x);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h b/chromium/content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h
deleted file mode 100644
index de1987f2e03..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h
+++ /dev/null
@@ -1,81 +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_COMPOSITING_IOSURFACE_SHADER_PROGRAMS_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_SHADER_PROGRAMS_MAC_H_
-
-#include <OpenGL/gl.h>
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-
-namespace content {
-
-// Provides caching of the compile-and-link step for shader programs at runtime
-// since, once compiled and linked, the programs can be shared. Callers invoke
-// one of the UseXXX() methods to glUseProgram() the program and have its
-// uniform variables bound with the given parameters.
-//
-// Note: All public methods must be invoked within the the same GL context!
-class CompositingIOSurfaceShaderPrograms {
- public:
- CompositingIOSurfaceShaderPrograms();
- ~CompositingIOSurfaceShaderPrograms();
-
- // Reset the cache, deleting any references to currently-cached shader
- // programs. This must be called within an active OpenGL context just before
- // destruction.
- void Reset();
-
- // Begin using the "blit" program, which is set up to sample the texture at
- // GL_TEXTURE_0. Returns false on error.
- bool UseBlitProgram();
-
- // Begin using the program that just draws solid white very efficiently.
- // Returns false on error.
- bool UseSolidWhiteProgram();
-
- // Begin using one of the two RGB-to-YV12 color conversion programs, as
- // specified by |pass_number| 1 or 2. The programs will sample the texture at
- // GL_TEXTURE0, and account for scaling in the X direction by |texel_scale_x|.
- // Returns false on error.
- bool UseRGBToYV12Program(int pass_number, float texel_scale_x);
-
- // |format| argument to use for glReadPixels() when reading back textures
- // generated by the RGBToYV12 program.
- GLenum rgb_to_yv12_output_format() const {
- return rgb_to_yv12_output_format_;
- }
-
- protected:
- FRIEND_TEST_ALL_PREFIXES(CompositingIOSurfaceTransformerTest,
- TransformsRGBToYV12);
-
- // Side effect: Calls Reset(), deleting any cached programs.
- void SetOutputFormatForTesting(GLenum format);
-
- private:
- enum { kNumShaderPrograms = 4 };
-
- // Helper methods to cache uniform variable locations.
- GLuint GetShaderProgram(int which);
- void BindUniformTextureVariable(int which, int texture_unit_offset);
- void BindUniformTexelScaleXVariable(int which, float texel_scale_x);
-
- // Cached values for previously-compiled/linked shader programs, and the
- // locations of their uniform variables.
- GLuint shader_programs_[kNumShaderPrograms];
- GLint texture_var_locations_[kNumShaderPrograms];
- GLint texel_scale_x_var_locations_[kNumShaderPrograms];
-
- // Byte order of the quads generated by the RGBToYV12 shader program. Must
- // always be GL_BGRA (default) or GL_RGBA (workaround case).
- GLenum rgb_to_yv12_output_format_;
-
- DISALLOW_COPY_AND_ASSIGN(CompositingIOSurfaceShaderPrograms);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_SHADER_PROGRAMS_MAC_H_
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac.cc b/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac.cc
deleted file mode 100644
index 2e0401ff476..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac.cc
+++ /dev/null
@@ -1,300 +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/compositing_iosurface_transformer_mac.h"
-
-#include <algorithm>
-
-#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
-#include "base/logging.h"
-#include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/size.h"
-
-namespace content {
-
-namespace {
-
-const GLenum kColorAttachments[] = {
- GL_COLOR_ATTACHMENT0_EXT,
- GL_COLOR_ATTACHMENT1_EXT
-};
-
-// Set viewport and model/projection matrices for drawing to a framebuffer of
-// size dst_size, with coordinates starting at (0, 0).
-void SetTransformationsForOffScreenRendering(const gfx::Size& dst_size) {
- glViewport(0, 0, dst_size.width(), dst_size.height());
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0, dst_size.width(), 0, dst_size.height(), -1, 1);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-}
-
-// Configure texture sampling parameters.
-void SetTextureParameters(GLenum target, GLint min_mag_filter, GLint wrap) {
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_mag_filter);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, min_mag_filter);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
-}
-
-// Draw the currently-bound texture. The src region is applied to the entire
-// destination framebuffer of the given size. Specify |flip_y| is the src
-// texture is upside-down relative to the destination.
-//
-// Assumption: The orthographic projection is set up as
-// (0,0)x(dst_width,dst_height).
-void DrawQuad(float src_x, float src_y, float src_width, float src_height,
- bool flip_y, float dst_width, float dst_height) {
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
- float vertices[4][2] = {
- { 0.0f, dst_height },
- { 0.0f, 0.0f },
- { dst_width, 0.0f },
- { dst_width, dst_height }
- };
- glVertexPointer(arraysize(vertices[0]), GL_FLOAT, sizeof(vertices[0]),
- vertices);
-
- float tex_coords[4][2] = {
- { src_x, src_y + src_height },
- { src_x, src_y },
- { src_x + src_width, src_y },
- { src_x + src_width, src_y + src_height }
- };
- if (flip_y) {
- std::swap(tex_coords[0][1], tex_coords[1][1]);
- std::swap(tex_coords[2][1], tex_coords[3][1]);
- }
- glTexCoordPointer(arraysize(tex_coords[0]), GL_FLOAT, sizeof(tex_coords[0]),
- tex_coords);
-
- COMPILE_ASSERT(arraysize(vertices) == arraysize(tex_coords),
- same_number_of_points_in_both);
- glDrawArrays(GL_QUADS, 0, arraysize(vertices));
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
-
-} // namespace
-
-CompositingIOSurfaceTransformer::CompositingIOSurfaceTransformer(
- GLenum texture_target, bool src_texture_needs_y_flip,
- CompositingIOSurfaceShaderPrograms* shader_program_cache)
- : texture_target_(texture_target),
- src_texture_needs_y_flip_(src_texture_needs_y_flip),
- shader_program_cache_(shader_program_cache),
- frame_buffer_(0) {
- DCHECK(texture_target_ == GL_TEXTURE_RECTANGLE_ARB)
- << "Fragment shaders currently only support RECTANGLE textures.";
- DCHECK(shader_program_cache_);
-
- memset(textures_, 0, sizeof(textures_));
-
- // The RGB-to-YV12 transform requires that the driver/hardware supports
- // multiple draw buffers.
- GLint max_draw_buffers = 1;
- glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
- system_supports_multiple_draw_buffers_ = (max_draw_buffers >= 2);
-}
-
-CompositingIOSurfaceTransformer::~CompositingIOSurfaceTransformer() {
- for (int i = 0; i < NUM_CACHED_TEXTURES; ++i)
- DCHECK_EQ(textures_[i], 0u) << "Failed to call ReleaseCachedGLObjects().";
- DCHECK_EQ(frame_buffer_, 0u) << "Failed to call ReleaseCachedGLObjects().";
-}
-
-void CompositingIOSurfaceTransformer::ReleaseCachedGLObjects() {
- for (int i = 0; i < NUM_CACHED_TEXTURES; ++i) {
- if (textures_[i]) {
- glDeleteTextures(1, &textures_[i]);
- textures_[i] = 0;
- texture_sizes_[i] = gfx::Size();
- }
- }
- if (frame_buffer_) {
- glDeleteFramebuffersEXT(1, &frame_buffer_);
- frame_buffer_ = 0;
- }
-}
-
-bool CompositingIOSurfaceTransformer::ResizeBilinear(
- GLuint src_texture, const gfx::Rect& src_subrect, const gfx::Size& dst_size,
- GLuint* texture) {
- if (src_subrect.IsEmpty() || dst_size.IsEmpty())
- return false;
-
- glActiveTexture(GL_TEXTURE0);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
-
- PrepareTexture(RGBA_OUTPUT, dst_size);
- PrepareFramebuffer();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame_buffer_);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- texture_target_, textures_[RGBA_OUTPUT], 0);
- DCHECK(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
-
- glBindTexture(texture_target_, src_texture);
- SetTextureParameters(
- texture_target_, src_subrect.size() == dst_size ? GL_NEAREST : GL_LINEAR,
- GL_CLAMP_TO_EDGE);
-
- const bool prepared = shader_program_cache_->UseBlitProgram();
- DCHECK(prepared);
- SetTransformationsForOffScreenRendering(dst_size);
- DrawQuad(src_subrect.x(), src_subrect.y(),
- src_subrect.width(), src_subrect.height(),
- src_texture_needs_y_flip_,
- dst_size.width(), dst_size.height());
- glUseProgram(0);
-
- glBindTexture(texture_target_, 0);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-
- *texture = textures_[RGBA_OUTPUT];
- return true;
-}
-
-bool CompositingIOSurfaceTransformer::TransformRGBToYV12(
- GLuint src_texture,
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- GLuint* texture_y,
- GLuint* texture_u,
- GLuint* texture_v,
- gfx::Size* packed_y_size,
- gfx::Size* packed_uv_size) {
- if (!system_supports_multiple_draw_buffers_)
- return false;
- if (src_subrect.IsEmpty() || dst_size.IsEmpty())
- return false;
-
- TRACE_EVENT0("gpu", "TransformRGBToYV12");
-
- glActiveTexture(GL_TEXTURE0);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
-
- // Resize output textures for each plane, and for the intermediate UUVV one
- // that becomes an input into pass #2. |packed_y_size| is the size of the Y
- // output texture, where its width is 1/4 the number of Y pixels because 4 Y
- // pixels are packed into a single quad. |packed_uv_size| is half the size of
- // Y in both dimensions, rounded up.
- *packed_y_size = gfx::Size((dst_size.width() + 3) / 4, dst_size.height());
- *packed_uv_size = gfx::Size((packed_y_size->width() + 1) / 2,
- (packed_y_size->height() + 1) / 2);
- PrepareTexture(Y_PLANE_OUTPUT, *packed_y_size);
- PrepareTexture(UUVV_INTERMEDIATE, *packed_y_size);
- PrepareTexture(U_PLANE_OUTPUT, *packed_uv_size);
- PrepareTexture(V_PLANE_OUTPUT, *packed_uv_size);
-
- /////////////////////////////////////////
- // Pass 1: RGB --(scaled)--> YYYY + UUVV
- PrepareFramebuffer();
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame_buffer_);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- texture_target_, textures_[Y_PLANE_OUTPUT], 0);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,
- texture_target_, textures_[UUVV_INTERMEDIATE], 0);
- DCHECK(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
- glDrawBuffers(2, kColorAttachments);
-
- // Read from |src_texture|. Enable bilinear filtering only if scaling is
- // required. The filtering will take place entirely in the first pass.
- glBindTexture(texture_target_, src_texture);
- SetTextureParameters(
- texture_target_, src_subrect.size() == dst_size ? GL_NEAREST : GL_LINEAR,
- GL_CLAMP_TO_EDGE);
-
- // Use the first-pass shader program and draw the scene.
- const bool prepared_pass_1 = shader_program_cache_->UseRGBToYV12Program(
- 1,
- static_cast<float>(src_subrect.width()) / dst_size.width());
- DCHECK(prepared_pass_1);
- SetTransformationsForOffScreenRendering(*packed_y_size);
- DrawQuad(src_subrect.x(), src_subrect.y(),
- ((packed_y_size->width() * 4.0f) / dst_size.width()) *
- src_subrect.width(),
- src_subrect.height(),
- src_texture_needs_y_flip_,
- packed_y_size->width(), packed_y_size->height());
-
- /////////////////////////////////////////
- // Pass 2: UUVV -> UUUU + VVVV
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- texture_target_, textures_[U_PLANE_OUTPUT], 0);
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,
- texture_target_, textures_[V_PLANE_OUTPUT], 0);
- DCHECK(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
-
- // Read from the intermediate UUVV texture. The second pass uses bilinear
- // minification to achieve vertical scaling, so enable it always.
- glBindTexture(texture_target_, textures_[UUVV_INTERMEDIATE]);
- SetTextureParameters(texture_target_, GL_LINEAR, GL_CLAMP_TO_EDGE);
-
- // Use the second-pass shader program and draw the scene.
- const bool prepared_pass_2 =
- shader_program_cache_->UseRGBToYV12Program(2, 1.0f);
- DCHECK(prepared_pass_2);
- SetTransformationsForOffScreenRendering(*packed_uv_size);
- DrawQuad(0.0f, 0.0f,
- packed_uv_size->width() * 2.0f,
- packed_uv_size->height() * 2.0f,
- false,
- packed_uv_size->width(), packed_uv_size->height());
- glUseProgram(0);
-
- // Before leaving, put back to drawing to a single rendering output.
- glDrawBuffers(1, kColorAttachments);
-
- glBindTexture(texture_target_, 0);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-
- *texture_y = textures_[Y_PLANE_OUTPUT];
- *texture_u = textures_[U_PLANE_OUTPUT];
- *texture_v = textures_[V_PLANE_OUTPUT];
- return true;
-}
-
-void CompositingIOSurfaceTransformer::PrepareTexture(
- CachedTexture which, const gfx::Size& size) {
- DCHECK_GE(which, 0);
- DCHECK_LT(which, NUM_CACHED_TEXTURES);
- DCHECK(!size.IsEmpty());
-
- if (!textures_[which]) {
- glGenTextures(1, &textures_[which]);
- DCHECK_NE(textures_[which], 0u);
- texture_sizes_[which] = gfx::Size();
- }
-
- // Re-allocate the texture if its size has changed since last use.
- if (texture_sizes_[which] != size) {
- TRACE_EVENT2("gpu", "Resize Texture",
- "which", which,
- "new_size", size.ToString());
- glBindTexture(texture_target_, textures_[which]);
- glTexImage2D(texture_target_, 0, GL_RGBA, size.width(), size.height(), 0,
- GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
- texture_sizes_[which] = size;
- }
-}
-
-void CompositingIOSurfaceTransformer::PrepareFramebuffer() {
- if (!frame_buffer_) {
- glGenFramebuffersEXT(1, &frame_buffer_);
- DCHECK_NE(frame_buffer_, 0u);
- }
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac.h b/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac.h
deleted file mode 100644
index 48900741944..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac.h
+++ /dev/null
@@ -1,123 +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_COMPOSITING_IOSURFACE_TRANSFORMER_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_TRANSFORMER_MAC_H_
-
-#include <OpenGL/gl.h>
-
-#include "base/basictypes.h"
-#include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
-#include "ui/gfx/size.h"
-
-namespace gfx {
-class Rect;
-} // namespace gfx
-
-namespace content {
-
-// Provides useful image filtering operations that are implemented efficiently
-// using OpenGL shader programs.
-//
-// Note: All methods assume to be called within an active OpenGL context.
-class CompositingIOSurfaceTransformer {
- public:
- // Construct a transformer that always uses the given parameters for texture
- // bindings. |texture_target| is one of the valid enums to use with
- // glBindTexture().
- // |src_texture_needs_y_flip| is true when the |src_texture| argument to any
- // of the methods below uses upside-down Y coordinates.
- // |shader_program_cache| is not owned by this instance.
- CompositingIOSurfaceTransformer(
- GLenum texture_target, bool src_texture_needs_y_flip,
- CompositingIOSurfaceShaderPrograms* shader_program_cache);
-
- ~CompositingIOSurfaceTransformer();
-
- // Delete any references to currently-cached OpenGL objects. This must be
- // called within the OpenGL context just before destruction.
- void ReleaseCachedGLObjects();
-
- // Resize using bilinear interpolation. Returns false on error. Otherwise,
- // the |texture| argument will point to the result. Ownership of the returned
- // |texture| remains with CompositingIOSurfaceTransformer (i.e., the caller
- // must not delete this texture). The |texture| remains valid until the next
- // call to ResizeBilinear() or ReleaseCachedGLObjects().
- //
- // If the src and dst sizes are identical, this becomes a simple copy into a
- // new texture.
- //
- // Note: This implementation is faulty in that minifications by more than 2X
- // will undergo aliasing.
- bool ResizeBilinear(GLuint src_texture, const gfx::Rect& src_subrect,
- const gfx::Size& dst_size, GLuint* texture);
-
- // Color format conversion from RGB to planar YV12 (also known as YUV420).
- //
- // YV12 is effectively a twelve bit per pixel format consisting of a full-
- // size y (luminance) plane and half-width, half-height u and v (blue and
- // red chrominance) planes. This method will return three off-screen
- // textures, one for each plane, via the output arguments |texture_y|,
- // |texture_u|, and |texture_v|. While the textures are in GL_RGBA format,
- // they should be interpreted as the appropriate single-byte, planar format
- // after reading the pixel data. The output arguments |packed_y_size| and
- // |packed_uv_size| follow from these special semantics: They represent the
- // size of their corresponding texture, if it was to be treated like RGBA
- // pixel data. That means their widths are in terms of "quads," where one
- // quad contains 4 Y (or U or V) pixels.
- //
- // Ownership of the returned textures remains with
- // CompositingIOSurfaceTransformer (i.e., the caller must not delete the
- // textures). The textures remain valid until the next call to
- // TransformRGBToYV12() or ReleaseCachedGLObjects().
- //
- // If |src_subrect|'s size does not match |dst_size|, the source will be
- // bilinearly interpolated during conversion.
- //
- // Returns true if successful, and the caller is responsible for deleting the
- // output textures.
- bool TransformRGBToYV12(
- GLuint src_texture, const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- GLuint* texture_y, GLuint* texture_u, GLuint* texture_v,
- gfx::Size* packed_y_size, gfx::Size* packed_uv_size);
-
- private:
- enum CachedTexture {
- RGBA_OUTPUT = 0,
- Y_PLANE_OUTPUT,
- UUVV_INTERMEDIATE,
- U_PLANE_OUTPUT,
- V_PLANE_OUTPUT,
- NUM_CACHED_TEXTURES
- };
-
- // If necessary, generate the texture and/or resize it to the given |size|.
- void PrepareTexture(CachedTexture which, const gfx::Size& size);
-
- // If necessary, generate a framebuffer object to be used as an intermediate
- // destination for drawing.
- void PrepareFramebuffer();
-
- // Target to bind all input and output textures to (which defines the type of
- // textures being created and read). Generally, this is
- // GL_TEXTURE_RECTANGLE_ARB.
- const GLenum texture_target_;
- const bool src_texture_needs_y_flip_;
- CompositingIOSurfaceShaderPrograms* const shader_program_cache_;
-
- // Cached OpenGL objects.
- GLuint textures_[NUM_CACHED_TEXTURES];
- gfx::Size texture_sizes_[NUM_CACHED_TEXTURES];
- GLuint frame_buffer_;
-
- // Auto-detected and set once in the constructor.
- bool system_supports_multiple_draw_buffers_;
-
- DISALLOW_COPY_AND_ASSIGN(CompositingIOSurfaceTransformer);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_TRANSFORMER_MAC_H_
diff --git a/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac_unittest.cc b/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac_unittest.cc
deleted file mode 100644
index 07c59429184..00000000000
--- a/chromium/content/browser/renderer_host/compositing_iosurface_transformer_mac_unittest.cc
+++ /dev/null
@@ -1,533 +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/compositing_iosurface_transformer_mac.h"
-
-#include <OpenGL/CGLCurrent.h>
-#include <OpenGL/CGLRenderers.h>
-#include <OpenGL/CGLTypes.h>
-#include <OpenGL/OpenGL.h>
-#include <OpenGL/gl.h>
-#include <OpenGL/glu.h>
-
-#include <algorithm>
-#include <cstdlib>
-#include <sstream>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
-#include "media/base/yuv_convert.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "ui/gfx/rect.h"
-
-namespace content {
-
-#define EXPECT_NO_GL_ERROR(stmt) \
- do { \
- stmt; \
- const GLenum error_code = glGetError(); \
- EXPECT_TRUE(GL_NO_ERROR == error_code) \
- << "for error code " << error_code \
- << ": " << gluErrorString(error_code); \
- } while(0)
-
-namespace {
-
-const GLenum kGLTextureTarget = GL_TEXTURE_RECTANGLE_ARB;
-
-enum RendererRestriction {
- RESTRICTION_NONE,
- RESTRICTION_SOFTWARE_ONLY,
- RESTRICTION_HARDWARE_ONLY
-};
-
-bool InitializeGLContext(CGLContextObj* context,
- RendererRestriction restriction) {
- std::vector<CGLPixelFormatAttribute> attribs;
- // Select off-screen renderers only.
- attribs.push_back(kCGLPFAOffScreen);
- // By default, the library will prefer hardware-accelerated renderers, but
- // falls back on the software ones if necessary. However, there are use cases
- // where we want to force a restriction (e.g., benchmarking performance).
- if (restriction == RESTRICTION_SOFTWARE_ONLY) {
- attribs.push_back(kCGLPFARendererID);
- attribs.push_back(static_cast<CGLPixelFormatAttribute>(
- kCGLRendererGenericFloatID));
- } else if (restriction == RESTRICTION_HARDWARE_ONLY) {
- attribs.push_back(kCGLPFAAccelerated);
- }
- attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
-
- CGLPixelFormatObj format;
- GLint num_pixel_formats = 0;
- bool success = true;
- if (CGLChoosePixelFormat(&attribs.front(), &format, &num_pixel_formats) !=
- kCGLNoError) {
- LOG(ERROR) << "Error choosing pixel format.";
- success = false;
- }
- if (success && num_pixel_formats <= 0) {
- LOG(ERROR) << "num_pixel_formats <= 0; actual value is "
- << num_pixel_formats;
- success = false;
- }
- if (success && CGLCreateContext(format, NULL, context) != kCGLNoError) {
- LOG(ERROR) << "Error creating context.";
- success = false;
- }
- CGLDestroyPixelFormat(format);
- return success;
-}
-
-// Returns a decent test pattern for testing all of: 1) orientation, 2) scaling,
-// 3) color space conversion (e.g., 4 pixels --> one U or V pixel), and 4)
-// texture alignment/processing. Example 32x32 bitmap:
-//
-// GGGGGGGGGGGGGGGGRRBBRRBBRRBBRRBB
-// GGGGGGGGGGGGGGGGRRBBRRBBRRBBRRBB
-// GGGGGGGGGGGGGGGGYYCCYYCCYYCCYYCC
-// GGGGGGGGGGGGGGGGYYCCYYCCYYCCYYCC
-// GGGGGGGGGGGGGGGGRRBBRRBBRRBBRRBB
-// GGGGGGGGGGGGGGGGRRBBRRBBRRBBRRBB
-// GGGGGGGGGGGGGGGGYYCCYYCCYYCCYYCC
-// GGGGGGGGGGGGGGGGYYCCYYCCYYCCYYCC
-// RRBBRRBBRRBBRRBBRRBBRRBBRRBBRRBB
-// RRBBRRBBRRBBRRBBRRBBRRBBRRBBRRBB
-// YYCCYYCCYYCCYYCCYYCCYYCCYYCCYYCC
-// YYCCYYCCYYCCYYCCYYCCYYCCYYCCYYCC
-// RRBBRRBBRRBBRRBBRRBBRRBBRRBBRRBB
-// RRBBRRBBRRBBRRBBRRBBRRBBRRBBRRBB
-// YYCCYYCCYYCCYYCCYYCCYYCCYYCCYYCC
-// YYCCYYCCYYCCYYCCYYCCYYCCYYCCYYCC
-//
-// Key: G = Gray, R = Red, B = Blue, Y = Yellow, C = Cyan
-SkBitmap GenerateTestPatternBitmap(const gfx::Size& size) {
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
- CHECK(bitmap.allocPixels());
- SkAutoLockPixels lock_bitmap(bitmap);
- bitmap.eraseColor(SK_ColorGRAY);
- for (int y = 0; y < size.height(); ++y) {
- uint32_t* p = bitmap.getAddr32(0, y);
- for (int x = 0; x < size.width(); ++x, ++p) {
- if ((x < (size.width() / 2)) && (y < (size.height() / 2)))
- continue; // Leave upper-left quadrant gray.
- *p = SkColorSetARGB(255,
- x % 4 < 2 ? 255 : 0,
- y % 4 < 2 ? 255 : 0,
- x % 4 < 2 ? 0 : 255);
- }
- }
- return bitmap;
-}
-
-// Creates a new texture consisting of the given |bitmap|.
-GLuint CreateTextureWithImage(const SkBitmap& bitmap) {
- GLuint texture;
- EXPECT_NO_GL_ERROR(glGenTextures(1, &texture));
- EXPECT_NO_GL_ERROR(glBindTexture(kGLTextureTarget, texture));
- {
- SkAutoLockPixels lock_bitmap(bitmap);
- EXPECT_NO_GL_ERROR(glTexImage2D(
- kGLTextureTarget, 0, GL_RGBA, bitmap.width(), bitmap.height(), 0,
- GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, bitmap.getPixels()));
- }
- glBindTexture(kGLTextureTarget, 0);
- return texture;
-}
-
-// Read back a texture from the GPU, returning the image data as an SkBitmap.
-SkBitmap ReadBackTexture(GLuint texture, const gfx::Size& size, GLenum format) {
- SkBitmap result;
- result.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
- CHECK(result.allocPixels());
-
- GLuint frame_buffer;
- EXPECT_NO_GL_ERROR(glGenFramebuffersEXT(1, &frame_buffer));
- EXPECT_NO_GL_ERROR(
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, frame_buffer));
- EXPECT_NO_GL_ERROR(glFramebufferTexture2DEXT(
- GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, kGLTextureTarget,
- texture, 0));
- DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
-
- {
- SkAutoLockPixels lock_result(result);
- EXPECT_NO_GL_ERROR(glReadPixels(
- 0, 0, size.width(), size.height(), format, GL_UNSIGNED_INT_8_8_8_8_REV,
- result.getPixels()));
- }
-
- EXPECT_NO_GL_ERROR(glDeleteFramebuffersEXT(1, &frame_buffer));
-
- return result;
-}
-
-// Returns the |src_rect| region of |src| scaled to |to_size| by drawing on a
-// Skia canvas, and using bilinear filtering (just like a GPU would).
-SkBitmap ScaleBitmapWithSkia(const SkBitmap& src,
- const gfx::Rect& src_rect,
- const gfx::Size& to_size) {
- SkBitmap cropped_src;
- if (src_rect == gfx::Rect(0, 0, src.width(), src.height())) {
- cropped_src = src;
- } else {
- CHECK(src.extractSubset(
- &cropped_src,
- SkIRect::MakeXYWH(src_rect.x(), src_rect.y(),
- src_rect.width(), src_rect.height())));
- }
-
- SkBitmap result;
- result.setConfig(cropped_src.config(), to_size.width(), to_size.height());
- CHECK(result.allocPixels());
-
- SkCanvas canvas(result);
- canvas.scale(static_cast<double>(result.width()) / cropped_src.width(),
- static_cast<double>(result.height()) / cropped_src.height());
- SkPaint paint;
- paint.setFilterLevel(SkPaint::kLow_FilterLevel); // Use bilinear filtering.
- canvas.drawBitmap(cropped_src, 0, 0, &paint);
-
- return result;
-}
-
-// The maximum value by which a pixel value may deviate from the expected value
-// before considering it "significantly different." This is meant to account
-// for the slight differences in filtering techniques used between the various
-// GPUs and software implementations.
-const int kDifferenceThreshold = 16;
-
-// Returns the number of pixels significantly different between |expected| and
-// |actual|.
-int ImageDifference(const SkBitmap& expected, const SkBitmap& actual) {
- SkAutoLockPixels lock_expected(expected);
- SkAutoLockPixels lock_actual(actual);
-
- // Sanity-check assumed image properties.
- DCHECK_EQ(expected.width(), actual.width());
- DCHECK_EQ(expected.height(), actual.height());
- DCHECK_EQ(SkBitmap::kARGB_8888_Config, expected.config());
- DCHECK_EQ(SkBitmap::kARGB_8888_Config, actual.config());
-
- // Compare both images.
- int num_pixels_different = 0;
- for (int y = 0; y < expected.height(); ++y) {
- const uint32_t* p = expected.getAddr32(0, y);
- const uint32_t* q = actual.getAddr32(0, y);
- for (int x = 0; x < expected.width(); ++x, ++p, ++q) {
- if (abs(static_cast<int>(SkColorGetR(*p)) -
- static_cast<int>(SkColorGetR(*q))) > kDifferenceThreshold ||
- abs(static_cast<int>(SkColorGetG(*p)) -
- static_cast<int>(SkColorGetG(*q))) > kDifferenceThreshold ||
- abs(static_cast<int>(SkColorGetB(*p)) -
- static_cast<int>(SkColorGetB(*q))) > kDifferenceThreshold) {
- ++num_pixels_different;
- }
- }
- }
-
- return num_pixels_different;
-}
-
-// Returns the number of pixels significantly different between |expected| and
-// |actual|. It is understood that |actual| contains 4-byte quads, and so we
-// may need to be ignoring a mod-4 number of pixels at the end of each of its
-// rows.
-int ImagePlaneDifference(const uint8* expected, const SkBitmap& actual,
- const gfx::Size& dst_size) {
- SkAutoLockPixels actual_lock(actual);
-
- int num_pixels_different = 0;
- for (int y = 0; y < dst_size.height(); ++y) {
- const uint8* p = expected + y * dst_size.width();
- const uint8* const p_end = p + dst_size.width();
- const uint8* q =
- reinterpret_cast<uint8*>(actual.getPixels()) + y * actual.rowBytes();
- for (; p < p_end; ++p, ++q) {
- if (abs(static_cast<int>(*p) - static_cast<int>(*q)) >
- kDifferenceThreshold) {
- ++num_pixels_different;
- }
- }
- }
-
- return num_pixels_different;
-}
-
-} // namespace
-
-// Note: All tests fixtures operate within an off-screen OpenGL context.
-class CompositingIOSurfaceTransformerTest : public testing::Test {
- public:
- CompositingIOSurfaceTransformerTest() {
- // TODO(miu): Try to use RESTRICTION_NONE to speed up the execution time of
- // unit tests, once it's established that the trybots and buildbots behave
- // well when using the GPU.
- CHECK(InitializeGLContext(&context_, RESTRICTION_SOFTWARE_ONLY));
- CGLSetCurrentContext(context_);
- shader_program_cache_.reset(new CompositingIOSurfaceShaderPrograms());
- transformer_.reset(new CompositingIOSurfaceTransformer(
- kGLTextureTarget, false, shader_program_cache_.get()));
- }
-
- virtual ~CompositingIOSurfaceTransformerTest() {
- transformer_->ReleaseCachedGLObjects();
- shader_program_cache_->Reset();
- CGLSetCurrentContext(NULL);
- CGLDestroyContext(context_);
- }
-
- protected:
- void RunResizeTest(const SkBitmap& src_bitmap, const gfx::Rect& src_rect,
- const gfx::Size& dst_size) {
- SCOPED_TRACE(::testing::Message()
- << "src_rect=(" << src_rect.x() << ',' << src_rect.y()
- << ")x[" << src_rect.width() << 'x' << src_rect.height()
- << "]; dst_size=[" << dst_size.width() << 'x'
- << dst_size.height() << ']');
-
- // Do the scale operation on the GPU.
- const GLuint original_texture = CreateTextureWithImage(src_bitmap);
- ASSERT_NE(0u, original_texture);
- GLuint scaled_texture = 0u;
- ASSERT_TRUE(transformer_->ResizeBilinear(
- original_texture, src_rect, dst_size, &scaled_texture));
- EXPECT_NE(0u, scaled_texture);
- CGLFlushDrawable(context_); // Account for some buggy driver impls.
- const SkBitmap result_bitmap =
- ReadBackTexture(scaled_texture, dst_size, GL_BGRA);
- EXPECT_NO_GL_ERROR(glDeleteTextures(1, &original_texture));
-
- // Compare the image read back to the version produced by a known-working
- // software implementation. Allow up to 2 lines of mismatch due to how
- // implementations disagree on resolving the processing of edges.
- const SkBitmap expected_bitmap =
- ScaleBitmapWithSkia(src_bitmap, src_rect, dst_size);
- EXPECT_GE(std::max(expected_bitmap.width(), expected_bitmap.height()) * 2,
- ImageDifference(expected_bitmap, result_bitmap));
- }
-
- void RunTransformRGBToYV12Test(
- const SkBitmap& src_bitmap, const gfx::Rect& src_rect,
- const gfx::Size& dst_size) {
- SCOPED_TRACE(::testing::Message()
- << "src_rect=(" << src_rect.x() << ',' << src_rect.y()
- << ")x[" << src_rect.width() << 'x' << src_rect.height()
- << "]; dst_size=[" << dst_size.width() << 'x'
- << dst_size.height() << ']');
-
- // Perform the RGB to YV12 conversion.
- const GLuint original_texture = CreateTextureWithImage(src_bitmap);
- ASSERT_NE(0u, original_texture);
- GLuint texture_y = 0u;
- GLuint texture_u = 0u;
- GLuint texture_v = 0u;
- gfx::Size packed_y_size;
- gfx::Size packed_uv_size;
- ASSERT_TRUE(transformer_->TransformRGBToYV12(
- original_texture, src_rect, dst_size,
- &texture_y, &texture_u, &texture_v, &packed_y_size, &packed_uv_size));
- EXPECT_NE(0u, texture_y);
- EXPECT_NE(0u, texture_u);
- EXPECT_NE(0u, texture_v);
- EXPECT_FALSE(packed_y_size.IsEmpty());
- EXPECT_FALSE(packed_uv_size.IsEmpty());
- EXPECT_NO_GL_ERROR(glDeleteTextures(1, &original_texture));
-
- // Read-back the texture for each plane.
- CGLFlushDrawable(context_); // Account for some buggy driver impls.
- const GLenum format = shader_program_cache_->rgb_to_yv12_output_format();
- const SkBitmap result_y_bitmap =
- ReadBackTexture(texture_y, packed_y_size, format);
- const SkBitmap result_u_bitmap =
- ReadBackTexture(texture_u, packed_uv_size, format);
- const SkBitmap result_v_bitmap =
- ReadBackTexture(texture_v, packed_uv_size, format);
-
- // Compare the Y, U, and V planes read-back to the version produced by a
- // known-working software implementation. Allow up to 2 lines of mismatch
- // due to how implementations disagree on resolving the processing of edges.
- const SkBitmap expected_bitmap =
- ScaleBitmapWithSkia(src_bitmap, src_rect, dst_size);
- const gfx::Size dst_uv_size(
- (dst_size.width() + 1) / 2, (dst_size.height() + 1) / 2);
- scoped_ptr<uint8[]> expected_y_plane(
- new uint8[dst_size.width() * dst_size.height()]);
- scoped_ptr<uint8[]> expected_u_plane(
- new uint8[dst_uv_size.width() * dst_uv_size.height()]);
- scoped_ptr<uint8[]> expected_v_plane(
- new uint8[dst_uv_size.width() * dst_uv_size.height()]);
- {
- SkAutoLockPixels src_bitmap_lock(expected_bitmap);
- media::ConvertRGB32ToYUV(
- reinterpret_cast<const uint8*>(expected_bitmap.getPixels()),
- expected_y_plane.get(), expected_u_plane.get(),
- expected_v_plane.get(),
- expected_bitmap.width(), expected_bitmap.height(),
- expected_bitmap.rowBytes(),
- dst_size.width(), (dst_size.width() + 1) / 2);
- }
- EXPECT_GE(
- std::max(expected_bitmap.width(), expected_bitmap.height()) * 2,
- ImagePlaneDifference(expected_y_plane.get(), result_y_bitmap, dst_size))
- << " for RGB --> Y Plane";
- EXPECT_GE(
- std::max(expected_bitmap.width(), expected_bitmap.height()),
- ImagePlaneDifference(expected_u_plane.get(), result_u_bitmap,
- dst_uv_size))
- << " for RGB --> U Plane";
- EXPECT_GE(
- std::max(expected_bitmap.width(), expected_bitmap.height()),
- ImagePlaneDifference(expected_v_plane.get(), result_v_bitmap,
- dst_uv_size))
- << " for RGB --> V Plane";
- }
-
- CompositingIOSurfaceShaderPrograms* shader_program_cache() const {
- return shader_program_cache_.get();
- }
-
- private:
- CGLContextObj context_;
- scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache_;
- scoped_ptr<CompositingIOSurfaceTransformer> transformer_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CompositingIOSurfaceTransformerTest);
-};
-
-TEST_F(CompositingIOSurfaceTransformerTest, ShaderProgramsCompileAndLink) {
- // Attempt to use each program, binding its required uniform variables.
- EXPECT_NO_GL_ERROR(shader_program_cache()->UseBlitProgram());
- EXPECT_NO_GL_ERROR(shader_program_cache()->UseSolidWhiteProgram());
- EXPECT_NO_GL_ERROR(shader_program_cache()->UseRGBToYV12Program(1, 1.0f));
- EXPECT_NO_GL_ERROR(shader_program_cache()->UseRGBToYV12Program(2, 1.0f));
-
- EXPECT_NO_GL_ERROR(glUseProgram(0));
-}
-
-namespace {
-
-const struct TestParameters {
- int src_width;
- int src_height;
- int scaled_width;
- int scaled_height;
-} kTestParameters[] = {
- // Test 1:1 copies, but exposing varying pixel packing configurations.
- { 64, 64, 64, 64 },
- { 63, 63, 63, 63 },
- { 62, 62, 62, 62 },
- { 61, 61, 61, 61 },
- { 60, 60, 60, 60 },
- { 59, 59, 59, 59 },
- { 58, 58, 58, 58 },
- { 57, 57, 57, 57 },
- { 56, 56, 56, 56 },
-
- // Even-size, one or both dimensions upscaled.
- { 32, 32, 64, 32 }, { 32, 32, 32, 64 }, { 32, 32, 64, 64 },
- // Even-size, one or both dimensions downscaled by 2X.
- { 32, 32, 16, 32 }, { 32, 32, 32, 16 }, { 32, 32, 16, 16 },
- // Even-size, one or both dimensions downscaled by 1 pixel.
- { 32, 32, 31, 32 }, { 32, 32, 32, 31 }, { 32, 32, 31, 31 },
- // Even-size, one or both dimensions downscaled by 2 pixels.
- { 32, 32, 30, 32 }, { 32, 32, 32, 30 }, { 32, 32, 30, 30 },
- // Even-size, one or both dimensions downscaled by 3 pixels.
- { 32, 32, 29, 32 }, { 32, 32, 32, 29 }, { 32, 32, 29, 29 },
-
- // Odd-size, one or both dimensions upscaled.
- { 33, 33, 66, 33 }, { 33, 33, 33, 66 }, { 33, 33, 66, 66 },
- // Odd-size, one or both dimensions downscaled by 2X.
- { 33, 33, 16, 33 }, { 33, 33, 33, 16 }, { 33, 33, 16, 16 },
- // Odd-size, one or both dimensions downscaled by 1 pixel.
- { 33, 33, 32, 33 }, { 33, 33, 33, 32 }, { 33, 33, 32, 32 },
- // Odd-size, one or both dimensions downscaled by 2 pixels.
- { 33, 33, 31, 33 }, { 33, 33, 33, 31 }, { 33, 33, 31, 31 },
- // Odd-size, one or both dimensions downscaled by 3 pixels.
- { 33, 33, 30, 33 }, { 33, 33, 33, 30 }, { 33, 33, 30, 30 },
-};
-
-} // namespace
-
-TEST_F(CompositingIOSurfaceTransformerTest, ResizesTexturesCorrectly) {
- for (size_t i = 0; i < arraysize(kTestParameters); ++i) {
- SCOPED_TRACE(::testing::Message() << "kTestParameters[" << i << ']');
-
- const TestParameters& params = kTestParameters[i];
- const gfx::Size src_size(params.src_width, params.src_height);
- const gfx::Size dst_size(params.scaled_width, params.scaled_height);
- const SkBitmap src_bitmap = GenerateTestPatternBitmap(src_size);
-
- // Full texture resize test.
- RunResizeTest(src_bitmap, gfx::Rect(src_size), dst_size);
- // Subrect resize test: missing top row in source.
- RunResizeTest(src_bitmap,
- gfx::Rect(0, 1, params.src_width, params.src_height - 1),
- dst_size);
- // Subrect resize test: missing left column in source.
- RunResizeTest(src_bitmap,
- gfx::Rect(1, 0, params.src_width - 1, params.src_height),
- dst_size);
- // Subrect resize test: missing top+bottom rows, and left column in source.
- RunResizeTest(src_bitmap,
- gfx::Rect(1, 1, params.src_width - 1, params.src_height - 2),
- dst_size);
- // Subrect resize test: missing top row, and left+right columns in source.
- RunResizeTest(src_bitmap,
- gfx::Rect(1, 1, params.src_width - 2, params.src_height - 1),
- dst_size);
- }
-}
-
-TEST_F(CompositingIOSurfaceTransformerTest, TransformsRGBToYV12) {
- static const GLenum kOutputFormats[] = { GL_BGRA, GL_RGBA };
-
- for (size_t i = 0; i < arraysize(kOutputFormats); ++i) {
- SCOPED_TRACE(::testing::Message() << "kOutputFormats[" << i << ']');
-
- shader_program_cache()->SetOutputFormatForTesting(kOutputFormats[i]);
-
- for (size_t j = 0; j < arraysize(kTestParameters); ++j) {
- SCOPED_TRACE(::testing::Message() << "kTestParameters[" << j << ']');
-
- const TestParameters& params = kTestParameters[j];
- const gfx::Size src_size(params.src_width, params.src_height);
- const gfx::Size dst_size(params.scaled_width, params.scaled_height);
- const SkBitmap src_bitmap = GenerateTestPatternBitmap(src_size);
-
- // Full texture resize test.
- RunTransformRGBToYV12Test(src_bitmap, gfx::Rect(src_size), dst_size);
- // Subrect resize test: missing top row in source.
- RunTransformRGBToYV12Test(
- src_bitmap, gfx::Rect(0, 1, params.src_width, params.src_height - 1),
- dst_size);
- // Subrect resize test: missing left column in source.
- RunTransformRGBToYV12Test(
- src_bitmap, gfx::Rect(1, 0, params.src_width - 1, params.src_height),
- dst_size);
- // Subrect resize test: missing top+bottom rows, and left column in
- // source.
- RunTransformRGBToYV12Test(
- src_bitmap,
- gfx::Rect(1, 1, params.src_width - 1, params.src_height - 2),
- dst_size);
- // Subrect resize test: missing top row, and left+right columns in source.
- RunTransformRGBToYV12Test(
- src_bitmap,
- gfx::Rect(1, 1, params.src_width - 2, params.src_height - 1),
- dst_size);
- }
- }
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/compositor_impl_android.cc b/chromium/content/browser/renderer_host/compositor_impl_android.cc
index 47f037d17f4..5d8ecc8138c 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android.cc
+++ b/chromium/content/browser/renderer_host/compositor_impl_android.cc
@@ -10,10 +10,12 @@
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/bind.h"
+#include "base/cancelable_callback.h"
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
@@ -24,10 +26,13 @@
#include "cc/output/compositor_frame.h"
#include "cc/output/context_provider.h"
#include "cc/output/output_surface.h"
+#include "cc/output/output_surface_client.h"
#include "cc/trees/layer_tree_host.h"
#include "content/browser/android/child_process_launcher_android.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/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"
@@ -36,6 +41,7 @@
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/public/browser/android/compositor_client.h"
+#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
@@ -43,11 +49,11 @@
#include "ui/base/android/window_android.h"
#include "ui/gfx/android/device_display_info.h"
#include "ui/gfx/frame_time.h"
-#include "ui/gl/android/surface_texture.h"
-#include "ui/gl/android/surface_texture_tracker.h"
#include "webkit/common/gpu/context_provider_in_process.h"
#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
+namespace content {
+
namespace {
const unsigned int kMaxSwapBuffers = 2U;
@@ -55,97 +61,75 @@ const unsigned int kMaxSwapBuffers = 2U;
// Used to override capabilities_.adjust_deadline_for_parent to false
class OutputSurfaceWithoutParent : public cc::OutputSurface {
public:
- OutputSurfaceWithoutParent(const scoped_refptr<
- content::ContextProviderCommandBuffer>& context_provider)
- : cc::OutputSurface(context_provider) {
+ OutputSurfaceWithoutParent(
+ const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+ base::WeakPtr<CompositorImpl> compositor_impl)
+ : cc::OutputSurface(context_provider),
+ swap_buffers_completion_callback_(
+ base::Bind(&OutputSurfaceWithoutParent::OnSwapBuffersCompleted,
+ base::Unretained(this))) {
capabilities_.adjust_deadline_for_parent = false;
+ compositor_impl_ = compositor_impl;
+ main_thread_ = base::MessageLoopProxy::current();
}
- virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
- content::ContextProviderCommandBuffer* provider_command_buffer =
- static_cast<content::ContextProviderCommandBuffer*>(
- context_provider_.get());
- content::CommandBufferProxyImpl* command_buffer_proxy =
- provider_command_buffer->GetCommandBufferProxy();
- DCHECK(command_buffer_proxy);
- command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
+ virtual void SwapBuffers(cc::CompositorFrame* frame) override {
+ for (size_t i = 0; i < frame->metadata.latency_info.size(); i++) {
+ frame->metadata.latency_info[i].AddLatencyNumber(
+ ui::INPUT_EVENT_BROWSER_SWAP_BUFFER_COMPONENT, 0, 0);
+ }
- OutputSurface::SwapBuffers(frame);
+ GetCommandBufferProxy()->SetLatencyInfo(frame->metadata.latency_info);
+ DCHECK(frame->gl_frame_data->sub_buffer_rect ==
+ gfx::Rect(frame->gl_frame_data->size));
+ context_provider_->ContextSupport()->Swap();
+ client_->DidSwapBuffers();
}
-};
-class SurfaceTextureTrackerImpl : public gfx::SurfaceTextureTracker {
- public:
- SurfaceTextureTrackerImpl() : next_surface_texture_id_(1) {
- thread_checker_.DetachFromThread();
- }
+ virtual bool BindToClient(cc::OutputSurfaceClient* client) override {
+ if (!OutputSurface::BindToClient(client))
+ return false;
+
+ GetCommandBufferProxy()->SetSwapBuffersCompletionCallback(
+ swap_buffers_completion_callback_.callback());
+
+ main_thread_->PostTask(
+ FROM_HERE,
+ base::Bind(&CompositorImpl::PopulateGpuCapabilities,
+ compositor_impl_,
+ context_provider_->ContextCapabilities().gpu));
- // Overridden from gfx::SurfaceTextureTracker:
- virtual scoped_refptr<gfx::SurfaceTexture> AcquireSurfaceTexture(
- int primary_id,
- int secondary_id) OVERRIDE {
- base::AutoLock lock(surface_textures_lock_);
- SurfaceTextureMapKey key(primary_id, secondary_id);
- SurfaceTextureMap::iterator it = surface_textures_.find(key);
- if (it == surface_textures_.end())
- return scoped_refptr<gfx::SurfaceTexture>();
- scoped_refptr<gfx::SurfaceTexture> surface_texture = it->second;
- surface_textures_.erase(it);
- return surface_texture;
+ return true;
}
- int AddSurfaceTexture(gfx::SurfaceTexture* surface_texture,
- int child_process_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- int surface_texture_id = next_surface_texture_id_++;
- if (next_surface_texture_id_ == INT_MAX)
- next_surface_texture_id_ = 1;
-
- base::AutoLock lock(surface_textures_lock_);
- SurfaceTextureMapKey key(surface_texture_id, child_process_id);
- DCHECK(surface_textures_.find(key) == surface_textures_.end());
- surface_textures_[key] = surface_texture;
- content::RegisterChildProcessSurfaceTexture(
- surface_texture_id,
- child_process_id,
- surface_texture->j_surface_texture().obj());
- return surface_texture_id;
+ private:
+ CommandBufferProxyImpl* GetCommandBufferProxy() {
+ ContextProviderCommandBuffer* provider_command_buffer =
+ static_cast<content::ContextProviderCommandBuffer*>(
+ context_provider_.get());
+ CommandBufferProxyImpl* command_buffer_proxy =
+ provider_command_buffer->GetCommandBufferProxy();
+ DCHECK(command_buffer_proxy);
+ return command_buffer_proxy;
}
- void RemoveAllSurfaceTextures(int child_process_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- base::AutoLock lock(surface_textures_lock_);
- SurfaceTextureMap::iterator it = surface_textures_.begin();
- while (it != surface_textures_.end()) {
- if (it->first.second == child_process_id) {
- content::UnregisterChildProcessSurfaceTexture(it->first.first,
- it->first.second);
- surface_textures_.erase(it++);
- } else {
- ++it;
- }
- }
+ void OnSwapBuffersCompleted(
+ const std::vector<ui::LatencyInfo>& latency_info) {
+ RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
+ OutputSurface::OnSwapBuffersComplete();
}
- private:
- typedef std::pair<int, int> SurfaceTextureMapKey;
- typedef base::hash_map<SurfaceTextureMapKey,
- scoped_refptr<gfx::SurfaceTexture> >
- SurfaceTextureMap;
- SurfaceTextureMap surface_textures_;
- mutable base::Lock surface_textures_lock_;
- int next_surface_texture_id_;
- base::ThreadChecker thread_checker_;
+ base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&)>
+ swap_buffers_completion_callback_;
+
+ scoped_refptr<base::MessageLoopProxy> main_thread_;
+ base::WeakPtr<CompositorImpl> compositor_impl_;
};
-base::LazyInstance<SurfaceTextureTrackerImpl> g_surface_texture_tracker =
- LAZY_INSTANCE_INITIALIZER;
static bool g_initialized = false;
} // anonymous namespace
-namespace content {
-
// static
Compositor* Compositor::Create(CompositorClient* client,
gfx::NativeWindow root_window) {
@@ -155,9 +139,6 @@ Compositor* Compositor::Create(CompositorClient* client,
// static
void Compositor::Initialize() {
DCHECK(!CompositorImpl::IsInitialized());
- // SurfaceTextureTracker instance must be set before we create a GPU thread
- // that could be using it to initialize GLImage instances.
- gfx::SurfaceTextureTracker::InitInstance(g_surface_texture_tracker.Pointer());
g_initialized = true;
}
@@ -166,25 +147,6 @@ bool CompositorImpl::IsInitialized() {
return g_initialized;
}
-// static
-int CompositorImpl::CreateSurfaceTexture(int child_process_id) {
- // Note: this needs to be 0 as the surface texture implemenation will take
- // ownership of the texture and call glDeleteTextures when the GPU service
- // attaches the surface texture to a real texture id. glDeleteTextures
- // silently ignores 0.
- const int kDummyTextureId = 0;
- scoped_refptr<gfx::SurfaceTexture> surface_texture =
- gfx::SurfaceTexture::Create(kDummyTextureId);
- return g_surface_texture_tracker.Pointer()->AddSurfaceTexture(
- surface_texture.get(), child_process_id);
-}
-
-// static
-void CompositorImpl::DestroyAllSurfaceTextures(int child_process_id) {
- g_surface_texture_tracker.Pointer()->RemoveAllSurfaceTextures(
- child_process_id);
-}
-
CompositorImpl::CompositorImpl(CompositorClient* client,
gfx::NativeWindow root_window)
: root_layer_(cc::Layer::Create()),
@@ -281,10 +243,9 @@ void CompositorImpl::Composite(CompositingTrigger trigger) {
if (!factory->GetGpuChannel() || factory->GetGpuChannel()->IsLost()) {
CauseForGpuLaunch cause =
CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
- factory->EstablishGpuChannel(
- cause,
- base::Bind(&CompositorImpl::OnGpuChannelEstablished,
- weak_factory_.GetWeakPtr()));
+ factory->EstablishGpuChannel(cause,
+ base::Bind(&CompositorImpl::ScheduleComposite,
+ weak_factory_.GetWeakPtr()));
return;
}
@@ -314,7 +275,6 @@ void CompositorImpl::Composite(CompositingTrigger trigger) {
// animation updates that will already be reflected in the current frame
// we are about to draw.
ignore_schedule_composite_ = true;
- client_->Layout();
const base::TimeTicks frame_time = gfx::FrameTime::Now();
if (needs_animate_) {
@@ -332,20 +292,20 @@ void CompositorImpl::Composite(CompositingTrigger trigger) {
root_window_->RequestVSyncUpdate();
}
-void CompositorImpl::OnGpuChannelEstablished() {
- ScheduleComposite();
-}
-
UIResourceProvider& CompositorImpl::GetUIResourceProvider() {
return ui_resource_provider_;
}
+ui::SystemUIResourceManager& CompositorImpl::GetSystemUIResourceManager() {
+ return ui_resource_provider_.GetSystemUIResourceManager();
+}
+
void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) {
- if (subroot_layer_) {
+ if (subroot_layer_.get()) {
subroot_layer_->RemoveFromParent();
subroot_layer_ = NULL;
}
- if (root_layer) {
+ if (root_layer.get()) {
subroot_layer_ = root_layer;
root_layer_->AddChild(root_layer);
}
@@ -379,7 +339,7 @@ void CompositorImpl::SetSurface(jobject surface) {
// First, cleanup any existing surface references.
if (surface_id_)
- content::UnregisterViewSurface(surface_id_);
+ UnregisterViewSurface(surface_id_);
SetWindowSurface(NULL);
// Now, set the new surface if we have one.
@@ -394,12 +354,27 @@ void CompositorImpl::SetSurface(jobject surface) {
if (window) {
SetWindowSurface(window);
ANativeWindow_release(window);
- content::RegisterViewSurface(surface_id_, j_surface.obj());
+ RegisterViewSurface(surface_id_, j_surface.obj());
}
}
void CompositorImpl::SetVisible(bool visible) {
if (!visible) {
+ DCHECK(host_);
+ // Look for any layers that were attached to the root for readback
+ // and are waiting for Composite() to happen.
+ bool readback_pending = false;
+ for (size_t i = 0; i < root_layer_->children().size(); ++i) {
+ if (root_layer_->children()[i]->HasCopyRequest()) {
+ readback_pending = true;
+ break;
+ }
+ }
+ if (readback_pending) {
+ ignore_schedule_composite_ = true;
+ host_->Composite(base::TimeTicks::Now());
+ ignore_schedule_composite_ = false;
+ }
if (WillComposite())
CancelComposite();
ui_resource_provider_.SetLayerTreeHost(NULL);
@@ -407,7 +382,6 @@ void CompositorImpl::SetVisible(bool visible) {
} else if (!host_) {
DCHECK(!WillComposite());
needs_composite_ = false;
- needs_animate_ = false;
pending_swapbuffers_ = 0;
cc::LayerTreeSettings settings;
settings.refresh_rate = 60.0;
@@ -417,14 +391,21 @@ void CompositorImpl::SetVisible(bool visible) {
settings.top_controls_height = 0.f;
settings.highp_threshold_min = 2048;
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
settings.initial_debug_state.SetRecordRenderingStats(
command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
settings.initial_debug_state.show_fps_counter =
command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
+ // TODO(enne): Update this this compositor to use the scheduler.
+ settings.single_thread_proxy_scheduler = false;
host_ = cc::LayerTreeHost::CreateSingleThreaded(
- this, this, HostSharedBitmapManager::current(), settings);
+ this,
+ this,
+ HostSharedBitmapManager::current(),
+ BrowserGpuMemoryBufferManager::current(),
+ settings,
+ base::MessageLoopProxy::current());
host_->SetRootLayer(root_layer_);
host_->SetVisible(true);
@@ -472,7 +453,7 @@ CreateGpuProcessViewContext(
const scoped_refptr<GpuChannelHost>& gpu_channel_host,
const blink::WebGraphicsContext3D::Attributes attributes,
int surface_id) {
- DCHECK(gpu_channel_host);
+ DCHECK(gpu_channel_host.get());
GURL url("chrome://gpu/Compositor::createContext3D");
static const size_t kBytesPerPixel = 4;
@@ -500,14 +481,29 @@ CreateGpuProcessViewContext(
}
void CompositorImpl::Layout() {
- // TODO: If we get this callback from the SingleThreadProxy, we need
- // to stop calling it ourselves in CompositorImpl::Composite().
- NOTREACHED();
+ ignore_schedule_composite_ = true;
client_->Layout();
+ ignore_schedule_composite_ = false;
}
-scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
- bool fallback) {
+void CompositorImpl::RequestNewOutputSurface(bool fallback) {
+ BrowserGpuChannelHostFactory* factory =
+ BrowserGpuChannelHostFactory::instance();
+ if (!factory->GetGpuChannel() || factory->GetGpuChannel()->IsLost()) {
+ CauseForGpuLaunch cause =
+ CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE;
+ factory->EstablishGpuChannel(
+ cause,
+ base::Bind(&CompositorImpl::CreateOutputSurface,
+ weak_factory_.GetWeakPtr(),
+ fallback));
+ return;
+ }
+
+ CreateOutputSurface(fallback);
+}
+
+void CompositorImpl::CreateOutputSurface(bool fallback) {
blink::WebGraphicsContext3D::Attributes attrs;
attrs.shareResources = true;
attrs.noAutomaticFlushes = true;
@@ -520,23 +516,30 @@ scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
BrowserGpuChannelHostFactory* factory =
BrowserGpuChannelHostFactory::instance();
scoped_refptr<GpuChannelHost> gpu_channel_host = factory->GetGpuChannel();
- if (gpu_channel_host && !gpu_channel_host->IsLost()) {
+ if (gpu_channel_host.get() && !gpu_channel_host->IsLost()) {
context_provider = ContextProviderCommandBuffer::Create(
CreateGpuProcessViewContext(gpu_channel_host, attrs, surface_id_),
"BrowserCompositor");
}
if (!context_provider.get()) {
LOG(ERROR) << "Failed to create 3D context for compositor.";
- return scoped_ptr<cc::OutputSurface>();
+ host_->SetOutputSurface(scoped_ptr<cc::OutputSurface>());
+ return;
}
- return scoped_ptr<cc::OutputSurface>(
- new OutputSurfaceWithoutParent(context_provider));
+ host_->SetOutputSurface(
+ scoped_ptr<cc::OutputSurface>(new OutputSurfaceWithoutParent(
+ context_provider, weak_factory_.GetWeakPtr())));
+}
+
+void CompositorImpl::PopulateGpuCapabilities(
+ gpu::Capabilities gpu_capabilities) {
+ ui_resource_provider_.SetSupportsETC1NonPowerOfTwo(
+ gpu_capabilities.texture_format_etc1_npot);
}
void CompositorImpl::OnLostResources() {
client_->DidLoseResources();
- ui_resource_provider_.UIResourcesAreInvalid();
}
void CompositorImpl::ScheduleComposite() {
@@ -552,7 +555,6 @@ void CompositorImpl::ScheduleComposite() {
}
void CompositorImpl::ScheduleAnimation() {
- DCHECK(!needs_animate_ || needs_composite_);
DCHECK(!needs_composite_ || WillComposite());
needs_animate_ = true;
@@ -582,6 +584,7 @@ void CompositorImpl::DidAbortSwapBuffers() {
// This really gets called only once from
// SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() when the
// context was lost.
+ ScheduleComposite();
client_->OnSwapBuffersCompleted(0);
}
diff --git a/chromium/content/browser/renderer_host/compositor_impl_android.h b/chromium/content/browser/renderer_host/compositor_impl_android.h
index 4792d9058c7..402271b1084 100644
--- a/chromium/content/browser/renderer_host/compositor_impl_android.h
+++ b/chromium/content/browser/renderer_host/compositor_impl_android.h
@@ -8,17 +8,18 @@
#include "base/basictypes.h"
#include "base/cancelable_callback.h"
#include "base/compiler_specific.h"
-#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "cc/resources/ui_resource_client.h"
#include "cc/trees/layer_tree_host_client.h"
#include "cc/trees/layer_tree_host_single_thread_client.h"
#include "content/browser/android/ui_resource_provider_impl.h"
#include "content/browser/renderer_host/image_transport_factory_android.h"
#include "content/common/content_export.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/public/browser/android/compositor.h"
+#include "gpu/command_buffer/common/capabilities.h"
#include "third_party/khronos/GLES2/gl2.h"
+#include "ui/base/android/system_ui_resource_manager.h"
#include "ui/base/android/window_android_compositor.h"
class SkBitmap;
@@ -48,56 +49,59 @@ class CONTENT_EXPORT CompositorImpl
static bool IsInitialized();
- // Creates a surface texture and returns a surface texture id. Returns -1 on
- // failure.
- static int CreateSurfaceTexture(int child_process_id);
-
- // Destroy all surface textures associated with |child_process_id|.
- static void DestroyAllSurfaceTextures(int child_process_id);
+ void PopulateGpuCapabilities(gpu::Capabilities gpu_capabilities);
private:
// Compositor implementation.
- virtual void SetRootLayer(scoped_refptr<cc::Layer> root) OVERRIDE;
- virtual void SetWindowSurface(ANativeWindow* window) OVERRIDE;
- virtual void SetSurface(jobject surface) OVERRIDE;
- virtual void SetVisible(bool visible) OVERRIDE;
- virtual void setDeviceScaleFactor(float factor) OVERRIDE;
- virtual void SetWindowBounds(const gfx::Size& size) OVERRIDE;
- virtual void SetHasTransparentBackground(bool flag) OVERRIDE;
- virtual void SetNeedsComposite() OVERRIDE;
- virtual UIResourceProvider& GetUIResourceProvider() OVERRIDE;
+ virtual void SetRootLayer(scoped_refptr<cc::Layer> root) override;
+ virtual void SetSurface(jobject surface) override;
+ virtual void SetVisible(bool visible) override;
+ virtual void setDeviceScaleFactor(float factor) override;
+ virtual void SetWindowBounds(const gfx::Size& size) override;
+ virtual void SetHasTransparentBackground(bool flag) override;
+ virtual void SetNeedsComposite() override;
+ virtual UIResourceProvider& GetUIResourceProvider() override;
// LayerTreeHostClient implementation.
- virtual void WillBeginMainFrame(int frame_id) OVERRIDE {}
- virtual void DidBeginMainFrame() OVERRIDE {}
- virtual void Animate(base::TimeTicks frame_begin_time) OVERRIDE {}
- virtual void Layout() OVERRIDE;
- virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
- float page_scale) OVERRIDE {}
- virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback)
- OVERRIDE;
- virtual void DidInitializeOutputSurface() OVERRIDE {}
- virtual void WillCommit() OVERRIDE {}
- virtual void DidCommit() OVERRIDE;
- virtual void DidCommitAndDrawFrame() OVERRIDE {}
- virtual void DidCompleteSwapBuffers() OVERRIDE;
+ virtual void WillBeginMainFrame(int frame_id) override {}
+ virtual void DidBeginMainFrame() override {}
+ virtual void BeginMainFrame(const cc::BeginFrameArgs& args) override {}
+ virtual void Layout() override;
+ virtual void ApplyViewportDeltas(
+ const gfx::Vector2d& inner_delta,
+ const gfx::Vector2d& outer_delta,
+ float page_scale,
+ float top_controls_delta) override {}
+ virtual void ApplyViewportDeltas(
+ const gfx::Vector2d& scroll_delta,
+ float page_scale,
+ float top_controls_delta) override {}
+ virtual void RequestNewOutputSurface(bool fallback) override;
+ virtual void DidInitializeOutputSurface() override {}
+ virtual void WillCommit() override {}
+ virtual void DidCommit() override;
+ virtual void DidCommitAndDrawFrame() override {}
+ virtual void DidCompleteSwapBuffers() override;
// LayerTreeHostSingleThreadClient implementation.
- virtual void ScheduleComposite() OVERRIDE;
- virtual void ScheduleAnimation() OVERRIDE;
- virtual void DidPostSwapBuffers() OVERRIDE;
- virtual void DidAbortSwapBuffers() OVERRIDE;
+ virtual void ScheduleComposite() override;
+ virtual void ScheduleAnimation() override;
+ virtual void DidPostSwapBuffers() override;
+ virtual void DidAbortSwapBuffers() override;
// ImageTransportFactoryAndroidObserver implementation.
- virtual void OnLostResources() OVERRIDE;
+ virtual void OnLostResources() override;
// WindowAndroidCompositor implementation.
- virtual void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) OVERRIDE;
+ virtual void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) override;
virtual void RequestCopyOfOutputOnRootLayer(
- scoped_ptr<cc::CopyOutputRequest> request) OVERRIDE;
+ scoped_ptr<cc::CopyOutputRequest> request) override;
virtual void OnVSync(base::TimeTicks frame_time,
- base::TimeDelta vsync_period) OVERRIDE;
- virtual void SetNeedsAnimate() OVERRIDE;
+ base::TimeDelta vsync_period) override;
+ virtual void SetNeedsAnimate() override;
+ virtual ui::SystemUIResourceManager& GetSystemUIResourceManager() override;
+
+ void SetWindowSurface(ANativeWindow* window);
enum CompositingTrigger {
DO_NOT_COMPOSITE,
@@ -106,6 +110,7 @@ class CONTENT_EXPORT CompositorImpl
};
void PostComposite(CompositingTrigger trigger);
void Composite(CompositingTrigger trigger);
+ void CreateOutputSurface(bool fallback);
bool WillCompositeThisFrame() const {
return current_composite_task_ &&
@@ -127,9 +132,6 @@ class CONTENT_EXPORT CompositorImpl
composite_on_vsync_trigger_ = DO_NOT_COMPOSITE;
will_composite_immediately_ = false;
}
- cc::UIResourceId GenerateUIResourceFromUIResourceBitmap(
- const cc::UIResourceBitmap& bitmap,
- bool is_transient);
void OnGpuChannelEstablished();
// root_layer_ is the persistent internal root layer, while subroot_layer_
diff --git a/chromium/content/browser/renderer_host/compositor_resize_lock_aura.cc b/chromium/content/browser/renderer_host/compositor_resize_lock_aura.cc
index 419b7b326b8..9d5b7d87274 100644
--- a/chromium/content/browser/renderer_host/compositor_resize_lock_aura.cc
+++ b/chromium/content/browser/renderer_host/compositor_resize_lock_aura.cc
@@ -19,8 +19,8 @@ CompositorResizeLock::CompositorResizeLock(
const base::TimeDelta& timeout)
: ResizeLock(new_size, defer_compositor_lock),
host_(host),
- weak_ptr_factory_(this),
- cancelled_(false) {
+ cancelled_(false),
+ weak_ptr_factory_(this) {
DCHECK(host_);
TRACE_EVENT_ASYNC_BEGIN2("ui", "CompositorResizeLock", this,
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 1c2be391053..ad706904812 100644
--- a/chromium/content/browser/renderer_host/compositor_resize_lock_aura.h
+++ b/chromium/content/browser/renderer_host/compositor_resize_lock_aura.h
@@ -26,21 +26,22 @@ class CompositorResizeLock : public ResizeLock {
const gfx::Size new_size,
bool defer_compositor_lock,
const base::TimeDelta& timeout);
- virtual ~CompositorResizeLock();
+ ~CompositorResizeLock() override;
- virtual bool GrabDeferredLock() OVERRIDE;
- virtual void UnlockCompositor() OVERRIDE;
+ bool GrabDeferredLock() override;
+ void UnlockCompositor() override;
protected:
- virtual void LockCompositor() OVERRIDE;
+ void LockCompositor() override;
void CancelLock();
private:
aura::WindowTreeHost* host_;
scoped_refptr<ui::CompositorLock> compositor_lock_;
- base::WeakPtrFactory<CompositorResizeLock> weak_ptr_factory_;
bool cancelled_;
+ base::WeakPtrFactory<CompositorResizeLock> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(CompositorResizeLock);
};
diff --git a/chromium/content/browser/renderer_host/database_message_filter.cc b/chromium/content/browser/renderer_host/database_message_filter.cc
index 7c7b9a36b1b..bb5bdd6946e 100644
--- a/chromium/content/browser/renderer_host/database_message_filter.cc
+++ b/chromium/content/browser/renderer_host/database_message_filter.cc
@@ -13,22 +13,22 @@
#include "content/common/database_messages.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/result_codes.h"
+#include "storage/browser/database/database_util.h"
+#include "storage/browser/database/vfs_backend.h"
+#include "storage/browser/quota/quota_manager.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/database/database_identifier.h"
#include "third_party/sqlite/sqlite3.h"
-#include "webkit/browser/database/database_util.h"
-#include "webkit/browser/database/vfs_backend.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-#include "webkit/common/database/database_identifier.h"
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
#endif
-using quota::QuotaManager;
-using quota::QuotaStatusCode;
-using webkit_database::DatabaseTracker;
-using webkit_database::DatabaseUtil;
-using webkit_database::VfsBackend;
+using storage::QuotaManager;
+using storage::QuotaStatusCode;
+using storage::DatabaseTracker;
+using storage::DatabaseUtil;
+using storage::VfsBackend;
namespace content {
namespace {
@@ -39,7 +39,7 @@ const int kDelayDeleteRetryMs = 100;
} // namespace
DatabaseMessageFilter::DatabaseMessageFilter(
- webkit_database::DatabaseTracker* db_tracker)
+ storage::DatabaseTracker* db_tracker)
: BrowserMessageFilter(DatabaseMsgStart),
db_tracker_(db_tracker),
observer_added_(false) {
@@ -270,19 +270,19 @@ void DatabaseMessageFilter::OnDatabaseGetSpaceAvailable(
}
quota_manager->GetUsageAndQuota(
- webkit_database::GetOriginFromIdentifier(origin_identifier),
- quota::kStorageTypeTemporary,
- base::Bind(&DatabaseMessageFilter::OnDatabaseGetUsageAndQuota,
- this, reply_msg));
+ storage::GetOriginFromIdentifier(origin_identifier),
+ storage::kStorageTypeTemporary,
+ base::Bind(
+ &DatabaseMessageFilter::OnDatabaseGetUsageAndQuota, this, reply_msg));
}
void DatabaseMessageFilter::OnDatabaseGetUsageAndQuota(
IPC::Message* reply_msg,
- quota::QuotaStatusCode status,
+ storage::QuotaStatusCode status,
int64 usage,
int64 quota) {
int64 available = 0;
- if ((status == quota::kQuotaStatusOk) && (usage < quota))
+ if ((status == storage::kQuotaStatusOk) && (usage < quota))
available = quota - usage;
DatabaseHostMsg_GetSpaceAvailable::WriteReplyParams(reply_msg, available);
Send(reply_msg);
diff --git a/chromium/content/browser/renderer_host/database_message_filter.h b/chromium/content/browser/renderer_host/database_message_filter.h
index aa99e03c4e0..dcac74ab2bc 100644
--- a/chromium/content/browser/renderer_host/database_message_filter.h
+++ b/chromium/content/browser/renderer_host/database_message_filter.h
@@ -8,31 +8,29 @@
#include "base/containers/hash_tables.h"
#include "base/strings/string16.h"
#include "content/public/browser/browser_message_filter.h"
-#include "webkit/browser/database/database_tracker.h"
-#include "webkit/common/database/database_connections.h"
-#include "webkit/common/quota/quota_types.h"
+#include "storage/browser/database/database_tracker.h"
+#include "storage/common/database/database_connections.h"
+#include "storage/common/quota/quota_types.h"
namespace content {
-class DatabaseMessageFilter
- : public BrowserMessageFilter,
- public webkit_database::DatabaseTracker::Observer {
+class DatabaseMessageFilter : public BrowserMessageFilter,
+ public storage::DatabaseTracker::Observer {
public:
- explicit DatabaseMessageFilter(webkit_database::DatabaseTracker* db_tracker);
+ explicit DatabaseMessageFilter(storage::DatabaseTracker* db_tracker);
// BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual void OverrideThreadForMessage(
- const IPC::Message& message,
- BrowserThread::ID* thread) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelClosing() override;
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
- webkit_database::DatabaseTracker* database_tracker() const {
+ storage::DatabaseTracker* database_tracker() const {
return db_tracker_.get();
}
private:
- virtual ~DatabaseMessageFilter();
+ ~DatabaseMessageFilter() override;
class PromptDelegate;
@@ -55,7 +53,7 @@ class DatabaseMessageFilter
void OnDatabaseGetSpaceAvailable(const std::string& origin_identifier,
IPC::Message* reply_msg);
void OnDatabaseGetUsageAndQuota(IPC::Message* reply_msg,
- quota::QuotaStatusCode status,
+ storage::QuotaStatusCode status,
int64 usage,
int64 quota);
@@ -73,12 +71,12 @@ class DatabaseMessageFilter
int error);
// DatabaseTracker::Observer callbacks (file thread)
- virtual void OnDatabaseSizeChanged(const std::string& origin_identifier,
- const base::string16& database_name,
- int64 database_size) OVERRIDE;
- virtual void OnDatabaseScheduledForDeletion(
+ void OnDatabaseSizeChanged(const std::string& origin_identifier,
+ const base::string16& database_name,
+ int64 database_size) override;
+ void OnDatabaseScheduledForDeletion(
const std::string& origin_identifier,
- const base::string16& database_name) OVERRIDE;
+ const base::string16& database_name) override;
void DatabaseDeleteFile(const base::string16& vfs_file_name,
bool sync_dir,
@@ -86,14 +84,14 @@ class DatabaseMessageFilter
int reschedule_count);
// The database tracker for the current browser context.
- scoped_refptr<webkit_database::DatabaseTracker> db_tracker_;
+ scoped_refptr<storage::DatabaseTracker> db_tracker_;
// True if and only if this instance was added as an observer
// to DatabaseTracker.
bool observer_added_;
// Keeps track of all DB connections opened by this renderer
- webkit_database::DatabaseConnections database_connections_;
+ storage::DatabaseConnections database_connections_;
};
} // namespace content
diff --git a/chromium/content/browser/renderer_host/delegated_frame_evictor.h b/chromium/content/browser/renderer_host/delegated_frame_evictor.h
index 64df6f7bc8c..796b6c255f0 100644
--- a/chromium/content/browser/renderer_host/delegated_frame_evictor.h
+++ b/chromium/content/browser/renderer_host/delegated_frame_evictor.h
@@ -20,7 +20,7 @@ class CONTENT_EXPORT DelegatedFrameEvictor : public RendererFrameManagerClient {
public:
// |client| must outlive |this|.
explicit DelegatedFrameEvictor(DelegatedFrameEvictorClient* client);
- virtual ~DelegatedFrameEvictor();
+ ~DelegatedFrameEvictor() override;
void SwappedFrame(bool visible);
void DiscardedFrame();
@@ -31,7 +31,7 @@ class CONTENT_EXPORT DelegatedFrameEvictor : public RendererFrameManagerClient {
private:
// RendererFrameManagerClient implementation.
- virtual void EvictCurrentFrame() OVERRIDE;
+ void EvictCurrentFrame() override;
DelegatedFrameEvictorClient* client_;
bool has_frame_;
diff --git a/chromium/content/browser/renderer_host/file_utilities_message_filter.cc b/chromium/content/browser/renderer_host/file_utilities_message_filter.cc
index d819c6dcc9c..f0a1e4ab6ae 100644
--- a/chromium/content/browser/renderer_host/file_utilities_message_filter.cc
+++ b/chromium/content/browser/renderer_host/file_utilities_message_filter.cc
@@ -4,7 +4,7 @@
#include "content/browser/renderer_host/file_utilities_message_filter.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/common/file_utilities_messages.h"
diff --git a/chromium/content/browser/renderer_host/file_utilities_message_filter.h b/chromium/content/browser/renderer_host/file_utilities_message_filter.h
index ecfbfe02ce9..54a5830a6d4 100644
--- a/chromium/content/browser/renderer_host/file_utilities_message_filter.h
+++ b/chromium/content/browser/renderer_host/file_utilities_message_filter.h
@@ -21,12 +21,12 @@ class FileUtilitiesMessageFilter : public BrowserMessageFilter {
explicit FileUtilitiesMessageFilter(int process_id);
// BrowserMessageFilter implementation.
- virtual void OverrideThreadForMessage(
- const IPC::Message& message,
- BrowserThread::ID* thread) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+
private:
- virtual ~FileUtilitiesMessageFilter();
+ ~FileUtilitiesMessageFilter() override;
typedef void (*FileInfoWriteFunc)(IPC::Message* reply_msg,
const base::File::Info& file_info);
diff --git a/chromium/content/browser/renderer_host/font_utils_linux.cc b/chromium/content/browser/renderer_host/font_utils_linux.cc
new file mode 100644
index 00000000000..2ee84e1f403
--- /dev/null
+++ b/chromium/content/browser/renderer_host/font_utils_linux.cc
@@ -0,0 +1,260 @@
+// 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 <fcntl.h>
+#include <fontconfig/fontconfig.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/posix/eintr_wrapper.h"
+#include "ppapi/c/trusted/ppb_browser_font_trusted.h"
+#include "third_party/npapi/bindings/npapi_extensions.h"
+
+namespace {
+
+// MSCharSetToFontconfig translates a Microsoft charset identifier to a
+// fontconfig language set by appending to |langset|.
+// Returns true if |langset| is Latin/Greek/Cyrillic.
+bool MSCharSetToFontconfig(FcLangSet* langset, unsigned fdwCharSet) {
+ // We have need to translate raw fdwCharSet values into terms that
+ // fontconfig can understand. (See the description of fdwCharSet in the MSDN
+ // documentation for CreateFont:
+ // http://msdn.microsoft.com/en-us/library/dd183499(VS.85).aspx )
+ //
+ // Although the argument is /called/ 'charset', the actual values conflate
+ // character sets (which are sets of Unicode code points) and character
+ // encodings (which are algorithms for turning a series of bits into a
+ // series of code points.) Sometimes the values will name a language,
+ // sometimes they'll name an encoding. In the latter case I'm assuming that
+ // they mean the set of code points in the domain of that encoding.
+ //
+ // fontconfig deals with ISO 639-1 language codes:
+ // http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
+ //
+ // So, for each of the documented fdwCharSet values I've had to take a
+ // guess at the set of ISO 639-1 languages intended.
+
+ bool is_lgc = false;
+ switch (fdwCharSet) {
+ case NPCharsetAnsi:
+ // 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:
+ is_lgc = true;
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("en"));
+ break;
+ case NPCharsetBaltic:
+ // 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:
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-tw"));
+ break;
+ case NPCharsetGB2312:
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-cn"));
+ break;
+ case NPCharsetEastEurope:
+ // A scattering of eastern European languages.
+ is_lgc = true;
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("pl"));
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("cs"));
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("sk"));
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hu"));
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hr"));
+ break;
+ case NPCharsetGreek:
+ is_lgc = true;
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("el"));
+ break;
+ case NPCharsetHangul:
+ case NPCharsetJohab:
+ // Korean
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ko"));
+ break;
+ case NPCharsetRussian:
+ is_lgc = true;
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ru"));
+ break;
+ case NPCharsetShiftJIS:
+ // Japanese
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ja"));
+ break;
+ case NPCharsetTurkish:
+ is_lgc = true;
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("tr"));
+ break;
+ case NPCharsetVietnamese:
+ is_lgc = true;
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("vi"));
+ break;
+ case NPCharsetArabic:
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ar"));
+ break;
+ case NPCharsetHebrew:
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("he"));
+ break;
+ case NPCharsetThai:
+ FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("th"));
+ break;
+ // default:
+ // Don't add any languages in that case that we don't recognise the
+ // constant.
+ }
+ return is_lgc;
+}
+
+} // namespace
+
+namespace content {
+
+int MatchFontFaceWithFallback(const std::string& face,
+ bool is_bold,
+ bool is_italic,
+ uint32 charset,
+ uint32 fallback_family) {
+ FcLangSet* langset = FcLangSetCreate();
+ bool is_lgc = MSCharSetToFontconfig(langset, charset);
+ FcPattern* pattern = FcPatternCreate();
+ FcPatternAddString(
+ pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(face.c_str()));
+
+ // TODO(thestig) Check if we can access Chrome's per-script font preference
+ // here and select better default fonts for non-LGC case.
+ std::string generic_font_name;
+ if (is_lgc) {
+ switch (fallback_family) {
+ case PP_BROWSERFONT_TRUSTED_FAMILY_SERIF:
+ generic_font_name = "Times New Roman";
+ break;
+ case PP_BROWSERFONT_TRUSTED_FAMILY_SANSSERIF:
+ generic_font_name = "Arial";
+ break;
+ case PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE:
+ generic_font_name = "Courier New";
+ break;
+ }
+ }
+ if (!generic_font_name.empty()) {
+ const FcChar8* fc_generic_font_name =
+ reinterpret_cast<const FcChar8*>(generic_font_name.c_str());
+ FcPatternAddString(pattern, FC_FAMILY, fc_generic_font_name);
+ }
+
+ if (is_bold)
+ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+ if (is_italic)
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+ FcPatternAddLangSet(pattern, FC_LANG, langset);
+ FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
+ FcConfigSubstitute(NULL, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+
+ FcResult result;
+ FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
+ int font_fd = -1;
+ int good_enough_index = -1;
+ bool good_enough_index_set = false;
+
+ if (font_set) {
+ for (int i = 0; i < font_set->nfont; ++i) {
+ FcPattern* current = font_set->fonts[i];
+
+ // Older versions of fontconfig have a bug where they cannot select
+ // only scalable fonts so we have to manually filter the results.
+ FcBool is_scalable;
+ if (FcPatternGetBool(current, FC_SCALABLE, 0, &is_scalable) !=
+ FcResultMatch ||
+ !is_scalable) {
+ continue;
+ }
+
+ FcChar8* c_filename;
+ if (FcPatternGetString(current, FC_FILE, 0, &c_filename) !=
+ FcResultMatch) {
+ continue;
+ }
+
+ // We only want to return sfnt (TrueType) based fonts. We don't have a
+ // very good way of detecting this so we'll filter based on the
+ // filename.
+ bool is_sfnt = false;
+ static const char kSFNTExtensions[][5] = {".ttf", ".otc", ".TTF", ".ttc",
+ ""};
+ const size_t filename_len = strlen(reinterpret_cast<char*>(c_filename));
+ for (unsigned j = 0;; j++) {
+ if (kSFNTExtensions[j][0] == 0) {
+ // None of the extensions matched.
+ break;
+ }
+ const size_t ext_len = strlen(kSFNTExtensions[j]);
+ if (filename_len > ext_len &&
+ memcmp(c_filename + filename_len - ext_len,
+ kSFNTExtensions[j],
+ ext_len) == 0) {
+ is_sfnt = true;
+ break;
+ }
+ }
+
+ if (!is_sfnt)
+ continue;
+
+ // This font is good enough to pass muster, but we might be able to do
+ // better with subsequent ones.
+ if (!good_enough_index_set) {
+ good_enough_index = i;
+ good_enough_index_set = true;
+ }
+
+ FcValue matrix;
+ bool have_matrix = FcPatternGet(current, FC_MATRIX, 0, &matrix) == 0;
+
+ if (is_italic && have_matrix) {
+ // we asked for an italic font, but fontconfig is giving us a
+ // non-italic font with a transformation matrix.
+ continue;
+ }
+
+ FcValue embolden;
+ const bool have_embolden =
+ FcPatternGet(current, FC_EMBOLDEN, 0, &embolden) == 0;
+
+ if (is_bold && have_embolden) {
+ // we asked for a bold font, but fontconfig gave us a non-bold font
+ // and asked us to apply fake bolding.
+ continue;
+ }
+
+ font_fd =
+ HANDLE_EINTR(open(reinterpret_cast<char*>(c_filename), O_RDONLY));
+ if (font_fd >= 0)
+ break;
+ }
+ }
+
+ if (font_fd == -1 && good_enough_index_set) {
+ // We didn't find a font that we liked, so we fallback to something
+ // acceptable.
+ FcPattern* current = font_set->fonts[good_enough_index];
+ FcChar8* c_filename;
+ FcPatternGetString(current, FC_FILE, 0, &c_filename);
+ font_fd = HANDLE_EINTR(open(reinterpret_cast<char*>(c_filename), O_RDONLY));
+ }
+
+ if (font_set)
+ FcFontSetDestroy(font_set);
+ FcPatternDestroy(pattern);
+
+ return font_fd;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/font_utils_linux.h b/chromium/content/browser/renderer_host/font_utils_linux.h
new file mode 100644
index 00000000000..669f816984c
--- /dev/null
+++ b/chromium/content/browser/renderer_host/font_utils_linux.h
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_FONT_UTILS_LINUX_H_
+#define CONTENT_BROWSER_RENDERER_HOST_FONT_UTILS_LINUX_H_
+
+#include <string>
+
+namespace content {
+
+int MatchFontFaceWithFallback(const std::string& face,
+ bool is_bold,
+ bool is_italic,
+ uint32 charset,
+ uint32 fallback_family);
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_FONT_UTILS_LINUX_H_
diff --git a/chromium/content/browser/renderer_host/gamepad_browser_message_filter.h b/chromium/content/browser/renderer_host/gamepad_browser_message_filter.h
index fefbf424e4d..e5dc8aefd7b 100644
--- a/chromium/content/browser/renderer_host/gamepad_browser_message_filter.h
+++ b/chromium/content/browser/renderer_host/gamepad_browser_message_filter.h
@@ -22,18 +22,16 @@ class GamepadBrowserMessageFilter :
GamepadBrowserMessageFilter();
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
// GamepadConsumer implementation.
- virtual void OnGamepadConnected(
- unsigned index,
- const blink::WebGamepad& gamepad) OVERRIDE;
- virtual void OnGamepadDisconnected(
- unsigned index,
- const blink::WebGamepad& gamepad) OVERRIDE;
+ void OnGamepadConnected(unsigned index,
+ const blink::WebGamepad& gamepad) override;
+ void OnGamepadDisconnected(unsigned index,
+ const blink::WebGamepad& gamepad) override;
private:
- virtual ~GamepadBrowserMessageFilter();
+ ~GamepadBrowserMessageFilter() override;
void OnGamepadStartPolling(base::SharedMemoryHandle* renderer_handle);
void OnGamepadStopPolling();
diff --git a/chromium/content/browser/renderer_host/gpu_message_filter.cc b/chromium/content/browser/renderer_host/gpu_message_filter.cc
index 1cbfaf08174..d16310679e7 100644
--- a/chromium/content/browser/renderer_host/gpu_message_filter.cc
+++ b/chromium/content/browser/renderer_host/gpu_message_filter.cc
@@ -134,6 +134,7 @@ void GpuMessageFilter::OnEstablishGpuChannel(
host->EstablishGpuChannel(
render_process_id_,
share_contexts,
+ false,
base::Bind(&GpuMessageFilter::EstablishChannelCallback,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(&reply)));
diff --git a/chromium/content/browser/renderer_host/gpu_message_filter.h b/chromium/content/browser/renderer_host/gpu_message_filter.h
index 559415e70fe..57dfe9b45c3 100644
--- a/chromium/content/browser/renderer_host/gpu_message_filter.h
+++ b/chromium/content/browser/renderer_host/gpu_message_filter.h
@@ -37,7 +37,7 @@ class GpuMessageFilter : public BrowserMessageFilter {
RenderWidgetHelper* render_widget_helper);
// BrowserMessageFilter methods:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
// This set of API is used to subscribe to frame presentation events.
// See RenderWidgetHostViewFrameSubscriber for more details.
@@ -52,7 +52,7 @@ class GpuMessageFilter : public BrowserMessageFilter {
struct CreateViewCommandBufferRequest;
struct FrameSubscription;
- virtual ~GpuMessageFilter();
+ ~GpuMessageFilter() override;
// Message handlers called on the browser IO thread:
void OnEstablishGpuChannel(CauseForGpuLaunch,
@@ -81,11 +81,11 @@ class GpuMessageFilter : public BrowserMessageFilter {
scoped_refptr<RenderWidgetHelper> render_widget_helper_;
- base::WeakPtrFactory<GpuMessageFilter> weak_ptr_factory_;
-
typedef std::vector<linked_ptr<FrameSubscription> > FrameSubscriptionList;
FrameSubscriptionList frame_subscription_list_;
+ base::WeakPtrFactory<GpuMessageFilter> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(GpuMessageFilter);
};
diff --git a/chromium/content/browser/renderer_host/image_transport_factory_android.cc b/chromium/content/browser/renderer_host/image_transport_factory_android.cc
index cf3ff8b1b7c..41e315608e0 100644
--- a/chromium/content/browser/renderer_host/image_transport_factory_android.cc
+++ b/chromium/content/browser/renderer_host/image_transport_factory_android.cc
@@ -24,7 +24,7 @@ class GLContextLostListener
: public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
public:
// WebGraphicsContextLostCallback implementation.
- virtual void onContextLost() OVERRIDE;
+ virtual void onContextLost() override;
private:
static void DidLoseContext();
};
@@ -38,8 +38,8 @@ class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
CmdBufferImageTransportFactory();
virtual ~CmdBufferImageTransportFactory();
- virtual GLHelper* GetGLHelper() OVERRIDE;
- virtual uint32 GetChannelID() OVERRIDE {
+ virtual GLHelper* GetGLHelper() override;
+ virtual uint32 GetChannelID() override {
return BrowserGpuChannelHostFactory::instance()->GetGpuChannelId();
}
@@ -55,7 +55,7 @@ CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
BrowserGpuChannelHostFactory::instance();
scoped_refptr<GpuChannelHost> gpu_channel_host(factory->EstablishGpuChannelSync(
CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE));
- DCHECK(gpu_channel_host);
+ DCHECK(gpu_channel_host.get());
blink::WebGraphicsContext3D::Attributes attrs;
attrs.shareResources = true;
@@ -83,7 +83,7 @@ CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
limits,
NULL));
context_->setContextLostCallback(context_lost_listener_.get());
- if (context_->makeContextCurrent())
+ if (context_->InitializeOnCurrentThread())
context_->pushGroupMarkerEXT(
base::StringPrintf("CmdBufferImageTransportFactory-%p",
context_.get()).c_str());
@@ -104,6 +104,20 @@ GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
} // anonymous namespace
// static
+void ImageTransportFactoryAndroid::InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactoryAndroid> test_factory) {
+ DCHECK(!g_factory);
+ g_factory = test_factory.release();
+}
+
+// static
+void ImageTransportFactoryAndroid::TerminateForUnitTests() {
+ DCHECK(g_factory);
+ delete g_factory;
+ g_factory = NULL;
+}
+
+// static
ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
if (!g_factory)
g_factory = new CmdBufferImageTransportFactory();
diff --git a/chromium/content/browser/renderer_host/image_transport_factory_android.h b/chromium/content/browser/renderer_host/image_transport_factory_android.h
index 3be7a678e69..25623811406 100644
--- a/chromium/content/browser/renderer_host/image_transport_factory_android.h
+++ b/chromium/content/browser/renderer_host/image_transport_factory_android.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_RENDERER_HOST_IMAGE_TRANSPORT_FACTORY_ANDROID_H_
#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
#include "ui/gfx/native_widget_types.h"
namespace gfx {
@@ -28,10 +29,16 @@ class ImageTransportFactoryAndroidObserver {
virtual void OnLostResources() = 0;
};
-class ImageTransportFactoryAndroid {
+class CONTENT_EXPORT ImageTransportFactoryAndroid {
public:
virtual ~ImageTransportFactoryAndroid();
+ // Initializes the global transport factory for unit tests.
+ static void InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactoryAndroid> test_factory);
+ // Terminates the global transport factory for unit tests.
+ static void TerminateForUnitTests();
+
static ImageTransportFactoryAndroid* GetInstance();
virtual GLHelper* GetGLHelper() = 0;
diff --git a/chromium/content/browser/renderer_host/ime_adapter_android.cc b/chromium/content/browser/renderer_host/ime_adapter_android.cc
index afbc43400f7..b7d3748002d 100644
--- a/chromium/content/browser/renderer_host/ime_adapter_android.cc
+++ b/chromium/content/browser/renderer_host/ime_adapter_android.cc
@@ -11,6 +11,7 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "content/browser/frame_host/frame_tree.h"
@@ -21,6 +22,7 @@
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/common/frame_messages.h"
+#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/native_web_keyboard_event.h"
@@ -28,6 +30,7 @@
#include "jni/ImeAdapter_jni.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "third_party/WebKit/public/web/WebTextInputType.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF16;
@@ -86,6 +89,14 @@ bool RegisterImeAdapter(JNIEnv* env) {
ui::TEXT_INPUT_TYPE_TELEPHONE,
ui::TEXT_INPUT_TYPE_NUMBER,
ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE);
+ Java_ImeAdapter_initializeTextInputFlags(
+ env,
+ blink::WebTextInputFlagAutocompleteOn,
+ blink::WebTextInputFlagAutocompleteOff,
+ blink::WebTextInputFlagAutocorrectOn,
+ blink::WebTextInputFlagAutocorrectOff,
+ blink::WebTextInputFlagSpellcheckOn,
+ blink::WebTextInputFlagSpellcheckOff);
return true;
}
@@ -147,9 +158,10 @@ bool ImeAdapterAndroid::SendSyntheticKeyEvent(JNIEnv*,
int type,
long time_ms,
int key_code,
+ int modifiers,
int text) {
NativeWebKeyboardEvent event(static_cast<blink::WebInputEvent::Type>(type),
- 0 /* modifiers */, time_ms / 1000.0, key_code,
+ modifiers, time_ms / 1000.0, key_code,
text, false /* is_system_key */);
rwhva_->SendKeyEvent(event);
return true;
@@ -256,6 +268,36 @@ void ImeAdapterAndroid::FocusedNodeChanged(bool is_editable_node) {
}
}
+void ImeAdapterAndroid::SetCharacterBounds(
+ const std::vector<gfx::Rect>& 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;
+ base::android::ScopedJavaLocalRef<jfloatArray> coordinates_dest_array(
+ env, env->NewFloatArray(coordinates_array_size));
+ if (coordinates_dest_array.is_null())
+ return;
+
+ scoped_ptr<jfloat[]> coordinates_array(new jfloat[coordinates_array_size]);
+ for (size_t i = 0; i < character_bounds.size(); ++i) {
+ const gfx::Rect& 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();
+ }
+ // TODO(yukawa): Consider to move this to base/android/jni_array.h
+ env->SetFloatArrayRegion(coordinates_dest_array.obj(), 0,
+ coordinates_array_size, coordinates_array.get());
+ base::android::CheckException(env);
+ Java_ImeAdapter_setCharacterBounds(env, obj.obj(),
+ coordinates_dest_array.obj());
+}
+
void ImeAdapterAndroid::SetEditableSelectionOffsets(JNIEnv*, jobject,
int start, int end) {
RenderFrameHost* rfh = GetFocusedFrame();
@@ -276,7 +318,7 @@ void ImeAdapterAndroid::SetComposingRegion(JNIEnv*, jobject,
underlines.push_back(blink::WebCompositionUnderline(
0, end - start, SK_ColorBLACK, false, SK_ColorTRANSPARENT));
- rfh->Send(new FrameMsg_SetCompositionFromExistingText(
+ rfh->Send(new InputMsg_SetCompositionFromExistingText(
rfh->GetRoutingID(), start, end, underlines));
}
diff --git a/chromium/content/browser/renderer_host/ime_adapter_android.h b/chromium/content/browser/renderer_host/ime_adapter_android.h
index a23696da37d..50e9dbfa89d 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.h"
namespace content {
@@ -41,6 +44,7 @@ class ImeAdapterAndroid {
int event_type,
long timestamp_ms,
int native_key_code,
+ int modifiers,
int unicode_char);
void SetComposingText(JNIEnv*,
jobject obj,
@@ -63,6 +67,7 @@ class ImeAdapterAndroid {
// Called from native -> java
void CancelComposition();
void FocusedNodeChanged(bool is_editable_node);
+ void SetCharacterBounds(const std::vector<gfx::Rect>& rects);
private:
RenderWidgetHostImpl* GetRenderWidgetHostImpl();
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 0c49a847578..c4b6d9600ab 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
@@ -31,22 +31,22 @@ class GestureEventQueueTest : public testing::Test,
: acked_gesture_event_count_(0),
sent_gesture_event_count_(0) {}
- virtual ~GestureEventQueueTest() {}
+ ~GestureEventQueueTest() override {}
// testing::Test
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
queue_.reset(new GestureEventQueue(this, this, DefaultConfig()));
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// Process all pending tasks to avoid leaks.
RunUntilIdle();
queue_.reset();
}
// GestureEventQueueClient
- virtual void SendGestureEventImmediately(
- const GestureEventWithLatencyInfo& event) OVERRIDE {
+ void SendGestureEventImmediately(
+ const GestureEventWithLatencyInfo& event) override {
++sent_gesture_event_count_;
if (sync_ack_result_) {
scoped_ptr<InputEventAckState> ack_result = sync_ack_result_.Pass();
@@ -54,19 +54,19 @@ class GestureEventQueueTest : public testing::Test,
}
}
- virtual void OnGestureEventAck(
- const GestureEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE {
+ void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override {
++acked_gesture_event_count_;
last_acked_event_ = event.event;
- if (sync_followup_event_)
- SimulateGestureEvent(*sync_followup_event_.Pass());
+ if (sync_followup_event_) {
+ auto sync_followup_event = sync_followup_event_.Pass();
+ SimulateGestureEvent(*sync_followup_event);
+ }
}
// TouchpadTapSuppressionControllerClient
- virtual void SendMouseEventImmediately(
- const MouseEventWithLatencyInfo& event) OVERRIDE {
- }
+ void SendMouseEventImmediately(
+ const MouseEventWithLatencyInfo& event) override {}
protected:
static GestureEventQueue::Config DefaultConfig() {
diff --git a/chromium/content/browser/renderer_host/input/gesture_text_selector.cc b/chromium/content/browser/renderer_host/input/gesture_text_selector.cc
new file mode 100644
index 00000000000..67c4fe7ebb0
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/gesture_text_selector.cc
@@ -0,0 +1,115 @@
+// 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/renderer_host/input/gesture_text_selector.h"
+
+#include "ui/events/event_constants.h"
+#include "ui/events/gesture_detection/gesture_detector.h"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
+#include "ui/events/gesture_detection/motion_event.h"
+
+using ui::GestureDetector;
+using ui::MotionEvent;
+
+namespace content {
+namespace {
+scoped_ptr<GestureDetector> CreateGestureDetector(
+ ui::GestureListener* listener) {
+ GestureDetector::Config config =
+ ui::DefaultGestureProviderConfig().gesture_detector_config;
+
+ ui::DoubleTapListener* null_double_tap_listener = nullptr;
+
+ // Doubletap, showpress and longpress detection are not required, and
+ // should be explicitly disabled for efficiency.
+ scoped_ptr<ui::GestureDetector> detector(
+ new ui::GestureDetector(config, listener, null_double_tap_listener));
+ detector->set_longpress_enabled(false);
+ detector->set_showpress_enabled(false);
+
+ return detector.Pass();
+}
+
+} // namespace
+
+GestureTextSelector::GestureTextSelector(GestureTextSelectorClient* client)
+ : client_(client),
+ text_selection_triggered_(false),
+ secondary_button_pressed_(false),
+ anchor_x_(0.0f),
+ anchor_y_(0.0f) {
+ DCHECK(client);
+}
+
+GestureTextSelector::~GestureTextSelector() {
+}
+
+bool GestureTextSelector::OnTouchEvent(const MotionEvent& event) {
+ if (event.GetAction() == MotionEvent::ACTION_DOWN) {
+ // Only trigger selection on ACTION_DOWN to prevent partial touch or gesture
+ // sequences from being forwarded.
+ text_selection_triggered_ = ShouldStartTextSelection(event);
+ secondary_button_pressed_ =
+ event.GetButtonState() == MotionEvent::BUTTON_SECONDARY;
+ anchor_x_ = event.GetX();
+ anchor_y_ = event.GetY();
+ }
+
+ if (!text_selection_triggered_)
+ return false;
+
+ if (event.GetAction() == MotionEvent::ACTION_MOVE) {
+ secondary_button_pressed_ =
+ event.GetButtonState() == MotionEvent::BUTTON_SECONDARY;
+ if (!secondary_button_pressed_) {
+ anchor_x_ = event.GetX();
+ anchor_y_ = event.GetY();
+ }
+ }
+
+ if (!gesture_detector_)
+ gesture_detector_ = CreateGestureDetector(this);
+
+ gesture_detector_->OnTouchEvent(event);
+
+ // Always return true, even if |gesture_detector_| technically doesn't
+ // consume the event, to prevent a partial touch stream from being forwarded.
+ return true;
+}
+
+bool GestureTextSelector::OnSingleTapUp(const MotionEvent& e) {
+ DCHECK(text_selection_triggered_);
+ client_->LongPress(e.GetEventTime(), e.GetX(), e.GetY());
+ return true;
+}
+
+bool GestureTextSelector::OnScroll(const MotionEvent& e1,
+ const MotionEvent& e2,
+ float distance_x,
+ float distance_y) {
+ DCHECK(text_selection_triggered_);
+
+ // Return if Stylus button is not pressed.
+ if (!secondary_button_pressed_)
+ return true;
+
+ // TODO(changwan): check if we can show handles after the scroll finishes
+ // instead. Currently it is not possible as ShowSelectionHandles should
+ // be called before we change the selection.
+ client_->ShowSelectionHandlesAutomatically();
+ client_->SelectRange(anchor_x_, anchor_y_, e2.GetX(), e2.GetY());
+ return true;
+}
+
+// static
+bool GestureTextSelector::ShouldStartTextSelection(const MotionEvent& event) {
+ DCHECK_GT(event.GetPointerCount(), 0u);
+ // Currently we are supporting stylus-only cases.
+ const bool is_stylus = event.GetToolType(0) == MotionEvent::TOOL_TYPE_STYLUS;
+ const bool is_only_secondary_button_pressed =
+ event.GetButtonState() == MotionEvent::BUTTON_SECONDARY;
+ return is_stylus && is_only_secondary_button_pressed;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/gesture_text_selector.h b/chromium/content/browser/renderer_host/input/gesture_text_selector.h
new file mode 100644
index 00000000000..e494045b731
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/gesture_text_selector.h
@@ -0,0 +1,72 @@
+// 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_RENDERER_HOST_INPUT_GESTURE_TEXT_SELECTOR_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_GESTURE_TEXT_SELECTOR_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "ui/events/gesture_detection/gesture_listeners.h"
+
+namespace ui {
+class GestureDetector;
+class MotionEvent;
+}
+
+namespace content {
+class GestureTextSelectorTest;
+
+// Interface with which GestureTextSelector can select, unselect, show
+// selection handles, or long press.
+class CONTENT_EXPORT GestureTextSelectorClient {
+ public:
+ virtual ~GestureTextSelectorClient() {}
+
+ virtual void ShowSelectionHandlesAutomatically() = 0;
+ virtual void SelectRange(float x1, float y1, float x2, float y2) = 0;
+ virtual void LongPress(base::TimeTicks time, float x, float y) = 0;
+};
+
+// A class to handle gesture-based text selection, such as when clicking first
+// button on stylus input. It also generates a synthetic long press gesture on
+// tap so that a word can be selected or the contextual menu can be shown.
+class CONTENT_EXPORT GestureTextSelector : public ui::SimpleGestureListener {
+ public:
+ explicit GestureTextSelector(GestureTextSelectorClient* client);
+ ~GestureTextSelector() override;
+
+ // This should be called before |event| is seen by the platform gesture
+ // detector or forwarded to web content.
+ bool OnTouchEvent(const ui::MotionEvent& event);
+
+ private:
+ friend class GestureTextSelectorTest;
+ FRIEND_TEST_ALL_PREFIXES(GestureTextSelectorTest,
+ ShouldStartTextSelection);
+
+ // SimpleGestureListener implementation.
+ bool OnSingleTapUp(const ui::MotionEvent& e) override;
+ bool OnScroll(const ui::MotionEvent& e1,
+ const ui::MotionEvent& e2,
+ float distance_x,
+ float distance_y) override;
+
+ static bool ShouldStartTextSelection(const ui::MotionEvent& event);
+
+ GestureTextSelectorClient* client_;
+ bool text_selection_triggered_;
+ bool secondary_button_pressed_;
+ float anchor_x_;
+ float anchor_y_;
+ scoped_ptr<ui::GestureDetector> gesture_detector_;
+
+ DISALLOW_COPY_AND_ASSIGN(GestureTextSelector);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_GESTURE_TEXT_SELECTOR_H_
diff --git a/chromium/content/browser/renderer_host/input/gesture_text_selector_unittest.cc b/chromium/content/browser/renderer_host/input/gesture_text_selector_unittest.cc
new file mode 100644
index 00000000000..dfa2af1ee54
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/gesture_text_selector_unittest.cc
@@ -0,0 +1,223 @@
+// 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 <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "content/browser/renderer_host/input/gesture_text_selector.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/gesture_detection/motion_event.h"
+#include "ui/events/test/motion_event_test_utils.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+using ui::MotionEvent;
+using ui::test::MockMotionEvent;
+
+namespace content {
+
+class GestureTextSelectorTest : public testing::Test,
+ public GestureTextSelectorClient {
+ public:
+ GestureTextSelectorTest() {}
+ ~GestureTextSelectorTest() override {}
+
+ // Test implementation.
+ void SetUp() override {
+ selector_.reset(new GestureTextSelector(this));
+ event_log_.clear();
+ }
+
+ void TearDown() override {
+ selector_.reset();
+ event_log_.clear();
+ }
+
+ // GestureTextSelectorClient implementation.
+ void ShowSelectionHandlesAutomatically() override {
+ event_log_.push_back("Show");
+ }
+
+ void SelectRange(float x1, float y1, float x2, float y2) override {
+ std::stringstream ss;
+ ss << "SelectRange(" << x1 << ", " << y1 << ", " << x2 << ", " << y2 << ")";
+ event_log_.push_back(ss.str());
+ }
+
+ void LongPress(base::TimeTicks time, float x, float y) override {
+ event_log_.push_back("LongPress");
+ }
+
+ protected:
+ scoped_ptr<GestureTextSelector> selector_;
+ std::vector<std::string> event_log_;
+};
+
+TEST_F(GestureTextSelectorTest, ShouldStartTextSelection) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ { // Touched with a finger.
+ MockMotionEvent e(MotionEvent::ACTION_DOWN, event_time, 50.0f, 50.0f);
+ e.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER);
+ e.set_button_state(0);
+ EXPECT_FALSE(selector_->ShouldStartTextSelection(e));
+ }
+
+ { // Touched with a stylus, but no button pressed.
+ MockMotionEvent e(MotionEvent::ACTION_DOWN, event_time, 50.0f, 50.0f);
+ e.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ e.set_button_state(0);
+ EXPECT_FALSE(selector_->ShouldStartTextSelection(e));
+ }
+
+ { // Touched with a stylus, with first button (BUTTON_SECONDARY) pressed.
+ MockMotionEvent e(MotionEvent::ACTION_DOWN, event_time, 50.0f, 50.0f);
+ e.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ e.set_button_state(MotionEvent::BUTTON_SECONDARY);
+ EXPECT_TRUE(selector_->ShouldStartTextSelection(e));
+ }
+
+ { // Touched with a stylus, with two buttons pressed.
+ MockMotionEvent e(MotionEvent::ACTION_DOWN, event_time, 50.0f, 50.0f);
+ e.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ e.set_button_state(
+ MotionEvent::BUTTON_SECONDARY | MotionEvent::BUTTON_TERTIARY);
+ EXPECT_FALSE(selector_->ShouldStartTextSelection(e));
+ }
+}
+
+TEST_F(GestureTextSelectorTest, FingerTouch) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float x = 50.0f;
+ const float y = 30.0f;
+ // 1. Touched with a finger: ignored
+ MockMotionEvent finger(MotionEvent::ACTION_DOWN, event_time, x, y);
+ finger.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER);
+ EXPECT_FALSE(selector_->OnTouchEvent(finger));
+ // We do not consume finger events.
+ EXPECT_TRUE(event_log_.empty());
+}
+
+TEST_F(GestureTextSelectorTest, PenDragging) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float x1 = 50.0f;
+ const float y1 = 30.0f;
+ const float x2 = 100.0f;
+ const float y2 = 90.0f;
+ // 1. ACTION_DOWN with stylus + button
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ MockMotionEvent action_down(MotionEvent::ACTION_DOWN, event_time, x1, y1);
+ action_down.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_down.set_button_state(MotionEvent::BUTTON_SECONDARY);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_down));
+ EXPECT_TRUE(event_log_.empty());
+
+ // 2. ACTION_MOVE
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ MockMotionEvent action_move(MotionEvent::ACTION_MOVE, event_time, x2, y2);
+ action_move.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_move.set_button_state(MotionEvent::BUTTON_SECONDARY);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_move));
+ ASSERT_EQ(2u, event_log_.size());
+ EXPECT_STREQ("Show", event_log_[0].c_str());
+ EXPECT_STREQ("SelectRange(50, 30, 100, 90)", event_log_[1].c_str());
+
+ // 3. ACTION_UP
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ MockMotionEvent action_up(MotionEvent::ACTION_UP, event_time, x2, y2);
+ action_up.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_up.set_button_state(0);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_up));
+ ASSERT_EQ(2u, event_log_.size()); // NO CHANGE
+}
+
+TEST_F(GestureTextSelectorTest, PenDraggingButtonNotPressed) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ float x = 50.0f;
+ float y = 30.0f;
+
+ // 1. ACTION_DOWN with stylus + button
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ MockMotionEvent action_down(MotionEvent::ACTION_DOWN, event_time, x, y);
+ action_down.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_down.set_button_state(MotionEvent::BUTTON_SECONDARY);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_down));
+ EXPECT_TRUE(event_log_.empty());
+
+ // 2. ACTION_MOVE
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ x += 20; // 70
+ y += 20; // 50
+ MockMotionEvent action_move(MotionEvent::ACTION_MOVE, event_time, x, y);
+ action_move.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_move.set_button_state(MotionEvent::BUTTON_SECONDARY);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_move));
+ ASSERT_EQ(2u, event_log_.size());
+ EXPECT_STREQ("Show", event_log_[0].c_str());
+ EXPECT_STREQ("SelectRange(50, 30, 70, 50)", event_log_[1].c_str());
+
+ // 3. ACTION_MOVE with stylus + no button
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ x += 20; // 90
+ y += 20; // 70
+ action_move = MockMotionEvent(MotionEvent::ACTION_MOVE, event_time, x, y);
+ action_move.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_move.set_button_state(0);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_move));
+ EXPECT_EQ(2u, event_log_.size()); // NO CHANGE
+
+ // 4. ACTION_MOVE with stylus + button pressed again
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ x += 20; // 110
+ y += 20; // 90
+ action_move = MockMotionEvent(MotionEvent::ACTION_MOVE, event_time, x, y);
+ action_move.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_move.set_button_state(MotionEvent::BUTTON_SECONDARY);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_move));
+ EXPECT_EQ(4u, event_log_.size());
+ EXPECT_STREQ("SelectRange(90, 70, 110, 90)", event_log_.back().c_str());
+
+ // 5. ACTION_UP
+ event_time += base::TimeDelta::FromMilliseconds(10);
+ MockMotionEvent action_up(MotionEvent::ACTION_UP, event_time, x, y);
+ action_up.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_up.set_button_state(0);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_up));
+ EXPECT_EQ(4u, event_log_.size()); // NO CHANGE
+}
+
+TEST_F(GestureTextSelectorTest, TapTriggersLongPressSelection) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float x1 = 50.0f;
+ const float y1 = 30.0f;
+ const float x2 = 51.0f;
+ const float y2 = 31.0f;
+ // 1. ACTION_DOWN with stylus + button
+ event_time += base::TimeDelta::FromMilliseconds(1);
+ MockMotionEvent action_down(MotionEvent::ACTION_DOWN, event_time, x1, y1);
+ action_down.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_down.set_button_state(MotionEvent::BUTTON_SECONDARY);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_down));
+ EXPECT_TRUE(event_log_.empty());
+
+ // 2. ACTION_MOVE
+ event_time += base::TimeDelta::FromMilliseconds(1);
+ MockMotionEvent action_move(MotionEvent::ACTION_MOVE, event_time, x2, y2);
+ action_move.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_move.set_button_state(MotionEvent::BUTTON_SECONDARY);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_move));
+ EXPECT_TRUE(event_log_.empty());
+
+ // 3. ACTION_UP
+ event_time += base::TimeDelta::FromMilliseconds(1);
+ MockMotionEvent action_up(MotionEvent::ACTION_UP, event_time, x2, y2);
+ action_up.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS);
+ action_up.set_button_state(0);
+ EXPECT_TRUE(selector_->OnTouchEvent(action_up));
+ ASSERT_EQ(1u, event_log_.size());
+ EXPECT_STREQ("LongPress", event_log_.back().c_str());
+}
+
+} // 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 1b30815c7ce..96b68c322fe 100644
--- a/chromium/content/browser/renderer_host/input/input_router.h
+++ b/chromium/content/browser/renderer_host/input/input_router.h
@@ -22,7 +22,7 @@ class InputRouterClient;
// received, it is free to customize when those events are dispatched.
class InputRouter : public IPC::Listener {
public:
- virtual ~InputRouter() {}
+ ~InputRouter() override {}
// Should be called only in response to |SetNeedsFlush| requests made via
// the |InputRouterClient|.
diff --git a/chromium/content/browser/renderer_host/input/input_router_config_helper.cc b/chromium/content/browser/renderer_host/input/input_router_config_helper.cc
index 31b17cfab70..d78b6cb2a90 100644
--- a/chromium/content/browser/renderer_host/input/input_router_config_helper.cc
+++ b/chromium/content/browser/renderer_host/input/input_router_config_helper.cc
@@ -9,8 +9,7 @@
#include "ui/events/gesture_detection/gesture_detector.h"
#if defined(USE_AURA)
-#include "ui/events/gestures/gesture_configuration.h"
-#include "ui/events/gestures/unified_gesture_detector_enabled.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
#elif defined(OS_ANDROID)
#include "ui/gfx/android/view_configuration.h"
#include "ui/gfx/screen.h"
@@ -20,30 +19,32 @@ namespace content {
namespace {
#if defined(USE_AURA)
-
+// TODO(jdduke): Consolidate router configuration paths using
+// ui::GestureConfiguration.
GestureEventQueue::Config GetGestureEventQueueConfig() {
GestureEventQueue::Config config;
-
+ ui::GestureConfiguration* gesture_config =
+ ui::GestureConfiguration::GetInstance();
config.debounce_interval = base::TimeDelta::FromMilliseconds(
- ui::GestureConfiguration::scroll_debounce_interval_in_ms());
+ gesture_config->scroll_debounce_interval_in_ms());
config.touchscreen_tap_suppression_config.enabled = true;
config.touchscreen_tap_suppression_config.max_cancel_to_down_time =
base::TimeDelta::FromMilliseconds(
- ui::GestureConfiguration::fling_max_cancel_to_down_time_in_ms());
+ gesture_config->fling_max_cancel_to_down_time_in_ms());
config.touchscreen_tap_suppression_config.max_tap_gap_time =
- base::TimeDelta::FromMilliseconds(static_cast<int>(
- ui::GestureConfiguration::semi_long_press_time_in_seconds() * 1000));
+ base::TimeDelta::FromMilliseconds(
+ gesture_config->semi_long_press_time_in_ms());
config.touchpad_tap_suppression_config.enabled = true;
config.touchpad_tap_suppression_config.max_cancel_to_down_time =
base::TimeDelta::FromMilliseconds(
- ui::GestureConfiguration::fling_max_cancel_to_down_time_in_ms());
+ gesture_config->fling_max_cancel_to_down_time_in_ms());
config.touchpad_tap_suppression_config.max_tap_gap_time =
- base::TimeDelta::FromMilliseconds(static_cast<int>(
- ui::GestureConfiguration::fling_max_tap_gap_time_in_ms() * 1000));
+ base::TimeDelta::FromMilliseconds(
+ gesture_config->fling_max_tap_gap_time_in_ms());
return config;
}
@@ -52,10 +53,8 @@ TouchEventQueue::Config GetTouchEventQueueConfig() {
TouchEventQueue::Config config;
config.touchmove_slop_suppression_length_dips =
- ui::GestureConfiguration::max_touch_move_in_pixels_for_click();
-
- config.touchmove_slop_suppression_region_includes_boundary =
- ui::IsUnifiedGestureDetectorEnabled();
+ ui::GestureConfiguration::GetInstance()
+ ->max_touch_move_in_pixels_for_click();
return config;
}
@@ -114,7 +113,7 @@ TouchEventQueue::Config GetTouchEventQueueConfig() {
TouchEventQueue::TouchScrollingMode GetTouchScrollingMode() {
std::string modeString =
- CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kTouchScrollingMode);
if (modeString == switches::kTouchScrollingModeAsyncTouchmove)
return TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE;
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 a509465a653..4848f6dc6f4 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl.cc
+++ b/chromium/content/browser/renderer_host/input/input_router_impl.cc
@@ -68,7 +68,7 @@ InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
client_(client),
ack_handler_(ack_handler),
routing_id_(routing_id),
- select_range_pending_(false),
+ select_message_pending_(false),
move_caret_pending_(false),
mouse_move_pending_(false),
mouse_wheel_pending_(false),
@@ -83,7 +83,9 @@ InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
UpdateTouchAckTimeoutEnabled();
}
-InputRouterImpl::~InputRouterImpl() {}
+InputRouterImpl::~InputRouterImpl() {
+ STLDeleteElements(&pending_select_messages_);
+}
void InputRouterImpl::Flush() {
flush_requested_ = true;
@@ -95,7 +97,8 @@ bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
switch (message->type()) {
// Check for types that require an ACK.
case InputMsg_SelectRange::ID:
- return SendSelectRange(message.Pass());
+ case InputMsg_MoveRangeSelectionExtent::ID:
+ return SendSelectMessage(message.Pass());
case InputMsg_MoveCaret::ID:
return SendMoveCaret(message.Pass());
case InputMsg_HandleInputEvent::ID:
@@ -150,8 +153,8 @@ void InputRouterImpl::SendWheelEvent(const QueuedWheelEvent& wheel_event) {
mouse_wheel_pending_ = true;
current_wheel_event_ = wheel_event;
- HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
- coalesced_mouse_wheel_events_.size());
+ LOCAL_HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
+ coalesced_mouse_wheel_events_.size());
FilterAndSendWebInputEvent(
wheel_event.event.event, wheel_event.event.latency, false);
@@ -164,7 +167,7 @@ void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
// renderer and we need to give something to the HandleKeyboardEvent
// handler.
key_queue_.push_back(key_event);
- HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
+ LOCAL_HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
gesture_event_queue_.FlingHasBeenHalted();
@@ -267,8 +270,10 @@ bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(InputRouterImpl, message)
IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck)
IPC_MESSAGE_HANDLER(InputHostMsg_DidOverscroll, OnDidOverscroll)
- IPC_MESSAGE_HANDLER(ViewHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SelectRange_ACK, OnSelectRangeAck)
+ IPC_MESSAGE_HANDLER(InputHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck)
+ IPC_MESSAGE_HANDLER(InputHostMsg_SelectRange_ACK, OnSelectMessageAck)
+ IPC_MESSAGE_HANDLER(InputHostMsg_MoveRangeSelectionExtent_ACK,
+ OnSelectMessageAck)
IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
OnHasTouchEventHandlers)
IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction,
@@ -298,14 +303,25 @@ void InputRouterImpl::OnGestureEventAck(
ack_handler_->OnGestureEventAck(event, ack_result);
}
-bool InputRouterImpl::SendSelectRange(scoped_ptr<IPC::Message> message) {
- DCHECK(message->type() == InputMsg_SelectRange::ID);
- if (select_range_pending_) {
- next_selection_range_ = message.Pass();
+bool InputRouterImpl::SendSelectMessage(
+ scoped_ptr<IPC::Message> message) {
+ DCHECK(message->type() == InputMsg_SelectRange::ID ||
+ message->type() == InputMsg_MoveRangeSelectionExtent::ID);
+
+ // TODO(jdduke): Factor out common logic between selection and caret-related
+ // IPC messages.
+ if (select_message_pending_) {
+ if (!pending_select_messages_.empty() &&
+ pending_select_messages_.back()->type() == message->type()) {
+ delete pending_select_messages_.back();
+ pending_select_messages_.pop_back();
+ }
+
+ pending_select_messages_.push_back(message.release());
return true;
}
- select_range_pending_ = true;
+ select_message_pending_ = true;
return Send(message.release());
}
@@ -353,8 +369,8 @@ void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
// cancelable (respect ACK disposition) or not.
bool ignores_ack = WebInputEventTraits::IgnoresAckDisposition(input_event);
if (WebInputEvent::isTouchEventType(input_event.type)) {
- DCHECK(!ignores_ack ==
- static_cast<const blink::WebTouchEvent&>(input_event).cancelable);
+ DCHECK_NE(static_cast<int>(ignores_ack),
+ static_cast<const blink::WebTouchEvent&>(input_event).cancelable);
}
// If we don't care about the ack disposition, send the ack immediately.
@@ -487,10 +503,15 @@ void InputRouterImpl::OnMsgMoveCaretAck() {
SendMoveCaret(next_move_caret_.Pass());
}
-void InputRouterImpl::OnSelectRangeAck() {
- select_range_pending_ = false;
- if (next_selection_range_)
- SendSelectRange(next_selection_range_.Pass());
+void InputRouterImpl::OnSelectMessageAck() {
+ select_message_pending_ = false;
+ if (!pending_select_messages_.empty()) {
+ scoped_ptr<IPC::Message> next_message =
+ make_scoped_ptr(pending_select_messages_.front());
+ pending_select_messages_.pop_front();
+
+ SendSelectMessage(next_message.Pass());
+ }
}
void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) {
@@ -679,7 +700,7 @@ bool InputRouterImpl::HasPendingEvents() const {
!key_queue_.empty() ||
mouse_move_pending_ ||
mouse_wheel_pending_ ||
- select_range_pending_ ||
+ select_message_pending_ ||
move_caret_pending_;
}
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 e06113b3e58..2b00c12996f 100644
--- a/chromium/content/browser/renderer_host/input/input_router_impl.h
+++ b/chromium/content/browser/renderer_host/input/input_router_impl.h
@@ -33,7 +33,6 @@ namespace content {
class InputAckHandler;
class InputRouterClient;
class OverscrollController;
-class RenderWidgetHostImpl;
struct DidOverscrollParams;
// A default implementation for browser input event routing.
@@ -54,52 +53,49 @@ class CONTENT_EXPORT InputRouterImpl
InputAckHandler* ack_handler,
int routing_id,
const Config& config);
- virtual ~InputRouterImpl();
+ ~InputRouterImpl() override;
// InputRouter
- virtual void Flush() OVERRIDE;
- virtual bool SendInput(scoped_ptr<IPC::Message> message) OVERRIDE;
- virtual void SendMouseEvent(
- const MouseEventWithLatencyInfo& mouse_event) OVERRIDE;
- virtual void SendWheelEvent(
- const MouseWheelEventWithLatencyInfo& wheel_event) OVERRIDE;
- virtual void SendKeyboardEvent(
- const NativeWebKeyboardEvent& key_event,
- const ui::LatencyInfo& latency_info,
- bool is_keyboard_shortcut) OVERRIDE;
- virtual void SendGestureEvent(
- const GestureEventWithLatencyInfo& gesture_event) OVERRIDE;
- virtual void SendTouchEvent(
- const TouchEventWithLatencyInfo& touch_event) OVERRIDE;
- virtual const NativeWebKeyboardEvent* GetLastKeyboardEvent() const OVERRIDE;
- virtual bool ShouldForwardTouchEvent() const OVERRIDE;
- virtual void OnViewUpdated(int view_flags) OVERRIDE;
- virtual bool HasPendingEvents() const OVERRIDE;
+ void Flush() override;
+ bool SendInput(scoped_ptr<IPC::Message> message) override;
+ void SendMouseEvent(const MouseEventWithLatencyInfo& mouse_event) override;
+ void SendWheelEvent(
+ const MouseWheelEventWithLatencyInfo& wheel_event) override;
+ void SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
+ const ui::LatencyInfo& latency_info,
+ bool is_keyboard_shortcut) override;
+ void SendGestureEvent(
+ const GestureEventWithLatencyInfo& gesture_event) override;
+ void SendTouchEvent(const TouchEventWithLatencyInfo& touch_event) override;
+ const NativeWebKeyboardEvent* GetLastKeyboardEvent() const override;
+ bool ShouldForwardTouchEvent() const override;
+ void OnViewUpdated(int view_flags) override;
+ bool HasPendingEvents() const override;
// IPC::Listener
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
friend class InputRouterImplTest;
// TouchpadTapSuppressionControllerClient
- virtual void SendMouseEventImmediately(
- const MouseEventWithLatencyInfo& mouse_event) OVERRIDE;
+ void SendMouseEventImmediately(
+ const MouseEventWithLatencyInfo& mouse_event) override;
// TouchEventQueueClient
- virtual void SendTouchEventImmediately(
- const TouchEventWithLatencyInfo& touch_event) OVERRIDE;
- virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE;
+ void SendTouchEventImmediately(
+ const TouchEventWithLatencyInfo& touch_event) override;
+ void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
// GetureEventFilterClient
- virtual void SendGestureEventImmediately(
- const GestureEventWithLatencyInfo& gesture_event) OVERRIDE;
- virtual void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE;
+ void SendGestureEventImmediately(
+ const GestureEventWithLatencyInfo& gesture_event) override;
+ void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
bool SendMoveCaret(scoped_ptr<IPC::Message> message);
- bool SendSelectRange(scoped_ptr<IPC::Message> message);
+ bool SendSelectMessage(scoped_ptr<IPC::Message> message);
bool Send(IPC::Message* message);
// Filters and forwards |input_event| to the appropriate handler.
@@ -152,7 +148,7 @@ private:
void OnInputEventAck(const InputHostMsg_HandleInputEvent_ACK_Params& ack);
void OnDidOverscroll(const DidOverscrollParams& params);
void OnMsgMoveCaretAck();
- void OnSelectRangeAck();
+ void OnSelectMessageAck();
void OnHasTouchEventHandlers(bool has_handlers);
void OnSetTouchAction(TouchAction touch_action);
@@ -216,11 +212,13 @@ private:
InputAckHandler* ack_handler_;
int routing_id_;
- // (Similar to |mouse_move_pending_|.) True while waiting for SelectRange_ACK.
- bool select_range_pending_;
+ // (Similar to |mouse_move_pending_|.) True while waiting for SelectRange_ACK
+ // or MoveRangeSelectionExtent_ACK.
+ bool select_message_pending_;
- // (Similar to |next_mouse_move_|.) The next SelectRange to send, if any.
- scoped_ptr<IPC::Message> next_selection_range_;
+ // Queue of pending select messages to send after receving the next select
+ // message ack.
+ std::deque<IPC::Message*> pending_select_messages_;
// (Similar to |mouse_move_pending_|.) True while waiting for MoveCaret_ACK.
bool move_caret_pending_;
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 0a8c89fd176..ad832642acf 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
@@ -28,26 +28,26 @@ namespace {
class NullInputAckHandler : public InputAckHandler {
public:
NullInputAckHandler() : ack_count_(0) {}
- virtual ~NullInputAckHandler() {}
+ ~NullInputAckHandler() override {}
// InputAckHandler
- virtual void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
- InputEventAckState ack_result) OVERRIDE {
+ void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
+ InputEventAckState ack_result) override {
++ack_count_;
}
- virtual void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE {
+ void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override {
++ack_count_;
}
- virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE {
+ void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override {
++ack_count_;
}
- virtual void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE {
+ void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override {
++ack_count_;
}
- virtual void OnUnexpectedEventAck(UnexpectedEventAckType type) OVERRIDE {
+ void OnUnexpectedEventAck(UnexpectedEventAckType type) override {
++ack_count_;
}
@@ -66,28 +66,28 @@ class NullInputAckHandler : public InputAckHandler {
class NullInputRouterClient : public InputRouterClient {
public:
NullInputRouterClient() {}
- virtual ~NullInputRouterClient() {}
+ ~NullInputRouterClient() override {}
// InputRouterClient
- virtual InputEventAckState FilterInputEvent(
+ InputEventAckState FilterInputEvent(
const blink::WebInputEvent& input_event,
- const ui::LatencyInfo& latency_info) OVERRIDE {
+ const ui::LatencyInfo& latency_info) override {
return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
- virtual void IncrementInFlightEventCount() OVERRIDE {}
- virtual void DecrementInFlightEventCount() OVERRIDE {}
- virtual void OnHasTouchEventHandlers(bool has_handlers) OVERRIDE {}
- virtual void DidFlush() OVERRIDE {}
- virtual void SetNeedsFlush() OVERRIDE {}
- virtual void DidOverscroll(const DidOverscrollParams& params) OVERRIDE {}
+ void IncrementInFlightEventCount() override {}
+ void DecrementInFlightEventCount() override {}
+ void OnHasTouchEventHandlers(bool has_handlers) override {}
+ void DidFlush() override {}
+ void SetNeedsFlush() override {}
+ void DidOverscroll(const DidOverscrollParams& params) override {}
};
class NullIPCSender : public IPC::Sender {
public:
NullIPCSender() : sent_count_(0) {}
- virtual ~NullIPCSender() {}
+ ~NullIPCSender() override {}
- virtual bool Send(IPC::Message* message) OVERRIDE {
+ bool Send(IPC::Message* message) override {
delete message;
++sent_count_;
return true;
@@ -197,11 +197,11 @@ class InputEventTimer {
class InputRouterImplPerfTest : public testing::Test {
public:
InputRouterImplPerfTest() : last_input_id_(0) {}
- virtual ~InputRouterImplPerfTest() {}
+ ~InputRouterImplPerfTest() override {}
protected:
// testing::Test
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
sender_.reset(new NullIPCSender());
client_.reset(new NullInputRouterClient());
ack_handler_.reset(new NullInputAckHandler());
@@ -212,7 +212,7 @@ class InputRouterImplPerfTest : public testing::Test {
InputRouterImpl::Config()));
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
base::MessageLoop::current()->RunUntilIdle();
input_router_.reset();
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 1fa1a7d305a..ed922c9d8ac 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
@@ -142,16 +142,16 @@ float PinchScaleToWheelDelta(float scale) {
class InputRouterImplTest : public testing::Test {
public:
InputRouterImplTest() {}
- virtual ~InputRouterImplTest() {}
+ ~InputRouterImplTest() override {}
protected:
// testing::Test
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
browser_context_.reset(new TestBrowserContext());
process_.reset(new MockRenderProcessHost(browser_context_.get()));
client_.reset(new MockInputRouterClient());
ack_handler_.reset(new MockInputAckHandler());
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitch(switches::kValidateInputEventStream);
input_router_.reset(new InputRouterImpl(process_.get(),
client_.get(),
@@ -162,7 +162,7 @@ class InputRouterImplTest : public testing::Test {
ack_handler_->set_input_router(input_router());
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// Process all pending tasks to avoid leaks.
base::MessageLoop::current()->RunUntilIdle();
@@ -284,7 +284,7 @@ class InputRouterImplTest : public testing::Test {
}
bool TouchEventTimeoutEnabled() const {
- return input_router()->touch_event_queue_.ack_timeout_enabled();
+ return input_router()->touch_event_queue_.IsAckTimeoutEnabled();
}
void Flush() const {
@@ -354,7 +354,7 @@ TEST_F(InputRouterImplTest, CoalescesRangeSelection) {
// Now ack the first message.
{
- scoped_ptr<IPC::Message> response(new ViewHostMsg_SelectRange_ACK(0));
+ scoped_ptr<IPC::Message> response(new InputHostMsg_SelectRange_ACK(0));
input_router_->OnMessageReceived(*response);
}
@@ -367,7 +367,197 @@ TEST_F(InputRouterImplTest, CoalescesRangeSelection) {
// Acking the coalesced msg should not send any more msg.
{
- scoped_ptr<IPC::Message> response(new ViewHostMsg_SelectRange_ACK(0));
+ scoped_ptr<IPC::Message> response(new InputHostMsg_SelectRange_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+}
+
+TEST_F(InputRouterImplTest, CoalescesMoveRangeSelectionExtent) {
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(1, 2))));
+ ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(1, 2));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ // Send two more messages without acking.
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(3, 4))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(5, 6))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ // Now ack the first message.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_MoveRangeSelectionExtent_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+
+ // Verify that the two messages are coalesced into one message.
+ ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(5, 6));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ // Acking the coalesced msg should not send any more msg.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_MoveRangeSelectionExtent_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+}
+
+TEST_F(InputRouterImplTest, InterleaveSelectRangeAndMoveRangeSelectionExtent) {
+ // Send first message: SelectRange.
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_SelectRange(0, gfx::Point(1, 2), gfx::Point(3, 4))));
+ ExpectIPCMessageWithArg2<InputMsg_SelectRange>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(1, 2),
+ gfx::Point(3, 4));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ // Send second message: MoveRangeSelectionExtent.
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(5, 6))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ // Send third message: SelectRange.
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_SelectRange(0, gfx::Point(7, 8), gfx::Point(9, 10))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ // Ack the messages and verify that they're not coalesced and that they're in
+ // correct order.
+
+ // Ack the first message.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_SelectRange_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+
+ ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(5, 6));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ // Ack the second message.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_MoveRangeSelectionExtent_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+
+ ExpectIPCMessageWithArg2<InputMsg_SelectRange>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(7, 8),
+ gfx::Point(9, 10));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ // Ack the third message.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_SelectRange_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+}
+
+TEST_F(InputRouterImplTest,
+ CoalescesInterleavedSelectRangeAndMoveRangeSelectionExtent) {
+ // Send interleaved SelectRange and MoveRangeSelectionExtent messages. They
+ // should be coalesced as shown by the arrows.
+ // > SelectRange
+ // MoveRangeSelectionExtent
+ // MoveRangeSelectionExtent
+ // > MoveRangeSelectionExtent
+ // SelectRange
+ // > SelectRange
+ // > MoveRangeSelectionExtent
+
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_SelectRange(0, gfx::Point(1, 2), gfx::Point(3, 4))));
+ ExpectIPCMessageWithArg2<InputMsg_SelectRange>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(1, 2),
+ gfx::Point(3, 4));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(5, 6))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(7, 8))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(9, 10))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_SelectRange(0, gfx::Point(11, 12), gfx::Point(13, 14))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_SelectRange(0, gfx::Point(15, 16), gfx::Point(17, 18))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ input_router_->SendInput(scoped_ptr<IPC::Message>(
+ new InputMsg_MoveRangeSelectionExtent(0, gfx::Point(19, 20))));
+ EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
+
+ // Ack the first message.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_SelectRange_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+
+ // Verify that the three MoveRangeSelectionExtent messages are coalesced into
+ // one message.
+ ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(9, 10));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ // Ack the second message.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_MoveRangeSelectionExtent_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+
+ // Verify that the two SelectRange messages are coalesced into one message.
+ ExpectIPCMessageWithArg2<InputMsg_SelectRange>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(15, 16),
+ gfx::Point(17, 18));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ // Ack the third message.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_SelectRange_ACK(0));
+ input_router_->OnMessageReceived(*response);
+ }
+
+ // Verify the fourth message.
+ ExpectIPCMessageWithArg1<InputMsg_MoveRangeSelectionExtent>(
+ process_->sink().GetMessageAt(0),
+ gfx::Point(19, 20));
+ EXPECT_EQ(1u, GetSentMessageCountAndResetSink());
+
+ // Ack the fourth message.
+ {
+ scoped_ptr<IPC::Message> response(
+ new InputHostMsg_MoveRangeSelectionExtent_ACK(0));
input_router_->OnMessageReceived(*response);
}
EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
@@ -391,7 +581,7 @@ TEST_F(InputRouterImplTest, CoalescesCaretMove) {
// Now ack the first message.
{
- scoped_ptr<IPC::Message> response(new ViewHostMsg_MoveCaret_ACK(0));
+ scoped_ptr<IPC::Message> response(new InputHostMsg_MoveCaret_ACK(0));
input_router_->OnMessageReceived(*response);
}
@@ -402,7 +592,7 @@ TEST_F(InputRouterImplTest, CoalescesCaretMove) {
// Acking the coalesced msg should not send any more msg.
{
- scoped_ptr<IPC::Message> response(new ViewHostMsg_MoveCaret_ACK(0));
+ scoped_ptr<IPC::Message> response(new InputHostMsg_MoveCaret_ACK(0));
input_router_->OnMessageReceived(*response);
}
EXPECT_EQ(0u, GetSentMessageCountAndResetSink());
@@ -619,8 +809,8 @@ TEST_F(InputRouterImplTest, TouchEventQueue) {
EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
}
-// Tests that the touch-queue is emptied if a page stops listening for touch
-// events.
+// Tests that the touch-queue is emptied after a page stops listening for touch
+// events and the outstanding ack is received.
TEST_F(InputRouterImplTest, TouchEventQueueFlush) {
OnHasTouchEventHandlers(true);
EXPECT_TRUE(client_->has_touch_handler());
@@ -632,15 +822,23 @@ TEST_F(InputRouterImplTest, TouchEventQueueFlush) {
// Send a touch-press event.
PressTouchPoint(1, 1);
SendTouchEvent();
+ MoveTouchPoint(0, 2, 2);
+ MoveTouchPoint(0, 3, 3);
EXPECT_FALSE(TouchEventQueueEmpty());
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
- // The page stops listening for touch-events. The touch-event queue should now
- // be emptied, but none of the queued touch-events should be sent to the
- // renderer.
+ // The page stops listening for touch-events. Note that flushing is deferred
+ // until the outstanding ack is received.
OnHasTouchEventHandlers(false);
EXPECT_FALSE(client_->has_touch_handler());
EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
+ EXPECT_FALSE(TouchEventQueueEmpty());
+ EXPECT_TRUE(input_router_->ShouldForwardTouchEvent());
+
+ // After the ack, the touch-event queue should be empty, and none of the
+ // flushed touch-events should have been sent to the renderer.
+ SendInputEventACK(WebInputEvent::TouchStart, INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
EXPECT_TRUE(TouchEventQueueEmpty());
EXPECT_FALSE(input_router_->ShouldForwardTouchEvent());
}
@@ -1097,53 +1295,40 @@ TEST_F(InputRouterImplTest,
// Start a touch sequence.
PressTouchPoint(1, 1);
SendTouchEvent();
+ EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
// TOUCH_ACTION_NONE should disable the timeout.
OnSetTouchAction(TOUCH_ACTION_NONE);
SendInputEventACK(WebInputEvent::TouchStart, INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
EXPECT_FALSE(TouchEventTimeoutEnabled());
- // End the touch sequence.
- ReleaseTouchPoint(0);
+ MoveTouchPoint(0, 1, 1);
SendTouchEvent();
- SendInputEventACK(WebInputEvent::TouchEnd, INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_FALSE(TouchEventTimeoutEnabled());
- ack_handler_->GetAndResetAckCount();
- GetSentMessageCountAndResetSink();
-
- // Start another touch sequence. While this does restore the touch timeout
- // the timeout will not apply until the *next* touch sequence. This affords a
- // touch-action response from the renderer without racing against the timeout.
- PressTouchPoint(1, 1);
- SendTouchEvent();
- EXPECT_TRUE(TouchEventTimeoutEnabled());
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
- // Delay the ack. The timeout should *not* fire.
+ // Delay the move ack. The timeout should not fire.
RunTasksAndWait(base::TimeDelta::FromMilliseconds(timeout_ms + 1));
EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
-
- // Finally send the ack. The touch sequence should not have been cancelled.
- SendInputEventACK(WebInputEvent::TouchStart,
- INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_TRUE(TouchEventTimeoutEnabled());
+ SendInputEventACK(WebInputEvent::TouchEnd, INPUT_EVENT_ACK_STATE_CONSUMED);
EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
- // End the sequence.
+ // End the touch sequence.
ReleaseTouchPoint(0);
SendTouchEvent();
SendInputEventACK(WebInputEvent::TouchEnd, INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
- EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ EXPECT_FALSE(TouchEventTimeoutEnabled());
+ ack_handler_->GetAndResetAckCount();
+ GetSentMessageCountAndResetSink();
- // A new touch sequence should (finally) be subject to the timeout.
+ // Start another touch sequence. This should restore the touch timeout.
PressTouchPoint(1, 1);
SendTouchEvent();
EXPECT_TRUE(TouchEventTimeoutEnabled());
- EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
+ EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
// Wait for the touch ack timeout to fire.
RunTasksAndWait(base::TimeDelta::FromMilliseconds(timeout_ms + 1));
diff --git a/chromium/content/browser/renderer_host/input/mock_input_ack_handler.h b/chromium/content/browser/renderer_host/input/mock_input_ack_handler.h
index 875964a8080..93f7ccadf4f 100644
--- a/chromium/content/browser/renderer_host/input/mock_input_ack_handler.h
+++ b/chromium/content/browser/renderer_host/input/mock_input_ack_handler.h
@@ -15,18 +15,18 @@ class InputRouter;
class MockInputAckHandler : public InputAckHandler {
public:
MockInputAckHandler();
- virtual ~MockInputAckHandler();
+ ~MockInputAckHandler() override;
// InputAckHandler
- virtual void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void OnUnexpectedEventAck(UnexpectedEventAckType type) OVERRIDE;
+ void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
+ InputEventAckState ack_result) override;
+ void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
+ void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
+ void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
+ void OnUnexpectedEventAck(UnexpectedEventAckType type) override;
size_t GetAndResetAckCount();
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 f0b31676ffd..a552ac0debf 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
@@ -17,18 +17,18 @@ class InputRouter;
class MockInputRouterClient : public InputRouterClient {
public:
MockInputRouterClient();
- virtual ~MockInputRouterClient();
+ ~MockInputRouterClient() override;
// InputRouterClient
- virtual InputEventAckState FilterInputEvent(
+ InputEventAckState FilterInputEvent(
const blink::WebInputEvent& input_event,
- const ui::LatencyInfo& latency_info) OVERRIDE;
- virtual void IncrementInFlightEventCount() OVERRIDE;
- virtual void DecrementInFlightEventCount() OVERRIDE;
- virtual void OnHasTouchEventHandlers(bool has_handlers) OVERRIDE;
- virtual void SetNeedsFlush() OVERRIDE;
- virtual void DidFlush() OVERRIDE;
- virtual void DidOverscroll(const DidOverscrollParams& params) OVERRIDE;
+ const ui::LatencyInfo& latency_info) override;
+ void IncrementInFlightEventCount() override;
+ void DecrementInFlightEventCount() override;
+ void OnHasTouchEventHandlers(bool has_handlers) override;
+ void SetNeedsFlush() override;
+ void DidFlush() override;
+ void DidOverscroll(const DidOverscrollParams& params) override;
bool GetAndResetFilterEventCalled();
size_t GetAndResetDidFlushCount();
diff --git a/chromium/content/browser/renderer_host/input/motion_event_android.cc b/chromium/content/browser/renderer_host/input/motion_event_android.cc
index 7409955bc9c..fa21047d71b 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_android.cc
+++ b/chromium/content/browser/renderer_host/input/motion_event_android.cc
@@ -4,8 +4,12 @@
#include "content/browser/renderer_host/input/motion_event_android.h"
+#include <android/input.h>
+
#include "base/android/jni_android.h"
+#include "base/float_util.h"
#include "jni/MotionEvent_jni.h"
+#include "ui/events/event_constants.h"
using base::android::AttachCurrentThread;
using namespace JNI_MotionEvent;
@@ -13,26 +17,6 @@ using namespace JNI_MotionEvent;
namespace content {
namespace {
-int ToAndroidAction(MotionEventAndroid::Action action) {
- switch (action) {
- case MotionEventAndroid::ACTION_DOWN:
- return ACTION_DOWN;
- case MotionEventAndroid::ACTION_UP:
- return ACTION_UP;
- case MotionEventAndroid::ACTION_MOVE:
- return ACTION_MOVE;
- case MotionEventAndroid::ACTION_CANCEL:
- return ACTION_CANCEL;
- case MotionEventAndroid::ACTION_POINTER_DOWN:
- return ACTION_POINTER_DOWN;
- case MotionEventAndroid::ACTION_POINTER_UP:
- return ACTION_POINTER_UP;
- };
- NOTREACHED() << "Invalid Android MotionEvent type for gesture detection: "
- << action;
- return ACTION_CANCEL;
-}
-
MotionEventAndroid::Action FromAndroidAction(int android_action) {
switch (android_action) {
case ACTION_DOWN:
@@ -54,16 +38,98 @@ MotionEventAndroid::Action FromAndroidAction(int android_action) {
return MotionEventAndroid::ACTION_CANCEL;
}
-int64 ToAndroidTime(base::TimeTicks time) {
- return (time - base::TimeTicks()).InMilliseconds();
+MotionEventAndroid::ToolType FromAndroidToolType(int android_tool_type) {
+ switch (android_tool_type) {
+ case TOOL_TYPE_UNKNOWN:
+ return MotionEventAndroid::TOOL_TYPE_UNKNOWN;
+ case TOOL_TYPE_FINGER:
+ return MotionEventAndroid::TOOL_TYPE_FINGER;
+ case TOOL_TYPE_STYLUS:
+ return MotionEventAndroid::TOOL_TYPE_STYLUS;
+ case TOOL_TYPE_MOUSE:
+ return MotionEventAndroid::TOOL_TYPE_MOUSE;
+ case TOOL_TYPE_ERASER:
+ return MotionEventAndroid::TOOL_TYPE_ERASER;
+ default:
+ NOTREACHED() << "Invalid Android MotionEvent tool type: "
+ << android_tool_type;
+ };
+ return MotionEventAndroid::TOOL_TYPE_UNKNOWN;
+}
+
+int FromAndroidButtonState(int button_state) {
+ int result = 0;
+ if ((button_state & BUTTON_BACK) != 0)
+ result |= MotionEventAndroid::BUTTON_BACK;
+ if ((button_state & BUTTON_FORWARD) != 0)
+ result |= MotionEventAndroid::BUTTON_FORWARD;
+ if ((button_state & BUTTON_PRIMARY) != 0)
+ result |= MotionEventAndroid::BUTTON_PRIMARY;
+ if ((button_state & BUTTON_SECONDARY) != 0)
+ result |= MotionEventAndroid::BUTTON_SECONDARY;
+ if ((button_state & BUTTON_TERTIARY) != 0)
+ result |= MotionEventAndroid::BUTTON_TERTIARY;
+ return result;
+}
+
+int FromAndroidMetaState(int meta_state) {
+ int flags = ui::EF_NONE;
+ if ((meta_state & AMETA_SHIFT_ON) != 0)
+ flags |= ui::EF_SHIFT_DOWN;
+ if ((meta_state & AMETA_CTRL_ON) != 0)
+ flags |= ui::EF_CONTROL_DOWN;
+ if ((meta_state & AMETA_ALT_ON) != 0)
+ flags |= ui::EF_ALT_DOWN;
+ if ((meta_state & AMETA_META_ON) != 0)
+ flags |= ui::EF_COMMAND_DOWN;
+ if ((meta_state & AMETA_CAPS_LOCK_ON) != 0)
+ flags |= ui::EF_CAPS_LOCK_DOWN;
+ return flags;
}
base::TimeTicks FromAndroidTime(int64 time_ms) {
return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms);
}
+float ToValidFloat(float x) {
+ if (base::IsNaN(x))
+ return 0.f;
+
+ // Wildly large orientation values have been observed in the wild after device
+ // rotation. There's not much we can do in that case other than simply
+ // sanitize results beyond an absurd and arbitrary threshold.
+ if (std::abs(x) > 1e5f)
+ return 0.f;
+
+ return x;
+}
+
} // namespace
+MotionEventAndroid::Pointer::Pointer(jint id,
+ jfloat pos_x_pixels,
+ jfloat pos_y_pixels,
+ jfloat touch_major_pixels,
+ jfloat touch_minor_pixels,
+ jfloat orientation_rad,
+ jint tool_type)
+ : id(id),
+ pos_x_pixels(pos_x_pixels),
+ pos_y_pixels(pos_y_pixels),
+ touch_major_pixels(touch_major_pixels),
+ touch_minor_pixels(touch_minor_pixels),
+ orientation_rad(orientation_rad),
+ tool_type(tool_type) {
+}
+
+MotionEventAndroid::CachedPointer::CachedPointer()
+ : id(0),
+ touch_major(0),
+ touch_minor(0),
+ orientation(0),
+ tool_type(TOOL_TYPE_UNKNOWN) {
+}
+
MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
JNIEnv* env,
jobject event,
@@ -72,95 +138,34 @@ MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
jint pointer_count,
jint history_size,
jint action_index,
- jfloat pos_x_0_pixels,
- jfloat pos_y_0_pixels,
- jfloat pos_x_1_pixels,
- jfloat pos_y_1_pixels,
- jint pointer_id_0,
- jint pointer_id_1,
- jfloat touch_major_0_pixels,
- jfloat touch_major_1_pixels,
- jfloat raw_pos_x_pixels,
- jfloat raw_pos_y_pixels)
- : cached_time_(FromAndroidTime(time_ms)),
+ jint android_button_state,
+ jint meta_state,
+ jfloat raw_offset_x_pixels,
+ jfloat raw_offset_y_pixels,
+ const Pointer& pointer0,
+ const Pointer& pointer1)
+ : pix_to_dip_(pix_to_dip),
+ cached_time_(FromAndroidTime(time_ms)),
cached_action_(FromAndroidAction(android_action)),
cached_pointer_count_(pointer_count),
cached_history_size_(history_size),
cached_action_index_(action_index),
- pix_to_dip_(pix_to_dip),
- should_recycle_(false) {
+ cached_button_state_(FromAndroidButtonState(android_button_state)),
+ cached_flags_(FromAndroidMetaState(meta_state)),
+ cached_raw_position_offset_(ToDips(raw_offset_x_pixels),
+ ToDips(raw_offset_y_pixels)) {
DCHECK_GT(pointer_count, 0);
DCHECK_GE(history_size, 0);
event_.Reset(env, event);
- DCHECK(event_.obj());
-
- cached_positions_[0] = ToDips(gfx::PointF(pos_x_0_pixels, pos_y_0_pixels));
- cached_positions_[1] = ToDips(gfx::PointF(pos_x_1_pixels, pos_y_1_pixels));
- cached_pointer_ids_[0] = pointer_id_0;
- cached_pointer_ids_[1] = pointer_id_1;
- cached_touch_majors_[0] = ToDips(touch_major_0_pixels);
- cached_touch_majors_[1] = ToDips(touch_major_1_pixels);
- cached_raw_position_offset_ =
- ToDips(gfx::PointF(raw_pos_x_pixels, raw_pos_y_pixels)) -
- cached_positions_[0];
-}
+ if (cached_pointer_count_ > MAX_POINTERS_TO_CACHE || history_size > 0)
+ DCHECK(event_.obj());
-MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
- JNIEnv* env,
- jobject event)
- : cached_time_(FromAndroidTime(Java_MotionEvent_getEventTime(env, event))),
- cached_action_(
- FromAndroidAction(Java_MotionEvent_getActionMasked(env, event))),
- cached_pointer_count_(Java_MotionEvent_getPointerCount(env, event)),
- cached_history_size_(Java_MotionEvent_getHistorySize(env, event)),
- cached_action_index_(Java_MotionEvent_getActionIndex(env, event)),
- pix_to_dip_(pix_to_dip),
- should_recycle_(true) {
- event_.Reset(env, event);
- DCHECK(event_.obj());
-
- for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) {
- if (i < cached_pointer_count_) {
- cached_positions_[i] =
- ToDips(gfx::PointF(Java_MotionEvent_getXF_I(env, event, i),
- Java_MotionEvent_getYF_I(env, event, i)));
- cached_pointer_ids_[i] = Java_MotionEvent_getPointerId(env, event, i);
- cached_touch_majors_[i] =
- ToDips(Java_MotionEvent_getTouchMajorF_I(env, event, i));
- } else {
- cached_pointer_ids_[i] = 0;
- cached_touch_majors_[i] = 0.f;
- }
- }
-
- cached_raw_position_offset_ =
- ToDips(gfx::PointF(Java_MotionEvent_getRawX(env, event),
- Java_MotionEvent_getRawY(env, event))) -
- cached_positions_[0];
-}
-
-MotionEventAndroid::MotionEventAndroid(const MotionEventAndroid& other)
- : event_(Obtain(other)),
- cached_time_(other.cached_time_),
- cached_action_(other.cached_action_),
- cached_pointer_count_(other.cached_pointer_count_),
- cached_history_size_(other.cached_history_size_),
- cached_action_index_(other.cached_action_index_),
- cached_raw_position_offset_(other.cached_raw_position_offset_),
- pix_to_dip_(other.pix_to_dip_),
- should_recycle_(true) {
- DCHECK(event_.obj());
- for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) {
- cached_positions_[i] = other.cached_positions_[i];
- cached_pointer_ids_[i] = other.cached_pointer_ids_[i];
- cached_touch_majors_[i] = other.cached_touch_majors_[i];
- }
+ cached_pointers_[0] = FromAndroidPointer(pointer0);
+ cached_pointers_[1] = FromAndroidPointer(pointer1);
}
MotionEventAndroid::~MotionEventAndroid() {
- if (should_recycle_)
- Java_MotionEvent_recycle(AttachCurrentThread(), event_.obj());
}
int MotionEventAndroid::GetId() const {
@@ -182,7 +187,7 @@ size_t MotionEventAndroid::GetPointerCount() const {
int MotionEventAndroid::GetPointerId(size_t pointer_index) const {
DCHECK_LT(pointer_index, cached_pointer_count_);
if (pointer_index < MAX_POINTERS_TO_CACHE)
- return cached_pointer_ids_[pointer_index];
+ return cached_pointers_[pointer_index].id;
return Java_MotionEvent_getPointerId(
AttachCurrentThread(), event_.obj(), pointer_index);
}
@@ -190,7 +195,7 @@ int MotionEventAndroid::GetPointerId(size_t pointer_index) const {
float MotionEventAndroid::GetX(size_t pointer_index) const {
DCHECK_LT(pointer_index, cached_pointer_count_);
if (pointer_index < MAX_POINTERS_TO_CACHE)
- return cached_positions_[pointer_index].x();
+ return cached_pointers_[pointer_index].position.x();
return ToDips(Java_MotionEvent_getXF_I(
AttachCurrentThread(), event_.obj(), pointer_index));
}
@@ -198,7 +203,7 @@ float MotionEventAndroid::GetX(size_t pointer_index) const {
float MotionEventAndroid::GetY(size_t pointer_index) const {
DCHECK_LT(pointer_index, cached_pointer_count_);
if (pointer_index < MAX_POINTERS_TO_CACHE)
- return cached_positions_[pointer_index].y();
+ return cached_pointers_[pointer_index].position.y();
return ToDips(Java_MotionEvent_getYF_I(
AttachCurrentThread(), event_.obj(), pointer_index));
}
@@ -214,13 +219,34 @@ float MotionEventAndroid::GetRawY(size_t pointer_index) const {
float MotionEventAndroid::GetTouchMajor(size_t pointer_index) const {
DCHECK_LT(pointer_index, cached_pointer_count_);
if (pointer_index < MAX_POINTERS_TO_CACHE)
- return cached_touch_majors_[pointer_index];
+ return cached_pointers_[pointer_index].touch_major;
return ToDips(Java_MotionEvent_getTouchMajorF_I(
AttachCurrentThread(), event_.obj(), pointer_index));
}
+float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const {
+ DCHECK_LT(pointer_index, cached_pointer_count_);
+ if (pointer_index < MAX_POINTERS_TO_CACHE)
+ return cached_pointers_[pointer_index].touch_minor;
+ return ToDips(Java_MotionEvent_getTouchMinorF_I(
+ AttachCurrentThread(), event_.obj(), pointer_index));
+}
+
+float MotionEventAndroid::GetOrientation(size_t pointer_index) const {
+ DCHECK_LT(pointer_index, cached_pointer_count_);
+ if (pointer_index < MAX_POINTERS_TO_CACHE)
+ return cached_pointers_[pointer_index].orientation;
+ return ToValidFloat(Java_MotionEvent_getOrientationF_I(
+ AttachCurrentThread(), event_.obj(), pointer_index));
+}
+
float MotionEventAndroid::GetPressure(size_t pointer_index) const {
DCHECK_LT(pointer_index, cached_pointer_count_);
+ // Note that this early return is a special case exercised only in testing, as
+ // caching the pressure values is not a worthwhile optimization (they're
+ // accessed at most once per event instance).
+ if (!event_.obj())
+ return 0.f;
return Java_MotionEvent_getPressureF_I(
AttachCurrentThread(), event_.obj(), pointer_index);
}
@@ -258,45 +284,38 @@ float MotionEventAndroid::GetHistoricalY(size_t pointer_index,
AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
}
-scoped_ptr<ui::MotionEvent> MotionEventAndroid::Clone() const {
- return scoped_ptr<MotionEvent>(new MotionEventAndroid(*this));
-}
-
-scoped_ptr<ui::MotionEvent> MotionEventAndroid::Cancel() const {
- // The input coordinates to |MotionEventAndroid| are always in device pixels,
- // but the cached coordinates are in DIPs.
- const gfx::PointF position_pixels =
- gfx::ScalePoint(cached_positions_[0], 1.f / pix_to_dip_);
- return scoped_ptr<MotionEvent>(
- new MotionEventAndroid(pix_to_dip_,
- AttachCurrentThread(),
- Obtain(GetDownTime(),
- GetEventTime(),
- MotionEventAndroid::ACTION_CANCEL,
- position_pixels.x(),
- position_pixels.y()).obj()));
-}
-
-float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const {
- return ToDips(Java_MotionEvent_getTouchMinorF_I(
+ui::MotionEvent::ToolType MotionEventAndroid::GetToolType(
+ size_t pointer_index) const {
+ DCHECK_LT(pointer_index, cached_pointer_count_);
+ if (pointer_index < MAX_POINTERS_TO_CACHE)
+ return cached_pointers_[pointer_index].tool_type;
+ return FromAndroidToolType(Java_MotionEvent_getToolType(
AttachCurrentThread(), event_.obj(), pointer_index));
}
-float MotionEventAndroid::GetOrientation() const {
- return Java_MotionEvent_getOrientationF(AttachCurrentThread(), event_.obj());
+int MotionEventAndroid::GetButtonState() const {
+ return cached_button_state_;
}
-base::TimeTicks MotionEventAndroid::GetDownTime() const {
- return FromAndroidTime(
- Java_MotionEvent_getDownTime(AttachCurrentThread(), event_.obj()));
+int MotionEventAndroid::GetFlags() const {
+ return cached_flags_;
}
float MotionEventAndroid::ToDips(float pixels) const {
return pixels * pix_to_dip_;
}
-gfx::PointF MotionEventAndroid::ToDips(const gfx::PointF& point_pixels) const {
- return gfx::ScalePoint(point_pixels, pix_to_dip_);
+MotionEventAndroid::CachedPointer MotionEventAndroid::FromAndroidPointer(
+ const Pointer& pointer) const {
+ CachedPointer result;
+ result.id = pointer.id;
+ result.position =
+ gfx::PointF(ToDips(pointer.pos_x_pixels), ToDips(pointer.pos_y_pixels));
+ result.touch_major = ToDips(pointer.touch_major_pixels);
+ result.touch_minor = ToDips(pointer.touch_minor_pixels);
+ result.orientation = ToValidFloat(pointer.orientation_rad);
+ result.tool_type = FromAndroidToolType(pointer.tool_type);
+ return result;
}
// static
@@ -304,27 +323,4 @@ bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv* env) {
return JNI_MotionEvent::RegisterNativesImpl(env);
}
-// static
-base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
- const MotionEventAndroid& event) {
- return Java_MotionEvent_obtainAVME_AVME(AttachCurrentThread(),
- event.event_.obj());
-}
-
-// static
-base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
- base::TimeTicks down_time,
- base::TimeTicks event_time,
- Action action,
- float x_pixels,
- float y_pixels) {
- return Java_MotionEvent_obtainAVME_J_J_I_F_F_I(AttachCurrentThread(),
- ToAndroidTime(down_time),
- ToAndroidTime(event_time),
- ToAndroidAction(action),
- x_pixels,
- y_pixels,
- 0);
-}
-
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/motion_event_android.h b/chromium/content/browser/renderer_host/input/motion_event_android.h
index 0362b0454e9..4af9f72e00b 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_android.h
+++ b/chromium/content/browser/renderer_host/input/motion_event_android.h
@@ -1,3 +1,4 @@
+
// 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.
@@ -10,6 +11,7 @@
#include "base/android/scoped_java_ref.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
+#include "content/common/content_export.h"
#include "ui/events/gesture_detection/motion_event.h"
#include "ui/gfx/geometry/point_f.h"
@@ -18,8 +20,25 @@ namespace content {
// Implementation of ui::MotionEvent wrapping a native Android MotionEvent.
// All *input* coordinates are in device pixels (as with Android MotionEvent),
// while all *output* coordinates are in DIPs (as with WebTouchEvent).
-class MotionEventAndroid : public ui::MotionEvent {
+class CONTENT_EXPORT MotionEventAndroid : public ui::MotionEvent {
public:
+ struct Pointer {
+ Pointer(jint id,
+ jfloat pos_x_pixels,
+ jfloat pos_y_pixels,
+ jfloat touch_major_pixels,
+ jfloat touch_minor_pixels,
+ jfloat orientation_rad,
+ jint tool_type);
+ jint id;
+ jfloat pos_x_pixels;
+ jfloat pos_y_pixels;
+ jfloat touch_major_pixels;
+ jfloat touch_minor_pixels;
+ jfloat orientation_rad;
+ jint tool_type;
+ };
+
// Forcing the caller to provide all cached values upon construction
// eliminates the need to perform a JNI call to retrieve values individually.
MotionEventAndroid(float pix_to_dip,
@@ -30,68 +49,49 @@ class MotionEventAndroid : public ui::MotionEvent {
jint pointer_count,
jint history_size,
jint action_index,
- jfloat pos_x_0_pixels,
- jfloat pos_y_0_pixels,
- jfloat pos_x_1_pixels,
- jfloat pos_y_1_pixels,
- jint pointer_id_0,
- jint pointer_id_1,
- jfloat touch_major_0_pixels,
- jfloat touch_major_1_pixels,
- jfloat raw_pos_x_pixels,
- jfloat raw_pos_y_pixels);
+ jint android_button_state,
+ jint meta_state,
+ jfloat raw_offset_x_pixels,
+ jfloat raw_offset_y_pixels,
+ const Pointer& pointer0,
+ const Pointer& pointer1);
virtual ~MotionEventAndroid();
// ui::MotionEvent methods.
- virtual int GetId() const OVERRIDE;
- virtual Action GetAction() const OVERRIDE;
- virtual int GetActionIndex() const OVERRIDE;
- virtual size_t GetPointerCount() const OVERRIDE;
- virtual int GetPointerId(size_t pointer_index) const OVERRIDE;
- virtual float GetX(size_t pointer_index) const OVERRIDE;
- virtual float GetY(size_t pointer_index) const OVERRIDE;
- virtual float GetRawX(size_t pointer_index) const OVERRIDE;
- virtual float GetRawY(size_t pointer_index) const OVERRIDE;
- virtual float GetTouchMajor(size_t pointer_index) const OVERRIDE;
- virtual float GetPressure(size_t pointer_index) const OVERRIDE;
- virtual base::TimeTicks GetEventTime() const OVERRIDE;
- virtual size_t GetHistorySize() const OVERRIDE;
+ virtual int GetId() const override;
+ virtual Action GetAction() const override;
+ virtual int GetActionIndex() const override;
+ virtual size_t GetPointerCount() const override;
+ virtual int GetPointerId(size_t pointer_index) const override;
+ virtual float GetX(size_t pointer_index) const override;
+ virtual float GetY(size_t pointer_index) const override;
+ virtual float GetRawX(size_t pointer_index) const override;
+ virtual float GetRawY(size_t pointer_index) const override;
+ virtual float GetTouchMajor(size_t pointer_index) const override;
+ virtual float GetTouchMinor(size_t pointer_index) const override;
+ virtual float GetOrientation(size_t pointer_index) const override;
+ virtual float GetPressure(size_t pointer_index) const override;
+ virtual base::TimeTicks GetEventTime() const override;
+ virtual size_t GetHistorySize() const override;
virtual base::TimeTicks GetHistoricalEventTime(
- size_t historical_index) const OVERRIDE;
+ size_t historical_index) const override;
virtual float GetHistoricalTouchMajor(size_t pointer_index,
- size_t historical_index) const OVERRIDE;
+ size_t historical_index) const override;
virtual float GetHistoricalX(size_t pointer_index,
- size_t historical_index) const OVERRIDE;
+ size_t historical_index) const override;
virtual float GetHistoricalY(size_t pointer_index,
- size_t historical_index) const OVERRIDE;
- virtual scoped_ptr<MotionEvent> Clone() const OVERRIDE;
- virtual scoped_ptr<MotionEvent> Cancel() const OVERRIDE;
-
- // Additional Android MotionEvent methods.
- float GetTouchMinor() const { return GetTouchMinor(0); }
- float GetTouchMinor(size_t pointer_index) const;
- float GetOrientation() const;
- base::TimeTicks GetDownTime() const;
+ size_t historical_index) const override;
+ virtual ToolType GetToolType(size_t pointer_index) const override;
+ virtual int GetButtonState() const override;
+ virtual int GetFlags() const override;
static bool RegisterMotionEventAndroid(JNIEnv* env);
- static base::android::ScopedJavaLocalRef<jobject> Obtain(
- const MotionEventAndroid& event);
- static base::android::ScopedJavaLocalRef<jobject> Obtain(
- base::TimeTicks down_time,
- base::TimeTicks event_time,
- Action action,
- float x_pixels,
- float y_pixels);
-
private:
- MotionEventAndroid();
- MotionEventAndroid(float pix_to_dip, JNIEnv* env, jobject event);
- MotionEventAndroid(const MotionEventAndroid&);
- MotionEventAndroid& operator=(const MotionEventAndroid&);
+ struct CachedPointer;
float ToDips(float pixels) const;
- gfx::PointF ToDips(const gfx::PointF& pixels) const;
+ CachedPointer FromAndroidPointer(const Pointer& pointer) const;
// Cache pointer coords, id's and major lengths for the most common
// touch-related scenarios, i.e., scrolling and pinching. This prevents
@@ -101,23 +101,29 @@ class MotionEventAndroid : public ui::MotionEvent {
// The Java reference to the underlying MotionEvent.
base::android::ScopedJavaGlobalRef<jobject> event_;
- base::TimeTicks cached_time_;
- Action cached_action_;
- size_t cached_pointer_count_;
- size_t cached_history_size_;
- int cached_action_index_;
- gfx::PointF cached_positions_[MAX_POINTERS_TO_CACHE];
- int cached_pointer_ids_[MAX_POINTERS_TO_CACHE];
- float cached_touch_majors_[MAX_POINTERS_TO_CACHE];
- gfx::Vector2dF cached_raw_position_offset_;
-
// Used to convert pixel coordinates from the Java-backed MotionEvent to
// DIP coordinates cached/returned by the MotionEventAndroid.
const float pix_to_dip_;
- // Whether |event_| should be recycled on destruction. This will only be true
- // for those events generated via |Obtain(...)|.
- bool should_recycle_;
+ const base::TimeTicks cached_time_;
+ const Action cached_action_;
+ const size_t cached_pointer_count_;
+ const size_t cached_history_size_;
+ const int cached_action_index_;
+ const int cached_button_state_;
+ const int cached_flags_;
+ const gfx::Vector2dF cached_raw_position_offset_;
+ struct CachedPointer {
+ CachedPointer();
+ int id;
+ gfx::PointF position;
+ float touch_major;
+ float touch_minor;
+ float orientation;
+ ToolType tool_type;
+ } cached_pointers_[MAX_POINTERS_TO_CACHE];
+
+ DISALLOW_COPY_AND_ASSIGN(MotionEventAndroid);
};
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/motion_event_android_unittest.cc b/chromium/content/browser/renderer_host/input/motion_event_android_unittest.cc
new file mode 100644
index 00000000000..d7482d9aa7e
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/motion_event_android_unittest.cc
@@ -0,0 +1,174 @@
+// 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 <android/input.h>
+
+#include "base/android/jni_android.h"
+#include "base/float_util.h"
+#include "content/browser/renderer_host/input/motion_event_android.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/test/motion_event_test_utils.h"
+
+using ui::MotionEvent;
+
+namespace content {
+namespace {
+const float kPixToDip = 0.5f;
+
+int kAndroidActionDown = AMOTION_EVENT_ACTION_DOWN;
+
+int kAndroidAltKeyDown = AMETA_ALT_ON;
+
+// Corresponds to TOOL_TYPE_FINGER, see
+// developer.android.com/reference/android/view/MotionEvent.html
+// #TOOL_TYPE_FINGER.
+int kAndroidToolTypeFinger = 1;
+
+// Corresponds to BUTTON_PRIMARY, see
+// developer.android.com/reference/android/view/MotionEvent.html#BUTTON_PRIMARY.
+int kAndroidButtonPrimary = 1;
+
+} // namespace
+
+// Note that these tests avoid creating a Java instance of the MotionEvent, as
+// we're primarily testing caching behavior, and the code necessary to
+// construct a Java-backed MotionEvent itself adds unnecessary complexity.
+TEST(MotionEventAndroidTest, Constructor) {
+ int event_time_ms = 5;
+ base::TimeTicks event_time =
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(event_time_ms);
+ MotionEventAndroid::Pointer p0(
+ 1, 13.7f, -7.13f, 5.3f, 1.2f, 0.1f, kAndroidToolTypeFinger);
+ MotionEventAndroid::Pointer p1(
+ 2, -13.7f, 7.13f, 3.5f, 12.1f, -0.1f, kAndroidToolTypeFinger);
+ float raw_offset = -3.f;
+ int pointer_count = 2;
+ int history_size = 0;
+ int action_index = -1;
+ MotionEventAndroid event(kPixToDip,
+ base::android::AttachCurrentThread(),
+ nullptr,
+ event_time_ms,
+ kAndroidActionDown,
+ pointer_count,
+ history_size,
+ action_index,
+ kAndroidButtonPrimary,
+ kAndroidAltKeyDown,
+ raw_offset,
+ -raw_offset,
+ p0,
+ p1);
+
+ EXPECT_EQ(MotionEvent::ACTION_DOWN, event.GetAction());
+ EXPECT_EQ(event_time, event.GetEventTime());
+ EXPECT_EQ(p0.pos_x_pixels * kPixToDip, event.GetX(0));
+ EXPECT_EQ(p0.pos_y_pixels * kPixToDip, event.GetY(0));
+ EXPECT_EQ(p1.pos_x_pixels * kPixToDip, event.GetX(1));
+ EXPECT_EQ(p1.pos_y_pixels * kPixToDip, event.GetY(1));
+ EXPECT_FLOAT_EQ((p0.pos_x_pixels + raw_offset) * kPixToDip, event.GetRawX(0));
+ EXPECT_FLOAT_EQ((p0.pos_y_pixels - raw_offset) * kPixToDip, event.GetRawY(0));
+ EXPECT_FLOAT_EQ((p1.pos_x_pixels + raw_offset) * kPixToDip, event.GetRawX(1));
+ EXPECT_FLOAT_EQ((p1.pos_y_pixels - raw_offset) * kPixToDip, event.GetRawY(1));
+ EXPECT_EQ(p0.touch_major_pixels * kPixToDip, event.GetTouchMajor(0));
+ EXPECT_EQ(p1.touch_major_pixels * kPixToDip, event.GetTouchMajor(1));
+ EXPECT_EQ(p0.touch_minor_pixels * kPixToDip, event.GetTouchMinor(0));
+ EXPECT_EQ(p1.touch_minor_pixels * kPixToDip, event.GetTouchMinor(1));
+ EXPECT_EQ(p0.orientation_rad, event.GetOrientation(0));
+ EXPECT_EQ(p1.orientation_rad, event.GetOrientation(1));
+ EXPECT_EQ(p0.id, event.GetPointerId(0));
+ EXPECT_EQ(p1.id, event.GetPointerId(1));
+ EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(0));
+ EXPECT_EQ(MotionEvent::TOOL_TYPE_FINGER, event.GetToolType(1));
+ EXPECT_EQ(MotionEvent::BUTTON_PRIMARY, event.GetButtonState());
+ EXPECT_EQ(ui::EF_ALT_DOWN, event.GetFlags());
+ EXPECT_EQ(static_cast<size_t>(pointer_count), event.GetPointerCount());
+ EXPECT_EQ(static_cast<size_t>(history_size), event.GetHistorySize());
+ EXPECT_EQ(action_index, event.GetActionIndex());
+}
+
+TEST(MotionEventAndroidTest, Clone) {
+ const int pointer_count = 1;
+ MotionEventAndroid::Pointer p0(
+ 1, 13.7f, -7.13f, 5.3f, 1.2f, 0.1f, kAndroidToolTypeFinger);
+ MotionEventAndroid::Pointer p1(0, 0, 0, 0, 0, 0, 0);
+ MotionEventAndroid event(kPixToDip,
+ base::android::AttachCurrentThread(),
+ nullptr,
+ 0,
+ kAndroidActionDown,
+ pointer_count,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ p0,
+ p1);
+
+ scoped_ptr<MotionEvent> clone = event.Clone();
+ EXPECT_EQ(ui::test::ToString(event), ui::test::ToString(*clone));
+}
+
+TEST(MotionEventAndroidTest, Cancel) {
+ const int event_time_ms = 5;
+ const int pointer_count = 1;
+ MotionEventAndroid::Pointer p0(
+ 1, 13.7f, -7.13f, 5.3f, 1.2f, 0.1f, kAndroidToolTypeFinger);
+ MotionEventAndroid::Pointer p1(0, 0, 0, 0, 0, 0, 0);
+ MotionEventAndroid event(kPixToDip,
+ base::android::AttachCurrentThread(),
+ nullptr,
+ event_time_ms,
+ kAndroidActionDown,
+ pointer_count,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ p0,
+ p1);
+
+ scoped_ptr<MotionEvent> cancel_event = event.Cancel();
+ EXPECT_EQ(MotionEvent::ACTION_CANCEL, cancel_event->GetAction());
+ EXPECT_EQ(
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(event_time_ms),
+ cancel_event->GetEventTime());
+ EXPECT_EQ(p0.pos_x_pixels * kPixToDip, cancel_event->GetX(0));
+ EXPECT_EQ(p0.pos_y_pixels * kPixToDip, cancel_event->GetY(0));
+ EXPECT_EQ(static_cast<size_t>(pointer_count),
+ cancel_event->GetPointerCount());
+ EXPECT_EQ(0U, cancel_event->GetHistorySize());
+}
+
+TEST(MotionEventAndroidTest, InvalidOrientationsSanitized) {
+ int pointer_count = 2;
+ float orientation0 = 1e10f;
+ float orientation1 = std::numeric_limits<float>::quiet_NaN();
+ MotionEventAndroid::Pointer p0(0, 0, 0, 0, 0, orientation0, 0);
+ MotionEventAndroid::Pointer p1(1, 0, 0, 0, 0, orientation1, 0);
+ MotionEventAndroid event(kPixToDip,
+ base::android::AttachCurrentThread(),
+ nullptr,
+ 0,
+ kAndroidActionDown,
+ pointer_count,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ p0,
+ p1);
+
+ EXPECT_EQ(0.f, event.GetOrientation(0));
+ EXPECT_EQ(0.f, event.GetOrientation(1));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/motion_event_web.cc b/chromium/content/browser/renderer_host/input/motion_event_web.cc
index d1ff8a3c84f..77a40a4fe25 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_web.cc
+++ b/chromium/content/browser/renderer_host/input/motion_event_web.cc
@@ -2,9 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// MSVC++ requires this to be set before any other includes to get M_PI.
+#define _USE_MATH_DEFINES
+
#include "content/browser/renderer_host/input/motion_event_web.h"
+#include <cmath>
+
#include "base/logging.h"
+#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/common/input/web_touch_event_traits.h"
using blink::WebInputEvent;
@@ -102,59 +108,58 @@ float MotionEventWeb::GetRawY(size_t pointer_index) const {
float MotionEventWeb::GetTouchMajor(size_t pointer_index) const {
DCHECK_LT(pointer_index, GetPointerCount());
- // TODO(jdduke): We should be a bit more careful about axes here.
return 2.f * std::max(event_.touches[pointer_index].radiusX,
event_.touches[pointer_index].radiusY);
}
-float MotionEventWeb::GetPressure(size_t pointer_index) const {
- return 0.f;
+float MotionEventWeb::GetTouchMinor(size_t pointer_index) const {
+ DCHECK_LT(pointer_index, GetPointerCount());
+ return 2.f * std::min(event_.touches[pointer_index].radiusX,
+ event_.touches[pointer_index].radiusY);
}
-base::TimeTicks MotionEventWeb::GetEventTime() const {
- return base::TimeTicks() +
- base::TimeDelta::FromMicroseconds(event_.timeStampSeconds *
- base::Time::kMicrosecondsPerSecond);
-}
+float MotionEventWeb::GetOrientation(size_t pointer_index) const {
+ DCHECK_LT(pointer_index, GetPointerCount());
-size_t MotionEventWeb::GetHistorySize() const { return 0; }
+ float rotation_angle_rad = event_.touches[pointer_index].rotationAngle
+ * M_PI / 180.f;
+ DCHECK(0 <= rotation_angle_rad && rotation_angle_rad <= M_PI_2)
+ << "Unexpected touch rotation angle";
+
+ if (event_.touches[pointer_index].radiusX
+ > event_.touches[pointer_index].radiusY) {
+ // The case radiusX == radiusY is omitted from here on purpose: for circles,
+ // we want to pass the angle (which could be any value in such cases but
+ // always seem to be set to zero) unchanged.
+ rotation_angle_rad -= (float) M_PI_2;
+ }
-base::TimeTicks MotionEventWeb::GetHistoricalEventTime(
- size_t historical_index) const {
- NOTIMPLEMENTED();
- return base::TimeTicks();
+ return rotation_angle_rad;
}
-float MotionEventWeb::GetHistoricalTouchMajor(size_t pointer_index,
- size_t historical_index) const {
- NOTIMPLEMENTED();
+float MotionEventWeb::GetPressure(size_t pointer_index) const {
return 0.f;
}
-float MotionEventWeb::GetHistoricalX(size_t pointer_index,
- size_t historical_index) const {
- NOTIMPLEMENTED();
- return 0.f;
+base::TimeTicks MotionEventWeb::GetEventTime() const {
+ return base::TimeTicks() +
+ base::TimeDelta::FromMicroseconds(event_.timeStampSeconds *
+ base::Time::kMicrosecondsPerSecond);
}
-float MotionEventWeb::GetHistoricalY(size_t pointer_index,
- size_t historical_index) const {
- NOTIMPLEMENTED();
- return 0.f;
+ui::MotionEvent::ToolType MotionEventWeb::GetToolType(
+ size_t pointer_index) const {
+ // TODO(jdduke): Plumb tool type from the platform event, crbug.com/404128.
+ DCHECK_LT(pointer_index, GetPointerCount());
+ return TOOL_TYPE_UNKNOWN;
}
-scoped_ptr<ui::MotionEvent> MotionEventWeb::Clone() const {
- return scoped_ptr<MotionEvent>(new MotionEventWeb(event_));
+int MotionEventWeb::GetButtonState() const {
+ return 0;
}
-scoped_ptr<ui::MotionEvent> MotionEventWeb::Cancel() const {
- WebTouchEvent cancel_event(event_);
- WebTouchEventTraits::ResetTypeAndTouchStates(
- blink::WebInputEvent::TouchCancel,
- // TODO(rbyers): Shouldn't we use a fresh timestamp?
- event_.timeStampSeconds,
- &cancel_event);
- return scoped_ptr<MotionEvent>(new MotionEventWeb(cancel_event));
+int MotionEventWeb::GetFlags() const {
+ return WebEventModifiersToEventFlags(event_.modifiers);
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/motion_event_web.h b/chromium/content/browser/renderer_host/input/motion_event_web.h
index f4ae25890fe..f3d85abfc12 100644
--- a/chromium/content/browser/renderer_host/input/motion_event_web.h
+++ b/chromium/content/browser/renderer_host/input/motion_event_web.h
@@ -14,35 +14,26 @@ namespace content {
class MotionEventWeb : public ui::MotionEvent {
public:
explicit MotionEventWeb(const blink::WebTouchEvent& event);
- virtual ~MotionEventWeb();
+ ~MotionEventWeb() override;
// ui::MotionEvent
- virtual int GetId() const OVERRIDE;
- virtual Action GetAction() const OVERRIDE;
- virtual int GetActionIndex() const OVERRIDE;
- virtual size_t GetPointerCount() const OVERRIDE;
- virtual int GetPointerId(size_t pointer_index) const OVERRIDE;
- virtual float GetX(size_t pointer_index) const OVERRIDE;
- virtual float GetY(size_t pointer_index) const OVERRIDE;
- virtual float GetRawX(size_t pointer_index) const OVERRIDE;
- virtual float GetRawY(size_t pointer_index) const OVERRIDE;
- virtual float GetTouchMajor(size_t pointer_index) const OVERRIDE;
- virtual float GetPressure(size_t pointer_index) const OVERRIDE;
- virtual base::TimeTicks GetEventTime() const OVERRIDE;
- virtual size_t GetHistorySize() const OVERRIDE;
- virtual base::TimeTicks GetHistoricalEventTime(
- size_t historical_index) const OVERRIDE;
- virtual float GetHistoricalTouchMajor(
- size_t pointer_index,
- size_t historical_index) const OVERRIDE;
- virtual float GetHistoricalX(
- size_t pointer_index,
- size_t historical_index) const OVERRIDE;
- virtual float GetHistoricalY(
- size_t pointer_index,
- size_t historical_index) const OVERRIDE;
- virtual scoped_ptr<MotionEvent> Clone() const OVERRIDE;
- virtual scoped_ptr<MotionEvent> Cancel() const OVERRIDE;
+ int GetId() const override;
+ Action GetAction() const override;
+ int GetActionIndex() const override;
+ size_t GetPointerCount() const override;
+ int GetPointerId(size_t pointer_index) const override;
+ float GetX(size_t pointer_index) const override;
+ float GetY(size_t pointer_index) const override;
+ float GetRawX(size_t pointer_index) const override;
+ float GetRawY(size_t pointer_index) const override;
+ float GetTouchMajor(size_t pointer_index) const override;
+ float GetTouchMinor(size_t pointer_index) const override;
+ float GetOrientation(size_t pointer_index) const override;
+ float GetPressure(size_t pointer_index) const override;
+ base::TimeTicks GetEventTime() const override;
+ ToolType GetToolType(size_t pointer_index) const override;
+ int GetButtonState() const override;
+ int GetFlags() const override;
private:
blink::WebTouchEvent event_;
diff --git a/chromium/content/browser/renderer_host/input/selection_event_type.h b/chromium/content/browser/renderer_host/input/selection_event_type.h
new file mode 100644
index 00000000000..567259f0496
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/selection_event_type.h
@@ -0,0 +1,29 @@
+// 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_RENDERER_HOST_INPUT_SELECTION_EVENT_TYPE_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_SELECTION_EVENT_TYPE_
+
+namespace content {
+
+// This file contains a list of events relating to selection and insertion, used
+// for notifying Java when the renderer selection has changed.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.content.browser.input
+enum SelectionEventType {
+ SELECTION_SHOWN,
+ SELECTION_CLEARED,
+ SELECTION_DRAG_STARTED,
+ SELECTION_DRAG_STOPPED,
+ INSERTION_SHOWN,
+ INSERTION_MOVED,
+ INSERTION_TAPPED,
+ INSERTION_CLEARED,
+ INSERTION_DRAG_STARTED,
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_SELECTION_EVENT_TYPE_
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.cc b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.cc
index 8314d948ba7..6e5e20fb22a 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_controller.cc
@@ -61,9 +61,10 @@ void SyntheticGestureController::OnDidFlushInput() {
return;
DCHECK(!pending_gesture_queue_.IsEmpty());
+ auto pending_gesture_result = pending_gesture_result_.Pass();
StopGesture(*pending_gesture_queue_.FrontGesture(),
pending_gesture_queue_.FrontCallback(),
- *pending_gesture_result_.Pass());
+ *pending_gesture_result);
pending_gesture_queue_.Pop();
if (!pending_gesture_queue_.IsEmpty())
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 b79e797aad2..8c08361e7d0 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
@@ -47,10 +47,10 @@ class MockSyntheticGesture : public SyntheticGesture {
step_count_(0) {
*finished_ = false;
}
- virtual ~MockSyntheticGesture() {}
+ ~MockSyntheticGesture() override {}
- virtual Result ForwardInputEvents(const base::TimeTicks& timestamp,
- SyntheticGestureTarget* target) OVERRIDE {
+ Result ForwardInputEvents(const base::TimeTicks& timestamp,
+ SyntheticGestureTarget* target) override {
step_count_++;
if (step_count_ == num_steps_) {
*finished_ = true;
@@ -75,22 +75,19 @@ class MockSyntheticGestureTarget : public SyntheticGestureTarget {
MockSyntheticGestureTarget()
: flush_requested_(false),
pointer_assumed_stopped_time_ms_(kPointerAssumedStoppedTimeMs) {}
- virtual ~MockSyntheticGestureTarget() {}
+ ~MockSyntheticGestureTarget() override {}
// SyntheticGestureTarget:
- virtual void DispatchInputEventToPlatform(
- const WebInputEvent& event) OVERRIDE {}
+ void DispatchInputEventToPlatform(const WebInputEvent& event) override {}
- virtual void SetNeedsFlush() OVERRIDE {
- flush_requested_ = true;
- }
+ void SetNeedsFlush() override { flush_requested_ = true; }
- virtual SyntheticGestureParams::GestureSourceType
- GetDefaultSyntheticGestureSourceType() const OVERRIDE {
+ SyntheticGestureParams::GestureSourceType
+ GetDefaultSyntheticGestureSourceType() const override {
return SyntheticGestureParams::TOUCH_INPUT;
}
- virtual base::TimeDelta PointerAssumedStoppedTime() const OVERRIDE {
+ base::TimeDelta PointerAssumedStoppedTime() const override {
return base::TimeDelta::FromMilliseconds(pointer_assumed_stopped_time_ms_);
}
@@ -98,11 +95,9 @@ class MockSyntheticGestureTarget : public SyntheticGestureTarget {
pointer_assumed_stopped_time_ms_ = time_ms;
}
- virtual float GetTouchSlopInDips() const OVERRIDE {
- return kTouchSlopInDips;
- }
+ float GetTouchSlopInDips() const override { return kTouchSlopInDips; }
- virtual float GetMinScalingSpanInDips() const OVERRIDE {
+ float GetMinScalingSpanInDips() const override {
return kMinScalingSpanInDips;
}
@@ -118,7 +113,7 @@ class MockSyntheticGestureTarget : public SyntheticGestureTarget {
class MockScrollGestureTarget : public MockSyntheticGestureTarget {
public:
MockScrollGestureTarget() : total_abs_scroll_distance_length_(0) {}
- virtual ~MockScrollGestureTarget() {}
+ ~MockScrollGestureTarget() override {}
gfx::Vector2dF start_to_end_distance() const {
return start_to_end_distance_;
@@ -135,10 +130,9 @@ class MockScrollGestureTarget : public MockSyntheticGestureTarget {
class MockScrollMouseTarget : public MockScrollGestureTarget {
public:
MockScrollMouseTarget() {}
- virtual ~MockScrollMouseTarget() {}
+ ~MockScrollMouseTarget() override {}
- virtual void DispatchInputEventToPlatform(
- const WebInputEvent& event) OVERRIDE {
+ void DispatchInputEventToPlatform(const WebInputEvent& event) override {
ASSERT_EQ(event.type, WebInputEvent::MouseWheel);
const WebMouseWheelEvent& mouse_wheel_event =
static_cast<const WebMouseWheelEvent&>(event);
@@ -151,10 +145,9 @@ class MockScrollMouseTarget : public MockScrollGestureTarget {
class MockScrollTouchTarget : public MockScrollGestureTarget {
public:
MockScrollTouchTarget() : started_(false) {}
- virtual ~MockScrollTouchTarget() {}
+ ~MockScrollTouchTarget() override {}
- virtual void DispatchInputEventToPlatform(
- const WebInputEvent& event) OVERRIDE {
+ void DispatchInputEventToPlatform(const WebInputEvent& event) override {
ASSERT_TRUE(WebInputEvent::isTouchEventType(event.type));
const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event);
ASSERT_EQ(touch_event.touchesLength, 1U);
@@ -200,10 +193,9 @@ class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget {
last_pointer_distance_(0),
zoom_direction_(ZOOM_DIRECTION_UNKNOWN),
started_(false) {}
- virtual ~MockSyntheticPinchTouchTarget() {}
+ ~MockSyntheticPinchTouchTarget() override {}
- virtual void DispatchInputEventToPlatform(
- const WebInputEvent& event) OVERRIDE {
+ void DispatchInputEventToPlatform(const WebInputEvent& event) override {
ASSERT_TRUE(WebInputEvent::isTouchEventType(event.type));
const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event);
ASSERT_EQ(touch_event.touchesLength, 2U);
@@ -278,7 +270,7 @@ class MockSyntheticPinchTouchTarget : public MockSyntheticGestureTarget {
class MockSyntheticTapGestureTarget : public MockSyntheticGestureTarget {
public:
MockSyntheticTapGestureTarget() : state_(NOT_STARTED) {}
- virtual ~MockSyntheticTapGestureTarget() {}
+ ~MockSyntheticTapGestureTarget() override {}
bool GestureFinished() const { return state_ == FINISHED; }
gfx::PointF position() const { return position_; }
@@ -300,10 +292,9 @@ class MockSyntheticTapGestureTarget : public MockSyntheticGestureTarget {
class MockSyntheticTapTouchTarget : public MockSyntheticTapGestureTarget {
public:
MockSyntheticTapTouchTarget() {}
- virtual ~MockSyntheticTapTouchTarget() {}
+ ~MockSyntheticTapTouchTarget() override {}
- virtual void DispatchInputEventToPlatform(
- const WebInputEvent& event) OVERRIDE {
+ void DispatchInputEventToPlatform(const WebInputEvent& event) override {
ASSERT_TRUE(WebInputEvent::isTouchEventType(event.type));
const WebTouchEvent& touch_event = static_cast<const WebTouchEvent&>(event);
ASSERT_EQ(touch_event.touchesLength, 1U);
@@ -333,10 +324,9 @@ class MockSyntheticTapTouchTarget : public MockSyntheticTapGestureTarget {
class MockSyntheticTapMouseTarget : public MockSyntheticTapGestureTarget {
public:
MockSyntheticTapMouseTarget() {}
- virtual ~MockSyntheticTapMouseTarget() {}
+ ~MockSyntheticTapMouseTarget() override {}
- virtual void DispatchInputEventToPlatform(
- const WebInputEvent& event) OVERRIDE {
+ void DispatchInputEventToPlatform(const WebInputEvent& event) override {
ASSERT_TRUE(WebInputEvent::isMouseEventType(event.type));
const WebMouseEvent& mouse_event = static_cast<const WebMouseEvent&>(event);
@@ -369,7 +359,7 @@ class MockSyntheticTapMouseTarget : public MockSyntheticTapGestureTarget {
class SyntheticGestureControllerTest : public testing::Test {
public:
SyntheticGestureControllerTest() {}
- virtual ~SyntheticGestureControllerTest() {}
+ ~SyntheticGestureControllerTest() override {}
protected:
template<typename MockGestureTarget>
@@ -379,14 +369,14 @@ class SyntheticGestureControllerTest : public testing::Test {
scoped_ptr<SyntheticGestureTarget>(target_)));
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
start_time_ = base::TimeTicks::Now();
time_ = start_time_;
num_success_ = 0;
num_failure_ = 0;
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
controller_.reset();
target_ = NULL;
time_ = base::TimeTicks();
@@ -430,10 +420,10 @@ class SyntheticGestureControllerTest : public testing::Test {
TEST_F(SyntheticGestureControllerTest, SingleGesture) {
CreateControllerAndTarget<MockSyntheticGestureTarget>();
- bool finished;
+ bool finished = false;
scoped_ptr<MockSyntheticGesture> gesture(
new MockSyntheticGesture(&finished, 3));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
EXPECT_TRUE(finished);
@@ -444,10 +434,10 @@ TEST_F(SyntheticGestureControllerTest, SingleGesture) {
TEST_F(SyntheticGestureControllerTest, GestureFailed) {
CreateControllerAndTarget<MockSyntheticGestureTarget>();
- bool finished;
+ bool finished = false;
scoped_ptr<MockSyntheticGesture> gesture(
new MockSyntheticGesture(&finished, 0));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
EXPECT_TRUE(finished);
@@ -458,14 +448,15 @@ TEST_F(SyntheticGestureControllerTest, GestureFailed) {
TEST_F(SyntheticGestureControllerTest, SuccessiveGestures) {
CreateControllerAndTarget<MockSyntheticGestureTarget>();
- bool finished_1, finished_2;
+ bool finished_1 = false;
scoped_ptr<MockSyntheticGesture> gesture_1(
new MockSyntheticGesture(&finished_1, 2));
+ bool finished_2 = false;
scoped_ptr<MockSyntheticGesture> gesture_2(
new MockSyntheticGesture(&finished_2, 4));
// Queue first gesture and wait for it to finish
- QueueSyntheticGesture(gesture_1.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture_1.Pass());
FlushInputUntilComplete();
EXPECT_TRUE(finished_1);
@@ -473,7 +464,7 @@ TEST_F(SyntheticGestureControllerTest, SuccessiveGestures) {
EXPECT_EQ(0, num_failure_);
// Queue second gesture.
- QueueSyntheticGesture(gesture_2.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture_2.Pass());
FlushInputUntilComplete();
EXPECT_TRUE(finished_2);
@@ -484,14 +475,15 @@ TEST_F(SyntheticGestureControllerTest, SuccessiveGestures) {
TEST_F(SyntheticGestureControllerTest, TwoGesturesInFlight) {
CreateControllerAndTarget<MockSyntheticGestureTarget>();
- bool finished_1, finished_2;
+ bool finished_1 = false;
scoped_ptr<MockSyntheticGesture> gesture_1(
new MockSyntheticGesture(&finished_1, 2));
+ bool finished_2 = false;
scoped_ptr<MockSyntheticGesture> gesture_2(
new MockSyntheticGesture(&finished_2, 4));
- QueueSyntheticGesture(gesture_1.PassAs<SyntheticGesture>());
- QueueSyntheticGesture(gesture_2.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture_1.Pass());
+ QueueSyntheticGesture(gesture_2.Pass());
FlushInputUntilComplete();
EXPECT_TRUE(finished_1);
@@ -510,8 +502,8 @@ TEST_F(SyntheticGestureControllerTest, GestureCompletedOnDidFlushInput) {
scoped_ptr<MockSyntheticGesture> gesture_2(
new MockSyntheticGesture(&finished_2, 4));
- QueueSyntheticGesture(gesture_1.PassAs<SyntheticGesture>());
- QueueSyntheticGesture(gesture_2.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture_1.Pass());
+ QueueSyntheticGesture(gesture_2.Pass());
while (target_->flush_requested()) {
target_->ClearFlushRequest();
@@ -561,16 +553,15 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchVertical) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
static_cast<MockScrollGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
- // TODO(dominikg): Remove adjustment when crbug.com/332418 is fixed.
EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_),
- scroll_target->start_to_end_distance() - gfx::Vector2dF(0, 0.001f));
+ scroll_target->start_to_end_distance());
}
TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchHorizontal) {
@@ -583,22 +574,15 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchHorizontal) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
static_cast<MockScrollGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
- // TODO(dominikg): Use vector comparison when crbug.com/332418 is fixed.
- //EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_),
- // scroll_target->start_to_end_distance());
- EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_).x(),
- scroll_target->start_to_end_distance().x());
- EXPECT_LT(AddTouchSlopToVector(params.distances[0], target_).y(),
- scroll_target->start_to_end_distance().y());
- EXPECT_GE(AddTouchSlopToVector(params.distances[0], target_).y(),
- scroll_target->start_to_end_distance().y() - 0.001f);
+ EXPECT_EQ(AddTouchSlopToVector(params.distances[0], target_),
+ scroll_target->start_to_end_distance());
}
void CheckIsWithinRangeSingle(float scroll_distance,
@@ -631,7 +615,7 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchDiagonal) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -658,7 +642,7 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchLongStop) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -686,7 +670,7 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchFling) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -708,7 +692,7 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureTouchZeroDistance) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -728,7 +712,7 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseVertical) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -748,7 +732,7 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseHorizontal) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -768,7 +752,7 @@ TEST_F(SyntheticGestureControllerTest, SingleScrollGestureMouseDiagonal) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -789,7 +773,7 @@ TEST_F(SyntheticGestureControllerTest, MultiScrollGestureMouse) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -811,7 +795,7 @@ TEST_F(SyntheticGestureControllerTest, MultiScrollGestureMouseHorizontal) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -857,7 +841,7 @@ TEST_F(SyntheticGestureControllerTest, MultiScrollGestureTouch) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
@@ -881,21 +865,20 @@ TEST_F(SyntheticGestureControllerTest, MultiScrollGestureTouchVertical) {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockScrollGestureTarget* scroll_target =
static_cast<MockScrollGestureTarget*>(target_);
EXPECT_EQ(1, num_success_);
EXPECT_EQ(0, num_failure_);
- // TODO(dominikg): Remove adjustment when crbug.com/332418 is fixed.
EXPECT_FLOAT_EQ(
params.distances[0].Length() + params.distances[1].Length() +
target_->GetTouchSlopInDips(),
- scroll_target->total_abs_scroll_distance_length() - 0.001f);
+ scroll_target->total_abs_scroll_distance_length());
EXPECT_EQ(AddTouchSlopToVector(params.distances[0] + params.distances[1],
target_),
- scroll_target->start_to_end_distance() - gfx::Vector2dF(0, 0.001f));
+ scroll_target->start_to_end_distance());
}
TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomIn) {
@@ -907,7 +890,7 @@ TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomIn) {
params.anchor.SetPoint(54, 89);
scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockSyntheticPinchTouchTarget* pinch_target =
@@ -928,7 +911,7 @@ TEST_F(SyntheticGestureControllerTest, PinchGestureTouchZoomOut) {
params.anchor.SetPoint(-12, 93);
scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockSyntheticPinchTouchTarget* pinch_target =
@@ -948,7 +931,7 @@ TEST_F(SyntheticGestureControllerTest, PinchGestureTouchNoScaling) {
params.scale_factor = 1.0f;
scoped_ptr<SyntheticPinchGesture> gesture(new SyntheticPinchGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockSyntheticPinchTouchTarget* pinch_target =
@@ -969,7 +952,7 @@ TEST_F(SyntheticGestureControllerTest, TapGestureTouch) {
params.position.SetPoint(87, -124);
scoped_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockSyntheticTapTouchTarget* tap_target =
@@ -992,7 +975,7 @@ TEST_F(SyntheticGestureControllerTest, TapGestureMouse) {
params.position.SetPoint(98, 123);
scoped_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params));
- QueueSyntheticGesture(gesture.PassAs<SyntheticGesture>());
+ QueueSyntheticGesture(gesture.Pass());
FlushInputUntilComplete();
MockSyntheticTapMouseTarget* tap_target =
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_android.h b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_android.h
index dcf146ffb92..571fcbdb76f 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_android.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_android.h
@@ -25,21 +25,21 @@ class SyntheticGestureTargetAndroid : public SyntheticGestureTargetBase {
// SyntheticGestureTargetBase:
virtual void DispatchWebTouchEventToPlatform(
const blink::WebTouchEvent& web_touch,
- const ui::LatencyInfo& latency_info) OVERRIDE;
+ const ui::LatencyInfo& latency_info) override;
virtual void DispatchWebMouseWheelEventToPlatform(
const blink::WebMouseWheelEvent& web_wheel,
- const ui::LatencyInfo& latency_info) OVERRIDE;
+ const ui::LatencyInfo& latency_info) override;
virtual void DispatchWebMouseEventToPlatform(
const blink::WebMouseEvent& web_mouse,
- const ui::LatencyInfo& latency_info) OVERRIDE;
+ const ui::LatencyInfo& latency_info) override;
// SyntheticGestureTarget:
virtual SyntheticGestureParams::GestureSourceType
- GetDefaultSyntheticGestureSourceType() const OVERRIDE;
+ GetDefaultSyntheticGestureSourceType() const override;
- virtual float GetTouchSlopInDips() const OVERRIDE;
+ virtual float GetTouchSlopInDips() const override;
- virtual float GetMinScalingSpanInDips() const OVERRIDE;
+ virtual float GetMinScalingSpanInDips() const override;
private:
// Enum values below need to be kept in sync with TouchEventSynthesizer.java
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
index 0b4d9c8c97f..a7626d440d4 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
@@ -10,7 +10,7 @@
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/events/event_processor.h"
-#include "ui/events/gestures/gesture_configuration.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
using blink::WebTouchEvent;
using blink::WebMouseWheelEvent;
@@ -135,11 +135,14 @@ SyntheticGestureTargetAura::GetDefaultSyntheticGestureSourceType() const {
float SyntheticGestureTargetAura::GetTouchSlopInDips() const {
// - 1 because Aura considers a pointer to be moving if it has moved at least
// 'max_touch_move_in_pixels_for_click' pixels.
- return ui::GestureConfiguration::max_touch_move_in_pixels_for_click() - 1;
+ return ui::GestureConfiguration::GetInstance()
+ ->max_touch_move_in_pixels_for_click() -
+ 1;
}
float SyntheticGestureTargetAura::GetMinScalingSpanInDips() const {
- return ui::GestureConfiguration::min_distance_for_pinch_scroll_in_pixels();
+ return ui::GestureConfiguration::GetInstance()
+ ->min_distance_for_pinch_scroll_in_pixels();
}
aura::Window* SyntheticGestureTargetAura::GetWindow() const {
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.h b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
index f3634d61162..53f06720b8e 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
@@ -26,23 +26,23 @@ class SyntheticGestureTargetAura : public SyntheticGestureTargetBase {
explicit SyntheticGestureTargetAura(RenderWidgetHostImpl* host);
// SyntheticGestureTargetBase:
- virtual void DispatchWebTouchEventToPlatform(
+ void DispatchWebTouchEventToPlatform(
const blink::WebTouchEvent& web_touch,
- const ui::LatencyInfo& latency_info) OVERRIDE;
- virtual void DispatchWebMouseWheelEventToPlatform(
+ const ui::LatencyInfo& latency_info) override;
+ void DispatchWebMouseWheelEventToPlatform(
const blink::WebMouseWheelEvent& web_wheel,
- const ui::LatencyInfo& latency_info) OVERRIDE;
- virtual void DispatchWebMouseEventToPlatform(
+ const ui::LatencyInfo& latency_info) override;
+ void DispatchWebMouseEventToPlatform(
const blink::WebMouseEvent& web_mouse,
- const ui::LatencyInfo& latency_info) OVERRIDE;
+ const ui::LatencyInfo& latency_info) override;
// SyntheticGestureTarget:
- virtual SyntheticGestureParams::GestureSourceType
- GetDefaultSyntheticGestureSourceType() const OVERRIDE;
+ SyntheticGestureParams::GestureSourceType
+ GetDefaultSyntheticGestureSourceType() const override;
- virtual float GetTouchSlopInDips() const OVERRIDE;
+ float GetTouchSlopInDips() const override;
- virtual float GetMinScalingSpanInDips() const OVERRIDE;
+ float GetMinScalingSpanInDips() const override;
private:
aura::Window* GetWindow() const;
diff --git a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.h b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.h
index a66a8d34cae..d48be113e62 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_gesture_target_base.h
@@ -25,7 +25,7 @@ class RenderWidgetHostImpl;
class SyntheticGestureTargetBase : public SyntheticGestureTarget {
public:
explicit SyntheticGestureTargetBase(RenderWidgetHostImpl* host);
- virtual ~SyntheticGestureTargetBase();
+ ~SyntheticGestureTargetBase() override;
virtual void DispatchWebTouchEventToPlatform(
const blink::WebTouchEvent& web_touch,
@@ -40,19 +40,18 @@ class SyntheticGestureTargetBase : public SyntheticGestureTarget {
const ui::LatencyInfo& latency_info);
// SyntheticGestureTarget:
- virtual void DispatchInputEventToPlatform(
- const blink::WebInputEvent& event) OVERRIDE;
+ void DispatchInputEventToPlatform(const blink::WebInputEvent& event) override;
- virtual void SetNeedsFlush() OVERRIDE;
+ void SetNeedsFlush() override;
- virtual SyntheticGestureParams::GestureSourceType
- GetDefaultSyntheticGestureSourceType() const OVERRIDE;
+ SyntheticGestureParams::GestureSourceType
+ GetDefaultSyntheticGestureSourceType() const override;
- virtual base::TimeDelta PointerAssumedStoppedTime() const OVERRIDE;
+ base::TimeDelta PointerAssumedStoppedTime() const override;
- virtual float GetTouchSlopInDips() const OVERRIDE;
+ float GetTouchSlopInDips() const override;
- virtual float GetMinScalingSpanInDips() const OVERRIDE;
+ float GetMinScalingSpanInDips() const override;
protected:
RenderWidgetHostImpl* render_widget_host() const { return host_; }
diff --git a/chromium/content/browser/renderer_host/input/synthetic_pinch_gesture.h b/chromium/content/browser/renderer_host/input/synthetic_pinch_gesture.h
index 76ee1da7b26..71e79ec6b2b 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_pinch_gesture.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_pinch_gesture.h
@@ -18,11 +18,11 @@ namespace content {
class CONTENT_EXPORT SyntheticPinchGesture : public SyntheticGesture {
public:
explicit SyntheticPinchGesture(const SyntheticPinchGestureParams& params);
- virtual ~SyntheticPinchGesture();
+ ~SyntheticPinchGesture() override;
- virtual SyntheticGesture::Result ForwardInputEvents(
+ SyntheticGesture::Result ForwardInputEvents(
const base::TimeTicks& timestamp,
- SyntheticGestureTarget* target) OVERRIDE;
+ SyntheticGestureTarget* target) override;
private:
enum GestureState {
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc b/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc
index b6b281406c3..8800aca2969 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc
@@ -99,15 +99,6 @@ void SyntheticSmoothScrollGesture::ForwardTouchInputEvents(
target->PointerAssumedStoppedTime()) {
event_timestamp = current_scroll_segment_stop_time_ +
target->PointerAssumedStoppedTime();
- // Send one last move event, but don't change the location. Without this
- // we'd still sometimes cause a fling on Android.
-
- // Required to suppress flings on Aura, see
- // |UpdateWebTouchPointFromUIEvent|, remove when crbug.com/332418
- // is fixed.
- touch_event_.touches[0].position.y += 0.001f;
-
- ForwardTouchEvent(target, event_timestamp);
ReleaseTouchPoint(target, event_timestamp);
state_ = DONE;
}
diff --git a/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h b/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h
index a4078550e0e..080e2dbaec1 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h
@@ -28,11 +28,11 @@ class CONTENT_EXPORT SyntheticSmoothScrollGesture : public SyntheticGesture {
public:
explicit SyntheticSmoothScrollGesture(
const SyntheticSmoothScrollGestureParams& params);
- virtual ~SyntheticSmoothScrollGesture();
+ ~SyntheticSmoothScrollGesture() override;
- virtual SyntheticGesture::Result ForwardInputEvents(
+ SyntheticGesture::Result ForwardInputEvents(
const base::TimeTicks& timestamp,
- SyntheticGestureTarget* target) OVERRIDE;
+ SyntheticGestureTarget* target) override;
private:
enum GestureState {
diff --git a/chromium/content/browser/renderer_host/input/synthetic_tap_gesture.h b/chromium/content/browser/renderer_host/input/synthetic_tap_gesture.h
index e67d1984d98..a42b2dd17ed 100644
--- a/chromium/content/browser/renderer_host/input/synthetic_tap_gesture.h
+++ b/chromium/content/browser/renderer_host/input/synthetic_tap_gesture.h
@@ -16,11 +16,11 @@ namespace content {
class CONTENT_EXPORT SyntheticTapGesture : public SyntheticGesture {
public:
explicit SyntheticTapGesture(const SyntheticTapGestureParams& params);
- virtual ~SyntheticTapGesture();
+ ~SyntheticTapGesture() override;
- virtual SyntheticGesture::Result ForwardInputEvents(
+ SyntheticGesture::Result ForwardInputEvents(
const base::TimeTicks& timestamp,
- SyntheticGestureTarget* target) OVERRIDE;
+ SyntheticGestureTarget* target) override;
private:
enum GestureState {
diff --git a/chromium/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc b/chromium/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc
index 702dc6f10b8..0c2e94f07e0 100644
--- a/chromium/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/tap_suppression_controller_unittest.cc
@@ -39,7 +39,7 @@ class MockTapSuppressionController : public TapSuppressionController,
time_(),
timer_started_(false) {}
- virtual ~MockTapSuppressionController() {}
+ ~MockTapSuppressionController() override {}
void SendGestureFlingCancel() {
last_actions_ = NONE;
@@ -89,26 +89,20 @@ class MockTapSuppressionController : public TapSuppressionController,
int last_actions() { return last_actions_; }
protected:
- virtual base::TimeTicks Now() OVERRIDE {
- return time_;
- }
+ base::TimeTicks Now() override { return time_; }
- virtual void StartTapDownTimer(const base::TimeDelta& delay) OVERRIDE {
+ void StartTapDownTimer(const base::TimeDelta& delay) override {
timer_expiry_time_ = time_ + delay;
timer_started_ = true;
}
- virtual void StopTapDownTimer() OVERRIDE {
- timer_started_ = false;
- }
+ void StopTapDownTimer() override { timer_started_ = false; }
private:
// TapSuppressionControllerClient implementation
- virtual void DropStashedTapDown() OVERRIDE {
- last_actions_ |= TAP_DOWN_DROPPED;
- }
+ void DropStashedTapDown() override { last_actions_ |= TAP_DOWN_DROPPED; }
- virtual void ForwardStashedTapDown() OVERRIDE {
+ void ForwardStashedTapDown() override {
last_actions_ |= STASHED_TAP_DOWN_FORWARDED;
}
@@ -131,19 +125,16 @@ class TapSuppressionControllerTest : public testing::Test {
public:
TapSuppressionControllerTest() {
}
- virtual ~TapSuppressionControllerTest() {
- }
+ ~TapSuppressionControllerTest() override {}
protected:
// testing::Test
- virtual void SetUp() {
+ void SetUp() override {
tap_suppression_controller_.reset(
new MockTapSuppressionController(GetConfig()));
}
- virtual void TearDown() {
- tap_suppression_controller_.reset();
- }
+ void TearDown() override { tap_suppression_controller_.reset(); }
static TapSuppressionController::Config GetConfig() {
TapSuppressionController::Config config;
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 9d9fb83785d..c9d0a2bef86 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -71,7 +71,7 @@ namespace content {
class TouchActionBrowserTest : public ContentBrowserTest {
public:
TouchActionBrowserTest() {}
- virtual ~TouchActionBrowserTest() {}
+ ~TouchActionBrowserTest() override {}
RenderWidgetHostImpl* GetWidgetHost() {
return RenderWidgetHostImpl::From(shell()->web_contents()->
@@ -97,7 +97,7 @@ class TouchActionBrowserTest : public ContentBrowserTest {
}
// ContentBrowserTest:
- virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
+ void SetUpCommandLine(CommandLine* cmd) override {
cmd->AppendSwitchASCII(switches::kTouchEvents,
switches::kTouchEventsEnabled);
// TODO(rbyers): Remove this switch once touch-action ships.
@@ -138,9 +138,9 @@ class TouchActionBrowserTest : public ContentBrowserTest {
scoped_ptr<SyntheticSmoothScrollGesture> gesture(
new SyntheticSmoothScrollGesture(params));
GetWidgetHost()->QueueSyntheticGesture(
- gesture.PassAs<SyntheticGesture>(),
+ gesture.Pass(),
base::Bind(&TouchActionBrowserTest::OnSyntheticGestureCompleted,
- base::Unretained(this)));
+ base::Unretained(this)));
// Runs until we get the OnSyntheticGestureCompleted callback
runner_->Run();
@@ -192,16 +192,8 @@ IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, DISABLED_DefaultAuto) {
// Verify that touching a touch-action: none region disables scrolling and
// enables all touch events to be sent.
// Disabled on MacOS because it doesn't support touch input.
-// Flaky on OS_CHROMEOS http://crbug.com/376695.
-// Also flaky on Linux Tests (TSan v2) http://crbug.com/376668.
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
-#define MAYBE_TouchActionNone DISABLED_TouchActionNone
-#elif defined(THREAD_SANITIZER) && defined(OS_LINUX)
-#define MAYBE_TouchActionNone DISABLED_TouchActionNone
-#else
-#define MAYBE_TouchActionNone TouchActionNone
-#endif
-IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_TouchActionNone) {
+// It's just flaky everywhere.
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, DISABLED_TouchActionNone) {
LoadURL();
bool scrolled = DoTouchScroll(gfx::Point(50, 150), gfx::Vector2d(0, 45));
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator.cc b/chromium/content/browser/renderer_host/input/touch_emulator.cc
index c7d5cc605a7..61ae63ef1ff 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator.cc
+++ b/chromium/content/browser/renderer_host/input/touch_emulator.cc
@@ -7,11 +7,11 @@
#include "content/browser/renderer_host/input/motion_event_web.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/common/input/web_touch_event_traits.h"
+#include "content/grit/content_resources.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
-#include "grit/content_resources.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
-#include "ui/events/gesture_detection/gesture_config_helper.h"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/screen.h"
@@ -47,14 +47,15 @@ TouchEmulator::TouchEmulator(TouchEmulatorClient* client)
: client_(client),
gesture_provider_(GetGestureProviderConfig(), this),
enabled_(false),
- allow_pinch_(false) {
+ emulated_stream_active_sequence_count_(0),
+ native_stream_active_sequence_count_(0) {
DCHECK(client_);
ResetState();
bool use_2x = gfx::Screen::GetNativeScreen()->
GetPrimaryDisplay().device_scale_factor() > 1.5f;
float cursor_scale_factor = use_2x ? 2.f : 1.f;
- InitCursorFromResource(&touch_cursor_,
+ cursor_size_ = InitCursorFromResource(&touch_cursor_,
cursor_scale_factor,
use_2x ? IDR_DEVTOOLS_TOUCH_CURSOR_ICON_2X :
IDR_DEVTOOLS_TOUCH_CURSOR_ICON);
@@ -85,18 +86,16 @@ void TouchEmulator::ResetState() {
last_mouse_move_timestamp_ = 0;
mouse_pressed_ = false;
shift_pressed_ = false;
- touch_active_ = false;
suppress_next_fling_cancel_ = false;
pinch_scale_ = 1.f;
pinch_gesture_active_ = false;
}
-void TouchEmulator::Enable(bool allow_pinch) {
+void TouchEmulator::Enable() {
if (!enabled_) {
enabled_ = true;
ResetState();
}
- allow_pinch_ = allow_pinch;
UpdateCursor();
}
@@ -109,7 +108,7 @@ void TouchEmulator::Disable() {
CancelTouch();
}
-void TouchEmulator::InitCursorFromResource(
+gfx::SizeF TouchEmulator::InitCursorFromResource(
WebCursor* cursor, float scale, int resource_id) {
gfx::Image& cursor_image =
content::GetContentClient()->GetNativeImageNamed(resource_id);
@@ -124,12 +123,18 @@ void TouchEmulator::InitCursorFromResource(
#endif
cursor->InitFromCursorInfo(cursor_info);
+ return gfx::ScaleSize(cursor_image.Size(), 1.f / scale);
}
bool TouchEmulator::HandleMouseEvent(const WebMouseEvent& mouse_event) {
if (!enabled_)
return false;
+ if (mouse_event.button == WebMouseEvent::ButtonRight &&
+ mouse_event.type == WebInputEvent::MouseDown) {
+ client_->ShowContextMenuAtPoint(gfx::Point(mouse_event.x, mouse_event.y));
+ }
+
if (mouse_event.button != WebMouseEvent::ButtonLeft)
return true;
@@ -154,7 +159,7 @@ bool TouchEmulator::HandleMouseEvent(const WebMouseEvent& mouse_event) {
if (FillTouchEventAndPoint(mouse_event) &&
gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_))) {
- client_->ForwardTouchEvent(touch_event_);
+ ForwardTouchEventToClient();
}
// Do not pass mouse events to the renderer.
@@ -166,7 +171,7 @@ bool TouchEmulator::HandleMouseWheelEvent(const WebMouseWheelEvent& event) {
return false;
// Send mouse wheel for easy scrolling when there is no active touch.
- return touch_active_;
+ return emulated_stream_active_sequence_count_ > 0;
}
bool TouchEmulator::HandleKeyboardEvent(const WebKeyboardEvent& event) {
@@ -192,11 +197,59 @@ bool TouchEmulator::HandleKeyboardEvent(const WebKeyboardEvent& event) {
return false;
}
-bool TouchEmulator::HandleTouchEventAck(InputEventAckState ack_result) {
- const bool event_consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
- gesture_provider_.OnTouchEventAck(event_consumed);
- // TODO(dgozman): Disable emulation when real touch events are available.
- return true;
+bool TouchEmulator::HandleTouchEvent(const blink::WebTouchEvent& event) {
+ // Block native event when emulated touch stream is active.
+ if (emulated_stream_active_sequence_count_)
+ return true;
+
+ bool is_sequence_start = WebTouchEventTraits::IsTouchSequenceStart(event);
+ // Do not allow middle-sequence event to pass through, if start was blocked.
+ if (!native_stream_active_sequence_count_ && !is_sequence_start)
+ return true;
+
+ if (is_sequence_start)
+ native_stream_active_sequence_count_++;
+ return false;
+}
+
+void TouchEmulator::ForwardTouchEventToClient() {
+ const bool event_consumed = true;
+ // Block emulated event when emulated native stream is active.
+ if (native_stream_active_sequence_count_) {
+ gesture_provider_.OnTouchEventAck(event_consumed);
+ return;
+ }
+
+ bool is_sequence_start =
+ WebTouchEventTraits::IsTouchSequenceStart(touch_event_);
+ // Do not allow middle-sequence event to pass through, if start was blocked.
+ if (!emulated_stream_active_sequence_count_ && !is_sequence_start) {
+ gesture_provider_.OnTouchEventAck(event_consumed);
+ return;
+ }
+
+ if (is_sequence_start)
+ emulated_stream_active_sequence_count_++;
+ client_->ForwardEmulatedTouchEvent(touch_event_);
+}
+
+bool TouchEmulator::HandleTouchEventAck(
+ const blink::WebTouchEvent& event, InputEventAckState ack_result) {
+ bool is_sequence_end = WebTouchEventTraits::IsTouchSequenceEnd(event);
+ if (emulated_stream_active_sequence_count_) {
+ if (is_sequence_end)
+ emulated_stream_active_sequence_count_--;
+
+ const bool event_consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
+ gesture_provider_.OnTouchEventAck(event_consumed);
+ return true;
+ }
+
+ // We may have not seen native touch sequence start (when created in the
+ // middle of a sequence), so don't decrement sequence count below zero.
+ if (is_sequence_end && native_stream_active_sequence_count_)
+ native_stream_active_sequence_count_--;
+ return false;
}
void TouchEmulator::OnGestureEvent(const ui::GestureEventData& gesture) {
@@ -266,16 +319,16 @@ void TouchEmulator::OnGestureEvent(const ui::GestureEventData& gesture) {
}
void TouchEmulator::CancelTouch() {
- if (!touch_active_)
+ if (!emulated_stream_active_sequence_count_)
return;
WebTouchEventTraits::ResetTypeAndTouchStates(
WebInputEvent::TouchCancel,
(base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(),
&touch_event_);
- touch_active_ = false;
- if (gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_)))
- client_->ForwardTouchEvent(touch_event_);
+ if (gesture_provider_.GetCurrentDownEvent() &&
+ gesture_provider_.OnTouchEvent(MotionEventWeb(touch_event_)))
+ ForwardTouchEventToClient();
}
void TouchEmulator::UpdateCursor() {
@@ -351,14 +404,12 @@ bool TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
switch (mouse_event.type) {
case WebInputEvent::MouseDown:
eventType = WebInputEvent::TouchStart;
- touch_active_ = true;
break;
case WebInputEvent::MouseMove:
eventType = WebInputEvent::TouchMove;
break;
case WebInputEvent::MouseUp:
eventType = WebInputEvent::TouchEnd;
- touch_active_ = false;
break;
default:
eventType = WebInputEvent::Undefined;
@@ -371,7 +422,8 @@ bool TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
WebTouchPoint& point = touch_event_.touches[0];
point.id = 0;
- point.radiusX = point.radiusY = 1.f;
+ point.radiusX = 0.5f * cursor_size_.width();
+ point.radiusY = 0.5f * cursor_size_.height();
point.force = 1.f;
point.rotationAngle = 0.f;
point.position.x = mouse_event.x;
@@ -383,7 +435,7 @@ bool TouchEmulator::FillTouchEventAndPoint(const WebMouseEvent& mouse_event) {
}
bool TouchEmulator::InPinchGestureMode() const {
- return shift_pressed_ && allow_pinch_;
+ return shift_pressed_;
}
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator.h b/chromium/content/browser/renderer_host/input/touch_emulator.h
index af1e056db30..c364eb9fdca 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator.h
+++ b/chromium/content/browser/renderer_host/input/touch_emulator.h
@@ -10,6 +10,7 @@
#include "content/common/input/input_event_ack_state.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/events/gesture_detection/filtered_gesture_provider.h"
+#include "ui/gfx/size_f.h"
namespace content {
@@ -17,29 +18,38 @@ namespace content {
class CONTENT_EXPORT TouchEmulator : public ui::GestureProviderClient {
public:
explicit TouchEmulator(TouchEmulatorClient* client);
- virtual ~TouchEmulator();
+ ~TouchEmulator() override;
- void Enable(bool allow_pinch);
+ void Enable();
void Disable();
- // Returns |true| if the event was consumed.
+ // 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 enabled_; }
+
+ // Returns |true| if the event was consumed. Consumed event should not
+ // propagate any further.
// TODO(dgozman): maybe pass latency info together with events.
bool HandleMouseEvent(const blink::WebMouseEvent& event);
bool HandleMouseWheelEvent(const blink::WebMouseWheelEvent& event);
bool HandleKeyboardEvent(const blink::WebKeyboardEvent& event);
+ bool HandleTouchEvent(const blink::WebTouchEvent& event);
// Returns |true| if the event ack was consumed. Consumed ack should not
// propagate any further.
- bool HandleTouchEventAck(InputEventAckState ack_result);
+ bool HandleTouchEventAck(const blink::WebTouchEvent& event,
+ InputEventAckState ack_result);
// Cancel any touches, for example, when focus is lost.
void CancelTouch();
private:
// ui::GestureProviderClient implementation.
- virtual void OnGestureEvent(const ui::GestureEventData& gesture) OVERRIDE;
+ void OnGestureEvent(const ui::GestureEventData& gesture) override;
- void InitCursorFromResource(WebCursor* cursor, float scale, int resource_id);
+ // Returns cursor size in DIP.
+ gfx::SizeF InitCursorFromResource(
+ WebCursor* cursor, float scale, int resource_id);
void ResetState();
void UpdateCursor();
bool UpdateShiftPressed(bool shift_pressed);
@@ -56,19 +66,21 @@ class CONTENT_EXPORT TouchEmulator : public ui::GestureProviderClient {
void PinchEnd(const blink::WebGestureEvent& event);
void ScrollEnd(const blink::WebGestureEvent& event);
+ void ForwardTouchEventToClient();
+
TouchEmulatorClient* const client_;
ui::FilteredGestureProvider gesture_provider_;
// Disabled emulator does only process touch acks left from previous
// emulation. It does not intercept any events.
bool enabled_;
- bool allow_pinch_;
// While emulation is on, default cursor is touch. Pressing shift changes
// cursor to the pinch one.
WebCursor pointer_cursor_;
WebCursor touch_cursor_;
WebCursor pinch_cursor_;
+ gfx::SizeF cursor_size_;
// These are used to drop extra mouse move events coming too quickly, so
// we don't handle too much touches in gesture provider.
@@ -79,7 +91,8 @@ class CONTENT_EXPORT TouchEmulator : public ui::GestureProviderClient {
bool shift_pressed_;
blink::WebTouchEvent touch_event_;
- bool touch_active_;
+ int emulated_stream_active_sequence_count_;
+ int native_stream_active_sequence_count_;
// Whether we should suppress next fling cancel. This may happen when we
// did not send fling start in pinch mode.
diff --git a/chromium/content/browser/renderer_host/input/touch_emulator_client.h b/chromium/content/browser/renderer_host/input/touch_emulator_client.h
index 92f382f5f9c..7f807368dcb 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator_client.h
+++ b/chromium/content/browser/renderer_host/input/touch_emulator_client.h
@@ -17,8 +17,9 @@ class CONTENT_EXPORT TouchEmulatorClient {
virtual ~TouchEmulatorClient() {}
virtual void ForwardGestureEvent(const blink::WebGestureEvent& event) = 0;
- virtual void ForwardTouchEvent(const blink::WebTouchEvent& event) = 0;
+ virtual void ForwardEmulatedTouchEvent(const blink::WebTouchEvent& event) = 0;
virtual void SetCursor(const WebCursor& cursor) = 0;
+ virtual void ShowContextMenuAtPoint(const gfx::Point& point) = 0;
};
} // namespace content
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 8fdfd54cce2..80eb51ad28a 100644
--- a/chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_emulator_unittest.cc
@@ -12,7 +12,6 @@
#include "content/browser/renderer_host/input/touch_emulator_client.h"
#include "content/common/input/web_input_event_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/gesture_detection/gesture_config_helper.h"
#if defined(USE_AURA)
#include "ui/aura/env.h"
@@ -35,6 +34,7 @@ class TouchEmulatorTest : public testing::Test,
TouchEmulatorTest()
: shift_pressed_(false),
mouse_pressed_(false),
+ ack_touches_synchronously_(true),
last_mouse_x_(-1),
last_mouse_y_(-1) {
last_event_time_seconds_ =
@@ -42,10 +42,10 @@ class TouchEmulatorTest : public testing::Test,
event_time_delta_seconds_ = 0.1;
}
- virtual ~TouchEmulatorTest() {}
+ ~TouchEmulatorTest() override {}
// testing::Test
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
#if defined(USE_AURA)
aura::Env::CreateInstance(true);
screen_.reset(aura::TestScreen::Create(gfx::Size()));
@@ -53,10 +53,10 @@ class TouchEmulatorTest : public testing::Test,
#endif
emulator_.reset(new TouchEmulator(this));
- emulator_->Enable(true /* allow_pinch */);
+ emulator_->Enable();
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
emulator_->Disable();
EXPECT_EQ("", ExpectedEvents());
@@ -66,23 +66,26 @@ class TouchEmulatorTest : public testing::Test,
#endif
}
- virtual void ForwardGestureEvent(
- const blink::WebGestureEvent& event) OVERRIDE {
+ void ForwardGestureEvent(const blink::WebGestureEvent& event) override {
forwarded_events_.push_back(event.type);
}
- virtual void ForwardTouchEvent(
- const blink::WebTouchEvent& event) OVERRIDE {
+ void ForwardEmulatedTouchEvent(const blink::WebTouchEvent& event) override {
forwarded_events_.push_back(event.type);
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);
int expectedCancelable = event.type != WebInputEvent::TouchCancel;
EXPECT_EQ(expectedCancelable, event.cancelable);
- emulator()->HandleTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ if (ack_touches_synchronously_) {
+ emulator()->HandleTouchEventAck(
+ event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ }
}
- virtual void SetCursor(const WebCursor& cursor) OVERRIDE {}
+ void SetCursor(const WebCursor& cursor) override {}
+
+ void ShowContextMenuAtPoint(const gfx::Point& point) override {}
protected:
TouchEmulator* emulator() const {
@@ -181,6 +184,68 @@ class TouchEmulatorTest : public testing::Test,
mouse_pressed_ = false;
}
+ bool TouchStart(int x, int y, bool ack) {
+ return SendTouchEvent(
+ WebInputEvent::TouchStart, WebTouchPoint::StatePressed, x, y, ack);
+ }
+
+ bool TouchMove(int x, int y, bool ack) {
+ return SendTouchEvent(
+ WebInputEvent::TouchMove, WebTouchPoint::StateMoved, x, y, ack);
+ }
+
+ bool TouchEnd(int x, int y, bool ack) {
+ return SendTouchEvent(
+ WebInputEvent::TouchEnd, WebTouchPoint::StateReleased, x, y, ack);
+ }
+
+ WebTouchEvent MakeTouchEvent(WebInputEvent::Type type,
+ WebTouchPoint::State state, int x, int y) {
+ WebTouchEvent event;
+ event.type = type;
+ event.timeStampSeconds = GetNextEventTimeSeconds();
+ event.touchesLength = 1;
+ event.touches[0].id = 0;
+ event.touches[0].state = state;
+ event.touches[0].position.x = x;
+ event.touches[0].position.y = y;
+ event.touches[0].screenPosition.x = x;
+ event.touches[0].screenPosition.y = y;
+ return event;
+ }
+
+ bool SendTouchEvent(WebInputEvent::Type type, WebTouchPoint::State state,
+ int x, int y, bool ack) {
+ WebTouchEvent event = MakeTouchEvent(type, state, x, y);
+ if (emulator()->HandleTouchEvent(event)) {
+ // Touch event is not forwarded.
+ return false;
+ }
+
+ if (ack) {
+ // Can't send ack if there are some pending acks.
+ DCHECK(!touch_events_to_ack_.size());
+
+ // Touch event is forwarded, ack should not be handled by emulator.
+ EXPECT_FALSE(emulator()->HandleTouchEventAck(
+ event, INPUT_EVENT_ACK_STATE_CONSUMED));
+ } else {
+ touch_events_to_ack_.push_back(event);
+ }
+ return true;
+ }
+
+ void AckOldestTouchEvent() {
+ DCHECK(touch_events_to_ack_.size());
+ WebTouchEvent event = touch_events_to_ack_[0];
+ touch_events_to_ack_.erase(touch_events_to_ack_.begin());
+ // Emulator should not handle ack from native stream.
+ EXPECT_FALSE(emulator()->HandleTouchEventAck(
+ event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS));
+ }
+
+ void DisableSynchronousTouchAck() { ack_touches_synchronously_ = false; }
+
private:
scoped_ptr<TouchEmulator> emulator_;
std::vector<WebInputEvent::Type> forwarded_events_;
@@ -191,8 +256,10 @@ class TouchEmulatorTest : public testing::Test,
double event_time_delta_seconds_;
bool shift_pressed_;
bool mouse_pressed_;
+ bool ack_touches_synchronously_;
int last_mouse_x_;
int last_mouse_y_;
+ std::vector<WebTouchEvent> touch_events_to_ack_;
base::MessageLoopForUI message_loop_;
};
@@ -263,6 +330,30 @@ TEST_F(TouchEmulatorTest, Pinch) {
EXPECT_EQ("TouchEnd GestureScrollEnd", ExpectedEvents());
}
+TEST_F(TouchEmulatorTest, CancelWithDelayedAck) {
+ DisableSynchronousTouchAck();
+
+ // Simulate a sequence that is interrupted by |CancelTouch()|.
+ MouseDown(100, 200);
+ EXPECT_EQ("TouchStart", ExpectedEvents());
+ MouseDrag(200, 200);
+ EXPECT_EQ("TouchMove", ExpectedEvents());
+ emulator()->CancelTouch();
+ EXPECT_EQ("TouchCancel", ExpectedEvents());
+ // The mouse up should have no effect as the sequence was already cancelled.
+ MouseUp(400, 200);
+ EXPECT_EQ("", ExpectedEvents());
+
+ // Simulate a sequence that fully completes before |CancelTouch()|.
+ MouseDown(100, 200);
+ EXPECT_EQ("TouchStart", ExpectedEvents());
+ MouseUp(100, 200);
+ EXPECT_EQ("TouchEnd", ExpectedEvents());
+ // |CancelTouch| should have no effect as the sequence was already terminated.
+ emulator()->CancelTouch();
+ EXPECT_EQ("", ExpectedEvents());
+}
+
TEST_F(TouchEmulatorTest, DisableAndReenable) {
MouseDown(100, 200);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
@@ -282,7 +373,7 @@ TEST_F(TouchEmulatorTest, DisableAndReenable) {
MouseMove(300, 300);
EXPECT_EQ("", ExpectedEvents());
- emulator()->Enable(true /* allow_pinch */);
+ emulator()->Enable();
MouseDown(300, 300);
EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
MouseDrag(300, 400);
@@ -342,8 +433,90 @@ TEST_F(TouchEmulatorTest, MouseWheel) {
emulator()->Disable();
EXPECT_EQ("TouchCancel GestureTapCancel", ExpectedEvents());
EXPECT_TRUE(SendMouseWheelEvent());
- emulator()->Enable(true /* allow_pinch */);
+ emulator()->Enable();
EXPECT_TRUE(SendMouseWheelEvent());
}
+TEST_F(TouchEmulatorTest, MultipleTouchStreams) {
+ // Native stream should be blocked while emulated is active.
+ MouseMove(100, 200);
+ EXPECT_EQ("", ExpectedEvents());
+ MouseDown(100, 200);
+ EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
+ EXPECT_FALSE(TouchStart(10, 10, true));
+ EXPECT_FALSE(TouchMove(20, 20, true));
+ MouseUp(200, 200);
+ EXPECT_EQ(
+ "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
+ " TouchEnd GestureScrollEnd",
+ ExpectedEvents());
+ EXPECT_FALSE(TouchEnd(20, 20, true));
+
+ // Emulated stream should be blocked while native is active.
+ EXPECT_TRUE(TouchStart(10, 10, true));
+ EXPECT_TRUE(TouchMove(20, 20, true));
+ MouseDown(300, 200);
+ EXPECT_EQ("", ExpectedEvents());
+ // Re-enabling in the middle of a touch sequence should not affect this.
+ emulator()->Disable();
+ emulator()->Enable();
+ MouseDrag(300, 300);
+ EXPECT_EQ("", ExpectedEvents());
+ MouseUp(300, 300);
+ EXPECT_EQ("", ExpectedEvents());
+ EXPECT_TRUE(TouchEnd(20, 20, true));
+ EXPECT_EQ("", ExpectedEvents());
+
+ // Late ack for TouchEnd should not mess things up.
+ EXPECT_TRUE(TouchStart(10, 10, false));
+ EXPECT_TRUE(TouchMove(20, 20, false));
+ emulator()->Disable();
+ EXPECT_TRUE(TouchEnd(20, 20, false));
+ EXPECT_TRUE(TouchStart(30, 30, false));
+ AckOldestTouchEvent(); // TouchStart.
+ emulator()->Enable();
+ AckOldestTouchEvent(); // TouchMove.
+ AckOldestTouchEvent(); // TouchEnd.
+ MouseDown(300, 200);
+ EXPECT_EQ("", ExpectedEvents());
+ MouseDrag(300, 300);
+ EXPECT_EQ("", ExpectedEvents());
+ MouseUp(300, 300);
+ EXPECT_EQ("", ExpectedEvents());
+ AckOldestTouchEvent(); // TouchStart.
+ MouseDown(300, 200);
+ EXPECT_EQ("", ExpectedEvents());
+ EXPECT_TRUE(TouchMove(30, 40, true));
+ EXPECT_TRUE(TouchEnd(30, 40, true));
+ MouseUp(300, 200);
+ EXPECT_EQ("", ExpectedEvents());
+
+ // Emulation should be back to normal.
+ MouseDown(100, 200);
+ EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
+ MouseUp(200, 200);
+ EXPECT_EQ(
+ "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
+ " TouchEnd GestureScrollEnd",
+ ExpectedEvents());
+}
+
+TEST_F(TouchEmulatorTest, MultipleTouchStreamsLateEnable) {
+ // Enabling in the middle of native touch sequence should be handled.
+ // Send artificial late TouchEnd ack, like it is the first thing emulator
+ // does see.
+ WebTouchEvent event = MakeTouchEvent(
+ WebInputEvent::TouchEnd, WebTouchPoint::StateReleased, 10, 10);
+ EXPECT_FALSE(emulator()->HandleTouchEventAck(
+ event, INPUT_EVENT_ACK_STATE_CONSUMED));
+
+ MouseDown(100, 200);
+ EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
+ MouseUp(200, 200);
+ EXPECT_EQ(
+ "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
+ " TouchEnd GestureScrollEnd",
+ ExpectedEvents());
+}
+
} // namespace content
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 bbac01c3ebf..fa109dedddf 100644
--- a/chromium/content/browser/renderer_host/input/touch_event_queue.cc
+++ b/chromium/content/browser/renderer_host/input/touch_event_queue.cc
@@ -69,15 +69,28 @@ class TouchEventQueue::TouchTimeoutHandler {
timeout_delay_(timeout_delay),
pending_ack_state_(PENDING_ACK_NONE),
timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut,
- base::Unretained(this))) {
+ base::Unretained(this))),
+ enabled_(true),
+ enabled_for_current_sequence_(false) {
DCHECK(timeout_delay != base::TimeDelta());
}
~TouchTimeoutHandler() {}
- void Start(const TouchEventWithLatencyInfo& event) {
+ void StartIfNecessary(const TouchEventWithLatencyInfo& event) {
DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE);
- DCHECK(ShouldTouchTriggerTimeout(event.event));
+ if (!enabled_)
+ return;
+
+ if (!ShouldTouchTriggerTimeout(event.event))
+ return;
+
+ if (WebTouchEventTraits::IsTouchSequenceStart(event.event))
+ enabled_for_current_sequence_ = true;
+
+ if (!enabled_for_current_sequence_)
+ return;
+
timeout_event_ = event;
timeout_monitor_.Restart(timeout_delay_);
}
@@ -85,6 +98,8 @@ class TouchEventQueue::TouchTimeoutHandler {
bool ConfirmTouchEvent(InputEventAckState ack_result) {
switch (pending_ack_state_) {
case PENDING_ACK_NONE:
+ if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
+ enabled_for_current_sequence_ = false;
timeout_monitor_.Stop();
return false;
case PENDING_ACK_ORIGINAL_EVENT:
@@ -95,7 +110,8 @@ class TouchEventQueue::TouchTimeoutHandler {
touch_queue_->SendTouchEventImmediately(cancel_event);
} else {
SetPendingAckState(PENDING_ACK_NONE);
- touch_queue_->UpdateTouchAckStates(timeout_event_.event, ack_result);
+ touch_queue_->UpdateTouchConsumerStates(timeout_event_.event,
+ ack_result);
}
return true;
case PENDING_ACK_CANCEL_EVENT:
@@ -109,19 +125,29 @@ class TouchEventQueue::TouchTimeoutHandler {
return HasTimeoutEvent();
}
- bool IsTimeoutTimerRunning() const {
- return timeout_monitor_.IsRunning();
- }
+ void SetEnabled(bool enabled) {
+ if (enabled_ == enabled)
+ return;
- void Reset() {
- pending_ack_state_ = PENDING_ACK_NONE;
- timeout_monitor_.Stop();
- }
+ enabled_ = enabled;
- void set_timeout_delay(base::TimeDelta timeout_delay) {
- timeout_delay_ = timeout_delay;
+ if (enabled_)
+ return;
+
+ enabled_for_current_sequence_ = false;
+ // Only reset the |timeout_handler_| if the timer is running and has not
+ // yet timed out. This ensures that an already timed out sequence is
+ // properly flushed by the handler.
+ if (IsTimeoutTimerRunning()) {
+ pending_ack_state_ = PENDING_ACK_NONE;
+ timeout_monitor_.Stop();
+ }
}
+ bool IsTimeoutTimerRunning() const { return timeout_monitor_.IsRunning(); }
+
+ bool enabled() const { return enabled_; }
+
private:
enum PendingAckState {
PENDING_ACK_NONE,
@@ -184,6 +210,9 @@ class TouchEventQueue::TouchTimeoutHandler {
// Provides timeout-based callback behavior.
TimeoutMonitor timeout_monitor_;
+
+ bool enabled_;
+ bool enabled_for_current_sequence_;
};
// Provides touchmove slop suppression for a single touch that remains within
@@ -193,9 +222,14 @@ class TouchEventQueue::TouchTimeoutHandler {
class TouchEventQueue::TouchMoveSlopSuppressor {
public:
TouchMoveSlopSuppressor(double slop_suppression_length_dips)
- : slop_suppression_length_dips_squared_(slop_suppression_length_dips *
- slop_suppression_length_dips),
- suppressing_touchmoves_(false) {}
+ : slop_suppression_length_dips_squared_(0),
+ suppressing_touchmoves_(false) {
+ if (slop_suppression_length_dips) {
+ slop_suppression_length_dips += kSlopEpsilon;
+ slop_suppression_length_dips_squared_ =
+ slop_suppression_length_dips * slop_suppression_length_dips;
+ }
+ }
bool FilterEvent(const WebTouchEvent& event) {
if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
@@ -248,15 +282,9 @@ class TouchEventQueue::TouchMoveSlopSuppressor {
// the Client receives the event with their original timestamp.
class CoalescedWebTouchEvent {
public:
- // Events for which |async| is true will not be ack'ed to the client after the
- // corresponding ack is received following dispatch.
- CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, bool async)
- : coalesced_event_(event) {
- if (async)
- coalesced_event_.event.cancelable = false;
- else
- events_to_ack_.push_back(event);
-
+ CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event,
+ bool suppress_client_ack)
+ : coalesced_event_(event), suppress_client_ack_(suppress_client_ack) {
TRACE_EVENT_ASYNC_BEGIN0("input", "TouchEventQueue::QueueEvent", this);
}
@@ -268,42 +296,48 @@ class CoalescedWebTouchEvent {
// the event was coalesced.
bool CoalesceEventIfPossible(
const TouchEventWithLatencyInfo& event_with_latency) {
- if (!WillDispatchAckToClient())
+ if (suppress_client_ack_)
return false;
if (!coalesced_event_.CanCoalesceWith(event_with_latency))
return false;
+ // Addition of the first event to |uncoaleseced_events_to_ack_| is deferred
+ // until the first coalesced event, optimizing the (common) case where the
+ // event is not coalesced at all.
+ if (uncoaleseced_events_to_ack_.empty())
+ uncoaleseced_events_to_ack_.push_back(coalesced_event_);
+
TRACE_EVENT_INSTANT0(
"input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD);
coalesced_event_.CoalesceWith(event_with_latency);
- events_to_ack_.push_back(event_with_latency);
+ uncoaleseced_events_to_ack_.push_back(event_with_latency);
+ DCHECK_GE(uncoaleseced_events_to_ack_.size(), 2U);
return true;
}
- void UpdateLatencyInfoForAck(const ui::LatencyInfo& renderer_latency_info) {
- if (!WillDispatchAckToClient())
- return;
-
- for (WebTouchEventWithLatencyList::iterator iter = events_to_ack_.begin(),
- end = events_to_ack_.end();
- iter != end;
- ++iter) {
- iter->latency.AddNewLatencyFrom(renderer_latency_info);
- }
- }
-
void DispatchAckToClient(InputEventAckState ack_result,
+ const ui::LatencyInfo* optional_latency_info,
TouchEventQueueClient* client) {
DCHECK(client);
- if (!WillDispatchAckToClient())
+ if (suppress_client_ack_)
return;
- for (WebTouchEventWithLatencyList::const_iterator
- iter = events_to_ack_.begin(),
- end = events_to_ack_.end();
+ if (uncoaleseced_events_to_ack_.empty()) {
+ if (optional_latency_info)
+ coalesced_event_.latency.AddNewLatencyFrom(*optional_latency_info);
+ client->OnTouchEventAck(coalesced_event_, ack_result);
+ return;
+ }
+
+ DCHECK_GE(uncoaleseced_events_to_ack_.size(), 2U);
+ for (WebTouchEventWithLatencyList::iterator
+ iter = uncoaleseced_events_to_ack_.begin(),
+ end = uncoaleseced_events_to_ack_.end();
iter != end;
++iter) {
+ if (optional_latency_info)
+ iter->latency.AddNewLatencyFrom(*optional_latency_info);
client->OnTouchEventAck(*iter, ack_result);
}
}
@@ -313,22 +347,22 @@ class CoalescedWebTouchEvent {
}
private:
- bool WillDispatchAckToClient() const { return !events_to_ack_.empty(); }
-
// This is the event that is forwarded to the renderer.
TouchEventWithLatencyInfo coalesced_event_;
// This is the list of the original events that were coalesced, each requiring
// future ack dispatch to the client.
+ // Note that this will be empty if no coalescing has occurred.
typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList;
- WebTouchEventWithLatencyList events_to_ack_;
+ WebTouchEventWithLatencyList uncoaleseced_events_to_ack_;
+
+ bool suppress_client_ack_;
DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent);
};
TouchEventQueue::Config::Config()
: touchmove_slop_suppression_length_dips(0),
- touchmove_slop_suppression_region_includes_boundary(true),
touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT),
touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
touch_ack_timeout_supported(false) {
@@ -339,19 +373,16 @@ TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
: client_(client),
dispatching_touch_ack_(NULL),
dispatching_touch_(false),
- touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT),
- ack_timeout_enabled_(config.touch_ack_timeout_supported),
+ has_handlers_(true),
+ drop_remaining_touches_in_sequence_(false),
touchmove_slop_suppressor_(new TouchMoveSlopSuppressor(
- config.touchmove_slop_suppression_length_dips +
- (config.touchmove_slop_suppression_region_includes_boundary
- ? kSlopEpsilon
- : -kSlopEpsilon))),
+ config.touchmove_slop_suppression_length_dips)),
send_touch_events_async_(false),
needs_async_touchmove_for_outer_slop_region_(false),
last_sent_touch_timestamp_sec_(0),
touch_scrolling_mode_(config.touch_scrolling_mode) {
DCHECK(client);
- if (ack_timeout_enabled_) {
+ if (config.touch_ack_timeout_supported) {
timeout_handler_.reset(
new TouchTimeoutHandler(this, config.touch_ack_timeout_delay));
}
@@ -411,11 +442,6 @@ void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result,
if (touch_queue_.empty())
return;
- if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED &&
- touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT) {
- touch_filtering_state_ = FORWARD_ALL_TOUCHES;
- }
-
PopTouchEventToClient(ack_result, latency_info);
TryForwardNextEventToRenderer();
}
@@ -446,19 +472,8 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
DCHECK(!empty());
DCHECK(!dispatching_touch_);
- DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES);
TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event();
- if (WebTouchEventTraits::IsTouchSequenceStart(touch.event)) {
- touch_filtering_state_ =
- ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT
- : FORWARD_ALL_TOUCHES;
- touch_ack_states_.clear();
- send_touch_events_async_ = false;
- touch_sequence_start_position_ =
- gfx::PointF(touch.event.touches[0].position);
- }
-
if (send_touch_events_async_ &&
touch.event.type == WebInputEvent::TouchMove) {
// Throttling touchmove's in a continuous touchmove stream while scrolling
@@ -503,7 +518,8 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
if (pending_async_touchmove_->CanCoalesceWith(touch)) {
pending_async_touchmove_->CoalesceWith(touch);
pending_async_touchmove_->event.cancelable = !send_touch_events_async_;
- touch = *pending_async_touchmove_.Pass();
+ touch = *pending_async_touchmove_;
+ pending_async_touchmove_.reset();
} else {
scoped_ptr<TouchEventWithLatencyInfo> async_move =
pending_async_touchmove_.Pass();
@@ -524,47 +540,43 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
// the touch timeout should not be started.
base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
SendTouchEventImmediately(touch);
- if (dispatching_touch_ &&
- touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT &&
- ShouldTouchTriggerTimeout(touch.event)) {
- DCHECK(timeout_handler_);
- timeout_handler_->Start(touch);
- }
+ if (dispatching_touch_ && timeout_handler_)
+ timeout_handler_->StartIfNecessary(touch);
}
void TouchEventQueue::OnGestureScrollEvent(
const GestureEventWithLatencyInfo& gesture_event) {
- if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin)
- return;
-
- if (touch_filtering_state_ != DROP_ALL_TOUCHES &&
- touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) {
- DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves())
- << "The renderer should be offered a touchmove before scrolling begins";
- }
-
- if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) {
- if (touch_filtering_state_ != DROP_ALL_TOUCHES &&
- touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) {
+ if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) {
+ if (!touch_consumer_states_.is_empty() &&
+ !drop_remaining_touches_in_sequence_) {
+ DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves())
+ << "A touch handler should be offered a touchmove before scrolling.";
+ }
+ if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE &&
+ !drop_remaining_touches_in_sequence_ &&
+ touch_consumer_states_.is_empty()) {
// If no touch points have a consumer, prevent all subsequent touch events
// received during the scroll from reaching the renderer. This ensures
// that the first touchstart the renderer sees in any given sequence can
// always be preventDefault'ed (cancelable == true).
// TODO(jdduke): Revisit if touchstarts during scroll are made cancelable.
- if (touch_ack_states_.empty() ||
- AllTouchAckStatesHaveState(
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)) {
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
- return;
- }
+ drop_remaining_touches_in_sequence_ = true;
+ }
+
+ if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) {
+ needs_async_touchmove_for_outer_slop_region_ = true;
+ pending_async_touchmove_.reset();
}
- pending_async_touchmove_.reset();
- send_touch_events_async_ = true;
- needs_async_touchmove_for_outer_slop_region_ = true;
return;
}
+ if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate)
+ return;
+
+ if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
+ send_touch_events_async_ = true;
+
if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL)
return;
@@ -575,10 +587,10 @@ void TouchEventQueue::OnGestureScrollEvent(
if (!dispatching_touch_ack_)
return;
- if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE)
+ if (drop_remaining_touches_in_sequence_)
return;
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
+ drop_remaining_touches_in_sequence_ = true;
// Fake a TouchCancel to cancel the touch points of the touch event
// that is currently being acked.
@@ -614,27 +626,7 @@ void TouchEventQueue::OnGestureEventAck(
void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
DCHECK(!dispatching_touch_ack_);
DCHECK(!dispatching_touch_);
-
- if (has_handlers) {
- if (touch_filtering_state_ == DROP_ALL_TOUCHES) {
- // If no touch handler was previously registered, ensure that we don't
- // send a partial touch sequence to the renderer.
- DCHECK(touch_queue_.empty());
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
- }
- } else {
- // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch
- // state tracking and/or touch-action filtering (e.g., if the touch handler
- // was removed mid-sequence), crbug.com/375940.
- touch_filtering_state_ = DROP_ALL_TOUCHES;
- pending_async_touchmove_.reset();
- if (timeout_handler_)
- timeout_handler_->Reset();
- if (!touch_queue_.empty())
- ProcessTouchAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, LatencyInfo());
- // As there is no touch handler, ack'ing the event should flush the queue.
- DCHECK(touch_queue_.empty());
- }
+ has_handlers_ = has_handlers;
}
bool TouchEventQueue::IsPendingAckTouchStart() const {
@@ -648,25 +640,12 @@ bool TouchEventQueue::IsPendingAckTouchStart() const {
}
void TouchEventQueue::SetAckTimeoutEnabled(bool enabled) {
- // The timeout handler is valid only if explicitly supported in the config.
- if (!timeout_handler_)
- return;
-
- if (ack_timeout_enabled_ == enabled)
- return;
-
- ack_timeout_enabled_ = enabled;
-
- if (enabled)
- return;
+ if (timeout_handler_)
+ timeout_handler_->SetEnabled(enabled);
+}
- if (touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT)
- touch_filtering_state_ = FORWARD_ALL_TOUCHES;
- // Only reset the |timeout_handler_| if the timer is running and has not yet
- // timed out. This ensures that an already timed out sequence is properly
- // flushed by the handler.
- if (timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning())
- timeout_handler_->Reset();
+bool TouchEventQueue::IsAckTimeoutEnabled() const {
+ return timeout_handler_ && timeout_handler_->enabled();
}
bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const {
@@ -686,36 +665,34 @@ void TouchEventQueue::FlushQueue() {
DCHECK(!dispatching_touch_ack_);
DCHECK(!dispatching_touch_);
pending_async_touchmove_.reset();
- if (touch_filtering_state_ != DROP_ALL_TOUCHES)
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
+ drop_remaining_touches_in_sequence_ = true;
while (!touch_queue_.empty())
PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
}
void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) {
- AckTouchEventToClient(ack_result, PopTouchEvent());
+ AckTouchEventToClient(ack_result, PopTouchEvent(), NULL);
}
void TouchEventQueue::PopTouchEventToClient(
InputEventAckState ack_result,
const LatencyInfo& renderer_latency_info) {
- scoped_ptr<CoalescedWebTouchEvent> acked_event = PopTouchEvent();
- acked_event->UpdateLatencyInfoForAck(renderer_latency_info);
- AckTouchEventToClient(ack_result, acked_event.Pass());
+ AckTouchEventToClient(ack_result, PopTouchEvent(), &renderer_latency_info);
}
void TouchEventQueue::AckTouchEventToClient(
InputEventAckState ack_result,
- scoped_ptr<CoalescedWebTouchEvent> acked_event) {
+ scoped_ptr<CoalescedWebTouchEvent> acked_event,
+ const ui::LatencyInfo* optional_latency_info) {
DCHECK(acked_event);
DCHECK(!dispatching_touch_ack_);
- UpdateTouchAckStates(acked_event->coalesced_event().event, ack_result);
+ UpdateTouchConsumerStates(acked_event->coalesced_event().event, ack_result);
// Note that acking the touch-event may result in multiple gestures being sent
// to the renderer, or touch-events being queued.
base::AutoReset<const CoalescedWebTouchEvent*> dispatching_touch_ack(
&dispatching_touch_ack_, acked_event.get());
- acked_event->DispatchAckToClient(ack_result, client_);
+ acked_event->DispatchAckToClient(ack_result, optional_latency_info, client_);
}
scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() {
@@ -748,19 +725,25 @@ TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
if (touchmove_slop_suppressor_->FilterEvent(event))
return ACK_WITH_NOT_CONSUMED;
- if (touch_filtering_state_ == DROP_ALL_TOUCHES)
- return ACK_WITH_NO_CONSUMER_EXISTS;
+ if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
+ touch_consumer_states_.clear();
+ send_touch_events_async_ = false;
+ pending_async_touchmove_.reset();
+ touch_sequence_start_position_ = gfx::PointF(event.touches[0].position);
+ drop_remaining_touches_in_sequence_ = false;
+ if (!has_handlers_) {
+ drop_remaining_touches_in_sequence_ = true;
+ return ACK_WITH_NO_CONSUMER_EXISTS;
+ }
+ }
- if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE &&
+ if (drop_remaining_touches_in_sequence_ &&
event.type != WebInputEvent::TouchCancel) {
- if (WebTouchEventTraits::IsTouchSequenceStart(event))
- return FORWARD_TO_RENDERER;
return ACK_WITH_NO_CONSUMER_EXISTS;
}
- // Touch press events should always be forwarded to the renderer.
if (event.type == WebInputEvent::TouchStart)
- return FORWARD_TO_RENDERER;
+ return has_handlers_ ? FORWARD_TO_RENDERER : ACK_WITH_NO_CONSUMER_EXISTS;
for (unsigned int i = 0; i < event.touchesLength; ++i) {
const WebTouchPoint& point = event.touches[i];
@@ -768,22 +751,15 @@ TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
if (point.state == WebTouchPoint::StateStationary)
continue;
- if (touch_ack_states_.count(point.id) > 0) {
- if (touch_ack_states_.find(point.id)->second !=
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
- return FORWARD_TO_RENDERER;
- } else {
- // If the ACK status of a point is unknown, then the event should be
- // forwarded to the renderer.
+ if (touch_consumer_states_.has_bit(point.id))
return FORWARD_TO_RENDERER;
- }
}
return ACK_WITH_NO_CONSUMER_EXISTS;
}
-void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event,
- InputEventAckState ack_result) {
+void TouchEventQueue::UpdateTouchConsumerStates(const WebTouchEvent& event,
+ InputEventAckState ack_result) {
// Update the ACK status for each touch point in the ACKed event.
if (event.type == WebInputEvent::TouchEnd ||
event.type == WebInputEvent::TouchCancel) {
@@ -792,31 +768,19 @@ void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event,
const WebTouchPoint& point = event.touches[i];
if (point.state == WebTouchPoint::StateReleased ||
point.state == WebTouchPoint::StateCancelled)
- touch_ack_states_.erase(point.id);
+ touch_consumer_states_.clear_bit(point.id);
}
} else if (event.type == WebInputEvent::TouchStart) {
for (unsigned i = 0; i < event.touchesLength; ++i) {
const WebTouchPoint& point = event.touches[i];
- if (point.state == WebTouchPoint::StatePressed)
- touch_ack_states_[point.id] = ack_result;
+ if (point.state == WebTouchPoint::StatePressed) {
+ if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
+ touch_consumer_states_.mark_bit(point.id);
+ else
+ touch_consumer_states_.clear_bit(point.id);
+ }
}
}
}
-bool TouchEventQueue::AllTouchAckStatesHaveState(
- InputEventAckState ack_state) const {
- if (touch_ack_states_.empty())
- return false;
-
- for (TouchPointAckStates::const_iterator iter = touch_ack_states_.begin(),
- end = touch_ack_states_.end();
- iter != end;
- ++iter) {
- if (iter->second != ack_state)
- return false;
- }
-
- return true;
-}
-
} // namespace content
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 ecb8fe83b40..3bdab903750 100644
--- a/chromium/content/browser/renderer_host/input/touch_event_queue.h
+++ b/chromium/content/browser/renderer_host/input/touch_event_queue.h
@@ -14,6 +14,7 @@
#include "content/common/content_export.h"
#include "content/common/input/input_event_ack_state.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/events/gesture_detection/bitset_32.h"
#include "ui/gfx/geometry/point_f.h"
namespace content {
@@ -62,11 +63,6 @@ class CONTENT_EXPORT TouchEventQueue {
// Defaults to 0 (disabled).
double touchmove_slop_suppression_length_dips;
- // Whether the touchmove slop suppression region is boundary inclusive.
- // Defaults to true.
- // TODO(jdduke): Remove when unified GR enabled, crbug.com/332418.
- bool touchmove_slop_suppression_region_includes_boundary;
-
// Determines the type of touch scrolling.
// Defaults to TouchEventQueue:::TOUCH_SCROLLING_MODE_DEFAULT.
TouchEventQueue::TouchScrollingMode touch_scrolling_mode;
@@ -119,6 +115,10 @@ class CONTENT_EXPORT TouchEventQueue {
// it will take effect only for the following touch sequence.
void SetAckTimeoutEnabled(bool enabled);
+ bool IsAckTimeoutEnabled() const;
+
+ bool IsForwardingTouches();
+
bool empty() const WARN_UNUSED_RESULT {
return touch_queue_.empty();
}
@@ -127,13 +127,7 @@ class CONTENT_EXPORT TouchEventQueue {
return touch_queue_.size();
}
- bool ack_timeout_enabled() const {
- return ack_timeout_enabled_;
- }
-
- bool has_handlers() const {
- return touch_filtering_state_ != DROP_ALL_TOUCHES;
- }
+ bool has_handlers() const { return has_handlers_; }
private:
class TouchTimeoutHandler;
@@ -165,9 +159,11 @@ class CONTENT_EXPORT TouchEventQueue {
void PopTouchEventToClient(InputEventAckState ack_result,
const ui::LatencyInfo& renderer_latency_info);
- // Ack all coalesced events in |acked_event| to the client with |ack_result|.
+ // Ack all coalesced events in |acked_event| to the client with |ack_result|,
+ // updating the acked events with |optional_latency_info| if it exists.
void AckTouchEventToClient(InputEventAckState ack_result,
- scoped_ptr<CoalescedWebTouchEvent> acked_event);
+ scoped_ptr<CoalescedWebTouchEvent> acked_event,
+ const ui::LatencyInfo* optional_latency_info);
// Safely pop the head of the queue.
scoped_ptr<CoalescedWebTouchEvent> PopTouchEvent();
@@ -184,10 +180,8 @@ class CONTENT_EXPORT TouchEventQueue {
// has no touch handler.
PreFilterResult FilterBeforeForwarding(const blink::WebTouchEvent& event);
void ForwardToRenderer(const TouchEventWithLatencyInfo& event);
- void UpdateTouchAckStates(const blink::WebTouchEvent& event,
- InputEventAckState ack_result);
- bool AllTouchAckStatesHaveState(InputEventAckState ack_state) const;
-
+ void UpdateTouchConsumerStates(const blink::WebTouchEvent& event,
+ InputEventAckState ack_result);
// Handles touch event forwarding and ack'ed event dispatch.
TouchEventQueueClient* client_;
@@ -195,9 +189,11 @@ class CONTENT_EXPORT TouchEventQueue {
typedef std::deque<CoalescedWebTouchEvent*> TouchQueue;
TouchQueue touch_queue_;
- // Maintain the ACK status for each touch point.
- typedef std::map<int, InputEventAckState> TouchPointAckStates;
- TouchPointAckStates touch_ack_states_;
+ // Maps whether each active pointer has a consumer (i.e., a touch point has a
+ // valid consumer iff |touch_consumer_states[pointer.id]| is true.).
+ // TODO(jdduke): Consider simply tracking whether *any* touchstart had a
+ // consumer, crbug.com/416497.
+ ui::BitSet32 touch_consumer_states_;
// Position of the first touch in the most recent sequence forwarded to the
// client.
@@ -212,18 +208,18 @@ class CONTENT_EXPORT TouchEventQueue {
// ack after forwarding a touch event to the client.
bool dispatching_touch_;
- enum TouchFilteringState {
- FORWARD_ALL_TOUCHES, // Don't filter at all - the default.
- FORWARD_TOUCHES_UNTIL_TIMEOUT, // Don't filter unless we get an ACK timeout.
- DROP_TOUCHES_IN_SEQUENCE, // Filter all events until a new touch
- // sequence is received.
- DROP_ALL_TOUCHES, // Filter all events, e.g., no touch handler.
- TOUCH_FILTERING_STATE_DEFAULT = FORWARD_ALL_TOUCHES,
- };
- TouchFilteringState touch_filtering_state_;
+ // Whether the renderer has at least one touch handler.
+ bool has_handlers_;
+
+ // Whether to allow any remaining touches for the current sequence. Note that
+ // this is a stricter condition than an empty |touch_consumer_states_|, as it
+ // also prevents forwarding of touchstart events for new pointers in the
+ // current sequence. This is only used when the event is synthetically
+ // cancelled after a touch timeout, or after a scroll event when the
+ // mode is TOUCH_SCROLLING_MODE_TOUCHCANCEL.
+ bool drop_remaining_touches_in_sequence_;
// Optional handler for timed-out touch event acks.
- bool ack_timeout_enabled_;
scoped_ptr<TouchTimeoutHandler> timeout_handler_;
// Suppression of TouchMove's within a slop region when a sequence has not yet
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 06a3a9f40f3..fcd5ce8d07b 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
@@ -35,30 +35,28 @@ class TouchEventQueueTest : public testing::Test,
acked_event_count_(0),
last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN),
slop_length_dips_(0),
- slop_includes_boundary_(true),
touch_scrolling_mode_(TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT) {}
- virtual ~TouchEventQueueTest() {}
+ ~TouchEventQueueTest() override {}
// testing::Test
- virtual void SetUp() OVERRIDE { ResetQueueWithConfig(CreateConfig()); }
+ void SetUp() override { ResetQueueWithConfig(CreateConfig()); }
- virtual void TearDown() OVERRIDE {
- queue_.reset();
- }
+ void TearDown() override { queue_.reset(); }
// TouchEventQueueClient
- virtual void SendTouchEventImmediately(
- const TouchEventWithLatencyInfo& event) OVERRIDE {
+ void SendTouchEventImmediately(
+ const TouchEventWithLatencyInfo& event) override {
++sent_event_count_;
last_sent_event_ = event.event;
- if (sync_ack_result_)
- SendTouchEventAck(*sync_ack_result_.Pass());
+ if (sync_ack_result_) {
+ auto sync_ack_result = sync_ack_result_.Pass();
+ SendTouchEventAck(*sync_ack_result);
+ }
}
- virtual void OnTouchEventAck(
- const TouchEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE {
+ void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override {
++acked_event_count_;
last_acked_event_ = event.event;
last_acked_event_state_ = ack_result;
@@ -81,8 +79,6 @@ class TouchEventQueueTest : public testing::Test,
TouchEventQueue::Config config;
config.touch_scrolling_mode = touch_scrolling_mode_;
config.touchmove_slop_suppression_length_dips = slop_length_dips_;
- config.touchmove_slop_suppression_region_includes_boundary =
- slop_includes_boundary_;
return config;
}
@@ -91,10 +87,8 @@ class TouchEventQueueTest : public testing::Test,
ResetQueueWithConfig(CreateConfig());
}
- void SetUpForTouchMoveSlopTesting(double slop_length_dips,
- bool slop_includes_boundary) {
+ void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
slop_length_dips_ = slop_length_dips;
- slop_includes_boundary_ = slop_includes_boundary;
ResetQueueWithConfig(CreateConfig());
}
@@ -175,6 +169,10 @@ class TouchEventQueueTest : public testing::Test,
touch_event_.timeStampSeconds += seconds;
}
+ void ResetTouchEvent() {
+ touch_event_ = SyntheticWebTouchEvent();
+ }
+
size_t GetAndResetAckedEventCount() {
size_t count = acked_event_count_;
acked_event_count_ = 0;
@@ -197,8 +195,6 @@ class TouchEventQueueTest : public testing::Test,
void SetAckTimeoutDisabled() { queue_->SetAckTimeoutEnabled(false); }
- bool IsTimeoutEnabled() const { return queue_->ack_timeout_enabled(); }
-
bool IsTimeoutRunning() const { return queue_->IsTimeoutRunningForTesting(); }
bool HasPendingAsyncTouchMove() const {
@@ -253,7 +249,6 @@ class TouchEventQueueTest : public testing::Test,
scoped_ptr<WebGestureEvent> followup_gesture_event_;
scoped_ptr<InputEventAckState> sync_ack_result_;
double slop_length_dips_;
- bool slop_includes_boundary_;
TouchEventQueue::TouchScrollingMode touch_scrolling_mode_;
base::MessageLoopForUI message_loop_;
};
@@ -287,9 +282,55 @@ TEST_F(TouchEventQueueTest, Basic) {
EXPECT_TRUE(acked_event().cancelable);
}
-// Tests that the touch-queue is emptied if a page stops listening for touch
-// events.
-TEST_F(TouchEventQueueTest, QueueFlushedWhenHandlersRemoved) {
+// Tests that touch-events with multiple points are queued properly.
+TEST_F(TouchEventQueueTest, BasicMultiTouch) {
+ const size_t kPointerCount = 10;
+ for (float i = 0; i < kPointerCount; ++i)
+ PressTouchPoint(i, i);
+
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(kPointerCount, queued_event_count());
+
+ for (int i = 0; i < static_cast<int>(kPointerCount); ++i)
+ MoveTouchPoint(i, 1.f + i, 2.f + i);
+
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ // All moves should coalesce.
+ EXPECT_EQ(kPointerCount + 1, queued_event_count());
+
+ for (int i = 0; i < static_cast<int>(kPointerCount); ++i)
+ ReleaseTouchPoint(kPointerCount - 1 - i);
+
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(kPointerCount * 2 + 1, queued_event_count());
+
+ // Ack all presses.
+ for (size_t i = 0; i < kPointerCount; ++i)
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ EXPECT_EQ(kPointerCount, GetAndResetAckedEventCount());
+ EXPECT_EQ(kPointerCount, GetAndResetSentEventCount());
+
+ // Ack the coalesced move.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(kPointerCount, GetAndResetAckedEventCount());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Ack all releases.
+ for (size_t i = 0; i < kPointerCount; ++i)
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ EXPECT_EQ(kPointerCount, GetAndResetAckedEventCount());
+ EXPECT_EQ(kPointerCount - 1, GetAndResetSentEventCount());
+}
+
+// Tests that the touch-queue continues delivering events for an active pointer
+// after all handlers are removed, but acks new pointers immediately as having
+// no consumer.
+TEST_F(TouchEventQueueTest, NoNewTouchesForwardedAfterHandlersRemoved) {
OnHasTouchEventHandlers(true);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
@@ -297,32 +338,51 @@ TEST_F(TouchEventQueueTest, QueueFlushedWhenHandlersRemoved) {
// Send a touch-press event.
PressTouchPoint(1, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
- ReleaseTouchPoint(0);
-
- // Events will be queued until the first sent event is ack'ed.
- for (int i = 5; i < 15; ++i) {
- PressTouchPoint(1, 1);
- MoveTouchPoint(0, i, i);
- ReleaseTouchPoint(0);
- }
- EXPECT_EQ(32U, queued_event_count());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
+ // Signal that all touch handlers have been removed.
+ OnHasTouchEventHandlers(false);
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(1U, queued_event_count());
- // Receive an ACK for the first touch-event. One of the queued touch-event
- // should be forwarded.
+ // Process the ack for the sent touch, ensuring that it is honored (despite
+ // the touch handler having been removed).
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_EQ(31U, queued_event_count());
- EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state());
- // Flush the queue. The touch-event queue should now be emptied, but none of
- // the queued touch-events should be sent to the renderer.
- OnHasTouchEventHandlers(false);
+ // Try forwarding a new pointer. It should be rejected immediately.
+ PressTouchPoint(2, 2);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
+
+ // Further events for the pointer without a handler should not be forwarded.
+ MoveTouchPoint(1, 3, 3);
+ ReleaseTouchPoint(1);
+ EXPECT_EQ(2U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
+
+ // Events for the first pointer, that had a handler, should be forwarded, even
+ // if the renderer reports that no handlers exist.
+ MoveTouchPoint(0, 4, 4);
+ ReleaseTouchPoint(0);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(2U, queued_event_count());
+
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state());
+
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(31U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state());
}
// Tests that addition of a touch handler during a touch sequence will not cause
@@ -366,14 +426,23 @@ TEST_F(TouchEventQueueTest, ActiveSequenceDroppedWhenHandlersRemoved) {
EXPECT_EQ(0U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, GetAndResetSentEventCount());
- // Touch handle deregistration should flush the queue.
+ // Unregister all touch handlers.
OnHasTouchEventHandlers(false);
- EXPECT_EQ(2U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, queued_event_count());
- // The ack should be ignored as the touch queue is now empty.
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ // Repeated registration/unregstration of handlers should have no effect as
+ // we're still awaiting the ack arrival.
+ OnHasTouchEventHandlers(true);
EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, queued_event_count());
+ OnHasTouchEventHandlers(false);
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, queued_event_count());
+
+ // The ack should be flush the queue.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ EXPECT_EQ(2U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, queued_event_count());
// Events should be dropped while there is no touch handler.
@@ -397,6 +466,34 @@ TEST_F(TouchEventQueueTest, ActiveSequenceDroppedWhenHandlersRemoved) {
EXPECT_EQ(1U, GetAndResetSentEventCount());
}
+// Tests that removal/addition of a touch handler without any intervening
+// touch activity has no affect on touch forwarding.
+TEST_F(TouchEventQueueTest,
+ ActiveSequenceUnaffectedByRepeatedHandlerRemovalAndAddition) {
+ // Send a touch-press event.
+ PressTouchPoint(1, 1);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
+
+ // Simulate the case where the touchstart handler removes itself, and adds a
+ // touchmove handler.
+ OnHasTouchEventHandlers(false);
+ OnHasTouchEventHandlers(true);
+
+ // Queue a touch-move event.
+ MoveTouchPoint(0, 5, 5);
+ EXPECT_EQ(2U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+
+ // The ack should trigger forwarding of the touchmove, as if no touch
+ // handler registration changes have occurred.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, queued_event_count());
+}
+
// Tests that touch-events are coalesced properly in the queue.
TEST_F(TouchEventQueueTest, Coalesce) {
// Send a touch-press event.
@@ -405,7 +502,7 @@ TEST_F(TouchEventQueueTest, Coalesce) {
// Send a few touch-move events, followed by a touch-release event. All the
// touch-move events should be coalesced into a single event.
- for (int i = 5; i < 15; ++i)
+ for (float i = 5; i < 15; ++i)
MoveTouchPoint(0, i, i);
EXPECT_EQ(0U, GetAndResetSentEventCount());
@@ -445,7 +542,7 @@ TEST_F(TouchEventQueueTest, SentTouchEventDoesNotCoalesce) {
// Send a few touch-move events, followed by a touch-release event. All the
// touch-move events should be coalesced into a single event.
- for (int i = 5; i < 15; ++i)
+ for (float i = 5; i < 15; ++i)
MoveTouchPoint(0, i, i);
EXPECT_EQ(0U, GetAndResetSentEventCount());
@@ -498,33 +595,23 @@ TEST_F(TouchEventQueueTest, MultiTouch) {
EXPECT_EQ(WebTouchPoint::StateMoved, event.touches[1].state);
}
-// Tests that if a touch-event queue is destroyed in response to a touch-event
-// in the renderer, then there is no crash when the ACK for that touch-event
-// comes back.
-TEST_F(TouchEventQueueTest, AckAfterQueueFlushed) {
- // Send some touch-events to the renderer.
+// Tests that the touch-event queue is robust to redundant acks.
+TEST_F(TouchEventQueueTest, SpuriousAcksIgnored) {
+ // Trigger a spurious ack.
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
+
+ // Send and ack a touch press.
PressTouchPoint(1, 1);
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, queued_event_count());
-
- MoveTouchPoint(0, 10, 10);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(2U, queued_event_count());
-
- // Receive an ACK for the press. This should cause the queued touch-move to
- // be sent to the renderer.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, queued_event_count());
-
- OnHasTouchEventHandlers(false);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, queued_event_count());
- // Now receive an ACK for the move.
+ // Trigger a spurious ack.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetAckedEventCount());
}
// Tests that touch-move events are not sent to the renderer if the preceding
@@ -717,10 +804,10 @@ TEST_F(TouchEventQueueTest, AckWithFollowupEvents) {
// Create a touch event that will be queued synchronously by a touch ack.
// Note, this will be triggered by all subsequent touch acks.
WebTouchEvent followup_event;
- followup_event.type = WebInputEvent::TouchStart;
+ followup_event.type = WebInputEvent::TouchMove;
followup_event.touchesLength = 1;
- followup_event.touches[0].id = 1;
- followup_event.touches[0].state = WebTouchPoint::StatePressed;
+ followup_event.touches[0].id = 0;
+ followup_event.touches[0].state = WebTouchPoint::StateMoved;
SetFollowupEvent(followup_event);
// Receive an ACK for the press. This should cause the followup touch-move to
@@ -859,13 +946,16 @@ TEST_F(TouchEventQueueTest, TouchCancelOnScroll) {
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
+ MoveTouchPoint(0, 30, 15);
+ EXPECT_EQ(2U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+
// Queue another TouchStart.
PressTouchPoint(20, 20);
- EXPECT_EQ(2U, queued_event_count());
+ EXPECT_EQ(3U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(WebInputEvent::TouchStart, latest_event().type);
- // GestureScrollBegin inserts a synthetic TouchCancel before the TouchStart.
WebGestureEvent followup_scroll;
followup_scroll.type = WebInputEvent::GestureScrollBegin;
SetFollowupEvent(followup_scroll);
@@ -873,6 +963,16 @@ TEST_F(TouchEventQueueTest, TouchCancelOnScroll) {
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(2U, queued_event_count());
+ EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
+
+ // GestureScrollUpdate inserts a synthetic TouchCancel before the TouchStart.
+ followup_scroll.type = WebInputEvent::GestureScrollUpdate;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(2U, queued_event_count());
EXPECT_EQ(WebInputEvent::TouchCancel, sent_event().type);
EXPECT_FALSE(sent_event().cancelable);
EXPECT_EQ(WebInputEvent::TouchStart, latest_event().type);
@@ -1146,14 +1246,12 @@ TEST_F(TouchEventQueueTest, NoTouchTimeoutIfDisabledAfterTouchStart) {
// Send the ack immediately. The timeout should not have fired.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_FALSE(IsTimeoutRunning());
- EXPECT_TRUE(IsTimeoutEnabled());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
// Now explicitly disable the timeout.
SetAckTimeoutDisabled();
EXPECT_FALSE(IsTimeoutRunning());
- EXPECT_FALSE(IsTimeoutEnabled());
// A TouchMove should not start or trigger the timeout.
MoveTouchPoint(0, 5, 5);
@@ -1174,19 +1272,6 @@ TEST_F(TouchEventQueueTest, NoTouchTimeoutIfAckIsSynchronous) {
EXPECT_FALSE(IsTimeoutRunning());
}
-// Tests that the timeout is disabled if the touch handler disappears.
-TEST_F(TouchEventQueueTest, NoTouchTimeoutIfTouchHandlerRemoved) {
- SetUpForTimeoutTesting(DefaultTouchTimeoutDelay());
-
- // Queue a TouchStart.
- PressTouchPoint(0, 1);
- ASSERT_TRUE(IsTimeoutRunning());
-
- // Unload the touch handler.
- OnHasTouchEventHandlers(false);
- EXPECT_FALSE(IsTimeoutRunning());
-}
-
// Tests that the timeout does not fire if explicitly disabled while an event
// is in-flight.
TEST_F(TouchEventQueueTest, NoTouchTimeoutIfDisabledWhileTimerIsActive) {
@@ -1356,10 +1441,9 @@ TEST_F(TouchEventQueueTest, NoCancelOnTouchTimeoutWithoutConsumer) {
// Tests that TouchMove's are dropped if within the boundary-inclusive slop
// suppression region for an unconsumed TouchStart.
TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) {
- const double kSlopLengthDips = 10.;
- const double kHalfSlopLengthDips = kSlopLengthDips / 2;
- const bool slop_includes_boundary = true;
- SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
+ const float kSlopLengthDips = 10;
+ const float kHalfSlopLengthDips = kSlopLengthDips / 2;
+ SetUpForTouchMoveSlopTesting(kSlopLengthDips);
// Queue a TouchStart.
PressTouchPoint(0, 0);
@@ -1400,10 +1484,10 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) {
// As soon as a TouchMove exceeds the (Euclidean) distance, no more
// TouchMove's should be suppressed.
- const double kFortyFiveDegreeSlopLengthXY =
- kSlopLengthDips * std::sqrt(2.) / 2.;
- MoveTouchPoint(0, kFortyFiveDegreeSlopLengthXY + .2,
- kFortyFiveDegreeSlopLengthXY + .2);
+ const float kFortyFiveDegreeSlopLengthXY =
+ kSlopLengthDips * std::sqrt(2.f) / 2;
+ MoveTouchPoint(0, kFortyFiveDegreeSlopLengthXY + .2f,
+ kFortyFiveDegreeSlopLengthXY + .2f);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
@@ -1428,7 +1512,7 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) {
ASSERT_EQ(0U, queued_event_count());
// The slop region is boundary-inclusive.
- MoveTouchPoint(0, kSlopLengthDips - 1., 0);
+ MoveTouchPoint(0, kSlopLengthDips - 1, 0);
EXPECT_EQ(0U, queued_event_count());
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
@@ -1439,67 +1523,38 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionIncludingSlopBoundary) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
-// Tests that TouchMove's are dropped if within the boundary-exclusive slop
-// suppression region for an unconsumed TouchStart.
-TEST_F(TouchEventQueueTest, TouchMoveSuppressionExcludingSlopBoundary) {
- const double kSlopLengthDips = 10.;
- const double kHalfSlopLengthDips = kSlopLengthDips / 2;
- const bool slop_includes_boundary = false;
- SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
+// Tests that TouchMove's are not dropped within the slop suppression region if
+// the touchstart was consumed.
+TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
+ const float kSlopLengthDips = 10;
+ const float kHalfSlopLengthDips = kSlopLengthDips / 2;
+ SetUpForTouchMoveSlopTesting(kSlopLengthDips);
// Queue a TouchStart.
PressTouchPoint(0, 0);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
ASSERT_EQ(1U, GetAndResetSentEventCount());
ASSERT_EQ(1U, GetAndResetAckedEventCount());
- // TouchMove's within the region should be suppressed.
+ // TouchMove's within the region should not be suppressed, as a touch was
+ // consumed.
MoveTouchPoint(0, 0, kHalfSlopLengthDips);
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
-
- MoveTouchPoint(0, kSlopLengthDips - 0.2f, 0);
- EXPECT_EQ(0U, queued_event_count());
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, acked_event_state());
-
- // As soon as a TouchMove reaches the (Euclidean) slop distance, no more
- // TouchMove's should be suppressed.
- MoveTouchPoint(0, kSlopLengthDips, 0);
- EXPECT_EQ(1U, queued_event_count());
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- EXPECT_EQ(0U, GetAndResetAckedEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
- MoveTouchPoint(0, kHalfSlopLengthDips, 0);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
}
-// Tests that TouchMove's are not dropped within the slop suppression region if
-// the touchstart was consumed.
-TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
- const double kSlopLengthDips = 10.;
- const double kHalfSlopLengthDips = kSlopLengthDips / 2;
- const bool slop_includes_boundary = true;
- SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
-
+// Tests that even very small TouchMove's are not suppressed when suppression is
+// disabled.
+TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionIfDisabled) {
// Queue a TouchStart.
PressTouchPoint(0, 0);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
ASSERT_EQ(1U, GetAndResetSentEventCount());
ASSERT_EQ(1U, GetAndResetAckedEventCount());
- // TouchMove's within the region should not be suppressed, as a touch was
- // consumed.
- MoveTouchPoint(0, 0, kHalfSlopLengthDips);
+ // Small TouchMove's should not be suppressed.
+ MoveTouchPoint(0, 0.001f, 0.001f);
EXPECT_EQ(1U, queued_event_count());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(0U, GetAndResetAckedEventCount());
@@ -1510,9 +1565,7 @@ TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterTouchConsumed) {
TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) {
const float kSlopLengthPixels = 7.f;
const float kDPIScale = 3.f;
- const bool slop_includes_boundary = true;
- SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale,
- slop_includes_boundary);
+ SetUpForTouchMoveSlopTesting(kSlopLengthPixels / kDPIScale);
// Queue a TouchStart.
PressTouchPoint(0, 0);
@@ -1550,10 +1603,9 @@ TEST_F(TouchEventQueueTest, TouchMoveSuppressionWithDIPScaling) {
// Tests that TouchMove's are not dropped if a secondary pointer is present
// during any movement.
TEST_F(TouchEventQueueTest, NoTouchMoveSuppressionAfterMultiTouch) {
- const double kSlopLengthDips = 10.;
- const double kHalfSlopLengthDips = kSlopLengthDips / 2;
- const bool slop_includes_boundary = true;
- SetUpForTouchMoveSlopTesting(kSlopLengthDips, slop_includes_boundary);
+ const float kSlopLengthDips = 10;
+ const float kHalfSlopLengthDips = kSlopLengthDips / 2;
+ SetUpForTouchMoveSlopTesting(kSlopLengthDips);
// Queue a TouchStart.
PressTouchPoint(0, 0);
@@ -1717,8 +1769,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- // Now send the first touch move and associated GestureScrollBegin,
- // but don't ACK the gesture event yet.
+ // Now send the first touch move and associated GestureScrollBegin.
MoveTouchPoint(0, 0, 5);
WebGestureEvent followup_scroll;
followup_scroll.type = WebInputEvent::GestureScrollBegin;
@@ -1726,9 +1777,21 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ SendGestureEventAck(WebInputEvent::GestureScrollBegin,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // Send the second touch move and associated GestureScrollUpdate, but don't
+ // ACK the gesture event yet.
+ MoveTouchPoint(0, 0, 50);
+ followup_scroll.type = WebInputEvent::GestureScrollUpdate;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
// Now queue a second touchmove and verify it's not (yet) dispatched.
- MoveTouchPoint(0, 0, 10);
+ MoveTouchPoint(0, 0, 100);
+ SetFollowupEvent(followup_scroll);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(HasPendingAsyncTouchMove());
EXPECT_EQ(0U, queued_event_count());
@@ -1737,6 +1800,8 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
// Queuing the final touchend should flush the pending, async touchmove.
ReleaseTouchPoint(0);
+ followup_scroll.type = WebInputEvent::GestureScrollEnd;
+ SetFollowupEvent(followup_scroll);
EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_FALSE(sent_event().cancelable);
@@ -1758,10 +1823,12 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
EXPECT_EQ(0U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
- // Now mark the scroll as not consumed (which would cause future
- // touchmoves in the active sequence to be sent if there was one).
- SendGestureEventAck(WebInputEvent::GestureScrollBegin,
- INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ // Now mark the scrolls as not consumed (which would cause future touchmoves
+ // in the active sequence to be sent if there was one).
+ SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
// Start a new touch sequence and verify that throttling has been reset.
// Touch moves after the start of scrolling will again be throttled.
@@ -1770,10 +1837,20 @@ TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(1U, GetAndResetAckedEventCount());
MoveTouchPoint(0, 0, 5);
+ followup_scroll.type = WebInputEvent::GestureScrollBegin;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ MoveTouchPoint(0, 0, 5);
+ followup_scroll.type = WebInputEvent::GestureScrollUpdate;
SetFollowupEvent(followup_scroll);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_FALSE(HasPendingAsyncTouchMove());
EXPECT_EQ(1U, GetAndResetSentEventCount());
EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
MoveTouchPoint(0, 0, 10);
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_TRUE(HasPendingAsyncTouchMove());
@@ -1993,6 +2070,8 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(0U, queued_event_count());
+ SendGestureEvent(WebInputEvent::GestureScrollUpdate);
+
// The async touchmove should be ack'ed immediately, but not forwarded.
// However, because the ack triggers a touchcancel, both the pending touch and
// the queued touchcancel should be flushed.
@@ -2010,7 +2089,7 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
EXPECT_EQ(1U, GetAndResetAckedEventCount());
EXPECT_EQ(1U, GetAndResetSentEventCount());
- // The ack for the asnc touchmove should not reach the client, as it has
+ // The ack for the async touchmove should not reach the client, as it has
// already been ack'ed.
SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_FALSE(sent_event().cancelable);
@@ -2026,4 +2105,124 @@ TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
EXPECT_EQ(0U, GetAndResetSentEventCount());
}
+// Ensure that the async touch is fully reset if the touch sequence restarts
+// without properly terminating.
+TEST_F(TouchEventQueueTest, AsyncTouchWithHardTouchStartReset) {
+ SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
+
+ PressTouchPoint(0, 0);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Trigger async touchmove dispatch.
+ MoveTouchPoint(0, 1, 1);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ WebGestureEvent followup_scroll;
+ followup_scroll.type = WebInputEvent::GestureScrollBegin;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, queued_event_count());
+ SendGestureEvent(WebInputEvent::GestureScrollUpdate);
+
+ // The async touchmove should be immediately ack'ed but delivery is deferred.
+ MoveTouchPoint(0, 2, 2);
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(WebInputEvent::TouchMove, acked_event().type);
+
+ // The queue should be robust to hard touch restarts with a new touch
+ // sequence. In this case, the deferred async touch should not be flushed
+ // by the new touch sequence.
+ SendGestureEvent(WebInputEvent::GestureScrollEnd);
+ ResetTouchEvent();
+
+ PressTouchPoint(0, 0);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ EXPECT_EQ(WebInputEvent::TouchStart, sent_event().type);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+}
+
+TEST_F(TouchEventQueueTest, TouchAbsorptionWithConsumedFirstMove) {
+ SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
+
+ // Queue a TouchStart.
+ PressTouchPoint(0, 1);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ MoveTouchPoint(0, 20, 5);
+ SendGestureEvent(blink::WebInputEvent::GestureScrollBegin);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(2U, GetAndResetSentEventCount());
+
+ // Even if the first touchmove event was consumed, subsequent unconsumed
+ // touchmove events should trigger scrolling.
+ MoveTouchPoint(0, 60, 5);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ MoveTouchPoint(0, 20, 5);
+ WebGestureEvent followup_scroll;
+ followup_scroll.type = WebInputEvent::GestureScrollUpdate;
+ SetFollowupEvent(followup_scroll);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendGestureEventAck(WebInputEvent::GestureScrollUpdate,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_TRUE(sent_event().cancelable);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+
+ // Touch move event is throttled.
+ MoveTouchPoint(0, 60, 5);
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(0U, queued_event_count());
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+}
+
+TEST_F(TouchEventQueueTest, UnseenTouchPointerIdsNotForwarded) {
+ SyntheticWebTouchEvent event;
+ event.PressPoint(0, 0);
+ SendTouchEvent(event);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Give the touchmove a previously unseen pointer id; it should not be sent.
+ int press_id = event.touches[0].id;
+ event.MovePoint(0, 1, 1);
+ event.touches[0].id = 7;
+ SendTouchEvent(event);
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Give the touchmove a valid id; it should be sent.
+ event.touches[0].id = press_id;
+ SendTouchEvent(event);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Do the same for release.
+ event.ReleasePoint(0);
+ event.touches[0].id = 11;
+ SendTouchEvent(event);
+ EXPECT_EQ(0U, GetAndResetSentEventCount());
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+
+ // Give the touchmove a valid id; it should be sent.
+ event.touches[0].id = press_id;
+ SendTouchEvent(event);
+ EXPECT_EQ(1U, GetAndResetSentEventCount());
+ SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(1U, GetAndResetAckedEventCount());
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_handle.cc b/chromium/content/browser/renderer_host/input/touch_handle.cc
new file mode 100644
index 00000000000..acfe3bd70f8
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/touch_handle.cc
@@ -0,0 +1,267 @@
+// 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/renderer_host/input/touch_handle.h"
+
+#include <cmath>
+
+namespace content {
+
+namespace {
+
+// Maximum duration of a fade sequence.
+const double kFadeDurationMs = 200;
+
+// Maximum amount of travel for a fade sequence. This avoids handle "ghosting"
+// when the handle is moving rapidly while the fade is active.
+const double kFadeDistanceSquared = 20.f * 20.f;
+
+// Avoid using an empty touch rect, as it may fail the intersection test event
+// if it lies within the other rect's bounds.
+const float kMinTouchMajorForHitTesting = 1.f;
+
+// The maximum touch size to use when computing whether a touch point is
+// targetting a touch handle. This is necessary for devices that misreport
+// touch radii, preventing inappropriately largely touch sizes from completely
+// breaking handle dragging behavior.
+const float kMaxTouchMajorForHitTesting = 36.f;
+
+} // namespace
+
+// Responsible for rendering a selection or insertion handle for text editing.
+TouchHandle::TouchHandle(TouchHandleClient* client,
+ TouchHandleOrientation orientation)
+ : drawable_(client->CreateDrawable()),
+ client_(client),
+ orientation_(orientation),
+ deferred_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
+ alpha_(0.f),
+ animate_deferred_fade_(false),
+ enabled_(true),
+ is_visible_(false),
+ is_dragging_(false),
+ is_drag_within_tap_region_(false) {
+ DCHECK_NE(orientation, TOUCH_HANDLE_ORIENTATION_UNDEFINED);
+ drawable_->SetEnabled(enabled_);
+ drawable_->SetOrientation(orientation_);
+ drawable_->SetAlpha(alpha_);
+ drawable_->SetVisible(is_visible_);
+ drawable_->SetFocus(position_);
+}
+
+TouchHandle::~TouchHandle() {
+}
+
+void TouchHandle::SetEnabled(bool enabled) {
+ if (enabled_ == enabled)
+ return;
+ if (!enabled) {
+ EndDrag();
+ EndFade();
+ }
+ enabled_ = enabled;
+ drawable_->SetEnabled(enabled);
+}
+
+void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) {
+ DCHECK(enabled_);
+ if (is_visible_ == visible)
+ return;
+
+ is_visible_ = visible;
+
+ // Handle repositioning may have been deferred while previously invisible.
+ if (visible)
+ drawable_->SetFocus(position_);
+
+ bool animate = animation_style != ANIMATION_NONE;
+ if (is_dragging_) {
+ animate_deferred_fade_ = animate;
+ return;
+ }
+
+ if (animate)
+ BeginFade();
+ else
+ EndFade();
+}
+
+void TouchHandle::SetPosition(const gfx::PointF& position) {
+ DCHECK(enabled_);
+ if (position_ == position)
+ return;
+ position_ = position;
+ // Suppress repositioning a handle while invisible or fading out to prevent it
+ // from "ghosting" outside the visible bounds. The position will be pushed to
+ // the drawable when the handle regains visibility (see |SetVisible()|).
+ if (is_visible_)
+ drawable_->SetFocus(position_);
+}
+
+void TouchHandle::SetOrientation(TouchHandleOrientation orientation) {
+ DCHECK(enabled_);
+ DCHECK_NE(orientation, TOUCH_HANDLE_ORIENTATION_UNDEFINED);
+ if (is_dragging_) {
+ deferred_orientation_ = orientation;
+ return;
+ }
+ DCHECK_EQ(deferred_orientation_, TOUCH_HANDLE_ORIENTATION_UNDEFINED);
+ if (orientation_ == orientation)
+ return;
+
+ orientation_ = orientation;
+ drawable_->SetOrientation(orientation);
+}
+
+bool TouchHandle::WillHandleTouchEvent(const ui::MotionEvent& event) {
+ if (!enabled_)
+ return false;
+
+ if (!is_dragging_ && event.GetAction() != ui::MotionEvent::ACTION_DOWN)
+ return false;
+
+ switch (event.GetAction()) {
+ case ui::MotionEvent::ACTION_DOWN: {
+ if (!is_visible_)
+ return false;
+ const float touch_size = std::max(
+ kMinTouchMajorForHitTesting,
+ std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor()));
+ const gfx::RectF touch_rect(event.GetX() - touch_size * .5f,
+ event.GetY() - touch_size * .5f,
+ touch_size,
+ touch_size);
+ if (!drawable_->IntersectsWith(touch_rect))
+ return false;
+ touch_down_position_ = gfx::PointF(event.GetX(), event.GetY());
+ touch_to_focus_offset_ = position_ - touch_down_position_;
+ touch_down_time_ = event.GetEventTime();
+ BeginDrag();
+ } break;
+
+ case ui::MotionEvent::ACTION_MOVE: {
+ gfx::PointF touch_move_position(event.GetX(), event.GetY());
+ if (is_drag_within_tap_region_) {
+ const float tap_slop = client_->GetTapSlop();
+ is_drag_within_tap_region_ =
+ (touch_move_position - touch_down_position_).LengthSquared() <
+ tap_slop * tap_slop;
+ }
+
+ // Note that we signal drag update even if we're inside the tap region,
+ // as there are cases where characters are narrower than the slop length.
+ client_->OnHandleDragUpdate(*this,
+ touch_move_position + touch_to_focus_offset_);
+ } break;
+
+ case ui::MotionEvent::ACTION_UP: {
+ if (is_drag_within_tap_region_ &&
+ (event.GetEventTime() - touch_down_time_) <
+ client_->GetTapTimeout()) {
+ client_->OnHandleTapped(*this);
+ }
+
+ EndDrag();
+ } break;
+
+ case ui::MotionEvent::ACTION_CANCEL:
+ EndDrag();
+ break;
+
+ default:
+ break;
+ };
+ return true;
+}
+
+bool TouchHandle::Animate(base::TimeTicks frame_time) {
+ if (fade_end_time_ == base::TimeTicks())
+ return false;
+
+ DCHECK(enabled_);
+
+ float time_u =
+ 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs;
+ float position_u =
+ (position_ - fade_start_position_).LengthSquared() / kFadeDistanceSquared;
+ float u = std::max(time_u, position_u);
+ SetAlpha(is_visible_ ? u : 1.f - u);
+
+ if (u >= 1.f) {
+ EndFade();
+ return false;
+ }
+
+ return true;
+}
+
+void TouchHandle::BeginDrag() {
+ DCHECK(enabled_);
+ if (is_dragging_)
+ return;
+ EndFade();
+ is_dragging_ = true;
+ is_drag_within_tap_region_ = true;
+ client_->OnHandleDragBegin(*this);
+}
+
+void TouchHandle::EndDrag() {
+ DCHECK(enabled_);
+ if (!is_dragging_)
+ return;
+
+ is_dragging_ = false;
+ is_drag_within_tap_region_ = false;
+ client_->OnHandleDragEnd(*this);
+
+ if (deferred_orientation_ != TOUCH_HANDLE_ORIENTATION_UNDEFINED) {
+ TouchHandleOrientation deferred_orientation = deferred_orientation_;
+ deferred_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED;
+ SetOrientation(deferred_orientation);
+ }
+
+ if (animate_deferred_fade_) {
+ BeginFade();
+ } else {
+ // As drawable visibility assignment is deferred while dragging, push the
+ // change by forcing fade completion.
+ EndFade();
+ }
+}
+
+void TouchHandle::BeginFade() {
+ DCHECK(enabled_);
+ DCHECK(!is_dragging_);
+ animate_deferred_fade_ = false;
+ const float target_alpha = is_visible_ ? 1.f : 0.f;
+ if (target_alpha == alpha_) {
+ EndFade();
+ return;
+ }
+
+ drawable_->SetVisible(true);
+ fade_end_time_ = base::TimeTicks::Now() +
+ base::TimeDelta::FromMillisecondsD(
+ kFadeDurationMs * std::abs(target_alpha - alpha_));
+ fade_start_position_ = position_;
+ client_->SetNeedsAnimate();
+}
+
+void TouchHandle::EndFade() {
+ DCHECK(enabled_);
+ animate_deferred_fade_ = false;
+ fade_end_time_ = base::TimeTicks();
+ SetAlpha(is_visible_ ? 1.f : 0.f);
+ drawable_->SetVisible(is_visible_);
+}
+
+void TouchHandle::SetAlpha(float alpha) {
+ alpha = std::max(0.f, std::min(1.f, alpha));
+ if (alpha_ == alpha)
+ return;
+ alpha_ = alpha;
+ drawable_->SetAlpha(alpha);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_handle.h b/chromium/content/browser/renderer_host/input/touch_handle.h
new file mode 100644
index 00000000000..7859febef23
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/touch_handle.h
@@ -0,0 +1,135 @@
+// 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_RENDERER_HOST_INPUT_TOUCH_HANDLE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_HANDLE_H_
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "ui/events/gesture_detection/motion_event.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace content {
+
+class TouchHandle;
+
+enum TouchHandleOrientation {
+ TOUCH_HANDLE_LEFT,
+ TOUCH_HANDLE_CENTER,
+ TOUCH_HANDLE_RIGHT,
+ TOUCH_HANDLE_ORIENTATION_UNDEFINED,
+};
+
+// Interface through which |TouchHandle| delegates rendering-specific duties.
+class CONTENT_EXPORT TouchHandleDrawable {
+ public:
+ virtual ~TouchHandleDrawable() {}
+ virtual void SetEnabled(bool enabled) = 0;
+ virtual void SetOrientation(TouchHandleOrientation orientation) = 0;
+ virtual void SetAlpha(float alpha) = 0;
+ virtual void SetFocus(const gfx::PointF& position) = 0;
+ virtual void SetVisible(bool visible) = 0;
+ virtual bool IntersectsWith(const gfx::RectF& rect) const = 0;
+};
+
+// Interface through which |TouchHandle| communicates handle manipulation and
+// requests concrete drawable instances.
+class CONTENT_EXPORT TouchHandleClient {
+ public:
+ virtual ~TouchHandleClient() {}
+ virtual void OnHandleDragBegin(const TouchHandle& handle) = 0;
+ virtual void OnHandleDragUpdate(const TouchHandle& handle,
+ const gfx::PointF& new_position) = 0;
+ virtual void OnHandleDragEnd(const TouchHandle& handle) = 0;
+ virtual void OnHandleTapped(const TouchHandle& handle) = 0;
+ virtual void SetNeedsAnimate() = 0;
+ virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() = 0;
+ virtual base::TimeDelta GetTapTimeout() const = 0;
+ virtual float GetTapSlop() const = 0;
+};
+
+// Responsible for displaying a selection or insertion handle for text
+// interaction.
+class CONTENT_EXPORT TouchHandle {
+ public:
+ // The drawable will be enabled but invisible until otherwise specified.
+ TouchHandle(TouchHandleClient* client, TouchHandleOrientation orientation);
+ ~TouchHandle();
+
+ // Sets whether the handle is active, allowing resource cleanup if necessary.
+ // If false, active animations or touch drag sequences will be cancelled.
+ // While disabled, manipulation is *explicitly not supported*, and may lead to
+ // undesirable and/or unstable side-effects. The handle can be safely
+ // re-enabled to allow continued operation.
+ void SetEnabled(bool enabled);
+
+ enum AnimationStyle { ANIMATION_NONE, ANIMATION_SMOOTH };
+ // Update the handle visibility, fading in/out according to |animation_style|.
+ // If an animation is in-progress, it will be overriden appropriately.
+ void SetVisible(bool visible, AnimationStyle animation_style);
+
+ // Update the handle placement to |position|.
+ // Note: If a fade out animation is active or the handle is invisible, the
+ // handle position will not be updated until the handle regains visibility.
+ void SetPosition(const gfx::PointF& position);
+
+ // Update the handle visuals to |orientation|.
+ // Note: If the handle is being dragged, the orientation change will be
+ // deferred until the drag has ceased.
+ void SetOrientation(TouchHandleOrientation orientation);
+
+ // Allows touch-dragging of the handle. Returns true if the event was
+ // consumed, in which case the caller should cease further handling.
+ bool WillHandleTouchEvent(const ui::MotionEvent& event);
+
+ // Ticks an active animation, as requested to the client by |SetNeedsAnimate|.
+ // Returns true if an animation is active and requires further ticking.
+ bool Animate(base::TimeTicks frame_time);
+
+ bool is_dragging() const { return is_dragging_; }
+ const gfx::PointF& position() const { return position_; }
+ TouchHandleOrientation orientation() const { return orientation_; }
+
+ private:
+ void BeginDrag();
+ void EndDrag();
+ void BeginFade();
+ void EndFade();
+ void SetAlpha(float alpha);
+
+ scoped_ptr<TouchHandleDrawable> drawable_;
+
+ TouchHandleClient* const client_;
+
+ gfx::PointF position_;
+ TouchHandleOrientation orientation_;
+ TouchHandleOrientation deferred_orientation_;
+
+ gfx::PointF touch_down_position_;
+ gfx::Vector2dF touch_to_focus_offset_;
+ base::TimeTicks touch_down_time_;
+
+ // Note that when a fade animation is active, |is_visible_| and |position_|
+ // may not reflect the actual visibilty and position of the drawable. This
+ // discrepancy is resolved either upon fade completion or cancellation.
+ base::TimeTicks fade_end_time_;
+ gfx::PointF fade_start_position_;
+ float alpha_;
+ bool animate_deferred_fade_;
+
+ bool enabled_;
+ bool is_visible_;
+ bool is_dragging_;
+ bool is_drag_within_tap_region_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchHandle);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_HANDLE_H_
diff --git a/chromium/content/browser/renderer_host/input/touch_handle_unittest.cc b/chromium/content/browser/renderer_host/input/touch_handle_unittest.cc
new file mode 100644
index 00000000000..a3459e6c585
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/touch_handle_unittest.cc
@@ -0,0 +1,491 @@
+// 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/renderer_host/input/touch_handle.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/test/motion_event_test_utils.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+using ui::test::MockMotionEvent;
+
+namespace content {
+namespace {
+
+const int kDefaultTapTimeoutMs = 200;
+const float kDefaultTapSlop = 10.f;
+const float kDefaultDrawableSize = 10.f;
+
+struct MockDrawableData {
+ MockDrawableData()
+ : orientation(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
+ alpha(0.f),
+ enabled(false),
+ visible(false),
+ rect(0, 0, kDefaultDrawableSize, kDefaultDrawableSize) {}
+ TouchHandleOrientation orientation;
+ float alpha;
+ bool enabled;
+ bool visible;
+ gfx::RectF rect;
+};
+
+class MockTouchHandleDrawable : public TouchHandleDrawable {
+ public:
+ explicit MockTouchHandleDrawable(MockDrawableData* data) : data_(data) {}
+ ~MockTouchHandleDrawable() override {}
+
+ void SetEnabled(bool enabled) override { data_->enabled = enabled; }
+
+ void SetOrientation(TouchHandleOrientation orientation) override {
+ data_->orientation = orientation;
+ }
+
+ void SetAlpha(float alpha) override { data_->alpha = alpha; }
+
+ void SetFocus(const gfx::PointF& position) override {
+ // Anchor focus to the top left of the rect (regardless of orientation).
+ data_->rect.set_origin(position);
+ }
+
+ void SetVisible(bool visible) override { data_->visible = visible; }
+
+ bool IntersectsWith(const gfx::RectF& rect) const override {
+ return data_->rect.Intersects(rect);
+ }
+
+ private:
+ MockDrawableData* data_;
+};
+
+} // namespace
+
+class TouchHandleTest : public testing::Test, public TouchHandleClient {
+ public:
+ TouchHandleTest()
+ : dragging_(false),
+ dragged_(false),
+ tapped_(false),
+ needs_animate_(false) {}
+
+ ~TouchHandleTest() override {}
+
+ // TouchHandleClient implementation.
+ void OnHandleDragBegin(const TouchHandle& handle) override {
+ dragging_ = true;
+ }
+
+ void OnHandleDragUpdate(const TouchHandle& handle,
+ const gfx::PointF& new_position) override {
+ dragged_ = true;
+ drag_position_ = new_position;
+ }
+
+ void OnHandleDragEnd(const TouchHandle& handle) override {
+ dragging_ = false;
+ }
+
+ void OnHandleTapped(const TouchHandle& handle) override { tapped_ = true; }
+
+ void SetNeedsAnimate() override { needs_animate_ = true; }
+
+ scoped_ptr<TouchHandleDrawable> CreateDrawable() override {
+ return scoped_ptr<TouchHandleDrawable>(
+ new MockTouchHandleDrawable(&drawable_data_));
+ }
+
+ base::TimeDelta GetTapTimeout() const override {
+ return base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs);
+ }
+
+ float GetTapSlop() const override { return kDefaultTapSlop; }
+
+ void Animate(TouchHandle& handle) {
+ needs_animate_ = false;
+ base::TimeTicks now = base::TimeTicks::Now();
+ while (handle.Animate(now))
+ now += base::TimeDelta::FromMilliseconds(16);
+ }
+
+ bool GetAndResetHandleDragged() {
+ bool dragged = dragged_;
+ dragged_ = false;
+ return dragged;
+ }
+
+ bool GetAndResetHandleTapped() {
+ bool tapped = tapped_;
+ tapped_ = false;
+ return tapped;
+ }
+
+ bool GetAndResetNeedsAnimate() {
+ bool needs_animate = needs_animate_;
+ needs_animate_ = false;
+ return needs_animate;
+ }
+
+ bool IsDragging() const { return dragging_; }
+ const gfx::PointF& DragPosition() const { return drag_position_; }
+ bool NeedsAnimate() const { return needs_animate_; }
+
+ const MockDrawableData& drawable() { return drawable_data_; }
+
+ private:
+ gfx::PointF drag_position_;
+ bool dragging_;
+ bool dragged_;
+ bool tapped_;
+ bool needs_animate_;
+
+ MockDrawableData drawable_data_;
+};
+
+TEST_F(TouchHandleTest, Visibility) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+ EXPECT_FALSE(drawable().visible);
+
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+ EXPECT_TRUE(drawable().visible);
+ EXPECT_EQ(1.f, drawable().alpha);
+
+ handle.SetVisible(false, TouchHandle::ANIMATION_NONE);
+ EXPECT_FALSE(drawable().visible);
+
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+ EXPECT_TRUE(drawable().visible);
+ EXPECT_EQ(1.f, drawable().alpha);
+}
+
+TEST_F(TouchHandleTest, VisibilityAnimation) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+ ASSERT_FALSE(NeedsAnimate());
+ ASSERT_FALSE(drawable().visible);
+ ASSERT_EQ(0.f, drawable().alpha);
+
+ handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
+ EXPECT_TRUE(NeedsAnimate());
+ EXPECT_TRUE(drawable().visible);
+ EXPECT_EQ(0.f, drawable().alpha);
+
+ Animate(handle);
+ EXPECT_TRUE(drawable().visible);
+ EXPECT_EQ(1.f, drawable().alpha);
+
+ ASSERT_FALSE(NeedsAnimate());
+ handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
+ EXPECT_TRUE(NeedsAnimate());
+ EXPECT_TRUE(drawable().visible);
+ EXPECT_EQ(1.f, drawable().alpha);
+
+ Animate(handle);
+ EXPECT_FALSE(drawable().visible);
+ EXPECT_EQ(0.f, drawable().alpha);
+
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+ EXPECT_EQ(1.f, drawable().alpha);
+ EXPECT_FALSE(GetAndResetNeedsAnimate());
+ handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
+ EXPECT_EQ(1.f, drawable().alpha);
+ EXPECT_TRUE(GetAndResetNeedsAnimate());
+ handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
+ EXPECT_EQ(1.f, drawable().alpha);
+ EXPECT_FALSE(GetAndResetNeedsAnimate());
+}
+
+TEST_F(TouchHandleTest, Orientation) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+ EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation);
+
+ handle.SetOrientation(TOUCH_HANDLE_LEFT);
+ EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation);
+
+ handle.SetOrientation(TOUCH_HANDLE_RIGHT);
+ EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
+
+ handle.SetOrientation(TOUCH_HANDLE_CENTER);
+ EXPECT_EQ(TOUCH_HANDLE_CENTER, drawable().orientation);
+}
+
+TEST_F(TouchHandleTest, Position) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+
+ gfx::PointF position;
+ EXPECT_EQ(gfx::PointF(), drawable().rect.origin());
+
+ position = gfx::PointF(7.3f, -3.7f);
+ handle.SetPosition(position);
+ EXPECT_EQ(position, drawable().rect.origin());
+
+ position = gfx::PointF(-7.3f, 3.7f);
+ handle.SetPosition(position);
+ EXPECT_EQ(position, drawable().rect.origin());
+}
+
+TEST_F(TouchHandleTest, PositionNotUpdatedWhileFadingOrInvisible) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+ ASSERT_TRUE(drawable().visible);
+ ASSERT_FALSE(NeedsAnimate());
+
+ gfx::PointF old_position(7.3f, -3.7f);
+ handle.SetPosition(old_position);
+ ASSERT_EQ(old_position, drawable().rect.origin());
+
+ handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
+ ASSERT_TRUE(NeedsAnimate());
+
+ gfx::PointF new_position(3.7f, -3.7f);
+ handle.SetPosition(new_position);
+ EXPECT_EQ(old_position, drawable().rect.origin());
+ EXPECT_TRUE(NeedsAnimate());
+
+ // While the handle is fading, the new position should not take affect.
+ base::TimeTicks now = base::TimeTicks::Now();
+ while (handle.Animate(now)) {
+ EXPECT_EQ(old_position, drawable().rect.origin());
+ now += base::TimeDelta::FromMilliseconds(16);
+ }
+
+ // Even after the animation terminates, the new position will not be pushed.
+ EXPECT_EQ(old_position, drawable().rect.origin());
+
+ // As soon as the handle becomes visible, the new position will be pushed.
+ handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
+ EXPECT_EQ(new_position, drawable().rect.origin());
+}
+
+TEST_F(TouchHandleTest, Enabled) {
+ // A newly created handle defaults to enabled.
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+ EXPECT_TRUE(drawable().enabled);
+
+ handle.SetVisible(true, TouchHandle::ANIMATION_SMOOTH);
+ EXPECT_TRUE(GetAndResetNeedsAnimate());
+ EXPECT_EQ(0.f, drawable().alpha);
+ handle.SetEnabled(false);
+ EXPECT_FALSE(drawable().enabled);
+
+ // Dragging should not be allowed while the handle is disabled.
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float kOffset = kDefaultDrawableSize / 2.f;
+ MockMotionEvent event(
+ MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
+ EXPECT_FALSE(handle.WillHandleTouchEvent(event));
+
+ // Disabling mid-animation should cancel the animation.
+ handle.SetEnabled(true);
+ handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
+ EXPECT_TRUE(drawable().visible);
+ EXPECT_TRUE(GetAndResetNeedsAnimate());
+ handle.SetEnabled(false);
+ EXPECT_FALSE(drawable().enabled);
+ EXPECT_FALSE(drawable().visible);
+ EXPECT_FALSE(handle.Animate(base::TimeTicks::Now()));
+
+ // Disabling mid-drag should cancel the drag.
+ handle.SetEnabled(true);
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(IsDragging());
+ handle.SetEnabled(false);
+ EXPECT_FALSE(IsDragging());
+ EXPECT_FALSE(handle.WillHandleTouchEvent(event));
+}
+
+TEST_F(TouchHandleTest, Drag) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float kOffset = kDefaultDrawableSize / 2.f;
+
+ // The handle must be visible to trigger drag.
+ MockMotionEvent event(
+ MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
+ EXPECT_FALSE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(IsDragging());
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+
+ // ACTION_DOWN must fall within the drawable region to trigger drag.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 50, 50);
+ EXPECT_FALSE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(IsDragging());
+
+ // Only ACTION_DOWN will trigger drag.
+ event = MockMotionEvent(
+ MockMotionEvent::ACTION_MOVE, event_time, kOffset, kOffset);
+ EXPECT_FALSE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(IsDragging());
+
+ // Start the drag.
+ event = MockMotionEvent(
+ MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(IsDragging());
+
+ event = MockMotionEvent(
+ MockMotionEvent::ACTION_MOVE, event_time, kOffset + 10, kOffset + 15);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetHandleDragged());
+ EXPECT_TRUE(IsDragging());
+ EXPECT_EQ(gfx::PointF(10, 15), DragPosition());
+
+ event = MockMotionEvent(
+ MockMotionEvent::ACTION_MOVE, event_time, kOffset - 10, kOffset - 15);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetHandleDragged());
+ EXPECT_TRUE(IsDragging());
+ EXPECT_EQ(gfx::PointF(-10, -15), DragPosition());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetHandleDragged());
+ EXPECT_FALSE(IsDragging());
+
+ // Non-ACTION_DOWN events after the drag has terminated should not be handled.
+ event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL);
+ EXPECT_FALSE(handle.WillHandleTouchEvent(event));
+}
+
+TEST_F(TouchHandleTest, DragDefersOrientationChange) {
+ TouchHandle handle(this, TOUCH_HANDLE_RIGHT);
+ ASSERT_EQ(drawable().orientation, TOUCH_HANDLE_RIGHT);
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+
+ MockMotionEvent event(MockMotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(IsDragging());
+
+ // Orientation changes will be deferred until the drag ends.
+ handle.SetOrientation(TOUCH_HANDLE_LEFT);
+ EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetHandleDragged());
+ EXPECT_TRUE(IsDragging());
+ EXPECT_EQ(TOUCH_HANDLE_RIGHT, drawable().orientation);
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetHandleDragged());
+ EXPECT_FALSE(IsDragging());
+ EXPECT_EQ(TOUCH_HANDLE_LEFT, drawable().orientation);
+}
+
+TEST_F(TouchHandleTest, DragDefersFade) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+
+ MockMotionEvent event(MockMotionEvent::ACTION_DOWN);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(IsDragging());
+
+ // Fade will be deferred until the drag ends.
+ handle.SetVisible(false, TouchHandle::ANIMATION_SMOOTH);
+ EXPECT_FALSE(NeedsAnimate());
+ EXPECT_TRUE(drawable().visible);
+ EXPECT_EQ(1.f, drawable().alpha);
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(NeedsAnimate());
+ EXPECT_TRUE(drawable().visible);
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(IsDragging());
+ EXPECT_TRUE(NeedsAnimate());
+
+ Animate(handle);
+ EXPECT_FALSE(drawable().visible);
+ EXPECT_EQ(0.f, drawable().alpha);
+}
+
+TEST_F(TouchHandleTest, DragTargettingUsesTouchSize) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ const float kTouchSize = 24.f;
+ const float kOffset = kDefaultDrawableSize + kTouchSize / 2.001f;
+
+ MockMotionEvent event(
+ MockMotionEvent::ACTION_DOWN, event_time, kOffset, kOffset);
+ event.SetTouchMajor(0.f);
+ EXPECT_FALSE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(IsDragging());
+
+ event.SetTouchMajor(kTouchSize / 2.f);
+ EXPECT_FALSE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(IsDragging());
+
+ event.SetTouchMajor(kTouchSize);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(IsDragging());
+
+ event.SetTouchMajor(kTouchSize * 2.f);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(IsDragging());
+
+ // Ensure a touch size of 0 can still register a hit.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN,
+ event_time,
+ kDefaultDrawableSize / 2.f,
+ kDefaultDrawableSize / 2.f);
+ event.SetTouchMajor(0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(IsDragging());
+}
+
+TEST_F(TouchHandleTest, Tap) {
+ TouchHandle handle(this, TOUCH_HANDLE_CENTER);
+ handle.SetVisible(true, TouchHandle::ANIMATION_NONE);
+
+ base::TimeTicks event_time = base::TimeTicks::Now();
+
+ // ACTION_CANCEL shouldn't trigger a tap.
+ MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ event_time += base::TimeDelta::FromMilliseconds(50);
+ event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetHandleTapped());
+
+ // Long press shouldn't trigger a tap.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ event_time += 2 * GetTapTimeout();
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetHandleTapped());
+
+ // Only a brief tap within the slop region should trigger a tap.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ event_time += GetTapTimeout() / 2;
+ event = MockMotionEvent(
+ MockMotionEvent::ACTION_MOVE, event_time, kDefaultTapSlop / 2.f, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ event = MockMotionEvent(
+ MockMotionEvent::ACTION_UP, event_time, kDefaultTapSlop / 2.f, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetHandleTapped());
+
+ // Moving beyond the slop region shouldn't trigger a tap.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ event_time += GetTapTimeout() / 2;
+ event = MockMotionEvent(
+ MockMotionEvent::ACTION_MOVE, event_time, kDefaultTapSlop * 2.f, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ event = MockMotionEvent(
+ MockMotionEvent::ACTION_UP, event_time, kDefaultTapSlop * 2.f, 0);
+ EXPECT_TRUE(handle.WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetHandleTapped());
+}
+
+} // namespace content
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 758f3ec6a29..3a9f2fd734e 100644
--- a/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
+++ b/chromium/content/browser/renderer_host/input/touch_input_browsertest.cc
@@ -97,7 +97,7 @@ class InputEventMessageFilter : public BrowserMessageFilter {
InputEventAckState last_ack_state() const { return state_; }
protected:
- virtual ~InputEventMessageFilter() {}
+ ~InputEventMessageFilter() override {}
private:
void ReceivedEventAck(WebInputEvent::Type type, InputEventAckState state) {
@@ -108,7 +108,7 @@ class InputEventMessageFilter : public BrowserMessageFilter {
}
// BrowserMessageFilter:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ 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);
@@ -131,7 +131,7 @@ class InputEventMessageFilter : public BrowserMessageFilter {
class TouchInputBrowserTest : public ContentBrowserTest {
public:
TouchInputBrowserTest() {}
- virtual ~TouchInputBrowserTest() {}
+ ~TouchInputBrowserTest() override {}
RenderWidgetHostImpl* GetWidgetHost() {
return RenderWidgetHostImpl::From(shell()->web_contents()->
@@ -156,10 +156,10 @@ class TouchInputBrowserTest : public ContentBrowserTest {
GiveItSomeTime();
filter_ = new InputEventMessageFilter();
- host->GetProcess()->AddFilter(filter_);
+ host->GetProcess()->AddFilter(filter_.get());
}
- virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
+ void SetUpCommandLine(CommandLine* cmd) override {
cmd->AppendSwitchASCII(switches::kTouchEvents,
switches::kTouchEventsEnabled);
}
@@ -183,14 +183,8 @@ IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_TouchNoHandler) {
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
filter()->WaitForAck(WebInputEvent::TouchStart);
- if (content::IsThreadedCompositingEnabled()) {
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
- filter()->last_ack_state());
- } else {
- // http://crbug.com/326232: This should be NO_CONSUMER_EXISTS once
- // WebViewImpl::hasTouchEventHandlersAt() is implemented.
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
- }
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+ filter()->last_ack_state());
// 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.
@@ -247,14 +241,8 @@ IN_PROC_BROWSER_TEST_F(TouchInputBrowserTest, MAYBE_MultiPointTouchPress) {
touch.PressPoint(25, 25);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
filter()->WaitForAck(WebInputEvent::TouchStart);
- if (content::IsThreadedCompositingEnabled()) {
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
- filter()->last_ack_state());
- } else {
- // http://crbug.com/326232: This should be NO_CONSUMER_EXISTS once
- // WebViewImpl::hasTouchEventHandlersAt() is implemented.
- EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
- }
+ EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+ filter()->last_ack_state());
touch.PressPoint(25, 125);
GetWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, ui::LatencyInfo());
diff --git a/chromium/content/browser/renderer_host/input/touch_selection_controller.cc b/chromium/content/browser/renderer_host/input/touch_selection_controller.cc
new file mode 100644
index 00000000000..4c8807d0fcc
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/touch_selection_controller.cc
@@ -0,0 +1,423 @@
+// 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/renderer_host/input/touch_selection_controller.h"
+
+#include "base/auto_reset.h"
+#include "base/logging.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+namespace content {
+namespace {
+
+TouchHandleOrientation ToTouchHandleOrientation(cc::SelectionBoundType type) {
+ switch (type) {
+ case cc::SELECTION_BOUND_LEFT:
+ return TOUCH_HANDLE_LEFT;
+ case cc::SELECTION_BOUND_RIGHT:
+ return TOUCH_HANDLE_RIGHT;
+ case cc::SELECTION_BOUND_CENTER:
+ return TOUCH_HANDLE_CENTER;
+ case cc::SELECTION_BOUND_EMPTY:
+ return TOUCH_HANDLE_ORIENTATION_UNDEFINED;
+ }
+ NOTREACHED() << "Invalid selection bound type: " << type;
+ return TOUCH_HANDLE_ORIENTATION_UNDEFINED;
+}
+
+} // namespace
+
+TouchSelectionController::TouchSelectionController(
+ TouchSelectionControllerClient* client,
+ base::TimeDelta tap_timeout,
+ float tap_slop)
+ : client_(client),
+ tap_timeout_(tap_timeout),
+ tap_slop_(tap_slop),
+ response_pending_input_event_(INPUT_EVENT_TYPE_NONE),
+ start_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
+ end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
+ is_insertion_active_(false),
+ activate_insertion_automatically_(false),
+ is_selection_active_(false),
+ activate_selection_automatically_(false),
+ selection_empty_(false),
+ selection_editable_(false),
+ temporarily_hidden_(false) {
+ DCHECK(client_);
+ HideAndDisallowShowingAutomatically();
+}
+
+TouchSelectionController::~TouchSelectionController() {
+}
+
+void TouchSelectionController::OnSelectionBoundsChanged(
+ const cc::ViewportSelectionBound& start,
+ const cc::ViewportSelectionBound& end) {
+ if (!activate_selection_automatically_ &&
+ !activate_insertion_automatically_) {
+ DCHECK_EQ(INPUT_EVENT_TYPE_NONE, response_pending_input_event_);
+ return;
+ }
+
+ if (start == start_ && end_ == end)
+ return;
+
+ start_ = start;
+ end_ = end;
+ start_orientation_ = ToTouchHandleOrientation(start_.type);
+ end_orientation_ = ToTouchHandleOrientation(end_.type);
+
+ // Ensure that |response_pending_input_event_| is cleared after the method
+ // completes, while also making its current value available for the duration
+ // of the call.
+ InputEventType causal_input_event = response_pending_input_event_;
+ response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
+ base::AutoReset<InputEventType> auto_reset_response_pending_input_event(
+ &response_pending_input_event_, causal_input_event);
+
+ const bool is_selection_dragging =
+ is_selection_active_ && (start_selection_handle_->is_dragging() ||
+ end_selection_handle_->is_dragging());
+
+ // It's possible that the bounds temporarily overlap while a selection handle
+ // is being dragged, incorrectly reporting a CENTER orientation.
+ // TODO(jdduke): This safeguard is racy, as it's possible the delayed response
+ // from handle positioning occurs *after* the handle dragging has ceased.
+ // Instead, prevent selection -> insertion transitions without an intervening
+ // action or selection clearing of some sort, crbug.com/392696.
+ if (is_selection_dragging) {
+ if (start_orientation_ == TOUCH_HANDLE_CENTER)
+ start_orientation_ = start_selection_handle_->orientation();
+ if (end_orientation_ == TOUCH_HANDLE_CENTER)
+ end_orientation_ = end_selection_handle_->orientation();
+ }
+
+ if (GetStartPosition() != GetEndPosition() ||
+ (is_selection_dragging &&
+ start_orientation_ != TOUCH_HANDLE_ORIENTATION_UNDEFINED &&
+ end_orientation_ != TOUCH_HANDLE_ORIENTATION_UNDEFINED)) {
+ OnSelectionChanged();
+ return;
+ }
+
+ if (start_orientation_ == TOUCH_HANDLE_CENTER && selection_editable_) {
+ OnInsertionChanged();
+ return;
+ }
+
+ HideAndDisallowShowingAutomatically();
+}
+
+bool TouchSelectionController::WillHandleTouchEvent(
+ const ui::MotionEvent& event) {
+ if (is_insertion_active_) {
+ DCHECK(insertion_handle_);
+ return insertion_handle_->WillHandleTouchEvent(event);
+ }
+
+ if (is_selection_active_) {
+ DCHECK(start_selection_handle_);
+ DCHECK(end_selection_handle_);
+ if (start_selection_handle_->is_dragging())
+ return start_selection_handle_->WillHandleTouchEvent(event);
+
+ if (end_selection_handle_->is_dragging())
+ return end_selection_handle_->WillHandleTouchEvent(event);
+
+ const gfx::PointF event_pos(event.GetX(), event.GetY());
+ if ((event_pos - GetStartPosition()).LengthSquared() <=
+ (event_pos - GetEndPosition()).LengthSquared())
+ return start_selection_handle_->WillHandleTouchEvent(event);
+ else
+ return end_selection_handle_->WillHandleTouchEvent(event);
+ }
+
+ return false;
+}
+
+void TouchSelectionController::OnLongPressEvent() {
+ response_pending_input_event_ = LONG_PRESS;
+ ShowSelectionHandlesAutomatically();
+ ShowInsertionHandleAutomatically();
+ ResetCachedValuesIfInactive();
+}
+
+void TouchSelectionController::OnTapEvent() {
+ response_pending_input_event_ = TAP;
+ ShowInsertionHandleAutomatically();
+ if (selection_empty_)
+ DeactivateInsertion();
+ ResetCachedValuesIfInactive();
+}
+
+void TouchSelectionController::HideAndDisallowShowingAutomatically() {
+ response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
+ DeactivateInsertion();
+ DeactivateSelection();
+ activate_insertion_automatically_ = false;
+ activate_selection_automatically_ = false;
+}
+
+void TouchSelectionController::SetTemporarilyHidden(bool hidden) {
+ if (temporarily_hidden_ == hidden)
+ return;
+ temporarily_hidden_ = hidden;
+
+ TouchHandle::AnimationStyle animation_style = GetAnimationStyle(true);
+ if (is_selection_active_) {
+ start_selection_handle_->SetVisible(GetStartVisible(), animation_style);
+ end_selection_handle_->SetVisible(GetEndVisible(), animation_style);
+ }
+ if (is_insertion_active_)
+ insertion_handle_->SetVisible(GetStartVisible(), animation_style);
+}
+
+void TouchSelectionController::OnSelectionEditable(bool editable) {
+ if (selection_editable_ == editable)
+ return;
+ selection_editable_ = editable;
+ ResetCachedValuesIfInactive();
+ if (!selection_editable_)
+ DeactivateInsertion();
+}
+
+void TouchSelectionController::OnSelectionEmpty(bool empty) {
+ if (selection_empty_ == empty)
+ return;
+ selection_empty_ = empty;
+ ResetCachedValuesIfInactive();
+}
+
+bool TouchSelectionController::Animate(base::TimeTicks frame_time) {
+ if (is_insertion_active_)
+ return insertion_handle_->Animate(frame_time);
+
+ if (is_selection_active_) {
+ bool needs_animate = start_selection_handle_->Animate(frame_time);
+ needs_animate |= end_selection_handle_->Animate(frame_time);
+ return needs_animate;
+ }
+
+ return false;
+}
+
+void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) {
+ if (&handle == insertion_handle_.get()) {
+ client_->OnSelectionEvent(INSERTION_DRAG_STARTED, handle.position());
+ return;
+ }
+
+ gfx::PointF base, extent;
+ if (&handle == start_selection_handle_.get()) {
+ base = end_selection_handle_->position() + GetEndLineOffset();
+ extent = start_selection_handle_->position() + GetStartLineOffset();
+ } else {
+ base = start_selection_handle_->position() + GetStartLineOffset();
+ extent = end_selection_handle_->position() + GetEndLineOffset();
+ }
+
+ // When moving the handle we want to move only the extent point. Before doing
+ // so we must make sure that the base point is set correctly.
+ client_->SelectBetweenCoordinates(base, extent);
+
+ client_->OnSelectionEvent(SELECTION_DRAG_STARTED, handle.position());
+}
+
+void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle,
+ const gfx::PointF& position) {
+ // As the position corresponds to the bottom left point of the selection
+ // bound, offset it by half the corresponding line height.
+ gfx::Vector2dF line_offset = &handle == end_selection_handle_.get()
+ ? GetStartLineOffset()
+ : GetEndLineOffset();
+ gfx::PointF line_position = position + line_offset;
+ if (&handle == insertion_handle_.get()) {
+ client_->MoveCaret(line_position);
+ } else {
+ client_->MoveRangeSelectionExtent(line_position);
+ }
+}
+
+void TouchSelectionController::OnHandleDragEnd(const TouchHandle& handle) {
+ if (&handle != insertion_handle_.get())
+ client_->OnSelectionEvent(SELECTION_DRAG_STOPPED, handle.position());
+}
+
+void TouchSelectionController::OnHandleTapped(const TouchHandle& handle) {
+ if (insertion_handle_ && &handle == insertion_handle_.get())
+ client_->OnSelectionEvent(INSERTION_TAPPED, handle.position());
+}
+
+void TouchSelectionController::SetNeedsAnimate() {
+ client_->SetNeedsAnimate();
+}
+
+scoped_ptr<TouchHandleDrawable> TouchSelectionController::CreateDrawable() {
+ return client_->CreateDrawable();
+}
+
+base::TimeDelta TouchSelectionController::GetTapTimeout() const {
+ return tap_timeout_;
+}
+
+float TouchSelectionController::GetTapSlop() const {
+ return tap_slop_;
+}
+
+void TouchSelectionController::ShowInsertionHandleAutomatically() {
+ if (activate_insertion_automatically_)
+ return;
+ activate_insertion_automatically_ = true;
+ ResetCachedValuesIfInactive();
+}
+
+void TouchSelectionController::ShowSelectionHandlesAutomatically() {
+ if (activate_selection_automatically_)
+ return;
+ activate_selection_automatically_ = true;
+ ResetCachedValuesIfInactive();
+}
+
+void TouchSelectionController::OnInsertionChanged() {
+ DeactivateSelection();
+
+ if (response_pending_input_event_ == TAP && selection_empty_) {
+ HideAndDisallowShowingAutomatically();
+ return;
+ }
+
+ if (!activate_insertion_automatically_)
+ return;
+
+ const bool was_active = is_insertion_active_;
+ const gfx::PointF position = GetStartPosition();
+ if (!is_insertion_active_)
+ ActivateInsertion();
+ else
+ client_->OnSelectionEvent(INSERTION_MOVED, position);
+
+ insertion_handle_->SetVisible(GetStartVisible(),
+ GetAnimationStyle(was_active));
+ insertion_handle_->SetPosition(position);
+}
+
+void TouchSelectionController::OnSelectionChanged() {
+ DeactivateInsertion();
+
+ if (!activate_selection_automatically_)
+ return;
+
+ const bool was_active = is_selection_active_;
+ ActivateSelection();
+
+ const TouchHandle::AnimationStyle animation = GetAnimationStyle(was_active);
+ start_selection_handle_->SetVisible(GetStartVisible(), animation);
+ end_selection_handle_->SetVisible(GetEndVisible(), animation);
+
+ start_selection_handle_->SetPosition(GetStartPosition());
+ end_selection_handle_->SetPosition(GetEndPosition());
+}
+
+void TouchSelectionController::ActivateInsertion() {
+ DCHECK(!is_selection_active_);
+
+ if (!insertion_handle_)
+ insertion_handle_.reset(new TouchHandle(this, TOUCH_HANDLE_CENTER));
+
+ if (!is_insertion_active_) {
+ is_insertion_active_ = true;
+ insertion_handle_->SetEnabled(true);
+ client_->OnSelectionEvent(INSERTION_SHOWN, GetStartPosition());
+ }
+}
+
+void TouchSelectionController::DeactivateInsertion() {
+ if (!is_insertion_active_)
+ return;
+ DCHECK(insertion_handle_);
+ is_insertion_active_ = false;
+ insertion_handle_->SetEnabled(false);
+ client_->OnSelectionEvent(INSERTION_CLEARED, gfx::PointF());
+}
+
+void TouchSelectionController::ActivateSelection() {
+ DCHECK(!is_insertion_active_);
+
+ if (!start_selection_handle_) {
+ start_selection_handle_.reset(new TouchHandle(this, start_orientation_));
+ } else {
+ start_selection_handle_->SetEnabled(true);
+ start_selection_handle_->SetOrientation(start_orientation_);
+ }
+
+ if (!end_selection_handle_) {
+ end_selection_handle_.reset(new TouchHandle(this, end_orientation_));
+ } else {
+ end_selection_handle_->SetEnabled(true);
+ end_selection_handle_->SetOrientation(end_orientation_);
+ }
+
+ // As a long press received while a selection is already active may trigger
+ // an entirely new selection, notify the client but avoid sending an
+ // intervening SELECTION_CLEARED update to avoid unnecessary state changes.
+ if (!is_selection_active_ || response_pending_input_event_ == LONG_PRESS) {
+ is_selection_active_ = true;
+ response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
+ client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition());
+ }
+}
+
+void TouchSelectionController::DeactivateSelection() {
+ if (!is_selection_active_)
+ return;
+ DCHECK(start_selection_handle_);
+ DCHECK(end_selection_handle_);
+ start_selection_handle_->SetEnabled(false);
+ end_selection_handle_->SetEnabled(false);
+ is_selection_active_ = false;
+ client_->OnSelectionEvent(SELECTION_CLEARED, gfx::PointF());
+}
+
+void TouchSelectionController::ResetCachedValuesIfInactive() {
+ if (is_selection_active_ || is_insertion_active_)
+ return;
+ start_ = cc::ViewportSelectionBound();
+ end_ = cc::ViewportSelectionBound();
+ start_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED;
+ end_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED;
+}
+
+const gfx::PointF& TouchSelectionController::GetStartPosition() const {
+ return start_.edge_bottom;
+}
+
+const gfx::PointF& TouchSelectionController::GetEndPosition() const {
+ return end_.edge_bottom;
+}
+
+gfx::Vector2dF TouchSelectionController::GetStartLineOffset() const {
+ return gfx::ScaleVector2d(start_.edge_top - start_.edge_bottom, 0.5f);
+}
+
+gfx::Vector2dF TouchSelectionController::GetEndLineOffset() const {
+ return gfx::ScaleVector2d(end_.edge_top - end_.edge_bottom, 0.5f);
+}
+
+bool TouchSelectionController::GetStartVisible() const {
+ return start_.visible && !temporarily_hidden_;
+}
+
+bool TouchSelectionController::GetEndVisible() const {
+ return end_.visible && !temporarily_hidden_;
+}
+
+TouchHandle::AnimationStyle TouchSelectionController::GetAnimationStyle(
+ bool was_active) const {
+ return was_active && client_->SupportsAnimation()
+ ? TouchHandle::ANIMATION_SMOOTH
+ : TouchHandle::ANIMATION_NONE;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touch_selection_controller.h b/chromium/content/browser/renderer_host/input/touch_selection_controller.h
new file mode 100644
index 00000000000..abe4ed46fac
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/touch_selection_controller.h
@@ -0,0 +1,150 @@
+// 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_RENDERER_HOST_INPUT_TOUCH_SELECTION_CONTROLLER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_SELECTION_CONTROLLER_H_
+
+#include "cc/output/viewport_selection_bound.h"
+#include "content/browser/renderer_host/input/selection_event_type.h"
+#include "content/browser/renderer_host/input/touch_handle.h"
+#include "content/common/content_export.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace blink {
+class WebInputEvent;
+}
+
+namespace ui {
+class MotionEvent;
+}
+
+namespace content {
+
+// Interface through which |TouchSelectionController| issues selection-related
+// commands, notifications and requests.
+class CONTENT_EXPORT TouchSelectionControllerClient {
+ public:
+ virtual ~TouchSelectionControllerClient() {}
+
+ virtual bool SupportsAnimation() const = 0;
+ virtual void SetNeedsAnimate() = 0;
+ virtual void MoveCaret(const gfx::PointF& position) = 0;
+ virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) = 0;
+ virtual void SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) = 0;
+ virtual void OnSelectionEvent(SelectionEventType event,
+ const gfx::PointF& position) = 0;
+ virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() = 0;
+};
+
+// Controller for manipulating text selection via touch input.
+class CONTENT_EXPORT TouchSelectionController : public TouchHandleClient {
+ public:
+ TouchSelectionController(TouchSelectionControllerClient* client,
+ base::TimeDelta tap_timeout,
+ float tap_slop);
+ ~TouchSelectionController() override;
+
+ // To be called when the selection bounds have changed.
+ // Note that such updates will trigger handle updates only if preceded
+ // by an appropriate call to allow automatic showing.
+ void OnSelectionBoundsChanged(const cc::ViewportSelectionBound& start,
+ const cc::ViewportSelectionBound& end);
+
+ // Allows touch-dragging of the handle.
+ // Returns true iff the event was consumed, in which case the caller should
+ // cease further handling of the event.
+ bool WillHandleTouchEvent(const ui::MotionEvent& event);
+
+ // To be called before forwarding a tap event. This allows automatically
+ // showing the insertion handle from subsequent bounds changes.
+ void OnTapEvent();
+
+ // To be called before forwarding a longpress event. This allows automatically
+ // showing the selection or insertion handles from subsequent bounds changes.
+ void OnLongPressEvent();
+
+ // Hide the handles and suppress bounds updates until the next explicit
+ // showing allowance.
+ void HideAndDisallowShowingAutomatically();
+
+ // Override the handle visibility according to |hidden|.
+ void SetTemporarilyHidden(bool hidden);
+
+ // To be called when the editability of the focused region changes.
+ void OnSelectionEditable(bool editable);
+
+ // To be called when the contents of the focused region changes.
+ void OnSelectionEmpty(bool empty);
+
+ // Ticks an active animation, as requested to the client by |SetNeedsAnimate|.
+ // Returns true if an animation is active and requires further ticking.
+ bool Animate(base::TimeTicks animate_time);
+
+ private:
+ enum InputEventType { TAP, LONG_PRESS, INPUT_EVENT_TYPE_NONE };
+
+ // TouchHandleClient implementation.
+ void OnHandleDragBegin(const TouchHandle& handle) override;
+ void OnHandleDragUpdate(const TouchHandle& handle,
+ const gfx::PointF& new_position) override;
+ void OnHandleDragEnd(const TouchHandle& handle) override;
+ void OnHandleTapped(const TouchHandle& handle) override;
+ void SetNeedsAnimate() override;
+ scoped_ptr<TouchHandleDrawable> CreateDrawable() override;
+ base::TimeDelta GetTapTimeout() const override;
+ float GetTapSlop() const override;
+
+ void ShowInsertionHandleAutomatically();
+ void ShowSelectionHandlesAutomatically();
+
+ void OnInsertionChanged();
+ void OnSelectionChanged();
+
+ void ActivateInsertion();
+ void DeactivateInsertion();
+ void ActivateSelection();
+ void DeactivateSelection();
+ void ResetCachedValuesIfInactive();
+
+ const gfx::PointF& GetStartPosition() const;
+ const gfx::PointF& GetEndPosition() const;
+ gfx::Vector2dF GetStartLineOffset() const;
+ gfx::Vector2dF GetEndLineOffset() const;
+ bool GetStartVisible() const;
+ bool GetEndVisible() const;
+ TouchHandle::AnimationStyle GetAnimationStyle(bool was_active) const;
+
+ TouchSelectionControllerClient* const client_;
+ const base::TimeDelta tap_timeout_;
+ const float tap_slop_;
+
+ InputEventType response_pending_input_event_;
+
+ cc::ViewportSelectionBound start_;
+ cc::ViewportSelectionBound end_;
+ TouchHandleOrientation start_orientation_;
+ TouchHandleOrientation end_orientation_;
+
+ scoped_ptr<TouchHandle> insertion_handle_;
+ bool is_insertion_active_;
+ bool activate_insertion_automatically_;
+
+ scoped_ptr<TouchHandle> start_selection_handle_;
+ scoped_ptr<TouchHandle> end_selection_handle_;
+ bool is_selection_active_;
+ bool activate_selection_automatically_;
+
+ bool selection_empty_;
+ bool selection_editable_;
+
+ bool temporarily_hidden_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchSelectionController);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_SELECTION_CONTROLLER_H_
diff --git a/chromium/content/browser/renderer_host/input/touch_selection_controller_unittest.cc b/chromium/content/browser/renderer_host/input/touch_selection_controller_unittest.cc
new file mode 100644
index 00000000000..de7d620ff97
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/touch_selection_controller_unittest.cc
@@ -0,0 +1,810 @@
+// 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/renderer_host/input/touch_selection_controller.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/test/motion_event_test_utils.h"
+
+using ui::test::MockMotionEvent;
+
+namespace content {
+namespace {
+
+const int kDefaultTapTimeoutMs = 200;
+const float kDefaulTapSlop = 10.f;
+
+class MockTouchHandleDrawable : public TouchHandleDrawable {
+ public:
+ explicit MockTouchHandleDrawable(bool* contains_point)
+ : intersects_rect_(contains_point) {}
+ ~MockTouchHandleDrawable() override {}
+ void SetEnabled(bool enabled) override {}
+ void SetOrientation(TouchHandleOrientation orientation) override {}
+ void SetAlpha(float alpha) override {}
+ void SetFocus(const gfx::PointF& position) override {}
+ void SetVisible(bool visible) override {}
+ bool IntersectsWith(const gfx::RectF& rect) const override {
+ return *intersects_rect_;
+ }
+
+ private:
+ bool* intersects_rect_;
+};
+
+} // namespace
+
+class TouchSelectionControllerTest : public testing::Test,
+ public TouchSelectionControllerClient {
+ public:
+ TouchSelectionControllerTest()
+ : last_event_(SELECTION_CLEARED),
+ caret_moved_(false),
+ selection_moved_(false),
+ selection_points_swapped_(false),
+ needs_animate_(false),
+ animation_enabled_(true),
+ dragging_enabled_(false) {}
+
+ ~TouchSelectionControllerTest() override {}
+
+ // testing::Test implementation.
+ void SetUp() override {
+ controller_.reset(new TouchSelectionController(
+ this,
+ base::TimeDelta::FromMilliseconds(kDefaultTapTimeoutMs),
+ kDefaulTapSlop));
+ }
+
+ void TearDown() override { controller_.reset(); }
+
+ // TouchSelectionControllerClient implementation.
+
+ bool SupportsAnimation() const override { return animation_enabled_; }
+
+ void SetNeedsAnimate() override { needs_animate_ = true; }
+
+ void MoveCaret(const gfx::PointF& position) override {
+ caret_moved_ = true;
+ caret_position_ = position;
+ }
+
+ void SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) override {
+ if (base == selection_end_ && extent == selection_start_)
+ selection_points_swapped_ = true;
+
+ selection_start_ = base;
+ selection_end_ = extent;
+ }
+
+ virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) override {
+ selection_moved_ = true;
+ selection_end_ = extent;
+ }
+
+ void OnSelectionEvent(SelectionEventType event,
+ const gfx::PointF& end_position) override {
+ last_event_ = event;
+ last_event_start_ = end_position;
+ }
+
+ scoped_ptr<TouchHandleDrawable> CreateDrawable() override {
+ return scoped_ptr<TouchHandleDrawable>(
+ new MockTouchHandleDrawable(&dragging_enabled_));
+ }
+
+ void SetAnimationEnabled(bool enabled) { animation_enabled_ = enabled; }
+ void SetDraggingEnabled(bool enabled) { dragging_enabled_ = enabled; }
+
+ void ClearSelection() {
+ controller_->OnSelectionBoundsChanged(cc::ViewportSelectionBound(),
+ cc::ViewportSelectionBound());
+ }
+
+ void ClearInsertion() { ClearSelection(); }
+
+ void ChangeInsertion(const gfx::RectF& rect, bool visible) {
+ cc::ViewportSelectionBound bound;
+ bound.type = cc::SELECTION_BOUND_CENTER;
+ bound.edge_top = rect.origin();
+ bound.edge_bottom = rect.bottom_left();
+ bound.visible = visible;
+ controller_->OnSelectionBoundsChanged(bound, bound);
+ }
+
+ void ChangeSelection(const gfx::RectF& start_rect,
+ bool start_visible,
+ const gfx::RectF& end_rect,
+ bool end_visible) {
+ cc::ViewportSelectionBound start_bound, end_bound;
+ start_bound.type = cc::SELECTION_BOUND_LEFT;
+ end_bound.type = cc::SELECTION_BOUND_RIGHT;
+ start_bound.edge_top = start_rect.origin();
+ start_bound.edge_bottom = start_rect.bottom_left();
+ end_bound.edge_top = end_rect.origin();
+ end_bound.edge_bottom = end_rect.bottom_left();
+ start_bound.visible = start_visible;
+ end_bound.visible = end_visible;
+ controller_->OnSelectionBoundsChanged(start_bound, end_bound);
+ }
+
+ void Animate() {
+ base::TimeTicks now = base::TimeTicks::Now();
+ while (needs_animate_) {
+ needs_animate_ = controller_->Animate(now);
+ now += base::TimeDelta::FromMilliseconds(16);
+ }
+ }
+
+ bool GetAndResetNeedsAnimate() {
+ bool needs_animate = needs_animate_;
+ Animate();
+ return needs_animate;
+ }
+
+ bool GetAndResetCaretMoved() {
+ bool moved = caret_moved_;
+ caret_moved_ = false;
+ return moved;
+ }
+
+ bool GetAndResetSelectionMoved() {
+ bool moved = selection_moved_;
+ selection_moved_ = false;
+ return moved;
+ }
+
+ bool GetAndResetSelectionPointsSwapped() {
+ bool swapped = selection_points_swapped_;
+ selection_points_swapped_ = false;
+ return swapped;
+ }
+
+ const gfx::PointF& GetLastCaretPosition() const { return caret_position_; }
+ const gfx::PointF& GetLastSelectionStart() const { return selection_start_; }
+ const gfx::PointF& GetLastSelectionEnd() const { return selection_end_; }
+ SelectionEventType GetLastEventType() const { return last_event_; }
+ const gfx::PointF& GetLastEventAnchor() const { return last_event_start_; }
+
+ TouchSelectionController& controller() { return *controller_; }
+
+ private:
+ gfx::PointF last_event_start_;
+ gfx::PointF caret_position_;
+ gfx::PointF selection_start_;
+ gfx::PointF selection_end_;
+ SelectionEventType last_event_;
+ bool caret_moved_;
+ bool selection_moved_;
+ bool selection_points_swapped_;
+ bool needs_animate_;
+ bool animation_enabled_;
+ bool dragging_enabled_;
+ scoped_ptr<TouchSelectionController> controller_;
+};
+
+TEST_F(TouchSelectionControllerTest, InsertionBasic) {
+ gfx::RectF insertion_rect(5, 5, 0, 10);
+ bool visible = true;
+
+ // Insertion events are ignored until automatic showing is enabled.
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
+ controller().OnTapEvent();
+
+ // Insertion events are ignored until the selection region is marked editable.
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
+
+ controller().OnTapEvent();
+ controller().OnSelectionEditable(true);
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
+
+ insertion_rect.Offset(1, 0);
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
+ EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
+
+ insertion_rect.Offset(0, 1);
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
+ EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
+
+ ClearInsertion();
+ EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
+}
+
+TEST_F(TouchSelectionControllerTest, InsertionClearedWhenNoLongerEditable) {
+ gfx::RectF insertion_rect(5, 5, 0, 10);
+ bool visible = true;
+ controller().OnTapEvent();
+ controller().OnSelectionEditable(true);
+
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
+
+ controller().OnSelectionEditable(false);
+ EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
+}
+
+TEST_F(TouchSelectionControllerTest, InsertionStaysHiddenIfEmptyRegionTapped) {
+ gfx::RectF insertion_rect(5, 5, 0, 10);
+ bool visible = true;
+ controller().OnSelectionEditable(true);
+
+ // Taps should be ignored if they're in an empty editable region.
+ controller().OnTapEvent();
+ controller().OnSelectionEmpty(true);
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
+
+ // Once the region becomes editable, taps should show the insertion handle.
+ controller().OnTapEvent();
+ controller().OnSelectionEmpty(false);
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
+
+ // Reset the selection.
+ controller().HideAndDisallowShowingAutomatically();
+ EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
+
+ // Long-pressing should show the handle even if the editable region is empty.
+ insertion_rect.Offset(2, -2);
+ controller().OnLongPressEvent();
+ controller().OnSelectionEmpty(true);
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
+
+ // Single Tap on an empty edit field should clear insertion handle.
+ controller().OnTapEvent();
+ EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
+}
+
+TEST_F(TouchSelectionControllerTest, InsertionAppearsAfterTapFollowingTyping) {
+ gfx::RectF insertion_rect(5, 5, 0, 10);
+ bool visible = true;
+
+ // Simulate the user tapping an empty text field.
+ controller().OnTapEvent();
+ controller().OnSelectionEditable(true);
+ controller().OnSelectionEmpty(true);
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
+
+ // Simulate the cursor moving while a user is typing.
+ insertion_rect.Offset(10, 0);
+ controller().OnSelectionEmpty(false);
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
+
+ // If the user taps the *same* position as the cursor at the end of the text
+ // entry, the handle should appear.
+ controller().OnTapEvent();
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(insertion_rect.bottom_left(), GetLastEventAnchor());
+}
+
+TEST_F(TouchSelectionControllerTest, InsertionToSelectionTransition) {
+ controller().OnLongPressEvent();
+ controller().OnSelectionEditable(true);
+
+ gfx::RectF start_rect(5, 5, 0, 10);
+ gfx::RectF end_rect(50, 5, 0, 10);
+ bool visible = true;
+
+ ChangeInsertion(start_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ ChangeInsertion(end_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
+
+ controller().HideAndDisallowShowingAutomatically();
+ EXPECT_EQ(INSERTION_CLEARED, GetLastEventType());
+
+ controller().OnTapEvent();
+ ChangeInsertion(end_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(end_rect.bottom_left(), GetLastEventAnchor());
+}
+
+TEST_F(TouchSelectionControllerTest, InsertionDragged) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ controller().OnTapEvent();
+ controller().OnSelectionEditable(true);
+
+ // The touch sequence should not be handled if insertion is not active.
+ MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_FALSE(controller().WillHandleTouchEvent(event));
+
+ float line_height = 10.f;
+ gfx::RectF start_rect(10, 0, 0, line_height);
+ bool visible = true;
+ ChangeInsertion(start_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ // The touch sequence should be handled only if the drawable reports a hit.
+ EXPECT_FALSE(controller().WillHandleTouchEvent(event));
+ SetDraggingEnabled(true);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetCaretMoved());
+
+ // The MoveCaret() result should reflect the movement.
+ // The reported position is offset from the center of |start_rect|.
+ gfx::PointF start_offset = start_rect.CenterPoint();
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetCaretMoved());
+ EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastCaretPosition());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetCaretMoved());
+ EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastCaretPosition());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 10);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetCaretMoved());
+ EXPECT_EQ(start_offset + gfx::Vector2dF(10, 10), GetLastCaretPosition());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetCaretMoved());
+
+ // Once the drag is complete, no more touch events should be consumed until
+ // the next ACTION_DOWN.
+ EXPECT_FALSE(controller().WillHandleTouchEvent(event));
+}
+
+TEST_F(TouchSelectionControllerTest, InsertionTapped) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ controller().OnTapEvent();
+ controller().OnSelectionEditable(true);
+ SetDraggingEnabled(true);
+
+ gfx::RectF start_rect(10, 0, 0, 10);
+ bool visible = true;
+ ChangeInsertion(start_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+
+ MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ //TODO(AKV): this test case has to be modified once crbug.com/394093 is fixed.
+ EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
+
+ // Reset the insertion.
+ ClearInsertion();
+ controller().OnTapEvent();
+ ChangeInsertion(start_rect, visible);
+ ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
+
+ // No tap should be signalled if the time between DOWN and UP was too long.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP,
+ event_time + base::TimeDelta::FromSeconds(1),
+ 0,
+ 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
+
+ // Reset the insertion.
+ ClearInsertion();
+ controller().OnTapEvent();
+ ChangeInsertion(start_rect, visible);
+ ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
+
+ // No tap should be signalled if the drag was too long.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 100, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 100, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
+
+ // Reset the insertion.
+ ClearInsertion();
+ controller().OnTapEvent();
+ ChangeInsertion(start_rect, visible);
+ ASSERT_EQ(INSERTION_SHOWN, GetLastEventType());
+
+ // No tap should be signalled if the touch sequence is cancelled.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ event = MockMotionEvent(MockMotionEvent::ACTION_CANCEL, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
+}
+
+TEST_F(TouchSelectionControllerTest, InsertionNotResetByRepeatedTapOrPress) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ controller().OnTapEvent();
+ controller().OnSelectionEditable(true);
+ SetDraggingEnabled(true);
+
+ gfx::RectF anchor_rect(10, 0, 0, 10);
+ bool visible = true;
+ ChangeInsertion(anchor_rect, visible);
+ EXPECT_EQ(INSERTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
+
+ // Tapping again shouldn't reset the active insertion point.
+ controller().OnTapEvent();
+ MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
+ EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
+ EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
+
+ anchor_rect.Offset(5, 15);
+ ChangeInsertion(anchor_rect, visible);
+ EXPECT_EQ(INSERTION_MOVED, GetLastEventType());
+ EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
+
+ // Pressing shouldn't reset the active insertion point.
+ controller().OnLongPressEvent();
+ controller().OnSelectionEmpty(true);
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(INSERTION_DRAG_STARTED, GetLastEventType());
+ EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(INSERTION_TAPPED, GetLastEventType());
+ EXPECT_EQ(anchor_rect.bottom_left(), GetLastEventAnchor());
+}
+
+TEST_F(TouchSelectionControllerTest, SelectionBasic) {
+ gfx::RectF start_rect(5, 5, 0, 10);
+ gfx::RectF end_rect(50, 5, 0, 10);
+ bool visible = true;
+
+ // Selection events are ignored until automatic showing is enabled.
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
+
+ controller().OnLongPressEvent();
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ start_rect.Offset(1, 0);
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ // Selection movement does not currently trigger a separate event.
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+
+ ClearSelection();
+ EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
+ EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
+}
+
+TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
+ gfx::RectF start_rect(5, 5, 0, 10);
+ gfx::RectF end_rect(50, 5, 0, 10);
+ bool visible = true;
+
+ controller().OnLongPressEvent();
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ // A long press triggering a new selection should re-send the SELECTION_SHOWN
+ // event notification.
+ start_rect.Offset(10, 10);
+ controller().OnLongPressEvent();
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+}
+
+TEST_F(TouchSelectionControllerTest, SelectionDragged) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ controller().OnLongPressEvent();
+
+ // The touch sequence should not be handled if selection is not active.
+ MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time, 0, 0);
+ EXPECT_FALSE(controller().WillHandleTouchEvent(event));
+
+ float line_height = 10.f;
+ gfx::RectF start_rect(0, 0, 0, line_height);
+ gfx::RectF end_rect(50, 0, 0, line_height);
+ bool visible = true;
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ // The touch sequence should be handled only if the drawable reports a hit.
+ EXPECT_FALSE(controller().WillHandleTouchEvent(event));
+ SetDraggingEnabled(true);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+
+ // The SelectBetweenCoordinates() result should reflect the movement. Note
+ // that the start coordinate will always reflect the "fixed" handle's
+ // position, in this case the position from |end_rect|.
+ // Note that the reported position is offset from the center of the
+ // input rects (i.e., the middle of the corresponding text line).
+ gfx::PointF fixed_offset = end_rect.CenterPoint();
+ gfx::PointF start_offset = start_rect.CenterPoint();
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_EQ(fixed_offset, GetLastSelectionStart());
+ EXPECT_EQ(start_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 5, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_EQ(fixed_offset, GetLastSelectionStart());
+ EXPECT_EQ(start_offset + gfx::Vector2dF(5, 5), GetLastSelectionEnd());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_EQ(fixed_offset, GetLastSelectionStart());
+ EXPECT_EQ(start_offset + gfx::Vector2dF(10, 5), GetLastSelectionEnd());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+
+ // Once the drag is complete, no more touch events should be consumed until
+ // the next ACTION_DOWN.
+ EXPECT_FALSE(controller().WillHandleTouchEvent(event));
+}
+
+TEST_F(TouchSelectionControllerTest, SelectionDraggedWithOverlap) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ controller().OnLongPressEvent();
+
+ float line_height = 10.f;
+ gfx::RectF start_rect(0, 0, 0, line_height);
+ gfx::RectF end_rect(50, 0, 0, line_height);
+ bool visible = true;
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ // The ACTION_DOWN should lock to the closest handle.
+ gfx::PointF end_offset = end_rect.CenterPoint();
+ gfx::PointF fixed_offset = start_rect.CenterPoint();
+ float touch_down_x = (end_offset.x() + fixed_offset.x()) / 2 + 1.f;
+ MockMotionEvent event(
+ MockMotionEvent::ACTION_DOWN, event_time, touch_down_x, 0);
+ SetDraggingEnabled(true);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+
+ // Even though the ACTION_MOVE is over the start handle, it should continue
+ // targetting the end handle that consumed the ACTION_DOWN.
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_EQ(fixed_offset, GetLastSelectionStart());
+ EXPECT_EQ(end_offset - gfx::Vector2dF(touch_down_x, 0),
+ GetLastSelectionEnd());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 0, 0);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+}
+
+TEST_F(TouchSelectionControllerTest, SelectionDraggedToSwitchBaseAndExtent) {
+ base::TimeTicks event_time = base::TimeTicks::Now();
+ controller().OnLongPressEvent();
+
+ float line_height = 10.f;
+ gfx::RectF start_rect(50, line_height, 0, line_height);
+ gfx::RectF end_rect(100, line_height, 0, line_height);
+ bool visible = true;
+ ChangeSelection(start_rect, visible, end_rect, visible);
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ SetDraggingEnabled(true);
+
+ // Move the extent, not triggering a swap of points.
+ MockMotionEvent event(MockMotionEvent::ACTION_DOWN, event_time,
+ end_rect.x(), end_rect.bottom());
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+ EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
+
+ gfx::PointF base_offset = start_rect.CenterPoint();
+ gfx::PointF extent_offset = end_rect.CenterPoint();
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
+ end_rect.x(), end_rect.bottom() + 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
+ EXPECT_EQ(base_offset, GetLastSelectionStart());
+ EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+
+ end_rect += gfx::Vector2dF(0, 5);
+ ChangeSelection(start_rect, visible, end_rect, visible);
+
+ // Move the base, triggering a swap of points.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
+ start_rect.x(), start_rect.bottom());
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+ EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
+
+ base_offset = end_rect.CenterPoint();
+ extent_offset = start_rect.CenterPoint();
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
+ start_rect.x(), start_rect.bottom() + 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
+ EXPECT_EQ(base_offset, GetLastSelectionStart());
+ EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+
+ start_rect += gfx::Vector2dF(0, 5);
+ ChangeSelection(start_rect, visible, end_rect, visible);
+
+ // Move the same point again, not triggering a swap of points.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
+ start_rect.x(), start_rect.bottom());
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+ EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
+
+ base_offset = end_rect.CenterPoint();
+ extent_offset = start_rect.CenterPoint();
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
+ start_rect.x(), start_rect.bottom() + 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
+ EXPECT_EQ(base_offset, GetLastSelectionStart());
+ EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+
+ start_rect += gfx::Vector2dF(0, 5);
+ ChangeSelection(start_rect, visible, end_rect, visible);
+
+ // Move the base, triggering a swap of points.
+ event = MockMotionEvent(MockMotionEvent::ACTION_DOWN, event_time,
+ end_rect.x(), end_rect.bottom());
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+ EXPECT_TRUE(GetAndResetSelectionPointsSwapped());
+
+ base_offset = start_rect.CenterPoint();
+ extent_offset = end_rect.CenterPoint();
+ event = MockMotionEvent(MockMotionEvent::ACTION_MOVE, event_time,
+ end_rect.x(), end_rect.bottom() + 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STARTED, GetLastEventType());
+ EXPECT_TRUE(GetAndResetSelectionMoved());
+ EXPECT_FALSE(GetAndResetSelectionPointsSwapped());
+ EXPECT_EQ(base_offset, GetLastSelectionStart());
+ EXPECT_EQ(extent_offset + gfx::Vector2dF(0, 5), GetLastSelectionEnd());
+
+ event = MockMotionEvent(MockMotionEvent::ACTION_UP, event_time, 10, 5);
+ EXPECT_TRUE(controller().WillHandleTouchEvent(event));
+ EXPECT_EQ(SELECTION_DRAG_STOPPED, GetLastEventType());
+ EXPECT_FALSE(GetAndResetSelectionMoved());
+}
+
+TEST_F(TouchSelectionControllerTest, Animation) {
+ controller().OnTapEvent();
+ controller().OnSelectionEditable(true);
+
+ gfx::RectF insertion_rect(5, 5, 0, 10);
+
+ bool visible = true;
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_FALSE(GetAndResetNeedsAnimate());
+
+ visible = false;
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_TRUE(GetAndResetNeedsAnimate());
+
+ visible = true;
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_TRUE(GetAndResetNeedsAnimate());
+
+ // If the handles are explicity hidden, no animation should be triggered.
+ controller().HideAndDisallowShowingAutomatically();
+ EXPECT_FALSE(GetAndResetNeedsAnimate());
+
+ // If the client doesn't support animation, no animation should be triggered.
+ SetAnimationEnabled(false);
+ controller().OnTapEvent();
+ visible = true;
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_FALSE(GetAndResetNeedsAnimate());
+}
+
+TEST_F(TouchSelectionControllerTest, TemporarilyHidden) {
+ controller().OnTapEvent();
+ controller().OnSelectionEditable(true);
+
+ gfx::RectF insertion_rect(5, 5, 0, 10);
+
+ bool visible = true;
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_FALSE(GetAndResetNeedsAnimate());
+
+ controller().SetTemporarilyHidden(true);
+ EXPECT_TRUE(GetAndResetNeedsAnimate());
+
+ visible = false;
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_FALSE(GetAndResetNeedsAnimate());
+
+ visible = true;
+ ChangeInsertion(insertion_rect, visible);
+ EXPECT_FALSE(GetAndResetNeedsAnimate());
+
+ controller().SetTemporarilyHidden(false);
+ EXPECT_TRUE(GetAndResetNeedsAnimate());
+}
+
+TEST_F(TouchSelectionControllerTest, SelectionClearOnTap) {
+ gfx::RectF start_rect(5, 5, 0, 10);
+ gfx::RectF end_rect(50, 5, 0, 10);
+ bool visible = true;
+
+ controller().OnLongPressEvent();
+ ChangeSelection(start_rect, visible, end_rect, visible);
+
+ // Selection should not be cleared if the selection bounds have not changed.
+ controller().OnTapEvent();
+ EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+ EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+ controller().OnTapEvent();
+ ClearSelection();
+ EXPECT_EQ(SELECTION_CLEARED, GetLastEventType());
+ EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h b/chromium/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h
index da74dfd6538..64e5d472e6f 100644
--- a/chromium/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h
+++ b/chromium/content/browser/renderer_host/input/touchpad_tap_suppression_controller.h
@@ -30,7 +30,7 @@ class TouchpadTapSuppressionController : public TapSuppressionControllerClient {
TouchpadTapSuppressionController(
TouchpadTapSuppressionControllerClient* client,
const TapSuppressionController::Config& config);
- virtual ~TouchpadTapSuppressionController();
+ ~TouchpadTapSuppressionController() override;
// Should be called on arrival of GestureFlingCancel events.
void GestureFlingCancel();
@@ -52,8 +52,8 @@ class TouchpadTapSuppressionController : public TapSuppressionControllerClient {
friend class MockRenderWidgetHost;
// TapSuppressionControllerClient implementation.
- virtual void DropStashedTapDown() OVERRIDE;
- virtual void ForwardStashedTapDown() OVERRIDE;
+ void DropStashedTapDown() override;
+ void ForwardStashedTapDown() override;
TouchpadTapSuppressionControllerClient* client_;
MouseEventWithLatencyInfo stashed_mouse_down_;
diff --git a/chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h b/chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h
index 706e9d8610e..35ff274356f 100644
--- a/chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h
+++ b/chromium/content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h
@@ -22,7 +22,7 @@ class TouchscreenTapSuppressionController
TouchscreenTapSuppressionController(
GestureEventQueue* geq,
const TapSuppressionController::Config& config);
- virtual ~TouchscreenTapSuppressionController();
+ ~TouchscreenTapSuppressionController() override;
// Should be called on arrival of GestureFlingCancel events.
void GestureFlingCancel();
@@ -37,8 +37,8 @@ class TouchscreenTapSuppressionController
private:
// TapSuppressionControllerClient implementation.
- virtual void DropStashedTapDown() OVERRIDE;
- virtual void ForwardStashedTapDown() OVERRIDE;
+ void DropStashedTapDown() override;
+ void ForwardStashedTapDown() override;
GestureEventQueue* gesture_event_queue_;
diff --git a/chromium/content/browser/renderer_host/input/web_input_event_builders_win.cc b/chromium/content/browser/renderer_host/input/web_input_event_builders_win.cc
index 19e8fc61771..73c9174bfe4 100644
--- a/chromium/content/browser/renderer_host/input/web_input_event_builders_win.cc
+++ b/chromium/content/browser/renderer_host/input/web_input_event_builders_win.cc
@@ -160,7 +160,9 @@ WebKeyboardEvent WebKeyboardEventBuilder::Build(HWND hwnd,
// NOTE: There doesn't seem to be a way to query the mouse button state in
// this case.
- if (LOWORD(lparam) > 1)
+ // Bit 30 of lParam represents the "previous key state". If set, the key was
+ // already down, therefore this is an auto-repeat.
+ if (lparam & 0x40000000)
result.modifiers |= WebInputEvent::IsAutoRepeat;
result.modifiers |= GetLocationModifier(wparam, lparam);
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 524cf001431..81fc359e63c 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
@@ -2,10 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// MSVC++ requires this to be set before any other includes to get M_PI.
+#define _USE_MATH_DEFINES
+
#include "content/browser/renderer_host/input/web_input_event_util.h"
+#include <cmath>
+
#include "base/strings/string_util.h"
#include "content/common/input/web_touch_event_traits.h"
+#include "ui/events/event_constants.h"
#include "ui/events/gesture_detection/gesture_event_data.h"
#include "ui/events/gesture_detection/motion_event.h"
@@ -188,7 +194,42 @@ WebTouchPoint CreateWebTouchPoint(const MotionEvent& event,
touch.position.y = event.GetY(pointer_index);
touch.screenPosition.x = event.GetRawX(pointer_index);
touch.screenPosition.y = event.GetRawY(pointer_index);
- touch.radiusX = touch.radiusY = event.GetTouchMajor(pointer_index) * 0.5f;
+
+ // A note on touch ellipse specifications:
+ //
+ // Android MotionEvent provides the major and minor axes of the touch ellipse,
+ // as well as the orientation of the major axis clockwise from vertical, in
+ // radians. See:
+ // http://developer.android.com/reference/android/view/MotionEvent.html
+ //
+ // The proposed extension to W3C Touch Events specifies the touch ellipse
+ // using two radii along x- & y-axes and a positive acute rotation angle in
+ // degrees. See:
+ // http://dvcs.w3.org/hg/webevents/raw-file/default/touchevents.html
+
+ float major_radius = event.GetTouchMajor(pointer_index) / 2.f;
+ float minor_radius = event.GetTouchMinor(pointer_index) / 2.f;
+ float orientation_deg = event.GetOrientation(pointer_index) * 180.f / M_PI;
+ DCHECK_GE(major_radius, 0);
+ DCHECK_GE(minor_radius, 0);
+ DCHECK_GE(major_radius, minor_radius);
+ // Allow a small bound tolerance to account for floating point conversion.
+ DCHECK_GT(orientation_deg, -90.01f);
+ DCHECK_LT(orientation_deg, 90.01f);
+ if (orientation_deg >= 0) {
+ // The case orientation_deg == 0 is handled here on purpose: although the
+ // 'else' block is equivalent in this case, we want to pass the 0 value
+ // unchanged (and 0 is the default value for many devices that don't
+ // report elliptical touches).
+ touch.radiusX = minor_radius;
+ touch.radiusY = major_radius;
+ touch.rotationAngle = orientation_deg;
+ } else {
+ touch.radiusX = major_radius;
+ touch.radiusY = minor_radius;
+ touch.rotationAngle = orientation_deg + 90;
+ }
+
touch.force = event.GetPressure(pointer_index);
return touch;
@@ -215,6 +256,10 @@ void UpdateWindowsKeyCodeAndKeyIdentifier(blink::WebKeyboardEvent* event,
blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
const ui::MotionEvent& event) {
+ COMPILE_ASSERT(static_cast<int>(MotionEvent::MAX_TOUCH_POINT_COUNT) ==
+ static_cast<int>(blink::WebTouchEvent::touchesLengthCap),
+ inconsistent_maximum_number_of_active_touch_points);
+
blink::WebTouchEvent result;
WebTouchEventTraits::ResetType(
@@ -222,6 +267,7 @@ blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
(event.GetEventTime() - base::TimeTicks()).InSecondsF(),
&result);
+ result.modifiers = EventFlagsToWebEventModifiers(event.GetFlags());
result.touchesLength =
std::min(event.GetPointerCount(),
static_cast<size_t>(WebTouchEvent::touchesLengthCap));
@@ -236,6 +282,7 @@ blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
WebGestureEvent CreateWebGestureEventFromGestureEventData(
const ui::GestureEventData& data) {
WebGestureEvent gesture;
+ gesture.modifiers = EventFlagsToWebEventModifiers(data.flags);
gesture.x = data.x;
gesture.y = data.y;
gesture.globalX = data.raw_x;
@@ -332,4 +379,60 @@ WebGestureEvent CreateWebGestureEventFromGestureEventData(
return gesture;
}
+int EventFlagsToWebEventModifiers(int flags) {
+ int modifiers = 0;
+
+ if (flags & ui::EF_SHIFT_DOWN)
+ modifiers |= blink::WebInputEvent::ShiftKey;
+ if (flags & ui::EF_CONTROL_DOWN)
+ modifiers |= blink::WebInputEvent::ControlKey;
+ if (flags & ui::EF_ALT_DOWN)
+ modifiers |= blink::WebInputEvent::AltKey;
+ if (flags & ui::EF_COMMAND_DOWN)
+ modifiers |= blink::WebInputEvent::MetaKey;
+
+ if (flags & ui::EF_LEFT_MOUSE_BUTTON)
+ modifiers |= blink::WebInputEvent::LeftButtonDown;
+ if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
+ modifiers |= blink::WebInputEvent::MiddleButtonDown;
+ if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
+ modifiers |= blink::WebInputEvent::RightButtonDown;
+ if (flags & ui::EF_CAPS_LOCK_DOWN)
+ modifiers |= blink::WebInputEvent::CapsLockOn;
+ if (flags & ui::EF_IS_REPEAT)
+ modifiers |= blink::WebInputEvent::IsAutoRepeat;
+ if (flags & ui::EF_NUMPAD_KEY)
+ modifiers |= blink::WebInputEvent::IsKeyPad;
+
+ return modifiers;
+}
+
+int WebEventModifiersToEventFlags(int modifiers) {
+ int flags = 0;
+
+ if (modifiers & blink::WebInputEvent::ShiftKey)
+ flags |= ui::EF_SHIFT_DOWN;
+ if (modifiers & blink::WebInputEvent::ControlKey)
+ flags |= ui::EF_CONTROL_DOWN;
+ if (modifiers & blink::WebInputEvent::AltKey)
+ flags |= ui::EF_ALT_DOWN;
+ if (modifiers & blink::WebInputEvent::MetaKey)
+ flags |= ui::EF_COMMAND_DOWN;
+
+ if (modifiers & blink::WebInputEvent::LeftButtonDown)
+ flags |= ui::EF_LEFT_MOUSE_BUTTON;
+ if (modifiers & blink::WebInputEvent::MiddleButtonDown)
+ flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
+ if (modifiers & blink::WebInputEvent::RightButtonDown)
+ flags |= ui::EF_RIGHT_MOUSE_BUTTON;
+ if (modifiers & blink::WebInputEvent::CapsLockOn)
+ flags |= ui::EF_CAPS_LOCK_DOWN;
+ if (modifiers & blink::WebInputEvent::IsAutoRepeat)
+ flags |= ui::EF_IS_REPEAT;
+ if (modifiers & blink::WebInputEvent::IsKeyPad)
+ flags |= ui::EF_NUMPAD_KEY;
+
+ return flags;
+}
+
} // 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 4143a1cbce4..1cadd7d0050 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
@@ -32,6 +32,10 @@ CONTENT_EXPORT blink::WebTouchEvent CreateWebTouchEventFromMotionEvent(
CONTENT_EXPORT blink::WebGestureEvent CreateWebGestureEventFromGestureEventData(
const ui::GestureEventData& data);
+int EventFlagsToWebEventModifiers(int flags);
+
+int WebEventModifiersToEventFlags(int modifiers);
+
} // 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
new file mode 100644
index 00000000000..1d29a070c17
--- /dev/null
+++ b/chromium/content/browser/renderer_host/input/web_input_event_util_unittest.cc
@@ -0,0 +1,61 @@
+// 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.
+
+// Needed on Windows to get |M_PI| from <cmath>.
+#ifdef _WIN32
+#define _USE_MATH_DEFINES
+#endif
+
+#include <cmath>
+
+#include "content/browser/renderer_host/input/web_input_event_util.h"
+#include "content/common/input/web_input_event_traits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/gesture_detection/motion_event_generic.h"
+
+using blink::WebInputEvent;
+using blink::WebTouchEvent;
+using blink::WebTouchPoint;
+using ui::MotionEvent;
+using ui::MotionEventGeneric;
+
+namespace content {
+
+TEST(WebInputEventUtilTest, MotionEventConversion) {
+ ui::PointerProperties pointer(5, 10, 40);
+ pointer.id = 15;
+ pointer.raw_x = 20;
+ pointer.raw_y = 25;
+ pointer.pressure = 30;
+ pointer.touch_minor = 35;
+ pointer.orientation = static_cast<float>(-M_PI / 2);
+ MotionEventGeneric event(
+ MotionEvent::ACTION_DOWN, base::TimeTicks::Now(), pointer);
+ event.set_flags(ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
+
+ WebTouchEvent expected_event;
+ expected_event.type = WebInputEvent::TouchStart;
+ expected_event.touchesLength = 1;
+ expected_event.timeStampSeconds =
+ (event.GetEventTime() - base::TimeTicks()).InSecondsF();
+ expected_event.modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
+ WebTouchPoint expected_pointer;
+ expected_pointer.id = pointer.id;
+ expected_pointer.state = WebTouchPoint::StatePressed;
+ expected_pointer.position = blink::WebFloatPoint(pointer.x, pointer.y);
+ expected_pointer.screenPosition =
+ blink::WebFloatPoint(pointer.raw_x, pointer.raw_y);
+ expected_pointer.radiusX = pointer.touch_major / 2.f;
+ expected_pointer.radiusY = pointer.touch_minor / 2.f;
+ expected_pointer.rotationAngle = 0.f;
+ expected_pointer.force = pointer.pressure;
+ expected_event.touches[0] = expected_pointer;
+
+ WebTouchEvent actual_event = CreateWebTouchEventFromMotionEvent(event);
+ EXPECT_EQ(WebInputEventTraits::ToString(expected_event),
+ WebInputEventTraits::ToString(actual_event));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/java/DEPS b/chromium/content/browser/renderer_host/java/DEPS
deleted file mode 100644
index 05512435883..00000000000
--- a/chromium/content/browser/renderer_host/java/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+content/child", # For java bridge bindings
- "+third_party/WebKit/public/web/WebBindings.h", # For java bridge bindings
-]
diff --git a/chromium/content/browser/renderer_host/java/java_bound_object.cc b/chromium/content/browser/renderer_host/java/java_bound_object.cc
deleted file mode 100644
index f812c429683..00000000000
--- a/chromium/content/browser/renderer_host/java/java_bound_object.cc
+++ /dev/null
@@ -1,1040 +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/renderer_host/java/java_bound_object.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/memory/singleton.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h"
-#include "content/browser/renderer_host/java/java_type.h"
-#include "content/browser/renderer_host/java/jni_helper.h"
-#include "content/public/browser/browser_thread.h"
-#include "third_party/WebKit/public/web/WebBindings.h"
-
-using base::StringPrintf;
-using base::android::AttachCurrentThread;
-using base::android::ConvertUTF8ToJavaString;
-using base::android::GetClass;
-using base::android::JavaRef;
-using base::android::ScopedJavaGlobalRef;
-using base::android::ScopedJavaLocalRef;
-using blink::WebBindings;
-
-// The conversion between JavaScript and Java types is based on the Live
-// Connect 2 spec. See
-// http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS.
-
-// Note that in some cases, we differ from from the spec in order to maintain
-// existing behavior. These areas are marked LIVECONNECT_COMPLIANCE. We may
-// revisit this decision in the future.
-
-namespace content {
-namespace {
-
-const char kJavaLangClass[] = "java/lang/Class";
-const char kJavaLangObject[] = "java/lang/Object";
-const char kJavaLangReflectMethod[] = "java/lang/reflect/Method";
-const char kJavaLangSecurityExceptionClass[] = "java/lang/SecurityException";
-const char kGetClass[] = "getClass";
-const char kGetMethods[] = "getMethods";
-const char kIsAnnotationPresent[] = "isAnnotationPresent";
-const char kReturningJavaLangClass[] = "()Ljava/lang/Class;";
-const char kReturningJavaLangReflectMethodArray[] =
- "()[Ljava/lang/reflect/Method;";
-const char kTakesJavaLangClassReturningBoolean[] = "(Ljava/lang/Class;)Z";
-// This is an exception message, so no need to localize.
-const char kAccessToObjectGetClassIsBlocked[] =
- "Access to java.lang.Object.getClass is blocked";
-
-// Our special NPObject type. We extend an NPObject with a pointer to a
-// JavaBoundObject. We also add static methods for each of the NPObject
-// callbacks, which are registered by our NPClass. These methods simply
-// delegate to the private implementation methods of JavaBoundObject.
-struct JavaNPObject : public NPObject {
- JavaBoundObject* bound_object;
-
- static const NPClass kNPClass;
-
- static NPObject* Allocate(NPP npp, NPClass* np_class);
- static void Deallocate(NPObject* np_object);
- static bool HasMethod(NPObject* np_object, NPIdentifier np_identifier);
- static bool Invoke(NPObject* np_object, NPIdentifier np_identifier,
- const NPVariant *args, uint32_t arg_count,
- NPVariant *result);
- static bool HasProperty(NPObject* np_object, NPIdentifier np_identifier);
- static bool GetProperty(NPObject* np_object, NPIdentifier np_identifier,
- NPVariant *result);
- static bool Enumerate(NPObject* object, NPIdentifier** values,
- uint32_t* count);
-};
-
-const NPClass JavaNPObject::kNPClass = {
- NP_CLASS_STRUCT_VERSION,
- JavaNPObject::Allocate,
- JavaNPObject::Deallocate,
- NULL, // NPInvalidate
- JavaNPObject::HasMethod,
- JavaNPObject::Invoke,
- NULL, // NPInvokeDefault
- JavaNPObject::HasProperty,
- JavaNPObject::GetProperty,
- NULL, // NPSetProperty,
- NULL, // NPRemoveProperty
- JavaNPObject::Enumerate,
- NULL,
-};
-
-NPObject* JavaNPObject::Allocate(NPP npp, NPClass* np_class) {
- JavaNPObject* obj = new JavaNPObject();
- return obj;
-}
-
-void JavaNPObject::Deallocate(NPObject* np_object) {
- JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
- delete obj->bound_object;
- delete obj;
-}
-
-bool JavaNPObject::HasMethod(NPObject* np_object, NPIdentifier np_identifier) {
- std::string name(WebBindings::utf8FromIdentifier(np_identifier));
- JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
- return obj->bound_object->HasMethod(name);
-}
-
-bool JavaNPObject::Invoke(NPObject* np_object, NPIdentifier np_identifier,
- const NPVariant* args, uint32_t arg_count,
- NPVariant* result) {
- std::string name(WebBindings::utf8FromIdentifier(np_identifier));
- JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
- return obj->bound_object->Invoke(name, args, arg_count, result);
-}
-
-bool JavaNPObject::HasProperty(NPObject* np_object,
- NPIdentifier np_identifier) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return false to indicate
- // that the property is not present. Spec requires supporting this correctly.
- return false;
-}
-
-bool JavaNPObject::GetProperty(NPObject* np_object,
- NPIdentifier np_identifier,
- NPVariant* result) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return false to indicate
- // that the property is undefined. Spec requires supporting this correctly.
- return false;
-}
-
-bool JavaNPObject::Enumerate(NPObject* np_object, NPIdentifier** values,
- uint32_t* count) {
- JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
- if (!obj->bound_object->CanEnumerateMethods()) return false;
- std::vector<std::string> method_names = obj->bound_object->GetMethodNames();
- *count = base::saturated_cast<uint32_t>(method_names.size());
- *values = static_cast<NPIdentifier*>(calloc(*count, sizeof(NPIdentifier)));
- for (uint32_t i = 0; i < *count; ++i) {
- (*values)[i] = WebBindings::getStringIdentifier(method_names[i].c_str());
- }
- return true;
-}
-
-// Calls a Java method through JNI. If the Java method raises an uncaught
-// exception, it is cleared and this method returns false. Otherwise, this
-// method returns true and the Java method's return value is provided as an
-// NPVariant. Note that this method does not do any type coercion. The Java
-// return value is simply converted to the corresponding NPAPI type.
-bool CallJNIMethod(
- jobject object,
- jclass clazz,
- const JavaType& return_type,
- jmethodID id,
- jvalue* parameters,
- NPVariant* result,
- const JavaRef<jclass>& safe_annotation_clazz,
- const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager,
- bool can_enumerate_methods) {
- DCHECK(object || clazz);
- JNIEnv* env = AttachCurrentThread();
- switch (return_type.type) {
- case JavaType::TypeBoolean:
- BOOLEAN_TO_NPVARIANT(
- object ? env->CallBooleanMethodA(object, id, parameters)
- : env->CallStaticBooleanMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeByte:
- INT32_TO_NPVARIANT(
- object ? env->CallByteMethodA(object, id, parameters)
- : env->CallStaticByteMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeChar:
- INT32_TO_NPVARIANT(
- object ? env->CallCharMethodA(object, id, parameters)
- : env->CallStaticCharMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeShort:
- INT32_TO_NPVARIANT(
- object ? env->CallShortMethodA(object, id, parameters)
- : env->CallStaticShortMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeInt:
- INT32_TO_NPVARIANT(object
- ? env->CallIntMethodA(object, id, parameters)
- : env->CallStaticIntMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeLong:
- DOUBLE_TO_NPVARIANT(
- object ? env->CallLongMethodA(object, id, parameters)
- : env->CallStaticLongMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeFloat:
- DOUBLE_TO_NPVARIANT(
- object ? env->CallFloatMethodA(object, id, parameters)
- : env->CallStaticFloatMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeDouble:
- DOUBLE_TO_NPVARIANT(
- object ? env->CallDoubleMethodA(object, id, parameters)
- : env->CallStaticDoubleMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeVoid:
- if (object)
- env->CallVoidMethodA(object, id, parameters);
- else
- env->CallStaticVoidMethodA(clazz, id, parameters);
- VOID_TO_NPVARIANT(*result);
- break;
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to not call methods that
- // return arrays. Spec requires calling the method and converting the
- // result to a JavaScript array.
- VOID_TO_NPVARIANT(*result);
- break;
- case JavaType::TypeString: {
- jstring java_string = static_cast<jstring>(
- object ? env->CallObjectMethodA(object, id, parameters)
- : env->CallStaticObjectMethodA(clazz, id, parameters));
- // If an exception was raised, we must clear it before calling most JNI
- // methods. ScopedJavaLocalRef is liable to make such calls, so we test
- // first.
- if (base::android::ClearException(env)) {
- return false;
- }
- ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string);
- if (!scoped_java_string.obj()) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined.
- // Spec requires returning a null string.
- VOID_TO_NPVARIANT(*result);
- break;
- }
- std::string str =
- base::android::ConvertJavaStringToUTF8(scoped_java_string);
- size_t length = str.length();
- // This pointer is freed in _NPN_ReleaseVariantValue in
- // third_party/WebKit/Source/WebCore/bindings/v8/npruntime.cpp.
- char* buffer = static_cast<char*>(malloc(length));
- str.copy(buffer, length, 0);
- STRINGN_TO_NPVARIANT(buffer, length, *result);
- break;
- }
- case JavaType::TypeObject: {
- // If an exception was raised, we must clear it before calling most JNI
- // methods. ScopedJavaLocalRef is liable to make such calls, so we test
- // first.
- jobject java_object =
- object ? env->CallObjectMethodA(object, id, parameters)
- : env->CallStaticObjectMethodA(clazz, id, parameters);
- if (base::android::ClearException(env)) {
- return false;
- }
- ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object);
- if (!scoped_java_object.obj()) {
- NULL_TO_NPVARIANT(*result);
- break;
- }
- OBJECT_TO_NPVARIANT(JavaBoundObject::Create(scoped_java_object,
- safe_annotation_clazz,
- manager,
- can_enumerate_methods),
- *result);
- break;
- }
- }
- return !base::android::ClearException(env);
-}
-
-double RoundDoubleTowardsZero(const double& x) {
- if (std::isnan(x)) {
- return 0.0;
- }
- return x > 0.0 ? floor(x) : ceil(x);
-}
-
-// Rounds to jlong using Java's type conversion rules.
-jlong RoundDoubleToLong(const double& x) {
- double intermediate = RoundDoubleTowardsZero(x);
- // The int64 limits can not be converted exactly to double values, so we
- // compare to custom constants. kint64max is 2^63 - 1, but the spacing
- // between double values in the the range 2^62 to 2^63 is 2^10. The cast is
- // required to silence a spurious gcc warning for integer overflow.
- const int64 limit = (GG_INT64_C(1) << 63) - static_cast<uint64>(1 << 10);
- DCHECK(limit > 0);
- const double kLargestDoubleLessThanInt64Max = limit;
- const double kSmallestDoubleGreaterThanInt64Min = -limit;
- if (intermediate > kLargestDoubleLessThanInt64Max) {
- return kint64max;
- }
- if (intermediate < kSmallestDoubleGreaterThanInt64Min) {
- return kint64min;
- }
- return static_cast<jlong>(intermediate);
-}
-
-// Rounds to jint using Java's type conversion rules.
-jint RoundDoubleToInt(const double& x) {
- double intermediate = RoundDoubleTowardsZero(x);
- // The int32 limits cast exactly to double values.
- intermediate = std::min(intermediate, static_cast<double>(kint32max));
- intermediate = std::max(intermediate, static_cast<double>(kint32min));
- return static_cast<jint>(intermediate);
-}
-
-jvalue CoerceJavaScriptNumberToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES.
-
- // For conversion to numeric types, we need to replicate Java's type
- // conversion rules. This requires that for integer values, we simply discard
- // all but the lowest n buts, where n is the number of bits in the target
- // type. For double values, the logic is more involved.
- jvalue result;
- DCHECK(variant.type == NPVariantType_Int32 ||
- variant.type == NPVariantType_Double);
- bool is_double = variant.type == NPVariantType_Double;
- switch (target_type.type) {
- case JavaType::TypeByte:
- result.b = is_double ?
- static_cast<jbyte>(RoundDoubleToInt(NPVARIANT_TO_DOUBLE(variant))) :
- static_cast<jbyte>(NPVARIANT_TO_INT32(variant));
- break;
- case JavaType::TypeChar:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert double to 0.
- // Spec requires converting doubles similarly to how we convert doubles to
- // other numeric types.
- result.c = is_double ? 0 :
- static_cast<jchar>(NPVARIANT_TO_INT32(variant));
- break;
- case JavaType::TypeShort:
- result.s = is_double ?
- static_cast<jshort>(RoundDoubleToInt(NPVARIANT_TO_DOUBLE(variant))) :
- static_cast<jshort>(NPVARIANT_TO_INT32(variant));
- break;
- case JavaType::TypeInt:
- result.i = is_double ? RoundDoubleToInt(NPVARIANT_TO_DOUBLE(variant)) :
- NPVARIANT_TO_INT32(variant);
- break;
- case JavaType::TypeLong:
- result.j = is_double ? RoundDoubleToLong(NPVARIANT_TO_DOUBLE(variant)) :
- NPVARIANT_TO_INT32(variant);
- break;
- case JavaType::TypeFloat:
- result.f = is_double ? static_cast<jfloat>(NPVARIANT_TO_DOUBLE(variant)) :
- NPVARIANT_TO_INT32(variant);
- break;
- case JavaType::TypeDouble:
- result.d = is_double ? NPVARIANT_TO_DOUBLE(variant) :
- NPVARIANT_TO_INT32(variant);
- break;
- case JavaType::TypeObject:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
- // requires handling object equivalents of primitive types.
- result.l = NULL;
- break;
- case JavaType::TypeString:
- result.l = coerce_to_string ?
- ConvertUTF8ToJavaString(
- AttachCurrentThread(),
- is_double ?
- base::StringPrintf("%.6lg", NPVARIANT_TO_DOUBLE(variant)) :
- base::Int64ToString(NPVARIANT_TO_INT32(variant))).Release() :
- NULL;
- break;
- case JavaType::TypeBoolean:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
- // requires converting to false for 0 or NaN, true otherwise.
- result.z = JNI_FALSE;
- break;
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-jvalue CoerceJavaScriptBooleanToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES.
- DCHECK_EQ(NPVariantType_Bool, variant.type);
- bool boolean_value = NPVARIANT_TO_BOOLEAN(variant);
- jvalue result;
- switch (target_type.type) {
- case JavaType::TypeBoolean:
- result.z = boolean_value ? JNI_TRUE : JNI_FALSE;
- break;
- case JavaType::TypeObject:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires handling java.lang.Boolean and java.lang.Object.
- result.l = NULL;
- break;
- case JavaType::TypeString:
- result.l = coerce_to_string ?
- ConvertUTF8ToJavaString(AttachCurrentThread(),
- boolean_value ? "true" : "false").Release() :
- NULL;
- break;
- case JavaType::TypeByte:
- case JavaType::TypeChar:
- case JavaType::TypeShort:
- case JavaType::TypeInt:
- case JavaType::TypeLong:
- case JavaType::TypeFloat:
- case JavaType::TypeDouble: {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
- // requires converting to 0 or 1.
- jvalue null_value = {0};
- result = null_value;
- break;
- }
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-jvalue CoerceJavaScriptStringToJavaValue(const NPVariant& variant,
- const JavaType& target_type) {
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES.
- DCHECK_EQ(NPVariantType_String, variant.type);
- jvalue result;
- switch (target_type.type) {
- case JavaType::TypeString:
- result.l = ConvertUTF8ToJavaString(
- AttachCurrentThread(),
- base::StringPiece(NPVARIANT_TO_STRING(variant).UTF8Characters,
- NPVARIANT_TO_STRING(variant).UTF8Length)).Release();
- break;
- case JavaType::TypeObject:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires handling java.lang.Object.
- result.l = NULL;
- break;
- case JavaType::TypeByte:
- case JavaType::TypeShort:
- case JavaType::TypeInt:
- case JavaType::TypeLong:
- case JavaType::TypeFloat:
- case JavaType::TypeDouble: {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
- // requires using valueOf() method of corresponding object type.
- jvalue null_value = {0};
- result = null_value;
- break;
- }
- case JavaType::TypeChar:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
- // requires using java.lang.Short.decode().
- result.c = 0;
- break;
- case JavaType::TypeBoolean:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
- // requires converting the empty string to false, otherwise true.
- result.z = JNI_FALSE;
- break;
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-// Note that this only handles primitive types and strings.
-jobject CreateJavaArray(const JavaType& type, jsize length) {
- JNIEnv* env = AttachCurrentThread();
- switch (type.type) {
- case JavaType::TypeBoolean:
- return env->NewBooleanArray(length);
- case JavaType::TypeByte:
- return env->NewByteArray(length);
- case JavaType::TypeChar:
- return env->NewCharArray(length);
- case JavaType::TypeShort:
- return env->NewShortArray(length);
- case JavaType::TypeInt:
- return env->NewIntArray(length);
- case JavaType::TypeLong:
- return env->NewLongArray(length);
- case JavaType::TypeFloat:
- return env->NewFloatArray(length);
- case JavaType::TypeDouble:
- return env->NewDoubleArray(length);
- case JavaType::TypeString: {
- ScopedJavaLocalRef<jclass> clazz(GetClass(env, "java/lang/String"));
- return env->NewObjectArray(length, clazz.obj(), NULL);
- }
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- case JavaType::TypeArray:
- case JavaType::TypeObject:
- // Not handled.
- NOTREACHED();
- }
- return NULL;
-}
-
-// Sets the specified element of the supplied array to the value of the
-// supplied jvalue. Requires that the type of the array matches that of the
-// jvalue. Handles only primitive types and strings. Note that in the case of a
-// string, the array takes a new reference to the string object.
-void SetArrayElement(jobject array,
- const JavaType& type,
- jsize index,
- const jvalue& value) {
- JNIEnv* env = AttachCurrentThread();
- switch (type.type) {
- case JavaType::TypeBoolean:
- env->SetBooleanArrayRegion(static_cast<jbooleanArray>(array), index, 1,
- &value.z);
- break;
- case JavaType::TypeByte:
- env->SetByteArrayRegion(static_cast<jbyteArray>(array), index, 1,
- &value.b);
- break;
- case JavaType::TypeChar:
- env->SetCharArrayRegion(static_cast<jcharArray>(array), index, 1,
- &value.c);
- break;
- case JavaType::TypeShort:
- env->SetShortArrayRegion(static_cast<jshortArray>(array), index, 1,
- &value.s);
- break;
- case JavaType::TypeInt:
- env->SetIntArrayRegion(static_cast<jintArray>(array), index, 1,
- &value.i);
- break;
- case JavaType::TypeLong:
- env->SetLongArrayRegion(static_cast<jlongArray>(array), index, 1,
- &value.j);
- break;
- case JavaType::TypeFloat:
- env->SetFloatArrayRegion(static_cast<jfloatArray>(array), index, 1,
- &value.f);
- break;
- case JavaType::TypeDouble:
- env->SetDoubleArrayRegion(static_cast<jdoubleArray>(array), index, 1,
- &value.d);
- break;
- case JavaType::TypeString:
- env->SetObjectArrayElement(static_cast<jobjectArray>(array), index,
- value.l);
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- case JavaType::TypeArray:
- case JavaType::TypeObject:
- // Not handled.
- NOTREACHED();
- }
- base::android::CheckException(env);
-}
-
-void ReleaseJavaValueIfRequired(JNIEnv* env,
- jvalue* value,
- const JavaType& type) {
- if (type.type == JavaType::TypeString ||
- type.type == JavaType::TypeObject ||
- type.type == JavaType::TypeArray) {
- env->DeleteLocalRef(value->l);
- value->l = NULL;
- }
-}
-
-jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string);
-
-// Returns a new local reference to a Java array.
-jobject CoerceJavaScriptObjectToArray(const NPVariant& variant,
- const JavaType& target_type) {
- DCHECK_EQ(JavaType::TypeArray, target_type.type);
- NPObject* object = NPVARIANT_TO_OBJECT(variant);
- DCHECK_NE(&JavaNPObject::kNPClass, object->_class);
-
- const JavaType& target_inner_type = *target_type.inner_type.get();
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for
- // multi-dimensional arrays. Spec requires handling multi-demensional arrays.
- if (target_inner_type.type == JavaType::TypeArray) {
- return NULL;
- }
-
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for object
- // arrays. Spec requires handling object arrays.
- if (target_inner_type.type == JavaType::TypeObject) {
- return NULL;
- }
-
- // If the object does not have a length property, return null.
- NPVariant length_variant;
- if (!WebBindings::getProperty(0, object,
- WebBindings::getStringIdentifier("length"),
- &length_variant)) {
- WebBindings::releaseVariantValue(&length_variant);
- return NULL;
- }
-
- // If the length property does not have numeric type, or is outside the valid
- // range for a Java array length, return null.
- jsize length = -1;
- if (NPVARIANT_IS_INT32(length_variant)
- && NPVARIANT_TO_INT32(length_variant) >= 0) {
- length = NPVARIANT_TO_INT32(length_variant);
- } else if (NPVARIANT_IS_DOUBLE(length_variant)
- && NPVARIANT_TO_DOUBLE(length_variant) >= 0.0
- && NPVARIANT_TO_DOUBLE(length_variant) <= kint32max) {
- length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(length_variant));
- }
- WebBindings::releaseVariantValue(&length_variant);
- if (length == -1) {
- return NULL;
- }
-
- // Create the Java array.
- // TODO(steveblock): Handle failure to create the array.
- jobject result = CreateJavaArray(target_inner_type, length);
- NPVariant value_variant;
- JNIEnv* env = AttachCurrentThread();
- for (jsize i = 0; i < length; ++i) {
- // It seems that getProperty() will set the variant to type void on failure,
- // but this doesn't seem to be documented, so do it explicitly here for
- // safety.
- VOID_TO_NPVARIANT(value_variant);
- // If this fails, for example due to a missing element, we simply treat the
- // value as JavaScript undefined.
- WebBindings::getProperty(0, object, WebBindings::getIntIdentifier(i),
- &value_variant);
- jvalue element = CoerceJavaScriptValueToJavaValue(value_variant,
- target_inner_type,
- false);
- SetArrayElement(result, target_inner_type, i, element);
- // CoerceJavaScriptValueToJavaValue() creates new local references to
- // strings, objects and arrays. Of these, only strings can occur here.
- // SetArrayElement() causes the array to take its own reference to the
- // string, so we can now release the local reference.
- DCHECK_NE(JavaType::TypeObject, target_inner_type.type);
- DCHECK_NE(JavaType::TypeArray, target_inner_type.type);
- ReleaseJavaValueIfRequired(env, &element, target_inner_type);
- WebBindings::releaseVariantValue(&value_variant);
- }
-
- return result;
-}
-
-jvalue CoerceJavaScriptObjectToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // This covers both JavaScript objects (including arrays) and Java objects.
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_OTHER_OBJECTS,
- // http://jdk6.java.net/plugin2/liveconnect/#JS_ARRAY_VALUES and
- // http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_OBJECTS
- DCHECK_EQ(NPVariantType_Object, variant.type);
-
- NPObject* object = NPVARIANT_TO_OBJECT(variant);
- bool is_java_object = &JavaNPObject::kNPClass == object->_class;
-
- jvalue result;
- switch (target_type.type) {
- case JavaType::TypeObject:
- if (is_java_object) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to pass all Java
- // objects. Spec requires passing only Java objects which are
- // assignment-compatibile.
- result.l = AttachCurrentThread()->NewLocalRef(
- JavaBoundObject::GetJavaObject(object).obj());
- } else {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec
- // requires converting if the target type is
- // netscape.javascript.JSObject, otherwise raising a JavaScript
- // exception.
- result.l = NULL;
- }
- break;
- case JavaType::TypeString:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to
- // "undefined". Spec requires calling toString() on the Java object.
- result.l = coerce_to_string ?
- ConvertUTF8ToJavaString(AttachCurrentThread(), "undefined").
- Release() :
- NULL;
- break;
- case JavaType::TypeByte:
- case JavaType::TypeShort:
- case JavaType::TypeInt:
- case JavaType::TypeLong:
- case JavaType::TypeFloat:
- case JavaType::TypeDouble:
- case JavaType::TypeChar: {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
- // requires raising a JavaScript exception.
- jvalue null_value = {0};
- result = null_value;
- break;
- }
- case JavaType::TypeBoolean:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
- // requires raising a JavaScript exception.
- result.z = JNI_FALSE;
- break;
- case JavaType::TypeArray:
- if (is_java_object) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- } else {
- result.l = CoerceJavaScriptObjectToArray(variant, target_type);
- }
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_NULL.
- DCHECK(variant.type == NPVariantType_Null ||
- variant.type == NPVariantType_Void);
- jvalue result;
- switch (target_type.type) {
- case JavaType::TypeObject:
- result.l = NULL;
- break;
- case JavaType::TypeString:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert undefined to
- // "undefined". Spec requires converting undefined to NULL.
- result.l = (coerce_to_string && variant.type == NPVariantType_Void) ?
- ConvertUTF8ToJavaString(AttachCurrentThread(), "undefined").
- Release() :
- NULL;
- break;
- case JavaType::TypeByte:
- case JavaType::TypeChar:
- case JavaType::TypeShort:
- case JavaType::TypeInt:
- case JavaType::TypeLong:
- case JavaType::TypeFloat:
- case JavaType::TypeDouble: {
- jvalue null_value = {0};
- result = null_value;
- break;
- }
- case JavaType::TypeBoolean:
- result.z = JNI_FALSE;
- break;
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-// coerce_to_string means that we should try to coerce all JavaScript values to
-// strings when required, rather than simply converting to NULL. This is used
-// to maintain current behaviour, which differs slightly depending upon whether
-// or not the coercion in question is for an array element.
-//
-// Note that the jvalue returned by this method may contain a new local
-// reference to an object (string, object or array). This must be released by
-// the caller.
-jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // Note that in all these conversions, the relevant field of the jvalue must
- // always be explicitly set, as jvalue does not initialize its fields.
-
- switch (variant.type) {
- case NPVariantType_Int32:
- case NPVariantType_Double:
- return CoerceJavaScriptNumberToJavaValue(variant, target_type,
- coerce_to_string);
- case NPVariantType_Bool:
- return CoerceJavaScriptBooleanToJavaValue(variant, target_type,
- coerce_to_string);
- case NPVariantType_String:
- return CoerceJavaScriptStringToJavaValue(variant, target_type);
- case NPVariantType_Object:
- return CoerceJavaScriptObjectToJavaValue(variant, target_type,
- coerce_to_string);
- case NPVariantType_Null:
- case NPVariantType_Void:
- return CoerceJavaScriptNullOrUndefinedToJavaValue(variant, target_type,
- coerce_to_string);
- }
- NOTREACHED();
- return jvalue();
-}
-
-} // namespace
-
-NPObject* JavaBoundObject::Create(
- const JavaRef<jobject>& object,
- const JavaRef<jclass>& safe_annotation_clazz,
- const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager,
- bool can_enumerate_methods) {
- // The first argument (a plugin's instance handle) is passed through to the
- // allocate function directly, and we don't use it, so it's ok to be 0.
- // The object is created with a ref count of one.
- NPObject* np_object = WebBindings::createObject(0, const_cast<NPClass*>(
- &JavaNPObject::kNPClass));
- // The NPObject takes ownership of the JavaBoundObject.
- reinterpret_cast<JavaNPObject*>(np_object)->bound_object =
- new JavaBoundObject(
- object, safe_annotation_clazz, manager, can_enumerate_methods);
- return np_object;
-}
-
-JavaBoundObject::JavaBoundObject(
- const JavaRef<jobject>& object,
- const JavaRef<jclass>& safe_annotation_clazz,
- const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager,
- bool can_enumerate_methods)
- : java_object_(AttachCurrentThread(), object.obj()),
- manager_(manager),
- are_methods_set_up_(false),
- object_get_class_method_id_(NULL),
- can_enumerate_methods_(can_enumerate_methods),
- safe_annotation_clazz_(safe_annotation_clazz) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&JavaBridgeDispatcherHostManager::JavaBoundObjectCreated,
- manager_,
- base::android::ScopedJavaGlobalRef<jobject>(object)));
- // Other than informing the JavaBridgeDispatcherHostManager that a java bound
- // object has been created (above), we don't do anything else with our Java
- // object when first created. We do it all lazily when a method is first
- // invoked.
-}
-
-JavaBoundObject::~JavaBoundObject() {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&JavaBridgeDispatcherHostManager::JavaBoundObjectDestroyed,
- manager_,
- base::android::ScopedJavaGlobalRef<jobject>(
- java_object_.get(AttachCurrentThread()))));
-}
-
-ScopedJavaLocalRef<jobject> JavaBoundObject::GetJavaObject(NPObject* object) {
- DCHECK_EQ(&JavaNPObject::kNPClass, object->_class);
- JavaBoundObject* jbo = reinterpret_cast<JavaNPObject*>(object)->bound_object;
- return jbo->java_object_.get(AttachCurrentThread());
-}
-
-std::vector<std::string> JavaBoundObject::GetMethodNames() const {
- EnsureMethodsAreSetUp();
- std::vector<std::string> result;
- for (JavaMethodMap::const_iterator it = methods_.begin();
- it != methods_.end();
- it = methods_.upper_bound(it->first)) {
- result.push_back(it->first);
- }
- return result;
-}
-
-bool JavaBoundObject::HasMethod(const std::string& name) const {
- EnsureMethodsAreSetUp();
- return methods_.find(name) != methods_.end();
-}
-
-bool JavaBoundObject::Invoke(const std::string& name, const NPVariant* args,
- size_t arg_count, NPVariant* result) {
- EnsureMethodsAreSetUp();
-
- // Get all methods with the correct name.
- std::pair<JavaMethodMap::const_iterator, JavaMethodMap::const_iterator>
- iters = methods_.equal_range(name);
- if (iters.first == iters.second) {
- return false;
- }
-
- // Take the first method with the correct number of arguments.
- JavaMethod* method = NULL;
- for (JavaMethodMap::const_iterator iter = iters.first; iter != iters.second;
- ++iter) {
- if (iter->second->num_parameters() == arg_count) {
- method = iter->second.get();
- break;
- }
- }
- if (!method) {
- return false;
- }
-
- // Block access to java.lang.Object.getClass.
- // As it is declared to be final, it is sufficient to compare methodIDs.
- if (method->id() == object_get_class_method_id_) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&JavaBoundObject::ThrowSecurityException,
- kAccessToObjectGetClassIsBlocked));
- return false;
- }
-
- // Coerce
- std::vector<jvalue> parameters(arg_count);
- for (size_t i = 0; i < arg_count; ++i) {
- parameters[i] = CoerceJavaScriptValueToJavaValue(args[i],
- method->parameter_type(i),
- true);
- }
-
- JNIEnv* env = AttachCurrentThread();
-
- ScopedJavaLocalRef<jobject> obj;
- ScopedJavaLocalRef<jclass> cls;
- bool ok = false;
- if (method->is_static()) {
- cls = GetLocalClassRef(env);
- } else {
- obj = java_object_.get(env);
- }
- if (!obj.is_null() || !cls.is_null()) {
- // Call
- ok = CallJNIMethod(obj.obj(), cls.obj(), method->return_type(),
- method->id(), &parameters[0], result,
- safe_annotation_clazz_,
- manager_,
- can_enumerate_methods_);
- }
-
- // Now that we're done with the jvalue, release any local references created
- // by CoerceJavaScriptValueToJavaValue().
- for (size_t i = 0; i < arg_count; ++i) {
- ReleaseJavaValueIfRequired(env, &parameters[i], method->parameter_type(i));
- }
-
- return ok;
-}
-
-ScopedJavaLocalRef<jclass> JavaBoundObject::GetLocalClassRef(
- JNIEnv* env) const {
- if (!object_get_class_method_id_) {
- object_get_class_method_id_ = GetMethodIDFromClassName(
- env, kJavaLangObject, kGetClass, kReturningJavaLangClass);
- }
-
- ScopedJavaLocalRef<jobject> obj = java_object_.get(env);
- if (!obj.is_null()) {
- return ScopedJavaLocalRef<jclass>(env, static_cast<jclass>(
- env->CallObjectMethod(obj.obj(), object_get_class_method_id_)));
- } else {
- return ScopedJavaLocalRef<jclass>();
- }
-}
-
-void JavaBoundObject::EnsureMethodsAreSetUp() const {
- if (are_methods_set_up_)
- return;
- are_methods_set_up_ = true;
-
- JNIEnv* env = AttachCurrentThread();
-
- ScopedJavaLocalRef<jclass> clazz = GetLocalClassRef(env);
- if (clazz.is_null()) {
- return;
- }
-
- ScopedJavaLocalRef<jobjectArray> methods(env, static_cast<jobjectArray>(
- env->CallObjectMethod(clazz.obj(), GetMethodIDFromClassName(
- env,
- kJavaLangClass,
- kGetMethods,
- kReturningJavaLangReflectMethodArray))));
-
- size_t num_methods = env->GetArrayLength(methods.obj());
- // Java objects always have public methods.
- DCHECK(num_methods);
-
- for (size_t i = 0; i < num_methods; ++i) {
- ScopedJavaLocalRef<jobject> java_method(
- env,
- env->GetObjectArrayElement(methods.obj(), i));
-
- if (!safe_annotation_clazz_.is_null()) {
- jboolean safe = env->CallBooleanMethod(java_method.obj(),
- GetMethodIDFromClassName(
- env,
- kJavaLangReflectMethod,
- kIsAnnotationPresent,
- kTakesJavaLangClassReturningBoolean),
- safe_annotation_clazz_.obj());
-
- if (!safe)
- continue;
- }
-
- JavaMethod* method = new JavaMethod(java_method);
- methods_.insert(std::make_pair(method->name(), method));
- }
-}
-
-// static
-void JavaBoundObject::ThrowSecurityException(const char* message) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- JNIEnv* env = AttachCurrentThread();
- base::android::ScopedJavaLocalRef<jclass> clazz(
- env, env->FindClass(kJavaLangSecurityExceptionClass));
- env->ThrowNew(clazz.obj(), message);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/java/java_bound_object.h b/chromium/content/browser/renderer_host/java/java_bound_object.h
deleted file mode 100644
index f29aed6df1b..00000000000
--- a/chromium/content/browser/renderer_host/java/java_bound_object.h
+++ /dev/null
@@ -1,96 +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_JAVA_JAVA_BOUND_OBJECT_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_BOUND_OBJECT_H_
-
-#include <jni.h>
-#include <map>
-#include <string>
-
-#include "base/android/jni_weak_ref.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/memory/linked_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/renderer_host/java/java_method.h"
-#include "third_party/npapi/bindings/npruntime.h"
-
-namespace content {
-
-class JavaBridgeDispatcherHostManager;
-
-// Wrapper around a Java object.
-//
-// Represents a Java object for use in the Java bridge. Holds a global ref to
-// the Java object and provides the ability to invoke methods on it.
-// Interrogation of the Java object for its methods is done lazily. This class
-// is not generally threadsafe. However, it does allow for instances to be
-// created and destroyed on different threads.
-class JavaBoundObject {
- public:
- // Takes a Java object and creates a JavaBoundObject around it. If
- // |safe_annotation_clazz| annotation is non-null, the method is exposed
- // to JavaScript. Returns an NPObject with a ref count of one which owns the
- // JavaBoundObject.
- // See also comment below for |manager_|.
- static NPObject* Create(
- const base::android::JavaRef<jobject>& object,
- const base::android::JavaRef<jclass>& safe_annotation_clazz,
- const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager,
- bool can_enumerate_methods);
-
- virtual ~JavaBoundObject();
-
- // Gets a local ref to the underlying JavaObject from a JavaBoundObject
- // wrapped as an NPObject. May return null if the underlying object has
- // been garbage collected.
- static base::android::ScopedJavaLocalRef<jobject> GetJavaObject(
- NPObject* object);
-
- // Methods to implement the NPObject callbacks.
- bool CanEnumerateMethods() const { return can_enumerate_methods_; }
- std::vector<std::string> GetMethodNames() const;
- bool HasMethod(const std::string& name) const;
- bool Invoke(const std::string& name, const NPVariant* args, size_t arg_count,
- NPVariant* result);
-
- private:
- JavaBoundObject(
- const base::android::JavaRef<jobject>& object,
- const base::android::JavaRef<jclass>& safe_annotation_clazz,
- const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager,
- bool can_enumerate_methods);
-
- void EnsureMethodsAreSetUp() const;
- base::android::ScopedJavaLocalRef<jclass> GetLocalClassRef(JNIEnv* env) const;
-
- static void ThrowSecurityException(const char* message);
-
- // The weak ref to the underlying Java object that this JavaBoundObject
- // instance represents.
- JavaObjectWeakGlobalRef java_object_;
-
- // Keep a pointer back to the JavaBridgeDispatcherHostManager so that we
- // can notify it when this JavaBoundObject is destroyed. JavaBoundObjects
- // may outlive the manager so keep a WeakPtr. Note the WeakPtr may only be
- // dereferenced on the UI thread.
- base::WeakPtr<JavaBridgeDispatcherHostManager> manager_;
-
- // Map of public methods, from method name to Method instance. Multiple
- // entries will be present for overloaded methods. Note that we can't use
- // scoped_ptr in STL containers as we can't copy it.
- typedef std::multimap<std::string, linked_ptr<JavaMethod> > JavaMethodMap;
- mutable JavaMethodMap methods_;
- mutable bool are_methods_set_up_;
- mutable jmethodID object_get_class_method_id_;
- const bool can_enumerate_methods_;
-
- base::android::ScopedJavaGlobalRef<jclass> safe_annotation_clazz_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(JavaBoundObject);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_BOUND_OBJECT_H_
diff --git a/chromium/content/browser/renderer_host/java/java_bridge_channel_host.cc b/chromium/content/browser/renderer_host/java/java_bridge_channel_host.cc
deleted file mode 100644
index 8f53b9d99a8..00000000000
--- a/chromium/content/browser/renderer_host/java/java_bridge_channel_host.cc
+++ /dev/null
@@ -1,95 +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 "content/browser/renderer_host/java/java_bridge_channel_host.h"
-
-#include "base/atomicops.h"
-#include "base/lazy_instance.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/waitable_event.h"
-#include "content/common/java_bridge_messages.h"
-
-using base::WaitableEvent;
-
-namespace content {
-namespace {
-struct WaitableEventLazyInstanceTraits
- : public base::DefaultLazyInstanceTraits<WaitableEvent> {
- static WaitableEvent* New(void* instance) {
- // Use placement new to initialize our instance in our preallocated space.
- // The parenthesis is very important here to force POD type initialization.
- return new (instance) WaitableEvent(false, false);
- }
-};
-base::LazyInstance<WaitableEvent, WaitableEventLazyInstanceTraits> dummy_event =
- LAZY_INSTANCE_INITIALIZER;
-
-base::subtle::AtomicWord g_last_id = 0;
-}
-
-JavaBridgeChannelHost::~JavaBridgeChannelHost() {
-#if defined(OS_POSIX)
- if (channel_handle_.socket.fd > 0) {
- close(channel_handle_.socket.fd);
- }
-#endif
-}
-
-JavaBridgeChannelHost* JavaBridgeChannelHost::GetJavaBridgeChannelHost(
- int renderer_id,
- base::MessageLoopProxy* ipc_message_loop) {
- std::string channel_name(base::StringPrintf("r%d.javabridge", renderer_id));
- // There's no need for a shutdown event here. If the browser is terminated
- // while the JavaBridgeChannelHost is blocked on a synchronous IPC call, the
- // renderer's shutdown event will cause the underlying channel to shut down,
- // thus terminating the IPC call.
- return static_cast<JavaBridgeChannelHost*>(NPChannelBase::GetChannel(
- channel_name,
- IPC::Channel::MODE_SERVER,
- ClassFactory,
- ipc_message_loop,
- true,
- dummy_event.Pointer()));
-}
-
-int JavaBridgeChannelHost::ThreadsafeGenerateRouteID() {
- return base::subtle::NoBarrier_AtomicIncrement(&g_last_id, 1);
-}
-
-int JavaBridgeChannelHost::GenerateRouteID() {
- return ThreadsafeGenerateRouteID();
-}
-
-bool JavaBridgeChannelHost::Init(base::MessageLoopProxy* ipc_message_loop,
- bool create_pipe_now,
- WaitableEvent* shutdown_event) {
- if (!NPChannelBase::Init(ipc_message_loop, create_pipe_now, shutdown_event)) {
- return false;
- }
-
- // Finish populating our ChannelHandle.
-#if defined(OS_POSIX)
- // We take control of the FD for all session between this host and
- // the corresponding renderers. We keep it open until this object
- // is deleted.
- channel_handle_.socket.fd = channel_->TakeClientFileDescriptor();
-#endif
-
- return true;
-}
-
-bool JavaBridgeChannelHost::OnControlMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(JavaBridgeChannelHost, message)
- IPC_MESSAGE_HANDLER(JavaBridgeMsg_GenerateRouteID, OnGenerateRouteID)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void JavaBridgeChannelHost::OnGenerateRouteID(int* route_id) {
- *route_id = GenerateRouteID();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/java/java_bridge_channel_host.h b/chromium/content/browser/renderer_host/java/java_bridge_channel_host.h
deleted file mode 100644
index 3f3f1468e9b..00000000000
--- a/chromium/content/browser/renderer_host/java/java_bridge_channel_host.h
+++ /dev/null
@@ -1,52 +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_JAVA_JAVA_BRIDGE_CHANNEL_HOST_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_BRIDGE_CHANNEL_HOST_H_
-
-#include "content/child/npapi/np_channel_base.h"
-
-namespace content {
-
-class JavaBridgeChannelHost : public NPChannelBase {
- public:
- static JavaBridgeChannelHost* GetJavaBridgeChannelHost(
- int renderer_id,
- base::MessageLoopProxy* ipc_message_loop);
-
- // A threadsafe function to generate a unique route ID. Used by the
- // JavaBridgeDispatcherHost on the UI thread and this class on the Java
- // Bridge's background thread.
- static int ThreadsafeGenerateRouteID();
-
- // NPChannelBase implementation:
- virtual int GenerateRouteID() OVERRIDE;
-
- // NPChannelBase override:
- virtual bool Init(base::MessageLoopProxy* ipc_message_loop,
- bool create_pipe_now,
- base::WaitableEvent* shutdown_event) OVERRIDE;
-
- protected:
- // NPChannelBase override:
- virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
-
- private:
- JavaBridgeChannelHost() {}
- friend class base::RefCountedThreadSafe<JavaBridgeChannelHost>;
- virtual ~JavaBridgeChannelHost();
-
- static NPChannelBase* ClassFactory() {
- return new JavaBridgeChannelHost();
- }
-
- // Message handlers
- void OnGenerateRouteID(int* route_id);
-
- DISALLOW_COPY_AND_ASSIGN(JavaBridgeChannelHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_BRIDGE_CHANNEL_HOST_H_
diff --git a/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc b/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
deleted file mode 100644
index 922b03a55e8..00000000000
--- a/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
+++ /dev/null
@@ -1,167 +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/renderer_host/java/java_bridge_dispatcher_host.h"
-
-#include "base/android/java_handler_thread.h"
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "content/browser/renderer_host/java/java_bridge_channel_host.h"
-#include "content/child/child_process.h"
-#include "content/child/npapi/npobject_stub.h"
-#include "content/child/npapi/npobject_util.h" // For CreateNPVariantParam()
-#include "content/common/java_bridge_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "third_party/WebKit/public/web/WebBindings.h"
-
-#if !defined(OS_ANDROID)
-#error "JavaBridge only supports OS_ANDROID"
-#endif
-
-namespace content {
-
-namespace {
-// The JavaBridge needs to use a Java thread so the callback
-// will happen on a thread with a prepared Looper.
-class JavaBridgeThread : public base::android::JavaHandlerThread {
- public:
- JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
- Start();
- }
- virtual ~JavaBridgeThread() {
- Stop();
- }
-};
-
-void CleanUpStubs(const std::vector<base::WeakPtr<NPObjectStub> > & stubs) {
- for (size_t i = 0; i < stubs.size(); ++i) {
- if (stubs[i]) {
- stubs[i]->DeleteSoon();
- }
- }
-}
-
-base::LazyInstance<JavaBridgeThread> g_background_thread =
- LAZY_INSTANCE_INITIALIZER;
-} // namespace
-
-JavaBridgeDispatcherHost::JavaBridgeDispatcherHost(
- RenderFrameHost* render_frame_host)
- : render_frame_host_(render_frame_host) {
-}
-
-JavaBridgeDispatcherHost::~JavaBridgeDispatcherHost() {
- g_background_thread.Get().message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&CleanUpStubs, stubs_));
-}
-
-void JavaBridgeDispatcherHost::AddNamedObject(const base::string16& name,
- NPObject* object) {
- NPVariant_Param variant_param;
- CreateNPVariantParam(object, &variant_param);
-
- Send(new JavaBridgeMsg_AddNamedObject(
- render_frame_host_->GetRoutingID(), name, variant_param));
-}
-
-void JavaBridgeDispatcherHost::RemoveNamedObject(const base::string16& name) {
- // On receipt of this message, the JavaBridgeDispatcher will drop its
- // reference to the corresponding proxy object. When the last reference is
- // removed, the proxy object will delete its NPObjectProxy, which will cause
- // the NPObjectStub to be deleted, which will drop its reference to the
- // original NPObject.
- Send(new JavaBridgeMsg_RemoveNamedObject(
- render_frame_host_->GetRoutingID(), name));
-}
-
-void JavaBridgeDispatcherHost::RenderFrameDeleted() {
- render_frame_host_ = NULL;
-}
-
-void JavaBridgeDispatcherHost::OnGetChannelHandle(IPC::Message* reply_msg) {
- g_background_thread.Get().message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&JavaBridgeDispatcherHost::GetChannelHandle, this, reply_msg));
-}
-
-void JavaBridgeDispatcherHost::Send(IPC::Message* msg) {
- if (render_frame_host_) {
- render_frame_host_->Send(msg);
- return;
- }
-
- delete msg;
-}
-
-void JavaBridgeDispatcherHost::GetChannelHandle(IPC::Message* reply_msg) {
- // The channel creates the channel handle based on the renderer ID we passed
- // to GetJavaBridgeChannelHost() and, on POSIX, the file descriptor used by
- // the underlying channel.
- JavaBridgeHostMsg_GetChannelHandle::WriteReplyParams(
- reply_msg,
- channel_->channel_handle());
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&JavaBridgeDispatcherHost::Send, this, reply_msg));
-}
-
-void JavaBridgeDispatcherHost::CreateNPVariantParam(NPObject* object,
- NPVariant_Param* param) {
- // The JavaBridgeChannelHost needs to be created on the background thread, as
- // that is where Java objects will live, and CreateNPVariantParam() needs the
- // channel to create the NPObjectStub. To avoid blocking here until the
- // channel is ready, create the NPVariant_Param by hand, then post a message
- // to the background thread to set up the channel and create the corresponding
- // NPObjectStub. Post that message before doing any IPC, to make sure that
- // the channel and object proxies are ready before responses are received
- // from the renderer.
-
- // Create an NPVariantParam suitable for serialization over IPC from our
- // NPVariant. See CreateNPVariantParam() in npobject_utils.
- param->type = NPVARIANT_PARAM_SENDER_OBJECT_ROUTING_ID;
- int route_id = JavaBridgeChannelHost::ThreadsafeGenerateRouteID();
- param->npobject_routing_id = route_id;
-
- blink::WebBindings::retainObject(object);
- g_background_thread.Get().message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&JavaBridgeDispatcherHost::CreateObjectStub, this, object,
- render_frame_host_->GetProcess()->GetID(), route_id));
-}
-
-void JavaBridgeDispatcherHost::CreateObjectStub(NPObject* object,
- int render_process_id,
- int route_id) {
- DCHECK_EQ(g_background_thread.Get().message_loop(),
- base::MessageLoop::current());
- if (!channel_.get()) {
- channel_ = JavaBridgeChannelHost::GetJavaBridgeChannelHost(
- render_process_id,
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
- }
-
- // In a typical scenario, the lifetime of each NPObjectStub is governed by
- // that of the NPObjectProxy in the renderer, via the channel. However,
- // we cannot guaranteed that the renderer always terminates cleanly
- // (crashes / sometimes just unavoidable). We keep a weak reference to
- // it now and schedule a delete on it when this host is getting deleted.
-
- // Pass 0 for the containing window, as it's only used by plugins to pump the
- // window message queue when a method on a renderer-side object causes a
- // dialog to be displayed, and the Java Bridge does not need this
- // functionality. The page URL is also not required.
- stubs_.push_back((new NPObjectStub(
- object, channel_.get(), route_id, 0, GURL()))->AsWeakPtr());
-
- // The NPObjectStub takes a reference to the NPObject. Release the ref added
- // in CreateNPVariantParam().
- blink::WebBindings::releaseObject(object);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host.h b/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host.h
deleted file mode 100644
index a656f07afb0..00000000000
--- a/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host.h
+++ /dev/null
@@ -1,71 +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_JAVA_JAVA_BRIDGE_DISPATCHER_HOST_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_BRIDGE_DISPATCHER_HOST_H_
-
-#include <vector>
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "content/child/npapi/npobject_stub.h"
-
-class RouteIDGenerator;
-struct NPObject;
-
-namespace IPC {
-class Message;
-}
-
-namespace content {
-class NPChannelBase;
-class RenderFrameHost;
-struct NPVariant_Param;
-
-// This class handles injecting Java objects into a single RenderFrame. The Java
-// object itself lives in the browser process on a background thread, while a
-// proxy object is created in the renderer. An instance of this class exists
-// for each RenderViewHost.
-class JavaBridgeDispatcherHost
- : public base::RefCountedThreadSafe<JavaBridgeDispatcherHost> {
- public:
- // We hold a weak pointer to the RenderFrameHost. It must outlive this object.
- explicit JavaBridgeDispatcherHost(RenderFrameHost* render_frame_host);
-
- // Injects |object| into the main frame of the corresponding RenderView. A
- // proxy object is created in the renderer and when the main frame's window
- // object is next cleared, this proxy object is bound to the window object
- // using |name|. The proxy object remains bound until the next time the
- // window object is cleared after a call to RemoveNamedObject() or
- // AddNamedObject() with the same name. The proxy object proxies calls back
- // to |object|, which is manipulated on the background thread. This class
- // holds a reference to |object| for the time that the proxy object is bound
- // to the window object.
- void AddNamedObject(const base::string16& name, NPObject* object);
- void RemoveNamedObject(const base::string16& name);
-
- // Since this object is ref-counted, it might outlive render_frame_host.
- void RenderFrameDeleted();
-
- void OnGetChannelHandle(IPC::Message* reply_msg);
- void Send(IPC::Message* msg);
-
- private:
- friend class base::RefCountedThreadSafe<JavaBridgeDispatcherHost>;
- virtual ~JavaBridgeDispatcherHost();
-
- void GetChannelHandle(IPC::Message* reply_msg);
- void CreateNPVariantParam(NPObject* object, NPVariant_Param* param);
- void CreateObjectStub(NPObject* object, int render_process_id, int route_id);
-
- scoped_refptr<NPChannelBase> channel_;
- RenderFrameHost* render_frame_host_;
- std::vector<base::WeakPtr<NPObjectStub> > stubs_;
-
- DISALLOW_COPY_AND_ASSIGN(JavaBridgeDispatcherHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_BRIDGE_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.cc b/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.cc
deleted file mode 100644
index 635a1d13c2c..00000000000
--- a/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.cc
+++ /dev/null
@@ -1,162 +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/renderer_host/java/java_bridge_dispatcher_host_manager.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_weak_ref.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/browser/renderer_host/java/java_bound_object.h"
-#include "content/browser/renderer_host/java/java_bridge_dispatcher_host.h"
-#include "content/common/android/hash_set.h"
-#include "content/common/java_bridge_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
-#include "third_party/WebKit/public/web/WebBindings.h"
-
-namespace content {
-
-JavaBridgeDispatcherHostManager::JavaBridgeDispatcherHostManager(
- WebContents* web_contents,
- jobject retained_object_set)
- : WebContentsObserver(web_contents),
- retained_object_set_(base::android::AttachCurrentThread(),
- retained_object_set),
- allow_object_contents_inspection_(true) {
- DCHECK(retained_object_set);
-}
-
-JavaBridgeDispatcherHostManager::~JavaBridgeDispatcherHostManager() {
- for (ObjectMap::iterator iter = objects_.begin(); iter != objects_.end();
- ++iter) {
- blink::WebBindings::releaseObject(iter->second);
- }
- DCHECK_EQ(0U, instances_.size());
-}
-
-void JavaBridgeDispatcherHostManager::AddNamedObject(const base::string16& name,
- NPObject* object) {
- // Record this object in a map so that we can add it into RenderViewHosts
- // created later. The JavaBridgeDispatcherHost instances will take a
- // reference to the object, but we take one too, because this method can be
- // called before there are any such instances.
- blink::WebBindings::retainObject(object);
- objects_[name] = object;
-
- for (InstanceMap::iterator iter = instances_.begin();
- iter != instances_.end(); ++iter) {
- iter->second->AddNamedObject(name, object);
- }
-}
-
-void JavaBridgeDispatcherHostManager::RemoveNamedObject(
- const base::string16& name) {
- ObjectMap::iterator iter = objects_.find(name);
- if (iter == objects_.end()) {
- return;
- }
-
- blink::WebBindings::releaseObject(iter->second);
- objects_.erase(iter);
-
- for (InstanceMap::iterator iter = instances_.begin();
- iter != instances_.end(); ++iter) {
- iter->second->RemoveNamedObject(name);
- }
-}
-
-void JavaBridgeDispatcherHostManager::RenderFrameCreated(
- RenderFrameHost* render_frame_host) {
- // Creates a JavaBridgeDispatcherHost for the specified RenderViewHost and
- // adds all currently registered named objects to the new instance.
- scoped_refptr<JavaBridgeDispatcherHost> instance =
- new JavaBridgeDispatcherHost(render_frame_host);
-
- for (ObjectMap::const_iterator iter = objects_.begin();
- iter != objects_.end(); ++iter) {
- instance->AddNamedObject(iter->first, iter->second);
- }
-
- instances_[render_frame_host] = instance;
-}
-
-void JavaBridgeDispatcherHostManager::RenderFrameDeleted(
- RenderFrameHost* render_frame_host) {
- if (!instances_.count(render_frame_host)) // Needed for tests.
- return;
- instances_[render_frame_host]->RenderFrameDeleted();
- instances_.erase(render_frame_host);
-}
-
-void JavaBridgeDispatcherHostManager::DocumentAvailableInMainFrame() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // Called when the window object has been cleared in the main frame.
- JNIEnv* env = base::android::AttachCurrentThread();
- base::android::ScopedJavaLocalRef<jobject> retained_object_set =
- retained_object_set_.get(env);
- if (!retained_object_set.is_null()) {
- JNI_Java_HashSet_clear(env, retained_object_set);
-
- // We also need to add back the named objects we have so far as they
- // should survive navigations.
- ObjectMap::iterator it = objects_.begin();
- for (; it != objects_.end(); ++it) {
- JNI_Java_HashSet_add(env, retained_object_set,
- JavaBoundObject::GetJavaObject(it->second));
- }
- }
-}
-
-bool JavaBridgeDispatcherHostManager::OnMessageReceived(
- const IPC::Message& message,
- RenderFrameHost* render_frame_host) {
- DCHECK(render_frame_host);
- if (!instances_.count(render_frame_host))
- return false;
- scoped_refptr<JavaBridgeDispatcherHost> instance =
- instances_[render_frame_host];
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(JavaBridgeDispatcherHostManager, message)
- IPC_MESSAGE_FORWARD_DELAY_REPLY(
- JavaBridgeHostMsg_GetChannelHandle,
- instance.get(),
- JavaBridgeDispatcherHost::OnGetChannelHandle)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void JavaBridgeDispatcherHostManager::JavaBoundObjectCreated(
- const base::android::JavaRef<jobject>& object) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- JNIEnv* env = base::android::AttachCurrentThread();
- base::android::ScopedJavaLocalRef<jobject> retained_object_set =
- retained_object_set_.get(env);
- if (!retained_object_set.is_null()) {
- JNI_Java_HashSet_add(env, retained_object_set, object);
- }
-}
-
-void JavaBridgeDispatcherHostManager::JavaBoundObjectDestroyed(
- const base::android::JavaRef<jobject>& object) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- JNIEnv* env = base::android::AttachCurrentThread();
- base::android::ScopedJavaLocalRef<jobject> retained_object_set =
- retained_object_set_.get(env);
- if (!retained_object_set.is_null()) {
- JNI_Java_HashSet_remove(env, retained_object_set, object);
- }
-}
-
-void JavaBridgeDispatcherHostManager::SetAllowObjectContentsInspection(
- bool allow) {
- allow_object_contents_inspection_ = allow;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h b/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h
deleted file mode 100644
index 8d03576be57..00000000000
--- a/chromium/content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h
+++ /dev/null
@@ -1,76 +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_JAVA_JAVA_BRIDGE_DISPATCHER_HOST_MANAGER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_BRIDGE_DISPATCHER_HOST_MANAGER_H_
-
-#include <map>
-
-#include "base/android/jni_weak_ref.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "content/public/browser/web_contents_observer.h"
-
-struct NPObject;
-
-namespace content {
-class JavaBridgeDispatcherHost;
-class RenderFrameHost;
-
-// This class handles injecting Java objects into all of the RenderFrames
-// associated with a WebContents. It manages a set of JavaBridgeDispatcherHost
-// objects, one per RenderFrameHost.
-class JavaBridgeDispatcherHostManager
- : public WebContentsObserver,
- public base::SupportsWeakPtr<JavaBridgeDispatcherHostManager> {
- public:
- JavaBridgeDispatcherHostManager(WebContents* web_contents,
- jobject retained_object_set);
- virtual ~JavaBridgeDispatcherHostManager();
-
- // These methods add or remove the object to each JavaBridgeDispatcherHost.
- // Each one holds a reference to the NPObject while the object is bound to
- // the corresponding RenderFrame. See JavaBridgeDispatcherHost for details.
- void AddNamedObject(const base::string16& name, NPObject* object);
- void RemoveNamedObject(const base::string16& name);
-
- // WebContentsObserver overrides
- virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void DocumentAvailableInMainFrame() OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message,
- RenderFrameHost* render_frame_host) OVERRIDE;
-
- void JavaBoundObjectCreated(const base::android::JavaRef<jobject>& object);
- void JavaBoundObjectDestroyed(const base::android::JavaRef<jobject>& object);
-
- bool GetAllowObjectContentsInspection() const {
- return allow_object_contents_inspection_;
- }
- void SetAllowObjectContentsInspection(bool allow);
-
- private:
- typedef std::map<RenderFrameHost*, scoped_refptr<JavaBridgeDispatcherHost> >
- InstanceMap;
- InstanceMap instances_;
- typedef std::map<base::string16, NPObject*> ObjectMap;
- ObjectMap objects_;
- // Every time a JavaBoundObject backed by a real Java object is
- // created/destroyed, we insert/remove a strong ref to that Java object into
- // this set so that it doesn't get garbage collected while it's still
- // potentially in use. Although the set is managed native side, it's owned
- // and defined in Java so that pushing refs into it does not create new GC
- // roots that would prevent ContentViewCore from being garbage collected.
- JavaObjectWeakGlobalRef retained_object_set_;
- bool allow_object_contents_inspection_;
-
- DISALLOW_COPY_AND_ASSIGN(JavaBridgeDispatcherHostManager);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_JAVA_JAVA_BRIDGE_DISPATCHER_HOST_MANAGER_H_
diff --git a/chromium/content/browser/renderer_host/java/java_type.cc b/chromium/content/browser/renderer_host/java/java_type.cc
deleted file mode 100644
index b590e7733c0..00000000000
--- a/chromium/content/browser/renderer_host/java/java_type.cc
+++ /dev/null
@@ -1,114 +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/renderer_host/java/java_type.h"
-
-#include "base/logging.h"
-
-namespace content {
-namespace {
-
-JavaType JavaTypeFromJNIName(const std::string& jni_name) {
- JavaType result;
- DCHECK(!jni_name.empty());
- switch (jni_name[0]) {
- case 'Z':
- result.type = JavaType::TypeBoolean;
- break;
- case 'B':
- result.type = JavaType::TypeByte;
- break;
- case 'C':
- result.type = JavaType::TypeChar;
- break;
- case 'S':
- result.type = JavaType::TypeShort;
- break;
- case 'I':
- result.type = JavaType::TypeInt;
- break;
- case 'J':
- result.type = JavaType::TypeLong;
- break;
- case 'F':
- result.type = JavaType::TypeFloat;
- break;
- case 'D':
- result.type = JavaType::TypeDouble;
- break;
- case '[':
- result.type = JavaType::TypeArray;
- // LIVECONNECT_COMPLIANCE: We don't support multi-dimensional arrays, so
- // there's no need to populate the inner types.
- break;
- case 'L':
- result.type = jni_name == "Ljava.lang.String;" ?
- JavaType::TypeString :
- JavaType::TypeObject;
- break;
- default:
- // Includes void (V).
- NOTREACHED();
- }
- return result;
-}
-
-} // namespace
-
-JavaType::JavaType() {
-}
-
-JavaType::JavaType(const JavaType& other) {
- *this = other;
-}
-
-JavaType::~JavaType() {
-}
-
-JavaType& JavaType::operator=(const JavaType& other) {
- type = other.type;
- if (other.inner_type) {
- DCHECK_EQ(JavaType::TypeArray, type);
- inner_type.reset(new JavaType(*other.inner_type));
- } else {
- inner_type.reset();
- }
- return *this;
-}
-
-JavaType JavaType::CreateFromBinaryName(const std::string& binary_name) {
- JavaType result;
- DCHECK(!binary_name.empty());
- if (binary_name == "boolean") {
- result.type = JavaType::TypeBoolean;
- } else if (binary_name == "byte") {
- result.type = JavaType::TypeByte;
- } else if (binary_name == "char") {
- result.type = JavaType::TypeChar;
- } else if (binary_name == "short") {
- result.type = JavaType::TypeShort;
- } else if (binary_name == "int") {
- result.type = JavaType::TypeInt;
- } else if (binary_name == "long") {
- result.type = JavaType::TypeLong;
- } else if (binary_name == "float") {
- result.type = JavaType::TypeFloat;
- } else if (binary_name == "double") {
- result.type = JavaType::TypeDouble;
- } else if (binary_name == "void") {
- result.type = JavaType::TypeVoid;
- } else if (binary_name[0] == '[') {
- result.type = JavaType::TypeArray;
- // The inner type of an array is represented in JNI format.
- result.inner_type.reset(new JavaType(JavaTypeFromJNIName(
- binary_name.substr(1))));
- } else if (binary_name == "java.lang.String") {
- result.type = JavaType::TypeString;
- } else {
- result.type = JavaType::TypeObject;
- }
- return result;
-}
-
-} // 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 86799c9bc99..25333b365c2 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
@@ -7,8 +7,9 @@
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/win/windows_version.h"
-#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_delegate.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/common/content_switches.h"
#include "ui/base/touch/touch_enabled.h"
@@ -20,38 +21,44 @@
namespace content {
+namespace {
+
// A custom MSAA object id used to determine if a screen reader or some
// other client is listening on MSAA events - if so, we enable full web
// accessibility support.
const int kIdScreenReaderHoneyPot = 1;
+} // namespace
+
LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() {
- ::DestroyWindow(hwnd());
+ if (::IsWindow(hwnd()))
+ ::DestroyWindow(hwnd());
}
// static
-scoped_ptr<LegacyRenderWidgetHostHWND> LegacyRenderWidgetHostHWND::Create(
- HWND parent) {
- // content_unittests passes in the desktop window as the parent. We allow
- // the LegacyRenderWidgetHostHWND instance to be created in this case for
- // these tests to pass.
+LegacyRenderWidgetHostHWND* LegacyRenderWidgetHostHWND::Create(
+ HWND parent,
+ LegacyRenderWidgetHostHWNDDelegate* delegate) {
if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableLegacyIntermediateWindow) ||
- (!GetWindowEventTarget(parent) && parent != ::GetDesktopWindow()))
- return scoped_ptr<LegacyRenderWidgetHostHWND>();
-
- scoped_ptr<LegacyRenderWidgetHostHWND> legacy_window_instance;
- legacy_window_instance.reset(new LegacyRenderWidgetHostHWND(parent));
- // If we failed to create the child, or if the switch to disable the legacy
- // window is passed in, then return NULL.
- if (!::IsWindow(legacy_window_instance->hwnd()))
- return scoped_ptr<LegacyRenderWidgetHostHWND>();
+ switches::kDisableLegacyIntermediateWindow)) {
+ return nullptr;
+ }
+ LegacyRenderWidgetHostHWND* legacy_window_instance =
+ new LegacyRenderWidgetHostHWND(parent, delegate);
+ // If we failed to create the child, return NULL.
+ if (!::IsWindow(legacy_window_instance->hwnd())) {
+ delete legacy_window_instance;
+ return nullptr;
+ }
legacy_window_instance->Init();
- return legacy_window_instance.Pass();
+ return legacy_window_instance;
}
void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) {
+ if (!::IsWindow(hwnd()))
+ return;
+
::SetParent(hwnd(), parent);
// If the new parent is the desktop Window, then we disable the child window
// to ensure that it does not receive any input events. It should not because
@@ -64,35 +71,38 @@ void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) {
}
HWND LegacyRenderWidgetHostHWND::GetParent() {
- return ::GetParent(hwnd());
-}
+ if (!::IsWindow(hwnd()))
+ return NULL;
-void LegacyRenderWidgetHostHWND::OnManagerDeleted() {
- manager_ = NULL;
+ return ::GetParent(hwnd());
}
void LegacyRenderWidgetHostHWND::Show() {
- ::ShowWindow(hwnd(), SW_SHOW);
+ if (::IsWindow(hwnd()))
+ ::ShowWindow(hwnd(), SW_SHOW);
}
void LegacyRenderWidgetHostHWND::Hide() {
- ::ShowWindow(hwnd(), SW_HIDE);
+ if (::IsWindow(hwnd()))
+ ::ShowWindow(hwnd(), SW_HIDE);
}
void LegacyRenderWidgetHostHWND::SetBounds(const gfx::Rect& bounds) {
+ if (!::IsWindow(hwnd()))
+ return;
+
gfx::Rect bounds_in_pixel = gfx::win::DIPToScreenRect(bounds);
::SetWindowPos(hwnd(), NULL, bounds_in_pixel.x(), bounds_in_pixel.y(),
- bounds_in_pixel.width(), bounds_in_pixel.height(), 0);
-}
-
-void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) {
- if (manager_)
- manager_->OnAccessibleHwndDeleted();
+ bounds_in_pixel.width(), bounds_in_pixel.height(),
+ SWP_NOREDRAW);
}
-LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(HWND parent)
- : manager_(NULL),
- mouse_tracking_enabled_(false) {
+LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(
+ HWND parent,
+ LegacyRenderWidgetHostHWNDDelegate* delegate)
+ : mouse_tracking_enabled_(false),
+ delegate_(delegate) {
+ DCHECK(delegate_);
RECT rect = {0};
Base::Create(parent, rect, L"Chrome Legacy Window",
WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
@@ -101,8 +111,9 @@ LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(HWND parent)
bool LegacyRenderWidgetHostHWND::Init() {
if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
- ui::AreTouchEventsEnabled())
+ ui::AreTouchEventsEnabled()) {
RegisterTouchWindow(hwnd(), TWF_WANTPALM);
+ }
HRESULT hr = ::CreateStdAccessibleObject(
hwnd(), OBJID_WINDOW, IID_IAccessible,
@@ -146,13 +157,16 @@ LRESULT LegacyRenderWidgetHostHWND::OnGetObject(UINT message,
return static_cast<LRESULT>(0L);
}
- if (OBJID_CLIENT != obj_id || !manager_)
+ if (OBJID_CLIENT != obj_id)
+ return static_cast<LRESULT>(0L);
+
+ base::win::ScopedComPtr<IAccessible> native_accessible(
+ delegate_->GetNativeViewAccessible());
+ if (!native_accessible)
return static_cast<LRESULT>(0L);
- base::win::ScopedComPtr<IAccessible> root(
- manager_->GetRoot()->ToBrowserAccessibilityWin());
return LresultFromObject(IID_IAccessible, w_param,
- static_cast<IAccessible*>(root.Detach()));
+ static_cast<IAccessible*>(native_accessible.Detach()));
}
// We send keyboard/mouse/touch messages to the parent window via SendMessage.
@@ -167,11 +181,14 @@ LRESULT LegacyRenderWidgetHostHWND::OnKeyboardRange(UINT message,
WPARAM w_param,
LPARAM l_param,
BOOL& handled) {
+ LRESULT ret = 0;
if (GetWindowEventTarget(GetParent())) {
- return GetWindowEventTarget(GetParent())->HandleKeyboardMessage(
- message, w_param, l_param);
+ bool msg_handled = false;
+ ret = GetWindowEventTarget(GetParent())->HandleKeyboardMessage(
+ message, w_param, l_param, &msg_handled);
+ handled = msg_handled;
}
- return 0;
+ return ret;
}
LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
@@ -200,28 +217,45 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
::MapWindowPoints(hwnd(), GetParent(), &mouse_coords, 1);
l_param = MAKELPARAM(mouse_coords.x, mouse_coords.y);
}
+
+ LRESULT ret = 0;
+
if (GetWindowEventTarget(GetParent())) {
- return GetWindowEventTarget(GetParent())->HandleMouseMessage(
- message, w_param, l_param);
+ bool msg_handled = false;
+ ret = GetWindowEventTarget(GetParent())->HandleMouseMessage(
+ message, w_param, l_param, &msg_handled);
+ handled = msg_handled;
+ // If the parent did not handle non client mouse messages, we call
+ // DefWindowProc on the message with the parent window handle. This
+ // ensures that WM_SYSCOMMAND is generated for the parent and we are
+ // out of the picture.
+ if (!handled &&
+ (message >= WM_NCMOUSEMOVE && message <= WM_NCXBUTTONDBLCLK)) {
+ ret = ::DefWindowProc(GetParent(), message, w_param, l_param);
+ handled = TRUE;
+ }
}
- return 0;
+ return ret;
}
LRESULT LegacyRenderWidgetHostHWND::OnMouseLeave(UINT message,
WPARAM w_param,
LPARAM l_param) {
mouse_tracking_enabled_ = false;
+ LRESULT ret = 0;
if ((::GetCapture() != GetParent()) && GetWindowEventTarget(GetParent())) {
// We should send a WM_MOUSELEAVE to the parent window only if the mouse
// has moved outside the bounds of the parent.
POINT cursor_pos;
::GetCursorPos(&cursor_pos);
if (::WindowFromPoint(cursor_pos) != GetParent()) {
- return GetWindowEventTarget(GetParent())->HandleMouseMessage(
- message, w_param, l_param);
+ bool msg_handled = false;
+ ret = GetWindowEventTarget(GetParent())->HandleMouseMessage(
+ message, w_param, l_param, &msg_handled);
+ SetMsgHandled(msg_handled);
}
}
- return 0;
+ return ret;
}
LRESULT LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message,
@@ -254,29 +288,37 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message,
LRESULT LegacyRenderWidgetHostHWND::OnTouch(UINT message,
WPARAM w_param,
LPARAM l_param) {
+ LRESULT ret = 0;
if (GetWindowEventTarget(GetParent())) {
- return GetWindowEventTarget(GetParent())->HandleTouchMessage(
- message, w_param, l_param);
+ bool msg_handled = false;
+ ret = GetWindowEventTarget(GetParent())->HandleTouchMessage(
+ message, w_param, l_param, &msg_handled);
+ SetMsgHandled(msg_handled);
}
- return 0;
+ return ret;
}
LRESULT LegacyRenderWidgetHostHWND::OnScroll(UINT message,
WPARAM w_param,
LPARAM l_param) {
+ LRESULT ret = 0;
if (GetWindowEventTarget(GetParent())) {
- return GetWindowEventTarget(GetParent())->HandleScrollMessage(
- message, w_param, l_param);
+ bool msg_handled = false;
+ ret = GetWindowEventTarget(GetParent())->HandleScrollMessage(
+ message, w_param, l_param, &msg_handled);
+ SetMsgHandled(msg_handled);
}
- return 0;
+ return ret;
}
LRESULT LegacyRenderWidgetHostHWND::OnNCHitTest(UINT message,
WPARAM w_param,
LPARAM l_param) {
if (GetWindowEventTarget(GetParent())) {
+ bool msg_handled = false;
LRESULT hit_test = GetWindowEventTarget(
- GetParent())->HandleNcHitTestMessage(message, w_param, l_param);
+ GetParent())->HandleNcHitTestMessage(message, w_param, l_param,
+ &msg_handled);
// If the parent returns HTNOWHERE which can happen for popup windows, etc
// we return HTCLIENT.
if (hit_test == HTNOWHERE)
diff --git a/chromium/content/browser/renderer_host/legacy_render_widget_host_win.h b/chromium/content/browser/renderer_host/legacy_render_widget_host_win.h
index 814c200c275..3222e05c1d4 100644
--- a/chromium/content/browser/renderer_host/legacy_render_widget_host_win.h
+++ b/chromium/content/browser/renderer_host/legacy_render_widget_host_win.h
@@ -11,9 +11,9 @@
#include <oleacc.h>
#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
#include "base/win/scoped_comptr.h"
#include "content/common/content_export.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
namespace ui {
@@ -21,8 +21,6 @@ class WindowEventTarget;
}
namespace content {
-class BrowserAccessibilityManagerWin;
-
// Reasons for the existence of this class outlined below:-
// 1. Some screen readers expect every tab / every unique web content container
// to be in its own HWND with class name Chrome_RenderWidgetHostHWND.
@@ -40,12 +38,11 @@ class BrowserAccessibilityManagerWin;
// fail.
// We should look to get rid of this code when all of the above are fixed.
+class LegacyRenderWidgetHostHWNDDelegate;
+
// This class implements a child HWND with the same size as the content area,
-// that delegates its accessibility implementation to the root of the
-// BrowserAccessibilityManager tree. This HWND is hooked up as the parent of
-// the root object in the BrowserAccessibilityManager tree, so when any
-// accessibility client calls ::WindowFromAccessibleObject, they get this
-// HWND instead of the DesktopWindowTreeHostWin.
+// and delegates its accessibility implementation to the
+// gfx::NativeViewAccessible provided by the owner class.
class CONTENT_EXPORT LegacyRenderWidgetHostHWND
: public ATL::CWindowImpl<LegacyRenderWidgetHostHWND,
NON_EXPORTED_BASE(ATL::CWindow),
@@ -57,12 +54,14 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
NON_EXPORTED_BASE(ATL::CWindow),
ATL::CWinTraits<WS_CHILD> > Base;
- ~LegacyRenderWidgetHostHWND();
+ virtual ~LegacyRenderWidgetHostHWND();
// Creates and returns an instance of the LegacyRenderWidgetHostHWND class on
// successful creation of a child window parented to the parent window passed
// in.
- static scoped_ptr<LegacyRenderWidgetHostHWND> Create(HWND parent);
+ static LegacyRenderWidgetHostHWND* Create(
+ HWND parent,
+ LegacyRenderWidgetHostHWNDDelegate* delegate);
BEGIN_MSG_MAP_EX(LegacyRenderWidgetHostHWND)
MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
@@ -84,6 +83,8 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
MESSAGE_HANDLER_EX(WM_SIZE, OnSize)
END_MSG_MAP()
+ // May be deleted at any time by Windows! Other classes should never store
+ // this value.
HWND hwnd() { return m_hWnd; }
// Called when the child window is to be reparented to a new window.
@@ -93,13 +94,6 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
IAccessible* window_accessible() { return window_accessible_; }
- void set_browser_accessibility_manager(
- content::BrowserAccessibilityManagerWin* manager) {
- manager_ = manager;
- }
-
- void OnManagerDeleted();
-
// Functions to show and hide the window.
void Show();
void Hide();
@@ -107,11 +101,9 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
// Resizes the window to the bounds passed in.
void SetBounds(const gfx::Rect& bounds);
- protected:
- virtual void OnFinalMessage(HWND hwnd) OVERRIDE;
-
private:
- LegacyRenderWidgetHostHWND(HWND parent);
+ LegacyRenderWidgetHostHWND(HWND parent,
+ LegacyRenderWidgetHostHWNDDelegate* delegate);
bool Init();
@@ -136,7 +128,8 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
LRESULT OnNCCalcSize(UINT message, WPARAM w_param, LPARAM l_param);
LRESULT OnSize(UINT message, WPARAM w_param, LPARAM l_param);
- content::BrowserAccessibilityManagerWin* manager_;
+ LegacyRenderWidgetHostHWNDDelegate* delegate_;
+
base::win::ScopedComPtr<IAccessible> window_accessible_;
// Set to true if we turned on mouse tracking.
@@ -148,4 +141,3 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_LEGACY_RENDER_WIDGET_HOST_WIN_H_
-
diff --git a/chromium/content/browser/renderer_host/legacy_render_widget_host_win_delegate.h b/chromium/content/browser/renderer_host/legacy_render_widget_host_win_delegate.h
new file mode 100644
index 00000000000..a94d81e0939
--- /dev/null
+++ b/chromium/content/browser/renderer_host/legacy_render_widget_host_win_delegate.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_LEGACY_RENDER_WIDGET_HOST_WIN_DELEGATE_H_
+#define CONTENT_BROWSER_RENDERER_HOST_LEGACY_RENDER_WIDGET_HOST_WIN_DELEGATE_H_
+
+#include "content/common/content_export.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace content {
+
+// A delegate interface for LegacyRenderWidgetHostHWND to query the
+// native view accessible from the owner class.
+class CONTENT_EXPORT LegacyRenderWidgetHostHWNDDelegate {
+ public:
+ // Get the native view accessible for the web contents.
+ // Once initialized, this should always return a valid object, but the
+ // object may change as the user navigates.
+ virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
+};
+
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_LEGACY_RENDER_WIDGET_HOST_WIN_DELEGATE_H_
diff --git a/chromium/content/browser/renderer_host/media/DEPS b/chromium/content/browser/renderer_host/media/DEPS
index c3a5b96fc44..21fd0fd9d57 100644
--- a/chromium/content/browser/renderer_host/media/DEPS
+++ b/chromium/content/browser/renderer_host/media/DEPS
@@ -1,3 +1,11 @@
include_rules = [
"+media",
]
+
+specific_include_rules = {
+ # TODO(miu): Need to relocate MediaStreamManager/DispatcherHost/UIProxy and
+ # friends to somewhere more appropriate. Perhaps content/browser/media?
+ "media_stream_ui_proxy(_unittest)?\.cc": [
+ "+content/browser/frame_host",
+ ],
+}
diff --git a/chromium/content/browser/renderer_host/media/OWNERS b/chromium/content/browser/renderer_host/media/OWNERS
index d32059427a5..0db86f8db0f 100644
--- a/chromium/content/browser/renderer_host/media/OWNERS
+++ b/chromium/content/browser/renderer_host/media/OWNERS
@@ -1,9 +1,7 @@
-acolwell@chromium.org
dalecurtis@chromium.org
ddorwin@chromium.org
perkj@chromium.org
scherkus@chromium.org
-shadi@chromium.org
tommi@chromium.org
vrk@chromium.org
wjia@chromium.org
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 17b4d7d251d..e360eb0eef2 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
@@ -14,6 +14,10 @@
#include "media/base/channel_layout.h"
#include "media/base/scoped_histogram_timer.h"
+#if defined(OS_CHROMEOS)
+#include "chromeos/audio/cras_audio_handler.h"
+#endif
+
namespace content {
const int AudioInputDeviceManager::kFakeOpenSessionId = 1;
@@ -28,6 +32,9 @@ AudioInputDeviceManager::AudioInputDeviceManager(
: listener_(NULL),
next_capture_session_id_(kFirstSessionId),
use_fake_device_(false),
+#if defined(OS_CHROMEOS)
+ keyboard_mic_streams_count_(0),
+#endif
audio_manager_(audio_manager) {
}
@@ -49,7 +56,7 @@ void AudioInputDeviceManager::Register(
const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!listener_);
- DCHECK(!device_task_runner_);
+ DCHECK(!device_task_runner_.get());
listener_ = listener;
device_task_runner_ = device_task_runner;
}
@@ -109,6 +116,43 @@ bool AudioInputDeviceManager::ShouldUseFakeDevice() const {
return use_fake_device_;
}
+#if defined(OS_CHROMEOS)
+void AudioInputDeviceManager::RegisterKeyboardMicStream(
+ const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ++keyboard_mic_streams_count_;
+ if (keyboard_mic_streams_count_ == 1) {
+ BrowserThread::PostTaskAndReply(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &AudioInputDeviceManager::SetKeyboardMicStreamActiveOnUIThread,
+ this,
+ true),
+ callback);
+ } else {
+ callback.Run();
+ }
+}
+
+void AudioInputDeviceManager::UnregisterKeyboardMicStream() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ --keyboard_mic_streams_count_;
+ DCHECK_GE(keyboard_mic_streams_count_, 0);
+ if (keyboard_mic_streams_count_ == 0) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &AudioInputDeviceManager::SetKeyboardMicStreamActiveOnUIThread,
+ this,
+ false));
+ }
+}
+#endif
+
void AudioInputDeviceManager::EnumerateOnDeviceThread(
MediaStreamType stream_type) {
SCOPED_UMA_HISTOGRAM_TIMER(
@@ -250,4 +294,13 @@ void AudioInputDeviceManager::GetFakeDeviceNames(
kFakeDeviceId2));
}
+#if defined(OS_CHROMEOS)
+void AudioInputDeviceManager::SetKeyboardMicStreamActiveOnUIThread(
+ bool active) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ chromeos::CrasAudioHandler::Get()->SetKeyboardMicActive(active);
+}
+#endif
+
+
} // namespace content
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 e8d44cb807a..a2d4ca4f92c 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
@@ -45,24 +45,35 @@ class CONTENT_EXPORT AudioInputDeviceManager : public MediaStreamProvider {
const StreamDeviceInfo* GetOpenedDeviceInfoById(int session_id);
// MediaStreamProvider implementation, called on IO thread.
- virtual void Register(MediaStreamProviderListener* listener,
- const scoped_refptr<base::SingleThreadTaskRunner>&
- device_task_runner) OVERRIDE;
- virtual void Unregister() OVERRIDE;
- virtual void EnumerateDevices(MediaStreamType stream_type) OVERRIDE;
- virtual int Open(const StreamDeviceInfo& device) OVERRIDE;
- virtual void Close(int session_id) OVERRIDE;
+ void Register(MediaStreamProviderListener* listener,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ device_task_runner) override;
+ void Unregister() override;
+ void EnumerateDevices(MediaStreamType stream_type) override;
+ int Open(const StreamDeviceInfo& device) override;
+ void Close(int session_id) override;
void UseFakeDevice();
bool ShouldUseFakeDevice() const;
+#if defined(OS_CHROMEOS)
+ // Registers and unregisters that a stream using keyboard mic has been opened
+ // or closed. Keeps count of how many such streams are open and activates and
+ // inactivates the keyboard mic accordingly. The (in)activation is done on the
+ // UI thread and for the register case a callback must therefor be provided
+ // which is called when activated.
+ // Called on the IO thread.
+ void RegisterKeyboardMicStream(const base::Closure& callback);
+ void UnregisterKeyboardMicStream();
+#endif
+
private:
// Used by the unittests to get a list of fake devices.
friend class MediaStreamDispatcherHostTest;
void GetFakeDeviceNames(media::AudioDeviceNames* device_names);
typedef std::vector<StreamDeviceInfo> StreamDeviceList;
- virtual ~AudioInputDeviceManager();
+ ~AudioInputDeviceManager() override;
// Enumerates audio input devices on media stream device thread.
void EnumerateOnDeviceThread(MediaStreamType stream_type);
@@ -87,12 +98,22 @@ class CONTENT_EXPORT AudioInputDeviceManager : public MediaStreamProvider {
// device is found, it will return devices_.end().
StreamDeviceList::iterator GetDevice(int session_id);
+#if defined(OS_CHROMEOS)
+ // Calls Cras audio handler and sets keyboard mic active status.
+ void SetKeyboardMicStreamActiveOnUIThread(bool active);
+#endif
+
// Only accessed on Browser::IO thread.
MediaStreamProviderListener* listener_;
int next_capture_session_id_;
bool use_fake_device_;
StreamDeviceList devices_;
+#if defined(OS_CHROMEOS)
+ // Keeps count of how many streams are using keyboard mic.
+ int keyboard_mic_streams_count_;
+#endif
+
media::AudioManager* const audio_manager_; // Weak.
// The message loop of media stream device thread that this object runs on.
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 c2963eefd36..f6a5fb2fade 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
@@ -55,7 +55,7 @@ class MAYBE_AudioInputDeviceManagerTest : public testing::Test {
MAYBE_AudioInputDeviceManagerTest() {}
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
// The test must run on Browser::IO.
message_loop_.reset(new base::MessageLoopForIO);
io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
@@ -84,7 +84,7 @@ class MAYBE_AudioInputDeviceManagerTest : public testing::Test {
message_loop_->RunUntilIdle();
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
manager_->Unregister();
io_thread_.reset();
}
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 2dcc56d0918..7b421ba6d55 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
@@ -19,6 +19,20 @@
#include "media/audio/audio_manager_base.h"
#include "media/base/audio_bus.h"
+namespace {
+
+void LogMessage(int stream_id, const std::string& msg, bool add_prefix) {
+ std::ostringstream oss;
+ oss << "[stream_id=" << stream_id << "] ";
+ if (add_prefix)
+ oss << "AIRH::";
+ oss << msg;
+ content::MediaStreamManager::SendMessageToNativeLog(oss.str());
+ DVLOG(1) << oss.str();
+}
+
+} // namespace
+
namespace content {
struct AudioInputRendererHost::AudioEntry {
@@ -42,12 +56,16 @@ struct AudioInputRendererHost::AudioEntry {
// 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_;
};
AudioInputRendererHost::AudioEntry::AudioEntry()
: stream_id(0),
shared_memory_segment_count(0),
- pending_close(false) {
+ pending_close(false),
+ has_keyboard_mic_(false) {
}
AudioInputRendererHost::AudioEntry::~AudioEntry() {}
@@ -133,8 +151,10 @@ void AudioInputRendererHost::DoCompleteCreation(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AudioEntry* entry = LookupByController(controller);
- if (!entry)
+ if (!entry) {
+ NOTREACHED() << "AudioInputController is invalid.";
return;
+ }
if (!PeerHandle()) {
NOTREACHED() << "Renderer process handle is invalid.";
@@ -162,22 +182,21 @@ void AudioInputRendererHost::DoCompleteCreation(
AudioInputSyncWriter* writer =
static_cast<AudioInputSyncWriter*>(entry->writer.get());
-#if defined(OS_WIN)
- base::SyncSocket::Handle foreign_socket_handle;
-#else
- base::FileDescriptor foreign_socket_handle;
-#endif
+ base::SyncSocket::TransitDescriptor socket_transit_descriptor;
// If we failed to prepare the sync socket for the renderer then we fail
// the construction of audio input stream.
- if (!writer->PrepareForeignSocketHandle(PeerHandle(),
- &foreign_socket_handle)) {
+ if (!writer->PrepareForeignSocket(PeerHandle(), &socket_transit_descriptor)) {
DeleteEntryOnError(entry, SYNC_SOCKET_ERROR);
return;
}
- Send(new AudioInputMsg_NotifyStreamCreated(entry->stream_id,
- foreign_memory_handle, foreign_socket_handle,
+ LogMessage(entry->stream_id,
+ "DoCompleteCreation: IPC channel and stream are now open",
+ true);
+
+ Send(new AudioInputMsg_NotifyStreamCreated(
+ entry->stream_id, foreign_memory_handle, socket_transit_descriptor,
entry->shared_memory.requested_size(),
entry->shared_memory_segment_count));
}
@@ -187,29 +206,39 @@ void AudioInputRendererHost::DoSendRecordingMessage(
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// TODO(henrika): See crbug.com/115262 for details on why this method
// should be implemented.
+ AudioEntry* entry = LookupByController(controller);
+ if (!entry) {
+ NOTREACHED() << "AudioInputController is invalid.";
+ return;
+ }
+ LogMessage(
+ entry->stream_id, "DoSendRecordingMessage: stream is now started", true);
}
void AudioInputRendererHost::DoHandleError(
media::AudioInputController* controller,
media::AudioInputController::ErrorCode error_code) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Log all errors even it is ignored later.
- MediaStreamManager::SendMessageToNativeLog(
- base::StringPrintf("AudioInputController error: %d", error_code));
+ AudioEntry* entry = LookupByController(controller);
+ if (!entry) {
+ NOTREACHED() << "AudioInputController is invalid.";
+ return;
+ }
// This is a fix for crbug.com/357501. The error can be triggered when closing
// the lid on Macs, which causes more problems than it fixes.
// Also, in crbug.com/357569, the goal is to remove usage of the error since
// it was added to solve a crash on Windows that no longer can be reproduced.
if (error_code == media::AudioInputController::NO_DATA_ERROR) {
- DVLOG(1) << "AudioInputRendererHost@" << this << "::DoHandleError: "
- << "NO_DATA_ERROR ignored.";
+ // TODO(henrika): it might be possible to do something other than just
+ // logging when we detect many NO_DATA_ERROR calls for a stream.
+ LogMessage(entry->stream_id, "AIC::DoCheckForNoData: NO_DATA_ERROR", false);
return;
}
- AudioEntry* entry = LookupByController(controller);
- if (!entry)
- return;
+ std::ostringstream oss;
+ oss << "AIC reports error_code=" << error_code;
+ LogMessage(entry->stream_id, oss.str(), false);
audio_log_->OnError(entry->stream_id);
DeleteEntryOnError(entry, AUDIO_INPUT_CONTROLLER_ERROR);
@@ -219,15 +248,13 @@ void AudioInputRendererHost::DoLog(media::AudioInputController* controller,
const std::string& message) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AudioEntry* entry = LookupByController(controller);
- if (!entry)
+ if (!entry) {
+ NOTREACHED() << "AudioInputController is invalid.";
return;
+ }
// Add stream ID and current audio level reported by AIC to native log.
- std::string log_string =
- base::StringPrintf("[stream_id=%d] ", entry->stream_id);
- log_string += message;
- MediaStreamManager::SendMessageToNativeLog(log_string);
- DVLOG(1) << log_string;
+ LogMessage(entry->stream_id, message, false);
}
bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message) {
@@ -250,15 +277,42 @@ void AudioInputRendererHost::OnCreateStream(
const AudioInputHostMsg_CreateStream_Config& config) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DVLOG(1) << "AudioInputRendererHost@" << this
- << "::OnCreateStream(stream_id=" << stream_id
- << ", render_view_id=" << render_view_id
- << ", session_id=" << session_id << ")";
+#if defined(OS_CHROMEOS)
+ if (config.params.channel_layout() ==
+ media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
+ media_stream_manager_->audio_input_device_manager()
+ ->RegisterKeyboardMicStream(
+ base::Bind(&AudioInputRendererHost::DoCreateStream,
+ this,
+ stream_id,
+ render_view_id,
+ session_id,
+ config));
+ } else {
+ DoCreateStream(stream_id, render_view_id, session_id, config);
+ }
+#else
+ DoCreateStream(stream_id, render_view_id, session_id, config);
+#endif
+}
+
+void AudioInputRendererHost::DoCreateStream(
+ int stream_id,
+ int render_view_id,
+ int session_id,
+ const AudioInputHostMsg_CreateStream_Config& config) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ std::ostringstream oss;
+ oss << "[stream_id=" << stream_id << "] "
+ << "AIRH::OnCreateStream(render_view_id=" << render_view_id
+ << ", session_id=" << session_id << ")";
DCHECK_GT(render_view_id, 0);
// media::AudioParameters is validated in the deserializer.
if (LookupById(stream_id) != NULL) {
SendErrorMessage(stream_id, STREAM_ALREADY_EXISTS);
+ MaybeUnregisterKeyboardMicStream(config);
return;
}
@@ -267,7 +321,7 @@ void AudioInputRendererHost::OnCreateStream(
ShouldUseFakeDevice()) {
audio_params.Reset(
media::AudioParameters::AUDIO_FAKE,
- config.params.channel_layout(), config.params.channels(), 0,
+ config.params.channel_layout(), config.params.channels(),
config.params.sample_rate(), config.params.bits_per_sample(),
config.params.frames_per_buffer());
}
@@ -282,11 +336,13 @@ void AudioInputRendererHost::OnCreateStream(
SendErrorMessage(stream_id, PERMISSION_DENIED);
DLOG(WARNING) << "No permission has been granted to input stream with "
<< "session_id=" << session_id;
+ MaybeUnregisterKeyboardMicStream(config);
return;
}
device_id = info->device.id;
device_name = info->device.name;
+ oss << ": device_name=" << device_name;
}
// Create a new AudioEntry structure.
@@ -305,6 +361,7 @@ void AudioInputRendererHost::OnCreateStream(
!entry->shared_memory.CreateAndMapAnonymous(size.ValueOrDie())) {
// If creation of shared memory failed then send an error message.
SendErrorMessage(stream_id, SHARED_MEMORY_CREATE_FAILED);
+ MaybeUnregisterKeyboardMicStream(config);
return;
}
@@ -313,6 +370,7 @@ void AudioInputRendererHost::OnCreateStream(
if (!writer->Init()) {
SendErrorMessage(stream_id, SYNC_WRITER_INIT_FAILED);
+ MaybeUnregisterKeyboardMicStream(config);
return;
}
@@ -331,40 +389,45 @@ void AudioInputRendererHost::OnCreateStream(
entry->writer.get(),
user_input_monitor_);
} else {
- // TODO(henrika): replace CreateLowLatency() with Create() as soon
- // as satish has ensured that Speech Input also uses the default low-
- // latency path. See crbug.com/112472 for details.
- entry->controller =
- media::AudioInputController::CreateLowLatency(audio_manager_,
- this,
- audio_params,
- device_id,
- entry->writer.get(),
- user_input_monitor_);
+ DCHECK_EQ(config.params.format(),
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY);
+ entry->controller = media::AudioInputController::CreateLowLatency(
+ audio_manager_,
+ this,
+ audio_params,
+ device_id,
+ entry->writer.get(),
+ user_input_monitor_,
+ config.automatic_gain_control);
+ oss << ", AGC=" << config.automatic_gain_control;
}
if (!entry->controller.get()) {
SendErrorMessage(stream_id, STREAM_CREATE_ERROR);
+ MaybeUnregisterKeyboardMicStream(config);
return;
}
- // Set the initial AGC state for the audio input stream. Note that, the AGC
- // is only supported in AUDIO_PCM_LOW_LATENCY mode.
- if (config.params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY)
- entry->controller->SetAutomaticGainControl(config.automatic_gain_control);
+#if defined(OS_CHROMEOS)
+ if (config.params.channel_layout() ==
+ media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
+ entry->has_keyboard_mic_ = true;
+ }
+#endif
+
+ MediaStreamManager::SendMessageToNativeLog(oss.str());
+ DVLOG(1) << oss.str();
// Since the controller was created successfully, create an entry and add it
// to the map.
entry->stream_id = stream_id;
audio_entries_.insert(std::make_pair(stream_id, entry.release()));
-
- MediaStreamManager::SendMessageToNativeLog(
- "Audio input stream created successfully. Device name: " + device_name);
audio_log_->OnCreated(stream_id, audio_params, device_id);
}
void AudioInputRendererHost::OnRecordStream(int stream_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LogMessage(stream_id, "OnRecordStream", true);
AudioEntry* entry = LookupById(stream_id);
if (!entry) {
@@ -378,6 +441,7 @@ void AudioInputRendererHost::OnRecordStream(int stream_id) {
void AudioInputRendererHost::OnCloseStream(int stream_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LogMessage(stream_id, "OnCloseStream", true);
AudioEntry* entry = LookupById(stream_id);
@@ -400,8 +464,10 @@ void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
void AudioInputRendererHost::SendErrorMessage(
int stream_id, ErrorCode error_code) {
- MediaStreamManager::SendMessageToNativeLog(
- base::StringPrintf("AudioInputRendererHost error: %d", error_code));
+ std::string err_msg =
+ base::StringPrintf("SendErrorMessage(error_code=%d)", error_code);
+ LogMessage(stream_id, err_msg, true);
+
Send(new AudioInputMsg_NotifyStreamStateChanged(
stream_id, media::AudioInputIPCDelegate::kError));
}
@@ -419,6 +485,7 @@ void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!entry->pending_close) {
+ LogMessage(entry->stream_id, "CloseAndDeleteStream", true);
entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
this, entry));
entry->pending_close = true;
@@ -428,6 +495,14 @@ void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ LogMessage(entry->stream_id, "DeleteEntry: stream is now closed", true);
+
+#if defined(OS_CHROMEOS)
+ if (entry->has_keyboard_mic_) {
+ media_stream_manager_->audio_input_device_manager()
+ ->UnregisterKeyboardMicStream();
+ }
+#endif
// Delete the entry when this method goes out of scope.
scoped_ptr<AudioEntry> entry_deleter(entry);
@@ -470,4 +545,15 @@ AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
return NULL;
}
+void AudioInputRendererHost::MaybeUnregisterKeyboardMicStream(
+ const AudioInputHostMsg_CreateStream_Config& config) {
+#if defined(OS_CHROMEOS)
+ if (config.params.channel_layout() ==
+ media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
+ media_stream_manager_->audio_input_device_manager()
+ ->UnregisterKeyboardMicStream();
+ }
+#endif
+}
+
} // namespace content
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 7bd6692eabb..b847bf6d4dc 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
@@ -107,19 +107,19 @@ class CONTENT_EXPORT AudioInputRendererHost
media::UserInputMonitor* user_input_monitor);
// BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelClosing() override;
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// AudioInputController::EventHandler implementation.
- virtual void OnCreated(media::AudioInputController* controller) OVERRIDE;
- virtual void OnRecording(media::AudioInputController* controller) OVERRIDE;
- virtual void OnError(media::AudioInputController* controller,
- media::AudioInputController::ErrorCode error_code) OVERRIDE;
- virtual void OnData(media::AudioInputController* controller,
- const media::AudioBus* data) OVERRIDE;
- virtual void OnLog(media::AudioInputController* controller,
- const std::string& message) OVERRIDE;
+ void OnCreated(media::AudioInputController* controller) override;
+ void OnRecording(media::AudioInputController* controller) override;
+ void OnError(media::AudioInputController* controller,
+ media::AudioInputController::ErrorCode error_code) override;
+ void OnData(media::AudioInputController* controller,
+ const media::AudioBus* data) override;
+ void OnLog(media::AudioInputController* controller,
+ const std::string& message) override;
private:
// TODO(henrika): extend test suite (compare AudioRenderHost)
@@ -130,18 +130,26 @@ class CONTENT_EXPORT AudioInputRendererHost
struct AudioEntry;
typedef std::map<int, AudioEntry*> AudioEntryMap;
- virtual ~AudioInputRendererHost();
+ ~AudioInputRendererHost() override;
// Methods called on IO thread ----------------------------------------------
// Audio related IPC message handlers.
+ // For ChromeOS: Checks if the stream should contain keyboard mic, if so
+ // registers to AudioInputDeviceManager. Then calls DoCreateStream.
+ // For non-ChromeOS: Just calls DoCreateStream.
+ void OnCreateStream(int stream_id,
+ int render_view_id,
+ int session_id,
+ const AudioInputHostMsg_CreateStream_Config& config);
+
// Creates an audio input stream with the specified format whose data is
// consumed by an entity in the render view referenced by |render_view_id|.
// |session_id| is used to find out which device to be used for the stream.
// Upon success/failure, the peer is notified via the
// NotifyStreamCreated message.
- void OnCreateStream(int stream_id,
+ void DoCreateStream(int stream_id,
int render_view_id,
int session_id,
const AudioInputHostMsg_CreateStream_Config& config);
@@ -196,6 +204,11 @@ class CONTENT_EXPORT AudioInputRendererHost
// event is received.
AudioEntry* LookupByController(media::AudioInputController* controller);
+ // If ChromeOS and |config|'s layout has keyboard mic, unregister in
+ // AudioInputDeviceManager.
+ void MaybeUnregisterKeyboardMicStream(
+ const AudioInputHostMsg_CreateStream_Config& config);
+
// Used to create an AudioInputController.
media::AudioManager* audio_manager_;
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 117fbe8fedb..987fd232054 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
@@ -60,18 +60,20 @@ void AudioInputSyncWriter::Write(const media::AudioBus* data,
if (last_write_time_.is_null()) {
// This is the first time Write is called.
base::TimeDelta interval = base::Time::Now() - creation_time_;
- oss << "Audio input data received for the first time: delay = "
- << interval.InMilliseconds() << "ms.";
+ oss << "AISW::Write: audio input data received for the first time: delay "
+ "= " << interval.InMilliseconds() << "ms";
} else {
base::TimeDelta interval = base::Time::Now() - last_write_time_;
if (interval > kLogDelayThreadhold) {
- oss << "Audio input data delay unexpectedly long: delay = "
- << interval.InMilliseconds() << "ms.";
+ oss << "AISW::Write: audio input data delay unexpectedly long: delay = "
+ << interval.InMilliseconds() << "ms";
}
}
- if (!oss.str().empty())
+ if (!oss.str().empty()) {
MediaStreamManager::SendMessageToNativeLog(oss.str());
+ DVLOG(1) << oss.str();
+ }
last_write_time_ = base::Time::Now();
#endif
@@ -105,27 +107,11 @@ bool AudioInputSyncWriter::Init() {
foreign_socket_.get());
}
-#if defined(OS_WIN)
-
-bool AudioInputSyncWriter::PrepareForeignSocketHandle(
+bool AudioInputSyncWriter::PrepareForeignSocket(
base::ProcessHandle process_handle,
- base::SyncSocket::Handle* foreign_handle) {
- ::DuplicateHandle(GetCurrentProcess(), foreign_socket_->handle(),
- process_handle, foreign_handle,
- 0, FALSE, DUPLICATE_SAME_ACCESS);
- return (*foreign_handle != 0);
+ base::SyncSocket::TransitDescriptor* descriptor) {
+ return foreign_socket_->PrepareTransitDescriptor(process_handle, descriptor);
}
-#else
-
-bool AudioInputSyncWriter::PrepareForeignSocketHandle(
- base::ProcessHandle process_handle,
- base::FileDescriptor* foreign_handle) {
- foreign_handle->fd = foreign_socket_->handle();
- foreign_handle->auto_close = false;
- return (foreign_handle->fd != -1);
-}
-
-#endif
} // namespace content
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 424d7907f11..1ace401441f 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
@@ -32,22 +32,18 @@ class AudioInputSyncWriter : public media::AudioInputController::SyncWriter {
int shared_memory_segment_count,
const media::AudioParameters& params);
- virtual ~AudioInputSyncWriter();
+ ~AudioInputSyncWriter() override;
// media::AudioInputController::SyncWriter implementation.
- virtual void UpdateRecordedBytes(uint32 bytes) OVERRIDE;
- virtual void Write(const media::AudioBus* data,
- double volume,
- bool key_pressed) OVERRIDE;
- virtual void Close() OVERRIDE;
+ void UpdateRecordedBytes(uint32 bytes) override;
+ void Write(const media::AudioBus* data,
+ double volume,
+ bool key_pressed) override;
+ void Close() override;
bool Init();
- bool PrepareForeignSocketHandle(base::ProcessHandle process_handle,
-#if defined(OS_WIN)
- base::SyncSocket::Handle* foreign_handle);
-#else
- base::FileDescriptor* foreign_handle);
-#endif
+ bool PrepareForeignSocket(base::ProcessHandle process_handle,
+ base::SyncSocket::TransitDescriptor* descriptor);
private:
base::SharedMemory* shared_memory_;
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 7b07fd99c3b..43555fcdb19 100644
--- a/chromium/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/chromium/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -6,10 +6,13 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/logging.h"
#include "base/memory/shared_memory.h"
#include "base/metrics/histogram.h"
#include "base/process/process.h"
#include "content/browser/browser_main_loop.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"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
@@ -39,7 +42,7 @@ class AudioRendererHost::AudioEntry
const std::string& output_device_id,
scoped_ptr<base::SharedMemory> shared_memory,
scoped_ptr<media::AudioOutputController::SyncReader> reader);
- virtual ~AudioEntry();
+ ~AudioEntry() override;
int stream_id() const {
return stream_id_;
@@ -66,12 +69,11 @@ class AudioRendererHost::AudioEntry
private:
// media::AudioOutputController::EventHandler implementation.
- virtual void OnCreated() OVERRIDE;
- virtual void OnPlaying() OVERRIDE;
- virtual void OnPaused() OVERRIDE;
- virtual void OnError() OVERRIDE;
- virtual void OnDeviceChange(int new_buffer_size, int new_sample_rate)
- OVERRIDE;
+ void OnCreated() override;
+ void OnPlaying() override;
+ void OnPaused() override;
+ void OnError() override;
+ void OnDeviceChange(int new_buffer_size, int new_sample_rate) override;
AudioRendererHost* const host_;
const int stream_id_;
@@ -238,24 +240,17 @@ void AudioRendererHost::DoCompleteCreation(int stream_id) {
AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
-#if defined(OS_WIN)
- base::SyncSocket::Handle foreign_socket_handle;
-#else
- base::FileDescriptor foreign_socket_handle;
-#endif
+ base::SyncSocket::TransitDescriptor socket_descriptor;
// If we failed to prepare the sync socket for the renderer then we fail
// the construction of audio stream.
- if (!reader->PrepareForeignSocketHandle(PeerHandle(),
- &foreign_socket_handle)) {
+ if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
ReportErrorAndClose(entry->stream_id());
return;
}
Send(new AudioMsg_NotifyStreamCreated(
- entry->stream_id(),
- foreign_memory_handle,
- foreign_socket_handle,
+ entry->stream_id(), foreign_memory_handle, socket_descriptor,
entry->shared_memory()->requested_size()));
}
@@ -272,30 +267,18 @@ void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
is_playing ? media::AudioOutputIPCDelegate::kPlaying
: media::AudioOutputIPCDelegate::kPaused));
- MediaObserver* const media_observer =
- GetContentClient()->browser()->GetMediaObserver();
- if (media_observer) {
- if (is_playing) {
- media_observer->OnAudioStreamPlaying(
- render_process_id_,
- entry->render_frame_id(),
- entry->stream_id(),
- base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
- entry->controller()));
- if (!entry->playing()) {
- entry->set_playing(true);
- base::AtomicRefCountInc(&num_playing_streams_);
- }
- } else {
- media_observer->OnAudioStreamStopped(render_process_id_,
- entry->render_frame_id(),
- entry->stream_id());
- if (entry->playing()) {
- entry->set_playing(false);
- base::AtomicRefCountDec(&num_playing_streams_);
- }
- }
+ if (is_playing) {
+ AudioStreamMonitor::StartMonitoringStream(
+ render_process_id_,
+ entry->render_frame_id(),
+ entry->stream_id(),
+ base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
+ entry->controller()));
+ } else {
+ AudioStreamMonitor::StopMonitoringStream(
+ render_process_id_, entry->render_frame_id(), entry->stream_id());
}
+ UpdateNumPlayingStreams(entry, is_playing);
}
RenderViewHost::AudioOutputControllerList
@@ -303,8 +286,9 @@ AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
RenderViewHost::AudioOutputControllerList controllers;
- AudioEntryMap::const_iterator it = audio_entries_.begin();
- for (; it != audio_entries_.end(); ++it) {
+ for (AudioEntryMap::const_iterator it = audio_entries_.begin();
+ it != audio_entries_.end();
+ ++it) {
AudioEntry* entry = it->second;
if (entry->render_view_id() == render_view_id)
controllers.push_back(entry->controller());
@@ -357,8 +341,6 @@ void AudioRendererHost::OnCreateStream(
output_device_id = info->device.matched_output_device_id;
// Create the shared memory and share with the renderer process.
- // For synchronized I/O (if input_channels > 0) then we allocate
- // extra memory after the output data for the input data.
uint32 shared_memory_size = AudioBus::CalculateMemorySize(params);
scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
@@ -378,18 +360,17 @@ void AudioRendererHost::OnCreateStream(
if (media_observer)
media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
- scoped_ptr<AudioEntry> entry(new AudioEntry(
- this,
- stream_id,
- render_view_id,
- render_frame_id,
- params,
- output_device_id,
- shared_memory.Pass(),
- reader.PassAs<media::AudioOutputController::SyncReader>()));
+ scoped_ptr<AudioEntry> entry(new AudioEntry(this,
+ stream_id,
+ render_view_id,
+ render_frame_id,
+ params,
+ output_device_id,
+ shared_memory.Pass(),
+ reader.Pass()));
if (mirroring_manager_) {
mirroring_manager_->AddDiverter(
- render_process_id_, entry->render_view_id(), entry->controller());
+ render_process_id_, entry->render_frame_id(), entry->controller());
}
audio_entries_.insert(std::make_pair(stream_id, entry.release()));
audio_log_->OnCreated(stream_id, params, output_device_id);
@@ -454,10 +435,8 @@ void AudioRendererHost::OnCloseStream(int stream_id) {
audio_entries_.erase(i);
media::AudioOutputController* const controller = entry->controller();
- if (mirroring_manager_) {
- mirroring_manager_->RemoveDiverter(
- render_process_id_, entry->render_view_id(), controller);
- }
+ if (mirroring_manager_)
+ mirroring_manager_->RemoveDiverter(controller);
controller->Close(
base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
audio_log_->OnClosed(stream_id);
@@ -465,17 +444,9 @@ void AudioRendererHost::OnCloseStream(int stream_id) {
void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // At this point, make the final "say" in audio playback state.
- MediaObserver* const media_observer =
- GetContentClient()->browser()->GetMediaObserver();
- if (media_observer) {
- media_observer->OnAudioStreamStopped(render_process_id_,
- entry->render_frame_id(),
- entry->stream_id());
- if (entry->playing())
- base::AtomicRefCountDec(&num_playing_streams_);
- }
+ AudioStreamMonitor::StopMonitoringStream(
+ render_process_id_, entry->render_frame_id(), entry->stream_id());
+ UpdateNumPlayingStreams(entry.get(), false);
}
void AudioRendererHost::ReportErrorAndClose(int stream_id) {
@@ -500,8 +471,44 @@ AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
return i != audio_entries_.end() ? i->second : NULL;
}
+void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry,
+ bool is_playing) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (entry->playing() == is_playing)
+ return;
+
+ bool should_alert_resource_scheduler;
+ if (is_playing) {
+ should_alert_resource_scheduler =
+ !RenderViewHasActiveAudio(entry->render_view_id());
+ entry->set_playing(true);
+ base::AtomicRefCountInc(&num_playing_streams_);
+ } else {
+ entry->set_playing(false);
+ should_alert_resource_scheduler =
+ !RenderViewHasActiveAudio(entry->render_view_id());
+ base::AtomicRefCountDec(&num_playing_streams_);
+ }
+
+ if (should_alert_resource_scheduler && ResourceDispatcherHostImpl::Get()) {
+ ResourceDispatcherHostImpl::Get()->OnAudioRenderHostStreamStateChanged(
+ render_process_id_, entry->render_view_id(), is_playing);
+ }
+}
+
bool AudioRendererHost::HasActiveAudio() {
return !base::AtomicRefCountIsZero(&num_playing_streams_);
}
+bool AudioRendererHost::RenderViewHasActiveAudio(int render_view_id) const {
+ for (AudioEntryMap::const_iterator it = audio_entries_.begin();
+ it != audio_entries_.end();
+ ++it) {
+ AudioEntry* entry = it->second;
+ if (entry->render_view_id() == render_view_id && entry->playing())
+ return true;
+ }
+ return false;
+}
+
} // namespace content
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 38317ef8094..11bc13f3900 100644
--- a/chromium/content/browser/renderer_host/media/audio_renderer_host.h
+++ b/chromium/content/browser/renderer_host/media/audio_renderer_host.h
@@ -81,14 +81,18 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
const RenderViewHost::GetAudioOutputControllersCallback& callback) const;
// BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelClosing() override;
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// Returns true if any streams managed by this host are actively playing. Can
// be called from any thread.
bool HasActiveAudio();
+ // Returns true if any streams managed by the RenderView identified by
+ // |render_view_id| are actively playing. Can be called from any thread.
+ bool RenderViewHasActiveAudio(int render_view_id) const;
+
private:
friend class AudioRendererHostTest;
friend class BrowserThread;
@@ -101,7 +105,7 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
class AudioEntry;
typedef std::map<int, AudioEntry*> AudioEntryMap;
- virtual ~AudioRendererHost();
+ ~AudioRendererHost() override;
// Methods called on IO thread ----------------------------------------------
@@ -157,6 +161,10 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// Returns NULL if not found.
AudioEntry* LookupById(int stream_id);
+ // A helper method to update the number of playing streams and alert the
+ // ResourceScheduler when the renderer starts or stops playing an audiostream.
+ void UpdateNumPlayingStreams(AudioEntry* entry, bool is_playing);
+
// ID of the RenderProcessHost that owns this instance.
const int render_process_id_;
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 343c9890810..8c03eaca66b 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
@@ -43,12 +43,9 @@ class MockAudioMirroringManager : public AudioMirroringManager {
MOCK_METHOD3(AddDiverter,
void(int render_process_id,
- int render_view_id,
- Diverter* diverter));
- MOCK_METHOD3(RemoveDiverter,
- void(int render_process_id,
- int render_view_id,
+ int render_frame_id,
Diverter* diverter));
+ MOCK_METHOD1(RemoveDiverter, void(Diverter* diverter));
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioMirroringManager);
@@ -101,14 +98,9 @@ class MockAudioRendererHost : public AudioRendererHost {
return true;
}
- void OnNotifyStreamCreated(int stream_id,
- base::SharedMemoryHandle handle,
-#if defined(OS_WIN)
- base::SyncSocket::Handle socket_handle,
-#else
- base::FileDescriptor socket_descriptor,
-#endif
- uint32 length) {
+ void OnNotifyStreamCreated(
+ int stream_id, base::SharedMemoryHandle handle,
+ base::SyncSocket::TransitDescriptor socket_descriptor, uint32 length) {
// Maps the shared memory.
shared_memory_.reset(new base::SharedMemory(handle, false));
CHECK(shared_memory_->Map(length));
@@ -116,12 +108,8 @@ class MockAudioRendererHost : public AudioRendererHost {
shared_memory_length_ = length;
// Create the SyncSocket using the handle.
- base::SyncSocket::Handle sync_socket_handle;
-#if defined(OS_WIN)
- sync_socket_handle = socket_handle;
-#else
- sync_socket_handle = socket_descriptor.fd;
-#endif
+ base::SyncSocket::Handle sync_socket_handle =
+ base::SyncSocket::UnwrapHandle(socket_descriptor);
sync_socket_.reset(new base::SyncSocket(sync_socket_handle));
// And then delegate the call to the mock method.
@@ -157,7 +145,7 @@ class AudioRendererHostTest : public testing::Test {
public:
AudioRendererHostTest() {
audio_manager_.reset(media::AudioManager::CreateForTesting());
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kUseFakeDeviceForMediaStream);
media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
host_ = new MockAudioRendererHost(audio_manager_.get(),
@@ -169,7 +157,7 @@ class AudioRendererHostTest : public testing::Test {
host_->set_peer_pid_for_testing(base::GetCurrentProcId());
}
- virtual ~AudioRendererHostTest() {
+ ~AudioRendererHostTest() override {
// Simulate closing the IPC channel and give the audio thread time to close
// the underlying streams.
host_->OnChannelClosing();
@@ -185,7 +173,7 @@ class AudioRendererHostTest : public testing::Test {
EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _));
EXPECT_CALL(mirroring_manager_,
- AddDiverter(kRenderProcessId, kRenderViewId, NotNull()))
+ AddDiverter(kRenderProcessId, kRenderFrameId, NotNull()))
.RetiresOnSaturation();
// Send a create stream message to the audio output stream and wait until
@@ -199,7 +187,6 @@ class AudioRendererHostTest : public testing::Test {
params = media::AudioParameters(
media::AudioParameters::AUDIO_FAKE,
media::CHANNEL_LAYOUT_STEREO,
- 2,
media::AudioParameters::kAudioCDSampleRate, 16,
media::AudioParameters::kAudioCDSampleRate / 10,
media::AudioParameters::NO_EFFECTS);
@@ -216,8 +203,7 @@ class AudioRendererHostTest : public testing::Test {
// At some point in the future, a corresponding RemoveDiverter() call must
// be made.
- EXPECT_CALL(mirroring_manager_,
- RemoveDiverter(kRenderProcessId, kRenderViewId, NotNull()))
+ EXPECT_CALL(mirroring_manager_, RemoveDiverter(NotNull()))
.RetiresOnSaturation();
SyncWithAudioThread();
}
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 3daacca566e..e6657ef74ca 100644
--- a/chromium/content/browser/renderer_host/media/audio_sync_reader.cc
+++ b/chromium/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -9,12 +9,31 @@
#include "base/command_line.h"
#include "base/memory/shared_memory.h"
#include "base/metrics/histogram.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/public/common/content_switches.h"
-#include "media/audio/audio_buffers_state.h"
#include "media/audio/audio_parameters.h"
using media::AudioBus;
+namespace {
+
+// Used to log if any audio glitches have been detected during an audio session.
+// Elements in this enum should not be added, deleted or rearranged.
+enum AudioGlitchResult {
+ AUDIO_RENDERER_NO_AUDIO_GLITCHES = 0,
+ AUDIO_RENDERER_AUDIO_GLITCHES = 1,
+ AUDIO_RENDERER_AUDIO_GLITCHES_MAX = AUDIO_RENDERER_AUDIO_GLITCHES
+};
+
+void LogAudioGlitchResult(AudioGlitchResult result) {
+ UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererAudioGlitches",
+ result,
+ AUDIO_RENDERER_AUDIO_GLITCHES_MAX + 1);
+}
+
+} // namespace
+
namespace content {
AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory,
@@ -47,6 +66,18 @@ AudioSyncReader::~AudioSyncReader() {
100.0 * renderer_missed_callback_count_ / renderer_callback_count_;
UMA_HISTOGRAM_PERCENTAGE(
"Media.AudioRendererMissedDeadline", percentage_missed);
+
+ // Add more detailed information regarding detected audio glitches where
+ // a non-zero value of |renderer_missed_callback_count_| is added to the
+ // AUDIO_RENDERER_AUDIO_GLITCHES bin.
+ renderer_missed_callback_count_ > 0 ?
+ LogAudioGlitchResult(AUDIO_RENDERER_AUDIO_GLITCHES) :
+ LogAudioGlitchResult(AUDIO_RENDERER_NO_AUDIO_GLITCHES);
+ std::string log_string =
+ base::StringPrintf("ASR: number of detected audio glitches=%d",
+ static_cast<int>(renderer_missed_callback_count_));
+ MediaStreamManager::SendMessageToNativeLog(log_string);
+ DVLOG(1) << log_string;
}
// media::AudioOutputController::SyncReader implementations.
@@ -83,24 +114,11 @@ bool AudioSyncReader::Init() {
foreign_socket_.get());
}
-#if defined(OS_WIN)
-bool AudioSyncReader::PrepareForeignSocketHandle(
+bool AudioSyncReader::PrepareForeignSocket(
base::ProcessHandle process_handle,
- base::SyncSocket::Handle* foreign_handle) {
- ::DuplicateHandle(GetCurrentProcess(), foreign_socket_->handle(),
- process_handle, foreign_handle,
- 0, FALSE, DUPLICATE_SAME_ACCESS);
- return (*foreign_handle != 0);
+ base::SyncSocket::TransitDescriptor* descriptor) {
+ return foreign_socket_->PrepareTransitDescriptor(process_handle, descriptor);
}
-#else
-bool AudioSyncReader::PrepareForeignSocketHandle(
- base::ProcessHandle process_handle,
- base::FileDescriptor* foreign_handle) {
- foreign_handle->fd = foreign_socket_->handle();
- foreign_handle->auto_close = false;
- return (foreign_handle->fd != -1);
-}
-#endif
bool AudioSyncReader::WaitUntilDataIsReady() {
base::TimeDelta timeout = maximum_wait_time_;
@@ -125,10 +143,11 @@ bool AudioSyncReader::WaitUntilDataIsReady() {
while (timeout.InMicroseconds() > 0) {
bytes_received = socket_->ReceiveWithTimeout(
&renderer_buffer_index, sizeof(renderer_buffer_index), timeout);
- if (!bytes_received)
+ if (bytes_received != sizeof(renderer_buffer_index)) {
+ bytes_received = 0;
break;
+ }
- DCHECK_EQ(bytes_received, sizeof(renderer_buffer_index));
if (renderer_buffer_index == buffer_index_)
break;
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 d596d1b4c0e..16af1921894 100644
--- a/chromium/content/browser/renderer_host/media/audio_sync_reader.h
+++ b/chromium/content/browser/renderer_host/media/audio_sync_reader.h
@@ -31,20 +31,16 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
AudioSyncReader(base::SharedMemory* shared_memory,
const media::AudioParameters& params);
- virtual ~AudioSyncReader();
+ ~AudioSyncReader() override;
// media::AudioOutputController::SyncReader implementations.
- virtual void UpdatePendingBytes(uint32 bytes) OVERRIDE;
- virtual void Read(media::AudioBus* dest) OVERRIDE;
- virtual void Close() OVERRIDE;
+ void UpdatePendingBytes(uint32 bytes) override;
+ void Read(media::AudioBus* dest) override;
+ void Close() override;
bool Init();
- bool PrepareForeignSocketHandle(base::ProcessHandle process_handle,
-#if defined(OS_WIN)
- base::SyncSocket::Handle* foreign_handle);
-#else
- base::FileDescriptor* foreign_handle);
-#endif
+ bool PrepareForeignSocket(base::ProcessHandle process_handle,
+ base::SyncSocket::TransitDescriptor* descriptor);
private:
// Blocks until data is ready for reading or a timeout expires. Returns false
diff --git a/chromium/content/browser/renderer_host/media/device_request_message_filter.cc b/chromium/content/browser/renderer_host/media/device_request_message_filter.cc
deleted file mode 100644
index db0d175e754..00000000000
--- a/chromium/content/browser/renderer_host/media/device_request_message_filter.cc
+++ /dev/null
@@ -1,150 +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.
-
-#include "content/browser/renderer_host/media/device_request_message_filter.h"
-
-#include "content/browser/browser_main_loop.h"
-#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/renderer_host/media/media_stream_manager.h"
-#include "content/common/media/media_stream_messages.h"
-#include "content/public/browser/resource_context.h"
-
-namespace content {
-
-DeviceRequestMessageFilter::DeviceRequestMessageFilter(
- ResourceContext* resource_context,
- MediaStreamManager* media_stream_manager,
- int render_process_id)
- : BrowserMessageFilter(MediaStreamMsgStart),
- resource_context_(resource_context),
- media_stream_manager_(media_stream_manager),
- render_process_id_(render_process_id) {
- DCHECK(resource_context);
- DCHECK(media_stream_manager);
-}
-
-DeviceRequestMessageFilter::~DeviceRequestMessageFilter() {
- // CHECK rather than DCHECK to make sure this never happens in the
- // wild. We want to be sure due to http://crbug.com/341211
- CHECK(requests_.empty());
-}
-
-struct DeviceRequestMessageFilter::DeviceRequest {
- DeviceRequest(int request_id,
- const GURL& origin,
- const std::string& audio_devices_label,
- const std::string& video_devices_label)
- : request_id(request_id),
- origin(origin),
- has_audio_returned(false),
- has_video_returned(false),
- audio_devices_label(audio_devices_label),
- video_devices_label(video_devices_label) {}
-
- int request_id;
- GURL origin;
- bool has_audio_returned;
- bool has_video_returned;
- std::string audio_devices_label;
- std::string video_devices_label;
- StreamDeviceInfoArray audio_devices;
- StreamDeviceInfoArray video_devices;
-};
-
-void DeviceRequestMessageFilter::DevicesEnumerated(
- int render_view_id,
- int page_request_id,
- const std::string& label,
- const StreamDeviceInfoArray& new_devices) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // Look up the DeviceRequest by id.
- DeviceRequestList::iterator request_it = requests_.begin();
- for (; request_it != requests_.end(); ++request_it) {
- if (label == request_it->audio_devices_label ||
- label == request_it->video_devices_label) {
- break;
- }
- }
- DCHECK(request_it != requests_.end());
-
- StreamDeviceInfoArray* audio_devices = &request_it->audio_devices;
- StreamDeviceInfoArray* video_devices = &request_it->video_devices;
-
- // Store hmac'd device ids instead of raw device ids.
- if (label == request_it->audio_devices_label) {
- request_it->has_audio_returned = true;
- DCHECK(audio_devices->empty());
- *audio_devices = new_devices;
- } else {
- DCHECK(label == request_it->video_devices_label);
- request_it->has_video_returned = true;
- DCHECK(video_devices->empty());
- *video_devices = new_devices;
- }
-
- if (!request_it->has_audio_returned || !request_it->has_video_returned) {
- // Wait for the rest of the devices to complete.
- return;
- }
-
- // Both audio and video devices are ready for copying.
- StreamDeviceInfoArray all_devices = *audio_devices;
- all_devices.insert(
- all_devices.end(), video_devices->begin(), video_devices->end());
-
- Send(new MediaStreamMsg_GetSourcesACK(request_it->request_id, all_devices));
-
- media_stream_manager_->CancelRequest(request_it->audio_devices_label);
- media_stream_manager_->CancelRequest(request_it->video_devices_label);
- requests_.erase(request_it);
-}
-
-bool DeviceRequestMessageFilter::OnMessageReceived(
- const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(DeviceRequestMessageFilter, message)
- IPC_MESSAGE_HANDLER(MediaStreamHostMsg_GetSources, OnGetSources)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void DeviceRequestMessageFilter::OnChannelClosing() {
- // Since the IPC channel is gone, cancel outstanding device requests.
- for (DeviceRequestList::iterator request_it = requests_.begin();
- request_it != requests_.end(); ++request_it) {
- media_stream_manager_->CancelRequest(request_it->audio_devices_label);
- media_stream_manager_->CancelRequest(request_it->video_devices_label);
- }
- requests_.clear();
-}
-
-void DeviceRequestMessageFilter::OnGetSources(int request_id,
- const GURL& security_origin) {
- if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
- render_process_id_, security_origin)) {
- LOG(ERROR) << "Disallowed URL in DRMF::OnGetSources: " << security_origin;
- return;
- }
-
- // Make request to get audio devices.
- const std::string& audio_label = media_stream_manager_->EnumerateDevices(
- this, -1, -1, resource_context_->GetMediaDeviceIDSalt(), -1,
- MEDIA_DEVICE_AUDIO_CAPTURE, security_origin,
- resource_context_->AllowMicAccess(security_origin));
- DCHECK(!audio_label.empty());
-
- // Make request for video devices.
- const std::string& video_label = media_stream_manager_->EnumerateDevices(
- this, -1, -1, resource_context_->GetMediaDeviceIDSalt(), -1,
- MEDIA_DEVICE_VIDEO_CAPTURE, security_origin,
- resource_context_->AllowCameraAccess(security_origin));
- DCHECK(!video_label.empty());
-
- requests_.push_back(DeviceRequest(
- request_id, security_origin, audio_label, video_label));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/device_request_message_filter.h b/chromium/content/browser/renderer_host/media/device_request_message_filter.h
deleted file mode 100644
index 2ec54ccfc37..00000000000
--- a/chromium/content/browser/renderer_host/media/device_request_message_filter.h
+++ /dev/null
@@ -1,81 +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.
-
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_DEVICE_REQUEST_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_DEVICE_REQUEST_MESSAGE_FILTER_H_
-
-#include <map>
-#include <string>
-
-#include "base/synchronization/lock.h"
-#include "content/browser/renderer_host/media/media_stream_requester.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/browser_message_filter.h"
-
-namespace content {
-
-class MediaStreamManager;
-class ResourceContext;
-
-// DeviceRequestMessageFilter used to delegate requests from the
-// MediaStreamCenter.
-class CONTENT_EXPORT DeviceRequestMessageFilter : public BrowserMessageFilter,
- public MediaStreamRequester {
- public:
- DeviceRequestMessageFilter(ResourceContext* resource_context,
- MediaStreamManager* media_stream_manager,
- int render_process_id);
-
- // MediaStreamRequester implementation.
- // TODO(vrk): Replace MediaStreamRequester interface with a single callback so
- // we don't have to override all these callbacks we don't care about.
- // (crbug.com/249476)
- virtual void StreamGenerated(
- int render_view_id, int page_request_id, const std::string& label,
- const StreamDeviceInfoArray& audio_devices,
- const StreamDeviceInfoArray& video_devices) OVERRIDE {}
- virtual void StreamGenerationFailed(
- int render_view_id,
- int page_request_id,
- content::MediaStreamRequestResult result) OVERRIDE {}
- virtual void DeviceStopped(int render_view_id,
- const std::string& label,
- const StreamDeviceInfo& device) OVERRIDE {}
- virtual void DeviceOpened(int render_view_id,
- int page_request_id,
- const std::string& label,
- const StreamDeviceInfo& video_device) OVERRIDE {}
- // DevicesEnumerated() is the only callback we're interested in.
- virtual void DevicesEnumerated(int render_view_id,
- int page_request_id,
- const std::string& label,
- const StreamDeviceInfoArray& devices) OVERRIDE;
-
- // BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OnChannelClosing() OVERRIDE;
-
- protected:
- virtual ~DeviceRequestMessageFilter();
-
- private:
- void OnGetSources(int request_id, const GURL& security_origin);
-
- // Owned by ProfileIOData which is guaranteed to outlive DRMF.
- ResourceContext* resource_context_;
- MediaStreamManager* media_stream_manager_;
-
- struct DeviceRequest;
- typedef std::vector<DeviceRequest> DeviceRequestList;
- // List of all requests.
- DeviceRequestList requests_;
-
- int render_process_id_;
-
- DISALLOW_COPY_AND_ASSIGN(DeviceRequestMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_DEVICE_REQUEST_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/renderer_host/media/device_request_message_filter_unittest.cc b/chromium/content/browser/renderer_host/media/device_request_message_filter_unittest.cc
deleted file mode 100644
index 6d6a9e34dad..00000000000
--- a/chromium/content/browser/renderer_host/media/device_request_message_filter_unittest.cc
+++ /dev/null
@@ -1,213 +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.
-
-#include "base/strings/string_number_conversions.h"
-#include "content/browser/renderer_host/media/device_request_message_filter.h"
-#include "content/browser/renderer_host/media/media_stream_manager.h"
-#include "content/common/media/media_stream_messages.h"
-#include "content/public/test/mock_resource_context.h"
-#include "content/public/test/test_browser_thread.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-using ::testing::Invoke;
-
-namespace content {
-
-static const std::string kAudioLabel = "audio_label";
-static const std::string kVideoLabel = "video_label";
-
-class MockMediaStreamManager : public MediaStreamManager {
- public:
- MockMediaStreamManager() {}
-
- virtual ~MockMediaStreamManager() {}
-
- MOCK_METHOD8(EnumerateDevices,
- std::string(MediaStreamRequester* requester,
- int render_process_id,
- int render_view_id,
- const ResourceContext::SaltCallback& rc,
- int page_request_id,
- MediaStreamType type,
- const GURL& security_origin,
- bool have_permission));
-
- std::string DoEnumerateDevices(MediaStreamRequester* requester,
- int render_process_id,
- int render_view_id,
- const ResourceContext::SaltCallback& rc,
- int page_request_id,
- MediaStreamType type,
- const GURL& security_origin,
- bool have_permission) {
- if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
- return kAudioLabel;
- } else {
- return kVideoLabel;
- }
- }
-};
-
-class MockDeviceRequestMessageFilter : public DeviceRequestMessageFilter {
- public:
- MockDeviceRequestMessageFilter(MockResourceContext* context,
- MockMediaStreamManager* manager)
- : DeviceRequestMessageFilter(context, manager, 0), received_id_(-1) {}
- StreamDeviceInfoArray requested_devices() { return requested_devices_; }
- int received_id() { return received_id_; }
-
- private:
- virtual ~MockDeviceRequestMessageFilter() {}
-
- // Override the Send() method to intercept the message that we're sending to
- // the renderer.
- virtual bool Send(IPC::Message* reply_msg) OVERRIDE {
- CHECK(reply_msg);
-
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(MockDeviceRequestMessageFilter, *reply_msg)
- IPC_MESSAGE_HANDLER(MediaStreamMsg_GetSourcesACK, SaveDevices)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- EXPECT_TRUE(handled);
-
- delete reply_msg;
- return true;
- }
-
- void SaveDevices(int request_id, const StreamDeviceInfoArray& devices) {
- received_id_ = request_id;
- requested_devices_ = devices;
- }
-
- int received_id_;
- StreamDeviceInfoArray requested_devices_;
-};
-
-class DeviceRequestMessageFilterTest : public testing::Test {
- public:
- DeviceRequestMessageFilterTest() : next_device_id_(0) {}
-
- void RunTest(int number_audio_devices, int number_video_devices) {
- AddAudioDevices(number_audio_devices);
- AddVideoDevices(number_video_devices);
- GURL origin("https://test.com");
- EXPECT_CALL(*media_stream_manager_,
- EnumerateDevices(_, _, _, _, _, MEDIA_DEVICE_AUDIO_CAPTURE,
- _, _))
- .Times(1);
- EXPECT_CALL(*media_stream_manager_,
- EnumerateDevices(_, _, _, _, _, MEDIA_DEVICE_VIDEO_CAPTURE,
- _, _))
- .Times(1);
- // Send message to get devices. Should trigger 2 EnumerateDevice() requests.
- const int kRequestId = 123;
- SendGetSourcesMessage(kRequestId, origin);
-
- // Run audio callback. Because there's still an outstanding video request,
- // this should not populate |message|.
- FireAudioDeviceCallback();
- EXPECT_EQ(0u, host_->requested_devices().size());
-
- // After the video device callback is fired, |message| should be populated.
- FireVideoDeviceCallback();
- EXPECT_EQ(static_cast<size_t>(number_audio_devices + number_video_devices),
- host_->requested_devices().size());
-
- EXPECT_EQ(kRequestId, host_->received_id());
- }
-
- protected:
- virtual ~DeviceRequestMessageFilterTest() {}
-
- virtual void SetUp() OVERRIDE {
- message_loop_.reset(new base::MessageLoopForIO);
- io_thread_.reset(
- new TestBrowserThread(BrowserThread::IO, message_loop_.get()));
-
- media_stream_manager_.reset(new MockMediaStreamManager());
- ON_CALL(*media_stream_manager_, EnumerateDevices(_, _, _, _, _, _, _, _))
- .WillByDefault(Invoke(media_stream_manager_.get(),
- &MockMediaStreamManager::DoEnumerateDevices));
-
- resource_context_.reset(new MockResourceContext(NULL));
- host_ = new MockDeviceRequestMessageFilter(resource_context_.get(),
- media_stream_manager_.get());
- }
-
- scoped_refptr<MockDeviceRequestMessageFilter> host_;
- scoped_ptr<MockMediaStreamManager> media_stream_manager_;
- scoped_ptr<MockResourceContext> resource_context_;
- StreamDeviceInfoArray physical_audio_devices_;
- StreamDeviceInfoArray physical_video_devices_;
- scoped_ptr<base::MessageLoop> message_loop_;
- scoped_ptr<TestBrowserThread> io_thread_;
-
- private:
- void AddAudioDevices(int number_of_devices) {
- for (int i = 0; i < number_of_devices; i++) {
- physical_audio_devices_.push_back(
- StreamDeviceInfo(
- MEDIA_DEVICE_AUDIO_CAPTURE,
- "/dev/audio/" + base::IntToString(next_device_id_),
- "Audio Device" + base::IntToString(next_device_id_)));
- next_device_id_++;
- }
- }
-
- void AddVideoDevices(int number_of_devices) {
- for (int i = 0; i < number_of_devices; i++) {
- physical_video_devices_.push_back(
- StreamDeviceInfo(
- MEDIA_DEVICE_VIDEO_CAPTURE,
- "/dev/video/" + base::IntToString(next_device_id_),
- "Video Device" + base::IntToString(next_device_id_)));
- next_device_id_++;
- }
- }
-
- void SendGetSourcesMessage(int request_id, const GURL& origin) {
- host_->OnMessageReceived(MediaStreamHostMsg_GetSources(request_id, origin));
- }
-
- void FireAudioDeviceCallback() {
- host_->DevicesEnumerated(-1, -1, kAudioLabel, physical_audio_devices_);
- }
-
- void FireVideoDeviceCallback() {
- host_->DevicesEnumerated(-1, -1, kVideoLabel, physical_video_devices_);
- }
-
- int next_device_id_;
-};
-
-TEST_F(DeviceRequestMessageFilterTest, TestGetSources_AudioAndVideoDevices) {
- // Runs through test with 1 audio and 1 video device.
- RunTest(1, 1);
-}
-
-TEST_F(DeviceRequestMessageFilterTest,
- TestGetSources_MultipleAudioAndVideoDevices) {
- // Runs through test with 3 audio devices and 2 video devices.
- RunTest(3, 2);
-}
-
-TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoVideoDevices) {
- // Runs through test with 4 audio devices and 0 video devices.
- RunTest(4, 0);
-}
-
-TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoAudioDevices) {
- // Runs through test with 0 audio devices and 3 video devices.
- RunTest(0, 3);
-}
-
-TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoDevices) {
- // Runs through test with no devices.
- RunTest(0, 0);
-}
-
-}; // namespace content
diff --git a/chromium/content/browser/renderer_host/media/media_capture_devices_impl.h b/chromium/content/browser/renderer_host/media/media_capture_devices_impl.h
index 078f659608b..77174cc6205 100644
--- a/chromium/content/browser/renderer_host/media/media_capture_devices_impl.h
+++ b/chromium/content/browser/renderer_host/media/media_capture_devices_impl.h
@@ -15,8 +15,8 @@ class MediaCaptureDevicesImpl : public MediaCaptureDevices {
static MediaCaptureDevicesImpl* GetInstance();
// Overriden from MediaCaptureDevices
- virtual const MediaStreamDevices& GetAudioCaptureDevices() OVERRIDE;
- virtual const MediaStreamDevices& GetVideoCaptureDevices() OVERRIDE;
+ const MediaStreamDevices& GetAudioCaptureDevices() override;
+ const MediaStreamDevices& GetVideoCaptureDevices() override;
// Called by MediaStreamManager to notify the change of media capture
// devices, these 2 methods are called in IO thread.
@@ -26,7 +26,7 @@ class MediaCaptureDevicesImpl : public MediaCaptureDevices {
private:
friend struct DefaultSingletonTraits<MediaCaptureDevicesImpl>;
MediaCaptureDevicesImpl();
- virtual ~MediaCaptureDevicesImpl();
+ ~MediaCaptureDevicesImpl() override;
void UpdateAudioDevicesOnUIThread(const content::MediaStreamDevices& devices);
void UpdateVideoDevicesOnUIThread(const content::MediaStreamDevices& devices);
diff --git a/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
index 91fad34fe5c..2b0a385f8f9 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -16,17 +16,15 @@ namespace content {
MediaStreamDispatcherHost::MediaStreamDispatcherHost(
int render_process_id,
const ResourceContext::SaltCallback& salt_callback,
- MediaStreamManager* media_stream_manager,
- ResourceContext* resource_context)
+ MediaStreamManager* media_stream_manager)
: BrowserMessageFilter(MediaStreamMsgStart),
render_process_id_(render_process_id),
salt_callback_(salt_callback),
- media_stream_manager_(media_stream_manager),
- resource_context_(resource_context) {
+ media_stream_manager_(media_stream_manager) {
}
void MediaStreamDispatcherHost::StreamGenerated(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfoArray& audio_devices,
@@ -36,12 +34,11 @@ void MediaStreamDispatcherHost::StreamGenerated(
<< ", {label = " << label << "})";
Send(new MediaStreamMsg_StreamGenerated(
- render_view_id, page_request_id, label, audio_devices,
- video_devices));
+ render_frame_id, page_request_id, label, audio_devices, video_devices));
}
void MediaStreamDispatcherHost::StreamGenerationFailed(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
content::MediaStreamRequestResult result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -50,12 +47,12 @@ void MediaStreamDispatcherHost::StreamGenerationFailed(
<< ", { result= " << result << "})";
- Send(new MediaStreamMsg_StreamGenerationFailed(render_view_id,
+ Send(new MediaStreamMsg_StreamGenerationFailed(render_frame_id,
page_request_id,
result));
}
-void MediaStreamDispatcherHost::DeviceStopped(int render_view_id,
+void MediaStreamDispatcherHost::DeviceStopped(int render_frame_id,
const std::string& label,
const StreamDeviceInfo& device) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -64,11 +61,11 @@ void MediaStreamDispatcherHost::DeviceStopped(int render_view_id,
<< "{type = " << device.device.type << "}, "
<< "{device_id = " << device.device.id << "})";
- Send(new MediaStreamMsg_DeviceStopped(render_view_id, label, device));
+ Send(new MediaStreamMsg_DeviceStopped(render_frame_id, label, device));
}
void MediaStreamDispatcherHost::DevicesEnumerated(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfoArray& devices) {
@@ -76,12 +73,12 @@ void MediaStreamDispatcherHost::DevicesEnumerated(
DVLOG(1) << "MediaStreamDispatcherHost::DevicesEnumerated("
<< ", {page_request_id = " << page_request_id << "})";
- Send(new MediaStreamMsg_DevicesEnumerated(render_view_id, page_request_id,
+ Send(new MediaStreamMsg_DevicesEnumerated(render_frame_id, page_request_id,
devices));
}
void MediaStreamDispatcherHost::DeviceOpened(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfo& video_device) {
@@ -90,7 +87,7 @@ void MediaStreamDispatcherHost::DeviceOpened(
<< ", {page_request_id = " << page_request_id << "})";
Send(new MediaStreamMsg_DeviceOpened(
- render_view_id, page_request_id, label, video_device));
+ render_frame_id, page_request_id, label, video_device));
}
bool MediaStreamDispatcherHost::OnMessageReceived(const IPC::Message& message) {
@@ -125,13 +122,13 @@ MediaStreamDispatcherHost::~MediaStreamDispatcherHost() {
}
void MediaStreamDispatcherHost::OnGenerateStream(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
const StreamOptions& components,
const GURL& security_origin,
bool user_gesture) {
DVLOG(1) << "MediaStreamDispatcherHost::OnGenerateStream("
- << render_view_id << ", "
+ << render_frame_id << ", "
<< page_request_id << ", ["
<< " audio:" << components.audio_requested
<< " video:" << components.video_requested
@@ -143,37 +140,36 @@ void MediaStreamDispatcherHost::OnGenerateStream(
return;
media_stream_manager_->GenerateStream(
- this, render_process_id_, render_view_id, salt_callback_,
+ this, render_process_id_, render_frame_id, salt_callback_,
page_request_id, components, security_origin, user_gesture);
}
-void MediaStreamDispatcherHost::OnCancelGenerateStream(int render_view_id,
+void MediaStreamDispatcherHost::OnCancelGenerateStream(int render_frame_id,
int page_request_id) {
DVLOG(1) << "MediaStreamDispatcherHost::OnCancelGenerateStream("
- << render_view_id << ", "
+ << render_frame_id << ", "
<< page_request_id << ")";
- media_stream_manager_->CancelRequest(render_process_id_, render_view_id,
+ media_stream_manager_->CancelRequest(render_process_id_, render_frame_id,
page_request_id);
}
void MediaStreamDispatcherHost::OnStopStreamDevice(
- int render_view_id,
+ int render_frame_id,
const std::string& device_id) {
DVLOG(1) << "MediaStreamDispatcherHost::OnStopStreamDevice("
- << render_view_id << ", "
+ << render_frame_id << ", "
<< device_id << ")";
- media_stream_manager_->StopStreamDevice(render_process_id_, render_view_id,
+ media_stream_manager_->StopStreamDevice(render_process_id_, render_frame_id,
device_id);
}
void MediaStreamDispatcherHost::OnEnumerateDevices(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
MediaStreamType type,
- const GURL& security_origin,
- bool hide_labels_if_no_access) {
+ const GURL& security_origin) {
DVLOG(1) << "MediaStreamDispatcherHost::OnEnumerateDevices("
- << render_view_id << ", "
+ << render_frame_id << ", "
<< page_request_id << ", "
<< type << ", "
<< security_origin.spec() << ")";
@@ -181,41 +177,29 @@ void MediaStreamDispatcherHost::OnEnumerateDevices(
if (!IsURLAllowed(security_origin))
return;
- DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
- type == MEDIA_DEVICE_VIDEO_CAPTURE ||
- type == MEDIA_DEVICE_AUDIO_OUTPUT);
- bool have_permission = true;
- if (hide_labels_if_no_access) {
- bool audio_type = type == MEDIA_DEVICE_AUDIO_CAPTURE ||
- type == MEDIA_DEVICE_AUDIO_OUTPUT;
- have_permission = audio_type ?
- resource_context_->AllowMicAccess(security_origin) :
- resource_context_->AllowCameraAccess(security_origin);
- }
-
media_stream_manager_->EnumerateDevices(
- this, render_process_id_, render_view_id, salt_callback_,
- page_request_id, type, security_origin, have_permission);
+ this, render_process_id_, render_frame_id, salt_callback_,
+ page_request_id, type, security_origin);
}
void MediaStreamDispatcherHost::OnCancelEnumerateDevices(
- int render_view_id,
+ int render_frame_id,
int page_request_id) {
DVLOG(1) << "MediaStreamDispatcherHost::OnCancelEnumerateDevices("
- << render_view_id << ", "
+ << render_frame_id << ", "
<< page_request_id << ")";
- media_stream_manager_->CancelRequest(render_process_id_, render_view_id,
+ media_stream_manager_->CancelRequest(render_process_id_, render_frame_id,
page_request_id);
}
void MediaStreamDispatcherHost::OnOpenDevice(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
const std::string& device_id,
MediaStreamType type,
const GURL& security_origin) {
DVLOG(1) << "MediaStreamDispatcherHost::OnOpenDevice("
- << render_view_id << ", "
+ << render_frame_id << ", "
<< page_request_id << ", device_id: "
<< device_id.c_str() << ", type: "
<< type << ", "
@@ -225,15 +209,15 @@ void MediaStreamDispatcherHost::OnOpenDevice(
return;
media_stream_manager_->OpenDevice(
- this, render_process_id_, render_view_id, salt_callback_,
+ this, render_process_id_, render_frame_id, salt_callback_,
page_request_id, device_id, type, security_origin);
}
void MediaStreamDispatcherHost::OnCloseDevice(
- int render_view_id,
+ int render_frame_id,
const std::string& label) {
DVLOG(1) << "MediaStreamDispatcherHost::OnCloseDevice("
- << render_view_id << ", "
+ << render_frame_id << ", "
<< label << ")";
media_stream_manager_->CancelRequest(label);
diff --git a/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.h b/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.h
index b599c39c951..f35ae26e992 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_dispatcher_host.h
@@ -22,79 +22,76 @@ class MediaStreamManager;
class ResourceContext;
// MediaStreamDispatcherHost is a delegate for Media Stream API messages used by
-// MediaStreamImpl. It's the complement of MediaStreamDispatcher
-// (owned by RenderView).
+// MediaStreamImpl. There is one MediaStreamDispatcherHost per
+// RenderProcessHost, the former owned by the latter.
class CONTENT_EXPORT MediaStreamDispatcherHost : public BrowserMessageFilter,
public MediaStreamRequester {
public:
MediaStreamDispatcherHost(
int render_process_id,
const ResourceContext::SaltCallback& salt_callback,
- MediaStreamManager* media_stream_manager,
- ResourceContext* resource_context);
+ MediaStreamManager* media_stream_manager);
// MediaStreamRequester implementation.
- virtual void StreamGenerated(
- int render_view_id,
+ void StreamGenerated(int render_frame_id,
+ int page_request_id,
+ const std::string& label,
+ const StreamDeviceInfoArray& audio_devices,
+ const StreamDeviceInfoArray& video_devices) override;
+ void StreamGenerationFailed(
+ int render_frame_id,
int page_request_id,
- const std::string& label,
- const StreamDeviceInfoArray& audio_devices,
- const StreamDeviceInfoArray& video_devices) OVERRIDE;
- virtual void StreamGenerationFailed(
- int render_view_id,
- int page_request_id,
- content::MediaStreamRequestResult result) OVERRIDE;
- virtual void DeviceStopped(int render_view_id,
- const std::string& label,
- const StreamDeviceInfo& device) OVERRIDE;
- virtual void DevicesEnumerated(int render_view_id,
- int page_request_id,
- const std::string& label,
- const StreamDeviceInfoArray& devices) OVERRIDE;
- virtual void DeviceOpened(int render_view_id,
- int page_request_id,
- const std::string& label,
- const StreamDeviceInfo& video_device) OVERRIDE;
+ content::MediaStreamRequestResult result) override;
+ void DeviceStopped(int render_frame_id,
+ const std::string& label,
+ const StreamDeviceInfo& device) override;
+ void DevicesEnumerated(int render_frame_id,
+ int page_request_id,
+ const std::string& label,
+ const StreamDeviceInfoArray& devices) override;
+ void DeviceOpened(int render_frame_id,
+ int page_request_id,
+ const std::string& label,
+ const StreamDeviceInfo& video_device) override;
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OnChannelClosing() OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnChannelClosing() override;
protected:
- virtual ~MediaStreamDispatcherHost();
+ ~MediaStreamDispatcherHost() override;
private:
friend class MockMediaStreamDispatcherHost;
- void OnGenerateStream(int render_view_id,
+ void OnGenerateStream(int render_frame_id,
int page_request_id,
const StreamOptions& components,
const GURL& security_origin,
bool user_gesture);
- void OnCancelGenerateStream(int render_view_id,
+ void OnCancelGenerateStream(int render_frame_id,
int page_request_id);
- void OnStopStreamDevice(int render_view_id,
+ void OnStopStreamDevice(int render_frame_id,
const std::string& device_id);
- void OnEnumerateDevices(int render_view_id,
+ void OnEnumerateDevices(int render_frame_id,
int page_request_id,
MediaStreamType type,
- const GURL& security_origin,
- bool hide_labels_if_no_access);
+ const GURL& security_origin);
- void OnCancelEnumerateDevices(int render_view_id,
+ void OnCancelEnumerateDevices(int render_frame_id,
int page_request_id);
- void OnOpenDevice(int render_view_id,
+ void OnOpenDevice(int render_frame_id,
int page_request_id,
const std::string& device_id,
MediaStreamType type,
const GURL& security_origin);
- void OnCloseDevice(int render_view_id,
+ void OnCloseDevice(int render_frame_id,
const std::string& label);
- void StoreRequest(int render_view_id,
+ void StoreRequest(int render_frame_id,
int page_request_id,
const std::string& label);
@@ -104,9 +101,6 @@ class CONTENT_EXPORT MediaStreamDispatcherHost : public BrowserMessageFilter,
ResourceContext::SaltCallback salt_callback_;
MediaStreamManager* media_stream_manager_;
- // Owned by ProfileIOData which is guaranteed to outlive MSDH.
- ResourceContext* const resource_context_;
-
DISALLOW_COPY_AND_ASSIGN(MediaStreamDispatcherHost);
};
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 a7edd38fc25..9b3d22f2661 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
@@ -33,6 +33,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_CHROMEOS)
+#include "chromeos/audio/cras_audio_handler.h"
+#endif
+
using ::testing::_;
using ::testing::DeleteArg;
using ::testing::DoAll;
@@ -52,10 +56,8 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost,
MockMediaStreamDispatcherHost(
const ResourceContext::SaltCallback salt_callback,
const scoped_refptr<base::MessageLoopProxy>& message_loop,
- MediaStreamManager* manager,
- ResourceContext* resource_context)
- : MediaStreamDispatcherHost(kProcessId, salt_callback, manager,
- resource_context),
+ MediaStreamManager* manager)
+ : MediaStreamDispatcherHost(kProcessId, salt_callback, manager),
message_loop_(message_loop),
current_ipc_(NULL) {}
@@ -70,22 +72,22 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost,
MOCK_METHOD2(OnDeviceOpened, void(int routing_id, int request_id));
// Accessor to private functions.
- void OnGenerateStream(int render_view_id,
+ void OnGenerateStream(int render_frame_id,
int page_request_id,
const StreamOptions& components,
const GURL& security_origin,
const base::Closure& quit_closure) {
quit_closures_.push(quit_closure);
MediaStreamDispatcherHost::OnGenerateStream(
- render_view_id, page_request_id, components, security_origin, false);
+ render_frame_id, page_request_id, components, security_origin, false);
}
- void OnStopStreamDevice(int render_view_id,
+ void OnStopStreamDevice(int render_frame_id,
const std::string& device_id) {
- MediaStreamDispatcherHost::OnStopStreamDevice(render_view_id, device_id);
+ MediaStreamDispatcherHost::OnStopStreamDevice(render_frame_id, device_id);
}
- void OnOpenDevice(int render_view_id,
+ void OnOpenDevice(int render_frame_id,
int page_request_id,
const std::string& device_id,
MediaStreamType type,
@@ -93,19 +95,17 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost,
const base::Closure& quit_closure) {
quit_closures_.push(quit_closure);
MediaStreamDispatcherHost::OnOpenDevice(
- render_view_id, page_request_id, device_id, type, security_origin);
+ render_frame_id, page_request_id, device_id, type, security_origin);
}
- void OnEnumerateDevices(int render_view_id,
+ void OnEnumerateDevices(int render_frame_id,
int page_request_id,
MediaStreamType type,
const GURL& security_origin,
- bool hide_labels_if_no_access,
const base::Closure& quit_closure) {
quit_closures_.push(quit_closure);
MediaStreamDispatcherHost::OnEnumerateDevices(
- render_view_id, page_request_id, type, security_origin,
- hide_labels_if_no_access);
+ render_frame_id, page_request_id, type, security_origin);
}
std::string label_;
@@ -120,7 +120,7 @@ class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost,
// This method is used to dispatch IPC messages to the renderer. We intercept
// these messages here and dispatch to our mock methods to verify the
// conversation between this object and the renderer.
- virtual bool Send(IPC::Message* message) OVERRIDE {
+ virtual bool Send(IPC::Message* message) override {
CHECK(message);
current_ipc_ = message;
@@ -225,7 +225,7 @@ class MediaStreamDispatcherHostTest : public testing::Test {
audio_manager_.reset(
new media::MockAudioManager(base::MessageLoopProxy::current()));
// Make sure we use fake devices to avoid long delays.
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kUseFakeDeviceForMediaStream);
// Create our own MediaStreamManager.
media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
@@ -234,29 +234,38 @@ class MediaStreamDispatcherHostTest : public testing::Test {
media_stream_manager_->video_capture_manager()
->video_capture_device_factory());
DCHECK(video_capture_device_factory_);
+#if defined(OS_WIN)
+ // Override the Video Capture Thread that MediaStreamManager constructs.
+ media_stream_manager_->video_capture_manager()->set_device_task_runner(
+ base::MessageLoopProxy::current());
+#endif
MockResourceContext* mock_resource_context =
static_cast<MockResourceContext*>(
browser_context_.GetResourceContext());
- mock_resource_context->set_mic_access(true);
- mock_resource_context->set_camera_access(true);
host_ = new MockMediaStreamDispatcherHost(
mock_resource_context->GetMediaDeviceIDSalt(),
base::MessageLoopProxy::current(),
- media_stream_manager_.get(),
- mock_resource_context);
+ media_stream_manager_.get());
// Use the fake content client and browser.
content_client_.reset(new TestContentClient());
SetContentClient(content_client_.get());
old_browser_client_ = SetBrowserClientForTesting(host_.get());
+
+#if defined(OS_CHROMEOS)
+ chromeos::CrasAudioHandler::InitializeForTesting();
+#endif
}
- virtual ~MediaStreamDispatcherHostTest() {
+ ~MediaStreamDispatcherHostTest() override {
+#if defined(OS_CHROMEOS)
+ chromeos::CrasAudioHandler::Shutdown();
+#endif
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
video_capture_device_factory_->GetDeviceNames(&physical_video_devices_);
ASSERT_GT(physical_video_devices_.size(), 0u);
@@ -265,21 +274,19 @@ class MediaStreamDispatcherHostTest : public testing::Test {
ASSERT_GT(physical_audio_devices_.size(), 0u);
}
- virtual void TearDown() OVERRIDE {
- host_->OnChannelClosing();
- }
+ void TearDown() override { host_->OnChannelClosing(); }
protected:
virtual void SetupFakeUI(bool expect_started) {
- scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
+ stream_ui_ = new MockMediaStreamUIProxy();
if (expect_started) {
- EXPECT_CALL(*stream_ui, OnStarted(_, _));
+ EXPECT_CALL(*stream_ui_, OnStarted(_, _));
}
media_stream_manager_->UseFakeUI(
- stream_ui.PassAs<FakeMediaStreamUIProxy>());
+ scoped_ptr<FakeMediaStreamUIProxy>(stream_ui_));
}
- void GenerateStreamAndWaitForResult(int render_view_id,
+ void GenerateStreamAndWaitForResult(int render_frame_id,
int page_request_id,
const StreamOptions& options) {
base::RunLoop run_loop;
@@ -289,10 +296,11 @@ class MediaStreamDispatcherHostTest : public testing::Test {
int expected_video_array_size =
(options.video_requested &&
physical_video_devices_.size() > 0) ? 1 : 0;
- EXPECT_CALL(*host_.get(), OnStreamGenerated(render_view_id, page_request_id,
+ EXPECT_CALL(*host_.get(), OnStreamGenerated(render_frame_id,
+ page_request_id,
expected_audio_array_size,
expected_video_array_size));
- host_->OnGenerateStream(render_view_id, page_request_id, options, origin_,
+ host_->OnGenerateStream(render_frame_id, page_request_id, options, origin_,
run_loop.QuitClosure());
run_loop.Run();
EXPECT_FALSE(DoesContainRawIds(host_->audio_devices_));
@@ -302,25 +310,25 @@ class MediaStreamDispatcherHostTest : public testing::Test {
}
void GenerateStreamAndWaitForFailure(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
const StreamOptions& options,
MediaStreamRequestResult expected_result) {
base::RunLoop run_loop;
EXPECT_CALL(*host_.get(),
- OnStreamGenerationFailed(render_view_id,
+ OnStreamGenerationFailed(render_frame_id,
page_request_id,
expected_result));
- host_->OnGenerateStream(render_view_id, page_request_id, options, origin_,
- run_loop.QuitClosure());
+ host_->OnGenerateStream(render_frame_id, page_request_id, options,
+ origin_, run_loop.QuitClosure());
run_loop.Run();
}
- void OpenVideoDeviceAndWaitForResult(int render_view_id,
+ void OpenVideoDeviceAndWaitForResult(int render_frame_id,
int page_request_id,
const std::string& device_id) {
base::RunLoop run_loop;
- host_->OnOpenDevice(render_view_id, page_request_id, device_id,
+ host_->OnOpenDevice(render_frame_id, page_request_id, device_id,
MEDIA_DEVICE_VIDEO_CAPTURE, origin_,
run_loop.QuitClosure());
run_loop.Run();
@@ -328,13 +336,12 @@ class MediaStreamDispatcherHostTest : public testing::Test {
EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->video_devices_, origin_));
}
- void EnumerateDevicesAndWaitForResult(int render_view_id,
+ void EnumerateDevicesAndWaitForResult(int render_frame_id,
int page_request_id,
- MediaStreamType type,
- bool hide_labels_if_no_access) {
+ MediaStreamType type) {
base::RunLoop run_loop;
- host_->OnEnumerateDevices(render_view_id, page_request_id, type, origin_,
- hide_labels_if_no_access, run_loop.QuitClosure());
+ host_->OnEnumerateDevices(render_frame_id, page_request_id, type, origin_,
+ run_loop.QuitClosure());
run_loop.Run();
ASSERT_FALSE(host_->enumerated_devices_.empty());
EXPECT_FALSE(DoesContainRawIds(host_->enumerated_devices_));
@@ -420,6 +427,7 @@ class MediaStreamDispatcherHostTest : public testing::Test {
scoped_refptr<MockMediaStreamDispatcherHost> host_;
scoped_ptr<media::AudioManager> audio_manager_;
scoped_ptr<MediaStreamManager> media_stream_manager_;
+ MockMediaStreamUIProxy* stream_ui_;
ContentBrowserClient* old_browser_client_;
scoped_ptr<ContentClient> content_client_;
content::TestBrowserThreadBundle thread_bundle_;
@@ -450,6 +458,9 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioOnly) {
EXPECT_EQ(host_->video_devices_.size(), 0u);
}
+// This test simulates a shutdown scenario: we don't setup a fake UI proxy for
+// MediaStreamManager, so it will create an ordinary one which will not find
+// a RenderFrameHostDelegate. This normally should only be the case at shutdown.
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithNothing) {
StreamOptions options(false, false);
@@ -457,7 +468,7 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithNothing) {
kRenderId,
kPageRequestId,
options,
- MEDIA_DEVICE_INVALID_STATE);
+ MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN);
}
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioAndVideo) {
@@ -470,8 +481,8 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioAndVideo) {
EXPECT_EQ(host_->video_devices_.size(), 1u);
}
-// This test generates two streams with video only using the same render view
-// id. The same capture device with the same device and session id is expected
+// This test generates two streams with video only using the same render frame
+// id. The same capture device with the same device and session id is expected
// to be used.
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsFromSameRenderId) {
StreamOptions options(false, true);
@@ -530,7 +541,7 @@ TEST_F(MediaStreamDispatcherHostTest,
// This test generates two streams with video only using two separate render
-// view ids. The same device id but different session ids are expected.
+// frame ids. The same device id but different session ids are expected.
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsDifferentRenderId) {
StreamOptions options(false, true);
@@ -545,7 +556,7 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsDifferentRenderId) {
const std::string device_id1 = host_->video_devices_.front().device.id;
const int session_id1 = host_->video_devices_.front().session_id;
- // Generate second stream from another render view.
+ // Generate second stream from another render frame.
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId+1, kPageRequestId + 1, options);
@@ -850,7 +861,7 @@ TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) {
scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
EXPECT_CALL(*stream_ui, OnStarted(_, _))
.WillOnce(SaveArg<0>(&close_callback));
- media_stream_manager_->UseFakeUI(stream_ui.PassAs<FakeMediaStreamUIProxy>());
+ media_stream_manager_->UseFakeUI(stream_ui.Pass());
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
@@ -884,53 +895,33 @@ TEST_F(MediaStreamDispatcherHostTest, VideoDeviceUnplugged) {
}
TEST_F(MediaStreamDispatcherHostTest, EnumerateAudioDevices) {
+ SetupFakeUI(false);
EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId,
- MEDIA_DEVICE_AUDIO_CAPTURE, true);
+ MEDIA_DEVICE_AUDIO_CAPTURE);
EXPECT_TRUE(DoesContainLabels(host_->enumerated_devices_));
}
TEST_F(MediaStreamDispatcherHostTest, EnumerateVideoDevices) {
+ SetupFakeUI(false);
EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId,
- MEDIA_DEVICE_VIDEO_CAPTURE, true);
+ MEDIA_DEVICE_VIDEO_CAPTURE);
EXPECT_TRUE(DoesContainLabels(host_->enumerated_devices_));
}
-TEST_F(MediaStreamDispatcherHostTest, EnumerateAudioDevicesNoAccessHideLabels) {
- MockResourceContext* mock_resource_context =
- static_cast<MockResourceContext*>(browser_context_.GetResourceContext());
- mock_resource_context->set_mic_access(false);
+TEST_F(MediaStreamDispatcherHostTest, EnumerateAudioDevicesNoAccess) {
+ SetupFakeUI(false);
+ stream_ui_->SetMicAccess(false);
EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId,
- MEDIA_DEVICE_AUDIO_CAPTURE, true);
+ MEDIA_DEVICE_AUDIO_CAPTURE);
EXPECT_TRUE(DoesNotContainLabels(host_->enumerated_devices_));
}
-TEST_F(MediaStreamDispatcherHostTest, EnumerateVideoDevicesNoAccessHideLabels) {
- MockResourceContext* mock_resource_context =
- static_cast<MockResourceContext*>(browser_context_.GetResourceContext());
- mock_resource_context->set_camera_access(false);
+TEST_F(MediaStreamDispatcherHostTest, EnumerateVideoDevicesNoAccess) {
+ SetupFakeUI(false);
+ stream_ui_->SetCameraAccess(false);
EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId,
- MEDIA_DEVICE_VIDEO_CAPTURE, true);
+ MEDIA_DEVICE_VIDEO_CAPTURE);
EXPECT_TRUE(DoesNotContainLabels(host_->enumerated_devices_));
}
-TEST_F(MediaStreamDispatcherHostTest,
- EnumerateAudioDevicesNoAccessNoHideLabels) {
- MockResourceContext* mock_resource_context =
- static_cast<MockResourceContext*>(browser_context_.GetResourceContext());
- mock_resource_context->set_mic_access(false);
- EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId,
- MEDIA_DEVICE_AUDIO_CAPTURE, false);
- EXPECT_TRUE(DoesContainLabels(host_->enumerated_devices_));
-}
-
-TEST_F(MediaStreamDispatcherHostTest,
- EnumerateVideoDevicesNoAccessNoHideLabels) {
- MockResourceContext* mock_resource_context =
- static_cast<MockResourceContext*>(browser_context_.GetResourceContext());
- mock_resource_context->set_camera_access(false);
- EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId,
- MEDIA_DEVICE_VIDEO_CAPTURE, false);
- EXPECT_TRUE(DoesContainLabels(host_->enumerated_devices_));
-}
-
}; // namespace content
diff --git a/chromium/content/browser/renderer_host/media/media_stream_manager.cc b/chromium/content/browser/renderer_host/media/media_stream_manager.cc
index 2b337cafa78..0124f21297f 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.cc
@@ -19,7 +19,6 @@
#include "content/browser/browser_main_loop.h"
#include "content/browser/media/capture/web_contents_capture_util.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
-#include "content/browser/renderer_host/media/device_request_message_filter.h"
#include "content/browser/renderer_host/media/media_capture_devices_impl.h"
#include "content/browser/renderer_host/media/media_stream_requester.h"
#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
@@ -31,6 +30,7 @@
#include "content/public/browser/media_observer.h"
#include "content/public/browser/media_request_state.h"
#include "content/public/browser/render_process_host.h"
+#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/media_stream_request.h"
#include "media/audio/audio_manager_base.h"
@@ -44,6 +44,10 @@
#include "base/win/scoped_com_initializer.h"
#endif
+#if defined(OS_CHROMEOS)
+#include "chromeos/audio/cras_audio_handler.h"
+#endif
+
namespace content {
// Forward declaration of DeviceMonitorMac and its only useable method.
@@ -118,6 +122,18 @@ void ParseStreamType(const StreamOptions& options,
}
}
+// Turns off available audio effects (removes the flag) if the options
+// explicitly turn them off.
+void FilterAudioEffects(const StreamOptions& options, int* effects) {
+ DCHECK(effects);
+ // TODO(ajm): Should we also handle ECHO_CANCELLER here?
+ std::string value;
+ if (options.GetFirstAudioConstraintByName(
+ kMediaStreamAudioDucking, &value, NULL) && value == "false") {
+ *effects &= ~media::AudioParameters::DUCKING;
+ }
+}
+
// Private helper method for SendMessageToNativeLog() that obtains the global
// MediaStreamManager instance on the UI thread before sending |message| to the
// webrtcLoggingPrivate API.
@@ -183,20 +199,18 @@ class MediaStreamManager::DeviceRequest {
public:
DeviceRequest(MediaStreamRequester* requester,
int requesting_process_id,
- int requesting_view_id,
+ int requesting_frame_id,
int page_request_id,
const GURL& security_origin,
- bool have_permission,
bool user_gesture,
MediaStreamRequestType request_type,
const StreamOptions& options,
const ResourceContext::SaltCallback& salt_callback)
: requester(requester),
requesting_process_id(requesting_process_id),
- requesting_view_id(requesting_view_id),
+ requesting_frame_id(requesting_frame_id),
page_request_id(page_request_id),
security_origin(security_origin),
- have_permission(have_permission),
user_gesture(user_gesture),
request_type(request_type),
options(options),
@@ -230,7 +244,7 @@ class MediaStreamManager::DeviceRequest {
const std::string& requested_video_device_id) {
DCHECK(!ui_request_);
ui_request_.reset(new MediaStreamRequest(requesting_process_id,
- requesting_view_id,
+ requesting_frame_id,
page_request_id,
security_origin,
user_gesture,
@@ -243,12 +257,12 @@ class MediaStreamManager::DeviceRequest {
// Creates a tab capture specific MediaStreamRequest object that is used by
// this request when UI is asked for permission and device selection.
- void CreateTabCatureUIRequest(int target_render_process_id,
- int target_render_view_id,
- const std::string& tab_capture_id) {
+ void CreateTabCaptureUIRequest(int target_render_process_id,
+ int target_render_frame_id,
+ const std::string& tab_capture_id) {
DCHECK(!ui_request_);
ui_request_.reset(new MediaStreamRequest(target_render_process_id,
- target_render_view_id,
+ target_render_frame_id,
page_request_id,
security_origin,
user_gesture,
@@ -283,17 +297,10 @@ class MediaStreamManager::DeviceRequest {
if (!ui_request_)
return;
- // If we appended a device_id scheme, we want to remove it when notifying
- // observers which may be in different modules since this scheme is only
- // used internally within the content module.
- std::string device_id =
- WebContentsCaptureUtil::StripWebContentsDeviceScheme(
- ui_request_->tab_capture_device_id);
-
media_observer->OnMediaRequestStateChanged(
- ui_request_->render_process_id, ui_request_->render_view_id,
+ ui_request_->render_process_id, ui_request_->render_frame_id,
ui_request_->page_request_id, ui_request_->security_origin,
- MediaStreamDevice(stream_type, device_id, device_id), new_state);
+ stream_type, new_state);
}
MediaRequestState state(MediaStreamType stream_type) const {
@@ -309,21 +316,17 @@ class MediaStreamManager::DeviceRequest {
// specifies the target renderer from which audio and video is captured.
const int requesting_process_id;
- // The render view id that requested this stream to be generated and that
+ // The render frame id that requested this stream to be generated and that
// will receive a handle to the MediaStream. This may be different from
- // MediaStreamRequest::render_view_id which in the tab capture case
+ // MediaStreamRequest::render_frame_id which in the tab capture case
// specifies the target renderer from which audio and video is captured.
- const int requesting_view_id;
+ const int requesting_frame_id;
- // An ID the render view provided to identify this request.
+ // An ID the render frame provided to identify this request.
const int page_request_id;
const GURL security_origin;
- // This is used when enumerating devices; if we don't have device access
- // permission, we remove the device label.
- bool have_permission;
-
const bool user_gesture;
const MediaStreamRequestType request_type;
@@ -357,13 +360,25 @@ MediaStreamManager::EnumerationCache::~EnumerationCache() {
MediaStreamManager::MediaStreamManager()
: audio_manager_(NULL),
+#if defined(OS_WIN)
+ video_capture_thread_("VideoCaptureThread"),
+#endif
monitoring_started_(false),
+#if defined(OS_CHROMEOS)
+ has_checked_keyboard_mic_(false),
+#endif
io_loop_(NULL),
use_fake_ui_(false) {}
MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
: audio_manager_(audio_manager),
+#if defined(OS_WIN)
+ video_capture_thread_("VideoCaptureThread"),
+#endif
monitoring_started_(false),
+#if defined(OS_CHROMEOS)
+ has_checked_keyboard_mic_(false),
+#endif
io_loop_(NULL),
use_fake_ui_(false) {
DCHECK(audio_manager_);
@@ -391,7 +406,7 @@ MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
MediaStreamManager::~MediaStreamManager() {
DVLOG(1) << "~MediaStreamManager";
DCHECK(requests_.empty());
- DCHECK(!device_task_runner_);
+ DCHECK(!device_task_runner_.get());
base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
// The PowerMonitor instance owned by BrowserMainLoops always outlives the
@@ -414,7 +429,7 @@ AudioInputDeviceManager* MediaStreamManager::audio_input_device_manager() {
std::string MediaStreamManager::MakeMediaAccessRequest(
int render_process_id,
- int render_view_id,
+ int render_frame_id,
int page_request_id,
const StreamOptions& options,
const GURL& security_origin,
@@ -425,10 +440,9 @@ std::string MediaStreamManager::MakeMediaAccessRequest(
// suggests that this is the wrong design. Can this be refactored?
DeviceRequest* request = new DeviceRequest(NULL,
render_process_id,
- render_view_id,
+ render_frame_id,
page_request_id,
security_origin,
- true,
false, // user gesture
MEDIA_DEVICE_ACCESS,
options,
@@ -451,7 +465,7 @@ std::string MediaStreamManager::MakeMediaAccessRequest(
void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
const ResourceContext::SaltCallback& sc,
int page_request_id,
const StreamOptions& options,
@@ -466,10 +480,9 @@ void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
DeviceRequest* request = new DeviceRequest(requester,
render_process_id,
- render_view_id,
+ render_frame_id,
page_request_id,
security_origin,
- true,
user_gesture,
MEDIA_GENERATE_STREAM,
options,
@@ -489,13 +502,13 @@ void MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
}
void MediaStreamManager::CancelRequest(int render_process_id,
- int render_view_id,
+ int render_frame_id,
int page_request_id) {
for (DeviceRequests::const_iterator request_it = requests_.begin();
request_it != requests_.end(); ++request_it) {
const DeviceRequest* request = request_it->second;
if (request->requesting_process_id == render_process_id &&
- request->requesting_view_id == render_view_id &&
+ request->requesting_frame_id == render_frame_id &&
request->page_request_id == page_request_id) {
CancelRequest(request_it->first);
return;
@@ -557,19 +570,19 @@ void MediaStreamManager::CancelAllRequests(int render_process_id) {
}
void MediaStreamManager::StopStreamDevice(int render_process_id,
- int render_view_id,
+ int render_frame_id,
const std::string& device_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DVLOG(1) << "StopStreamDevice({render_view_id = " << render_view_id << "} "
+ DVLOG(1) << "StopStreamDevice({render_frame_id = " << render_frame_id << "} "
<< ", {device_id = " << device_id << "})";
- // Find the first request for this |render_process_id| and |render_view_id|
+ // Find the first request for this |render_process_id| and |render_frame_id|
// of type MEDIA_GENERATE_STREAM that has requested to use |device_id| and
// stop it.
for (DeviceRequests::iterator request_it = requests_.begin();
- request_it != requests_.end(); ++request_it) {
+ request_it != requests_.end(); ++request_it) {
DeviceRequest* request = request_it->second;
if (request->requesting_process_id != render_process_id ||
- request->requesting_view_id != render_view_id ||
+ request->requesting_frame_id != render_frame_id ||
request->request_type != MEDIA_GENERATE_STREAM) {
continue;
}
@@ -648,12 +661,11 @@ void MediaStreamManager::CloseDevice(MediaStreamType type, int session_id) {
std::string MediaStreamManager::EnumerateDevices(
MediaStreamRequester* requester,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
const ResourceContext::SaltCallback& sc,
int page_request_id,
MediaStreamType type,
- const GURL& security_origin,
- bool have_permission) {
+ const GURL& security_origin) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(requester);
DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
@@ -662,10 +674,9 @@ std::string MediaStreamManager::EnumerateDevices(
DeviceRequest* request = new DeviceRequest(requester,
render_process_id,
- render_view_id,
+ render_frame_id,
page_request_id,
security_origin,
- have_permission,
false, // user gesture
MEDIA_ENUMERATE_DEVICES,
StreamOptions(),
@@ -733,8 +744,7 @@ void MediaStreamManager::DoEnumerateDevices(const std::string& label) {
DVLOG(1) << "Enumerate Devices ({label = " << label << "})";
}
-void MediaStreamManager::EnumerateAudioOutputDevices(
- const std::string& label) {
+void MediaStreamManager::EnumerateAudioOutputDevices(const std::string& label) {
DCHECK(device_task_runner_->BelongsToCurrentThread());
scoped_ptr<media::AudioDeviceNames> device_names(
@@ -786,7 +796,7 @@ void MediaStreamManager::AudioOutputDevicesEnumerated(
void MediaStreamManager::OpenDevice(MediaStreamRequester* requester,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
const ResourceContext::SaltCallback& sc,
int page_request_id,
const std::string& device_id,
@@ -810,10 +820,9 @@ void MediaStreamManager::OpenDevice(MediaStreamRequester* requester,
}
DeviceRequest* request = new DeviceRequest(requester,
render_process_id,
- render_view_id,
+ render_frame_id,
page_request_id,
security_origin,
- true,
false, // user gesture
MEDIA_OPEN_DEVICE,
options,
@@ -910,7 +919,7 @@ void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) {
session_ids.push_back(device_it->session_id);
if (it->second->requester) {
it->second->requester->DeviceStopped(
- it->second->requesting_view_id,
+ it->second->requesting_frame_id,
it->first,
*device_it);
}
@@ -1081,7 +1090,7 @@ void MediaStreamManager::StartEnumeration(DeviceRequest* request) {
// Start enumeration for devices of all requested device types.
const MediaStreamType streams[] = { request->audio_type(),
request->video_type() };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(streams); ++i) {
+ for (size_t i = 0; i < arraysize(streams); ++i) {
if (streams[i] == MEDIA_NO_SERVICE)
continue;
request->SetState(streams[i], MEDIA_REQUEST_STATE_REQUESTED);
@@ -1220,6 +1229,10 @@ void MediaStreamManager::SetupRequest(const std::string& label) {
return;
}
+#if defined(OS_CHROMEOS)
+ EnsureKeyboardMicChecked();
+#endif
+
if (!is_web_contents_capture && !is_screen_capture) {
if (EnumerationRequired(&audio_enumeration_cache_, audio_type) ||
EnumerationRequired(&video_enumeration_cache_, video_type)) {
@@ -1295,17 +1308,10 @@ bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
// Customize options for a WebContents based capture.
int target_render_process_id = 0;
- int target_render_view_id = 0;
-
- // TODO(justinlin): Can't plumb audio mirroring using stream type right
- // now, so plumbing by device_id. Will revisit once it's refactored.
- // http://crbug.com/163100
- std::string tab_capture_device_id =
- WebContentsCaptureUtil::AppendWebContentsDeviceScheme(capture_device_id);
+ int target_render_frame_id = 0;
bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
- tab_capture_device_id, &target_render_process_id,
- &target_render_view_id);
+ capture_device_id, &target_render_process_id, &target_render_frame_id);
if (!has_valid_device_id ||
(request->audio_type() != MEDIA_TAB_AUDIO_CAPTURE &&
request->audio_type() != MEDIA_NO_SERVICE) ||
@@ -1314,15 +1320,15 @@ bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
return false;
}
- request->CreateTabCatureUIRequest(target_render_process_id,
- target_render_view_id,
- tab_capture_device_id);
+ request->CreateTabCaptureUIRequest(target_render_process_id,
+ target_render_frame_id,
+ capture_device_id);
DVLOG(3) << "SetupTabCaptureRequest "
- << ", {tab_capture_device_id = " << tab_capture_device_id << "}"
+ << ", {capture_device_id = " << capture_device_id << "}"
<< ", {target_render_process_id = " << target_render_process_id
<< "}"
- << ", {target_render_view_id = " << target_render_view_id << "}";
+ << ", {target_render_frame_id = " << target_render_frame_id << "}";
return true;
}
@@ -1394,15 +1400,19 @@ bool MediaStreamManager::FindExistingRequestedDeviceInfo(
it != requests_.end() ; ++it) {
const DeviceRequest* request = it->second;
if (request->requesting_process_id == new_request.requesting_process_id &&
- request->requesting_view_id == new_request.requesting_view_id &&
+ request->requesting_frame_id == new_request.requesting_frame_id &&
request->request_type == new_request.request_type) {
for (StreamDeviceInfoArray::const_iterator device_it =
request->devices.begin();
device_it != request->devices.end(); ++device_it) {
if (device_it->device.id == source_id &&
device_it->device.type == new_device_info.type) {
- *existing_device_info = *device_it;
- *existing_request_state = request->state(device_it->device.type);
+ *existing_device_info = *device_it;
+ // Make sure that the audio |effects| reflect what the request
+ // is set to and not what the capabilities are.
+ FilterAudioEffects(request->options,
+ &existing_device_info->device.input.effects);
+ *existing_request_state = request->state(device_it->device.type);
return true;
}
}
@@ -1431,7 +1441,7 @@ void MediaStreamManager::FinalizeGenerateStream(const std::string& label,
}
request->requester->StreamGenerated(
- request->requesting_view_id,
+ request->requesting_frame_id,
request->page_request_id,
label, audio_devices, video_devices);
}
@@ -1442,7 +1452,7 @@ void MediaStreamManager::FinalizeRequestFailed(
content::MediaStreamRequestResult result) {
if (request->requester)
request->requester->StreamGenerationFailed(
- request->requesting_view_id,
+ request->requesting_frame_id,
request->page_request_id,
result);
@@ -1457,7 +1467,7 @@ void MediaStreamManager::FinalizeRequestFailed(
void MediaStreamManager::FinalizeOpenDevice(const std::string& label,
DeviceRequest* request) {
const StreamDeviceInfoArray& requested_devices = request->devices;
- request->requester->DeviceOpened(request->requesting_view_id,
+ request->requester->DeviceOpened(request->requesting_frame_id,
request->page_request_id,
label, requested_devices.front());
}
@@ -1466,6 +1476,11 @@ void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label,
DeviceRequest* request) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_EQ(request->request_type, MEDIA_ENUMERATE_DEVICES);
+ DCHECK(((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT) &&
+ request->video_type() == MEDIA_NO_SERVICE) ||
+ (request->audio_type() == MEDIA_NO_SERVICE &&
+ request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE));
if (request->security_origin.is_valid()) {
for (StreamDeviceInfoArray::iterator it = request->devices.begin();
@@ -1476,11 +1491,48 @@ void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label,
request->devices.clear();
}
- if (!request->have_permission)
+ if (use_fake_ui_) {
+ if (!fake_ui_)
+ fake_ui_.reset(new FakeMediaStreamUIProxy());
+ request->ui_proxy = fake_ui_.Pass();
+ } else {
+ request->ui_proxy = MediaStreamUIProxy::Create();
+ }
+
+ // Output label permissions are based on input permission.
+ MediaStreamType type =
+ request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ request->audio_type() == MEDIA_DEVICE_AUDIO_OUTPUT
+ ? MEDIA_DEVICE_AUDIO_CAPTURE
+ : MEDIA_DEVICE_VIDEO_CAPTURE;
+
+ request->ui_proxy->CheckAccess(
+ request->security_origin,
+ type,
+ request->requesting_process_id,
+ request->requesting_frame_id,
+ base::Bind(&MediaStreamManager::HandleCheckMediaAccessResponse,
+ base::Unretained(this),
+ label));
+}
+
+void MediaStreamManager::HandleCheckMediaAccessResponse(
+ const std::string& label,
+ bool have_access) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ DeviceRequest* request = FindRequest(label);
+ if (!request) {
+ // This can happen if the request was cancelled.
+ DVLOG(1) << "The request with label " << label << " does not exist.";
+ return;
+ }
+
+ if (!have_access)
ClearDeviceLabels(&request->devices);
request->requester->DevicesEnumerated(
- request->requesting_view_id,
+ request->requesting_frame_id,
request->page_request_id,
label,
request->devices);
@@ -1528,7 +1580,7 @@ void MediaStreamManager::FinalizeMediaAccessRequest(
void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (device_task_runner_)
+ if (device_task_runner_.get())
return;
device_task_runner_ = audio_manager_->GetWorkerTaskRunner();
@@ -1549,7 +1601,16 @@ void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
video_capture_manager_ =
new VideoCaptureManager(media::VideoCaptureDeviceFactory::CreateFactory(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)));
+#if defined(OS_WIN)
+ // Use an STA Video Capture Thread to try to avoid crashes on enumeration of
+ // buggy third party Direct Show modules, http://crbug.com/428958.
+ video_capture_thread_.init_com_with_mta(false);
+ CHECK(video_capture_thread_.Start());
+ video_capture_manager_->Register(this,
+ video_capture_thread_.message_loop_proxy());
+#else
video_capture_manager_->Register(this, device_task_runner_);
+#endif
}
void MediaStreamManager::Opened(MediaStreamType stream_type,
@@ -1583,6 +1644,14 @@ void MediaStreamManager::Opened(MediaStreamType stream_type,
audio_input_device_manager_->GetOpenedDeviceInfoById(
device_it->session_id);
device_it->device.input = info->device.input;
+
+ // Since the audio input device manager will set the input
+ // parameters to the default settings (including supported effects),
+ // we need to adjust those settings here according to what the
+ // request asks for.
+ FilterAudioEffects(request->options,
+ &device_it->device.input.effects);
+
device_it->device.matched_output = info->device.matched_output;
}
}
@@ -1817,8 +1886,6 @@ void MediaStreamManager::HandleAccessRequestResponse(
StreamDeviceInfo device_info;
device_info.device = *device_it;
- // TODO(justinlin): Nicer way to do this?
- // Re-append the device's id since we lost it when posting request to UI.
if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
device_info.device.id = request->UIRequest()->tab_capture_device_id;
@@ -1847,7 +1914,7 @@ void MediaStreamManager::HandleAccessRequestResponse(
}
// If this is request for a new MediaStream, a device is only opened once
- // per render view. This is so that the permission to use a device can be
+ // per render frame. This is so that the permission to use a device can be
// revoked by a single call to StopStreamDevice regardless of how many
// MediaStreams it is being used in.
if (request->request_type == MEDIA_GENERATE_STREAM) {
@@ -1900,7 +1967,7 @@ void MediaStreamManager::StopMediaStreamFromBrowser(const std::string& label) {
if (request->requester) {
for (StreamDeviceInfoArray::iterator device_it = request->devices.begin();
device_it != request->devices.end(); ++device_it) {
- request->requester->DeviceStopped(request->requesting_view_id,
+ request->requester->DeviceStopped(request->requesting_frame_id,
label,
*device_it);
}
@@ -1919,7 +1986,7 @@ void MediaStreamManager::WillDestroyCurrentMessageLoop() {
DVLOG(3) << "MediaStreamManager::WillDestroyCurrentMessageLoop()";
DCHECK_EQ(base::MessageLoop::current(), io_loop_);
DCHECK(requests_.empty());
- if (device_task_runner_) {
+ if (device_task_runner_.get()) {
StopMonitoring();
video_capture_manager_->Unregister();
@@ -2038,4 +2105,36 @@ void MediaStreamManager::OnMediaStreamUIWindowId(MediaStreamType video_type,
}
}
+#if defined(OS_CHROMEOS)
+void MediaStreamManager::EnsureKeyboardMicChecked() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!has_checked_keyboard_mic_) {
+ has_checked_keyboard_mic_ = true;
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&MediaStreamManager::CheckKeyboardMicOnUIThread,
+ base::Unretained(this)));
+ }
+}
+
+void MediaStreamManager::CheckKeyboardMicOnUIThread() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // We will post this on the device thread before the media media access
+ // request is posted on the UI thread, so setting the keyboard mic info will
+ // be done before any stream is created.
+ if (chromeos::CrasAudioHandler::Get()->HasKeyboardMic()) {
+ device_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaStreamManager::SetKeyboardMicOnDeviceThread,
+ base::Unretained(this)));
+ }
+}
+
+void MediaStreamManager::SetKeyboardMicOnDeviceThread() {
+ DCHECK(device_task_runner_->BelongsToCurrentThread());
+ audio_manager_->SetHasKeyboardMic();
+}
+#endif
+
} // namespace content
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 1de659c3937..9499e32f257 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_manager.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_manager.h
@@ -37,6 +37,7 @@
#include "base/message_loop/message_loop.h"
#include "base/power_monitor/power_observer.h"
#include "base/system_monitor/system_monitor.h"
+#include "base/threading/thread.h"
#include "content/browser/renderer_host/media/media_stream_provider.h"
#include "content/common/content_export.h"
#include "content/common/media/media_stream_options.h"
@@ -50,6 +51,7 @@ class AudioManager;
namespace content {
class AudioInputDeviceManager;
+class BrowserContext;
class FakeMediaStreamUIProxy;
class MediaStreamDeviceSettings;
class MediaStreamRequester;
@@ -71,7 +73,7 @@ class CONTENT_EXPORT MediaStreamManager
MediaRequestResponseCallback;
explicit MediaStreamManager(media::AudioManager* audio_manager);
- virtual ~MediaStreamManager();
+ ~MediaStreamManager() override;
// Used to access VideoCaptureManager.
VideoCaptureManager* video_capture_manager();
@@ -81,13 +83,13 @@ class CONTENT_EXPORT MediaStreamManager
// Creates a new media access request which is identified by a unique string
// that's returned to the caller. This will trigger the infobar and ask users
- // for access to the device. |render_process_id| and |render_view_id| refer
- // to the view where the infobar will appear to the user. |callback| is
+ // for access to the device. |render_process_id| and |render_frame_id| are
+ // used to determine where the infobar will appear to the user. |callback| is
// used to send the selected device to the clients. An empty list of device
// will be returned if the users deny the access.
std::string MakeMediaAccessRequest(
int render_process_id,
- int render_view_id,
+ int render_frame_id,
int page_request_id,
const StreamOptions& options,
const GURL& security_origin,
@@ -95,11 +97,11 @@ class CONTENT_EXPORT MediaStreamManager
// GenerateStream opens new media devices according to |components|. It
// creates a new request which is identified by a unique string that's
- // returned to the caller. |render_process_id| and |render_view_id| refer to
- // the view where the infobar will appear to the user.
+ // returned to the caller. |render_process_id| and |render_frame_id| are used
+ // to determine where the infobar will appear to the user.
void GenerateStream(MediaStreamRequester* requester,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
const ResourceContext::SaltCallback& sc,
int page_request_id,
const StreamOptions& components,
@@ -107,7 +109,7 @@ class CONTENT_EXPORT MediaStreamManager
bool user_gesture);
void CancelRequest(int render_process_id,
- int render_view_id,
+ int render_frame_id,
int page_request_id);
// Cancel an open request identified by |label|.
@@ -116,10 +118,10 @@ class CONTENT_EXPORT MediaStreamManager
// Cancel all requests for the given |render_process_id|.
void CancelAllRequests(int render_process_id);
- // Closes the stream device for a certain render view. The stream must have
+ // Closes the stream device for a certain render frame. The stream must have
// been opened by a call to GenerateStream.
void StopStreamDevice(int render_process_id,
- int render_view_id,
+ int render_frame_id,
const std::string& device_id);
// Gets a list of devices of |type|, which must be MEDIA_DEVICE_AUDIO_CAPTURE
@@ -129,22 +131,20 @@ class CONTENT_EXPORT MediaStreamManager
// and video devices and also start monitoring device changes, such as
// plug/unplug. The new device lists will be delivered via media observer to
// MediaCaptureDevicesDispatcher.
- // If |have_permission| is false, we remove the device label from the result.
virtual std::string EnumerateDevices(MediaStreamRequester* requester,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
const ResourceContext::SaltCallback& sc,
int page_request_id,
MediaStreamType type,
- const GURL& security_origin,
- bool have_permission);
+ const GURL& security_origin);
// Open a device identified by |device_id|. |type| must be either
// MEDIA_DEVICE_AUDIO_CAPTURE or MEDIA_DEVICE_VIDEO_CAPTURE.
// The request is identified using string returned to the caller.
void OpenDevice(MediaStreamRequester* requester,
int render_process_id,
- int render_view_id,
+ int render_frame_id,
const ResourceContext::SaltCallback& sc,
int page_request_id,
const std::string& device_id,
@@ -166,18 +166,14 @@ class CONTENT_EXPORT MediaStreamManager
void EnsureDeviceMonitorStarted();
// Implements MediaStreamProviderListener.
- virtual void Opened(MediaStreamType stream_type,
- int capture_session_id) OVERRIDE;
- virtual void Closed(MediaStreamType stream_type,
- int capture_session_id) OVERRIDE;
- virtual void DevicesEnumerated(MediaStreamType stream_type,
- const StreamDeviceInfoArray& devices) OVERRIDE;
- virtual void Aborted(MediaStreamType stream_type,
- int capture_session_id) OVERRIDE;
+ void Opened(MediaStreamType stream_type, int capture_session_id) override;
+ void Closed(MediaStreamType stream_type, int capture_session_id) override;
+ void DevicesEnumerated(MediaStreamType stream_type,
+ const StreamDeviceInfoArray& devices) override;
+ void Aborted(MediaStreamType stream_type, int capture_session_id) override;
// Implements base::SystemMonitor::DevicesChangedObserver.
- virtual void OnDevicesChanged(
- base::SystemMonitor::DeviceType device_type) OVERRIDE;
+ void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) override;
// 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).
@@ -196,7 +192,7 @@ class CONTENT_EXPORT MediaStreamManager
// But for some tests which use TestBrowserThreadBundle, we need to call
// WillDestroyCurrentMessageLoop explicitly because the notification happens
// too late. (see http://crbug.com/247525#c14).
- virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+ void WillDestroyCurrentMessageLoop() override;
// Sends log messages to the render process hosts whose corresponding render
// processes are making device requests, to be used by the
@@ -209,8 +205,8 @@ class CONTENT_EXPORT MediaStreamManager
static void SendMessageToNativeLog(const std::string& message);
// base::PowerObserver overrides.
- virtual void OnSuspend() OVERRIDE;
- virtual void OnResume() OVERRIDE;
+ void OnSuspend() override;
+ void OnResume() override;
protected:
// Used for testing.
@@ -301,7 +297,7 @@ class CONTENT_EXPORT MediaStreamManager
// needed.
void PostRequestToUI(const std::string& label, DeviceRequest* request);
// Returns true if a device with |device_id| has already been requested with
- // a render procecss_id and render_view_id and type equal to the the values
+ // 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
// about the device.
bool FindExistingRequestedDeviceInfo(
@@ -322,6 +318,8 @@ class CONTENT_EXPORT MediaStreamManager
const MediaStreamDevices& devices);
void FinalizeEnumerateDevices(const std::string& label,
DeviceRequest* request);
+ void HandleCheckMediaAccessResponse(const std::string& label,
+ bool have_access);
// This method is called when an audio or video device is plugged in or
// removed. It make sure all MediaStreams that use a removed device is
@@ -362,6 +360,20 @@ class CONTENT_EXPORT MediaStreamManager
StreamDeviceInfoArray devices,
gfx::NativeViewId window_id);
+#if defined(OS_CHROMEOS)
+ // Ensures that we have checked for presence of a keyboard mic. This is only
+ // done once. This function should be called before posting a request on the
+ // UI thread.
+ void EnsureKeyboardMicChecked();
+
+ // Checks if the system has a keyboard mic, and if so, inform the audio
+ // manager via SetKeyboardMicOnDeviceThread().
+ void CheckKeyboardMicOnUIThread();
+
+ // Tells the audio mananger that the system supports a keyboard mic.
+ void SetKeyboardMicOnDeviceThread();
+#endif
+
// Task runner shared by VideoCaptureManager and AudioInputDeviceManager and
// used for enumerating audio output devices.
// Note: Enumeration tasks may take seconds to complete so must never be run
@@ -371,10 +383,21 @@ class CONTENT_EXPORT MediaStreamManager
media::AudioManager* const audio_manager_; // not owned
scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_;
scoped_refptr<VideoCaptureManager> video_capture_manager_;
+#if defined(OS_WIN)
+ base::Thread video_capture_thread_;
+#endif
// Indicator of device monitoring state.
bool monitoring_started_;
+#if defined(OS_CHROMEOS)
+ // Flag that's set when we have checked if the system has a keyboard mic. We
+ // only need to check it once, and not when constructing since that will
+ // affect startup time.
+ // Must be accessed on the IO thread;
+ bool has_checked_keyboard_mic_;
+#endif
+
// Stores most recently enumerated device lists. The cache is cleared when
// monitoring is stopped or there is no request for that type of device.
EnumerationCache audio_enumeration_cache_;
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 e01b945b815..51ab0a52bfb 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
@@ -55,10 +55,10 @@ typedef media::FakeAudioManager AudioManagerPlatform;
class MockAudioManager : public AudioManagerPlatform {
public:
MockAudioManager() : AudioManagerPlatform(&fake_audio_log_factory_) {}
- virtual ~MockAudioManager() {}
+ ~MockAudioManager() override {}
- virtual void GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) OVERRIDE {
+ void GetAudioInputDeviceNames(
+ media::AudioDeviceNames* device_names) override {
DCHECK(device_names->empty());
if (HasAudioInputDevices()) {
AudioManagerBase::GetAudioInputDeviceNames(device_names);
@@ -79,7 +79,7 @@ class MediaStreamManagerTest : public ::testing::Test {
: thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
message_loop_(base::MessageLoopProxy::current()) {
// Create our own MediaStreamManager. Use fake devices to run on the bots.
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kUseFakeDeviceForMediaStream);
audio_manager_.reset(new MockAudioManager());
media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
@@ -99,7 +99,7 @@ class MediaStreamManagerTest : public ::testing::Test {
protected:
std::string MakeMediaAccessRequest(int index) {
const int render_process_id = 1;
- const int render_view_id = 1;
+ const int render_frame_id = 1;
const int page_request_id = 1;
const GURL security_origin;
MediaStreamManager::MediaRequestResponseCallback callback =
@@ -107,7 +107,7 @@ class MediaStreamManagerTest : public ::testing::Test {
base::Unretained(this), index);
StreamOptions options(true, true);
return media_stream_manager_->MakeMediaAccessRequest(render_process_id,
- render_view_id,
+ render_frame_id,
page_request_id,
options,
security_origin,
@@ -146,7 +146,7 @@ TEST_F(MediaStreamManagerTest, MakeMultipleRequests) {
// Second request.
int render_process_id = 2;
- int render_view_id = 2;
+ int render_frame_id = 2;
int page_request_id = 2;
GURL security_origin;
StreamOptions options(true, true);
@@ -155,7 +155,7 @@ TEST_F(MediaStreamManagerTest, MakeMultipleRequests) {
base::Unretained(this), 1);
std::string label2 = media_stream_manager_->MakeMediaAccessRequest(
render_process_id,
- render_view_id,
+ render_frame_id,
page_request_id,
options,
security_origin,
diff --git a/chromium/content/browser/renderer_host/media/media_stream_requester.h b/chromium/content/browser/renderer_host/media/media_stream_requester.h
index 337effade97..c36f166670f 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_requester.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_requester.h
@@ -18,29 +18,29 @@ namespace content {
class CONTENT_EXPORT MediaStreamRequester {
public:
// Called as a reply of a successful call to GenerateStream.
- virtual void StreamGenerated(int render_view_id,
+ virtual void StreamGenerated(int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfoArray& audio_devices,
const StreamDeviceInfoArray& video_devices) = 0;
// Called if GenerateStream failed.
virtual void StreamGenerationFailed(
- int render_view_id,
+ int render_frame_id,
int page_request_id,
content::MediaStreamRequestResult result) = 0;
// Called if a device has been stopped by a user from UI or the device
- // has become unavailable. |render_view_id| is the render view that requested
- // the device and |label| is the label of the request|.
- virtual void DeviceStopped(int render_view_id,
+ // has become unavailable. |render_frame_id| is the render frame that
+ // requested the device and |label| is the label of the request.
+ virtual void DeviceStopped(int render_frame_id,
const std::string& label,
const StreamDeviceInfo& device) = 0;
// Called as a reply of a successful call to EnumerateDevices.
- virtual void DevicesEnumerated(int render_view_id,
+ virtual void DevicesEnumerated(int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfoArray& devices) = 0;
// Called as a reply of a successful call to OpenDevice.
- virtual void DeviceOpened(int render_view_id,
+ virtual void DeviceOpened(int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfo& device_info) = 0;
diff --git a/chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.cc b/chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.cc
index 9bae1f72839..328d60e28ac 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.cc
+++ b/chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.cc
@@ -49,13 +49,16 @@ bool MediaStreamTrackMetricsHost::OnMessageReceived(
void MediaStreamTrackMetricsHost::OnAddTrack(uint64 id,
bool is_audio,
bool is_remote) {
- DCHECK(tracks_.find(id) == tracks_.end());
+ if (tracks_.find(id) != tracks_.end())
+ return;
+
TrackInfo info = {is_audio, is_remote, base::TimeTicks::Now()};
tracks_[id] = info;
}
void MediaStreamTrackMetricsHost::OnRemoveTrack(uint64 id) {
- DCHECK(tracks_.find(id) != tracks_.end());
+ if (tracks_.find(id) == tracks_.end())
+ return;
TrackInfo& info = tracks_[id];
ReportDuration(info);
diff --git a/chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.h b/chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.h
index 081b0d51137..35235dba611 100644
--- a/chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.h
+++ b/chromium/content/browser/renderer_host/media/media_stream_track_metrics_host.h
@@ -31,10 +31,10 @@ class MediaStreamTrackMetricsHost
explicit MediaStreamTrackMetricsHost();
protected:
- virtual ~MediaStreamTrackMetricsHost();
+ ~MediaStreamTrackMetricsHost() override;
// BrowserMessageFilter override.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
void OnAddTrack(uint64 id, bool is_audio, bool is_remote);
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 048b078c2bf..990471f94bc 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
@@ -30,7 +30,7 @@ class MediaStreamDeviceUIControllerTest
const std::string&, const StreamDeviceInfoArray&));
MOCK_METHOD1(SettingsError, void(const std::string&));
MOCK_METHOD1(StopStreamFromUI, void(const std::string&));
- void GetAvailableDevices(MediaStreamDevices* devices) OVERRIDE {
+ void GetAvailableDevices(MediaStreamDevices* devices) override {
devices->push_back(MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE,
"mic",
"mic_id",
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 1c924241aa3..d6d827540a6 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
@@ -5,8 +5,8 @@
#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
#include "base/command_line.h"
-#include "content/browser/renderer_host/render_view_host_delegate.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/frame_host/render_frame_host_delegate.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "media/video/capture/fake_video_capture_device.h"
@@ -16,10 +16,14 @@ namespace content {
class MediaStreamUIProxy::Core {
public:
explicit Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
- RenderViewHostDelegate* test_render_delegate);
+ RenderFrameHostDelegate* test_render_delegate);
~Core();
void RequestAccess(const MediaStreamRequest& request);
+ bool CheckAccess(const GURL& security_origin,
+ MediaStreamType type,
+ int process_id,
+ int frame_id);
void OnStarted(gfx::NativeViewId* window_id);
private:
@@ -27,11 +31,13 @@ class MediaStreamUIProxy::Core {
content::MediaStreamRequestResult result,
scoped_ptr<MediaStreamUI> stream_ui);
void ProcessStopRequestFromUI();
+ RenderFrameHostDelegate* GetRenderFrameHostDelegate(int render_process_id,
+ int render_frame_id);
base::WeakPtr<MediaStreamUIProxy> proxy_;
scoped_ptr<MediaStreamUI> ui_;
- RenderViewHostDelegate* const test_render_delegate_;
+ RenderFrameHostDelegate* const test_render_delegate_;
// WeakPtr<> is used to RequestMediaAccessPermission() because there is no way
// cancel media requests.
@@ -41,7 +47,7 @@ class MediaStreamUIProxy::Core {
};
MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy,
- RenderViewHostDelegate* test_render_delegate)
+ RenderFrameHostDelegate* test_render_delegate)
: proxy_(proxy),
test_render_delegate_(test_render_delegate),
weak_factory_(this) {
@@ -55,24 +61,15 @@ void MediaStreamUIProxy::Core::RequestAccess(
const MediaStreamRequest& request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- RenderViewHostDelegate* render_delegate;
-
- if (test_render_delegate_) {
- render_delegate = test_render_delegate_;
- } else {
- RenderViewHostImpl* host = RenderViewHostImpl::FromID(
- request.render_process_id, request.render_view_id);
-
- // Tab may have gone away.
- if (!host || !host->GetDelegate()) {
- ProcessAccessRequestResponse(
- MediaStreamDevices(),
- MEDIA_DEVICE_INVALID_STATE,
- scoped_ptr<MediaStreamUI>());
- return;
- }
+ RenderFrameHostDelegate* render_delegate = GetRenderFrameHostDelegate(
+ request.render_process_id, request.render_frame_id);
- render_delegate = host->GetDelegate();
+ // Tab may have gone away, or has no delegate from which to request access.
+ if (!render_delegate) {
+ ProcessAccessRequestResponse(MediaStreamDevices(),
+ MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
+ scoped_ptr<MediaStreamUI>());
+ return;
}
render_delegate->RequestMediaAccessPermission(
@@ -80,6 +77,20 @@ void MediaStreamUIProxy::Core::RequestAccess(
weak_factory_.GetWeakPtr()));
}
+bool MediaStreamUIProxy::Core::CheckAccess(const GURL& security_origin,
+ MediaStreamType type,
+ int render_process_id,
+ int render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ RenderFrameHostDelegate* render_delegate =
+ GetRenderFrameHostDelegate(render_process_id, render_frame_id);
+ if (!render_delegate)
+ return false;
+
+ return render_delegate->CheckMediaAccessPermission(security_origin, type);
+}
+
void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (ui_) {
@@ -109,6 +120,16 @@ void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() {
base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_));
}
+RenderFrameHostDelegate* MediaStreamUIProxy::Core::GetRenderFrameHostDelegate(
+ int render_process_id,
+ int render_frame_id) {
+ if (test_render_delegate_)
+ return test_render_delegate_;
+ RenderFrameHostImpl* host =
+ RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
+ return host ? host->delegate() : NULL;
+}
+
// static
scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL));
@@ -116,13 +137,13 @@ scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() {
// static
scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests(
- RenderViewHostDelegate* render_delegate) {
+ RenderFrameHostDelegate* render_delegate) {
return scoped_ptr<MediaStreamUIProxy>(
new MediaStreamUIProxy(render_delegate));
}
MediaStreamUIProxy::MediaStreamUIProxy(
- RenderViewHostDelegate* test_render_delegate)
+ RenderFrameHostDelegate* test_render_delegate)
: weak_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
core_.reset(new Core(weak_factory_.GetWeakPtr(), test_render_delegate));
@@ -130,7 +151,6 @@ MediaStreamUIProxy::MediaStreamUIProxy(
MediaStreamUIProxy::~MediaStreamUIProxy() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, core_.release());
}
void MediaStreamUIProxy::RequestAccess(
@@ -144,6 +164,28 @@ void MediaStreamUIProxy::RequestAccess(
base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request));
}
+void MediaStreamUIProxy::CheckAccess(
+ const GURL& security_origin,
+ MediaStreamType type,
+ int render_process_id,
+ int render_frame_id,
+ const base::Callback<void(bool)>& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&Core::CheckAccess,
+ base::Unretained(core_.get()),
+ security_origin,
+ type,
+ render_process_id,
+ render_frame_id),
+ base::Bind(&MediaStreamUIProxy::OnCheckedAccess,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback,
const WindowIdCallback& window_id_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -163,13 +205,6 @@ void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback,
base::Owned(window_id)));
}
-void MediaStreamUIProxy::OnWindowId(const WindowIdCallback& window_id_callback,
- gfx::NativeViewId* window_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!window_id_callback.is_null())
- window_id_callback.Run(*window_id);
-}
-
void MediaStreamUIProxy::ProcessAccessRequestResponse(
const MediaStreamDevices& devices,
content::MediaStreamRequestResult result) {
@@ -190,8 +225,25 @@ void MediaStreamUIProxy::ProcessStopRequestFromUI() {
cb.Run();
}
+void MediaStreamUIProxy::OnWindowId(const WindowIdCallback& window_id_callback,
+ gfx::NativeViewId* window_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!window_id_callback.is_null())
+ window_id_callback.Run(*window_id);
+}
+
+void MediaStreamUIProxy::OnCheckedAccess(
+ const base::Callback<void(bool)>& callback,
+ bool have_access) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!callback.is_null())
+ callback.Run(have_access);
+}
+
FakeMediaStreamUIProxy::FakeMediaStreamUIProxy()
- : MediaStreamUIProxy(NULL) {
+ : MediaStreamUIProxy(NULL),
+ mic_access_(true),
+ camera_access_(true) {
}
FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {}
@@ -201,6 +253,14 @@ void FakeMediaStreamUIProxy::SetAvailableDevices(
devices_ = devices;
}
+void FakeMediaStreamUIProxy::SetMicAccess(bool access) {
+ mic_access_ = access;
+}
+
+void FakeMediaStreamUIProxy::SetCameraAccess(bool access) {
+ camera_access_ = access;
+}
+
void FakeMediaStreamUIProxy::RequestAccess(
const MediaStreamRequest& request,
const ResponseCallback& response_callback) {
@@ -245,7 +305,7 @@ void FakeMediaStreamUIProxy::RequestAccess(
}
}
- // Fail the request if a device exist for the requested type.
+ // Fail the request if a device doesn't exist for the requested type.
if ((request.audio_type != MEDIA_NO_SERVICE && !accepted_audio) ||
(request.video_type != MEDIA_NO_SERVICE && !accepted_video)) {
devices_to_use.clear();
@@ -261,6 +321,33 @@ void FakeMediaStreamUIProxy::RequestAccess(
MEDIA_DEVICE_OK));
}
+void FakeMediaStreamUIProxy::CheckAccess(
+ const GURL& security_origin,
+ MediaStreamType type,
+ int render_process_id,
+ int render_frame_id,
+ const base::Callback<void(bool)>& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ type == MEDIA_DEVICE_VIDEO_CAPTURE);
+
+ bool have_access = false;
+ if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kUseFakeUIForMediaStream) != "deny") {
+ have_access =
+ type == MEDIA_DEVICE_AUDIO_CAPTURE ? mic_access_ : camera_access_;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&MediaStreamUIProxy::OnCheckedAccess,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ have_access));
+ return;
+}
+
void FakeMediaStreamUIProxy::OnStarted(
const base::Closure& stop_callback,
const WindowIdCallback& window_id_callback) {}
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 01be16676cd..23fc592e62b 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
@@ -9,15 +9,16 @@
#include "base/callback.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"
namespace content {
-class RenderViewHostDelegate;
+class RenderFrameHostDelegate;
// MediaStreamUIProxy proxies calls to media stream UI between IO thread and UI
// thread. One instance of this class is create per MediaStream object. It must
-// be create, used and destroyed on IO thread.
+// be created, used and destroyed on IO thread.
class CONTENT_EXPORT MediaStreamUIProxy {
public:
typedef base::Callback<
@@ -29,7 +30,7 @@ class CONTENT_EXPORT MediaStreamUIProxy {
static scoped_ptr<MediaStreamUIProxy> Create();
static scoped_ptr<MediaStreamUIProxy> CreateForTests(
- RenderViewHostDelegate* render_delegate);
+ RenderFrameHostDelegate* render_delegate);
virtual ~MediaStreamUIProxy();
@@ -40,6 +41,16 @@ class CONTENT_EXPORT MediaStreamUIProxy {
virtual void RequestAccess(const MediaStreamRequest& request,
const ResponseCallback& response_callback);
+ // Checks if we have permission to access the microphone or camera. Note that
+ // this does not query the user, it checks any stored settings such as policy
+ // or extension permissions. |type| must be MEDIA_DEVICE_AUDIO_CAPTURE
+ // or MEDIA_DEVICE_VIDEO_CAPTURE.
+ virtual void CheckAccess(const GURL& security_origin,
+ MediaStreamType type,
+ int render_process_id,
+ int render_frame_id,
+ const base::Callback<void(bool)>& callback);
+
// Notifies the UI that the MediaStream has been started. Must be called after
// access has been approved using RequestAccess(). |stop_callback| is be
// called on the IO thread after the user has requests the stream to be
@@ -48,10 +59,10 @@ class CONTENT_EXPORT MediaStreamUIProxy {
virtual void OnStarted(const base::Closure& stop_callback,
const WindowIdCallback& window_id_callback);
- void SetRenderViewHostDelegateForTests(RenderViewHostDelegate* delegate);
+ void SetRenderFrameHostDelegateForTests(RenderFrameHostDelegate* delegate);
protected:
- MediaStreamUIProxy(RenderViewHostDelegate* test_render_delegate);
+ explicit MediaStreamUIProxy(RenderFrameHostDelegate* test_render_delegate);
private:
class Core;
@@ -64,8 +75,10 @@ class CONTENT_EXPORT MediaStreamUIProxy {
void ProcessStopRequestFromUI();
void OnWindowId(const WindowIdCallback& window_id_callback,
gfx::NativeViewId* window_id);
+ void OnCheckedAccess(const base::Callback<void(bool)>& callback,
+ bool have_access);
- scoped_ptr<Core> core_;
+ scoped_ptr<Core, content::BrowserThread::DeleteOnUIThread> core_;
ResponseCallback response_callback_;
base::Closure stop_callback_;
@@ -77,20 +90,31 @@ class CONTENT_EXPORT MediaStreamUIProxy {
class CONTENT_EXPORT FakeMediaStreamUIProxy : public MediaStreamUIProxy {
public:
explicit FakeMediaStreamUIProxy();
- virtual ~FakeMediaStreamUIProxy();
+ ~FakeMediaStreamUIProxy() override;
void SetAvailableDevices(const MediaStreamDevices& devices);
+ void SetMicAccess(bool access);
+ void SetCameraAccess(bool access);
// MediaStreamUIProxy overrides.
- virtual void RequestAccess(
- const MediaStreamRequest& request,
- const ResponseCallback& response_callback) OVERRIDE;
- virtual void OnStarted(const base::Closure& stop_callback,
- const WindowIdCallback& window_id_callback) OVERRIDE;
+ void RequestAccess(const MediaStreamRequest& request,
+ const ResponseCallback& response_callback) override;
+ void CheckAccess(const GURL& security_origin,
+ MediaStreamType type,
+ int render_process_id,
+ int render_frame_id,
+ const base::Callback<void(bool)>& callback) override;
+ void OnStarted(const base::Closure& stop_callback,
+ const WindowIdCallback& window_id_callback) override;
private:
+ // This is used for RequestAccess().
MediaStreamDevices devices_;
+ // These are used for CheckAccess().
+ bool mic_access_;
+ bool camera_access_;
+
DISALLOW_COPY_AND_ASSIGN(FakeMediaStreamUIProxy);
};
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 4529b4999d9..4eb7546e651 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
@@ -5,7 +5,7 @@
#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
#include "base/message_loop/message_loop.h"
-#include "content/browser/renderer_host/render_view_host_delegate.h"
+#include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/public/common/renderer_preferences.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -19,22 +19,14 @@ using testing::SaveArg;
namespace content {
namespace {
-class MockRenderViewHostDelegate : public RenderViewHostDelegate {
+class MockRenderFrameHostDelegate : public RenderFrameHostDelegate {
public:
MOCK_METHOD2(RequestMediaAccessPermission,
void(const MediaStreamRequest& request,
const MediaResponseCallback& callback));
-
- // Stubs for pure virtual methods we don't care about.
- virtual gfx::Rect GetRootWindowResizerRect() const OVERRIDE {
- NOTREACHED();
- return gfx::Rect();
- }
- virtual RendererPreferences GetRendererPrefs(
- BrowserContext* browser_context) const OVERRIDE {
- NOTREACHED();
- return RendererPreferences();
- }
+ MOCK_METHOD2(CheckMediaAccessPermission,
+ bool(const GURL& security_origin,
+ MediaStreamType type));
};
class MockResponseCallback {
@@ -42,6 +34,7 @@ class MockResponseCallback {
MOCK_METHOD2(OnAccessRequestResponse,
void(const MediaStreamDevices& devices,
content::MediaStreamRequestResult result));
+ MOCK_METHOD1(OnCheckResponse, void(bool have_access));
};
class MockMediaStreamUI : public MediaStreamUI {
@@ -66,7 +59,7 @@ class MediaStreamUIProxyTest : public testing::Test {
proxy_ = MediaStreamUIProxy::CreateForTests(&delegate_);
}
- virtual ~MediaStreamUIProxyTest() {
+ ~MediaStreamUIProxyTest() override {
proxy_.reset();
message_loop_.RunUntilIdle();
}
@@ -76,7 +69,7 @@ class MediaStreamUIProxyTest : public testing::Test {
TestBrowserThread ui_thread_;
TestBrowserThread io_thread_;
- MockRenderViewHostDelegate delegate_;
+ MockRenderFrameHostDelegate delegate_;
MockResponseCallback response_callback_;
scoped_ptr<MediaStreamUIProxy> proxy_;
};
@@ -84,7 +77,7 @@ class MediaStreamUIProxyTest : public testing::Test {
MATCHER_P(SameRequest, expected, "") {
return
expected.render_process_id == arg.render_process_id &&
- expected.render_view_id == arg.render_view_id &&
+ expected.render_frame_id == arg.render_frame_id &&
expected.tab_capture_device_id == arg.tab_capture_device_id &&
expected.security_origin == arg.security_origin &&
expected.request_type == arg.request_type &&
@@ -140,7 +133,7 @@ TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, "Mic", "Mic"));
scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
EXPECT_CALL(*ui, OnStarted(_)).WillOnce(Return(0));
- callback.Run(devices, MEDIA_DEVICE_OK, ui.PassAs<MediaStreamUI>());
+ callback.Run(devices, MEDIA_DEVICE_OK, ui.Pass());
MediaStreamDevices response;
EXPECT_CALL(response_callback_, OnAccessRequestResponse(_, _))
@@ -199,7 +192,7 @@ TEST_F(MediaStreamUIProxyTest, StopFromUI) {
scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
EXPECT_CALL(*ui, OnStarted(_))
.WillOnce(testing::DoAll(SaveArg<0>(&stop_callback), Return(0)));
- callback.Run(devices, MEDIA_DEVICE_OK, ui.PassAs<MediaStreamUI>());
+ callback.Run(devices, MEDIA_DEVICE_OK, ui.Pass());
MediaStreamDevices response;
EXPECT_CALL(response_callback_, OnAccessRequestResponse(_, _))
@@ -244,8 +237,7 @@ TEST_F(MediaStreamUIProxyTest, WindowIdCallbackCalled) {
scoped_ptr<MockMediaStreamUI> ui(new MockMediaStreamUI());
EXPECT_CALL(*ui, OnStarted(_)).WillOnce(Return(kWindowId));
- callback.Run(
- MediaStreamDevices(), MEDIA_DEVICE_OK, ui.PassAs<MediaStreamUI>());
+ callback.Run(MediaStreamDevices(), MEDIA_DEVICE_OK, ui.Pass());
EXPECT_CALL(response_callback_, OnAccessRequestResponse(_, _));
MockStopStreamHandler handler;
@@ -258,4 +250,16 @@ TEST_F(MediaStreamUIProxyTest, WindowIdCallbackCalled) {
message_loop_.RunUntilIdle();
}
+TEST_F(MediaStreamUIProxyTest, CheckAccess) {
+ proxy_->CheckAccess(GURL("http://origin/"),
+ MEDIA_DEVICE_AUDIO_CAPTURE,
+ 0,
+ 0,
+ base::Bind(&MockResponseCallback::OnCheckResponse,
+ base::Unretained(&response_callback_)));
+ EXPECT_CALL(delegate_, CheckMediaAccessPermission(_, _));
+ EXPECT_CALL(response_callback_, OnCheckResponse(_));
+ message_loop_.RunUntilIdle();
+}
+
} // content
diff --git a/chromium/content/browser/renderer_host/media/mock_media_observer.h b/chromium/content/browser/renderer_host/media/mock_media_observer.h
index 04678c9235a..ae4e7e61f28 100644
--- a/chromium/content/browser/renderer_host/media/mock_media_observer.h
+++ b/chromium/content/browser/renderer_host/media/mock_media_observer.h
@@ -21,9 +21,9 @@ class MockMediaObserver : public MediaObserver {
virtual ~MockMediaObserver();
MOCK_METHOD6(OnMediaRequestStateChanged,
- void(int render_process_id, int render_view_id,
+ void(int render_process_id, int render_frame_id,
int page_request_id, const GURL& security_origin,
- const MediaStreamDevice& device,
+ MediaStreamType stream_type,
const MediaRequestState state));
};
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 a5e0ba3fb0a..cae185d6598 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
@@ -3,14 +3,17 @@
// found in the LICENSE file.
#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/common/media/peer_connection_tracker_messages.h"
+#include "content/public/browser/render_process_host.h"
namespace content {
PeerConnectionTrackerHost::PeerConnectionTrackerHost(int render_process_id)
: BrowserMessageFilter(PeerConnectionTrackerMsgStart),
- render_process_id_(render_process_id) {}
+ render_process_id_(render_process_id) {
+}
bool PeerConnectionTrackerHost::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
@@ -38,6 +41,27 @@ void PeerConnectionTrackerHost::OverrideThreadForMessage(
PeerConnectionTrackerHost::~PeerConnectionTrackerHost() {
}
+void PeerConnectionTrackerHost::OnChannelConnected(int32 peer_pid) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ // Add PowerMonitor when connected to channel rather than in constructor due
+ // to thread safety concerns. Observers of PowerMonitor must be added and
+ // removed on the same thread. BrowserMessageFilter is created on the UI
+ // thread but can be destructed on the UI or IO thread because they are
+ // referenced by RenderProcessHostImpl on the UI thread and ChannelProxy on
+ // the IO thread. Using OnChannelConnected and OnChannelClosing guarantees
+ // execution on the IO thread.
+ base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
+ if (power_monitor)
+ power_monitor->AddObserver(this);
+}
+
+void PeerConnectionTrackerHost::OnChannelClosing() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
+ if (power_monitor)
+ power_monitor->RemoveObserver(this);
+}
+
void PeerConnectionTrackerHost::OnAddPeerConnection(
const PeerConnectionInfo& info) {
WebRTCInternals::GetInstance()->OnAddPeerConnection(
@@ -45,7 +69,7 @@ void PeerConnectionTrackerHost::OnAddPeerConnection(
peer_pid(),
info.lid,
info.url,
- info.servers,
+ info.rtc_configuration,
info.constraints);
}
@@ -82,4 +106,17 @@ void PeerConnectionTrackerHost::OnGetUserMedia(
video_constraints);
}
+void PeerConnectionTrackerHost::OnSuspend() {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&PeerConnectionTrackerHost::SendOnSuspendOnUIThread, this));
+}
+
+void PeerConnectionTrackerHost::SendOnSuspendOnUIThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ content::RenderProcessHost* host =
+ content::RenderProcessHost::FromID(render_process_id_);
+ if (host)
+ host->Send(new PeerConnectionTracker_OnSuspend());
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/media/peer_connection_tracker_host.h b/chromium/content/browser/renderer_host/media/peer_connection_tracker_host.h
index 6a411e8ba00..0d7b506a047 100644
--- a/chromium/content/browser/renderer_host/media/peer_connection_tracker_host.h
+++ b/chromium/content/browser/renderer_host/media/peer_connection_tracker_host.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_PEER_CONNECTION_TRACKER_HOST_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_PEER_CONNECTION_TRACKER_HOST_H_
+#include "base/power_monitor/power_observer.h"
#include "content/public/browser/browser_message_filter.h"
struct PeerConnectionInfo;
@@ -16,19 +17,26 @@ class ListValue;
namespace content {
// This class is the host for PeerConnectionTracker in the browser process
-// managed by RenderProcessHostImpl. It passes IPC messages between
-// WebRTCInternals and PeerConnectionTracker.
-class PeerConnectionTrackerHost : public BrowserMessageFilter {
+// managed by RenderProcessHostImpl. It receives PeerConnection events from
+// PeerConnectionTracker as IPC messages that it forwards to WebRTCInternals.
+// It also forwards browser process events to PeerConnectionTracker via IPC.
+class PeerConnectionTrackerHost : public BrowserMessageFilter,
+ public base::PowerObserver {
public:
PeerConnectionTrackerHost(int render_process_id);
// content::BrowserMessageFilter override.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OverrideThreadForMessage(const IPC::Message& message,
- BrowserThread::ID* thread) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
+ void OnChannelConnected(int32 peer_pid) override;
+ void OnChannelClosing() override;
+
+ // base::PowerObserver override.
+ void OnSuspend() override;
protected:
- virtual ~PeerConnectionTrackerHost();
+ ~PeerConnectionTrackerHost() override;
private:
// Handlers for peer connection messages coming from the renderer.
@@ -42,6 +50,7 @@ class PeerConnectionTrackerHost : public BrowserMessageFilter {
bool video,
const std::string& audio_constraints,
const std::string& video_constraints);
+ void SendOnSuspendOnUIThread();
int render_process_id_;
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 92523756eff..f583a94adaa 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
@@ -19,6 +19,7 @@ const int VideoCaptureBufferPool::kInvalidId = -1;
VideoCaptureBufferPool::VideoCaptureBufferPool(int count)
: count_(count),
next_buffer_id_(0) {
+ DCHECK_GT(count, 0);
}
VideoCaptureBufferPool::~VideoCaptureBufferPool() {
@@ -168,4 +169,3 @@ VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer(
}
} // namespace content
-
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 4775a77c061..c0b462bce26 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller.cc
@@ -12,8 +12,10 @@
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
#include "content/browser/renderer_host/media/media_stream_manager.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 "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/video_frame.h"
@@ -21,6 +23,12 @@
#include "media/base/yuv_convert.h"
#include "third_party/libyuv/include/libyuv.h"
+#if defined(OS_ANDROID)
+#include "content/browser/renderer_host/image_transport_factory_android.h"
+#else
+#include "content/browser/compositor/image_transport_factory.h"
+#endif
+
using media::VideoCaptureFormat;
namespace content {
@@ -34,9 +42,6 @@ static const int kInfiniteRatio = 99999;
name, \
(height) ? ((width) * 100) / (height) : kInfiniteRatio);
-// The number of buffers that VideoCaptureBufferPool should allocate.
-const int kNoOfBuffers = 3;
-
class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer {
public:
PoolBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
@@ -44,15 +49,45 @@ class PoolBuffer : public media::VideoCaptureDevice::Client::Buffer {
void* data,
size_t size)
: Buffer(buffer_id, data, size), pool_(pool) {
- DCHECK(pool_);
+ DCHECK(pool_.get());
}
private:
- virtual ~PoolBuffer() { pool_->RelinquishProducerReservation(id()); }
+ ~PoolBuffer() override { pool_->RelinquishProducerReservation(id()); }
const scoped_refptr<VideoCaptureBufferPool> pool_;
};
+class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
+ public:
+ explicit SyncPointClientImpl(GLHelper* gl_helper) : gl_helper_(gl_helper) {}
+ ~SyncPointClientImpl() override {}
+ uint32 InsertSyncPoint() override { return gl_helper_->InsertSyncPoint(); }
+ void WaitSyncPoint(uint32 sync_point) override {
+ gl_helper_->WaitSyncPoint(sync_point);
+ }
+
+ private:
+ GLHelper* gl_helper_;
+};
+
+void ReturnVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
+ uint32 sync_point) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+#if defined(OS_ANDROID)
+ GLHelper* gl_helper =
+ ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
+#else
+ GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
+#endif
+ DCHECK(gl_helper);
+ // UpdateReleaseSyncPoint() creates a new sync_point using |gl_helper|, so
+ // wait the given |sync_point| using |gl_helper|.
+ gl_helper->WaitSyncPoint(sync_point);
+ SyncPointClientImpl client(gl_helper);
+ video_frame->UpdateReleaseSyncPoint(&client);
+}
+
} // anonymous namespace
struct VideoCaptureController::ControllerClient {
@@ -66,7 +101,8 @@ struct VideoCaptureController::ControllerClient {
render_process_handle(render_process),
session_id(session_id),
parameters(params),
- session_closed(false) {}
+ session_closed(false),
+ paused(false) {}
~ControllerClient() {}
@@ -98,6 +134,10 @@ struct VideoCaptureController::ControllerClient {
// implicitly), we could avoid tracking this state here in the Controller, and
// simplify the code in both places.
bool session_closed;
+
+ // Indicates whether the client is paused, if true, VideoCaptureController
+ // stops updating its buffer.
+ bool paused;
};
// Receives events from the VideoCaptureDevice and posts them to a
@@ -114,24 +154,23 @@ class VideoCaptureController::VideoCaptureDeviceClient
explicit VideoCaptureDeviceClient(
const base::WeakPtr<VideoCaptureController>& controller,
const scoped_refptr<VideoCaptureBufferPool>& buffer_pool);
- virtual ~VideoCaptureDeviceClient();
+ ~VideoCaptureDeviceClient() override;
// VideoCaptureDevice::Client implementation.
- virtual scoped_refptr<Buffer> ReserveOutputBuffer(
- media::VideoFrame::Format format,
- const gfx::Size& size) OVERRIDE;
- virtual void OnIncomingCapturedData(const uint8* data,
- int length,
- const VideoCaptureFormat& frame_format,
- int rotation,
- base::TimeTicks timestamp) OVERRIDE;
- virtual void OnIncomingCapturedVideoFrame(
+ scoped_refptr<Buffer> ReserveOutputBuffer(media::VideoFrame::Format format,
+ const gfx::Size& size) override;
+ void OnIncomingCapturedData(const uint8* data,
+ int length,
+ const VideoCaptureFormat& frame_format,
+ int rotation,
+ base::TimeTicks timestamp) override;
+ void OnIncomingCapturedVideoFrame(
const scoped_refptr<Buffer>& buffer,
const VideoCaptureFormat& buffer_format,
const scoped_refptr<media::VideoFrame>& frame,
- base::TimeTicks timestamp) OVERRIDE;
- virtual void OnError(const std::string& reason) OVERRIDE;
- virtual void OnLog(const std::string& message) OVERRIDE;
+ base::TimeTicks timestamp) override;
+ void OnError(const std::string& reason) override;
+ void OnLog(const std::string& message) override;
private:
scoped_refptr<Buffer> DoReserveOutputBuffer(media::VideoFrame::Format format,
@@ -142,20 +181,19 @@ class VideoCaptureController::VideoCaptureDeviceClient
// The pool of shared-memory buffers used for capturing.
const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
-
- bool first_frame_;
};
-VideoCaptureController::VideoCaptureController()
- : buffer_pool_(new VideoCaptureBufferPool(kNoOfBuffers)),
+VideoCaptureController::VideoCaptureController(int max_buffers)
+ : buffer_pool_(new VideoCaptureBufferPool(max_buffers)),
state_(VIDEO_CAPTURE_STATE_STARTED),
+ has_received_frames_(false),
weak_ptr_factory_(this) {
}
VideoCaptureController::VideoCaptureDeviceClient::VideoCaptureDeviceClient(
const base::WeakPtr<VideoCaptureController>& controller,
const scoped_refptr<VideoCaptureBufferPool>& buffer_pool)
- : controller_(controller), buffer_pool_(buffer_pool), first_frame_(true) {}
+ : controller_(controller), buffer_pool_(buffer_pool) {}
VideoCaptureController::VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {}
@@ -233,6 +271,22 @@ int VideoCaptureController::RemoveClient(
return session_id;
}
+void VideoCaptureController::PauseOrResumeClient(
+ const VideoCaptureControllerID& id,
+ VideoCaptureControllerEventHandler* event_handler,
+ bool pause) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DVLOG(1) << "VideoCaptureController::PauseOrResumeClient, id "
+ << id.device_id << ", " << pause;
+
+ ControllerClient* client = FindClient(id, event_handler, controller_clients_);
+ if (!client)
+ return;
+
+ DCHECK(client->paused != pause);
+ client->paused = pause;
+}
+
void VideoCaptureController::StopSession(int session_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id;
@@ -249,7 +303,7 @@ void VideoCaptureController::ReturnBuffer(
const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* event_handler,
int buffer_id,
- const std::vector<uint32>& sync_points) {
+ uint32 sync_point) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ControllerClient* client = FindClient(id, event_handler, controller_clients_);
@@ -264,13 +318,12 @@ void VideoCaptureController::ReturnBuffer(
}
scoped_refptr<media::VideoFrame> frame = iter->second;
client->active_buffers.erase(iter);
-
- if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
- for (size_t i = 0; i < sync_points.size(); i++)
- frame->AppendReleaseSyncPoint(sync_points[i]);
- }
-
buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
+
+ if (sync_point)
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ReturnVideoFrame, frame, sync_point));
}
const media::VideoCaptureFormat&
@@ -330,7 +383,7 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedData(
scoped_refptr<Buffer> buffer =
DoReserveOutputBuffer(media::VideoFrame::I420, dimensions);
- if (!buffer)
+ if (!buffer.get())
return;
uint8* yplane = NULL;
bool flip = false;
@@ -429,7 +482,7 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedData(
base::SharedMemory::NULLHandle(),
base::TimeDelta(),
base::Closure());
- DCHECK(frame);
+ DCHECK(frame.get());
VideoCaptureFormat format(
dimensions, frame_format.frame_rate, media::PIXEL_FORMAT_I420);
@@ -443,22 +496,6 @@ void VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedData(
format,
frame,
timestamp));
-
- if (first_frame_) {
- UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width",
- frame_format.frame_size.width());
- UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height",
- frame_format.frame_size.height());
- UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio",
- frame_format.frame_size.width(),
- frame_format.frame_size.height());
- UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate",
- frame_format.frame_rate);
- UMA_HISTOGRAM_ENUMERATION("Media.VideoCapture.PixelFormat",
- frame_format.pixel_format,
- media::PIXEL_FORMAT_MAX);
- first_frame_ = false;
- }
}
void
@@ -481,8 +518,13 @@ VideoCaptureController::VideoCaptureDeviceClient::OnIncomingCapturedVideoFrame(
void VideoCaptureController::VideoCaptureDeviceClient::OnError(
const std::string& reason) {
- MediaStreamManager::SendMessageToNativeLog(
- "Error on video capture: " + reason);
+ const std::string log_message = base::StringPrintf(
+ "Error on video capture: %s, OS message: %s",
+ reason.c_str(),
+ logging::SystemErrorCodeToString(
+ logging::GetLastSystemErrorCode()).c_str());
+ DLOG(ERROR) << log_message;
+ MediaStreamManager::SendMessageToNativeLog(log_message);
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(&VideoCaptureController::DoErrorOnIOThread, controller_));
@@ -548,7 +590,7 @@ void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
for (ControllerClients::iterator client_it = controller_clients_.begin();
client_it != controller_clients_.end(); ++client_it) {
ControllerClient* client = *client_it;
- if (client->session_closed)
+ if (client->session_closed || client->paused)
continue;
if (frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
@@ -569,7 +611,8 @@ void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
}
client->event_handler->OnBufferReady(
- client->controller_id, buffer->id(), buffer_format, timestamp);
+ client->controller_id, buffer->id(), buffer_format,
+ frame->visible_rect(), timestamp);
}
bool inserted =
@@ -580,6 +623,19 @@ void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
}
}
+ if (!has_received_frames_) {
+ UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Width",
+ buffer_format.frame_size.width());
+ UMA_HISTOGRAM_COUNTS("Media.VideoCapture.Height",
+ buffer_format.frame_size.height());
+ UMA_HISTOGRAM_ASPECT_RATIO("Media.VideoCapture.AspectRatio",
+ buffer_format.frame_size.width(),
+ buffer_format.frame_size.height());
+ UMA_HISTOGRAM_COUNTS("Media.VideoCapture.FrameRate",
+ buffer_format.frame_rate);
+ has_received_frames_ = true;
+ }
+
buffer_pool_->HoldForConsumers(buffer->id(), count);
}
@@ -642,9 +698,19 @@ VideoCaptureController::FindClient(
return NULL;
}
-int VideoCaptureController::GetClientCount() {
+int VideoCaptureController::GetClientCount() const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return controller_clients_.size();
}
+int VideoCaptureController::GetActiveClientCount() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ int active_client_count = 0;
+ for (ControllerClient* client : controller_clients_) {
+ if (!client->paused)
+ ++active_client_count;
+ }
+ return active_client_count;
+}
+
} // namespace content
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 9b8287002ec..720213ecf26 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_controller.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_controller.h
@@ -66,7 +66,12 @@ class VideoCaptureBufferPool;
class CONTENT_EXPORT VideoCaptureController {
public:
- VideoCaptureController();
+ // |max_buffers| is the maximum number of video frame buffers in-flight at any
+ // one time. This value should be based on the logical capacity of the
+ // capture pipeline, and not on hardware performance. For example, tab
+ // capture requires more buffers than webcam capture because the pipeline is
+ // longer (it includes read-backs pending in the GPU pipeline).
+ explicit VideoCaptureController(int max_buffers);
virtual ~VideoCaptureController();
base::WeakPtr<VideoCaptureController> GetWeakPtr();
@@ -91,7 +96,15 @@ class CONTENT_EXPORT VideoCaptureController {
int RemoveClient(const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* event_handler);
- int GetClientCount();
+ // Pause or resume the video capture for specified client.
+ void PauseOrResumeClient(const VideoCaptureControllerID& id,
+ VideoCaptureControllerEventHandler* event_handler,
+ bool pause);
+
+ int GetClientCount() const;
+
+ // Return the number of clients that aren't paused.
+ int GetActiveClientCount() const;
// API called directly by VideoCaptureManager in case the device is
// prematurely closed.
@@ -105,10 +118,12 @@ class CONTENT_EXPORT VideoCaptureController {
void ReturnBuffer(const VideoCaptureControllerID& id,
VideoCaptureControllerEventHandler* event_handler,
int buffer_id,
- const std::vector<uint32>& sync_points);
+ uint32 sync_point);
const media::VideoCaptureFormat& GetVideoCaptureFormat() const;
+ bool has_received_frames() const { return has_received_frames_; }
+
private:
class VideoCaptureDeviceClient;
@@ -146,6 +161,9 @@ class CONTENT_EXPORT VideoCaptureController {
// state which stops the flow of data to clients.
VideoCaptureState state_;
+ // True if the controller has received a video frame from the device.
+ bool has_received_frames_;
+
media::VideoCaptureFormat video_capture_format_;
base::WeakPtrFactory<VideoCaptureController> weak_ptr_factory_;
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 3e709476a12..2bddf694606 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
@@ -9,6 +9,10 @@
#include "base/time/time.h"
#include "content/common/content_export.h"
+namespace gfx {
+class Rect;
+} // namespace gfx
+
namespace gpu {
struct MailboxHolder;
} // namespace gpu
@@ -51,6 +55,7 @@ class CONTENT_EXPORT VideoCaptureControllerEventHandler {
virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const media::VideoCaptureFormat& format,
+ const gfx::Rect& visible_rect,
base::TimeTicks timestamp) = 0;
// A texture mailbox buffer has been filled with data.
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 f650397de7b..87cb033b1fa 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
@@ -16,6 +16,7 @@
#include "content/browser/renderer_host/media/video_capture_controller.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/gpu/client/gl_helper.h"
#include "content/common/media/media_stream_options.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
@@ -24,6 +25,12 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_ANDROID)
+#include "content/browser/renderer_host/test/no_transport_image_transport_factory_android.h"
+#else
+#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
+#endif
+
using ::testing::InSequence;
using ::testing::Mock;
@@ -46,22 +53,23 @@ class MockVideoCaptureControllerEventHandler
MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&));
MOCK_METHOD1(DoError, void(const VideoCaptureControllerID&));
- virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE {
+ virtual void OnError(const VideoCaptureControllerID& id) override {
DoError(id);
}
virtual void OnBufferCreated(const VideoCaptureControllerID& id,
base::SharedMemoryHandle handle,
- int length, int buffer_id) OVERRIDE {
+ int length, int buffer_id) override {
DoBufferCreated(id);
}
virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
- int buffer_id) OVERRIDE {
+ int buffer_id) override {
DoBufferDestroyed(id);
}
virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) OVERRIDE {
+ const gfx::Rect& visible_rect,
+ base::TimeTicks timestamp) override {
DoBufferReady(id);
base::MessageLoop::current()->PostTask(
FROM_HERE,
@@ -70,17 +78,14 @@ class MockVideoCaptureControllerEventHandler
id,
this,
buffer_id,
- std::vector<uint32>()));
+ 0));
}
virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) OVERRIDE {
+ base::TimeTicks timestamp) override {
DoMailboxBufferReady(id);
- // Use a very different syncpoint value when returning a new syncpoint.
- std::vector<uint32> release_sync_points;
- release_sync_points.push_back(~mailbox_holder.sync_point);
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureController::ReturnBuffer,
@@ -88,9 +93,9 @@ class MockVideoCaptureControllerEventHandler
id,
this,
buffer_id,
- release_sync_points));
+ mailbox_holder.sync_point));
}
- virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {
+ virtual void OnEnded(const VideoCaptureControllerID& id) override {
DoEnded(id);
// OnEnded() must respond by (eventually) unregistering the client.
base::MessageLoop::current()->PostTask(FROM_HERE,
@@ -105,13 +110,13 @@ class MockVideoCaptureControllerEventHandler
class VideoCaptureControllerTest : public testing::Test {
public:
VideoCaptureControllerTest() {}
- virtual ~VideoCaptureControllerTest() {}
+ ~VideoCaptureControllerTest() override {}
protected:
static const int kPoolSize = 3;
- virtual void SetUp() OVERRIDE {
- controller_.reset(new VideoCaptureController());
+ void SetUp() override {
+ controller_.reset(new VideoCaptureController(kPoolSize));
device_ = controller_->NewDeviceClient().Pass();
client_a_.reset(new MockVideoCaptureControllerEventHandler(
controller_.get()));
@@ -119,9 +124,7 @@ class VideoCaptureControllerTest : public testing::Test {
controller_.get()));
}
- virtual void TearDown() OVERRIDE {
- base::RunLoop().RunUntilIdle();
- }
+ void TearDown() override { base::RunLoop().RunUntilIdle(); }
scoped_refptr<media::VideoFrame> WrapI420Buffer(
const scoped_refptr<media::VideoCaptureDevice::Client::Buffer>& buffer,
@@ -263,17 +266,25 @@ TEST_F(VideoCaptureControllerTest, AddAndRemoveClients) {
<< "Client count should return to zero after all clients are gone.";
}
-static void CacheSyncPoint(std::vector<uint32>* called_release_sync_points,
- const std::vector<uint32>& release_sync_points) {
- DCHECK(called_release_sync_points->empty());
- called_release_sync_points->assign(release_sync_points.begin(),
- release_sync_points.end());
+static void CacheSyncPoint(uint32* called_release_sync_point,
+ uint32 release_sync_point) {
+ *called_release_sync_point = release_sync_point;
}
// This test will connect and disconnect several clients while simulating an
// active capture device being started and generating frames. It runs on one
// thread and is intended to behave deterministically.
TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
+// VideoCaptureController::ReturnBuffer() uses ImageTransportFactory.
+#if defined(OS_ANDROID)
+ ImageTransportFactoryAndroid::InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactoryAndroid>(
+ new NoTransportImageTransportFactoryAndroid));
+#else
+ ImageTransportFactory::InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactory>(new NoTransportImageTransportFactory));
+#endif
+
media::VideoCaptureParams session_100;
session_100.requested_format = media::VideoCaptureFormat(
gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);
@@ -320,7 +331,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer;
buffer =
device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
- ASSERT_TRUE(buffer);
+ ASSERT_TRUE(buffer.get());
memset(buffer->data(), buffer_no++, buffer->size());
{
InSequence s;
@@ -355,7 +366,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
// delay. This shouldn't affect anything.
buffer =
device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
- ASSERT_TRUE(buffer);
+ ASSERT_TRUE(buffer.get());
memset(buffer->data(), buffer_no++, buffer->size());
device_->OnIncomingCapturedVideoFrame(
buffer,
@@ -386,7 +397,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
for (int i = 0; i < kPoolSize; i++) {
buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420,
capture_resolution);
- ASSERT_TRUE(buffer);
+ ASSERT_TRUE(buffer.get());
memset(buffer->data(), buffer_no++, buffer->size());
device_->OnIncomingCapturedVideoFrame(
buffer,
@@ -399,7 +410,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
}
// ReserveOutputBuffer ought to fail now, because the pool is depleted.
ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420,
- capture_resolution));
+ capture_resolution).get());
// The new client needs to be told of 3 buffers; the old clients only 2.
EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize);
@@ -426,7 +437,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
// Queue up another buffer.
buffer =
device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
- ASSERT_TRUE(buffer);
+ ASSERT_TRUE(buffer.get());
memset(buffer->data(), buffer_no++, buffer->size());
device_->OnIncomingCapturedVideoFrame(
buffer,
@@ -444,7 +455,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
EXPECT_CALL(*client_a_, DoEnded(client_a_route_2)).Times(1);
controller_->StopSession(200);
}
- ASSERT_TRUE(buffer);
+ ASSERT_TRUE(buffer.get());
memset(buffer->data(), buffer_no++, buffer->size());
device_->OnIncomingCapturedVideoFrame(
buffer,
@@ -473,7 +484,7 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
for (int i = 0; i < shm_buffers; ++i) {
buffer = device_->ReserveOutputBuffer(media::VideoFrame::I420,
capture_resolution);
- ASSERT_TRUE(buffer);
+ ASSERT_TRUE(buffer.get());
device_->OnIncomingCapturedVideoFrame(
buffer,
media::VideoCaptureFormat(capture_resolution,
@@ -484,42 +495,55 @@ TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
buffer = NULL;
}
std::vector<uint32> mailbox_syncpoints(mailbox_buffers);
- std::vector<std::vector<uint32> > release_syncpoint_vectors(mailbox_buffers);
+ std::vector<uint32> release_syncpoints(mailbox_buffers);
+#if defined(OS_ANDROID)
+ GLHelper* gl_helper =
+ ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
+#else
+ GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
+#endif
for (int i = 0; i < mailbox_buffers; ++i) {
buffer = device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE,
gfx::Size(0, 0));
- ASSERT_TRUE(buffer);
- mailbox_syncpoints[i] = i;
+ ASSERT_TRUE(buffer.get());
+ mailbox_syncpoints[i] = gl_helper->InsertSyncPoint();
device_->OnIncomingCapturedVideoFrame(
buffer,
media::VideoCaptureFormat(capture_resolution,
device_format.frame_rate,
media::PIXEL_FORMAT_TEXTURE),
- WrapMailboxBuffer(
- buffer,
- make_scoped_ptr(new gpu::MailboxHolder(
- gpu::Mailbox(), 0, mailbox_syncpoints[i])),
- base::Bind(&CacheSyncPoint, &release_syncpoint_vectors[i]),
- capture_resolution),
+ WrapMailboxBuffer(buffer,
+ make_scoped_ptr(new gpu::MailboxHolder(
+ gpu::Mailbox(), 0, mailbox_syncpoints[i])),
+ base::Bind(&CacheSyncPoint, &release_syncpoints[i]),
+ capture_resolution),
base::TimeTicks());
buffer = NULL;
}
// ReserveOutputBuffers ought to fail now regardless of buffer format, because
// the pool is depleted.
ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::I420,
- capture_resolution));
+ capture_resolution).get());
ASSERT_FALSE(device_->ReserveOutputBuffer(media::VideoFrame::NATIVE_TEXTURE,
- gfx::Size(0, 0)));
+ gfx::Size(0, 0)).get());
EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(shm_buffers);
EXPECT_CALL(*client_b_, DoMailboxBufferReady(client_b_route_2))
.Times(mailbox_buffers);
base::RunLoop().RunUntilIdle();
for (size_t i = 0; i < mailbox_syncpoints.size(); ++i) {
- // See: MockVideoCaptureControllerEventHandler::OnMailboxBufferReady()
- ASSERT_EQ(1u, release_syncpoint_vectors[i].size());
- ASSERT_EQ(mailbox_syncpoints[i], ~release_syncpoint_vectors[i][0]);
+ // A new release sync point must be inserted when the video frame is
+ // returned to the Browser process.
+ // See: MockVideoCaptureControllerEventHandler::OnMailboxBufferReady() and
+ // VideoCaptureController::ReturnBuffer()
+ ASSERT_NE(mailbox_syncpoints[i], release_syncpoints[i]);
}
Mock::VerifyAndClearExpectations(client_b_.get());
+
+#if defined(OS_ANDROID)
+ ImageTransportFactoryAndroid::TerminateForUnitTests();
+#else
+ ImageTransportFactory::Terminate();
+#endif
}
// Exercises the OnError() codepath of VideoCaptureController, and tests the
@@ -553,7 +577,7 @@ TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer =
device_->ReserveOutputBuffer(media::VideoFrame::I420, capture_resolution);
- ASSERT_TRUE(buffer);
+ ASSERT_TRUE(buffer.get());
device_->OnIncomingCapturedVideoFrame(
buffer,
@@ -592,7 +616,7 @@ TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
const gfx::Size dims(320, 240);
scoped_refptr<media::VideoCaptureDevice::Client::Buffer> buffer =
device_->ReserveOutputBuffer(media::VideoFrame::I420, dims);
- ASSERT_TRUE(buffer);
+ ASSERT_TRUE(buffer.get());
device_->OnError("Test error");
device_->OnIncomingCapturedVideoFrame(
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 a7fdf9d76e1..cc340e3dd80 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_host.cc
@@ -77,6 +77,7 @@ void VideoCaptureHost::OnBufferReady(
const VideoCaptureControllerID& controller_id,
int buffer_id,
const media::VideoCaptureFormat& frame_format,
+ const gfx::Rect& visible_rect,
base::TimeTicks timestamp) {
BrowserThread::PostTask(
BrowserThread::IO,
@@ -86,6 +87,7 @@ void VideoCaptureHost::OnBufferReady(
controller_id,
buffer_id,
frame_format,
+ visible_rect,
timestamp));
}
@@ -143,6 +145,7 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread(
const VideoCaptureControllerID& controller_id,
int buffer_id,
const media::VideoCaptureFormat& format,
+ const gfx::Rect& visible_rect,
base::TimeTicks timestamp) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -150,7 +153,7 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread(
return;
Send(new VideoCaptureMsg_BufferReady(
- controller_id.device_id, buffer_id, format, timestamp));
+ controller_id.device_id, buffer_id, format, visible_rect, timestamp));
}
void VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread(
@@ -199,6 +202,7 @@ bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(VideoCaptureHost, message)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Start, OnStartCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, OnPauseCapture)
+ IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Resume, OnResumeCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, OnStopCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady, OnReceiveEmptyBuffer)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceSupportedFormats,
@@ -218,9 +222,11 @@ void VideoCaptureHost::OnStartCapture(int device_id,
DVLOG(1) << "VideoCaptureHost::OnStartCapture:"
<< " session_id=" << session_id
<< ", device_id=" << device_id
- << ", format=" << params.requested_format.frame_size.ToString()
+ << ", format=" << params.requested_format.ToString()
<< "@" << params.requested_format.frame_rate
- << " (" << (params.allow_resolution_change ? "variable" : "constant")
+ << " (" << (params.resolution_change_policy ==
+ media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT ?
+ "variable" : "constant")
<< ")";
VideoCaptureControllerID controller_id(device_id);
if (entries_.find(controller_id) != entries_.end()) {
@@ -290,14 +296,39 @@ void VideoCaptureHost::OnStopCapture(int device_id) {
void VideoCaptureHost::OnPauseCapture(int device_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DVLOG(1) << "VideoCaptureHost::OnPauseCapture, device_id " << device_id;
- // Not used.
- Send(new VideoCaptureMsg_StateChanged(device_id, VIDEO_CAPTURE_STATE_ERROR));
+
+ VideoCaptureControllerID controller_id(device_id);
+ EntryMap::iterator it = entries_.find(controller_id);
+ if (it == entries_.end())
+ return;
+
+ if (it->second) {
+ media_stream_manager_->video_capture_manager()->PauseCaptureForClient(
+ it->second.get(), controller_id, this);
+ }
}
-void VideoCaptureHost::OnReceiveEmptyBuffer(
+void VideoCaptureHost::OnResumeCapture(
int device_id,
- int buffer_id,
- const std::vector<uint32>& sync_points) {
+ media::VideoCaptureSessionId session_id,
+ const media::VideoCaptureParams& params) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DVLOG(1) << "VideoCaptureHost::OnResumeCapture, device_id " << device_id;
+
+ VideoCaptureControllerID controller_id(device_id);
+ EntryMap::iterator it = entries_.find(controller_id);
+ if (it == entries_.end())
+ return;
+
+ if (it->second) {
+ media_stream_manager_->video_capture_manager()->ResumeCaptureForClient(
+ session_id, params, it->second.get(), controller_id, this);
+ }
+}
+
+void VideoCaptureHost::OnReceiveEmptyBuffer(int device_id,
+ int buffer_id,
+ uint32 sync_point) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
VideoCaptureControllerID controller_id(device_id);
@@ -305,7 +336,7 @@ void VideoCaptureHost::OnReceiveEmptyBuffer(
if (it != entries_.end()) {
const base::WeakPtr<VideoCaptureController>& controller = it->second;
if (controller)
- controller->ReturnBuffer(controller_id, this, buffer_id, sync_points);
+ controller->ReturnBuffer(controller_id, this, buffer_id, sync_point);
}
}
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 caecb1ae228..1fd9813760e 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_host.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_host.h
@@ -71,28 +71,29 @@ class CONTENT_EXPORT VideoCaptureHost
explicit VideoCaptureHost(MediaStreamManager* media_stream_manager);
// BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelClosing() override;
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// VideoCaptureControllerEventHandler implementation.
- virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE;
- virtual void OnBufferCreated(const VideoCaptureControllerID& id,
- base::SharedMemoryHandle handle,
- int length,
- int buffer_id) OVERRIDE;
- virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
- int buffer_id) OVERRIDE;
- virtual void OnBufferReady(const VideoCaptureControllerID& id,
- int buffer_id,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) OVERRIDE;
- virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
- int buffer_id,
- const gpu::MailboxHolder& mailbox_holder,
- const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) OVERRIDE;
- virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE;
+ void OnError(const VideoCaptureControllerID& id) override;
+ void OnBufferCreated(const VideoCaptureControllerID& id,
+ base::SharedMemoryHandle handle,
+ int length,
+ int buffer_id) override;
+ void OnBufferDestroyed(const VideoCaptureControllerID& id,
+ int buffer_id) override;
+ void OnBufferReady(const VideoCaptureControllerID& id,
+ int buffer_id,
+ const media::VideoCaptureFormat& format,
+ const gfx::Rect& visible_rect,
+ base::TimeTicks timestamp) override;
+ void OnMailboxBufferReady(const VideoCaptureControllerID& id,
+ int buffer_id,
+ const gpu::MailboxHolder& mailbox_holder,
+ const media::VideoCaptureFormat& format,
+ base::TimeTicks timestamp) override;
+ void OnEnded(const VideoCaptureControllerID& id) override;
private:
friend class BrowserThread;
@@ -100,7 +101,7 @@ class CONTENT_EXPORT VideoCaptureHost
friend class MockVideoCaptureHost;
friend class VideoCaptureHostTest;
- virtual ~VideoCaptureHost();
+ ~VideoCaptureHost() override;
// IPC message: Start capture on the VideoCaptureDevice referenced by
// |session_id|. |device_id| is an id created by VideoCaptureMessageFilter
@@ -122,11 +123,13 @@ class CONTENT_EXPORT VideoCaptureHost
// IPC message: Pause capture on device referenced by |device_id|.
void OnPauseCapture(int device_id);
+ void OnResumeCapture(int device_id,
+ media::VideoCaptureSessionId session_id,
+ const media::VideoCaptureParams& params);
+
// IPC message: Receive an empty buffer from renderer. Send it to device
// referenced by |device_id|.
- void OnReceiveEmptyBuffer(int device_id,
- int buffer_id,
- const std::vector<uint32>& sync_points);
+ void OnReceiveEmptyBuffer(int device_id, int buffer_id, uint32 sync_point);
// IPC message: Get supported formats referenced by |capture_session_id|.
// |device_id| is needed for message back-routing purposes.
@@ -157,6 +160,7 @@ class CONTENT_EXPORT VideoCaptureHost
const VideoCaptureControllerID& controller_id,
int buffer_id,
const media::VideoCaptureFormat& format,
+ const gfx::Rect& visible_rect,
base::TimeTicks timestamp);
// Sends a filled texture mailbox buffer to the VideoCaptureMessageFilter.
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 6088081bf7b..6787a385e6e 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
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
@@ -34,6 +34,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_CHROMEOS)
+#include "chromeos/audio/cras_audio_handler.h"
+#endif
+
using ::testing::_;
using ::testing::AtLeast;
using ::testing::AnyNumber;
@@ -86,23 +90,23 @@ class MockMediaStreamRequester : public MediaStreamRequester {
// MediaStreamRequester implementation.
MOCK_METHOD5(StreamGenerated,
- void(int render_view_id,
+ void(int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfoArray& audio_devices,
const StreamDeviceInfoArray& video_devices));
MOCK_METHOD3(StreamGenerationFailed,
- void(int render_view_id,
+ void(int render_frame_id,
int page_request_id,
content::MediaStreamRequestResult result));
- MOCK_METHOD3(DeviceStopped, void(int render_view_id,
+ MOCK_METHOD3(DeviceStopped, void(int render_frame_id,
const std::string& label,
const StreamDeviceInfo& device));
- MOCK_METHOD4(DevicesEnumerated, void(int render_view_id,
+ MOCK_METHOD4(DevicesEnumerated, void(int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfoArray& devices));
- MOCK_METHOD4(DeviceOpened, void(int render_view_id,
+ MOCK_METHOD4(DeviceOpened, void(int render_frame_id,
int page_request_id,
const std::string& label,
const StreamDeviceInfo& device_info));
@@ -126,10 +130,11 @@ class MockVideoCaptureHost : public VideoCaptureHost {
int buffer_id));
MOCK_METHOD2(OnBufferFreed,
void(int device_id, int buffer_id));
- MOCK_METHOD4(OnBufferFilled,
+ MOCK_METHOD5(OnBufferFilled,
void(int device_id,
int buffer_id,
const media::VideoCaptureFormat& format,
+ const gfx::Rect& visible_rect,
base::TimeTicks timestamp));
MOCK_METHOD5(OnMailboxBufferFilled,
void(int device_id,
@@ -152,7 +157,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
void ReturnReceivedDibs(int device_id) {
int handle = GetReceivedDib();
while (handle) {
- this->OnReceiveEmptyBuffer(device_id, handle, std::vector<uint32>());
+ this->OnReceiveEmptyBuffer(device_id, handle, 0);
handle = GetReceivedDib();
}
}
@@ -177,7 +182,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
// This method is used to dispatch IPC messages to the renderer. We intercept
// these messages here and dispatch to our mock methods to verify the
// conversation between this object and the renderer.
- virtual bool Send(IPC::Message* message) OVERRIDE {
+ virtual bool Send(IPC::Message* message) override {
CHECK(message);
// In this method we dispatch the messages to the according handlers as if
@@ -222,6 +227,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
void OnBufferFilledDispatch(int device_id,
int buffer_id,
const media::VideoCaptureFormat& frame_format,
+ const gfx::Rect& visible_rect,
base::TimeTicks timestamp) {
base::SharedMemory* dib = filled_dib_[buffer_id];
ASSERT_TRUE(dib != NULL);
@@ -238,10 +244,9 @@ class MockVideoCaptureHost : public VideoCaptureHost {
dumper_.NewVideoFrame(dib->memory());
}
- OnBufferFilled(device_id, buffer_id, frame_format, timestamp);
+ OnBufferFilled(device_id, buffer_id, frame_format, visible_rect, timestamp);
if (return_buffers_) {
- VideoCaptureHost::OnReceiveEmptyBuffer(
- device_id, buffer_id, std::vector<uint32>());
+ VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0);
}
}
@@ -253,8 +258,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
OnMailboxBufferFilled(
device_id, buffer_id, mailbox_holder, format, timestamp);
if (return_buffers_) {
- VideoCaptureHost::OnReceiveEmptyBuffer(
- device_id, buffer_id, std::vector<uint32>());
+ VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0);
}
}
@@ -283,8 +287,13 @@ class VideoCaptureHostTest : public testing::Test {
message_loop_(base::MessageLoopProxy::current()),
opened_session_id_(kInvalidMediaCaptureSessionId) {}
- virtual void SetUp() OVERRIDE {
+ virtual void SetUp() override {
SetBrowserClientForTesting(&browser_client_);
+
+#if defined(OS_CHROMEOS)
+ chromeos::CrasAudioHandler::InitializeForTesting();
+#endif
+
// Create our own MediaStreamManager.
audio_manager_.reset(media::AudioManager::CreateForTesting());
#ifndef TEST_REAL_CAPTURE_DEVICE
@@ -301,7 +310,7 @@ class VideoCaptureHostTest : public testing::Test {
OpenSession();
}
- virtual void TearDown() OVERRIDE {
+ virtual void TearDown() override {
// Verifies and removes the expectations on host_ and
// returns true iff successful.
Mock::VerifyAndClearExpectations(host_.get());
@@ -315,11 +324,15 @@ class VideoCaptureHostTest : public testing::Test {
// Release the reference to the mock object. The object will be destructed
// on the current message loop.
host_ = NULL;
+
+#if defined(OS_CHROMEOS)
+ chromeos::CrasAudioHandler::Shutdown();
+#endif
}
void OpenSession() {
const int render_process_id = 1;
- const int render_view_id = 1;
+ const int render_frame_id = 1;
const int page_request_id = 1;
const GURL security_origin("http://test.com");
@@ -332,13 +345,12 @@ class VideoCaptureHostTest : public testing::Test {
std::string label = media_stream_manager_->EnumerateDevices(
&stream_requester_,
render_process_id,
- render_view_id,
+ render_frame_id,
browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
page_request_id,
MEDIA_DEVICE_VIDEO_CAPTURE,
- security_origin,
- true);
- EXPECT_CALL(stream_requester_, DevicesEnumerated(render_view_id,
+ security_origin);
+ EXPECT_CALL(stream_requester_, DevicesEnumerated(render_frame_id,
page_request_id,
label,
_))
@@ -359,13 +371,13 @@ class VideoCaptureHostTest : public testing::Test {
media_stream_manager_->OpenDevice(
&stream_requester_,
render_process_id,
- render_view_id,
+ render_frame_id,
browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
page_request_id,
devices[0].device.id,
MEDIA_DEVICE_VIDEO_CAPTURE,
security_origin);
- EXPECT_CALL(stream_requester_, DeviceOpened(render_view_id,
+ EXPECT_CALL(stream_requester_, DeviceOpened(render_frame_id,
page_request_id,
_,
_))
@@ -390,13 +402,14 @@ class VideoCaptureHostTest : public testing::Test {
protected:
void StartCapture() {
- EXPECT_CALL(*host_, OnNewBufferCreated(kDeviceId, _, _, _))
- .Times(AnyNumber()).WillRepeatedly(Return());
+ EXPECT_CALL(*host_.get(), OnNewBufferCreated(kDeviceId, _, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(Return());
base::RunLoop run_loop;
- EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _))
- .Times(AnyNumber()).WillOnce(ExitMessageLoop(
- message_loop_, run_loop.QuitClosure()));
+ EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _))
+ .Times(AnyNumber())
+ .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
media::VideoCaptureParams params;
params.requested_format = media::VideoCaptureFormat(
@@ -410,7 +423,8 @@ class VideoCaptureHostTest : public testing::Test {
// asynchronous start operations to complete.
InSequence s;
base::RunLoop run_loop;
- EXPECT_CALL(*host_, OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STOPPED));
+ EXPECT_CALL(*host_.get(),
+ OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STOPPED));
media::VideoCaptureParams params;
params.requested_format = media::VideoCaptureFormat(
gfx::Size(352, 288), 30, media::PIXEL_FORMAT_I420);
@@ -426,7 +440,7 @@ class VideoCaptureHostTest : public testing::Test {
.Times(AnyNumber()).WillRepeatedly(Return());
base::RunLoop run_loop;
- EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _))
+ EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _, _))
.Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
@@ -441,7 +455,8 @@ class VideoCaptureHostTest : public testing::Test {
void StopCapture() {
base::RunLoop run_loop;
- EXPECT_CALL(*host_, OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STOPPED))
+ EXPECT_CALL(*host_.get(),
+ OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STOPPED))
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
host_->OnStopCapture(kDeviceId);
@@ -457,9 +472,9 @@ class VideoCaptureHostTest : public testing::Test {
void NotifyPacketReady() {
base::RunLoop run_loop;
- EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _))
- .Times(AnyNumber()).WillOnce(ExitMessageLoop(
- message_loop_, run_loop.QuitClosure()))
+ EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _))
+ .Times(AnyNumber())
+ .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()))
.RetiresOnSaturation();
run_loop.Run();
}
@@ -470,8 +485,8 @@ class VideoCaptureHostTest : public testing::Test {
void SimulateError() {
// Expect a change state to error state sent through IPC.
- EXPECT_CALL(*host_, OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_ERROR))
- .Times(1);
+ EXPECT_CALL(*host_.get(),
+ OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_ERROR)).Times(1);
VideoCaptureControllerID id(kDeviceId);
host_->OnError(id);
// Wait for the error callback.
@@ -499,8 +514,8 @@ TEST_F(VideoCaptureHostTest, CloseSessionWithoutStopping) {
// When the session is closed via the stream without stopping capture, the
// ENDED event is sent.
- EXPECT_CALL(*host_, OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_ENDED))
- .Times(1);
+ EXPECT_CALL(*host_.get(),
+ OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_ENDED)).Times(1);
CloseSession();
base::RunLoop().RunUntilIdle();
}
@@ -524,8 +539,8 @@ TEST_F(VideoCaptureHostTest, StartCaptureErrorStop) {
}
TEST_F(VideoCaptureHostTest, StartCaptureError) {
- EXPECT_CALL(*host_, OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STOPPED))
- .Times(0);
+ EXPECT_CALL(*host_.get(),
+ OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STOPPED)).Times(0);
StartCapture();
NotifyPacketReady();
SimulateError();
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 3e9e0bfa864..617a8696dee 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.cc
@@ -14,6 +14,7 @@
#include "base/task_runner_util.h"
#include "base/threading/sequenced_worker_pool.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"
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
#include "content/public/browser/browser_thread.h"
@@ -70,6 +71,29 @@ void ConsolidateCaptureFormats(media::VideoCaptureFormats* formats) {
}
}
+// The maximum number of buffers in the capture pipeline. See
+// VideoCaptureController ctor comments for more details.
+const int kMaxNumberOfBuffers = 3;
+const int kMaxNumberOfBuffersForTabCapture = 5;
+
+// Used for logging capture events.
+// Elements in this enum should not be deleted or rearranged; the only
+// permitted operation is to add new elements before NUM_VIDEO_CAPTURE_EVENT.
+enum VideoCaptureEvent {
+ VIDEO_CAPTURE_START_CAPTURE = 0,
+ VIDEO_CAPTURE_STOP_CAPTURE_OK = 1,
+ VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR = 2,
+ VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DEVICE = 3,
+ VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DESKTOP_OR_TAB = 4,
+ NUM_VIDEO_CAPTURE_EVENT
+};
+
+void LogVideoCaptureEvent(VideoCaptureEvent event) {
+ UMA_HISTOGRAM_ENUMERATION("Media.VideoCaptureManager.Event",
+ event,
+ NUM_VIDEO_CAPTURE_EVENT);
+}
+
} // namespace
namespace content {
@@ -84,15 +108,6 @@ VideoCaptureManager::DeviceEntry::DeviceEntry(
VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
-VideoCaptureManager::DeviceInfo::DeviceInfo() {}
-
-VideoCaptureManager::DeviceInfo::DeviceInfo(
- const media::VideoCaptureDevice::Name& name,
- const media::VideoCaptureFormats& supported_formats)
- : name(name),
- supported_formats(supported_formats) {}
-
-VideoCaptureManager::DeviceInfo::~DeviceInfo() {}
VideoCaptureManager::VideoCaptureManager(
scoped_ptr<media::VideoCaptureDeviceFactory> factory)
@@ -215,7 +230,8 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
// We look up the device id from the renderer in our local enumeration
// since the renderer does not have all the information that might be
// held in the browser-side VideoCaptureDevice::Name structure.
- DeviceInfo* found = FindDeviceInfoById(entry->id, devices_info_cache_);
+ media::VideoCaptureDeviceInfo* found =
+ FindDeviceInfoById(entry->id, devices_info_cache_);
if (found) {
video_capture_device =
video_capture_device_factory_->Create(found->name);
@@ -242,6 +258,8 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
notification_window_ids_.end()) {
static_cast<DesktopCaptureDevice*>(video_capture_device.get())
->SetNotificationWindowId(notification_window_ids_[session_id]);
+ VLOG(2) << "Screen capture notification window passed for session "
+ << session_id;
}
}
#endif // defined(ENABLE_SCREEN_CAPTURE)
@@ -282,8 +300,10 @@ void VideoCaptureManager::StartCaptureForClient(
DCHECK(entry->video_capture_controller);
+ LogVideoCaptureEvent(VIDEO_CAPTURE_START_CAPTURE);
+
// First client starts the device.
- if (entry->video_capture_controller->GetClientCount() == 0) {
+ if (entry->video_capture_controller->GetActiveClientCount() == 0) {
DVLOG(1) << "VideoCaptureManager starting device (type = "
<< entry->stream_type << ", id = " << entry->id << ")";
@@ -317,7 +337,18 @@ void VideoCaptureManager::StopCaptureForClient(
NOTREACHED();
return;
}
- if (aborted_due_to_error) {
+ if (!aborted_due_to_error) {
+ if (controller->has_received_frames()) {
+ LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_OK);
+ } else if (entry->stream_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
+ LogVideoCaptureEvent(
+ VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DEVICE);
+ } else {
+ LogVideoCaptureEvent(
+ VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DESKTOP_OR_TAB);
+ }
+ } else {
+ LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR);
SessionMap::iterator it;
for (it = sessions_.begin(); it != sessions_.end(); ++it) {
if (it->second.type == entry->stream_type &&
@@ -338,6 +369,71 @@ void VideoCaptureManager::StopCaptureForClient(
DestroyDeviceEntryIfNoClients(entry);
}
+void VideoCaptureManager::PauseCaptureForClient(
+ VideoCaptureController* controller,
+ VideoCaptureControllerID client_id,
+ VideoCaptureControllerEventHandler* client_handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(controller);
+ DCHECK(client_handler);
+ DeviceEntry* entry = GetDeviceEntryForController(controller);
+ if (!entry) {
+ NOTREACHED();
+ return;
+ }
+
+ // We only pause the MEDIA_DEVICE_VIDEO_CAPTURE entry to release camera to
+ // system.
+ if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
+ return;
+
+ controller->PauseOrResumeClient(client_id, client_handler, true);
+ if (controller->GetActiveClientCount() != 0)
+ return;
+
+ // There is no more client, release the camera.
+ device_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
+ base::Unretained(entry)));
+}
+
+void VideoCaptureManager::ResumeCaptureForClient(
+ media::VideoCaptureSessionId session_id,
+ const media::VideoCaptureParams& params,
+ VideoCaptureController* controller,
+ VideoCaptureControllerID client_id,
+ VideoCaptureControllerEventHandler* client_handler) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(controller);
+ DCHECK(client_handler);
+
+ DeviceEntry* entry = GetDeviceEntryForController(controller);
+ if (!entry) {
+ NOTREACHED();
+ return;
+ }
+
+ // We only pause/resume the MEDIA_DEVICE_VIDEO_CAPTURE entry.
+ if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE)
+ return;
+
+ controller->PauseOrResumeClient(client_id, client_handler, false);
+ if (controller->GetActiveClientCount() != 1)
+ return;
+
+ // This is first active client, allocate the camera.
+ device_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &VideoCaptureManager::DoStartDeviceOnDeviceThread,
+ this,
+ session_id,
+ entry,
+ params,
+ base::Passed(entry->video_capture_controller->NewDeviceClient())));
+}
+
bool VideoCaptureManager::GetDeviceSupportedFormats(
media::VideoCaptureSessionId capture_session_id,
media::VideoCaptureFormats* supported_formats) {
@@ -350,7 +446,7 @@ bool VideoCaptureManager::GetDeviceSupportedFormats(
DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name;
// Return all available formats of the device, regardless its started state.
- DeviceInfo* existing_device =
+ media::VideoCaptureDeviceInfo* existing_device =
FindDeviceInfoById(it->second.id, devices_info_cache_);
if (existing_device)
*supported_formats = existing_device->supported_formats;
@@ -383,8 +479,11 @@ void VideoCaptureManager::SetDesktopCaptureWindowId(
media::VideoCaptureSessionId session_id,
gfx::NativeViewId window_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ VLOG(2) << "SetDesktopCaptureWindowId called for session " << session_id;
+
SessionMap::iterator session_it = sessions_.find(session_id);
if (session_it == sessions_.end()) {
+ VLOG(2) << "Session not found, will save the notification window.";
device_task_runner_->PostTask(
FROM_HERE,
base::Bind(
@@ -397,13 +496,16 @@ void VideoCaptureManager::SetDesktopCaptureWindowId(
DeviceEntry* const existing_device =
GetDeviceEntryForMediaStreamDevice(session_it->second);
- if (!existing_device)
+ if (!existing_device) {
+ VLOG(2) << "Failed to find an existing device.";
return;
+ }
DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type);
DesktopMediaID id = DesktopMediaID::Parse(existing_device->id);
if (id.type == DesktopMediaID::TYPE_NONE ||
id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
+ VLOG(2) << "Video capture device type mismatch.";
return;
}
@@ -449,7 +551,7 @@ void VideoCaptureManager::OnClosed(
void VideoCaptureManager::OnDevicesInfoEnumerated(
MediaStreamType stream_type,
base::ElapsedTimer* timer,
- const DeviceInfos& new_devices_info_cache) {
+ const media::VideoCaptureDeviceInfos& new_devices_info_cache) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
UMA_HISTOGRAM_TIMES(
"Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime",
@@ -460,13 +562,15 @@ void VideoCaptureManager::OnDevicesInfoEnumerated(
}
devices_info_cache_ = new_devices_info_cache;
+ MediaInternals::GetInstance()->UpdateVideoCaptureDeviceCapabilities(
+ devices_info_cache_);
+
// Walk the |devices_info_cache_| and transform from VCD::Name to
// StreamDeviceInfo for return purposes.
StreamDeviceInfoArray devices;
- for (DeviceInfos::const_iterator it = devices_info_cache_.begin();
- it != devices_info_cache_.end(); ++it) {
+ for (const auto& it : devices_info_cache_) {
devices.push_back(StreamDeviceInfo(
- stream_type, it->name.GetNameAndModel(), it->name.id()));
+ stream_type, it.name.GetNameAndModel(), it.name.id()));
}
listener_->DevicesEnumerated(stream_type, devices);
}
@@ -476,23 +580,21 @@ bool VideoCaptureManager::IsOnDeviceThread() const {
}
void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread(
- base::Callback<void(const DeviceInfos&)> on_devices_enumerated_callback,
+ base::Callback<void(const media::VideoCaptureDeviceInfos&)>
+ on_devices_enumerated_callback,
MediaStreamType stream_type,
- const DeviceInfos& old_device_info_cache,
+ const media::VideoCaptureDeviceInfos& old_device_info_cache,
scoped_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
// keep there the truly new devices.
- DeviceInfos new_devices_info_cache;
- for (DeviceInfos::const_iterator it_device_info =
- old_device_info_cache.begin();
- it_device_info != old_device_info_cache.end(); ++it_device_info) {
+ media::VideoCaptureDeviceInfos new_devices_info_cache;
+ for (const auto& device_info : old_device_info_cache) {
for (media::VideoCaptureDevice::Names::iterator it =
- names_snapshot->begin();
- it != names_snapshot->end(); ++it) {
- if (it_device_info->name.id() == it->id()) {
- new_devices_info_cache.push_back(*it_device_info);
+ names_snapshot->begin(); it != names_snapshot->end(); ++it) {
+ if (device_info.name.id() == it->id()) {
+ new_devices_info_cache.push_back(device_info);
names_snapshot->erase(it);
break;
}
@@ -500,13 +602,10 @@ void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread(
}
// Get the supported capture formats for the new devices in |names_snapshot|.
- for (media::VideoCaptureDevice::Names::const_iterator it =
- names_snapshot->begin();
- it != names_snapshot->end(); ++it) {
- media::VideoCaptureFormats supported_formats;
- DeviceInfo device_info(*it, media::VideoCaptureFormats());
+ for (const auto& it : *names_snapshot) {
+ media::VideoCaptureDeviceInfo device_info(it, media::VideoCaptureFormats());
video_capture_device_factory_->GetDeviceSupportedFormats(
- *it, &(device_info.supported_formats));
+ it, &(device_info.supported_formats));
ConsolidateCaptureFormats(&device_info.supported_formats);
new_devices_info_cache.push_back(device_info);
}
@@ -582,8 +681,10 @@ VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
return existing_device;
}
+ const int max_buffers = device_info.type == MEDIA_TAB_VIDEO_CAPTURE ?
+ kMaxNumberOfBuffersForTabCapture : kMaxNumberOfBuffers;
scoped_ptr<VideoCaptureController> video_capture_controller(
- new VideoCaptureController());
+ new VideoCaptureController(max_buffers));
DeviceEntry* new_device = new DeviceEntry(device_info.type,
device_info.id,
video_capture_controller.Pass());
@@ -591,13 +692,12 @@ VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
return new_device;
}
-VideoCaptureManager::DeviceInfo* VideoCaptureManager::FindDeviceInfoById(
+media::VideoCaptureDeviceInfo* VideoCaptureManager::FindDeviceInfoById(
const std::string& id,
- DeviceInfos& device_vector) {
- for (DeviceInfos::iterator it = device_vector.begin();
- it != device_vector.end(); ++it) {
- if (it->name.id() == id)
- return &(*it);
+ media::VideoCaptureDeviceInfos& device_vector) {
+ for (auto& it : device_vector) {
+ if (it.name.id() == id)
+ return &(it);
}
return NULL;
}
@@ -611,6 +711,7 @@ void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread(
DesktopCaptureDevice* device =
static_cast<DesktopCaptureDevice*>(entry->video_capture_device.get());
device->SetNotificationWindowId(window_id);
+ VLOG(2) << "Screen capture notification window passed on device thread.";
#endif
}
@@ -621,6 +722,8 @@ void VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread(
DCHECK(notification_window_ids_.find(session_id) ==
notification_window_ids_.end());
notification_window_ids_[session_id] = window_id;
+ VLOG(2) << "Screen capture notification window saved for session "
+ << session_id << " on device thread.";
}
} // 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 7f69d56a904..544fb86472f 100644
--- a/chromium/content/browser/renderer_host/media/video_capture_manager.h
+++ b/chromium/content/browser/renderer_host/media/video_capture_manager.h
@@ -27,6 +27,7 @@
#include "content/common/media/media_stream_options.h"
#include "media/video/capture/video_capture_device.h"
#include "media/video/capture/video_capture_device_factory.h"
+#include "media/video/capture/video_capture_device_info.h"
#include "media/video/capture/video_capture_types.h"
namespace content {
@@ -44,17 +45,17 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
scoped_ptr<media::VideoCaptureDeviceFactory> factory);
// Implements MediaStreamProvider.
- virtual void Register(MediaStreamProviderListener* listener,
- const scoped_refptr<base::SingleThreadTaskRunner>&
- device_task_runner) OVERRIDE;
+ void Register(MediaStreamProviderListener* listener,
+ const scoped_refptr<base::SingleThreadTaskRunner>&
+ device_task_runner) override;
- virtual void Unregister() OVERRIDE;
+ void Unregister() override;
- virtual void EnumerateDevices(MediaStreamType stream_type) OVERRIDE;
+ void EnumerateDevices(MediaStreamType stream_type) override;
- virtual int Open(const StreamDeviceInfo& device) OVERRIDE;
+ int Open(const StreamDeviceInfo& device) override;
- virtual void Close(int capture_session_id) OVERRIDE;
+ void Close(int capture_session_id) override;
// Called by VideoCaptureHost to locate a capture device for |capture_params|,
// adding the Host as a client of the device's controller if successful. The
@@ -84,6 +85,28 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
VideoCaptureControllerEventHandler* client_handler,
bool aborted_due_to_error);
+ // Called by VideoCaptureHost to pause to update video buffer specified by
+ // |client_id| and |client_handler|. If all clients of |controller| are
+ // paused, the corresponding device will be closed.
+ void PauseCaptureForClient(
+ VideoCaptureController* controller,
+ VideoCaptureControllerID client_id,
+ VideoCaptureControllerEventHandler* client_handler);
+
+ // Called by VideoCaptureHost to resume to update video buffer specified by
+ // |client_id| and |client_handler|. The |session_id| and |params| should be
+ // same as those used in StartCaptureForClient().
+ // If this is first active client of |controller|, device will be allocated
+ // and it will take a little time to resume.
+ // Allocating device could failed if other app holds the camera, the error
+ // will be notified through VideoCaptureControllerEventHandler::OnError().
+ void ResumeCaptureForClient(
+ media::VideoCaptureSessionId session_id,
+ const media::VideoCaptureParams& params,
+ VideoCaptureController* controller,
+ VideoCaptureControllerID client_id,
+ VideoCaptureControllerEventHandler* client_handler);
+
// 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
@@ -108,23 +131,17 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
return video_capture_device_factory_.get();
}
+#if defined(OS_WIN)
+ void set_device_task_runner(
+ const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
+ device_task_runner_ = device_task_runner;
+ }
+#endif
+
private:
- virtual ~VideoCaptureManager();
+ ~VideoCaptureManager() override;
struct DeviceEntry;
- // This data structure is a convenient wrap of a devices' name and associated
- // video capture supported formats.
- struct DeviceInfo {
- DeviceInfo();
- DeviceInfo(const media::VideoCaptureDevice::Name& name,
- const media::VideoCaptureFormats& supported_formats);
- ~DeviceInfo();
-
- media::VideoCaptureDevice::Name name;
- media::VideoCaptureFormats supported_formats;
- };
- typedef std::vector<DeviceInfo> DeviceInfos;
-
// Checks to see if |entry| has no clients left on its controller. If so,
// remove it from the list of devices, and delete it asynchronously. |entry|
// may be freed by this function.
@@ -135,9 +152,10 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
media::VideoCaptureSessionId capture_session_id);
void OnClosed(MediaStreamType type,
media::VideoCaptureSessionId capture_session_id);
- void OnDevicesInfoEnumerated(MediaStreamType stream_type,
- base::ElapsedTimer* timer,
- const DeviceInfos& new_devices_info_cache);
+ void OnDevicesInfoEnumerated(
+ MediaStreamType stream_type,
+ base::ElapsedTimer* timer,
+ const media::VideoCaptureDeviceInfos& new_devices_info_cache);
// Finds a DeviceEntry by its device ID and type, if it is already opened.
DeviceEntry* GetDeviceEntryForMediaStreamDevice(
@@ -158,9 +176,10 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// devices in the system |names_snapshot|. Retrieves the supported formats of
// the new devices and sends the new cache to OnDevicesInfoEnumerated().
void ConsolidateDevicesInfoOnDeviceThread(
- base::Callback<void(const DeviceInfos&)> on_devices_enumerated_callback,
+ base::Callback<void(const media::VideoCaptureDeviceInfos&)>
+ on_devices_enumerated_callback,
MediaStreamType stream_type,
- const DeviceInfos& old_device_info_cache,
+ const media::VideoCaptureDeviceInfos& old_device_info_cache,
scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot);
// Creates and Starts a new VideoCaptureDevice, storing the result in
@@ -176,8 +195,9 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// |entry->video_capture_device|.
void DoStopDeviceOnDeviceThread(DeviceEntry* entry);
- DeviceInfo* FindDeviceInfoById(const std::string& id,
- DeviceInfos& device_vector);
+ media::VideoCaptureDeviceInfo* FindDeviceInfoById(
+ const std::string& id,
+ media::VideoCaptureDeviceInfos& device_vector);
void SetDesktopCaptureWindowIdOnDeviceThread(DeviceEntry* entry,
gfx::NativeViewId window_id);
@@ -238,7 +258,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// this list in OnDevicesInfoEnumerated(). GetDeviceSupportedFormats() will
// use this list if the device is not started, otherwise it will retrieve the
// active device capture format from the VideoCaptureController associated.
- DeviceInfos devices_info_cache_;
+ media::VideoCaptureDeviceInfos devices_info_cache_;
// Accessed on the device thread only.
std::map<media::VideoCaptureSessionId, gfx::NativeViewId>
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 8599924b052..e42601ae44b 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
@@ -48,19 +48,20 @@ class MockFrameObserver : public VideoCaptureControllerEventHandler {
virtual void OnBufferCreated(const VideoCaptureControllerID& id,
base::SharedMemoryHandle handle,
- int length, int buffer_id) OVERRIDE {}
+ int length, int buffer_id) override {}
virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
- int buffer_id) OVERRIDE {}
+ int buffer_id) override {}
virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) OVERRIDE {}
+ const gfx::Rect& visible_rect,
+ base::TimeTicks timestamp) override {}
virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
const media::VideoCaptureFormat& format,
- base::TimeTicks timestamp) OVERRIDE {}
- virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {}
+ base::TimeTicks timestamp) override {}
+ virtual void OnEnded(const VideoCaptureControllerID& id) override {}
void OnGotControllerCallback(VideoCaptureControllerID) {}
};
@@ -69,10 +70,10 @@ class MockFrameObserver : public VideoCaptureControllerEventHandler {
class VideoCaptureManagerTest : public testing::Test {
public:
VideoCaptureManagerTest() : next_client_id_(1) {}
- virtual ~VideoCaptureManagerTest() {}
+ ~VideoCaptureManagerTest() override {}
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
listener_.reset(new MockMediaStreamProviderListener());
message_loop_.reset(new base::MessageLoopForIO);
io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO,
@@ -88,7 +89,7 @@ class VideoCaptureManagerTest : public testing::Test {
frame_observer_.reset(new MockFrameObserver());
}
- virtual void TearDown() OVERRIDE {}
+ void TearDown() override {}
void OnGotControllerCallback(
VideoCaptureControllerID id,
diff --git a/chromium/content/browser/renderer_host/media/webrtc_identity_service_host.h b/chromium/content/browser/renderer_host/media/webrtc_identity_service_host.h
index 7bc8233b9cd..1cc1f6bcf18 100644
--- a/chromium/content/browser/renderer_host/media/webrtc_identity_service_host.h
+++ b/chromium/content/browser/renderer_host/media/webrtc_identity_service_host.h
@@ -30,10 +30,10 @@ class CONTENT_EXPORT WebRTCIdentityServiceHost : public BrowserMessageFilter {
scoped_refptr<WebRTCIdentityStore> identity_store);
protected:
- virtual ~WebRTCIdentityServiceHost();
+ ~WebRTCIdentityServiceHost() override;
// content::BrowserMessageFilter override.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
// |sequence_number| is the same as in the OnRequestIdentity call.
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 a785a22b993..4a9c5d2db38 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
@@ -29,11 +29,10 @@ class MockWebRTCIdentityStore : public WebRTCIdentityStore {
public:
MockWebRTCIdentityStore() : WebRTCIdentityStore(base::FilePath(), NULL) {}
- virtual base::Closure RequestIdentity(
- const GURL& origin,
- const std::string& identity_name,
- const std::string& common_name,
- const CompletionCallback& callback) OVERRIDE {
+ base::Closure RequestIdentity(const GURL& origin,
+ const std::string& identity_name,
+ const std::string& common_name,
+ const CompletionCallback& callback) override {
EXPECT_TRUE(callback_.is_null());
callback_ = callback;
@@ -51,7 +50,7 @@ class MockWebRTCIdentityStore : public WebRTCIdentityStore {
}
private:
- virtual ~MockWebRTCIdentityStore() {}
+ ~MockWebRTCIdentityStore() override {}
void OnCancel() { callback_.Reset(); }
@@ -67,13 +66,13 @@ class WebRTCIdentityServiceHostForTest : public WebRTCIdentityServiceHost {
policy->Add(FAKE_RENDERER_ID);
}
- virtual bool Send(IPC::Message* message) OVERRIDE {
+ bool Send(IPC::Message* message) override {
messages_.push_back(*message);
delete message;
return true;
}
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ bool OnMessageReceived(const IPC::Message& message) override {
return WebRTCIdentityServiceHost::OnMessageReceived(message);
}
@@ -84,7 +83,7 @@ class WebRTCIdentityServiceHostForTest : public WebRTCIdentityServiceHost {
void ClearMessages() { messages_.clear(); }
private:
- virtual ~WebRTCIdentityServiceHostForTest() {
+ ~WebRTCIdentityServiceHostForTest() override {
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
policy->Remove(FAKE_RENDERER_ID);
diff --git a/chromium/content/browser/renderer_host/memory_benchmark_message_filter.h b/chromium/content/browser/renderer_host/memory_benchmark_message_filter.h
index 7255ab915e6..d30e3a78fb1 100644
--- a/chromium/content/browser/renderer_host/memory_benchmark_message_filter.h
+++ b/chromium/content/browser/renderer_host/memory_benchmark_message_filter.h
@@ -15,9 +15,10 @@ class MemoryBenchmarkMessageFilter : public BrowserMessageFilter {
public:
MemoryBenchmarkMessageFilter();
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
+
private:
- virtual ~MemoryBenchmarkMessageFilter();
+ ~MemoryBenchmarkMessageFilter() override;
void OnHeapProfilerDump(const std::string& reason);
diff --git a/chromium/content/browser/renderer_host/native_web_keyboard_event.cc b/chromium/content/browser/renderer_host/native_web_keyboard_event.cc
index 646b358ac8d..502b30d9981 100644
--- a/chromium/content/browser/renderer_host/native_web_keyboard_event.cc
+++ b/chromium/content/browser/renderer_host/native_web_keyboard_event.cc
@@ -17,7 +17,7 @@ int GetModifiersFromNativeWebKeyboardEvent(
modifiers |= ui::EF_CONTROL_DOWN;
if (event.modifiers & NativeWebKeyboardEvent::AltKey)
modifiers |= ui::EF_ALT_DOWN;
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
if (event.modifiers & NativeWebKeyboardEvent::MetaKey)
modifiers |= ui::EF_COMMAND_DOWN;
#endif
diff --git a/chromium/content/browser/renderer_host/overscroll_controller.cc b/chromium/content/browser/renderer_host/overscroll_controller.cc
index 3a6e7576563..86dc692fea2 100644
--- a/chromium/content/browser/renderer_host/overscroll_controller.cc
+++ b/chromium/content/browser/renderer_host/overscroll_controller.cc
@@ -15,7 +15,7 @@ using blink::WebInputEvent;
namespace {
bool IsScrollEndEffectEnabled() {
- return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kScrollEndEffect) == "1";
}
@@ -212,20 +212,18 @@ bool OverscrollController::ProcessEventForOverscroll(
static_cast<const blink::WebMouseWheelEvent&>(event);
if (!wheel.hasPreciseScrollingDeltas)
break;
-
- ProcessOverscroll(wheel.deltaX * wheel.accelerationRatioX,
- wheel.deltaY * wheel.accelerationRatioY,
- wheel.type);
- event_processed = true;
+ event_processed =
+ ProcessOverscroll(wheel.deltaX * wheel.accelerationRatioX,
+ wheel.deltaY * wheel.accelerationRatioY,
+ wheel.type);
break;
}
case blink::WebInputEvent::GestureScrollUpdate: {
const blink::WebGestureEvent& gesture =
static_cast<const blink::WebGestureEvent&>(event);
- ProcessOverscroll(gesture.data.scrollUpdate.deltaX,
- gesture.data.scrollUpdate.deltaY,
- gesture.type);
- event_processed = true;
+ event_processed = ProcessOverscroll(gesture.data.scrollUpdate.deltaX,
+ gesture.data.scrollUpdate.deltaY,
+ gesture.type);
break;
}
case blink::WebInputEvent::GestureFlingStart: {
@@ -263,7 +261,7 @@ bool OverscrollController::ProcessEventForOverscroll(
return event_processed;
}
-void OverscrollController::ProcessOverscroll(float delta_x,
+bool OverscrollController::ProcessOverscroll(float delta_x,
float delta_y,
blink::WebInputEvent::Type type) {
if (scroll_state_ != STATE_CONTENT_SCROLLING)
@@ -279,7 +277,7 @@ void OverscrollController::ProcessOverscroll(float delta_x,
if (fabs(overscroll_delta_x_) <= horiz_threshold &&
fabs(overscroll_delta_y_) <= vert_threshold) {
SetOverscrollMode(OVERSCROLL_NONE);
- return;
+ return true;
}
// Compute the current overscroll direction. If the direction is different
@@ -306,7 +304,7 @@ void OverscrollController::ProcessOverscroll(float delta_x,
SetOverscrollMode(OVERSCROLL_NONE);
if (overscroll_mode_ == OVERSCROLL_NONE)
- return;
+ return false;
// Tell the delegate about the overscroll update so that it can update
// the display accordingly (e.g. show history preview etc.).
@@ -332,8 +330,9 @@ void OverscrollController::ProcessOverscroll(float delta_x,
} else {
delegate_delta_y = 0.f;
}
- delegate_->OnOverscrollUpdate(delegate_delta_x, delegate_delta_y);
+ return delegate_->OnOverscrollUpdate(delegate_delta_x, delegate_delta_y);
}
+ return false;
}
void OverscrollController::CompleteAction() {
diff --git a/chromium/content/browser/renderer_host/overscroll_controller.h b/chromium/content/browser/renderer_host/overscroll_controller.h
index 5577ce97f3d..a6287efd3bd 100644
--- a/chromium/content/browser/renderer_host/overscroll_controller.h
+++ b/chromium/content/browser/renderer_host/overscroll_controller.h
@@ -91,8 +91,9 @@ class OverscrollController {
// Processes horizontal overscroll. This can update both the overscroll mode
// and the over scroll amount (i.e. |overscroll_mode_|, |overscroll_delta_x_|
- // and |overscroll_delta_y_|).
- void ProcessOverscroll(float 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);
diff --git a/chromium/content/browser/renderer_host/overscroll_controller_delegate.h b/chromium/content/browser/renderer_host/overscroll_controller_delegate.h
index 59295ce4127..54b5da18857 100644
--- a/chromium/content/browser/renderer_host/overscroll_controller_delegate.h
+++ b/chromium/content/browser/renderer_host/overscroll_controller_delegate.h
@@ -23,8 +23,9 @@ class OverscrollControllerDelegate {
// events will only be processed if the visible bounds are non-empty.
virtual gfx::Rect GetVisibleBounds() const = 0;
- // This is called for each update in the overscroll amount.
- virtual void OnOverscrollUpdate(float delta_x, float delta_y) = 0;
+ // This is called for each update in the overscroll amount. Returns true if
+ // the delegate consumed the event.
+ virtual bool OnOverscrollUpdate(float delta_x, float delta_y) = 0;
// This is called when the overscroll completes.
virtual void OnOverscrollComplete(OverscrollMode overscroll_mode) = 0;
diff --git a/chromium/content/browser/renderer_host/p2p/OWNERS b/chromium/content/browser/renderer_host/p2p/OWNERS
index f12c2d60e83..49f36fb7949 100644
--- a/chromium/content/browser/renderer_host/p2p/OWNERS
+++ b/chromium/content/browser/renderer_host/p2p/OWNERS
@@ -1,3 +1,3 @@
hclam@chromium.org
-mallinath@chromium.org
sergeyu@chromium.org
+juberti@chromium.org
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 bb8c1fb9610..8bab6aff976 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
@@ -269,7 +269,7 @@ void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
void P2PSocketDispatcherHost::OnSend(int socket_id,
const net::IPEndPoint& socket_address,
const std::vector<char>& data,
- const talk_base::PacketOptions& options,
+ const rtc::PacketOptions& options,
uint64 packet_id) {
P2PSocketHost* socket = LookupSocket(socket_id);
if (!socket) {
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 21376bdd320..18b18df2272 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_dispatcher_host.h
@@ -22,7 +22,7 @@ namespace net {
class URLRequestContextGetter;
}
-namespace talk_base {
+namespace rtc {
struct PacketOptions;
}
@@ -39,12 +39,12 @@ class P2PSocketDispatcherHost
net::URLRequestContextGetter* url_context);
// content::BrowserMessageFilter overrides.
- virtual void OnChannelClosing() OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelClosing() override;
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// net::NetworkChangeNotifier::IPAddressObserver interface.
- virtual void OnIPAddressChanged() OVERRIDE;
+ void OnIPAddressChanged() override;
// Starts the RTP packet header dumping. Must be called on the IO thread.
void StartRtpDump(
@@ -56,7 +56,7 @@ class P2PSocketDispatcherHost
void StopRtpDumpOnUIThread(bool incoming, bool outgoing);
protected:
- virtual ~P2PSocketDispatcherHost();
+ ~P2PSocketDispatcherHost() override;
private:
friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
@@ -84,7 +84,7 @@ class P2PSocketDispatcherHost
void OnSend(int socket_id,
const net::IPEndPoint& socket_address,
const std::vector<char>& data,
- const talk_base::PacketOptions& options,
+ const rtc::PacketOptions& options,
uint64 packet_id);
void OnSetOption(int socket_id, P2PSocketOption option, int value);
void OnDestroySocket(int socket_id);
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host.cc b/chromium/content/browser/renderer_host/p2p/socket_host.cc
index 007ab77a200..8f6e71f3c71 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host.cc
@@ -4,6 +4,7 @@
#include "content/browser/renderer_host/p2p/socket_host.h"
+#include "base/metrics/histogram.h"
#include "base/sys_byteorder.h"
#include "content/browser/renderer_host/p2p/socket_host_tcp.h"
#include "content/browser/renderer_host/p2p/socket_host_tcp_server.h"
@@ -11,20 +12,22 @@
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/hmac.h"
-#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
-#include "third_party/libjingle/source/talk/base/byteorder.h"
-#include "third_party/libjingle/source/talk/base/messagedigest.h"
-#include "third_party/libjingle/source/talk/p2p/base/stun.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"
namespace {
const uint32 kStunMagicCookie = 0x2112A442;
-const int kMinRtpHdrLen = 12;
-const int kRtpExtnHdrLen = 4;
-const int kDtlsRecordHeaderLen = 13;
-const int kTurnChannelHdrLen = 4;
-const int kAbsSendTimeExtnLen = 3;
-const int kOneByteHdrLen = 1;
+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
@@ -33,37 +36,50 @@ static const unsigned char kFakeAuthTag[10] = {
0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd
};
-bool IsTurnChannelData(const char* data) {
- return ((*data & 0xC0) == 0x40);
+bool IsTurnChannelData(const char* data, size_t length) {
+ return length >= kTurnChannelHeaderLength && ((*data & 0xC0) == 0x40);
}
-bool IsDtlsPacket(const char* data, int len) {
+bool IsDtlsPacket(const char* data, size_t length) {
const uint8* u = reinterpret_cast<const uint8*>(data);
- return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64));
+ return (length >= kDtlsRecordHeaderLength && (u[0] > 19 && u[0] < 64));
}
-bool IsRtcpPacket(const char* data) {
+bool IsRtcpPacket(const char* data, size_t length) {
+ if (length < kMinRtcpHeaderLength) {
+ return false;
+ }
+
int type = (static_cast<uint8>(data[1]) & 0x7F);
return (type >= 64 && type < 96);
}
-bool IsTurnSendIndicationPacket(const char* data) {
- uint16 type = talk_base::GetBE16(data);
+bool IsTurnSendIndicationPacket(const char* data, size_t length) {
+ if (length < content::P2PSocketHost::kStunHeaderSize) {
+ return false;
+ }
+
+ uint16 type = rtc::GetBE16(data);
return (type == cricket::TURN_SEND_INDICATION);
}
-bool IsRtpPacket(const char* data, int len) {
- return ((*data & 0xC0) == 0x80);
+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, int length, size_t* header_length) {
- if (header_length)
+bool ValidateRtpHeader(const char* rtp, size_t length, size_t* header_length) {
+ if (header_length) {
*header_length = 0;
+ }
+
+ if (length < kMinRtpHeaderLength) {
+ return false;
+ }
- int cc_count = rtp[0] & 0x0F;
- int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count;
- if (rtp_hdr_len_without_extn > length) {
+ 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;
}
@@ -71,29 +87,40 @@ bool ValidateRtpHeader(const char* rtp, int length, size_t* header_length) {
// length is verified above.
if (!(rtp[0] & 0x10)) {
if (header_length)
- *header_length = rtp_hdr_len_without_extn;
+ *header_length = header_length_without_extension;
return true;
}
- rtp += rtp_hdr_len_without_extn;
+ 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 extn_length = talk_base::GetBE16(rtp + 2) * 4;
+ uint16 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_hdr_len_without_extn + kRtpExtnHdrLen + extn_length > length) {
+ if (rtp_header_length > length) {
return false;
}
- if (header_length)
- *header_length = rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length;
+ if (header_length) {
+ *header_length = rtp_header_length;
+ }
return true;
}
-void UpdateAbsSendTimeExtnValue(char* extn_data, int len,
- uint32 abs_send_time) {
+void UpdateAbsSendTimeExtensionValue(char* extension_data,
+ size_t length,
+ uint32 abs_send_time) {
// Absolute send time in RTP streams.
//
// The absolute send time is signaled to the receiver in-band using the
@@ -109,7 +136,11 @@ void UpdateAbsSendTimeExtnValue(char* extn_data, int len,
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=2 | absolute send time |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- DCHECK_EQ(len, kAbsSendTimeExtnLen);
+ if (length != kAbsSendTimeExtensionLength) {
+ NOTREACHED();
+ return;
+ }
+
// Now() has resolution ~1-15ms, using HighResNow(). But it is warned not to
// use it unless necessary, as it is expensive than Now().
uint32 now_second = abs_send_time;
@@ -121,24 +152,29 @@ void UpdateAbsSendTimeExtnValue(char* extn_data, int len,
((now_us << 18) / base::Time::kMicrosecondsPerSecond) & 0x00FFFFFF;
}
// TODO(mallinath) - Add SetBE24 to byteorder.h in libjingle.
- extn_data[0] = static_cast<uint8>(now_second >> 16);
- extn_data[1] = static_cast<uint8>(now_second >> 8);
- extn_data[2] = static_cast<uint8>(now_second);
+ extension_data[0] = static_cast<uint8>(now_second >> 16);
+ extension_data[1] = static_cast<uint8>(now_second >> 8);
+ extension_data[2] = static_cast<uint8>(now_second);
}
-// Assumes |len| is actual packet length + tag length. Updates HMAC at end of
+// Assumes |length| is actual packet length + tag length. Updates HMAC at end of
// the RTP packet.
-void UpdateRtpAuthTag(char* rtp, int len,
- const talk_base::PacketOptions& options) {
+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())
+ if (options.packet_time_params.srtp_auth_key.empty()) {
return;
+ }
size_t tag_length = options.packet_time_params.srtp_auth_tag_len;
- char* auth_tag = rtp + (len - tag_length);
- // We should have a fake HMAC value @ auth_tag.
- DCHECK_EQ(0, memcmp(auth_tag, kFakeAuthTag, tag_length));
+ // 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*>(
@@ -148,15 +184,20 @@ void UpdateRtpAuthTag(char* rtp, int len,
return;
}
- if (hmac.DigestLength() < tag_length) {
+ 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, 4);
+ 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 = len - tag_length + 4;
+ int auth_required_length = length - tag_length + kRocLength;
unsigned char output[64];
if (!hmac.Sign(base::StringPiece(rtp, auth_required_length),
@@ -175,8 +216,9 @@ namespace content {
namespace packet_processing_helpers {
-bool ApplyPacketOptions(char* data, int length,
- const talk_base::PacketOptions& options,
+bool ApplyPacketOptions(char* data,
+ size_t length,
+ const rtc::PacketOptions& options,
uint32 abs_send_time) {
DCHECK(data != NULL);
DCHECK(length > 0);
@@ -188,13 +230,13 @@ bool ApplyPacketOptions(char* data, int length,
}
DCHECK(!IsDtlsPacket(data, length));
- DCHECK(!IsRtcpPacket(data));
+ 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.
- int rtp_start_pos;
- int rtp_length;
+ size_t rtp_start_pos;
+ size_t rtp_length;
if (!GetRtpPacketStartPositionAndLength(
data, length, &rtp_start_pos, &rtp_length)) {
// This method should never return false.
@@ -208,9 +250,11 @@ bool ApplyPacketOptions(char* data, int length,
// 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) {
- UpdateRtpAbsSendTimeExtn(
- start, rtp_length,
- options.packet_time_params.rtp_sendtime_extension_id, abs_send_time);
+ UpdateRtpAbsSendTimeExtension(
+ start,
+ rtp_length,
+ options.packet_time_params.rtp_sendtime_extension_id,
+ abs_send_time);
}
UpdateRtpAuthTag(start, rtp_length, options);
@@ -218,11 +262,16 @@ bool ApplyPacketOptions(char* data, int length,
}
bool GetRtpPacketStartPositionAndLength(const char* packet,
- int length,
- int* rtp_start_pos,
- int* rtp_packet_length) {
- int rtp_begin, rtp_length;
- if (IsTurnChannelData(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
@@ -233,32 +282,23 @@ bool GetRtpPacketStartPositionAndLength(const char* packet,
// / Application Data /
// / /
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- if (length < kTurnChannelHdrLen) {
- return false;
- }
-
- rtp_begin = kTurnChannelHdrLen;
- rtp_length = talk_base::GetBE16(&packet[2]);
- if (length < rtp_length + kTurnChannelHdrLen) {
- return false;
- }
- } else if (IsTurnSendIndicationPacket(packet)) {
- if (length <= P2PSocketHost::kStunHeaderSize) {
- // Message must be greater than 20 bytes, if it's carrying any payload.
+ 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.
- int stun_msg_len = talk_base::GetBE16(&packet[2]);
- if (stun_msg_len + P2PSocketHost::kStunHeaderSize != 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.
- const char* start = packet + rtp_begin;
bool data_attr_present = false;
- while ((packet + rtp_begin) - start < stun_msg_len) {
+ while (rtp_begin < length) {
// Keep reading STUN attributes until we hit DATA attribute.
// Attribute will be a TLV structure.
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -273,17 +313,26 @@ bool GetRtpPacketStartPositionAndLength(const char* packet,
// padding so that its value contains a multiple of 4 bytes. The
// padding bits are ignored, and may be any value.
uint16 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 = talk_base::GetBE16(&packet[rtp_begin]);
- attr_length = talk_base::GetBE16(
+ 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 < attr_length + rtp_begin) {
+ if (length < rtp_begin + attr_length) {
return false;
}
if (attr_type != cricket::STUN_ATTR_DATA) {
- rtp_begin += sizeof(attr_type) + sizeof(attr_length) + attr_length;
+ rtp_begin += attr_length;
if ((attr_length % 4) != 0) {
rtp_begin += (4 - (attr_length % 4));
}
@@ -291,12 +340,8 @@ bool GetRtpPacketStartPositionAndLength(const char* packet,
}
data_attr_present = true;
- rtp_begin += 4; // Skip STUN_DATA_ATTR header.
rtp_length = attr_length;
- // One final check of length before exiting.
- if (length < rtp_length + rtp_begin) {
- return false;
- }
+
// We found STUN_DATA_ATTR. We can skip parsing rest of the packet.
break;
}
@@ -314,8 +359,7 @@ bool GetRtpPacketStartPositionAndLength(const char* packet,
}
// Making sure we have a valid RTP packet at the end.
- if (!(rtp_length < kMinRtpHdrLen) &&
- IsRtpPacket(packet + rtp_begin, rtp_length) &&
+ if (IsRtpPacket(packet + rtp_begin, rtp_length) &&
ValidateRtpHeader(packet + rtp_begin, rtp_length, NULL)) {
*rtp_start_pos = rtp_begin;
*rtp_packet_length = rtp_length;
@@ -326,8 +370,10 @@ bool GetRtpPacketStartPositionAndLength(const char* packet,
// ValidateRtpHeader must be called before this method to make sure, we have
// a sane rtp packet.
-bool UpdateRtpAbsSendTimeExtn(char* rtp, int length,
- int extension_id, uint32 abs_send_time) {
+bool UpdateRtpAbsSendTimeExtension(char* rtp,
+ size_t length,
+ int extension_id,
+ uint32 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -346,17 +392,18 @@ bool UpdateRtpAbsSendTimeExtn(char* rtp, int length,
return true;
}
- int cc_count = rtp[0] & 0x0F;
- int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count;
+ size_t cc_count = rtp[0] & 0x0F;
+ size_t header_length_without_extension = kMinRtpHeaderLength + 4 * cc_count;
- rtp += rtp_hdr_len_without_extn;
+ rtp += header_length_without_extension;
// Getting extension profile ID and length.
- uint16 profile_id = talk_base::GetBE16(rtp);
+ uint16 profile_id = rtc::GetBE16(rtp);
// Length is in 32 bit words.
- uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4;
+ uint16 extension_length_in_32bits = rtc::GetBE16(rtp + 2);
+ size_t extension_length = extension_length_in_32bits * 4;
- rtp += kRtpExtnHdrLen; // Moving past extn header.
+ rtp += kRtpExtensionHeaderLength; // Moving past extension header.
bool found = false;
// WebRTC is using one byte header extension.
@@ -365,7 +412,7 @@ bool UpdateRtpAbsSendTimeExtn(char* rtp, int length,
// 0
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
- // | ID | len |
+ // | ID |length |
// +-+-+-+-+-+-+-+-+
// 0 1 2 3
@@ -379,20 +426,26 @@ bool UpdateRtpAbsSendTimeExtn(char* rtp, int length,
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | data |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- char* extn_start = rtp;
- while (rtp - extn_start < extn_length) {
+ const char* extension_start = rtp;
+ const char* extension_end = extension_start + extension_length;
+
+ while (rtp < extension_end) {
const int id = (*rtp & 0xF0) >> 4;
- const int len = (*rtp & 0x0F) + 1;
+ 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) {
- UpdateAbsSendTimeExtnValue(rtp + kOneByteHdrLen, len, abs_send_time);
+ UpdateAbsSendTimeExtensionValue(
+ rtp + kOneByteHeaderLength, length, abs_send_time);
found = true;
break;
}
- rtp += kOneByteHdrLen + len;
+ rtp += kOneByteHeaderLength + length;
// Counting padding bytes.
- while ((*rtp == 0) && (rtp - extn_start < extn_length)) {
+ while ((rtp < extension_end) && (*rtp == 0)) {
++rtp;
}
}
@@ -402,32 +455,61 @@ bool UpdateRtpAbsSendTimeExtn(char* rtp, int length,
} // packet_processing_helpers
-P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, int socket_id)
+P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender,
+ int socket_id,
+ ProtocolType protocol_type)
: message_sender_(message_sender),
id_(socket_id),
state_(STATE_UNINITIALIZED),
dump_incoming_rtp_packet_(false),
dump_outgoing_rtp_packet_(false),
- weak_ptr_factory_(this) {
+ weak_ptr_factory_(this),
+ protocol_type_(protocol_type),
+ send_packets_delayed_total_(0),
+ send_packets_total_(0),
+ send_bytes_delayed_max_(0),
+ send_bytes_delayed_cur_(0) {
}
-P2PSocketHost::~P2PSocketHost() { }
+P2PSocketHost::~P2PSocketHost() {
+ if (protocol_type_ == P2PSocketHost::UDP) {
+ UMA_HISTOGRAM_COUNTS_10000("WebRTC.SystemMaxConsecutiveBytesDelayed_UDP",
+ send_bytes_delayed_max_);
+ } else {
+ UMA_HISTOGRAM_COUNTS_10000("WebRTC.SystemMaxConsecutiveBytesDelayed_TCP",
+ send_bytes_delayed_max_);
+ }
+
+ if (send_packets_total_ > 0) {
+ int delay_rate = (send_packets_delayed_total_ * 100) / send_packets_total_;
+ if (protocol_type_ == P2PSocketHost::UDP) {
+ UMA_HISTOGRAM_PERCENTAGE("WebRTC.SystemPercentPacketsDelayed_UDP",
+ delay_rate);
+ } else {
+ UMA_HISTOGRAM_PERCENTAGE("WebRTC.SystemPercentPacketsDelayed_TCP",
+ delay_rate);
+ }
+ }
+}
// Verifies that the packet |data| has a valid STUN header.
// static
bool P2PSocketHost::GetStunPacketType(
const char* data, int data_size, StunMessageType* type) {
- if (data_size < kStunHeaderSize)
+ if (data_size < kStunHeaderSize) {
return false;
+ }
uint32 cookie = base::NetToHost32(*reinterpret_cast<const uint32*>(data + 4));
- if (cookie != kStunMagicCookie)
+ if (cookie != kStunMagicCookie) {
return false;
+ }
uint16 length = base::NetToHost16(*reinterpret_cast<const uint16*>(data + 2));
- if (length != data_size - kStunHeaderSize)
+ if (length != data_size - kStunHeaderSize) {
return false;
+ }
int message_type = base::NetToHost16(*reinterpret_cast<const uint16*>(data));
@@ -501,11 +583,13 @@ void P2PSocketHost::StartRtpDump(
DCHECK(!packet_callback.is_null());
DCHECK(incoming || outgoing);
- if (incoming)
+ if (incoming) {
dump_incoming_rtp_packet_ = true;
+ }
- if (outgoing)
+ if (outgoing) {
dump_outgoing_rtp_packet_ = true;
+ }
packet_dump_callback_ = packet_callback;
}
@@ -514,27 +598,32 @@ void P2PSocketHost::StopRtpDump(bool incoming, bool outgoing) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(incoming || outgoing);
- if (incoming)
+ if (incoming) {
dump_incoming_rtp_packet_ = false;
+ }
- if (outgoing)
+ if (outgoing) {
dump_outgoing_rtp_packet_ = false;
+ }
- if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_)
+ if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_) {
packet_dump_callback_.Reset();
+ }
}
void P2PSocketHost::DumpRtpPacket(const char* packet,
size_t length,
bool incoming) {
- if (IsDtlsPacket(packet, length) || IsRtcpPacket(packet))
+ if (IsDtlsPacket(packet, length) || IsRtcpPacket(packet, length)) {
return;
+ }
- int rtp_packet_pos = 0;
- int rtp_packet_length = length;
+ 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))
+ packet, length, &rtp_packet_pos, &rtp_packet_length)) {
return;
+ }
packet += rtp_packet_pos;
@@ -582,4 +671,24 @@ void P2PSocketHost::DumpRtpPacketOnIOThread(scoped_ptr<uint8[]> packet_header,
incoming));
}
+void P2PSocketHost::IncrementDelayedPackets() {
+ send_packets_delayed_total_++;
+}
+
+void P2PSocketHost::IncrementTotalSentPackets() {
+ send_packets_total_++;
+}
+
+void P2PSocketHost::IncrementDelayedBytes(uint32 size) {
+ send_bytes_delayed_cur_ += size;
+ if (send_bytes_delayed_cur_ > send_bytes_delayed_max_) {
+ send_bytes_delayed_max_ = send_bytes_delayed_cur_;
+ }
+}
+
+void P2PSocketHost::DecrementDelayedBytes(uint32 size) {
+ send_bytes_delayed_cur_ -= size;
+ DCHECK_GE(send_bytes_delayed_cur_, 0);
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host.h b/chromium/content/browser/renderer_host/p2p/socket_host.h
index bfcbbd229f1..390c115efb6 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host.h
@@ -20,7 +20,7 @@ namespace net {
class URLRequestContextGetter;
}
-namespace talk_base {
+namespace rtc {
struct PacketOptions;
}
@@ -33,20 +33,24 @@ namespace packet_processing_helpers {
// 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, int length,
- const talk_base::PacketOptions& options,
+CONTENT_EXPORT bool ApplyPacketOptions(char* data,
+ size_t length,
+ const rtc::PacketOptions& options,
uint32 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,
- int length,
- int* rtp_start_pos,
- int* rtp_packet_length);
+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 UpdateRtpAbsSendTimeExtn(char* rtp, int length,
- int extension_id,
- uint32 abs_send_time);
+CONTENT_EXPORT bool UpdateRtpAbsSendTimeExtension(char* rtp,
+ size_t length,
+ int extension_id,
+ uint32 abs_send_time);
} // packet_processing_helpers
@@ -70,7 +74,7 @@ class CONTENT_EXPORT P2PSocketHost {
// Sends |data| on the socket to |to|.
virtual void Send(const net::IPEndPoint& to,
const std::vector<char>& data,
- const talk_base::PacketOptions& options,
+ const rtc::PacketOptions& options,
uint64 packet_id) = 0;
virtual P2PSocketHost* AcceptIncomingTcpConnection(
@@ -87,6 +91,9 @@ class CONTENT_EXPORT P2PSocketHost {
protected:
friend class P2PSocketHostTcpTestBase;
+ // This should match suffix IPProtocolType defined in histograms.xml.
+ enum ProtocolType { UDP = 0x1, TCP = 0x2 };
+
// TODO(mallinath) - Remove this below enum and use one defined in
// libjingle/souce/talk/p2p/base/stun.h
enum StunMessageType {
@@ -121,7 +128,9 @@ class CONTENT_EXPORT P2PSocketHost {
STATE_ERROR,
};
- P2PSocketHost(IPC::Sender* message_sender, int socket_id);
+ P2PSocketHost(IPC::Sender* message_sender,
+ int socket_id,
+ ProtocolType protocol_type);
// Verifies that the packet |data| has a valid STUN header. In case
// of success stores type of the message in |type|.
@@ -138,6 +147,12 @@ class CONTENT_EXPORT P2PSocketHost {
size_t packet_length,
bool incoming);
+ // Used by subclasses to track the metrics of delayed bytes and packets.
+ void IncrementDelayedPackets();
+ void IncrementTotalSentPackets();
+ void IncrementDelayedBytes(uint32 size);
+ void DecrementDelayedBytes(uint32 size);
+
IPC::Sender* message_sender_;
int id_;
State state_;
@@ -147,6 +162,19 @@ class CONTENT_EXPORT P2PSocketHost {
base::WeakPtrFactory<P2PSocketHost> weak_ptr_factory_;
+ ProtocolType protocol_type_;
+
+ private:
+ // Track total delayed packets for calculating how many packets are
+ // delayed by system at the end of call.
+ uint32 send_packets_delayed_total_;
+ uint32 send_packets_total_;
+
+ // Track the maximum of consecutive delayed bytes caused by system's
+ // EWOULDBLOCK.
+ int32 send_bytes_delayed_max_;
+ int32 send_bytes_delayed_cur_;
+
DISALLOW_COPY_AND_ASSIGN(P2PSocketHost);
};
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 978f6269f5d..79f7b14b0b8 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -18,7 +18,7 @@
#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/libjingle/source/talk/base/asyncpacketsocket.h"
+#include "third_party/webrtc/base/asyncpacketsocket.h"
namespace {
@@ -49,7 +49,7 @@ P2PSocketHostTcpBase::P2PSocketHostTcpBase(
int socket_id,
P2PSocketType type,
net::URLRequestContextGetter* url_context)
- : P2PSocketHost(message_sender, socket_id),
+ : P2PSocketHost(message_sender, socket_id, P2PSocketHost::TCP),
write_pending_(false),
connected_(false),
type_(type),
@@ -83,8 +83,18 @@ bool P2PSocketHostTcpBase::Init(const net::IPEndPoint& local_address,
remote_address_ = remote_address;
state_ = STATE_CONNECTING;
- net::HostPortPair dest_host_port_pair =
- net::HostPortPair::FromIPEndPoint(remote_address.ip_address);
+ net::HostPortPair dest_host_port_pair;
+ // If there is no resolved address, let's try with domain name, assuming
+ // socket layer will do the DNS resolve.
+ if (remote_address.ip_address.address().empty()) {
+ DCHECK(!remote_address.hostname.empty());
+ dest_host_port_pair = net::HostPortPair(remote_address.hostname,
+ remote_address.ip_address.port());
+ } else {
+ dest_host_port_pair = net::HostPortPair::FromIPEndPoint(
+ remote_address.ip_address);
+ }
+
// TODO(mallinath) - We are ignoring local_address altogether. We should
// find a way to inject this into ProxyResolvingClientSocket. This could be
// a problem on multi-homed host.
@@ -175,8 +185,15 @@ void P2PSocketHostTcpBase::StartTls() {
// Default ssl config.
const net::SSLConfig ssl_config;
- net::HostPortPair dest_host_port_pair =
+ net::HostPortPair dest_host_port_pair;
+
+ // Calling net::HostPortPair::FromIPEndPoint will crash if the IP address is
+ // empty.
+ if (!remote_address_.ip_address.address().empty()) {
net::HostPortPair::FromIPEndPoint(remote_address_.ip_address);
+ } else {
+ dest_host_port_pair.set_port(remote_address_.ip_address.port());
+ }
if (!remote_address_.hostname.empty())
dest_host_port_pair.set_host(remote_address_.hostname);
@@ -217,29 +234,48 @@ void P2PSocketHostTcpBase::OnOpen() {
<< kSendSocketBufferSize;
}
- DoSendSocketCreateMsg();
+ if (!DoSendSocketCreateMsg())
+ return;
+
+ DCHECK_EQ(state_, STATE_OPEN);
DoRead();
}
-void P2PSocketHostTcpBase::DoSendSocketCreateMsg() {
+bool P2PSocketHostTcpBase::DoSendSocketCreateMsg() {
DCHECK(socket_.get());
- net::IPEndPoint address;
- int result = socket_->GetLocalAddress(&address);
+ net::IPEndPoint local_address;
+ int result = socket_->GetLocalAddress(&local_address);
if (result < 0) {
LOG(ERROR) << "P2PSocketHostTcpBase::OnConnected: unable to get local"
<< " address: " << result;
OnError();
- return;
+ return false;
}
- VLOG(1) << "Local address: " << address.ToString();
+ VLOG(1) << "Local address: " << local_address.ToString();
+
+ net::IPEndPoint remote_address;
+ result = socket_->GetPeerAddress(&remote_address);
+ if (result < 0) {
+ LOG(ERROR) << "P2PSocketHostTcpBase::OnConnected: unable to get peer"
+ << " address: " << result;
+ OnError();
+ return false;
+ }
+ VLOG(1) << "Remote address: " << remote_address.ToString();
+ if (remote_address_.ip_address.address().empty()) {
+ // Save |remote_address| if address is empty.
+ remote_address_.ip_address = remote_address;
+ }
// If we are not doing TLS, we are ready to send data now.
// In case of TLS SignalConnect will be sent only after TLS handshake is
// successfull. So no buffering will be done at socket handlers if any
// packets sent before that by the application.
- message_sender_->Send(new P2PMsg_OnSocketCreated(id_, address));
+ message_sender_->Send(new P2PMsg_OnSocketCreated(
+ id_, local_address, remote_address));
+ return true;
}
void P2PSocketHostTcpBase::DoRead() {
@@ -298,7 +334,7 @@ void P2PSocketHostTcpBase::OnPacket(const std::vector<char>& data) {
// but may be honored in the future.
void P2PSocketHostTcpBase::Send(const net::IPEndPoint& to,
const std::vector<char>& data,
- const talk_base::PacketOptions& options,
+ const rtc::PacketOptions& options,
uint64 packet_id) {
if (!socket_) {
// The Send message may be sent after the an OnError message was
@@ -329,8 +365,11 @@ void P2PSocketHostTcpBase::Send(const net::IPEndPoint& to,
void P2PSocketHostTcpBase::WriteOrQueue(
scoped_refptr<net::DrainableIOBuffer>& buffer) {
+ IncrementTotalSentPackets();
if (write_buffer_.get()) {
write_queue_.push(buffer);
+ IncrementDelayedPackets();
+ IncrementDelayedBytes(buffer->size());
return;
}
@@ -368,6 +407,8 @@ void P2PSocketHostTcpBase::HandleWriteResult(int result) {
} else {
write_buffer_ = write_queue_.front();
write_queue_.pop();
+ // Update how many bytes are still waiting to be sent.
+ DecrementDelayedBytes(write_buffer_->size());
}
}
} else if (result == net::ERR_IO_PENDING) {
@@ -458,7 +499,7 @@ int P2PSocketHostTcp::ProcessInput(char* input, int input_len) {
void P2PSocketHostTcp::DoSend(const net::IPEndPoint& to,
const std::vector<char>& data,
- const talk_base::PacketOptions& options) {
+ const rtc::PacketOptions& options) {
int size = kPacketHeaderSize + data.size();
scoped_refptr<net::DrainableIOBuffer> buffer =
new net::DrainableIOBuffer(new net::IOBuffer(size), size);
@@ -511,7 +552,7 @@ int P2PSocketHostStunTcp::ProcessInput(char* input, int input_len) {
void P2PSocketHostStunTcp::DoSend(const net::IPEndPoint& to,
const std::vector<char>& data,
- const talk_base::PacketOptions& options) {
+ const rtc::PacketOptions& options) {
// Each packet is expected to have header (STUN/TURN ChannelData), where
// header contains message type and and length of message.
if (data.size() < kPacketHeaderSize + kPacketLengthOffset) {
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.h b/chromium/content/browser/renderer_host/p2p/socket_host_tcp.h
index f5ff8633b06..4c2bb313f93 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_tcp.h
@@ -32,28 +32,29 @@ class CONTENT_EXPORT P2PSocketHostTcpBase : public P2PSocketHost {
int socket_id,
P2PSocketType type,
net::URLRequestContextGetter* url_context);
- virtual ~P2PSocketHostTcpBase();
+ ~P2PSocketHostTcpBase() override;
bool InitAccepted(const net::IPEndPoint& remote_address,
net::StreamSocket* socket);
// P2PSocketHost overrides.
- virtual bool Init(const net::IPEndPoint& local_address,
- const P2PHostAndIPEndPoint& remote_address) OVERRIDE;
- virtual void Send(const net::IPEndPoint& to,
- const std::vector<char>& data,
- const talk_base::PacketOptions& options,
- uint64 packet_id) OVERRIDE;
- virtual P2PSocketHost* AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address, int id) OVERRIDE;
- virtual bool SetOption(P2PSocketOption option, int value) OVERRIDE;
+ bool Init(const net::IPEndPoint& local_address,
+ const P2PHostAndIPEndPoint& remote_address) override;
+ void Send(const net::IPEndPoint& to,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options,
+ uint64 packet_id) override;
+ P2PSocketHost* AcceptIncomingTcpConnection(
+ const net::IPEndPoint& remote_address,
+ int id) override;
+ bool SetOption(P2PSocketOption option, int value) override;
protected:
// Derived classes will provide the implementation.
virtual int ProcessInput(char* input, int input_len) = 0;
virtual void DoSend(const net::IPEndPoint& to,
const std::vector<char>& data,
- const talk_base::PacketOptions& options) = 0;
+ const rtc::PacketOptions& options) = 0;
void WriteOrQueue(scoped_refptr<net::DrainableIOBuffer>& buffer);
void OnPacket(const std::vector<char>& data);
@@ -80,7 +81,7 @@ class CONTENT_EXPORT P2PSocketHostTcpBase : public P2PSocketHost {
// Helper method to send socket create message and start read.
void OnOpen();
- void DoSendSocketCreateMsg();
+ bool DoSendSocketCreateMsg();
P2PHostAndIPEndPoint remote_address_;
@@ -104,13 +105,14 @@ class CONTENT_EXPORT P2PSocketHostTcp : public P2PSocketHostTcpBase {
int socket_id,
P2PSocketType type,
net::URLRequestContextGetter* url_context);
- virtual ~P2PSocketHostTcp();
+ ~P2PSocketHostTcp() override;
protected:
- virtual int ProcessInput(char* input, int input_len) OVERRIDE;
- virtual void DoSend(const net::IPEndPoint& to,
- const std::vector<char>& data,
- const talk_base::PacketOptions& options) OVERRIDE;
+ int ProcessInput(char* input, int input_len) override;
+ void DoSend(const net::IPEndPoint& to,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options) override;
+
private:
DISALLOW_COPY_AND_ASSIGN(P2PSocketHostTcp);
};
@@ -126,13 +128,14 @@ class CONTENT_EXPORT P2PSocketHostStunTcp : public P2PSocketHostTcpBase {
P2PSocketType type,
net::URLRequestContextGetter* url_context);
- virtual ~P2PSocketHostStunTcp();
+ ~P2PSocketHostStunTcp() override;
protected:
- virtual int ProcessInput(char* input, int input_len) OVERRIDE;
- virtual void DoSend(const net::IPEndPoint& to,
- const std::vector<char>& data,
- const talk_base::PacketOptions& options) OVERRIDE;
+ int ProcessInput(char* input, int input_len) override;
+ void DoSend(const net::IPEndPoint& to,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options) override;
+
private:
int GetExpectedPacketSize(const char* data, int len, int* pad_bytes);
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 2418de9e87c..0976b22ad2b 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
@@ -23,7 +23,7 @@ namespace content {
P2PSocketHostTcpServer::P2PSocketHostTcpServer(IPC::Sender* message_sender,
int socket_id,
P2PSocketType client_type)
- : P2PSocketHost(message_sender, socket_id),
+ : P2PSocketHost(message_sender, socket_id, P2PSocketHost::TCP),
client_type_(client_type),
socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
accept_callback_(base::Bind(&P2PSocketHostTcpServer::OnAccepted,
@@ -61,7 +61,10 @@ bool P2PSocketHostTcpServer::Init(const net::IPEndPoint& local_address,
VLOG(1) << "Local address: " << local_address_.ToString();
state_ = STATE_OPEN;
- message_sender_->Send(new P2PMsg_OnSocketCreated(id_, local_address_));
+ // NOTE: Remote address can be empty as socket is just listening
+ // in this state.
+ message_sender_->Send(new P2PMsg_OnSocketCreated(
+ id_, local_address_, remote_address.ip_address));
DoAccept();
return true;
}
@@ -116,7 +119,7 @@ void P2PSocketHostTcpServer::OnAccepted(int result) {
void P2PSocketHostTcpServer::Send(const net::IPEndPoint& to,
const std::vector<char>& data,
- const talk_base::PacketOptions& options,
+ const rtc::PacketOptions& options,
uint64 packet_id) {
NOTREACHED();
OnError();
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h
index e050b00fa06..df2053224fa 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server.h
@@ -31,19 +31,19 @@ class CONTENT_EXPORT P2PSocketHostTcpServer : public P2PSocketHost {
P2PSocketHostTcpServer(IPC::Sender* message_sender,
int socket_id,
P2PSocketType client_type);
- virtual ~P2PSocketHostTcpServer();
+ ~P2PSocketHostTcpServer() override;
// P2PSocketHost overrides.
- virtual bool Init(const net::IPEndPoint& local_address,
- const P2PHostAndIPEndPoint& remote_address) OVERRIDE;
- virtual void Send(const net::IPEndPoint& to,
- const std::vector<char>& data,
- const talk_base::PacketOptions& options,
- uint64 packet_id) OVERRIDE;
- virtual P2PSocketHost* AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address, int id) OVERRIDE;
- virtual bool SetOption(P2PSocketOption option, int value) OVERRIDE;
-
+ bool Init(const net::IPEndPoint& local_address,
+ const P2PHostAndIPEndPoint& remote_address) override;
+ void Send(const net::IPEndPoint& to,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options,
+ uint64 packet_id) override;
+ P2PSocketHost* AcceptIncomingTcpConnection(
+ const net::IPEndPoint& remote_address,
+ int id) override;
+ bool SetOption(P2PSocketOption option, int value) override;
private:
friend class P2PSocketHostTcpServerTest;
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
index 270fad90cb1..64b420b8b8b 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
@@ -26,7 +26,7 @@ class FakeServerSocket : public net::ServerSocket {
accept_socket_(NULL) {
}
- virtual ~FakeServerSocket() {}
+ ~FakeServerSocket() override {}
bool listening() { return listening_; }
@@ -47,19 +47,19 @@ class FakeServerSocket : public net::ServerSocket {
}
}
- virtual int Listen(const net::IPEndPoint& address, int backlog) OVERRIDE {
+ int Listen(const net::IPEndPoint& address, int backlog) override {
local_address_ = address;
listening_ = true;
return net::OK;
}
- virtual int GetLocalAddress(net::IPEndPoint* address) const OVERRIDE {
+ int GetLocalAddress(net::IPEndPoint* address) const override {
*address = local_address_;
return net::OK;
}
- virtual int Accept(scoped_ptr<net::StreamSocket>* socket,
- const net::CompletionCallback& callback) OVERRIDE {
+ int Accept(scoped_ptr<net::StreamSocket>* socket,
+ const net::CompletionCallback& callback) override {
DCHECK(socket);
if (!incoming_sockets_.empty()) {
socket->reset(incoming_sockets_.front());
@@ -89,7 +89,7 @@ namespace content {
class P2PSocketHostTcpServerTest : public testing::Test {
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
socket_ = new FakeServerSocket();
socket_host_.reset(
new P2PSocketHostTcpServer(&sender_, 0, P2P_SOCKET_TCP_CLIENT));
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
index 24b77c3adbe..cd5a9093aa7 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
@@ -25,7 +25,7 @@ class P2PSocketHostTcpTestBase : public testing::Test {
: socket_type_(type) {
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
EXPECT_CALL(sender_, Send(
MatchMessage(static_cast<uint32>(P2PMsg_OnSocketCreated::ID))))
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
@@ -89,7 +89,7 @@ TEST_F(P2PSocketHostTcpTest, SendStunNoAuth) {
.Times(3)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
socket_host_->Send(dest_.ip_address, packet1, options, 0);
@@ -121,7 +121,7 @@ TEST_F(P2PSocketHostTcpTest, ReceiveStun) {
.Times(3)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
socket_host_->Send(dest_.ip_address, packet1, options, 0);
@@ -168,7 +168,7 @@ TEST_F(P2PSocketHostTcpTest, SendDataNoAuth) {
MatchMessage(static_cast<uint32>(P2PMsg_OnError::ID))))
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet;
CreateRandomPacket(&packet);
socket_host_->Send(dest_.ip_address, packet, options, 0);
@@ -194,7 +194,7 @@ TEST_F(P2PSocketHostTcpTest, SendAfterStunRequest) {
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
socket_->AppendInputData(&received_data[0], received_data.size());
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
// Now we should be able to send any data to |dest_|.
std::vector<char> packet;
CreateRandomPacket(&packet);
@@ -218,7 +218,7 @@ TEST_F(P2PSocketHostTcpTest, AsyncWrites) {
.Times(2)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
@@ -254,7 +254,7 @@ TEST_F(P2PSocketHostTcpTest, SendDataWithPacketOptions) {
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
socket_->AppendInputData(&received_data[0], received_data.size());
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
options.packet_time_params.rtp_sendtime_extension_id = 3;
// Now we should be able to send any data to |dest_|.
std::vector<char> packet;
@@ -278,7 +278,7 @@ TEST_F(P2PSocketHostStunTcpTest, SendStunNoAuth) {
.Times(3)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
socket_host_->Send(dest_.ip_address, packet1, options, 0);
@@ -307,7 +307,7 @@ TEST_F(P2PSocketHostStunTcpTest, ReceiveStun) {
.Times(3)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
socket_host_->Send(dest_.ip_address, packet1, options, 0);
@@ -351,7 +351,7 @@ TEST_F(P2PSocketHostStunTcpTest, SendDataNoAuth) {
MatchMessage(static_cast<uint32>(P2PMsg_OnError::ID))))
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet;
CreateRandomPacket(&packet);
socket_host_->Send(dest_.ip_address, packet, options, 0);
@@ -370,7 +370,7 @@ TEST_F(P2PSocketHostStunTcpTest, AsyncWrites) {
.Times(2)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
socket_host_->Send(dest_.ip_address, packet1, options, 0);
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 b27b55b9982..acab45ff25f 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
@@ -31,7 +31,7 @@ class MockIPCSender : public IPC::Sender {
class FakeSocket : public net::StreamSocket {
public:
FakeSocket(std::string* written_data);
- virtual ~FakeSocket();
+ ~FakeSocket() override;
void set_async_write(bool async_write) { async_write_ = async_write; }
void AppendInputData(const char* data, int data_size);
@@ -41,26 +41,28 @@ class FakeSocket : public net::StreamSocket {
void SetLocalAddress(const net::IPEndPoint& local_address);
// net::Socket implementation.
- virtual int Read(net::IOBuffer* buf, int buf_len,
- const net::CompletionCallback& callback) OVERRIDE;
- virtual int Write(net::IOBuffer* buf, int buf_len,
- const net::CompletionCallback& callback) OVERRIDE;
- virtual int SetReceiveBufferSize(int32 size) OVERRIDE;
- virtual int SetSendBufferSize(int32 size) OVERRIDE;
- virtual int Connect(const net::CompletionCallback& callback) OVERRIDE;
- virtual void Disconnect() OVERRIDE;
- virtual bool IsConnected() const OVERRIDE;
- virtual bool IsConnectedAndIdle() const OVERRIDE;
- virtual int GetPeerAddress(net::IPEndPoint* address) const OVERRIDE;
- virtual int GetLocalAddress(net::IPEndPoint* address) const OVERRIDE;
- virtual const net::BoundNetLog& NetLog() const OVERRIDE;
- virtual void SetSubresourceSpeculation() OVERRIDE;
- virtual void SetOmniboxSpeculation() OVERRIDE;
- virtual bool WasEverUsed() const OVERRIDE;
- virtual bool UsingTCPFastOpen() const OVERRIDE;
- virtual bool WasNpnNegotiated() const OVERRIDE;
- virtual net::NextProto GetNegotiatedProtocol() const OVERRIDE;
- virtual bool GetSSLInfo(net::SSLInfo* ssl_info) OVERRIDE;
+ int Read(net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) override;
+ int Write(net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) override;
+ int SetReceiveBufferSize(int32 size) override;
+ int SetSendBufferSize(int32 size) override;
+ int Connect(const net::CompletionCallback& callback) override;
+ void Disconnect() override;
+ bool IsConnected() const override;
+ bool IsConnectedAndIdle() const override;
+ int GetPeerAddress(net::IPEndPoint* address) const override;
+ int GetLocalAddress(net::IPEndPoint* address) const override;
+ const net::BoundNetLog& NetLog() const override;
+ 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;
private:
void DoAsyncWrite(scoped_refptr<net::IOBuffer> buf, int buf_len,
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc b/chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc
index 50a4dd0ac83..0ef92eb8a6f 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_throttler.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "content/browser/renderer_host/p2p/socket_host_throttler.h"
-#include "third_party/libjingle/source/talk/base/ratelimiter.h"
-#include "third_party/libjingle/source/talk/base/timing.h"
+#include "third_party/webrtc/base/ratelimiter.h"
+#include "third_party/webrtc/base/timing.h"
namespace content {
@@ -16,19 +16,19 @@ const int kMaxIceMessageBandwidth = 256 * 1024;
P2PMessageThrottler::P2PMessageThrottler()
- : timing_(new talk_base::Timing()),
- rate_limiter_(new talk_base::RateLimiter(kMaxIceMessageBandwidth, 1.0)) {
+ : timing_(new rtc::Timing()),
+ rate_limiter_(new rtc::RateLimiter(kMaxIceMessageBandwidth, 1.0)) {
}
P2PMessageThrottler::~P2PMessageThrottler() {
}
-void P2PMessageThrottler::SetTiming(scoped_ptr<talk_base::Timing> timing) {
+void P2PMessageThrottler::SetTiming(scoped_ptr<rtc::Timing> timing) {
timing_ = timing.Pass();
}
void P2PMessageThrottler::SetSendIceBandwidth(int bandwidth_kbps) {
- rate_limiter_.reset(new talk_base::RateLimiter(bandwidth_kbps, 1.0));
+ rate_limiter_.reset(new rtc::RateLimiter(bandwidth_kbps, 1.0));
}
bool P2PMessageThrottler::DropNextPacket(size_t packet_len) {
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_throttler.h b/chromium/content/browser/renderer_host/p2p/socket_host_throttler.h
index 166d30054f5..a28a5885621 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_throttler.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_throttler.h
@@ -8,7 +8,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
-namespace talk_base {
+namespace rtc {
class RateLimiter;
class Timing;
}
@@ -24,13 +24,13 @@ class CONTENT_EXPORT P2PMessageThrottler {
P2PMessageThrottler();
virtual ~P2PMessageThrottler();
- void SetTiming(scoped_ptr<talk_base::Timing> timing);
+ void SetTiming(scoped_ptr<rtc::Timing> timing);
bool DropNextPacket(size_t packet_len);
void SetSendIceBandwidth(int bandwith_kbps);
private:
- scoped_ptr<talk_base::Timing> timing_;
- scoped_ptr<talk_base::RateLimiter> rate_limiter_;
+ scoped_ptr<rtc::Timing> timing_;
+ scoped_ptr<rtc::RateLimiter> rate_limiter_;
DISALLOW_COPY_AND_ASSIGN(P2PMessageThrottler);
};
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 5dad882629f..29883179715 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -6,7 +6,10 @@
#include "base/bind.h"
#include "base/debug/trace_event.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
#include "content/browser/renderer_host/p2p/socket_host_throttler.h"
#include "content/common/p2p_messages.h"
#include "content/public/browser/content_browser_client.h"
@@ -15,7 +18,7 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
-#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
+#include "third_party/webrtc/base/asyncpacketsocket.h"
namespace {
@@ -52,7 +55,7 @@ namespace content {
P2PSocketHostUdp::PendingPacket::PendingPacket(
const net::IPEndPoint& to,
const std::vector<char>& content,
- const talk_base::PacketOptions& options,
+ const rtc::PacketOptions& options,
uint64 id)
: to(to),
data(new net::IOBuffer(content.size())),
@@ -68,7 +71,7 @@ P2PSocketHostUdp::PendingPacket::~PendingPacket() {
P2PSocketHostUdp::P2PSocketHostUdp(IPC::Sender* message_sender,
int socket_id,
P2PMessageThrottler* throttler)
- : P2PSocketHost(message_sender, socket_id),
+ : P2PSocketHost(message_sender, socket_id, P2PSocketHost::UDP),
socket_(
new net::UDPServerSocket(GetContentClient()->browser()->GetNetLog(),
net::NetLog::Source())),
@@ -84,6 +87,21 @@ P2PSocketHostUdp::~P2PSocketHostUdp() {
}
}
+void P2PSocketHostUdp::SetSendBufferSize() {
+ unsigned int send_buffer_size = 0;
+
+ base::StringToUint(
+ base::FieldTrialList::FindFullName("WebRTC-SystemUDPSendSocketSize"),
+ &send_buffer_size);
+
+ if (send_buffer_size > 0) {
+ if (!SetOption(P2P_SOCKET_OPT_SNDBUF, send_buffer_size)) {
+ LOG(WARNING) << "Failed to set socket send buffer size to "
+ << send_buffer_size;
+ }
+ }
+}
+
bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address,
const P2PHostAndIPEndPoint& remote_address) {
DCHECK_EQ(state_, STATE_UNINITIALIZED);
@@ -113,7 +131,11 @@ bool P2PSocketHostUdp::Init(const net::IPEndPoint& local_address,
state_ = STATE_OPEN;
- message_sender_->Send(new P2PMsg_OnSocketCreated(id_, address));
+ SetSendBufferSize();
+
+ // NOTE: Remote address will be same as what renderer provided.
+ message_sender_->Send(new P2PMsg_OnSocketCreated(
+ id_, address, remote_address.ip_address));
recv_buffer_ = new net::IOBuffer(kReadBufferSize);
DoRead();
@@ -184,7 +206,7 @@ void P2PSocketHostUdp::HandleReadResult(int result) {
void P2PSocketHostUdp::Send(const net::IPEndPoint& to,
const std::vector<char>& data,
- const talk_base::PacketOptions& options,
+ const rtc::PacketOptions& options,
uint64 packet_id) {
if (!socket_) {
// The Send message may be sent after the an OnError message was
@@ -209,8 +231,12 @@ void P2PSocketHostUdp::Send(const net::IPEndPoint& to,
}
}
+ IncrementTotalSentPackets();
+
if (send_pending_) {
send_queue_.push_back(PendingPacket(to, data, options, packet_id));
+ IncrementDelayedBytes(data.size());
+ IncrementDelayedPackets();
} else {
// TODO(mallinath: Remove unnecessary memcpy in this case.
PendingPacket packet(to, data, options, packet_id);
@@ -239,52 +265,64 @@ void P2PSocketHostUdp::DoSend(const PendingPacket& packet) {
last_dscp_ = net::DSCP_NO_CHANGE;
}
}
+
+ uint64 tick_received = base::TimeTicks::Now().ToInternalValue();
+
packet_processing_helpers::ApplyPacketOptions(
packet.data->data(), packet.size, packet.packet_options, 0);
- int result = socket_->SendTo(
- packet.data.get(),
- packet.size,
- packet.to,
- base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), packet.id));
+ int result = socket_->SendTo(packet.data.get(),
+ packet.size,
+ packet.to,
+ base::Bind(&P2PSocketHostUdp::OnSend,
+ base::Unretained(this),
+ packet.id,
+ tick_received));
// sendto() may return an error, e.g. if we've received an ICMP Destination
// Unreachable message. When this happens try sending the same packet again,
// and just drop it if it fails again.
if (IsTransientError(result)) {
- result = socket_->SendTo(
- packet.data.get(),
- packet.size,
- packet.to,
- base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this),
- packet.id));
+ result = socket_->SendTo(packet.data.get(),
+ packet.size,
+ packet.to,
+ base::Bind(&P2PSocketHostUdp::OnSend,
+ base::Unretained(this),
+ packet.id,
+ tick_received));
}
if (result == net::ERR_IO_PENDING) {
send_pending_ = true;
} else {
- HandleSendResult(packet.id, result);
+ HandleSendResult(packet.id, tick_received, result);
}
if (dump_outgoing_rtp_packet_)
DumpRtpPacket(packet.data->data(), packet.size, false);
}
-void P2PSocketHostUdp::OnSend(uint64 packet_id, int result) {
+void P2PSocketHostUdp::OnSend(uint64 packet_id,
+ uint64 tick_received,
+ int result) {
DCHECK(send_pending_);
DCHECK_NE(result, net::ERR_IO_PENDING);
send_pending_ = false;
- HandleSendResult(packet_id, result);
+ HandleSendResult(packet_id, tick_received, result);
// Send next packets if we have them waiting in the buffer.
while (state_ == STATE_OPEN && !send_queue_.empty() && !send_pending_) {
- DoSend(send_queue_.front());
+ PendingPacket packet = send_queue_.front();
+ DoSend(packet);
send_queue_.pop_front();
+ DecrementDelayedBytes(packet.size);
}
}
-void P2PSocketHostUdp::HandleSendResult(uint64 packet_id, int result) {
+void P2PSocketHostUdp::HandleSendResult(uint64 packet_id,
+ uint64 tick_received,
+ int result) {
TRACE_EVENT_ASYNC_END1("p2p", "Send", packet_id,
"result", result);
if (result < 0) {
@@ -296,6 +334,14 @@ void P2PSocketHostUdp::HandleSendResult(uint64 packet_id, int result) {
VLOG(0) << "sendto() has failed twice returning a "
" transient error. Dropping the packet.";
}
+
+ // UMA to track the histograms from 1ms to 1 sec for how long a packet spends
+ // in the browser process.
+ UMA_HISTOGRAM_TIMES(
+ "WebRTC.SystemSendPacketDuration_UDP" /* name */,
+ base::TimeTicks::Now() -
+ base::TimeTicks::FromInternalValue(tick_received) /* sample */);
+
message_sender_->Send(new P2PMsg_OnSendComplete(id_));
}
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 b22795c059d..f0b04a65496 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_udp.h
@@ -18,7 +18,7 @@
#include "content/common/p2p_socket_type.h"
#include "net/base/ip_endpoint.h"
#include "net/udp/udp_server_socket.h"
-#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
+#include "third_party/webrtc/base/asyncpacketsocket.h"
namespace content {
@@ -29,18 +29,19 @@ class CONTENT_EXPORT P2PSocketHostUdp : public P2PSocketHost {
P2PSocketHostUdp(IPC::Sender* message_sender,
int socket_id,
P2PMessageThrottler* throttler);
- virtual ~P2PSocketHostUdp();
+ ~P2PSocketHostUdp() override;
// P2PSocketHost overrides.
- virtual bool Init(const net::IPEndPoint& local_address,
- const P2PHostAndIPEndPoint& remote_address) OVERRIDE;
- virtual void Send(const net::IPEndPoint& to,
- const std::vector<char>& data,
- const talk_base::PacketOptions& options,
- uint64 packet_id) OVERRIDE;
- virtual P2PSocketHost* AcceptIncomingTcpConnection(
- const net::IPEndPoint& remote_address, int id) OVERRIDE;
- virtual bool SetOption(P2PSocketOption option, int value) OVERRIDE;
+ bool Init(const net::IPEndPoint& local_address,
+ const P2PHostAndIPEndPoint& remote_address) override;
+ void Send(const net::IPEndPoint& to,
+ const std::vector<char>& data,
+ const rtc::PacketOptions& options,
+ uint64 packet_id) override;
+ P2PSocketHost* AcceptIncomingTcpConnection(
+ const net::IPEndPoint& remote_address,
+ int id) override;
+ bool SetOption(P2PSocketOption option, int value) override;
private:
friend class P2PSocketHostUdpTest;
@@ -50,25 +51,27 @@ class CONTENT_EXPORT P2PSocketHostUdp : public P2PSocketHost {
struct PendingPacket {
PendingPacket(const net::IPEndPoint& to,
const std::vector<char>& content,
- const talk_base::PacketOptions& options,
+ const rtc::PacketOptions& options,
uint64 id);
~PendingPacket();
net::IPEndPoint to;
scoped_refptr<net::IOBuffer> data;
int size;
- talk_base::PacketOptions packet_options;
+ rtc::PacketOptions packet_options;
uint64 id;
};
void OnError();
+ void SetSendBufferSize();
+
void DoRead();
void OnRecv(int result);
void HandleReadResult(int result);
void DoSend(const PendingPacket& packet);
- void OnSend(uint64 packet_id, int result);
- void HandleSendResult(uint64 packet_id, int result);
+ void OnSend(uint64 packet_id, uint64 tick_received, int result);
+ void HandleSendResult(uint64 packet_id, uint64 tick_received, int result);
scoped_ptr<net::DatagramServerSocket> socket_;
scoped_refptr<net::IOBuffer> recv_buffer_;
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 6235cb07d9f..5d67a24fc33 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
@@ -17,7 +17,7 @@
#include "net/udp/datagram_server_socket.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/libjingle/source/talk/base/timing.h"
+#include "third_party/webrtc/base/timing.h"
using ::testing::_;
using ::testing::DeleteArg;
@@ -26,10 +26,10 @@ using ::testing::Return;
namespace {
-class FakeTiming : public talk_base::Timing {
+class FakeTiming : public rtc::Timing {
public:
FakeTiming() : now_(0.0) {}
- virtual double TimerNow() OVERRIDE { return now_; }
+ double TimerNow() override { return now_; }
void set_now(double now) { now_ = now; }
private:
@@ -46,27 +46,27 @@ class FakeDatagramServerSocket : public net::DatagramServerSocket {
: sent_packets_(sent_packets) {
}
- virtual void Close() OVERRIDE {
- }
+ void Close() override {}
- virtual int GetPeerAddress(net::IPEndPoint* address) const OVERRIDE {
+ int GetPeerAddress(net::IPEndPoint* address) const override {
NOTREACHED();
return net::ERR_SOCKET_NOT_CONNECTED;
}
- virtual int GetLocalAddress(net::IPEndPoint* address) const OVERRIDE {
+ int GetLocalAddress(net::IPEndPoint* address) const override {
*address = address_;
return 0;
}
- virtual int Listen(const net::IPEndPoint& address) OVERRIDE {
+ int Listen(const net::IPEndPoint& address) override {
address_ = address;
return 0;
}
- virtual int RecvFrom(net::IOBuffer* buf, int buf_len,
- net::IPEndPoint* address,
- const net::CompletionCallback& callback) OVERRIDE {
+ int RecvFrom(net::IOBuffer* buf,
+ int buf_len,
+ net::IPEndPoint* address,
+ const net::CompletionCallback& callback) override {
CHECK(recv_callback_.is_null());
if (incoming_packets_.size() > 0) {
scoped_refptr<net::IOBuffer> buffer(buf);
@@ -85,22 +85,19 @@ class FakeDatagramServerSocket : public net::DatagramServerSocket {
}
}
- virtual int SendTo(net::IOBuffer* buf, int buf_len,
- const net::IPEndPoint& address,
- const net::CompletionCallback& callback) OVERRIDE {
+ int SendTo(net::IOBuffer* buf,
+ int buf_len,
+ const net::IPEndPoint& address,
+ const net::CompletionCallback& callback) override {
scoped_refptr<net::IOBuffer> buffer(buf);
std::vector<char> data_vector(buffer->data(), buffer->data() + buf_len);
sent_packets_->push_back(UDPPacket(address, data_vector));
return buf_len;
}
- virtual int SetReceiveBufferSize(int32 size) OVERRIDE {
- return net::OK;
- }
+ int SetReceiveBufferSize(int32 size) override { return net::OK; }
- virtual int SetSendBufferSize(int32 size) OVERRIDE {
- return net::OK;
- }
+ int SetSendBufferSize(int32 size) override { return net::OK; }
void ReceivePacket(const net::IPEndPoint& address, std::vector<char> data) {
if (!recv_callback_.is_null()) {
@@ -116,53 +113,43 @@ class FakeDatagramServerSocket : public net::DatagramServerSocket {
}
}
- virtual const net::BoundNetLog& NetLog() const OVERRIDE {
- return net_log_;
- }
+ const net::BoundNetLog& NetLog() const override { return net_log_; }
- virtual void AllowAddressReuse() OVERRIDE {
- NOTIMPLEMENTED();
- }
+ void AllowAddressReuse() override { NOTIMPLEMENTED(); }
- virtual void AllowBroadcast() OVERRIDE {
- NOTIMPLEMENTED();
- }
+ void AllowBroadcast() override { NOTIMPLEMENTED(); }
- virtual int JoinGroup(
- const net::IPAddressNumber& group_address) const OVERRIDE {
+ int JoinGroup(const net::IPAddressNumber& group_address) const override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
}
- virtual int LeaveGroup(
- const net::IPAddressNumber& group_address) const OVERRIDE {
+ int LeaveGroup(const net::IPAddressNumber& group_address) const override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
}
- virtual int SetMulticastInterface(uint32 interface_index) OVERRIDE {
+ int SetMulticastInterface(uint32 interface_index) override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
}
- virtual int SetMulticastTimeToLive(int time_to_live) OVERRIDE {
+ int SetMulticastTimeToLive(int time_to_live) override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
}
- virtual int SetMulticastLoopbackMode(bool loopback) OVERRIDE {
+ int SetMulticastLoopbackMode(bool loopback) override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
}
- virtual int SetDiffServCodePoint(net::DiffServCodePoint dscp) OVERRIDE {
+ int SetDiffServCodePoint(net::DiffServCodePoint dscp) override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
}
- virtual void DetachFromThread() OVERRIDE {
- NOTIMPLEMENTED();
- }
+ void DetachFromThread() override { NOTIMPLEMENTED(); }
private:
net::IPEndPoint address_;
@@ -182,7 +169,7 @@ namespace content {
class P2PSocketHostUdpTest : public testing::Test {
protected:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
EXPECT_CALL(sender_, Send(
MatchMessage(static_cast<uint32>(P2PMsg_OnSocketCreated::ID))))
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
@@ -197,7 +184,7 @@ class P2PSocketHostUdpTest : public testing::Test {
dest1_ = ParseAddress(kTestIpAddress1, kTestPort1);
dest2_ = ParseAddress(kTestIpAddress2, kTestPort2);
- scoped_ptr<talk_base::Timing> timing(new FakeTiming());
+ scoped_ptr<rtc::Timing> timing(new FakeTiming());
throttler_.SetTiming(timing.Pass());
}
@@ -221,7 +208,7 @@ TEST_F(P2PSocketHostUdpTest, SendStunNoAuth) {
.Times(3)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
socket_host_->Send(dest1_, packet1, options, 0);
@@ -247,7 +234,7 @@ TEST_F(P2PSocketHostUdpTest, SendDataNoAuth) {
MatchMessage(static_cast<uint32>(P2PMsg_OnError::ID))))
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet;
CreateRandomPacket(&packet);
socket_host_->Send(dest1_, packet, options, 0);
@@ -271,7 +258,7 @@ TEST_F(P2PSocketHostUdpTest, SendAfterStunRequest) {
MatchMessage(static_cast<uint32>(P2PMsg_OnSendComplete::ID))))
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet;
CreateRandomPacket(&packet);
socket_host_->Send(dest1_, packet, options, 0);
@@ -296,7 +283,7 @@ TEST_F(P2PSocketHostUdpTest, SendAfterStunResponse) {
MatchMessage(static_cast<uint32>(P2PMsg_OnSendComplete::ID))))
.WillOnce(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet;
CreateRandomPacket(&packet);
socket_host_->Send(dest1_, packet, options, 0);
@@ -317,7 +304,7 @@ TEST_F(P2PSocketHostUdpTest, SendAfterStunResponseDifferentHost) {
socket_->ReceivePacket(dest1_, request_packet);
// Should fail when trying to send the same packet to |dest2_|.
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet;
CreateRandomPacket(&packet);
EXPECT_CALL(sender_, Send(
@@ -334,7 +321,7 @@ TEST_F(P2PSocketHostUdpTest, ThrottleAfterLimit) {
.Times(2)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
throttler_.SetSendIceBandwidth(packet1.size() * 2);
@@ -363,7 +350,7 @@ TEST_F(P2PSocketHostUdpTest, ThrottleAfterLimitAfterReceive) {
.Times(4)
.WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> packet1;
CreateStunRequest(&packet1);
throttler_.SetSendIceBandwidth(packet1.size());
diff --git a/chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc b/chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc
index 1404ced5bc6..7e9393fd96c 100644
--- a/chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/p2p/socket_host_unittest.cc
@@ -152,152 +152,158 @@ namespace content {
// This test verifies parsing of all invalid raw packets.
TEST(P2PSocketHostTest, TestInvalidRawRtpMessages) {
- int start_pos = INT_MAX, rtp_length = INT_MAX;
+ 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(INT_MAX, start_pos);
- EXPECT_EQ(INT_MAX, 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(INT_MAX, start_pos);
- EXPECT_EQ(INT_MAX, 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.
- int start_pos = INT_MAX, rtp_length = INT_MAX;
+ 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(INT_MAX, start_pos);
- EXPECT_EQ(INT_MAX, 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(INT_MAX, start_pos);
- EXPECT_EQ(INT_MAX, 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(INT_MAX, start_pos);
- EXPECT_EQ(INT_MAX, 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) {
- int start_pos = INT_MAX, rtp_length = INT_MAX;
+ 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(INT_MAX, start_pos);
- EXPECT_EQ(INT_MAX, 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(INT_MAX, start_pos);
- EXPECT_EQ(INT_MAX, 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) {
- int start_pos = INT_MAX, rtp_length = INT_MAX;
+ 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(20, rtp_length);
- EXPECT_EQ(0, start_pos);
+ 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) {
- int start_pos = INT_MAX, rtp_length = INT_MAX;
+ 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(24, rtp_length);
- EXPECT_EQ(0, start_pos);
+ EXPECT_EQ(24U, rtp_length);
+ EXPECT_EQ(0U, start_pos);
}
// This test verifies parsing of a valid TURN Send Indication messages.
TEST(P2PSocketHostTest, TestValidTurnSendIndicationMessages) {
- int start_pos = INT_MAX, rtp_length = INT_MAX;
+ 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(12, rtp_length);
- EXPECT_EQ(32, start_pos);
+ EXPECT_EQ(12U, rtp_length);
+ EXPECT_EQ(32U, start_pos);
- start_pos = INT_MAX, rtp_length = INT_MAX;
+ 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(24, rtp_length);
- EXPECT_EQ(32, start_pos);
+ EXPECT_EQ(24U, rtp_length);
+ EXPECT_EQ(32U, start_pos);
}
// This test verifies parsing of valid TURN Channel Messages.
TEST(P2PSocketHostTest, TestValidTurnChannelMessages) {
- int start_pos = -1, rtp_length = -1;
+ 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(12, rtp_length);
- EXPECT_EQ(4, start_pos);
+ EXPECT_EQ(12U, rtp_length);
+ EXPECT_EQ(4U, start_pos);
- start_pos = -1, rtp_length = -1;
+ start_pos = 0, rtp_length = 0;
EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength(
reinterpret_cast<char*>(kTurnChannelMsgWithAbsSendTimeExtension),
sizeof(kTurnChannelMsgWithAbsSendTimeExtension),
&start_pos, &rtp_length));
- EXPECT_EQ(20, rtp_length);
- EXPECT_EQ(4, start_pos);
+ 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::UpdateRtpAbsSendTimeExtn(
- reinterpret_cast<char*>(kRtpMsgWith2ByteExtnHeader),
- sizeof(kRtpMsgWith2ByteExtnHeader), 3, 0));
+ 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::UpdateRtpAbsSendTimeExtn(
+ EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension(
reinterpret_cast<char*>(kTurnSendIndicationMsgWithoutRtpExtension),
- sizeof(kTurnSendIndicationMsgWithoutRtpExtension), 3, 0));
+ sizeof(kTurnSendIndicationMsgWithoutRtpExtension),
+ 3,
+ 0));
- EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtn(
+ EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension(
reinterpret_cast<char*>(kTurnSendIndicationMsgWithAbsSendTimeExtension),
- sizeof(kTurnSendIndicationMsgWithAbsSendTimeExtension), 3, 0));
+ 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 };
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
std::vector<char> rtp_packet;
rtp_packet.resize(sizeof(kRtpMsgWithAbsSendTimeExtension) + 4); // tag length
memcpy(&rtp_packet[0], kRtpMsgWithAbsSendTimeExtension,
@@ -317,7 +323,7 @@ TEST(P2PSocketHostTest, TestApplyPacketOptionsWithDefaultValues) {
// Veirfy HMAC is updated when packet option parameters are set.
TEST(P2PSocketHostTest, TestApplyPacketOptionsWithAuthParams) {
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
options.packet_time_params.srtp_auth_key.resize(20);
options.packet_time_params.srtp_auth_key.assign(
kTestKey, kTestKey + sizeof(kTestKey));
@@ -341,14 +347,16 @@ TEST(P2PSocketHostTest, TestApplyPacketOptionsWithAuthParams) {
// Verify finding an extension ID in a raw rtp message.
TEST(P2PSocketHostTest, TestUpdateAbsSendTimeExtensionInRtpPacket) {
- EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtn(
+ EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension(
reinterpret_cast<char*>(kRtpMsgWithAbsSendTimeExtension),
- sizeof(kRtpMsgWithAbsSendTimeExtension), 3, 0));
+ sizeof(kRtpMsgWithAbsSendTimeExtension),
+ 3,
+ 0));
}
// Verify we update both AbsSendTime extension header and HMAC.
TEST(P2PSocketHostTest, TestApplyPacketOptionsWithAuthParamsAndAbsSendTime) {
- talk_base::PacketOptions options;
+ rtc::PacketOptions options;
options.packet_time_params.srtp_auth_key.resize(20);
options.packet_time_params.srtp_auth_key.assign(
kTestKey, kTestKey + sizeof(kTestKey));
diff --git a/chromium/content/browser/renderer_host/pepper/OWNERS b/chromium/content/browser/renderer_host/pepper/OWNERS
index 4523b30354e..d107f297fa7 100644
--- a/chromium/content/browser/renderer_host/pepper/OWNERS
+++ b/chromium/content/browser/renderer_host/pepper/OWNERS
@@ -2,4 +2,3 @@ bbudge@chromium.org
dmichael@chromium.org
raymes@chromium.org
teravest@chromium.org
-yzshen@chromium.org
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 403b129a469..130245e6022 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
@@ -37,7 +37,7 @@ BrowserPpapiHost* BrowserPpapiHost::CreateExternalPluginProcess(
scoped_refptr<PepperMessageFilter> pepper_message_filter(
new PepperMessageFilter());
channel->AddFilter(pepper_message_filter->GetFilter());
- channel->AddFilter(browser_ppapi_host->message_filter());
+ channel->AddFilter(browser_ppapi_host->message_filter().get());
channel->AddFilter((new TraceMessageFilter())->GetFilter());
return browser_ppapi_host;
diff --git a/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h b/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
index 16fec3d2907..bd0c61d7c59 100644
--- a/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
+++ b/chromium/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h
@@ -22,6 +22,10 @@
#include "ipc/message_filter.h"
#include "ppapi/host/ppapi_host.h"
+#if !defined(ENABLE_PLUGINS)
+#error "Plugins should be enabled"
+#endif
+
namespace content {
class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
@@ -38,23 +42,22 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
const base::FilePath& profile_data_directory,
bool in_process,
bool external_plugin);
- virtual ~BrowserPpapiHostImpl();
+ ~BrowserPpapiHostImpl() override;
// BrowserPpapiHost.
- virtual ppapi::host::PpapiHost* GetPpapiHost() OVERRIDE;
- virtual base::ProcessHandle GetPluginProcessHandle() const OVERRIDE;
- virtual bool IsValidInstance(PP_Instance instance) const OVERRIDE;
- virtual bool GetRenderFrameIDsForInstance(PP_Instance instance,
- int* render_process_id,
- int* render_frame_id) const
- OVERRIDE;
- virtual const std::string& GetPluginName() OVERRIDE;
- virtual const base::FilePath& GetPluginPath() OVERRIDE;
- virtual const base::FilePath& GetProfileDataDirectory() OVERRIDE;
- virtual GURL GetDocumentURLForInstance(PP_Instance instance) OVERRIDE;
- virtual GURL GetPluginURLForInstance(PP_Instance instance) OVERRIDE;
- virtual void SetOnKeepaliveCallback(
- const BrowserPpapiHost::OnKeepaliveCallback& callback) OVERRIDE;
+ ppapi::host::PpapiHost* GetPpapiHost() override;
+ base::ProcessHandle GetPluginProcessHandle() const override;
+ bool IsValidInstance(PP_Instance instance) const override;
+ bool GetRenderFrameIDsForInstance(PP_Instance instance,
+ int* render_process_id,
+ int* render_frame_id) const override;
+ const std::string& GetPluginName() override;
+ const base::FilePath& GetPluginPath() override;
+ const base::FilePath& GetProfileDataDirectory() override;
+ GURL GetDocumentURLForInstance(PP_Instance instance) override;
+ GURL GetPluginURLForInstance(PP_Instance instance) override;
+ void SetOnKeepaliveCallback(
+ const BrowserPpapiHost::OnKeepaliveCallback& callback) override;
void set_plugin_process_handle(base::ProcessHandle handle) {
plugin_process_handle_ = handle;
@@ -89,12 +92,12 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost {
BrowserPpapiHostImpl* browser_ppapi_host_impl);
// IPC::MessageFilter.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
void OnHostDestroyed();
private:
- virtual ~HostMessageFilter();
+ ~HostMessageFilter() override;
void OnKeepalive();
void OnHostMsgLogInterfaceUsage(int hash) const;
diff --git a/chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc b/chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
index e1ce0320b6e..9a88cfc460a 100644
--- a/chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
+++ b/chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
@@ -18,6 +18,7 @@
#include "content/browser/renderer_host/pepper/pepper_printing_host.h"
#include "content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h"
#include "content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h"
+#include "content/browser/renderer_host/pepper/pepper_truetype_font_host.h"
#include "content/browser/renderer_host/pepper/pepper_truetype_font_list_host.h"
#include "content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h"
#include "ppapi/host/message_filter_host.h"
@@ -29,6 +30,7 @@
using ppapi::host::MessageFilterHost;
using ppapi::host::ResourceHost;
using ppapi::host::ResourceMessageFilter;
+using ppapi::proxy::SerializedTrueTypeFontDesc;
using ppapi::UnpackMessage;
namespace content {
@@ -140,6 +142,20 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
params.pp_resource(),
manager.Pass()));
}
+ case PpapiHostMsg_TrueTypeFont_Create::ID: {
+ SerializedTrueTypeFontDesc desc;
+ if (!UnpackMessage<PpapiHostMsg_TrueTypeFont_Create>(message, &desc)) {
+ NOTREACHED();
+ return scoped_ptr<ResourceHost>();
+ }
+ // Check that the family name is valid UTF-8 before passing it to the
+ // host OS.
+ if (!base::IsStringUTF8(desc.family))
+ return scoped_ptr<ResourceHost>();
+
+ return scoped_ptr<ResourceHost>(new PepperTrueTypeFontHost(
+ host_, instance, params.pp_resource(), desc));
+ }
case PpapiHostMsg_TrueTypeFontSingleton_Create::ID: {
return scoped_ptr<ResourceHost>(new PepperTrueTypeFontListHost(
host_, instance, params.pp_resource()));
@@ -242,7 +258,7 @@ ContentBrowserPepperHostFactory::CreateNewTCPSocket(
scoped_refptr<ResourceMessageFilter> tcp_socket(
new PepperTCPSocketMessageFilter(this, host_, instance, version));
- if (!tcp_socket)
+ if (!tcp_socket.get())
return scoped_ptr<ResourceHost>();
return scoped_ptr<ResourceHost>(new MessageFilterHost(
diff --git a/chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h b/chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h
index 04267a32e8a..84161f3392d 100644
--- a/chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h
+++ b/chromium/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h
@@ -26,13 +26,13 @@ class ContentBrowserPepperHostFactory : public ppapi::host::HostFactory {
// Non-owning pointer to the filter must outlive this class.
explicit ContentBrowserPepperHostFactory(BrowserPpapiHostImpl* host);
- virtual ~ContentBrowserPepperHostFactory();
+ ~ContentBrowserPepperHostFactory() override;
- virtual scoped_ptr<ppapi::host::ResourceHost> CreateResourceHost(
+ scoped_ptr<ppapi::host::ResourceHost> CreateResourceHost(
ppapi::host::PpapiHost* host,
const ppapi::proxy::ResourceMessageCallParams& params,
PP_Instance instance,
- const IPC::Message& message) OVERRIDE;
+ const IPC::Message& message) override;
// Creates ResourceHost for already accepted TCP |socket|. In the case of
// failure returns wrapped NULL.
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.cc
index 40c13dfee01..e2c909c9ae5 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.cc
@@ -23,14 +23,14 @@ class FontMessageFilter : public ppapi::host::ResourceMessageFilter {
FontMessageFilter();
// ppapi::host::ResourceMessageFilter implementation.
- virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
- const IPC::Message& msg) OVERRIDE;
- virtual int32_t OnResourceMessageReceived(
+ scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) override;
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
private:
- virtual ~FontMessageFilter();
+ ~FontMessageFilter() override;
// Message handler.
int32_t OnHostMsgGetFontFamilies(ppapi::host::HostMessageContext* context);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.h b/chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.h
index c002e634c91..643be703b9d 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_browser_font_singleton_host.h
@@ -17,7 +17,7 @@ class PepperBrowserFontSingletonHost : public ppapi::host::ResourceHost {
PepperBrowserFontSingletonHost(BrowserPpapiHost* host,
PP_Instance instance,
PP_Resource resource);
- virtual ~PepperBrowserFontSingletonHost();
+ ~PepperBrowserFontSingletonHost() override;
private:
DISALLOW_COPY_AND_ASSIGN(PepperBrowserFontSingletonHost);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc b/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc
index a6b61981ac5..d4913da4ce8 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.cc
@@ -97,8 +97,8 @@ int32_t PepperExternalFileRefBackend::GetAbsolutePath(
return PP_OK_COMPLETIONPENDING;
}
-fileapi::FileSystemURL PepperExternalFileRefBackend::GetFileSystemURL() const {
- return fileapi::FileSystemURL();
+storage::FileSystemURL PepperExternalFileRefBackend::GetFileSystemURL() const {
+ return storage::FileSystemURL();
}
base::FilePath PepperExternalFileRefBackend::GetExternalFilePath() const {
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h b/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h
index 4d2980ae421..f3c3c947d57 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h
@@ -25,29 +25,28 @@ class PepperExternalFileRefBackend : public PepperFileRefBackend {
PepperExternalFileRefBackend(ppapi::host::PpapiHost* host,
int render_process_id,
const base::FilePath& path);
- virtual ~PepperExternalFileRefBackend();
+ ~PepperExternalFileRefBackend() override;
// PepperFileRefBackend overrides.
- virtual int32_t MakeDirectory(ppapi::host::ReplyMessageContext context,
- int32_t make_directory_flags) OVERRIDE;
- virtual int32_t Touch(ppapi::host::ReplyMessageContext context,
- PP_Time last_accessed_time,
- PP_Time last_modified_time) OVERRIDE;
- virtual int32_t Delete(ppapi::host::ReplyMessageContext context) OVERRIDE;
- virtual int32_t Rename(ppapi::host::ReplyMessageContext context,
- PepperFileRefHost* new_file_ref) OVERRIDE;
- virtual int32_t Query(ppapi::host::ReplyMessageContext context) OVERRIDE;
- virtual int32_t ReadDirectoryEntries(ppapi::host::ReplyMessageContext context)
- OVERRIDE;
- virtual int32_t GetAbsolutePath(ppapi::host::ReplyMessageContext context)
- OVERRIDE;
- virtual fileapi::FileSystemURL GetFileSystemURL() const OVERRIDE;
- virtual base::FilePath GetExternalFilePath() const OVERRIDE;
+ int32_t MakeDirectory(ppapi::host::ReplyMessageContext context,
+ int32_t make_directory_flags) override;
+ int32_t Touch(ppapi::host::ReplyMessageContext context,
+ PP_Time last_accessed_time,
+ PP_Time last_modified_time) override;
+ int32_t Delete(ppapi::host::ReplyMessageContext context) override;
+ int32_t Rename(ppapi::host::ReplyMessageContext context,
+ PepperFileRefHost* new_file_ref) override;
+ int32_t Query(ppapi::host::ReplyMessageContext context) override;
+ int32_t ReadDirectoryEntries(
+ ppapi::host::ReplyMessageContext context) override;
+ int32_t GetAbsolutePath(ppapi::host::ReplyMessageContext context) override;
+ storage::FileSystemURL GetFileSystemURL() const override;
+ base::FilePath GetExternalFilePath() const override;
- virtual int32_t CanRead() const OVERRIDE;
- virtual int32_t CanWrite() const OVERRIDE;
- virtual int32_t CanCreate() const OVERRIDE;
- virtual int32_t CanReadWrite() const OVERRIDE;
+ int32_t CanRead() const override;
+ int32_t CanWrite() const override;
+ int32_t CanCreate() const override;
+ int32_t CanReadWrite() const override;
private:
// Generic reply callback.
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 e350138f8a7..31850f85171 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
@@ -28,11 +28,11 @@
#include "ppapi/shared_impl/file_system_util.h"
#include "ppapi/shared_impl/file_type_conversion.h"
#include "ppapi/shared_impl/time_conversion.h"
-#include "webkit/browser/fileapi/file_observers.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-#include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
-#include "webkit/common/fileapi/file_system_util.h"
+#include "storage/browser/fileapi/file_observers.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/browser/fileapi/task_runner_bound_observer_list.h"
+#include "storage/common/fileapi/file_system_util.h"
namespace content {
@@ -87,7 +87,7 @@ void DidCloseFile(const base::Closure& on_close_callback) {
}
void DidOpenFile(base::WeakPtr<PepperFileIOHost> file_host,
- fileapi::FileSystemOperation::OpenFileCallback callback,
+ storage::FileSystemOperation::OpenFileCallback callback,
base::File file,
const base::Closure& on_close_callback) {
if (file_host) {
@@ -109,7 +109,8 @@ PepperFileIOHost::PepperFileIOHost(BrowserPpapiHostImpl* host,
: ResourceHost(host->GetPpapiHost(), instance, resource),
browser_ppapi_host_(host),
render_process_host_(NULL),
- file_(BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)),
+ file_(BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
+ .get()),
open_flags_(0),
file_system_type_(PP_FILESYSTEMTYPE_INVALID),
max_written_offset_(0),
@@ -186,13 +187,13 @@ int32_t PepperFileIOHost::OnHostMsgOpen(
// Not all external file systems are fully supported yet.
// Whitelist the supported ones.
- if (file_system_url_.mount_type() == fileapi::kFileSystemTypeExternal) {
+ if (file_system_url_.mount_type() == storage::kFileSystemTypeExternal) {
switch (file_system_url_.type()) {
- case fileapi::kFileSystemTypeNativeMedia:
- case fileapi::kFileSystemTypeDeviceMedia:
- case fileapi::kFileSystemTypePicasa:
- case fileapi::kFileSystemTypeItunes:
- case fileapi::kFileSystemTypeIphoto:
+ case storage::kFileSystemTypeNativeMedia:
+ 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 abef036c95b..36f7dba09a4 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
@@ -12,7 +12,6 @@
#include "base/files/file.h"
#include "base/files/file_proxy.h"
#include "base/memory/weak_ptr.h"
-#include "base/platform_file.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_platform_file.h"
@@ -21,8 +20,8 @@
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/resource_host.h"
#include "ppapi/shared_impl/file_io_state_manager.h"
+#include "storage/browser/fileapi/file_system_context.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_context.h"
namespace ppapi {
struct FileGrowth;
@@ -39,18 +38,18 @@ class PepperFileIOHost : public ppapi::host::ResourceHost,
PepperFileIOHost(BrowserPpapiHostImpl* host,
PP_Instance instance,
PP_Resource resource);
- virtual ~PepperFileIOHost();
+ ~PepperFileIOHost() override;
// ppapi::host::ResourceHost override.
- virtual int32_t OnResourceMessageReceived(
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
struct UIThreadStuff {
UIThreadStuff();
~UIThreadStuff();
base::ProcessId resolved_render_process_id;
- scoped_refptr<fileapi::FileSystemContext> file_system_context;
+ scoped_refptr<storage::FileSystemContext> file_system_context;
};
private:
@@ -127,8 +126,8 @@ class PepperFileIOHost : public ppapi::host::ResourceHost,
base::WeakPtr<PepperFileSystemBrowserHost> file_system_host_;
// Valid only for PP_FILESYSTEMTYPE_LOCAL{PERSISTENT,TEMPORARY}.
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
- fileapi::FileSystemURL file_system_url_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
+ storage::FileSystemURL file_system_url_;
base::Closure on_close_callback_;
int64_t max_written_offset_;
bool check_quota_;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.cc
index a8d362d36e8..6a1d9affe23 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.cc
@@ -17,7 +17,7 @@
#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/file_ref_util.h"
-#include "webkit/browser/fileapi/file_permission_policy.h"
+#include "storage/browser/fileapi/file_permission_policy.h"
using ppapi::host::ResourceHost;
@@ -109,10 +109,10 @@ PP_FileSystemType PepperFileRefHost::GetFileSystemType() const {
return fs_type_;
}
-fileapi::FileSystemURL PepperFileRefHost::GetFileSystemURL() const {
+storage::FileSystemURL PepperFileRefHost::GetFileSystemURL() const {
if (backend_)
return backend_->GetFileSystemURL();
- return fileapi::FileSystemURL();
+ return storage::FileSystemURL();
}
base::FilePath PepperFileRefHost::GetExternalFilePath() const {
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.h b/chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.h
index d850504d175..5f6d11eb119 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_ref_host.h
@@ -15,7 +15,7 @@
#include "ppapi/c/pp_time.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/resource_host.h"
-#include "webkit/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/file_system_url.h"
namespace content {
class PepperFileRefHost;
@@ -40,7 +40,7 @@ class PepperFileRefBackend {
virtual int32_t ReadDirectoryEntries(
ppapi::host::ReplyMessageContext context) = 0;
virtual int32_t GetAbsolutePath(ppapi::host::ReplyMessageContext context) = 0;
- virtual fileapi::FileSystemURL GetFileSystemURL() const = 0;
+ virtual storage::FileSystemURL GetFileSystemURL() const = 0;
virtual base::FilePath GetExternalFilePath() const = 0;
// Returns an error from the pp_errors.h enum.
@@ -65,17 +65,17 @@ class CONTENT_EXPORT PepperFileRefHost
PP_Resource resource,
const base::FilePath& external_path);
- virtual ~PepperFileRefHost();
+ ~PepperFileRefHost() override;
// ResourceHost overrides.
- virtual int32_t OnResourceMessageReceived(
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
- virtual bool IsFileRefHost() OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
+ bool IsFileRefHost() override;
// Required to support Rename().
PP_FileSystemType GetFileSystemType() const;
- fileapi::FileSystemURL GetFileSystemURL() const;
+ storage::FileSystemURL GetFileSystemURL() const;
// Required to support FileIO.
base::FilePath GetExternalFilePath() const;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
index 5eec4105002..d5f1da50f86 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "content/browser/renderer_host/pepper/pepper_file_io_host.h"
#include "content/browser/renderer_host/pepper/quota_reservation.h"
+#include "content/common/pepper_file_util.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/plugin_service.h"
@@ -21,11 +22,11 @@
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/file_system_util.h"
#include "ppapi/shared_impl/file_type_conversion.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
-#include "webkit/common/fileapi/file_system_util.h"
-#include "webkit/common/quota/quota_types.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/fileapi/file_system_util.h"
+#include "storage/common/quota/quota_types.h"
namespace content {
@@ -34,7 +35,7 @@ namespace {
// This is the minimum amount of quota we reserve per file system.
const int64_t kMinimumQuotaReservationSize = 1024 * 1024; // 1 MB
-scoped_refptr<fileapi::FileSystemContext> GetFileSystemContextFromRenderId(
+scoped_refptr<storage::FileSystemContext> GetFileSystemContextFromRenderId(
int render_process_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
@@ -117,7 +118,7 @@ bool PepperFileSystemBrowserHost::IsFileSystemHost() { return true; }
void PepperFileSystemBrowserHost::OpenQuotaFile(
PepperFileIOHost* file_io_host,
- const fileapi::FileSystemURL& url,
+ const storage::FileSystemURL& url,
const OpenQuotaFileCallback& callback) {
int32_t id = file_io_host->pp_resource();
std::pair<FileMap::iterator, bool> insert_result =
@@ -162,9 +163,9 @@ int32_t PepperFileSystemBrowserHost::OnHostMsgOpen(
return PP_ERROR_INPROGRESS;
called_open_ = true;
- fileapi::FileSystemType file_system_type =
- ppapi::PepperFileSystemTypeToFileSystemType(type_);
- if (file_system_type == fileapi::kFileSystemTypeUnknown)
+ storage::FileSystemType file_system_type =
+ PepperFileSystemTypeToFileSystemType(type_);
+ if (file_system_type == storage::kFileSystemTypeUnknown)
return PP_ERROR_FAILED;
int render_process_id = 0;
@@ -187,7 +188,7 @@ int32_t PepperFileSystemBrowserHost::OnHostMsgOpen(
void PepperFileSystemBrowserHost::OpenExistingFileSystem(
const base::Closure& callback,
- scoped_refptr<fileapi::FileSystemContext> file_system_context) {
+ scoped_refptr<storage::FileSystemContext> file_system_context) {
if (file_system_context.get()) {
opened_ = true;
} else {
@@ -206,8 +207,8 @@ void PepperFileSystemBrowserHost::OpenExistingFileSystem(
void PepperFileSystemBrowserHost::OpenFileSystem(
ppapi::host::ReplyMessageContext reply_context,
- fileapi::FileSystemType file_system_type,
- scoped_refptr<fileapi::FileSystemContext> file_system_context) {
+ storage::FileSystemType file_system_type,
+ scoped_refptr<storage::FileSystemContext> file_system_context) {
if (!file_system_context.get()) {
OpenFileSystemComplete(
reply_context, GURL(), std::string(), base::File::FILE_ERROR_FAILED);
@@ -221,7 +222,7 @@ void PepperFileSystemBrowserHost::OpenFileSystem(
file_system_context_->OpenFileSystem(
origin,
file_system_type,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(&PepperFileSystemBrowserHost::OpenFileSystemComplete,
weak_factory_.GetWeakPtr(),
reply_context));
@@ -253,14 +254,14 @@ void PepperFileSystemBrowserHost::OpenIsolatedFileSystem(
ppapi::host::ReplyMessageContext reply_context,
const std::string& fsid,
PP_IsolatedFileSystemType_Private type,
- scoped_refptr<fileapi::FileSystemContext> file_system_context) {
+ scoped_refptr<storage::FileSystemContext> file_system_context) {
if (!file_system_context.get()) {
SendReplyForIsolatedFileSystem(reply_context, fsid, PP_ERROR_FAILED);
return;
}
SetFileSystemContext(file_system_context);
- root_url_ = GURL(fileapi::GetIsolatedFileSystemRootURIString(
+ root_url_ = GURL(storage::GetIsolatedFileSystemRootURIString(
browser_ppapi_host_->GetDocumentURLForInstance(pp_instance()).GetOrigin(),
fsid,
ppapi::IsolatedFileSystemTypeToRootName(type)));
@@ -287,7 +288,7 @@ void PepperFileSystemBrowserHost::OpenIsolatedFileSystem(
void PepperFileSystemBrowserHost::OpenPluginPrivateFileSystem(
ppapi::host::ReplyMessageContext reply_context,
const std::string& fsid,
- scoped_refptr<fileapi::FileSystemContext> file_system_context) {
+ scoped_refptr<storage::FileSystemContext> file_system_context) {
GURL origin =
browser_ppapi_host_->GetDocumentURLForInstance(pp_instance()).GetOrigin();
if (!origin.is_valid()) {
@@ -303,10 +304,10 @@ void PepperFileSystemBrowserHost::OpenPluginPrivateFileSystem(
file_system_context->OpenPluginPrivateFileSystem(
origin,
- fileapi::kFileSystemTypePluginPrivate,
+ storage::kFileSystemTypePluginPrivate,
fsid,
plugin_id,
- fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
+ storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
base::Bind(
&PepperFileSystemBrowserHost::OpenPluginPrivateFileSystemComplete,
weak_factory_.GetWeakPtr(),
@@ -334,18 +335,18 @@ int32_t PepperFileSystemBrowserHost::OnHostMsgInitIsolatedFileSystem(
called_open_ = true;
// Do a sanity check.
- if (!fileapi::ValidateIsolatedFileSystemId(fsid))
+ if (!storage::ValidateIsolatedFileSystemId(fsid))
return PP_ERROR_BADARGUMENT;
int render_process_id = 0;
int unused;
if (!browser_ppapi_host_->GetRenderFrameIDsForInstance(
pp_instance(), &render_process_id, &unused)) {
- fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
+ storage::IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
return PP_ERROR_FAILED;
}
- root_url_ = GURL(fileapi::GetIsolatedFileSystemRootURIString(
+ root_url_ = GURL(storage::GetIsolatedFileSystemRootURIString(
browser_ppapi_host_->GetDocumentURLForInstance(pp_instance()).GetOrigin(),
fsid,
ppapi::IsolatedFileSystemTypeToRootName(type)));
@@ -400,14 +401,14 @@ void PepperFileSystemBrowserHost::SendReplyForIsolatedFileSystem(
const std::string& fsid,
int32_t error) {
if (error != PP_OK)
- fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
+ storage::IsolatedContext::GetInstance()->RevokeFileSystem(fsid);
reply_context.params.set_result(error);
host()->SendReply(reply_context,
PpapiPluginMsg_FileSystem_InitIsolatedFileSystemReply());
}
void PepperFileSystemBrowserHost::SetFileSystemContext(
- scoped_refptr<fileapi::FileSystemContext> file_system_context) {
+ scoped_refptr<storage::FileSystemContext> file_system_context) {
file_system_context_ = file_system_context;
if (type_ != PP_FILESYSTEMTYPE_EXTERNAL || root_url_.is_valid()) {
file_system_operation_runner_ =
@@ -421,15 +422,15 @@ bool PepperFileSystemBrowserHost::ShouldCreateQuotaReservation() const {
return false;
// For file system types with quota, some origins have unlimited storage.
- quota::QuotaManagerProxy* quota_manager_proxy =
+ storage::QuotaManagerProxy* quota_manager_proxy =
file_system_context_->quota_manager_proxy();
CHECK(quota_manager_proxy);
CHECK(quota_manager_proxy->quota_manager());
- fileapi::FileSystemType file_system_type =
- ppapi::PepperFileSystemTypeToFileSystemType(type_);
+ storage::FileSystemType file_system_type =
+ PepperFileSystemTypeToFileSystemType(type_);
return !quota_manager_proxy->quota_manager()->IsStorageUnlimited(
root_url_.GetOrigin(),
- fileapi::FileSystemTypeToQuotaStorageType(file_system_type));
+ storage::FileSystemTypeToQuotaStorageType(file_system_type));
}
void PepperFileSystemBrowserHost::CreateQuotaReservation(
@@ -441,7 +442,7 @@ void PepperFileSystemBrowserHost::CreateQuotaReservation(
base::Bind(&QuotaReservation::Create,
file_system_context_,
root_url_.GetOrigin(),
- ppapi::PepperFileSystemTypeToFileSystemType(type_)),
+ PepperFileSystemTypeToFileSystemType(type_)),
base::Bind(&PepperFileSystemBrowserHost::GotQuotaReservation,
weak_factory_.GetWeakPtr(),
callback));
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h b/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h
index f6f75fb9aa5..669adde14c7 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h
@@ -19,8 +19,8 @@
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/resource_host.h"
#include "ppapi/shared_impl/file_growth.h"
+#include "storage/browser/fileapi/file_system_context.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_context.h"
namespace content {
@@ -37,7 +37,7 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost
PP_Instance instance,
PP_Resource resource,
PP_FileSystemType type);
- virtual ~PepperFileSystemBrowserHost();
+ ~PepperFileSystemBrowserHost() override;
// Opens the PepperFileSystemBrowserHost to use an existing file system at the
// given |root_url|. The file system at |root_url| must already be opened and
@@ -46,30 +46,30 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost
void OpenExisting(const GURL& root_url, const base::Closure& callback);
// ppapi::host::ResourceHost overrides.
- virtual int32_t OnResourceMessageReceived(
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
- virtual bool IsFileSystemHost() OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
+ bool IsFileSystemHost() override;
// Supports FileRefs direct access on the host side.
PP_FileSystemType GetType() const { return type_; }
bool IsOpened() const { return opened_; }
GURL GetRootUrl() const { return root_url_; }
- scoped_refptr<fileapi::FileSystemContext> GetFileSystemContext() const {
+ scoped_refptr<storage::FileSystemContext> GetFileSystemContext() const {
return file_system_context_;
}
// Supports FileIOs direct access on the host side.
// Non-NULL only for PP_FILESYSTEMTYPE_LOCAL{PERSISTENT,TEMPORARY}.
- fileapi::FileSystemOperationRunner* GetFileSystemOperationRunner() const {
+ storage::FileSystemOperationRunner* GetFileSystemOperationRunner() const {
return file_system_operation_runner_.get();
}
- bool ChecksQuota() const { return quota_reservation_ != NULL; }
+ bool ChecksQuota() const { return quota_reservation_.get() != NULL; }
// Opens a file for writing with quota checks. Returns the file size in the
// callback.
typedef base::Callback<void(int64_t)> OpenQuotaFileCallback;
void OpenQuotaFile(PepperFileIOHost* file_io_host,
- const fileapi::FileSystemURL& url,
+ const storage::FileSystemURL& url,
const OpenQuotaFileCallback& callback);
// Closes the file. This must be called after OpenQuotaFile and before the
// PepperFileIOHost is destroyed.
@@ -81,11 +81,11 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost
void OpenExistingFileSystem(
const base::Closure& callback,
- scoped_refptr<fileapi::FileSystemContext> file_system_context);
+ scoped_refptr<storage::FileSystemContext> file_system_context);
void OpenFileSystem(
ppapi::host::ReplyMessageContext reply_context,
- fileapi::FileSystemType file_system_type,
- scoped_refptr<fileapi::FileSystemContext> file_system_context);
+ storage::FileSystemType file_system_type,
+ scoped_refptr<storage::FileSystemContext> file_system_context);
void OpenFileSystemComplete(ppapi::host::ReplyMessageContext reply_context,
const GURL& root,
const std::string& name,
@@ -94,11 +94,11 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost
ppapi::host::ReplyMessageContext reply_context,
const std::string& fsid,
PP_IsolatedFileSystemType_Private type,
- scoped_refptr<fileapi::FileSystemContext> file_system_context);
+ scoped_refptr<storage::FileSystemContext> file_system_context);
void OpenPluginPrivateFileSystem(
ppapi::host::ReplyMessageContext reply_context,
const std::string& fsid,
- scoped_refptr<fileapi::FileSystemContext> file_system_context);
+ scoped_refptr<storage::FileSystemContext> file_system_context);
void OpenPluginPrivateFileSystemComplete(
ppapi::host::ReplyMessageContext reply_context,
const std::string& fsid,
@@ -122,7 +122,7 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost
int32_t error);
void SetFileSystemContext(
- scoped_refptr<fileapi::FileSystemContext> file_system_context);
+ scoped_refptr<storage::FileSystemContext> file_system_context);
bool ShouldCreateQuotaReservation() const;
void CreateQuotaReservation(const base::Closure& callback);
@@ -147,9 +147,9 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost
bool called_open_; // whether open has been called.
bool opened_; // whether open succeeded.
GURL root_url_;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
- scoped_ptr<fileapi::FileSystemOperationRunner> file_system_operation_runner_;
+ scoped_ptr<storage::FileSystemOperationRunner> file_system_operation_runner_;
// Used only for file systems with quota.
// When a PepperFileIOHost calls OpenQuotaFile, we add the id and a non-owning
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host_unittest.cc b/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host_unittest.cc
index 8aa144cf426..ccc9c610d21 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_file_system_browser_host_unittest.cc
@@ -19,9 +19,9 @@ class PepperFileSystemBrowserHostTest : public testing::Test,
public BrowserPpapiHostTest {
public:
PepperFileSystemBrowserHostTest() {}
- virtual ~PepperFileSystemBrowserHostTest() {}
+ ~PepperFileSystemBrowserHostTest() override {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
PP_Instance pp_instance = 12345;
PP_Resource pp_resource = 67890;
host_.reset(new PepperFileSystemBrowserHost(GetBrowserPpapiHost(),
@@ -30,7 +30,7 @@ class PepperFileSystemBrowserHostTest : public testing::Test,
PP_FILESYSTEMTYPE_ISOLATED));
}
- virtual void TearDown() OVERRIDE { host_.reset(); }
+ void TearDown() override { host_.reset(); }
protected:
std::string GeneratePluginId(const std::string& mime_type) {
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 d4413b20c9c..5452bafc09c 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
@@ -5,9 +5,9 @@
#include "content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h"
#include "base/bind.h"
-#include "base/file_util.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
#include "base/threading/sequenced_worker_pool.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/renderer_host/pepper/pepper_security_helper.h"
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h
index ab21076262b..301f97e9632 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h
@@ -43,14 +43,14 @@ class PepperFlashFileMessageFilter : public ppapi::host::ResourceMessageFilter {
typedef base::Callback<bool(int, const base::FilePath&)>
CheckPermissionsCallback;
- virtual ~PepperFlashFileMessageFilter();
+ ~PepperFlashFileMessageFilter() override;
// ppapi::host::ResourceMessageFilter overrides.
- virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
- const IPC::Message& msg) OVERRIDE;
- virtual int32_t OnResourceMessageReceived(
+ scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) override;
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
int32_t OnOpenFile(ppapi::host::HostMessageContext* context,
const ppapi::PepperFilePath& path,
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h b/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h
index c9f2c18fbc6..8d6ee7346fa 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host.h
@@ -37,19 +37,17 @@ class CONTENT_EXPORT PepperGamepadHost :
PP_Instance instance,
PP_Resource resource);
- virtual ~PepperGamepadHost();
+ ~PepperGamepadHost() override;
- virtual int32_t OnResourceMessageReceived(
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
// GamepadConsumer implementation.
- virtual void OnGamepadConnected(
- unsigned index,
- const blink::WebGamepad& gamepad) OVERRIDE {}
- virtual void OnGamepadDisconnected(
- unsigned index,
- const blink::WebGamepad& gamepad) OVERRIDE {}
+ void OnGamepadConnected(unsigned index,
+ const blink::WebGamepad& gamepad) override {}
+ void OnGamepadDisconnected(unsigned index,
+ const blink::WebGamepad& gamepad) override {}
private:
int32_t OnRequestMemory(ppapi::host::HostMessageContext* context);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc b/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc
index f86c944a46d..b5787e170b5 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_gamepad_host_unittest.cc
@@ -26,7 +26,7 @@ class PepperGamepadHostTest : public testing::Test,
public BrowserPpapiHostTest {
public:
PepperGamepadHostTest() {}
- virtual ~PepperGamepadHostTest() {}
+ ~PepperGamepadHostTest() override {}
void ConstructService(const blink::WebGamepads& test_data) {
service_.reset(new GamepadServiceTestConstructor(test_data));
@@ -140,29 +140,19 @@ TEST_F(PepperGamepadHostTest, WaitForReply) {
gamepad_host.OnResourceMessageReceived(
PpapiHostMsg_Gamepad_RequestMemory(), &context));
- // Wait for the gamepad background thread to read twice to make sure we
- // don't get a message yet (see below for why).
MockGamepadDataFetcher* fetcher = service_->data_fetcher();
- fetcher->WaitForDataRead();
- fetcher->WaitForDataRead();
+ fetcher->WaitForDataReadAndCallbacksIssued();
// It should not have sent the callback message.
service_->message_loop().RunUntilIdle();
EXPECT_EQ(0u, sink().message_count());
// Set a button down and wait for it to be read twice.
- //
- // We wait for two reads before calling RunAllPending because the provider
- // will read the data on the background thread (setting the event) and *then*
- // will issue the callback on our thread. Waiting for it to read twice
- // ensures that it was able to issue callbacks for the first read (if it
- // issued one) before we try to check for it.
blink::WebGamepads button_down_data = default_data;
button_down_data.items[0].buttons[0].value = 1.f;
button_down_data.items[0].buttons[0].pressed = true;
fetcher->SetTestData(button_down_data);
- fetcher->WaitForDataRead();
- fetcher->WaitForDataRead();
+ fetcher->WaitForDataReadAndCallbacksIssued();
// It should have sent a callback.
service_->message_loop().RunUntilIdle();
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h
index 8fb404df4e3..a5321845b8a 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h
@@ -43,17 +43,17 @@ class CONTENT_EXPORT PepperHostResolverMessageFilter
bool private_api);
protected:
- virtual ~PepperHostResolverMessageFilter();
+ ~PepperHostResolverMessageFilter() override;
private:
typedef std::vector<PP_NetAddress_Private> NetAddressList;
// ppapi::host::ResourceMessageFilter overrides.
- virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
- const IPC::Message& message) OVERRIDE;
- virtual int32_t OnResourceMessageReceived(
+ scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
int32_t OnMsgResolve(const ppapi::host::HostMessageContext* context,
const ppapi::HostPortPair& host_port,
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 bc7f2b6a119..ddab7c00822 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
@@ -7,7 +7,7 @@
#include <string>
#include "base/callback.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/file_util_proxy.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
@@ -33,10 +33,10 @@
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_file_ref_api.h"
#include "ppapi/thunk/ppb_file_system_api.h"
-#include "webkit/browser/fileapi/file_system_operation.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/common/fileapi/file_system_util.h"
+#include "storage/browser/fileapi/file_system_operation.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "storage/common/fileapi/file_system_util.h"
using ppapi::host::PpapiHost;
using ppapi::host::ResourceHost;
@@ -59,11 +59,11 @@ PepperInternalFileRefBackend::PepperInternalFileRefBackend(
PepperInternalFileRefBackend::~PepperInternalFileRefBackend() {}
-fileapi::FileSystemURL PepperInternalFileRefBackend::GetFileSystemURL() const {
+storage::FileSystemURL PepperInternalFileRefBackend::GetFileSystemURL() const {
if (!fs_url_.is_valid() && fs_host_.get() && fs_host_->IsOpened()) {
GURL fs_path =
fs_host_->GetRootUrl().Resolve(net::EscapePath(path_.substr(1)));
- scoped_refptr<fileapi::FileSystemContext> fs_context =
+ scoped_refptr<storage::FileSystemContext> fs_context =
GetFileSystemContext();
if (fs_context.get())
fs_url_ = fs_context->CrackURL(fs_path);
@@ -75,7 +75,7 @@ base::FilePath PepperInternalFileRefBackend::GetExternalFilePath() const {
return base::FilePath();
}
-scoped_refptr<fileapi::FileSystemContext>
+scoped_refptr<storage::FileSystemContext>
PepperInternalFileRefBackend::GetFileSystemContext() const {
if (!fs_host_.get())
return NULL;
@@ -146,7 +146,7 @@ int32_t PepperInternalFileRefBackend::Rename(
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
- fileapi::FileSystemURL new_url = new_file_ref->GetFileSystemURL();
+ storage::FileSystemURL new_url = new_file_ref->GetFileSystemURL();
if (!new_url.is_valid())
return PP_ERROR_FAILED;
if (!new_url.IsInSameFileSystem(GetFileSystemURL()))
@@ -155,7 +155,7 @@ int32_t PepperInternalFileRefBackend::Rename(
GetFileSystemContext()->operation_runner()->Move(
GetFileSystemURL(),
new_url,
- fileapi::FileSystemOperation::OPTION_NONE,
+ storage::FileSystemOperation::OPTION_NONE,
base::Bind(&PepperInternalFileRefBackend::DidFinish,
weak_factory_.GetWeakPtr(),
reply_context,
@@ -197,8 +197,8 @@ int32_t PepperInternalFileRefBackend::ReadDirectoryEntries(
if (!GetFileSystemURL().is_valid())
return PP_ERROR_FAILED;
- fileapi::FileSystemOperation::FileEntryList* accumulated_file_list =
- new fileapi::FileSystemOperation::FileEntryList;
+ storage::FileSystemOperation::FileEntryList* accumulated_file_list =
+ new storage::FileSystemOperation::FileEntryList;
GetFileSystemContext()->operation_runner()->ReadDirectory(
GetFileSystemURL(),
base::Bind(&PepperInternalFileRefBackend::ReadDirectoryComplete,
@@ -210,9 +210,9 @@ int32_t PepperInternalFileRefBackend::ReadDirectoryEntries(
void PepperInternalFileRefBackend::ReadDirectoryComplete(
ppapi::host::ReplyMessageContext context,
- fileapi::FileSystemOperation::FileEntryList* accumulated_file_list,
+ storage::FileSystemOperation::FileEntryList* accumulated_file_list,
base::File::Error error,
- const fileapi::FileSystemOperation::FileEntryList& file_list,
+ const storage::FileSystemOperation::FileEntryList& file_list,
bool has_more) {
accumulated_file_list->insert(
accumulated_file_list->end(), file_list.begin(), file_list.end());
@@ -228,7 +228,7 @@ void PepperInternalFileRefBackend::ReadDirectoryComplete(
if (dir_path.empty() || dir_path[dir_path.size() - 1] != '/')
dir_path += '/';
- for (fileapi::FileSystemOperation::FileEntryList::const_iterator it =
+ for (storage::FileSystemOperation::FileEntryList::const_iterator it =
accumulated_file_list->begin();
it != accumulated_file_list->end();
++it) {
@@ -241,7 +241,7 @@ void PepperInternalFileRefBackend::ReadDirectoryComplete(
info.file_system_type = fs_type_;
info.file_system_plugin_resource = fs_host_->pp_resource();
std::string path =
- dir_path + fileapi::FilePathToString(base::FilePath(it->name));
+ dir_path + storage::FilePathToString(base::FilePath(it->name));
info.internal_path = path;
info.display_name = ppapi::GetNameForInternalFilePath(path);
infos.push_back(info);
@@ -261,7 +261,7 @@ int32_t PepperInternalFileRefBackend::GetAbsolutePath(
}
int32_t PepperInternalFileRefBackend::CanRead() const {
- fileapi::FileSystemURL url = GetFileSystemURL();
+ storage::FileSystemURL url = GetFileSystemURL();
if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
return PP_ERROR_FAILED;
if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFileSystemFile(
@@ -272,7 +272,7 @@ int32_t PepperInternalFileRefBackend::CanRead() const {
}
int32_t PepperInternalFileRefBackend::CanWrite() const {
- fileapi::FileSystemURL url = GetFileSystemURL();
+ storage::FileSystemURL url = GetFileSystemURL();
if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
return PP_ERROR_FAILED;
if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanWriteFileSystemFile(
@@ -283,7 +283,7 @@ int32_t PepperInternalFileRefBackend::CanWrite() const {
}
int32_t PepperInternalFileRefBackend::CanCreate() const {
- fileapi::FileSystemURL url = GetFileSystemURL();
+ storage::FileSystemURL url = GetFileSystemURL();
if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
return PP_ERROR_FAILED;
if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanCreateFileSystemFile(
@@ -294,7 +294,7 @@ int32_t PepperInternalFileRefBackend::CanCreate() const {
}
int32_t PepperInternalFileRefBackend::CanReadWrite() const {
- fileapi::FileSystemURL url = GetFileSystemURL();
+ storage::FileSystemURL url = GetFileSystemURL();
if (!FileSystemURLIsValid(GetFileSystemContext().get(), url))
return PP_ERROR_FAILED;
ChildProcessSecurityPolicyImpl* policy =
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h b/chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h
index 4214de01785..e210763c810 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h
@@ -12,9 +12,9 @@
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/pp_time.h"
#include "ppapi/host/ppapi_host.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation.h"
-#include "webkit/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/fileapi/file_system_operation.h"
+#include "storage/browser/fileapi/file_system_url.h"
namespace content {
@@ -28,29 +28,28 @@ class PepperInternalFileRefBackend : public PepperFileRefBackend {
int render_process_id,
base::WeakPtr<PepperFileSystemBrowserHost> fs_host,
const std::string& path);
- virtual ~PepperInternalFileRefBackend();
+ ~PepperInternalFileRefBackend() override;
// PepperFileRefBackend overrides.
- virtual int32_t MakeDirectory(ppapi::host::ReplyMessageContext context,
- int32_t make_directory_flags) OVERRIDE;
- virtual int32_t Touch(ppapi::host::ReplyMessageContext context,
- PP_Time last_accessed_time,
- PP_Time last_modified_time) OVERRIDE;
- virtual int32_t Delete(ppapi::host::ReplyMessageContext context) OVERRIDE;
- virtual int32_t Rename(ppapi::host::ReplyMessageContext context,
- PepperFileRefHost* new_file_ref) OVERRIDE;
- virtual int32_t Query(ppapi::host::ReplyMessageContext context) OVERRIDE;
- virtual int32_t ReadDirectoryEntries(ppapi::host::ReplyMessageContext context)
- OVERRIDE;
- virtual int32_t GetAbsolutePath(ppapi::host::ReplyMessageContext context)
- OVERRIDE;
- virtual fileapi::FileSystemURL GetFileSystemURL() const OVERRIDE;
- virtual base::FilePath GetExternalFilePath() const OVERRIDE;
-
- virtual int32_t CanRead() const OVERRIDE;
- virtual int32_t CanWrite() const OVERRIDE;
- virtual int32_t CanCreate() const OVERRIDE;
- virtual int32_t CanReadWrite() const OVERRIDE;
+ int32_t MakeDirectory(ppapi::host::ReplyMessageContext context,
+ int32_t make_directory_flags) override;
+ int32_t Touch(ppapi::host::ReplyMessageContext context,
+ PP_Time last_accessed_time,
+ PP_Time last_modified_time) override;
+ int32_t Delete(ppapi::host::ReplyMessageContext context) override;
+ int32_t Rename(ppapi::host::ReplyMessageContext context,
+ PepperFileRefHost* new_file_ref) override;
+ int32_t Query(ppapi::host::ReplyMessageContext context) override;
+ int32_t ReadDirectoryEntries(
+ ppapi::host::ReplyMessageContext context) override;
+ int32_t GetAbsolutePath(ppapi::host::ReplyMessageContext context) override;
+ storage::FileSystemURL GetFileSystemURL() const override;
+ base::FilePath GetExternalFilePath() const override;
+
+ int32_t CanRead() const override;
+ int32_t CanWrite() const override;
+ int32_t CanCreate() const override;
+ int32_t CanReadWrite() const override;
private:
// Generic reply callback.
@@ -64,12 +63,12 @@ class PepperInternalFileRefBackend : public PepperFileRefBackend {
const base::File::Info& file_info);
void ReadDirectoryComplete(
ppapi::host::ReplyMessageContext context,
- fileapi::FileSystemOperation::FileEntryList* accumulated_file_list,
+ storage::FileSystemOperation::FileEntryList* accumulated_file_list,
base::File::Error error,
- const fileapi::FileSystemOperation::FileEntryList& file_list,
+ const storage::FileSystemOperation::FileEntryList& file_list,
bool has_more);
- scoped_refptr<fileapi::FileSystemContext> GetFileSystemContext() const;
+ scoped_refptr<storage::FileSystemContext> GetFileSystemContext() const;
ppapi::host::PpapiHost* host_;
int render_process_id_;
@@ -77,7 +76,7 @@ class PepperInternalFileRefBackend : public PepperFileRefBackend {
PP_FileSystemType fs_type_;
std::string path_;
- mutable fileapi::FileSystemURL fs_url_;
+ mutable storage::FileSystemURL fs_url_;
base::WeakPtrFactory<PepperInternalFileRefBackend> weak_factory_;
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_message_filter.h
index 68dac47fc8d..02a89adf016 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_message_filter.h
@@ -24,10 +24,10 @@ class PepperMessageFilter : public BrowserMessageFilter {
PepperMessageFilter();
// BrowserMessageFilter methods.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
protected:
- virtual ~PepperMessageFilter();
+ ~PepperMessageFilter() override;
private:
void OnX509CertificateParseDER(const std::vector<char>& der,
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.h b/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.h
index 12241c5c5b4..71974219a19 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_network_monitor_host.h
@@ -26,10 +26,10 @@ class CONTENT_EXPORT PepperNetworkMonitorHost
PP_Instance instance,
PP_Resource resource);
- virtual ~PepperNetworkMonitorHost();
+ ~PepperNetworkMonitorHost() override;
// net::NetworkChangeNotifier::IPAddressObserver interface.
- virtual void OnIPAddressChanged() OVERRIDE;
+ void OnIPAddressChanged() override;
private:
void OnPermissionCheckResult(bool can_use_network_monitor);
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 4b3d817b66e..b80d1c6f9c3 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
@@ -11,6 +11,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/socket_permission_request.h"
+#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/proxy/proxy_info.h"
#include "net/url_request/url_request_context.h"
@@ -145,9 +146,11 @@ void PepperNetworkProxyHost::TryToSendUnsentRequests() {
request.reply_context,
base::Owned(proxy_info));
int result = proxy_service_->ResolveProxy(request.url,
+ net::LOAD_NORMAL,
proxy_info,
callback,
&pending_request,
+ NULL,
net::BoundNetLog());
pending_requests_.push(pending_request);
// If it was handled synchronously, we must run the callback now;
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 28f52b66273..eddbc89a1bd 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
@@ -37,7 +37,7 @@ class CONTENT_EXPORT PepperNetworkProxyHost : public ppapi::host::ResourceHost {
PP_Instance instance,
PP_Resource resource);
- virtual ~PepperNetworkProxyHost();
+ ~PepperNetworkProxyHost() override;
private:
// We retrieve the appropriate URLRequestContextGetter and whether this API
@@ -55,9 +55,9 @@ class CONTENT_EXPORT PepperNetworkProxyHost : public ppapi::host::ResourceHost {
void DidGetUIThreadData(const UIThreadData&);
// ResourceHost implementation.
- virtual int32_t OnResourceMessageReceived(
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
int32_t OnMsgGetProxyForURL(ppapi::host::HostMessageContext* context,
const std::string& url);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc b/chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc
index de5f5fec949..1343f9a12f6 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.cc
@@ -5,6 +5,8 @@
#include "content/browser/renderer_host/pepper/pepper_print_settings_manager.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_client.h"
#include "ppapi/c/pp_errors.h"
#include "printing/printing_context.h"
#include "printing/units.h"
@@ -13,7 +15,7 @@ namespace content {
namespace {
-#if defined(ENABLE_FULL_PRINTING)
+#if defined(ENABLE_PRINT_PREVIEW)
// Print units conversion functions.
int32_t DeviceUnitsInPoints(int32_t device_units,
int32_t device_units_per_inch) {
@@ -42,12 +44,23 @@ PP_Rect PrintAreaToPPPrintArea(const gfx::Rect& print_area,
return result;
}
+class PrintingContextDelegate : public printing::PrintingContext::Delegate {
+ public:
+ // PrintingContext::Delegate methods.
+ gfx::NativeView GetParentView() override { return NULL; }
+ std::string GetAppLocale() override {
+ return GetContentClient()->browser()->GetApplicationLocale();
+ }
+};
+
PepperPrintSettingsManager::Result ComputeDefaultPrintSettings() {
// This function should run on the UI thread because |PrintingContext| methods
// call into platform APIs.
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ PrintingContextDelegate delegate;
scoped_ptr<printing::PrintingContext> context(
- printing::PrintingContext::Create(std::string()));
+ printing::PrintingContext::Create(&delegate));
if (!context.get() ||
context->UseDefaultSettings() != printing::PrintingContext::OK) {
return PepperPrintSettingsManager::Result(PP_PrintSettings_Dev(),
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.h b/chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.h
index 48a8e9f100e..9199e72655b 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_print_settings_manager.h
@@ -32,11 +32,11 @@ class CONTENT_EXPORT PepperPrintSettingsManagerImpl
: public PepperPrintSettingsManager {
public:
PepperPrintSettingsManagerImpl() {}
- virtual ~PepperPrintSettingsManagerImpl() {}
+ ~PepperPrintSettingsManagerImpl() override {}
// PepperPrintSettingsManager implementation.
- virtual void GetDefaultPrintSettings(
- PepperPrintSettingsManager::Callback callback) OVERRIDE;
+ void GetDefaultPrintSettings(
+ PepperPrintSettingsManager::Callback callback) override;
private:
DISALLOW_COPY_AND_ASSIGN(PepperPrintSettingsManagerImpl);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_printing_host.h b/chromium/content/browser/renderer_host/pepper/pepper_printing_host.h
index ec956292b2d..fb2536d9945 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_printing_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_printing_host.h
@@ -22,12 +22,12 @@ class CONTENT_EXPORT PepperPrintingHost : public ppapi::host::ResourceHost {
PP_Instance instance,
PP_Resource resource,
scoped_ptr<PepperPrintSettingsManager> print_settings_manager);
- virtual ~PepperPrintingHost();
+ ~PepperPrintingHost() override;
// ppapi::host::ResourceHost implementation.
- virtual int32_t OnResourceMessageReceived(
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
private:
int32_t OnGetDefaultPrintSettings(ppapi::host::HostMessageContext* context);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_printing_host_unittest.cc b/chromium/content/browser/renderer_host/pepper/pepper_printing_host_unittest.cc
index d9780425d20..36b006c8075 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_printing_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_printing_host_unittest.cc
@@ -21,11 +21,11 @@ namespace {
class MockPepperPrintSettingsManager : public PepperPrintSettingsManager {
public:
MockPepperPrintSettingsManager(const PP_PrintSettings_Dev& settings);
- virtual ~MockPepperPrintSettingsManager() {}
+ ~MockPepperPrintSettingsManager() override {}
// PepperPrintSettingsManager implementation.
- virtual void GetDefaultPrintSettings(
- PepperPrintSettingsManager::Callback callback) OVERRIDE;
+ void GetDefaultPrintSettings(
+ PepperPrintSettingsManager::Callback callback) override;
private:
PP_PrintSettings_Dev settings_;
@@ -47,7 +47,7 @@ class PepperPrintingHostTest : public testing::Test,
public:
PepperPrintingHostTest() {}
- virtual ~PepperPrintingHostTest() {}
+ ~PepperPrintingHostTest() override {}
DISALLOW_COPY_AND_ASSIGN(PepperPrintingHostTest);
};
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.h b/chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.h
index 5683ab9ed0c..109da1f2856 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_renderer_connection.h
@@ -36,10 +36,10 @@ class PepperRendererConnection : public BrowserMessageFilter {
explicit PepperRendererConnection(int render_process_id);
// BrowserMessageFilter overrides.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
private:
- virtual ~PepperRendererConnection();
+ ~PepperRendererConnection() override;
// Returns the host for the child process for the given |child_process_id|.
// If |child_process_id| is 0, returns the host owned by this
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_security_helper.cc b/chromium/content/browser/renderer_host/pepper/pepper_security_helper.cc
index ab516283d58..3bb92bf8b48 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_security_helper.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_security_helper.cc
@@ -77,7 +77,7 @@ bool CanOpenWithPepperFlags(int pp_open_flags,
bool CanOpenFileSystemURLWithPepperFlags(int pp_open_flags,
int child_id,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
return CanOpenFileWithPepperFlags(
&ChildProcessSecurityPolicyImpl::CanReadFileSystemFile,
&ChildProcessSecurityPolicyImpl::CanWriteFileSystemFile,
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_security_helper.h b/chromium/content/browser/renderer_host/pepper/pepper_security_helper.h
index d0a39831324..790b4cfe997 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_security_helper.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_security_helper.h
@@ -7,7 +7,7 @@
#include "base/files/file_path.h"
#include "content/common/content_export.h"
-#include "webkit/browser/fileapi/file_system_url.h"
+#include "storage/browser/fileapi/file_system_url.h"
namespace content {
@@ -22,7 +22,7 @@ CONTENT_EXPORT bool CanOpenWithPepperFlags(int pp_open_flags,
CONTENT_EXPORT bool CanOpenFileSystemURLWithPepperFlags(
int pp_open_flags,
int child_id,
- const fileapi::FileSystemURL& url);
+ const storage::FileSystemURL& url);
} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
index 43262fc8c1a..b1bc22fe627 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
@@ -41,7 +41,7 @@ class CONTENT_EXPORT PepperTCPServerSocketMessageFilter
static size_t GetNumInstances();
protected:
- virtual ~PepperTCPServerSocketMessageFilter();
+ ~PepperTCPServerSocketMessageFilter() override;
private:
enum State {
@@ -53,11 +53,11 @@ class CONTENT_EXPORT PepperTCPServerSocketMessageFilter
};
// ppapi::host::ResourceMessageFilter overrides.
- virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
- const IPC::Message& message) OVERRIDE;
- virtual int32_t OnResourceMessageReceived(
+ scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
int32_t OnMsgListen(const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& addr,
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
index 5c4e066b360..7c9250f4899 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
@@ -63,14 +63,14 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
static size_t GetNumInstances();
private:
- virtual ~PepperTCPSocketMessageFilter();
+ ~PepperTCPSocketMessageFilter() override;
// ppapi::host::ResourceMessageFilter overrides.
- virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
- const IPC::Message& message) OVERRIDE;
- virtual int32_t OnResourceMessageReceived(
+ scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
int32_t OnMsgBind(const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& net_addr);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font.h b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font.h
new file mode 100644
index 00000000000..f26b9bd9b79
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font.h
@@ -0,0 +1,55 @@
+// 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_RENDERER_HOST_PEPPER_PEPPER_TRUETYPE_FONT_H_
+#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_TRUETYPE_FONT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "ppapi/proxy/serialized_structs.h"
+
+namespace content {
+
+class PepperTrueTypeFont
+ : public base::RefCountedThreadSafe<PepperTrueTypeFont> {
+ public:
+ // Factory method to create a font for the current host.
+ static PepperTrueTypeFont* Create();
+
+ // Initializes the font. Updates the descriptor with the actual font's
+ // characteristics. The exact font will depend on the host platform's font
+ // matching and fallback algorithm. On failure, returns NULL and leaves desc
+ // unchanged.
+ // NOTE: This method may perform long blocking file IO.
+ virtual int32_t Initialize(
+ ppapi::proxy::SerializedTrueTypeFontDesc* desc) = 0;
+
+ // Retrieves an array of TrueType table tags contained in this font. Returns
+ // the number of tags on success, a Pepper error code on failure. 'tags' are
+ // written only on success.
+ // NOTE: This method may perform long blocking file IO. It may be called even
+ // though the call to Initialize failed. Implementors must check validity.
+ virtual int32_t GetTableTags(std::vector<uint32_t>* tags) = 0;
+
+ // Gets a TrueType font table corresponding to the given tag. The 'offset' and
+ // 'max_data_length' parameters determine what part of the table is returned.
+ // Returns the data size in bytes on success, a Pepper error code on failure.
+ // 'data' is written only on success.
+ // NOTE: This method may perform long blocking file IO. It may be called even
+ // though the call to Initialize failed. Implementors must check validity.
+ virtual int32_t GetTable(uint32_t table_tag,
+ int32_t offset,
+ int32_t max_data_length,
+ std::string* data) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<PepperTrueTypeFont>;
+ virtual ~PepperTrueTypeFont() {};
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_TRUETYPE_FONT_H_
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_android.cc b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_android.cc
new file mode 100644
index 00000000000..d259aae2526
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_android.cc
@@ -0,0 +1,16 @@
+// 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 "base/logging.h"
+#include "content/browser/renderer_host/pepper/pepper_truetype_font.h"
+
+namespace content {
+
+// static
+PepperTrueTypeFont* PepperTrueTypeFont::Create() {
+ NOTIMPLEMENTED(); // Not implemented on Android.
+ return NULL;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc
new file mode 100644
index 00000000000..060a0e68b40
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.cc
@@ -0,0 +1,159 @@
+// 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/renderer_host/pepper/pepper_truetype_font_host.h"
+
+#include "base/bind.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "content/browser/renderer_host/pepper/pepper_truetype_font.h"
+#include "content/public/browser/browser_ppapi_host.h"
+#include "content/public/browser/browser_thread.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/host/ppapi_host.h"
+#include "ppapi/proxy/ppapi_messages.h"
+
+using ppapi::host::HostMessageContext;
+using ppapi::host::ReplyMessageContext;
+using ppapi::proxy::SerializedTrueTypeFontDesc;
+
+namespace content {
+
+PepperTrueTypeFontHost::PepperTrueTypeFontHost(
+ BrowserPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource,
+ const SerializedTrueTypeFontDesc& desc)
+ : ResourceHost(host->GetPpapiHost(), instance, resource),
+ initialize_completed_(false),
+ weak_factory_(this) {
+ font_ = PepperTrueTypeFont::Create();
+ // Initialize the font on a blocking pool thread. This must complete before
+ // using |font_|.
+ base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
+ task_runner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken());
+ SerializedTrueTypeFontDesc* actual_desc =
+ new SerializedTrueTypeFontDesc(desc);
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&PepperTrueTypeFont::Initialize, font_, actual_desc),
+ base::Bind(&PepperTrueTypeFontHost::OnInitializeComplete,
+ weak_factory_.GetWeakPtr(),
+ base::Owned(actual_desc)));
+}
+
+PepperTrueTypeFontHost::~PepperTrueTypeFontHost() {
+ if (font_.get()) {
+ // Release the font on the task runner in case the implementation requires
+ // long blocking operations.
+ font_->AddRef();
+ PepperTrueTypeFont* raw_font = font_.get();
+ font_ = NULL;
+ task_runner_->ReleaseSoon(FROM_HERE, raw_font);
+ }
+}
+
+int32_t PepperTrueTypeFontHost::OnResourceMessageReceived(
+ const IPC::Message& msg,
+ HostMessageContext* context) {
+ if (!host()->permissions().HasPermission(ppapi::PERMISSION_DEV))
+ return PP_ERROR_FAILED;
+
+ PPAPI_BEGIN_MESSAGE_MAP(PepperTrueTypeFontHost, msg)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_TrueTypeFont_GetTableTags,
+ OnHostMsgGetTableTags)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_TrueTypeFont_GetTable,
+ OnHostMsgGetTable)
+ PPAPI_END_MESSAGE_MAP()
+ return PP_ERROR_FAILED;
+}
+
+int32_t PepperTrueTypeFontHost::OnHostMsgGetTableTags(
+ HostMessageContext* context) {
+ if (!font_.get())
+ return PP_ERROR_FAILED;
+
+ // Get font data on a thread that allows slow blocking operations.
+ std::vector<uint32_t>* tags = new std::vector<uint32_t>();
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&PepperTrueTypeFont::GetTableTags, font_, tags),
+ base::Bind(&PepperTrueTypeFontHost::OnGetTableTagsComplete,
+ weak_factory_.GetWeakPtr(),
+ base::Owned(tags),
+ context->MakeReplyMessageContext()));
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperTrueTypeFontHost::OnHostMsgGetTable(HostMessageContext* context,
+ uint32_t table,
+ int32_t offset,
+ int32_t max_data_length) {
+ if (!font_.get())
+ return PP_ERROR_FAILED;
+ if (offset < 0 || max_data_length < 0)
+ return PP_ERROR_BADARGUMENT;
+
+ // Get font data on a thread that allows slow blocking operations.
+ std::string* data = new std::string();
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&PepperTrueTypeFont::GetTable,
+ font_,
+ table,
+ offset,
+ max_data_length,
+ data),
+ base::Bind(&PepperTrueTypeFontHost::OnGetTableComplete,
+ weak_factory_.GetWeakPtr(),
+ base::Owned(data),
+ context->MakeReplyMessageContext()));
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void PepperTrueTypeFontHost::OnInitializeComplete(
+ SerializedTrueTypeFontDesc* desc,
+ int32_t result) {
+ DCHECK(!initialize_completed_);
+ initialize_completed_ = true;
+ // Release the font if there was an error, so future calls will fail.
+ if (result != PP_OK)
+ font_ = NULL;
+ host()->SendUnsolicitedReply(
+ pp_resource(), PpapiPluginMsg_TrueTypeFont_CreateReply(*desc, result));
+}
+
+void PepperTrueTypeFontHost::OnGetTableTagsComplete(
+ std::vector<uint32_t>* tags,
+ ReplyMessageContext reply_context,
+ int32_t result) {
+ DCHECK(initialize_completed_);
+ // It's possible that Initialize failed and that |font_| is NULL. Check that
+ // the font implementation doesn't return PP_OK in that case.
+ DCHECK(font_.get() || result != PP_OK);
+ reply_context.params.set_result(result);
+ host()->SendReply(reply_context,
+ PpapiPluginMsg_TrueTypeFont_GetTableTagsReply(*tags));
+}
+
+void PepperTrueTypeFontHost::OnGetTableComplete(
+ std::string* data,
+ ReplyMessageContext reply_context,
+ int32_t result) {
+ DCHECK(initialize_completed_);
+ // It's possible that Initialize failed and that |font_| is NULL. Check that
+ // the font implementation doesn't return PP_OK in that case.
+ DCHECK(font_.get() || result != PP_OK);
+ reply_context.params.set_result(result);
+ host()->SendReply(reply_context,
+ PpapiPluginMsg_TrueTypeFont_GetTableReply(*data));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.h b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.h
new file mode 100644
index 00000000000..b449547010a
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_host.h
@@ -0,0 +1,69 @@
+// 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_RENDERER_HOST_PEPPER_PEPPER_TRUETYPE_FONT_HOST_H_
+#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_TRUETYPE_FONT_HOST_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "content/browser/renderer_host/pepper/pepper_truetype_font.h"
+#include "content/common/content_export.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/host/resource_host.h"
+
+namespace content {
+
+class BrowserPpapiHost;
+
+class CONTENT_EXPORT PepperTrueTypeFontHost : public ppapi::host::ResourceHost {
+ public:
+ PepperTrueTypeFontHost(BrowserPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource,
+ const ppapi::proxy::SerializedTrueTypeFontDesc& desc);
+
+ ~PepperTrueTypeFontHost() override;
+
+ int32_t OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) override;
+
+ private:
+ int32_t OnHostMsgGetTableTags(ppapi::host::HostMessageContext* context);
+ int32_t OnHostMsgGetTable(ppapi::host::HostMessageContext* context,
+ uint32_t table,
+ int32_t offset,
+ int32_t max_data_length);
+
+ void OnInitializeComplete(ppapi::proxy::SerializedTrueTypeFontDesc* desc,
+ int32_t result);
+ void OnGetTableTagsComplete(std::vector<uint32_t>* tags,
+ ppapi::host::ReplyMessageContext reply_context,
+ int32_t result);
+ void OnGetTableComplete(std::string* data,
+ ppapi::host::ReplyMessageContext reply_context,
+ int32_t result);
+
+ // We use a SequencedTaskRunner to run potentially slow font operations and
+ // ensure that Initialize completes before we make any calls to get font data.
+ // Even though we allow multiple pending GetTableTags and GetTable calls, this
+ // implies that they run serially.
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ scoped_refptr<PepperTrueTypeFont> font_;
+ bool initialize_completed_;
+
+ base::WeakPtrFactory<PepperTrueTypeFontHost> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontHost);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_TRUETYPE_FONT_HOST_H_
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_linux.cc b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_linux.cc
new file mode 100644
index 00000000000..ebfacb87b30
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_linux.cc
@@ -0,0 +1,156 @@
+// 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 "base/compiler_specific.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/sys_byteorder.h"
+#include "content/browser/renderer_host/font_utils_linux.h"
+#include "content/browser/renderer_host/pepper/pepper_truetype_font.h"
+#include "content/public/common/child_process_sandbox_support_linux.h"
+#include "ppapi/c/dev/ppb_truetype_font_dev.h"
+#include "ppapi/c/pp_errors.h"
+
+namespace content {
+
+namespace {
+
+class PepperTrueTypeFontLinux : public PepperTrueTypeFont {
+ public:
+ PepperTrueTypeFontLinux();
+
+ // PepperTrueTypeFont implementation.
+ int32_t Initialize(ppapi::proxy::SerializedTrueTypeFontDesc* desc) override;
+ int32_t GetTableTags(std::vector<uint32_t>* tags) override;
+ int32_t GetTable(uint32_t table_tag,
+ int32_t offset,
+ int32_t max_data_length,
+ std::string* data) override;
+
+ private:
+ ~PepperTrueTypeFontLinux() override;
+
+ base::ScopedFD fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontLinux);
+};
+
+PepperTrueTypeFontLinux::PepperTrueTypeFontLinux() {
+}
+
+PepperTrueTypeFontLinux::~PepperTrueTypeFontLinux() {
+}
+
+int32_t PepperTrueTypeFontLinux::Initialize(
+ ppapi::proxy::SerializedTrueTypeFontDesc* desc) {
+ // If no face is provided, convert family to the platform defaults. These
+ // names should be mapped by FontConfig to an appropriate default font.
+ if (desc->family.empty()) {
+ switch (desc->generic_family) {
+ case PP_TRUETYPEFONTFAMILY_SERIF:
+ desc->family = "serif";
+ break;
+ case PP_TRUETYPEFONTFAMILY_SANSSERIF:
+ desc->family = "sans-serif";
+ break;
+ case PP_TRUETYPEFONTFAMILY_CURSIVE:
+ desc->family = "cursive";
+ break;
+ case PP_TRUETYPEFONTFAMILY_FANTASY:
+ desc->family = "fantasy";
+ break;
+ case PP_TRUETYPEFONTFAMILY_MONOSPACE:
+ desc->family = "monospace";
+ break;
+ }
+ }
+
+ fd_.reset(
+ MatchFontFaceWithFallback(desc->family,
+ desc->weight >= PP_TRUETYPEFONTWEIGHT_BOLD,
+ desc->style & PP_TRUETYPEFONTSTYLE_ITALIC,
+ desc->charset,
+ PP_BROWSERFONT_TRUSTED_FAMILY_DEFAULT));
+ // TODO(bbudge) Modify content API to return results of font matching and
+ // fallback, so we can update |desc| to reflect that.
+ return fd_.is_valid() ? PP_OK : PP_ERROR_FAILED;
+}
+
+int32_t PepperTrueTypeFontLinux::GetTableTags(std::vector<uint32_t>* tags) {
+ if (!fd_.is_valid())
+ return PP_ERROR_FAILED;
+ // Get the 2 byte numTables field at an offset of 4 in the font.
+ uint8_t num_tables_buf[2];
+ size_t output_length = sizeof(num_tables_buf);
+ if (!GetFontTable(fd_.get(),
+ 0 /* tag */,
+ 4 /* offset */,
+ reinterpret_cast<uint8_t*>(&num_tables_buf),
+ &output_length))
+ return PP_ERROR_FAILED;
+ DCHECK(output_length == sizeof(num_tables_buf));
+ // Font data is stored in big-endian order.
+ uint16_t num_tables = (num_tables_buf[0] << 8) | num_tables_buf[1];
+
+ // The font has a header, followed by n table entries in its directory.
+ static const size_t kFontHeaderSize = 12;
+ static const size_t kTableEntrySize = 16;
+ output_length = num_tables * kTableEntrySize;
+ scoped_ptr<uint8_t[]> table_entries(new uint8_t[output_length]);
+ // Get the table directory entries, which follow the font header.
+ if (!GetFontTable(fd_.get(),
+ 0 /* tag */,
+ kFontHeaderSize /* offset */,
+ table_entries.get(),
+ &output_length))
+ return PP_ERROR_FAILED;
+ DCHECK(output_length == num_tables * kTableEntrySize);
+
+ tags->resize(num_tables);
+ for (uint16_t i = 0; i < num_tables; i++) {
+ uint8_t* entry = table_entries.get() + i * kTableEntrySize;
+ uint32_t tag = static_cast<uint32_t>(entry[0]) << 24 |
+ static_cast<uint32_t>(entry[1]) << 16 |
+ static_cast<uint32_t>(entry[2]) << 8 |
+ static_cast<uint32_t>(entry[3]);
+ (*tags)[i] = tag;
+ }
+
+ return num_tables;
+}
+
+int32_t PepperTrueTypeFontLinux::GetTable(uint32_t table_tag,
+ int32_t offset,
+ int32_t max_data_length,
+ std::string* data) {
+ if (!fd_.is_valid())
+ return PP_ERROR_FAILED;
+ // Get the size of the font data first.
+ size_t table_size = 0;
+ // Tags are byte swapped on Linux.
+ table_tag = base::ByteSwap(table_tag);
+ if (!GetFontTable(fd_.get(), table_tag, offset, NULL, &table_size))
+ return PP_ERROR_FAILED;
+ // Only retrieve as much as the caller requested.
+ table_size = std::min(table_size, static_cast<size_t>(max_data_length));
+ data->resize(table_size);
+ if (!GetFontTable(fd_.get(),
+ table_tag,
+ offset,
+ reinterpret_cast<uint8_t*>(&(*data)[0]),
+ &table_size))
+ return PP_ERROR_FAILED;
+
+ return base::checked_cast<int32_t>(table_size);
+}
+
+} // namespace
+
+// static
+PepperTrueTypeFont* PepperTrueTypeFont::Create() {
+ return new PepperTrueTypeFontLinux();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.cc b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.cc
index 7479046cfe7..3730724aa25 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.cc
@@ -27,14 +27,14 @@ class FontMessageFilter : public ppapi::host::ResourceMessageFilter {
FontMessageFilter();
// ppapi::host::ResourceMessageFilter implementation.
- virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
- const IPC::Message& msg) OVERRIDE;
- virtual int32_t OnResourceMessageReceived(
+ scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) override;
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
private:
- virtual ~FontMessageFilter();
+ ~FontMessageFilter() override;
// Message handlers.
int32_t OnHostMsgGetFontFamilies(ppapi::host::HostMessageContext* context);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.h b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.h
index 69a471bb33e..19999ca1f59 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.h
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_host.h
@@ -17,7 +17,7 @@ class PepperTrueTypeFontListHost : public ppapi::host::ResourceHost {
PepperTrueTypeFontListHost(BrowserPpapiHost* host,
PP_Instance instance,
PP_Resource resource);
- virtual ~PepperTrueTypeFontListHost();
+ ~PepperTrueTypeFontListHost() override;
private:
DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontListHost);
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_win.cc b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_win.cc
index 8e275904081..158d8ea9de1 100644
--- a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_win.cc
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_list_win.cc
@@ -63,7 +63,7 @@ void GetFontFamilies_SlowBlocking(FontFamilyList* font_families) {
memset(&logfont, 0, sizeof(logfont));
logfont.lfCharSet = DEFAULT_CHARSET;
base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
- ::EnumFontFamiliesExW(hdc,
+ ::EnumFontFamiliesExW(hdc.Get(),
&logfont,
(FONTENUMPROCW) & EnumFontFamiliesProc,
(LPARAM)font_families,
@@ -78,7 +78,7 @@ void GetFontsInFamily_SlowBlocking(const std::string& family,
base::string16 family16 = base::UTF8ToUTF16(family);
memcpy(&logfont.lfFaceName, &family16[0], sizeof(logfont.lfFaceName));
base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
- ::EnumFontFamiliesExW(hdc,
+ ::EnumFontFamiliesExW(hdc.Get(),
&logfont,
(FONTENUMPROCW) & EnumFontsInFamilyProc,
(LPARAM)fonts_in_family,
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_mac.mm b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_mac.mm
new file mode 100644
index 00000000000..1e52e172bbf
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_mac.mm
@@ -0,0 +1,412 @@
+// 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/renderer_host/pepper/pepper_truetype_font.h"
+
+#import <ApplicationServices/ApplicationServices.h>
+
+#include <stdio.h>
+
+#include "base/compiler_specific.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/sys_byteorder.h"
+#include "ppapi/c/dev/ppb_truetype_font_dev.h"
+#include "ppapi/c/pp_errors.h"
+
+namespace content {
+
+namespace {
+
+static bool FindFloat(CFDictionaryRef dict, CFStringRef name, float* value) {
+ CFNumberRef num;
+ return CFDictionaryGetValueIfPresent(
+ dict, name, reinterpret_cast<const void**>(&num)) &&
+ CFNumberIsFloatType(num) &&
+ CFNumberGetValue(num, kCFNumberFloatType, value);
+}
+
+float GetMacWeight(PP_TrueTypeFontWeight_Dev weight) {
+ // Map values from NORMAL (400) to HEAVY (900) to the range [0 .. 1], and
+ // values below NORMAL to the range [-0.6 .. 0]. NORMAL should map to 0.
+ float normal = PP_TRUETYPEFONTWEIGHT_NORMAL;
+ float heavy = PP_TRUETYPEFONTWEIGHT_HEAVY;
+ return (weight - normal) / (heavy - normal);
+}
+
+PP_TrueTypeFontWeight_Dev GetPepperWeight(float weight) {
+ // Perform the inverse mapping of GetMacWeight.
+ return static_cast<PP_TrueTypeFontWeight_Dev>(
+ weight * (PP_TRUETYPEFONTWEIGHT_HEAVY - PP_TRUETYPEFONTWEIGHT_NORMAL) +
+ PP_TRUETYPEFONTWEIGHT_NORMAL);
+}
+
+float GetMacWidth(PP_TrueTypeFontWidth_Dev width) {
+ // Map values from NORMAL (4) to ULTRA_EXPANDED (8) to the range [0 .. 1],
+ // and values below NORMAL to the range [-1 .. 0]. Normal should map to 0.
+ float normal = PP_TRUETYPEFONTWIDTH_NORMAL;
+ float ultra_expanded = PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED;
+ return (width - normal) / (ultra_expanded - normal);
+}
+
+PP_TrueTypeFontWidth_Dev GetPepperWidth(float width) {
+ // Perform the inverse mapping of GetMacWeight.
+ return static_cast<PP_TrueTypeFontWidth_Dev>(
+ width *
+ (PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED - PP_TRUETYPEFONTWIDTH_NORMAL) +
+ PP_TRUETYPEFONTWIDTH_NORMAL);
+}
+
+#define MAKE_TABLE_TAG(a, b, c, d) ((a) << 24) + ((b) << 16) + ((c) << 8) + (d)
+
+// TrueType font header and table entry structs. See
+// https://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
+struct FontHeader {
+ int32_t font_type;
+ uint16_t num_tables;
+ uint16_t search_range;
+ uint16_t entry_selector;
+ uint16_t range_shift;
+};
+static_assert(sizeof(FontHeader) == 12, "FontHeader wrong size");
+
+struct FontDirectoryEntry {
+ uint32_t tag;
+ uint32_t checksum;
+ uint32_t offset;
+ uint32_t logical_length;
+};
+static_assert(sizeof(FontDirectoryEntry) == 16,
+ "FontDirectoryEntry wrong size");
+
+uint32_t CalculateChecksum(char* table, int32_t table_length) {
+ uint32_t sum = 0;
+ uint32_t* current = reinterpret_cast<uint32_t*>(table);
+ uint32_t length = (table_length + 3) / 4;
+ // Raw font data is big-endian.
+ while (length-- > 0)
+ sum += base::NetToHost32(*current++);
+ return sum;
+}
+
+class PepperTrueTypeFontMac : public PepperTrueTypeFont {
+ public:
+ PepperTrueTypeFontMac();
+
+ // PepperTrueTypeFont implementation.
+ int32_t Initialize(ppapi::proxy::SerializedTrueTypeFontDesc* desc) override;
+ int32_t GetTableTags(std::vector<uint32_t>* tags) override;
+ int32_t GetTable(uint32_t table_tag,
+ int32_t offset,
+ int32_t max_data_length,
+ std::string* data) override;
+
+ private:
+ ~PepperTrueTypeFontMac() override;
+
+ virtual int32_t GetEntireFont(int32_t offset,
+ int32_t max_data_length,
+ std::string* data);
+
+ base::ScopedCFTypeRef<CTFontRef> font_ref_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontMac);
+};
+
+PepperTrueTypeFontMac::PepperTrueTypeFontMac() {
+}
+
+PepperTrueTypeFontMac::~PepperTrueTypeFontMac() {
+}
+
+int32_t PepperTrueTypeFontMac::Initialize(
+ ppapi::proxy::SerializedTrueTypeFontDesc* desc) {
+ // Create the font in a nested scope, so we can use the same variable names
+ // when we get the actual font characteristics.
+ {
+ // Create attributes and traits dictionaries.
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> attributes_ref(
+ CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> traits_ref(
+ CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+ if (!attributes_ref || !traits_ref)
+ return PP_ERROR_FAILED;
+
+ CFDictionaryAddValue(attributes_ref, kCTFontTraitsAttribute, traits_ref);
+
+ // Use symbolic traits to specify traits when possible.
+ CTFontSymbolicTraits symbolic_traits = 0;
+ if (desc->style & PP_TRUETYPEFONTSTYLE_ITALIC)
+ symbolic_traits |= kCTFontItalicTrait;
+ if (desc->weight == PP_TRUETYPEFONTWEIGHT_BOLD)
+ symbolic_traits |= kCTFontBoldTrait;
+ if (desc->width == PP_TRUETYPEFONTWIDTH_CONDENSED)
+ symbolic_traits |= kCTFontCondensedTrait;
+ else if (desc->width == PP_TRUETYPEFONTWIDTH_EXPANDED)
+ symbolic_traits |= kCTFontExpandedTrait;
+
+ base::ScopedCFTypeRef<CFNumberRef> symbolic_traits_ref(CFNumberCreate(
+ kCFAllocatorDefault, kCFNumberSInt32Type, &symbolic_traits));
+ if (!symbolic_traits_ref)
+ return PP_ERROR_FAILED;
+ CFDictionaryAddValue(traits_ref, kCTFontSymbolicTrait, symbolic_traits_ref);
+
+ // Font family matching doesn't work using family classes in symbolic
+ // traits. Instead, map generic_family to font families that are always
+ // available.
+ std::string family(desc->family);
+ if (family.empty()) {
+ switch (desc->generic_family) {
+ case PP_TRUETYPEFONTFAMILY_SERIF:
+ family = "Times";
+ break;
+ case PP_TRUETYPEFONTFAMILY_SANSSERIF:
+ family = "Helvetica";
+ break;
+ case PP_TRUETYPEFONTFAMILY_CURSIVE:
+ family = "Apple Chancery";
+ break;
+ case PP_TRUETYPEFONTFAMILY_FANTASY:
+ family = "Papyrus";
+ break;
+ case PP_TRUETYPEFONTFAMILY_MONOSPACE:
+ family = "Courier";
+ break;
+ }
+ }
+
+ base::ScopedCFTypeRef<CFStringRef> name_ref(
+ base::SysUTF8ToCFStringRef(family));
+ if (name_ref)
+ CFDictionaryAddValue(
+ attributes_ref, kCTFontFamilyNameAttribute, name_ref);
+
+ if (desc->weight != PP_TRUETYPEFONTWEIGHT_NORMAL &&
+ desc->weight != PP_TRUETYPEFONTWEIGHT_BOLD) {
+ float weight = GetMacWeight(desc->weight);
+ base::ScopedCFTypeRef<CFNumberRef> weight_trait_ref(
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &weight));
+ if (weight_trait_ref)
+ CFDictionaryAddValue(traits_ref, kCTFontWeightTrait, weight_trait_ref);
+ }
+
+ if (desc->width != PP_TRUETYPEFONTWIDTH_NORMAL &&
+ desc->width != PP_TRUETYPEFONTWIDTH_CONDENSED &&
+ desc->width != PP_TRUETYPEFONTWIDTH_EXPANDED) {
+ float width = GetMacWidth(desc->width);
+ base::ScopedCFTypeRef<CFNumberRef> width_trait_ref(
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &width));
+ if (width_trait_ref)
+ CFDictionaryAddValue(traits_ref, kCTFontWidthTrait, width_trait_ref);
+ }
+
+ base::ScopedCFTypeRef<CTFontDescriptorRef> desc_ref(
+ CTFontDescriptorCreateWithAttributes(attributes_ref));
+
+ if (desc_ref)
+ font_ref_.reset(CTFontCreateWithFontDescriptor(desc_ref, 0, NULL));
+
+ if (!font_ref_.get())
+ return PP_ERROR_FAILED;
+ }
+
+ // Now query to get the actual font characteristics.
+ base::ScopedCFTypeRef<CTFontDescriptorRef> desc_ref(
+ CTFontCopyFontDescriptor(font_ref_));
+
+ base::ScopedCFTypeRef<CFStringRef> family_name_ref(
+ base::mac::CFCast<CFStringRef>(
+ CTFontDescriptorCopyAttribute(desc_ref, kCTFontFamilyNameAttribute)));
+ desc->family = base::SysCFStringRefToUTF8(family_name_ref);
+
+ base::ScopedCFTypeRef<CFDictionaryRef> traits_ref(
+ base::mac::CFCast<CFDictionaryRef>(
+ CTFontDescriptorCopyAttribute(desc_ref, kCTFontTraitsAttribute)));
+
+ desc->style = PP_TRUETYPEFONTSTYLE_NORMAL;
+ CTFontSymbolicTraits symbolic_traits(CTFontGetSymbolicTraits(font_ref_));
+ if (symbolic_traits & kCTFontItalicTrait)
+ desc->style = static_cast<PP_TrueTypeFontStyle_Dev>(
+ desc->style | PP_TRUETYPEFONTSTYLE_ITALIC);
+ if (symbolic_traits & kCTFontBoldTrait) {
+ desc->weight = PP_TRUETYPEFONTWEIGHT_BOLD;
+ } else {
+ float weight;
+ if (FindFloat(traits_ref, kCTFontWeightTrait, &weight))
+ desc->weight = GetPepperWeight(weight);
+ }
+ if (symbolic_traits & kCTFontCondensedTrait) {
+ desc->width = PP_TRUETYPEFONTWIDTH_CONDENSED;
+ } else if (symbolic_traits & kCTFontExpandedTrait) {
+ desc->width = PP_TRUETYPEFONTWIDTH_EXPANDED;
+ } else {
+ float width;
+ if (FindFloat(traits_ref, kCTFontWidthTrait, &width))
+ desc->width = GetPepperWidth(width);
+ }
+
+ // Character set isn't supported on Mac.
+ desc->charset = PP_TRUETYPEFONTCHARSET_DEFAULT;
+ return PP_OK;
+}
+
+int32_t PepperTrueTypeFontMac::GetTableTags(std::vector<uint32_t>* tags) {
+ if (!font_ref_.get())
+ return PP_ERROR_FAILED;
+ base::ScopedCFTypeRef<CFArrayRef> tag_array(
+ CTFontCopyAvailableTables(font_ref_, kCTFontTableOptionNoOptions));
+ if (!tag_array)
+ return PP_ERROR_FAILED;
+
+ // Items returned by CTFontCopyAvailableTables are not boxed. Whose bright
+ // idea was this?
+ CFIndex length = CFArrayGetCount(tag_array);
+ tags->resize(length);
+ for (CFIndex i = 0; i < length; ++i) {
+ (*tags)[i] =
+ reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(tag_array, i));
+ }
+ return length;
+}
+
+int32_t PepperTrueTypeFontMac::GetTable(uint32_t table_tag,
+ int32_t offset,
+ int32_t max_data_length,
+ std::string* data) {
+ if (!font_ref_.get())
+ return PP_ERROR_FAILED;
+
+ if (!table_tag)
+ return GetEntireFont(offset, max_data_length, data);
+
+ base::ScopedCFTypeRef<CFDataRef> table_ref(
+ CTFontCopyTable(font_ref_,
+ static_cast<CTFontTableTag>(table_tag),
+ kCTFontTableOptionNoOptions));
+ if (!table_ref)
+ return PP_ERROR_FAILED;
+
+ CFIndex table_size = CFDataGetLength(table_ref);
+ CFIndex safe_offset =
+ std::min(base::checked_cast<CFIndex>(offset), table_size);
+ CFIndex safe_length = std::min(table_size - safe_offset,
+ base::checked_cast<CFIndex>(max_data_length));
+ data->resize(safe_length);
+ CFDataGetBytes(table_ref,
+ CFRangeMake(safe_offset, safe_length),
+ reinterpret_cast<UInt8*>(&(*data)[0]));
+
+ return safe_length;
+}
+
+int32_t PepperTrueTypeFontMac::GetEntireFont(int32_t offset,
+ int32_t max_data_length,
+ std::string* data) {
+ // Reconstruct the font header, table directory, and tables.
+ std::vector<uint32_t> table_tags;
+ int32_t table_count = GetTableTags(&table_tags);
+ if (table_count < 0)
+ return table_count; // PPAPI error code.
+
+ // Allocate enough room for the header and the table directory entries.
+ std::string font(
+ sizeof(FontHeader) + sizeof(FontDirectoryEntry) * table_count, 0);
+ // Map the OS X font type value to a TrueType scalar type.
+ base::ScopedCFTypeRef<CFNumberRef> font_type_ref(
+ base::mac::CFCast<CFNumberRef>(
+ CTFontCopyAttribute(font_ref_, kCTFontFormatAttribute)));
+ int32_t font_type;
+ CFNumberGetValue(font_type_ref, kCFNumberSInt32Type, &font_type);
+ switch (font_type) {
+ case kCTFontFormatOpenTypePostScript:
+ font_type = MAKE_TABLE_TAG('O', 'T', 'T', 'O');
+ break;
+ case kCTFontFormatTrueType:
+ case kCTFontFormatBitmap:
+ font_type = MAKE_TABLE_TAG('t', 'r', 'u', 'e');
+ break;
+ case kCTFontFormatPostScript:
+ font_type = MAKE_TABLE_TAG('t', 'y', 'p', '1');
+ break;
+ case kCTFontFormatOpenTypeTrueType:
+ case kCTFontFormatUnrecognized:
+ default:
+ font_type = MAKE_TABLE_TAG(0, 1, 0, 0);
+ break;
+ }
+
+ // Calculate the rest of the header values.
+ uint16_t num_tables = base::checked_cast<uint16_t>(table_count);
+ uint16_t entry_selector = 0;
+ uint16_t search_range = 1;
+ while (search_range < (num_tables >> 1)) {
+ entry_selector++;
+ search_range <<= 1;
+ }
+ search_range <<= 4;
+ uint16_t range_shift = (num_tables << 4) - search_range;
+
+ // Write the header, with values in big-endian order.
+ FontHeader* font_header = reinterpret_cast<FontHeader*>(&font[0]);
+ font_header->font_type = base::HostToNet32(font_type);
+ font_header->num_tables = base::HostToNet16(num_tables);
+ font_header->search_range = base::HostToNet16(search_range);
+ font_header->entry_selector = base::HostToNet16(entry_selector);
+ font_header->range_shift = base::HostToNet16(range_shift);
+
+ for (int32_t i = 0; i < table_count; i++) {
+ // Get the table data.
+ std::string table;
+ int32_t table_size =
+ GetTable(table_tags[i], 0, std::numeric_limits<int32_t>::max(), &table);
+ if (table_size < 0)
+ return table_size; // PPAPI error code.
+
+ // Append it to the font data so far, and zero pad so tables stay aligned.
+ size_t table_offset = font.size();
+ font.append(table);
+ size_t padding = font.size() & 0x3;
+ font.append(padding, 0);
+
+ // Fill in the directory entry for this table.
+ FontDirectoryEntry* entry = reinterpret_cast<FontDirectoryEntry*>(
+ &font[0] + sizeof(FontHeader) + i * sizeof(FontDirectoryEntry));
+ entry->tag = base::HostToNet32(table_tags[i]);
+ entry->checksum =
+ base::HostToNet32(CalculateChecksum(&font[table_offset], table_size));
+ entry->offset = base::HostToNet32(table_offset);
+ entry->logical_length = base::HostToNet32(table_size);
+ // TODO(bbudge) set the 'head' table checksumAdjustment.
+ }
+
+ // Extract a substring if the caller specified an offset or max data length.
+ int32_t font_size = base::checked_cast<int32_t>(font.size());
+ int32_t safe_offset = std::min(offset, font_size);
+ int32_t safe_length = std::min(font_size - safe_offset, max_data_length);
+ if (safe_offset || safe_length != font_size)
+ font = font.substr(safe_offset, safe_length);
+
+ data->clear();
+ data->swap(font);
+ return safe_length;
+}
+
+} // namespace
+
+// static
+PepperTrueTypeFont* PepperTrueTypeFont::Create() {
+ return new PepperTrueTypeFontMac();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_win.cc b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_win.cc
new file mode 100644
index 00000000000..6eb36a1e358
--- /dev/null
+++ b/chromium/content/browser/renderer_host/pepper/pepper_truetype_font_win.cc
@@ -0,0 +1,237 @@
+// 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/renderer_host/pepper/pepper_truetype_font.h"
+
+#include <windows.h>
+#include <set>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_byteorder.h"
+#include "base/win/scoped_gdi_object.h"
+#include "base/win/scoped_hdc.h"
+#include "base/win/scoped_select_object.h"
+#include "ppapi/c/dev/ppb_truetype_font_dev.h"
+#include "ppapi/c/pp_errors.h"
+
+namespace content {
+
+namespace {
+
+class PepperTrueTypeFontWin : public PepperTrueTypeFont {
+ public:
+ PepperTrueTypeFontWin();
+
+ // PepperTrueTypeFont implementation.
+ virtual int32_t Initialize(
+ ppapi::proxy::SerializedTrueTypeFontDesc* desc) override;
+ virtual int32_t GetTableTags(std::vector<uint32_t>* tags) override;
+ virtual int32_t GetTable(uint32_t table_tag,
+ int32_t offset,
+ int32_t max_data_length,
+ std::string* data) override;
+
+ private:
+ virtual ~PepperTrueTypeFontWin();
+
+ DWORD GetFontData(HDC hdc,
+ DWORD table,
+ DWORD offset,
+ LPVOID buffer,
+ DWORD length);
+
+ base::win::ScopedHFONT font_;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontWin);
+};
+
+PepperTrueTypeFontWin::PepperTrueTypeFontWin() {
+}
+
+PepperTrueTypeFontWin::~PepperTrueTypeFontWin() {
+}
+
+int32_t PepperTrueTypeFontWin::Initialize(
+ ppapi::proxy::SerializedTrueTypeFontDesc* desc) {
+ DWORD pitch_and_family = DEFAULT_PITCH;
+ switch (desc->generic_family) {
+ case PP_TRUETYPEFONTFAMILY_SERIF:
+ pitch_and_family |= FF_ROMAN;
+ break;
+ case PP_TRUETYPEFONTFAMILY_SANSSERIF:
+ pitch_and_family |= FF_SWISS;
+ break;
+ case PP_TRUETYPEFONTFAMILY_CURSIVE:
+ pitch_and_family |= FF_SCRIPT;
+ break;
+ case PP_TRUETYPEFONTFAMILY_FANTASY:
+ pitch_and_family |= FF_DECORATIVE;
+ break;
+ case PP_TRUETYPEFONTFAMILY_MONOSPACE:
+ pitch_and_family |= FF_MODERN;
+ break;
+ }
+ // TODO(bbudge) support widths (extended, condensed).
+
+ font_.Set(CreateFont(0 /* height */,
+ 0 /* width */,
+ 0 /* escapement */,
+ 0 /* orientation */,
+ desc->weight, // our weight enum matches Windows.
+ (desc->style & PP_TRUETYPEFONTSTYLE_ITALIC) ? 1 : 0,
+ 0 /* underline */,
+ 0 /* strikeout */,
+ desc->charset, // our charset enum matches Windows.
+ OUT_OUTLINE_PRECIS, // truetype and other outline fonts
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ pitch_and_family,
+ base::UTF8ToUTF16(desc->family).c_str()));
+ if (!font_.Get())
+ return PP_ERROR_FAILED;
+
+ LOGFONT font_desc;
+ if (!::GetObject(font_.Get(), sizeof(LOGFONT), &font_desc))
+ return PP_ERROR_FAILED;
+
+ switch (font_desc.lfPitchAndFamily & 0xF0) { // Top 4 bits are family.
+ case FF_ROMAN:
+ desc->generic_family = PP_TRUETYPEFONTFAMILY_SERIF;
+ break;
+ case FF_SWISS:
+ desc->generic_family = PP_TRUETYPEFONTFAMILY_SANSSERIF;
+ break;
+ case FF_SCRIPT:
+ desc->generic_family = PP_TRUETYPEFONTFAMILY_CURSIVE;
+ break;
+ case FF_DECORATIVE:
+ desc->generic_family = PP_TRUETYPEFONTFAMILY_FANTASY;
+ break;
+ case FF_MODERN:
+ desc->generic_family = PP_TRUETYPEFONTFAMILY_MONOSPACE;
+ break;
+ }
+
+ desc->style = font_desc.lfItalic ? PP_TRUETYPEFONTSTYLE_ITALIC
+ : PP_TRUETYPEFONTSTYLE_NORMAL;
+ desc->weight = static_cast<PP_TrueTypeFontWeight_Dev>(font_desc.lfWeight);
+ desc->width = PP_TRUETYPEFONTWIDTH_NORMAL;
+ desc->charset = static_cast<PP_TrueTypeFontCharset_Dev>(font_desc.lfCharSet);
+
+ // To get the face name, select the font and query for the name. GetObject
+ // doesn't fill in the name field of the LOGFONT structure.
+ base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
+ if (hdc.IsValid()) {
+ base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get());
+ WCHAR name[LF_FACESIZE];
+ GetTextFace(hdc.Get(), LF_FACESIZE, name);
+ desc->family = base::UTF16ToUTF8(name);
+ }
+
+ return PP_OK;
+}
+
+int32_t PepperTrueTypeFontWin::GetTableTags(std::vector<uint32_t>* tags) {
+ if (!font_.Get())
+ return PP_ERROR_FAILED;
+
+ base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
+ if (!hdc.IsValid())
+ return PP_ERROR_FAILED;
+
+ base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get());
+
+ // Get the whole font header.
+ static const DWORD kFontHeaderSize = 12;
+ uint8_t header_buf[kFontHeaderSize];
+ if (GetFontData(hdc.Get(), 0, 0, header_buf, kFontHeaderSize) == GDI_ERROR)
+ return PP_ERROR_FAILED;
+
+ // The numTables follows a 4 byte scalerType tag. Font data is stored in
+ // big-endian order.
+ DWORD num_tables = (header_buf[4] << 8) | header_buf[5];
+
+ // The size in bytes of an entry in the table directory.
+ static const DWORD kDirectoryEntrySize = 16;
+ DWORD directory_size = num_tables * kDirectoryEntrySize;
+ scoped_ptr<uint8_t[]> directory(new uint8_t[directory_size]);
+ // Get the table directory entries after the font header.
+ if (GetFontData(hdc.Get(), 0 /* tag */, kFontHeaderSize, directory.get(),
+ directory_size) ==
+ GDI_ERROR)
+ return PP_ERROR_FAILED;
+
+ tags->resize(num_tables);
+ for (DWORD i = 0; i < num_tables; i++) {
+ const uint8_t* entry = directory.get() + i * kDirectoryEntrySize;
+ uint32_t tag = static_cast<uint32_t>(entry[0]) << 24 |
+ static_cast<uint32_t>(entry[1]) << 16 |
+ static_cast<uint32_t>(entry[2]) << 8 |
+ static_cast<uint32_t>(entry[3]);
+ (*tags)[i] = tag;
+ }
+
+ return num_tables;
+}
+
+int32_t PepperTrueTypeFontWin::GetTable(uint32_t table_tag,
+ int32_t offset,
+ int32_t max_data_length,
+ std::string* data) {
+ if (!font_.Get())
+ return PP_ERROR_FAILED;
+
+ base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
+ if (!hdc.IsValid())
+ return PP_ERROR_FAILED;
+
+ base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get());
+
+ // Tags are byte swapped on Windows.
+ table_tag = base::ByteSwap(table_tag);
+ // Get the size of the font table first.
+ DWORD table_size = GetFontData(hdc.Get(), table_tag, 0, NULL, 0);
+ if (table_size == GDI_ERROR)
+ return PP_ERROR_FAILED;
+
+ DWORD safe_offset = std::min(static_cast<DWORD>(offset), table_size);
+ DWORD safe_length =
+ std::min(table_size - safe_offset, static_cast<DWORD>(max_data_length));
+ data->resize(safe_length);
+ if (safe_length == 0) {
+ table_size = 0;
+ } else {
+ table_size = GetFontData(hdc.Get(),
+ table_tag,
+ safe_offset,
+ reinterpret_cast<uint8_t*>(&(*data)[0]),
+ safe_length);
+ if (table_size == GDI_ERROR)
+ return PP_ERROR_FAILED;
+ }
+ return static_cast<int32_t>(table_size);
+}
+
+DWORD PepperTrueTypeFontWin::GetFontData(HDC hdc,
+ DWORD table,
+ DWORD offset,
+ void* buffer,
+ DWORD length) {
+ // If this is a zero byte read, return a successful result.
+ if (buffer && !length)
+ return 0;
+
+ return ::GetFontData(hdc, table, offset, buffer, length);
+}
+
+} // namespace
+
+// static
+PepperTrueTypeFont* PepperTrueTypeFont::Create() {
+ return new PepperTrueTypeFontWin();
+}
+
+} // namespace content
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 a4ed3dca46e..26c0e44ee34 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
@@ -23,6 +23,7 @@
#include "ppapi/host/error_conversion.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/ppapi_host.h"
+#include "ppapi/host/resource_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/udp_socket_resource_base.h"
#include "ppapi/shared_impl/private/net_address_private_impl.h"
@@ -46,6 +47,8 @@ PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
: allow_address_reuse_(false),
allow_broadcast_(false),
closed_(false),
+ remaining_recv_slots_(
+ ppapi::proxy::UDPSocketResourceBase::kPluginReceiveBufferSlots),
external_plugin_(host->external_plugin()),
private_api_(private_api),
render_process_id_(0),
@@ -74,8 +77,8 @@ PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
const IPC::Message& message) {
switch (message.type()) {
case PpapiHostMsg_UDPSocket_SetOption::ID:
- case PpapiHostMsg_UDPSocket_RecvFrom::ID:
case PpapiHostMsg_UDPSocket_Close::ID:
+ case PpapiHostMsg_UDPSocket_RecvSlotAvailable::ID:
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
case PpapiHostMsg_UDPSocket_Bind::ID:
case PpapiHostMsg_UDPSocket_SendTo::ID:
@@ -91,12 +94,12 @@ int32_t PepperUDPSocketMessageFilter::OnResourceMessageReceived(
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SetOption,
OnMsgSetOption)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_Bind, OnMsgBind)
- PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_RecvFrom,
- OnMsgRecvFrom)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SendTo,
OnMsgSendTo)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_UDPSocket_Close,
OnMsgClose)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
+ PpapiHostMsg_UDPSocket_RecvSlotAvailable, OnMsgRecvSlotAvailable)
PPAPI_END_MESSAGE_MAP()
return PP_ERROR_FAILED;
}
@@ -188,45 +191,6 @@ int32_t PepperUDPSocketMessageFilter::OnMsgBind(
return PP_OK_COMPLETIONPENDING;
}
-int32_t PepperUDPSocketMessageFilter::OnMsgRecvFrom(
- const ppapi::host::HostMessageContext* context,
- int32_t num_bytes) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(context);
- DCHECK(socket_.get());
-
- if (closed_ || !socket_.get())
- return PP_ERROR_FAILED;
-
- if (recvfrom_buffer_.get())
- return PP_ERROR_INPROGRESS;
-
- if (num_bytes <= 0 ||
- num_bytes > ppapi::proxy::UDPSocketResourceBase::kMaxReadSize) {
- // |num_bytes| value is checked on the plugin side.
- NOTREACHED();
- return PP_ERROR_BADARGUMENT;
- }
-
- recvfrom_buffer_ = new net::IOBuffer(num_bytes);
-
- // Use base::Unretained(this), so that the lifespan of this object doesn't
- // have to last until the callback is called.
- // It is safe to do so because |socket_| is owned by this object. If this
- // object gets destroyed (and so does |socket_|), the callback won't be
- // called.
- int net_result = socket_->RecvFrom(
- recvfrom_buffer_.get(),
- num_bytes,
- &recvfrom_address_,
- base::Bind(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
- base::Unretained(this),
- context->MakeReplyMessageContext()));
- if (net_result != net::ERR_IO_PENDING)
- OnRecvFromCompleted(context->MakeReplyMessageContext(), net_result);
- return PP_OK_COMPLETIONPENDING;
-}
-
int32_t PepperUDPSocketMessageFilter::OnMsgSendTo(
const ppapi::host::HostMessageContext* context,
const std::string& data,
@@ -262,6 +226,23 @@ int32_t PepperUDPSocketMessageFilter::OnMsgClose(
return PP_OK;
}
+int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
+ const ppapi::host::HostMessageContext* context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (remaining_recv_slots_ <
+ ppapi::proxy::UDPSocketResourceBase::kPluginReceiveBufferSlots) {
+ remaining_recv_slots_++;
+ }
+
+ if (!recvfrom_buffer_.get() && !closed_ && socket_.get()) {
+ DCHECK_EQ(1u, remaining_recv_slots_);
+ DoRecvFrom();
+ }
+
+ return PP_OK;
+}
+
void PepperUDPSocketMessageFilter::DoBind(
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& addr) {
@@ -312,6 +293,33 @@ void PepperUDPSocketMessageFilter::DoBind(
allow_broadcast_ = false;
socket_.swap(socket);
SendBindReply(context, PP_OK, net_address);
+
+ DoRecvFrom();
+}
+
+void PepperUDPSocketMessageFilter::DoRecvFrom() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!closed_);
+ DCHECK(socket_.get());
+ DCHECK(!recvfrom_buffer_.get());
+ DCHECK_GT(remaining_recv_slots_, 0u);
+
+ recvfrom_buffer_ = new net::IOBuffer(
+ ppapi::proxy::UDPSocketResourceBase::kMaxReadSize);
+
+ // Use base::Unretained(this), so that the lifespan of this object doesn't
+ // have to last until the callback is called.
+ // It is safe to do so because |socket_| is owned by this object. If this
+ // object gets destroyed (and so does |socket_|), the callback won't be
+ // called.
+ int net_result = socket_->RecvFrom(
+ recvfrom_buffer_.get(),
+ ppapi::proxy::UDPSocketResourceBase::kMaxReadSize,
+ &recvfrom_address_,
+ base::Bind(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
+ base::Unretained(this)));
+ if (net_result != net::ERR_IO_PENDING)
+ OnRecvFromCompleted(net_result);
}
void PepperUDPSocketMessageFilter::DoSendTo(
@@ -371,9 +379,7 @@ void PepperUDPSocketMessageFilter::Close() {
closed_ = true;
}
-void PepperUDPSocketMessageFilter::OnRecvFromCompleted(
- const ppapi::host::ReplyMessageContext& context,
- int net_result) {
+void PepperUDPSocketMessageFilter::OnRecvFromCompleted(int net_result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(recvfrom_buffer_.get());
@@ -389,13 +395,19 @@ void PepperUDPSocketMessageFilter::OnRecvFromCompleted(
}
if (pp_result >= 0) {
- SendRecvFromReply(
- context, PP_OK, std::string(recvfrom_buffer_->data(), pp_result), addr);
+ SendRecvFromResult(PP_OK, std::string(recvfrom_buffer_->data(), pp_result),
+ addr);
} else {
- SendRecvFromError(context, pp_result);
+ SendRecvFromError(pp_result);
}
recvfrom_buffer_ = NULL;
+
+ DCHECK_GT(remaining_recv_slots_, 0u);
+ remaining_recv_slots_--;
+
+ if (remaining_recv_slots_ > 0 && !closed_ && socket_.get())
+ DoRecvFrom();
}
void PepperUDPSocketMessageFilter::OnSendToCompleted(
@@ -421,14 +433,15 @@ void PepperUDPSocketMessageFilter::SendBindReply(
SendReply(reply_context, PpapiPluginMsg_UDPSocket_BindReply(addr));
}
-void PepperUDPSocketMessageFilter::SendRecvFromReply(
- const ppapi::host::ReplyMessageContext& context,
+void PepperUDPSocketMessageFilter::SendRecvFromResult(
int32_t result,
const std::string& data,
const PP_NetAddress_Private& addr) {
- ppapi::host::ReplyMessageContext reply_context(context);
- reply_context.params.set_result(result);
- SendReply(reply_context, PpapiPluginMsg_UDPSocket_RecvFromReply(data, addr));
+ if (resource_host()) {
+ resource_host()->host()->SendUnsolicitedReply(
+ resource_host()->pp_resource(),
+ PpapiPluginMsg_UDPSocket_PushRecvResult(result, data, addr));
+ }
}
void PepperUDPSocketMessageFilter::SendSendToReply(
@@ -447,12 +460,9 @@ void PepperUDPSocketMessageFilter::SendBindError(
}
void PepperUDPSocketMessageFilter::SendRecvFromError(
- const ppapi::host::ReplyMessageContext& context,
int32_t result) {
- SendRecvFromReply(context,
- result,
- std::string(),
- NetAddressPrivateImpl::kInvalidNetAddress);
+ SendRecvFromResult(result, std::string(),
+ NetAddressPrivateImpl::kInvalidNetAddress);
}
void PepperUDPSocketMessageFilter::SendSendToError(
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 8ca7f0800bc..1aa2c36cad4 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
@@ -53,55 +53,53 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
static size_t GetNumInstances();
protected:
- virtual ~PepperUDPSocketMessageFilter();
+ ~PepperUDPSocketMessageFilter() override;
private:
// ppapi::host::ResourceMessageFilter overrides.
- virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
- const IPC::Message& message) OVERRIDE;
- virtual int32_t OnResourceMessageReceived(
+ scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
+ int32_t OnResourceMessageReceived(
const IPC::Message& msg,
- ppapi::host::HostMessageContext* context) OVERRIDE;
+ ppapi::host::HostMessageContext* context) override;
int32_t OnMsgSetOption(const ppapi::host::HostMessageContext* context,
PP_UDPSocket_Option name,
const ppapi::SocketOptionData& value);
int32_t OnMsgBind(const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& addr);
- int32_t OnMsgRecvFrom(const ppapi::host::HostMessageContext* context,
- int32_t num_bytes);
int32_t OnMsgSendTo(const ppapi::host::HostMessageContext* context,
const std::string& data,
const PP_NetAddress_Private& addr);
int32_t OnMsgClose(const ppapi::host::HostMessageContext* context);
+ int32_t OnMsgRecvSlotAvailable(
+ const ppapi::host::HostMessageContext* context);
void DoBind(const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& addr);
+ void DoRecvFrom();
void DoSendTo(const ppapi::host::ReplyMessageContext& context,
const std::string& data,
const PP_NetAddress_Private& addr);
void Close();
- void OnRecvFromCompleted(const ppapi::host::ReplyMessageContext& context,
- int net_result);
+ void OnRecvFromCompleted(int net_result);
void OnSendToCompleted(const ppapi::host::ReplyMessageContext& context,
int net_result);
void SendBindReply(const ppapi::host::ReplyMessageContext& context,
int32_t result,
const PP_NetAddress_Private& addr);
- void SendRecvFromReply(const ppapi::host::ReplyMessageContext& context,
- int32_t result,
- const std::string& data,
- const PP_NetAddress_Private& addr);
+ void SendRecvFromResult(int32_t result,
+ const std::string& data,
+ const PP_NetAddress_Private& addr);
void SendSendToReply(const ppapi::host::ReplyMessageContext& context,
int32_t result,
int32_t bytes_written);
void SendBindError(const ppapi::host::ReplyMessageContext& context,
int32_t result);
- void SendRecvFromError(const ppapi::host::ReplyMessageContext& context,
- int32_t result);
+ void SendRecvFromError(int32_t result);
void SendSendToError(const ppapi::host::ReplyMessageContext& context,
int32_t result);
@@ -116,6 +114,8 @@ class CONTENT_EXPORT PepperUDPSocketMessageFilter
net::IPEndPoint recvfrom_address_;
+ size_t remaining_recv_slots_;
+
bool external_plugin_;
bool private_api_;
diff --git a/chromium/content/browser/renderer_host/pepper/quota_reservation.cc b/chromium/content/browser/renderer_host/pepper/quota_reservation.cc
index 85a404cac36..5343cbd153f 100644
--- a/chromium/content/browser/renderer_host/pepper/quota_reservation.cc
+++ b/chromium/content/browser/renderer_host/pepper/quota_reservation.cc
@@ -7,26 +7,26 @@
#include "base/bind.h"
#include "base/callback.h"
#include "content/public/browser/browser_thread.h"
-#include "webkit/browser/fileapi/file_system_operation_runner.h"
-#include "webkit/browser/fileapi/quota/open_file_handle.h"
-#include "webkit/browser/fileapi/quota/quota_reservation.h"
-#include "webkit/common/fileapi/file_system_util.h"
+#include "storage/browser/fileapi/file_system_operation_runner.h"
+#include "storage/browser/fileapi/quota/open_file_handle.h"
+#include "storage/browser/fileapi/quota/quota_reservation.h"
+#include "storage/common/fileapi/file_system_util.h"
namespace content {
// static
scoped_refptr<QuotaReservation> QuotaReservation::Create(
- scoped_refptr<fileapi::FileSystemContext> file_system_context,
+ scoped_refptr<storage::FileSystemContext> file_system_context,
const GURL& origin_url,
- fileapi::FileSystemType type) {
+ storage::FileSystemType type) {
return scoped_refptr<QuotaReservation>(
new QuotaReservation(file_system_context, origin_url, type));
}
QuotaReservation::QuotaReservation(
- scoped_refptr<fileapi::FileSystemContext> file_system_context,
+ scoped_refptr<storage::FileSystemContext> file_system_context,
const GURL& origin_url,
- fileapi::FileSystemType file_system_type)
+ storage::FileSystemType file_system_type)
: file_system_context_(file_system_context) {
quota_reservation_ =
file_system_context->CreateQuotaReservationOnFileTaskRunner(
@@ -35,10 +35,11 @@ QuotaReservation::QuotaReservation(
// For unit testing only.
QuotaReservation::QuotaReservation(
- scoped_refptr<fileapi::QuotaReservation> quota_reservation,
+ scoped_refptr<storage::QuotaReservation> quota_reservation,
const GURL& /* origin_url */,
- fileapi::FileSystemType /* file_system_type */)
- : quota_reservation_(quota_reservation) {}
+ storage::FileSystemType /* file_system_type */)
+ : quota_reservation_(quota_reservation) {
+}
QuotaReservation::~QuotaReservation() {
// We should have no open files at this point.
@@ -48,9 +49,9 @@ QuotaReservation::~QuotaReservation() {
}
int64_t QuotaReservation::OpenFile(int32_t id,
- const fileapi::FileSystemURL& url) {
+ const storage::FileSystemURL& url) {
base::FilePath platform_file_path;
- if (file_system_context_) {
+ if (file_system_context_.get()) {
base::File::Error error =
file_system_context_->operation_runner()->SyncGetPlatformPath(
url, &platform_file_path);
@@ -63,7 +64,7 @@ int64_t QuotaReservation::OpenFile(int32_t id,
platform_file_path = url.path();
}
- scoped_ptr<fileapi::OpenFileHandle> file_handle =
+ scoped_ptr<storage::OpenFileHandle> file_handle =
quota_reservation_->GetOpenFileHandle(platform_file_path);
std::pair<FileMap::iterator, bool> insert_result =
files_.insert(std::make_pair(id, file_handle.get()));
@@ -116,7 +117,7 @@ void QuotaReservation::GotReservedQuota(const ReserveQuotaCallback& callback,
for (FileMap::iterator it = files_.begin(); it != files_.end(); ++it)
file_sizes[it->first] = it->second->GetMaxWrittenOffset();
- if (file_system_context_) {
+ if (file_system_context_.get()) {
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
@@ -129,8 +130,9 @@ void QuotaReservation::GotReservedQuota(const ReserveQuotaCallback& callback,
}
void QuotaReservation::DeleteOnCorrectThread() const {
- if (file_system_context_ && !file_system_context_->default_file_task_runner()
- ->RunsTasksOnCurrentThread()) {
+ if (file_system_context_.get() &&
+ !file_system_context_->default_file_task_runner()
+ ->RunsTasksOnCurrentThread()) {
file_system_context_->default_file_task_runner()->DeleteSoon(FROM_HERE,
this);
} else {
diff --git a/chromium/content/browser/renderer_host/pepper/quota_reservation.h b/chromium/content/browser/renderer_host/pepper/quota_reservation.h
index 33490918f93..7ea637c2b8f 100644
--- a/chromium/content/browser/renderer_host/pepper/quota_reservation.h
+++ b/chromium/content/browser/renderer_host/pepper/quota_reservation.h
@@ -12,10 +12,10 @@
#include "content/common/content_export.h"
#include "ppapi/c/pp_stdint.h" // For int64_t on Windows.
#include "ppapi/shared_impl/file_growth.h"
+#include "storage/browser/fileapi/file_system_context.h"
#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-namespace fileapi {
+namespace storage {
class FileSystemURL;
class OpenFileHandle;
class QuotaReservation;
@@ -36,12 +36,12 @@ class CONTENT_EXPORT QuotaReservation
public:
// Static method to facilitate construction on the file task runner.
static scoped_refptr<QuotaReservation> Create(
- scoped_refptr<fileapi::FileSystemContext> file_system_context,
+ scoped_refptr<storage::FileSystemContext> file_system_context,
const GURL& origin_url,
- fileapi::FileSystemType file_system_type);
+ storage::FileSystemType file_system_type);
// Opens a file with the given id and path and returns its current size.
- int64_t OpenFile(int32_t id, const fileapi::FileSystemURL& url);
+ int64_t OpenFile(int32_t id, const storage::FileSystemURL& url);
// Closes the file opened by OpenFile with the given id.
void CloseFile(int32_t id, const ppapi::FileGrowth& file_growth);
// Refreshes the quota reservation to a new amount. A map that associates file
@@ -65,15 +65,15 @@ class CONTENT_EXPORT QuotaReservation
friend class QuotaReservationTest;
QuotaReservation(
- scoped_refptr<fileapi::FileSystemContext> file_system_context,
+ scoped_refptr<storage::FileSystemContext> file_system_context,
const GURL& origin_url,
- fileapi::FileSystemType file_system_type);
+ storage::FileSystemType file_system_type);
// For unit testing only. A QuotaReservation intended for unit testing will
// have file_system_context_ == NULL.
- QuotaReservation(scoped_refptr<fileapi::QuotaReservation> quota_reservation,
+ QuotaReservation(scoped_refptr<storage::QuotaReservation> quota_reservation,
const GURL& origin_url,
- fileapi::FileSystemType file_system_type);
+ storage::FileSystemType file_system_type);
~QuotaReservation();
@@ -82,9 +82,9 @@ class CONTENT_EXPORT QuotaReservation
void DeleteOnCorrectThread() const;
- scoped_refptr<fileapi::FileSystemContext> file_system_context_;
- scoped_refptr<fileapi::QuotaReservation> quota_reservation_;
- typedef std::map<int32_t, fileapi::OpenFileHandle*> FileMap;
+ scoped_refptr<storage::FileSystemContext> file_system_context_;
+ scoped_refptr<storage::QuotaReservation> quota_reservation_;
+ typedef std::map<int32_t, storage::OpenFileHandle*> FileMap;
FileMap files_;
DISALLOW_COPY_AND_ASSIGN(QuotaReservation);
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 e949074efb8..6eb6f13b4d1 100644
--- a/chromium/content/browser/renderer_host/pepper/quota_reservation_unittest.cc
+++ b/chromium/content/browser/renderer_host/pepper/quota_reservation_unittest.cc
@@ -6,22 +6,22 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/file_util.h"
#include "base/files/file.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "storage/browser/fileapi/quota/quota_reservation.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/fileapi/quota/quota_reservation.h"
-using fileapi::QuotaReservationManager;
+using storage::QuotaReservationManager;
namespace content {
namespace {
const char kOrigin[] = "http://example.com";
-const fileapi::FileSystemType kType = fileapi::kFileSystemTypeTemporary;
+const storage::FileSystemType kType = storage::kFileSystemTypeTemporary;
const base::FilePath::StringType file1_name = FILE_PATH_LITERAL("file1");
const base::FilePath::StringType file2_name = FILE_PATH_LITERAL("file2");
@@ -33,30 +33,30 @@ const int kFile3ID = 3;
class FakeBackend : public QuotaReservationManager::QuotaBackend {
public:
FakeBackend() {}
- virtual ~FakeBackend() {}
+ ~FakeBackend() override {}
- virtual void ReserveQuota(
+ void ReserveQuota(
const GURL& origin,
- fileapi::FileSystemType type,
+ storage::FileSystemType type,
int64 delta,
- const QuotaReservationManager::ReserveQuotaCallback& callback) OVERRIDE {
+ const QuotaReservationManager::ReserveQuotaCallback& callback) override {
base::MessageLoopProxy::current()->PostTask(
FROM_HERE,
base::Bind(base::IgnoreResult(callback), base::File::FILE_OK, delta));
}
- virtual void ReleaseReservedQuota(const GURL& origin,
- fileapi::FileSystemType type,
- int64 size) OVERRIDE {}
+ void ReleaseReservedQuota(const GURL& origin,
+ storage::FileSystemType type,
+ int64 size) override {}
- virtual void CommitQuotaUsage(const GURL& origin,
- fileapi::FileSystemType type,
- int64 delta) OVERRIDE {}
+ void CommitQuotaUsage(const GURL& origin,
+ storage::FileSystemType type,
+ int64 delta) override {}
- virtual void IncrementDirtyCount(const GURL& origin,
- fileapi::FileSystemType type) OVERRIDE {}
- virtual void DecrementDirtyCount(const GURL& origin,
- fileapi::FileSystemType type) OVERRIDE {}
+ void IncrementDirtyCount(const GURL& origin,
+ storage::FileSystemType type) override {}
+ void DecrementDirtyCount(const GURL& origin,
+ storage::FileSystemType type) override {}
private:
DISALLOW_COPY_AND_ASSIGN(FakeBackend);
@@ -67,16 +67,16 @@ class FakeBackend : public QuotaReservationManager::QuotaBackend {
class QuotaReservationTest : public testing::Test {
public:
QuotaReservationTest() {}
- virtual ~QuotaReservationTest() {}
+ ~QuotaReservationTest() override {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
ASSERT_TRUE(work_dir_.CreateUniqueTempDir());
reservation_manager_.reset(new QuotaReservationManager(
scoped_ptr<QuotaReservationManager::QuotaBackend>(new FakeBackend)));
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
reservation_manager_.reset();
base::RunLoop().RunUntilIdle();
}
@@ -85,16 +85,16 @@ class QuotaReservationTest : public testing::Test {
return work_dir_.path().Append(file_name);
}
- fileapi::FileSystemURL MakeFileSystemURL(
+ storage::FileSystemURL MakeFileSystemURL(
const base::FilePath::StringType& file_name) {
- return fileapi::FileSystemURL::CreateForTest(
+ return storage::FileSystemURL::CreateForTest(
GURL(kOrigin), kType, MakeFilePath(file_name));
}
scoped_refptr<QuotaReservation> CreateQuotaReservation(
- scoped_refptr<fileapi::QuotaReservation> reservation,
+ scoped_refptr<storage::QuotaReservation> reservation,
const GURL& origin,
- fileapi::FileSystemType type) {
+ storage::FileSystemType type) {
// Sets reservation_ as a side effect.
return scoped_refptr<QuotaReservation>(
new QuotaReservation(reservation, origin, type));
@@ -114,7 +114,7 @@ class QuotaReservationTest : public testing::Test {
private:
base::MessageLoop message_loop_;
base::ScopedTempDir work_dir_;
- scoped_ptr<fileapi::QuotaReservationManager> reservation_manager_;
+ scoped_ptr<storage::QuotaReservationManager> reservation_manager_;
DISALLOW_COPY_AND_ASSIGN(QuotaReservationTest);
};
@@ -148,9 +148,9 @@ void ReserveQuota(scoped_refptr<QuotaReservation> quota_reservation,
// 2) Open a file, grow it, close it, and reserve quota with correct sizes.
TEST_F(QuotaReservationTest, ReserveQuota) {
GURL origin(kOrigin);
- fileapi::FileSystemType type = kType;
+ storage::FileSystemType type = kType;
- scoped_refptr<fileapi::QuotaReservation> reservation(
+ scoped_refptr<storage::QuotaReservation> reservation(
reservation_manager()->CreateReservation(origin, type));
scoped_refptr<QuotaReservation> test =
CreateQuotaReservation(reservation, origin, type);
@@ -189,9 +189,9 @@ TEST_F(QuotaReservationTest, ReserveQuota) {
// 1) We can open and close multiple files.
TEST_F(QuotaReservationTest, MultipleFiles) {
GURL origin(kOrigin);
- fileapi::FileSystemType type = kType;
+ storage::FileSystemType type = kType;
- scoped_refptr<fileapi::QuotaReservation> reservation(
+ scoped_refptr<storage::QuotaReservation> reservation(
reservation_manager()->CreateReservation(origin, type));
scoped_refptr<QuotaReservation> test =
CreateQuotaReservation(reservation, origin, type);
diff --git a/chromium/content/browser/renderer_host/render_message_filter.cc b/chromium/content/browser/renderer_host/render_message_filter.cc
index cb1617089fc..0474e081bc7 100644
--- a/chromium/content/browser/renderer_host/render_message_filter.cc
+++ b/chromium/content/browser/renderer_host/render_message_filter.cc
@@ -10,6 +10,7 @@
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/debug/alias.h"
+#include "base/numerics/safe_math.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
@@ -19,21 +20,25 @@
#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/gpu/browser_gpu_memory_buffer_manager.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/media/media_internals.h"
#include "content/browser/plugin_process_host.h"
-#include "content/browser/plugin_service_impl.h"
-#include "content/browser/ppapi_plugin_process_host.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/renderer_host/render_widget_resize_helper.h"
+#include "content/browser/transition_request_manager.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/cookie_data.h"
#include "content/common/desktop_notification_messages.h"
#include "content/common/frame_messages.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+#include "content/common/host_discardable_shared_memory_manager.h"
#include "content/common/host_shared_bitmap_manager.h"
#include "content/common/media/media_param_traits.h"
#include "content/common/view_messages.h"
@@ -87,6 +92,11 @@
#include "media/base/android/webaudio_media_codec_bridge.h"
#endif
+#if defined(ENABLE_PLUGINS)
+#include "content/browser/plugin_service_impl.h"
+#include "content/browser/ppapi_plugin_process_host.h"
+#endif
+
using net::CookieStore;
namespace content {
@@ -96,10 +106,6 @@ namespace {
const int kPluginsRefreshThresholdInSeconds = 3;
#endif
-// When two CPU usage queries arrive within this interval, we sample the CPU
-// usage only once and send it as a response for both queries.
-static const int64 kCPUUsageSampleIntervalMs = 900;
-
const uint32 kFilteredMessageClasses[] = {
ChildProcessMsgStart,
DesktopNotificationMsgStart,
@@ -143,6 +149,7 @@ class RenderMessageCompletionCallback {
IPC::Message* reply_msg_;
};
+#if defined(ENABLE_PLUGINS)
class OpenChannelToPpapiPluginCallback
: public RenderMessageCompletionCallback,
public PpapiPluginProcessHost::PluginClient {
@@ -154,27 +161,23 @@ class OpenChannelToPpapiPluginCallback
context_(context) {
}
- virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
- int* renderer_id) OVERRIDE {
+ void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
+ int* renderer_id) override {
*renderer_handle = filter()->PeerHandle();
*renderer_id = filter()->render_process_id();
}
- virtual void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle,
- base::ProcessId plugin_pid,
- int plugin_child_id) OVERRIDE {
+ void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int plugin_child_id) override {
ViewHostMsg_OpenChannelToPepperPlugin::WriteReplyParams(
reply_msg(), channel_handle, plugin_pid, plugin_child_id);
SendReplyAndDeleteThis();
}
- virtual bool OffTheRecord() OVERRIDE {
- return filter()->OffTheRecord();
- }
+ bool OffTheRecord() override { return filter()->OffTheRecord(); }
- virtual ResourceContext* GetResourceContext() OVERRIDE {
- return context_;
- }
+ ResourceContext* GetResourceContext() override { return context_; }
private:
ResourceContext* context_;
@@ -189,31 +192,30 @@ class OpenChannelToPpapiBrokerCallback
routing_id_(routing_id) {
}
- virtual ~OpenChannelToPpapiBrokerCallback() {}
+ ~OpenChannelToPpapiBrokerCallback() override {}
- virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
- int* renderer_id) OVERRIDE {
+ void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
+ int* renderer_id) override {
*renderer_handle = filter_->PeerHandle();
*renderer_id = filter_->render_process_id();
}
- virtual void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle,
- base::ProcessId plugin_pid,
- int /* plugin_child_id */) OVERRIDE {
+ void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle,
+ base::ProcessId plugin_pid,
+ int /* plugin_child_id */) override {
filter_->Send(new ViewMsg_PpapiBrokerChannelCreated(routing_id_,
plugin_pid,
channel_handle));
delete this;
}
- virtual bool OffTheRecord() OVERRIDE {
- return filter_->OffTheRecord();
- }
+ bool OffTheRecord() override { return filter_->OffTheRecord(); }
private:
scoped_refptr<RenderMessageFilter> filter_;
int routing_id_;
};
+#endif // defined(ENABLE_PLUGINS)
} // namespace
@@ -230,15 +232,11 @@ class RenderMessageFilter::OpenChannelToNpapiPluginCallback
sent_plugin_channel_request_(false) {
}
- virtual int ID() OVERRIDE {
- return filter()->render_process_id();
- }
+ int ID() override { return filter()->render_process_id(); }
- virtual ResourceContext* GetResourceContext() OVERRIDE {
- return context_;
- }
+ ResourceContext* GetResourceContext() override { return context_; }
- virtual bool OffTheRecord() OVERRIDE {
+ bool OffTheRecord() override {
if (filter()->OffTheRecord())
return true;
if (GetContentClient()->browser()->AllowSaveLocalState(context_))
@@ -252,26 +250,22 @@ class RenderMessageFilter::OpenChannelToNpapiPluginCallback
return false;
}
- virtual void SetPluginInfo(const WebPluginInfo& info) OVERRIDE {
- info_ = info;
- }
+ void SetPluginInfo(const WebPluginInfo& info) override { info_ = info; }
- virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
+ void OnFoundPluginProcessHost(PluginProcessHost* host) override {
DCHECK(host);
host_ = host;
}
- virtual void OnSentPluginChannelRequest() OVERRIDE {
+ void OnSentPluginChannelRequest() override {
sent_plugin_channel_request_ = true;
}
- virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
+ void OnChannelOpened(const IPC::ChannelHandle& handle) override {
WriteReplyAndDeleteThis(handle);
}
- virtual void OnError() OVERRIDE {
- WriteReplyAndDeleteThis(IPC::ChannelHandle());
- }
+ void OnError() override { WriteReplyAndDeleteThis(IPC::ChannelHandle()); }
PluginProcessHost* host() const {
return host_;
@@ -319,12 +313,12 @@ RenderMessageFilter::RenderMessageFilter(
incognito_(browser_context->IsOffTheRecord()),
dom_storage_context_(dom_storage_context),
render_process_id_(render_process_id),
- cpu_usage_(0),
audio_manager_(audio_manager),
media_internals_(media_internals) {
DCHECK(request_context_.get());
- render_widget_helper_->Init(render_process_id_, resource_dispatcher_host_);
+ if (render_widget_helper)
+ render_widget_helper_->Init(render_process_id_, resource_dispatcher_host_);
}
RenderMessageFilter::~RenderMessageFilter() {
@@ -332,6 +326,11 @@ RenderMessageFilter::~RenderMessageFilter() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(plugin_host_clients_.empty());
HostSharedBitmapManager::current()->ProcessRemoved(PeerHandle());
+ BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager =
+ BrowserGpuMemoryBufferManager::current();
+ if (gpu_memory_buffer_manager)
+ gpu_memory_buffer_manager->ProcessRemoved(PeerHandle(), render_process_id_);
+ HostDiscardableSharedMemoryManager::current()->ProcessRemoved(PeerHandle());
}
void RenderMessageFilter::OnChannelClosing() {
@@ -354,18 +353,6 @@ void RenderMessageFilter::OnChannelClosing() {
plugin_host_clients_.clear();
}
-void RenderMessageFilter::OnChannelConnected(int32 peer_id) {
- base::ProcessHandle handle = PeerHandle();
-#if defined(OS_MACOSX)
- process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(handle,
- NULL));
-#else
- process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(handle));
-#endif
- cpu_usage_ = process_metrics_->GetCPUUsage(); // Initialize CPU usage counters
- cpu_usage_sample_time_ = base::TimeTicks::Now();
-}
-
bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderMessageFilter, message)
@@ -389,6 +376,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_LoadFont, OnLoadFont)
#endif
IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SaveImageFromDataURL,
+ OnSaveImageFromDataURL)
#if defined(ENABLE_PLUGINS)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPlugins, OnGetPlugins)
IPC_MESSAGE_HANDLER(FrameHostMsg_GetPluginInfo, OnGetPluginInfo)
@@ -403,20 +392,32 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToPpapiBroker,
OnOpenChannelToPpapiBroker)
#endif
+#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
- render_widget_helper_->DidReceiveBackingStoreMsg(message))
+ RenderWidgetResizeHelper::Get()->PostRendererProcessMsg(
+ render_process_id_, message))
IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_UpdateRect,
- render_widget_helper_->DidReceiveBackingStoreMsg(message))
+ RenderWidgetResizeHelper::Get()->PostRendererProcessMsg(
+ render_process_id_, message))
+#endif
IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_CheckPermission,
OnCheckNotificationPermission)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory,
OnAllocateSharedMemory)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
ChildProcessHostMsg_SyncAllocateSharedBitmap, OnAllocateSharedBitmap)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(
+ ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
+ OnAllocateGpuMemoryBuffer)
+ IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DeletedGpuMemoryBuffer,
+ OnDeletedGpuMemoryBuffer)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_AllocatedSharedBitmap,
OnAllocatedSharedBitmap)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_DeletedSharedBitmap,
OnDeletedSharedBitmap)
+ IPC_MESSAGE_HANDLER(
+ ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory,
+ OnAllocateLockedDiscardableSharedMemory)
#if defined(OS_POSIX) && !defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB, OnAllocTransportDIB)
IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB, OnFreeTransportDIB)
@@ -424,7 +425,6 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewHostMsg_DidGenerateCacheableMetadata,
OnCacheableMetadataAvailable)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_Keygen, OnKeygen)
- IPC_MESSAGE_HANDLER(ViewHostMsg_GetCPUUsage, OnGetCPUUsage)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetAudioHardwareConfig,
OnGetAudioHardwareConfig)
#if defined(OS_WIN)
@@ -437,6 +437,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
#if defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(ViewHostMsg_RunWebAudioMediaCodec, OnWebAudioMediaCodec)
#endif
+ IPC_MESSAGE_HANDLER(FrameHostMsg_AddNavigationTransitionData,
+ OnAddNavigationTransitionData)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -504,6 +506,7 @@ void RenderMessageFilter::OnCreateWindow(
*route_id = MSG_ROUTING_NONE;
*main_frame_route_id = MSG_ROUTING_NONE;
*surface_id = 0;
+ *cloned_session_storage_namespace_id = 0;
return;
}
@@ -546,7 +549,7 @@ void RenderMessageFilter::OnGetProcessMemorySizes(size_t* private_bytes,
PeerHandle()));
#else
scoped_ptr<ProcessMetrics> metrics(ProcessMetrics::CreateProcessMetrics(
- PeerHandle(), content::BrowserChildProcessHost::GetPortProvider()));
+ PeerHandle(), BrowserChildProcessHost::GetPortProvider()));
#endif
if (!metrics->GetMemoryBytes(private_bytes, shared_bytes)) {
*private_bytes = 0;
@@ -822,16 +825,6 @@ void RenderMessageFilter::OnGenerateRoutingID(int* route_id) {
*route_id = render_widget_helper_->GetNextRoutingID();
}
-void RenderMessageFilter::OnGetCPUUsage(int* cpu_usage) {
- base::TimeTicks now = base::TimeTicks::Now();
- int64 since_last_sample_ms = (now - cpu_usage_sample_time_).InMilliseconds();
- if (since_last_sample_ms > kCPUUsageSampleIntervalMs) {
- cpu_usage_sample_time_ = now;
- cpu_usage_ = static_cast<int>(process_metrics_->GetCPUUsage());
- }
- *cpu_usage = cpu_usage_;
-}
-
void RenderMessageFilter::OnGetAudioHardwareConfig(
media::AudioParameters* input_params,
media::AudioParameters* output_params) {
@@ -851,11 +844,11 @@ void RenderMessageFilter::OnGetMonitorColorProfile(std::vector<char>* profile) {
}
#endif
-void RenderMessageFilter::OnDownloadUrl(int render_view_id,
- const GURL& url,
- const Referrer& referrer,
- const base::string16& suggested_name,
- const bool use_prompt) {
+void RenderMessageFilter::DownloadUrl(int render_view_id,
+ const GURL& url,
+ const Referrer& referrer,
+ const base::string16& suggested_name,
+ const bool use_prompt) const {
scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
save_info->suggested_name = suggested_name;
save_info->prompt_for_save_location = use_prompt;
@@ -867,6 +860,7 @@ void RenderMessageFilter::OnDownloadUrl(int render_view_id,
// default cookie store.
// TODO(tburkard): retrieve the appropriate special cookie store, if this
// is ever to be used for downloads as well.
+
scoped_ptr<net::URLRequest> request(
resource_context_->GetRequestContext()->CreateRequest(
url, net::DEFAULT_PRIORITY, NULL, NULL));
@@ -880,10 +874,30 @@ void RenderMessageFilter::OnDownloadUrl(int render_view_id,
render_view_id,
false,
save_info.Pass(),
- content::DownloadItem::kInvalidId,
+ DownloadItem::kInvalidId,
ResourceDispatcherHostImpl::DownloadStartedCallback());
}
+void RenderMessageFilter::OnDownloadUrl(int render_view_id,
+ const GURL& url,
+ const Referrer& referrer,
+ const base::string16& suggested_name) {
+ DownloadUrl(render_view_id, url, referrer, suggested_name, false);
+}
+
+void RenderMessageFilter::OnSaveImageFromDataURL(int render_view_id,
+ const std::string& url_str) {
+ // Please refer to RenderViewImpl::saveImageFromDataURL().
+ if (url_str.length() >= kMaxLengthOfDataURLString)
+ return;
+
+ GURL data_url(url_str);
+ if (!data_url.SchemeIs(url::kDataScheme))
+ return;
+
+ DownloadUrl(render_view_id, data_url, Referrer(), base::string16(), true);
+}
+
void RenderMessageFilter::OnCheckNotificationPermission(
const GURL& source_origin, int* result) {
#if defined(ENABLE_NOTIFICATIONS)
@@ -939,6 +953,14 @@ void RenderMessageFilter::OnDeletedSharedBitmap(const cc::SharedBitmapId& id) {
HostSharedBitmapManager::current()->ChildDeletedSharedBitmap(id);
}
+void RenderMessageFilter::OnAllocateLockedDiscardableSharedMemory(
+ uint32 size,
+ base::SharedMemoryHandle* handle) {
+ HostDiscardableSharedMemoryManager::current()
+ ->AllocateLockedDiscardableSharedMemoryForChild(
+ PeerHandle(), size, handle);
+}
+
net::CookieStore* RenderMessageFilter::GetCookieStoreForURL(
const GURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -977,24 +999,10 @@ void RenderMessageFilter::OnFreeTransportDIB(
}
#endif
-bool RenderMessageFilter::CheckPreparsedJsCachingEnabled() const {
- static bool checked = false;
- static bool result = false;
- if (!checked) {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- result = command_line.HasSwitch(switches::kEnablePreparsedJsCaching);
- checked = true;
- }
- return result;
-}
-
void RenderMessageFilter::OnCacheableMetadataAvailable(
const GURL& url,
double expected_response_time,
const std::vector<char>& data) {
- if (!CheckPreparsedJsCachingEnabled())
- return;
-
net::HttpCache* cache = request_context_->GetURLRequestContext()->
http_transaction_factory()->GetCache();
DCHECK(cache);
@@ -1220,4 +1228,61 @@ void RenderMessageFilter::OnWebAudioMediaCodec(
}
#endif
+void RenderMessageFilter::OnAddNavigationTransitionData(
+ FrameHostMsg_AddNavigationTransitionData_Params params) {
+ if (params.elements.size() > TransitionRequestManager::kMaxNumOfElements)
+ return;
+ TransitionRequestManager::GetInstance()->AddPendingTransitionRequestData(
+ render_process_id_,
+ params.render_frame_id,
+ params.allowed_destination_host_pattern,
+ params.selector,
+ params.markup,
+ params.elements);
+}
+
+void RenderMessageFilter::OnAllocateGpuMemoryBuffer(
+ uint32 width,
+ uint32 height,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ IPC::Message* reply) {
+ DCHECK(BrowserGpuMemoryBufferManager::current());
+
+ base::CheckedNumeric<int> size = width;
+ size *= height;
+ if (!size.IsValid()) {
+ GpuMemoryBufferAllocated(reply, gfx::GpuMemoryBufferHandle());
+ return;
+ }
+
+ BrowserGpuMemoryBufferManager::current()
+ ->AllocateGpuMemoryBufferForChildProcess(
+ gfx::Size(width, height),
+ format,
+ usage,
+ PeerHandle(),
+ render_process_id_,
+ base::Bind(
+ &RenderMessageFilter::GpuMemoryBufferAllocated, this, reply));
+}
+
+void RenderMessageFilter::GpuMemoryBufferAllocated(
+ IPC::Message* reply,
+ const gfx::GpuMemoryBufferHandle& handle) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer::WriteReplyParams(reply,
+ handle);
+ Send(reply);
+}
+
+void RenderMessageFilter::OnDeletedGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ uint32 sync_point) {
+ DCHECK(BrowserGpuMemoryBufferManager::current());
+
+ BrowserGpuMemoryBufferManager::current()->ChildProcessDeletedGpuMemoryBuffer(
+ id, PeerHandle(), render_process_id_, sync_point);
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_message_filter.h b/chromium/content/browser/renderer_host/render_message_filter.h
index 95a80acbf0c..9d836262035 100644
--- a/chromium/content/browser/renderer_host/render_message_filter.h
+++ b/chromium/content/browser/renderer_host/render_message_filter.h
@@ -20,7 +20,6 @@
#include "base/strings/string16.h"
#include "build/build_config.h"
#include "cc/resources/shared_bitmap_manager.h"
-#include "content/common/pepper_renderer_instance_data.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/common/three_d_api_types.h"
#include "ipc/message_filter.h"
@@ -28,10 +27,14 @@
#include "media/base/channel_layout.h"
#include "net/cookies/canonical_cookie.h"
#include "third_party/WebKit/public/web/WebPopupType.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/surface/transport_dib.h"
#if defined(OS_MACOSX)
+#include <IOSurface/IOSurfaceAPI.h>
+#include "base/mac/scoped_cftyperef.h"
#include "content/common/mac/font_loader.h"
#endif
@@ -39,7 +42,12 @@
#include "base/threading/worker_pool.h"
#endif
+#if defined(ENABLE_PLUGINS)
+#include "content/common/pepper_renderer_instance_data.h"
+#endif
+
struct FontDescriptor;
+struct FrameHostMsg_AddNavigationTransitionData_Params;
struct ViewHostMsg_CreateWindow_Params;
namespace blink {
@@ -52,6 +60,10 @@ class SharedMemory;
class TaskRunner;
}
+namespace gfx {
+struct GpuMemoryBufferHandle;
+}
+
namespace media {
class AudioManager;
struct MediaLogEvent;
@@ -77,7 +89,7 @@ struct WebPluginInfo;
// This class filters out incoming IPC messages for the renderer process on the
// IPC thread.
-class RenderMessageFilter : public BrowserMessageFilter {
+class CONTENT_EXPORT RenderMessageFilter : public BrowserMessageFilter {
public:
// Create the filter.
RenderMessageFilter(int render_process_id,
@@ -90,14 +102,13 @@ class RenderMessageFilter : public BrowserMessageFilter {
DOMStorageContextWrapper* dom_storage_context);
// IPC::MessageFilter methods:
- virtual void OnChannelClosing() OVERRIDE;
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
+ void OnChannelClosing() override;
// BrowserMessageFilter methods:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
- virtual base::TaskRunner* OverrideTaskRunnerForMessage(
- const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnDestruct() const override;
+ base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& message) override;
bool OffTheRecord() const;
@@ -108,14 +119,22 @@ class RenderMessageFilter : public BrowserMessageFilter {
// Only call on the IO thread.
net::CookieStore* GetCookieStoreForURL(const GURL& url);
+ protected:
+ ~RenderMessageFilter() override;
+
+ // This method will be overridden by TestSaveImageFromDataURL class for test.
+ virtual void DownloadUrl(int render_view_id,
+ const GURL& url,
+ const Referrer& referrer,
+ const base::string16& suggested_name,
+ const bool use_prompt) const;
+
private:
friend class BrowserThread;
friend class base::DeleteHelper<RenderMessageFilter>;
class OpenChannelToNpapiPluginCallback;
- virtual ~RenderMessageFilter();
-
void OnGetProcessMemorySizes(size_t* private_bytes, size_t* shared_bytes);
void OnCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
int* route_id,
@@ -158,6 +177,7 @@ class RenderMessageFilter : public BrowserMessageFilter {
const base::string16& characters);
#endif
+#if defined(ENABLE_PLUGINS)
void OnGetPlugins(bool refresh, IPC::Message* reply_msg);
void GetPluginsCallback(IPC::Message* reply_msg,
const std::vector<WebPluginInfo>& plugins);
@@ -185,17 +205,16 @@ class RenderMessageFilter : public BrowserMessageFilter {
bool is_external);
void OnOpenChannelToPpapiBroker(int routing_id,
const base::FilePath& path);
+#endif // defined(ENABLE_PLUGINS)
void OnGenerateRoutingID(int* route_id);
void OnDownloadUrl(int render_view_id,
const GURL& url,
const Referrer& referrer,
- const base::string16& suggested_name,
- const bool use_prompt);
+ const base::string16& suggested_name);
+ void OnSaveImageFromDataURL(int render_view_id, const std::string& url_str);
void OnCheckNotificationPermission(const GURL& source_origin,
int* permission_level);
- void OnGetCPUUsage(int* cpu_usage);
-
void OnGetAudioHardwareConfig(media::AudioParameters* input_params,
media::AudioParameters* output_params);
@@ -221,6 +240,11 @@ class RenderMessageFilter : public BrowserMessageFilter {
void OnDeletedSharedBitmap(const cc::SharedBitmapId& id);
void OnResolveProxy(const GURL& url, IPC::Message* reply_msg);
+ // Browser side discardable shared memory allocation.
+ void OnAllocateLockedDiscardableSharedMemory(
+ uint32 size,
+ base::SharedMemoryHandle* handle);
+
// Browser side transport DIB allocation
void OnAllocTransportDIB(uint32 size,
bool cache_in_browser,
@@ -270,6 +294,19 @@ class RenderMessageFilter : public BrowserMessageFilter {
uint32_t data_size);
#endif
+ void OnAddNavigationTransitionData(
+ FrameHostMsg_AddNavigationTransitionData_Params params);
+
+ void OnAllocateGpuMemoryBuffer(uint32 width,
+ uint32 height,
+ gfx::GpuMemoryBuffer::Format format,
+ gfx::GpuMemoryBuffer::Usage usage,
+ IPC::Message* reply);
+ void GpuMemoryBufferAllocated(IPC::Message* reply,
+ const gfx::GpuMemoryBufferHandle& handle);
+ void OnDeletedGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ uint32 sync_point);
+
// Cached resource request dispatcher host and plugin service, guaranteed to
// be non-null if Init succeeds. We do not own the objects, they are managed
// by the BrowserProcess, which has a wider scope than we do.
@@ -298,13 +335,6 @@ class RenderMessageFilter : public BrowserMessageFilter {
std::set<OpenChannelToNpapiPluginCallback*> plugin_host_clients_;
- // Records the last time we sampled CPU usage of the renderer process.
- base::TimeTicks cpu_usage_sample_time_;
- // Records the last sampled CPU usage in percents.
- int cpu_usage_;
- // Used for sampling CPU usage of the renderer process.
- scoped_ptr<base::ProcessMetrics> process_metrics_;
-
media::AudioManager* audio_manager_;
MediaInternals* media_internals_;
diff --git a/chromium/content/browser/renderer_host/render_process_host_browsertest.cc b/chromium/content/browser/renderer_host/render_process_host_browsertest.cc
index b77f20fa44b..f2856bfdc86 100644
--- a/chromium/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -2,18 +2,24 @@
// 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/renderer_host/render_process_host_impl.h"
#include "content/common/child_process_messages.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.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 "net/test/embedded_test_server/embedded_test_server.h"
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
namespace content {
namespace {
@@ -36,13 +42,12 @@ class RenderProcessHostTest : public ContentBrowserTest,
protected:
// RenderProcessHostObserver:
- virtual void RenderProcessExited(RenderProcessHost* host,
- base::ProcessHandle handle,
- base::TerminationStatus status,
- int exit_code) OVERRIDE {
+ void RenderProcessExited(RenderProcessHost* host,
+ base::TerminationStatus status,
+ int exit_code) override {
++process_exits_;
}
- virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
+ void RenderProcessHostDestroyed(RenderProcessHost* host) override {
++host_destructions_;
}
@@ -115,15 +120,14 @@ class ShellCloser : public RenderProcessHostObserver {
protected:
// RenderProcessHostObserver:
- virtual void RenderProcessExited(RenderProcessHost* host,
- base::ProcessHandle handle,
- base::TerminationStatus status,
- int exit_code) OVERRIDE {
+ void RenderProcessExited(RenderProcessHost* host,
+ base::TerminationStatus status,
+ int exit_code) override {
logging_string_->append("ShellCloser::RenderProcessExited ");
shell_->Close();
}
- virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
+ void RenderProcessHostDestroyed(RenderProcessHost* host) override {
logging_string_->append("ShellCloser::RenderProcessHostDestroyed ");
}
@@ -140,14 +144,13 @@ class ObserverLogger : public RenderProcessHostObserver {
protected:
// RenderProcessHostObserver:
- virtual void RenderProcessExited(RenderProcessHost* host,
- base::ProcessHandle handle,
- base::TerminationStatus status,
- int exit_code) OVERRIDE {
+ void RenderProcessExited(RenderProcessHost* host,
+ base::TerminationStatus status,
+ int exit_code) override {
logging_string_->append("ObserverLogger::RenderProcessExited ");
}
- virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE {
+ void RenderProcessHostDestroyed(RenderProcessHost* host) override {
logging_string_->append("ObserverLogger::RenderProcessHostDestroyed ");
host_destroyed_ = true;
}
@@ -192,5 +195,42 @@ IN_PROC_BROWSER_TEST_F(RenderProcessHostTest,
}
}
+#if defined(OS_WIN)
+// Provides functionality to test renderer processes with the Win32K lockdown
+// process mitigation.
+class Win32KLockdownRendererProcessHostTest : public RenderProcessHostTest {
+ public:
+ Win32KLockdownRendererProcessHostTest() {}
+
+ virtual ~Win32KLockdownRendererProcessHostTest() {}
+
+ protected:
+ virtual void SetUp() override {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitch(switches::kEnableWin32kRendererLockDown);
+ RenderProcessHostTest::SetUp();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Win32KLockdownRendererProcessHostTest);
+};
+
+// Tests whether navigation requests with the Win32K lockdown mitigation set
+// work correctly.
+IN_PROC_BROWSER_TEST_F(Win32KLockdownRendererProcessHostTest,
+ RendererWin32KLockdownNavigationTest) {
+ if (base::win::GetVersion() < base::win::VERSION_WIN8)
+ return;
+
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ GURL test_url = embedded_test_server()->GetURL("/simple_page.html");
+ NavigateToURL(shell(), test_url);
+
+ EXPECT_EQ(1, RenderProcessHostCount());
+ EXPECT_EQ(0, process_exits_);
+}
+#endif
+
} // namespace
} // namespace content
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 2eafd8c9c47..c582a6e97a6 100644
--- a/chromium/content/browser/renderer_host/render_process_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_impl.cc
@@ -11,10 +11,6 @@
#include <limits>
#include <vector>
-#if defined(OS_POSIX)
-#include <utility> // for pair<>
-#endif
-
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -26,8 +22,7 @@
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
-#include "base/numerics/safe_math.h"
-#include "base/path_service.h"
+#include "base/process/process_handle.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -40,12 +35,12 @@
#include "cc/base/switches.h"
#include "content/browser/appcache/appcache_dispatcher_host.h"
#include "content/browser/appcache/chrome_appcache_service.h"
-#include "content/browser/battery_status/battery_status_message_filter.h"
#include "content/browser/browser_child_process_host_impl.h"
#include "content/browser/browser_main.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/browser_plugin/browser_plugin_message_filter.h"
#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/device_sensors/device_light_message_filter.h"
#include "content/browser/device_sensors/device_motion_message_filter.h"
#include "content/browser/device_sensors/device_orientation_message_filter.h"
#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
@@ -54,6 +49,7 @@
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/fileapi/fileapi_message_filter.h"
#include "content/browser/frame_host/render_frame_message_filter.h"
+#include "content/browser/geofencing/geofencing_dispatcher_host.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
@@ -69,9 +65,9 @@
#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/plugin_service_impl.h"
+#include "content/browser/notifications/notification_message_filter.h"
#include "content/browser/profiler_message_filter.h"
-#include "content/browser/push_messaging_message_filter.h"
+#include "content/browser/push_messaging/push_messaging_message_filter.h"
#include "content/browser/quota_dispatcher_host.h"
#include "content/browser/renderer_host/clipboard_message_filter.h"
#include "content/browser/renderer_host/database_message_filter.h"
@@ -80,12 +76,10 @@
#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/device_request_message_filter.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/p2p/socket_dispatcher_host.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"
@@ -93,26 +87,22 @@
#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_impl.h"
-#include "content/browser/renderer_host/socket_stream_dispatcher_host.h"
#include "content/browser/renderer_host/text_input_client_message_filter.h"
#include "content/browser/renderer_host/websocket_dispatcher_host.h"
#include "content/browser/resolve_proxy_msg_helper.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_dispatcher_host.h"
#include "content/browser/shared_worker/shared_worker_message_filter.h"
+#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/browser/speech/speech_recognition_dispatcher_host.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/streams/stream_context.h"
#include "content/browser/tracing/trace_message_filter.h"
#include "content/browser/vibration/vibration_message_filter.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
-#include "content/browser/worker_host/worker_message_filter.h"
-#include "content/browser/worker_host/worker_storage_partition.h"
#include "content/common/child_process_host_impl.h"
#include "content/common/child_process_messages.h"
#include "content/common/content_switches_internal.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl_shm.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/mojo/mojo_messages.h"
#include "content/common/resource_messages.h"
@@ -132,63 +122,66 @@
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/process_type.h"
+#include "content/public/common/resource_type.h"
#include "content/public/common/result_codes.h"
#include "content/public/common/sandboxed_process_launcher_delegate.h"
#include "content/public/common/url_constants.h"
+#include "device/battery/battery_monitor_impl.h"
+#include "gpu/command_buffer/client/gpu_switches.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_logging.h"
#include "ipc/ipc_switches.h"
+#include "ipc/mojo/ipc_channel_mojo.h"
+#include "ipc/mojo/ipc_channel_mojo_host.h"
#include "media/base/media_switches.h"
-#include "mojo/common/common_type_converters.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/skia/include/core/SkBitmap.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event_switches.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_switches.h"
+#include "ui/gl/gpu_switching_manager.h"
#include "ui/native_theme/native_theme_switches.h"
-#include "webkit/browser/fileapi/sandbox_file_system_backend.h"
-#include "webkit/common/resource_type.h"
#if defined(OS_ANDROID)
#include "content/browser/media/android/browser_demuxer_android.h"
-#include "content/browser/renderer_host/compositor_impl_android.h"
-#include "content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.h"
-#endif
-
-#if defined(OS_MACOSX)
-#include "content/common/gpu/client/gpu_memory_buffer_impl_io_surface.h"
+#include "content/browser/screen_orientation/screen_orientation_message_filter_android.h"
#endif
#if defined(OS_WIN)
-#include "base/strings/string_number_conversions.h"
#include "base/win/scoped_com_initializer.h"
#include "content/common/font_cache_dispatcher_win.h"
#include "content/common/sandbox_win.h"
#include "ui/gfx/win/dpi.h"
#endif
-#if defined(OS_MACOSX)
-#include "content/public/common/sandbox_type_mac.h"
+#if defined(ENABLE_BROWSER_CDMS)
+#include "content/browser/media/cdm/browser_cdm_manager.h"
+#endif
+
+#if defined(ENABLE_PLUGINS)
+#include "content/browser/plugin_service_impl.h"
#endif
#if defined(ENABLE_WEBRTC)
#include "content/browser/media/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"
#include "content/common/media/aec_dump_messages.h"
#include "content/common/media/media_stream_messages.h"
#endif
extern bool g_exited_main_message_loop;
-static const char* kSiteProcessMapKeyName = "content_site_process_map";
-
namespace content {
namespace {
+const char kSiteProcessMapKeyName[] = "content_site_process_map";
+
void CacheShaderInfo(int32 id, base::FilePath path) {
ShaderCacheFactory::GetInstance()->SetCacheInfo(id, path);
}
@@ -200,11 +193,11 @@ void RemoveShaderInfo(int32 id) {
net::URLRequestContext* GetRequestContext(
scoped_refptr<net::URLRequestContextGetter> request_context,
scoped_refptr<net::URLRequestContextGetter> media_request_context,
- ResourceType::Type resource_type) {
- // If the request has resource type of ResourceType::MEDIA, we use a request
+ ResourceType resource_type) {
+ // If the request has resource type of RESOURCE_TYPE_MEDIA, we use a request
// context specific to media for handling it because these resources have
// specific needs for caching.
- if (resource_type == ResourceType::MEDIA)
+ if (resource_type == RESOURCE_TYPE_MEDIA)
return media_request_context->GetURLRequestContext();
return request_context->GetURLRequestContext();
}
@@ -306,15 +299,15 @@ SiteProcessMap* GetSiteProcessMapForBrowserContext(BrowserContext* context) {
// NOTE: changes to this class need to be reviewed by the security team.
class RendererSandboxedProcessLauncherDelegate
- : public content::SandboxedProcessLauncherDelegate {
+ : public SandboxedProcessLauncherDelegate {
public:
- RendererSandboxedProcessLauncherDelegate(IPC::ChannelProxy* channel)
+ explicit RendererSandboxedProcessLauncherDelegate(IPC::ChannelProxy* channel)
#if defined(OS_POSIX)
- : ipc_fd_(channel->TakeClientFileDescriptor())
+ : ipc_fd_(channel->TakeClientFileDescriptor())
#endif // OS_POSIX
{}
- virtual ~RendererSandboxedProcessLauncherDelegate() {}
+ ~RendererSandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
@@ -324,51 +317,28 @@ class RendererSandboxedProcessLauncherDelegate
}
#elif defined(OS_POSIX)
- virtual bool ShouldUseZygote() OVERRIDE {
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
- CommandLine::StringType renderer_prefix =
+ bool ShouldUseZygote() 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();
}
- virtual int GetIpcFd() OVERRIDE {
- return ipc_fd_;
- }
-#if defined(OS_MACOSX)
- virtual SandboxType GetSandboxType() OVERRIDE {
- return SANDBOX_TYPE_RENDERER;
- }
-#endif
+ base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); }
#endif // OS_WIN
private:
#if defined(OS_POSIX)
- int ipc_fd_;
+ base::ScopedFD ipc_fd_;
#endif // OS_POSIX
};
-#if defined(OS_MACOSX)
-void AddBooleanValue(CFMutableDictionaryRef dictionary,
- const CFStringRef key,
- bool value) {
- CFDictionaryAddValue(
- dictionary, key, value ? kCFBooleanTrue : kCFBooleanFalse);
-}
-
-void AddIntegerValue(CFMutableDictionaryRef dictionary,
- const CFStringRef key,
- int32 value) {
- base::ScopedCFTypeRef<CFNumberRef> number(
- CFNumberCreate(NULL, kCFNumberSInt32Type, &value));
- CFDictionaryAddValue(dictionary, key, number.get());
-}
-#endif
-
const char kSessionStorageHolderKey[] = "kSessionStorageHolderKey";
class SessionStorageHolder : public base::SupportsUserData::Data {
public:
SessionStorageHolder() {}
- virtual ~SessionStorageHolder() {}
+ ~SessionStorageHolder() override {}
void Hold(const SessionStorageNamespaceMap& sessions, int view_route_id) {
session_storage_namespaces_awaiting_close_[view_route_id] = sessions;
@@ -404,15 +374,22 @@ size_t RenderProcessHost::GetMaxRendererProcessCount() {
if (g_max_renderer_count_override)
return g_max_renderer_count_override;
- // Defines the maximum number of renderer processes according to the
- // amount of installed memory as reported by the OS. The calculation
- // assumes that you want the renderers to use half of the installed
- // RAM and assuming that each WebContents uses ~40MB.
- // If you modify this assumption, you need to adjust the
- // ThirtyFourTabs test to match the expected number of processes.
+#if defined(OS_ANDROID)
+ // On Android we don't maintain a limit of renderer process hosts - we are
+ // happy with keeping a lot of these, as long as the number of live renderer
+ // processes remains reasonable, and on Android the OS takes care of that.
+ return std::numeric_limits<size_t>::max();
+#endif
+
+ // On other platforms, we calculate the maximum number of renderer process
+ // hosts according to the amount of installed memory as reported by the OS.
+ // The calculation assumes that you want the renderers to use half of the
+ // installed RAM and assuming that each WebContents uses ~40MB. If you modify
+ // this assumption, you need to adjust the ThirtyFourTabs test to match the
+ // expected number of processes.
//
- // With the given amounts of installed memory below on a 32-bit CPU,
- // the maximum renderer count will roughly be as follows:
+ // With the given amounts of installed memory below on a 32-bit CPU, the
+ // maximum renderer count will roughly be as follows:
//
// 128 MB -> 3
// 512 MB -> 6
@@ -456,7 +433,7 @@ RenderProcessHostImpl::RenderProcessHostImpl(
is_self_deleted_(false),
#endif
pending_views_(0),
- mojo_activation_required_(false),
+ mojo_application_host_(new MojoApplicationHost),
visible_widgets_(0),
backgrounded_(true),
is_initialized_(false),
@@ -483,7 +460,7 @@ RenderProcessHostImpl::RenderProcessHostImpl(
mark_child_process_activity_time();
if (!GetBrowserContext()->IsOffTheRecord() &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuShaderDiskCache)) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&CacheShaderInfo, GetID(),
@@ -539,7 +516,7 @@ RenderProcessHostImpl::~RenderProcessHostImpl() {
ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetID());
if (gpu_observer_registered_) {
- GpuDataManagerImpl::GetInstance()->RemoveObserver(this);
+ ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
gpu_observer_registered_ = false;
}
@@ -552,15 +529,11 @@ RenderProcessHostImpl::~RenderProcessHostImpl() {
UnregisterHost(GetID());
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuShaderDiskCache)) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&RemoveShaderInfo, GetID()));
}
-
-#if defined(OS_ANDROID)
- CompositorImpl::DestroyAllSurfaceTextures(GetID());
-#endif
}
void RenderProcessHostImpl::EnableSendQueue() {
@@ -573,11 +546,12 @@ bool RenderProcessHostImpl::Init() {
if (channel_)
return true;
- CommandLine::StringType renderer_prefix;
+ base::CommandLine::StringType renderer_prefix;
#if defined(OS_POSIX)
// A command prefix is something prepended to the command line of the spawned
// process. It is supported only on POSIX systems.
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
renderer_prefix =
browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);
#endif // defined(OS_POSIX)
@@ -598,20 +572,16 @@ bool RenderProcessHostImpl::Init() {
// Setup the IPC channel.
const std::string channel_id =
IPC::Channel::GenerateVerifiedChannelID(std::string());
- channel_ = IPC::ChannelProxy::Create(
- channel_id,
- IPC::Channel::MODE_SERVER,
- this,
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get());
+ channel_ = CreateChannelProxy(channel_id);
// Setup the Mojo channel.
- mojo_application_host_.reset(new MojoApplicationHost());
mojo_application_host_->Init();
// Call the embedder first so that their IPC filters have priority.
GetContentClient()->browser()->RenderProcessWillLaunch(this);
CreateMessageFilters();
+ RegisterMojoServices();
if (run_renderer_in_process()) {
DCHECK(g_renderer_main_thread_factory);
@@ -640,7 +610,7 @@ bool RenderProcessHostImpl::Init() {
} else {
// Build command line for renderer. We call AppendRendererCommandLine()
// first so the process type argument will appear first.
- CommandLine* cmd_line = new CommandLine(renderer_path);
+ base::CommandLine* cmd_line = new base::CommandLine(renderer_path);
if (!renderer_prefix.empty())
cmd_line->PrependWrapper(renderer_prefix);
AppendRendererCommandLine(cmd_line);
@@ -660,25 +630,43 @@ bool RenderProcessHostImpl::Init() {
if (!gpu_observer_registered_) {
gpu_observer_registered_ = true;
- GpuDataManagerImpl::GetInstance()->AddObserver(this);
+ ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
}
+ power_monitor_broadcaster_.Init();
+
is_initialized_ = true;
+ init_time_ = base::TimeTicks::Now();
return true;
}
-void RenderProcessHostImpl::MaybeActivateMojo() {
- // TODO(darin): Following security review, we can unconditionally initialize
- // Mojo in all renderers. We will then be able to directly call Activate()
- // from OnProcessLaunched.
- if (!mojo_activation_required_)
- return; // Waiting on someone to require Mojo.
+bool RenderProcessHostImpl::ShouldUseMojoChannel() const {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ return command_line.HasSwitch(switches::kEnableRendererMojoChannel) ||
+ IPC::ChannelMojo::ShouldBeUsed();
+}
+
+scoped_ptr<IPC::ChannelProxy> RenderProcessHostImpl::CreateChannelProxy(
+ const std::string& channel_id) {
+ scoped_refptr<base::SingleThreadTaskRunner> runner =
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+ if (ShouldUseMojoChannel()) {
+ VLOG(1) << "Mojo Channel is enabled on host";
+ if (!channel_mojo_host_) {
+ channel_mojo_host_.reset(new IPC::ChannelMojoHost(
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
+ }
- if (!GetHandle())
- return; // Waiting on renderer startup.
+ return IPC::ChannelProxy::Create(
+ IPC::ChannelMojo::CreateServerFactory(
+ channel_mojo_host_->channel_delegate(), channel_id),
+ this,
+ runner.get());
+ }
- if (!mojo_application_host_->did_activate())
- mojo_application_host_->Activate(this, GetHandle());
+ return IPC::ChannelProxy::Create(
+ channel_id, IPC::Channel::MODE_SERVER, this, runner.get());
}
void RenderProcessHostImpl::CreateMessageFilters() {
@@ -736,17 +724,17 @@ void RenderProcessHostImpl::CreateMessageFilters() {
AddFilter(new AudioInputRendererHost(
audio_manager,
media_stream_manager,
- BrowserMainLoop::GetInstance()->audio_mirroring_manager(),
+ AudioMirroringManager::GetInstance(),
BrowserMainLoop::GetInstance()->user_input_monitor()));
// The AudioRendererHost needs to be available for lookup, so it's
// stashed in a member variable.
audio_renderer_host_ = new AudioRendererHost(
GetID(),
audio_manager,
- BrowserMainLoop::GetInstance()->audio_mirroring_manager(),
+ AudioMirroringManager::GetInstance(),
media_internals,
media_stream_manager);
- AddFilter(audio_renderer_host_);
+ AddFilter(audio_renderer_host_.get());
AddFilter(
new MidiHost(GetID(), BrowserMainLoop::GetInstance()->midi_manager()));
AddFilter(new VideoCaptureHost(media_stream_manager));
@@ -773,10 +761,7 @@ void RenderProcessHostImpl::CreateMessageFilters() {
AddFilter(new MediaStreamDispatcherHost(
GetID(),
browser_context->GetResourceContext()->GetMediaDeviceIDSalt(),
- media_stream_manager,
- resource_context));
- AddFilter(new DeviceRequestMessageFilter(
- resource_context, media_stream_manager, GetID()));
+ media_stream_manager));
AddFilter(new MediaStreamTrackMetricsHost());
#endif
#if defined(ENABLE_PLUGINS)
@@ -804,23 +789,17 @@ void RenderProcessHostImpl::CreateMessageFilters() {
channel_->AddFilter(new FontCacheDispatcher());
#elif defined(OS_ANDROID)
browser_demuxer_android_ = new BrowserDemuxerAndroid();
- AddFilter(browser_demuxer_android_);
+ AddFilter(browser_demuxer_android_.get());
+#endif
+#if defined(ENABLE_BROWSER_CDMS)
+ browser_cdm_manager_ = new BrowserCdmManager(GetID(), NULL);
+ AddFilter(browser_cdm_manager_.get());
#endif
-
- SocketStreamDispatcherHost::GetRequestContextCallback
- request_context_callback(
- base::Bind(&GetRequestContext, request_context,
- media_request_context));
-
- SocketStreamDispatcherHost* socket_stream_dispatcher_host =
- new SocketStreamDispatcherHost(
- GetID(), request_context_callback, resource_context);
- AddFilter(socket_stream_dispatcher_host);
WebSocketDispatcherHost::GetRequestContextCallback
websocket_request_context_callback(
base::Bind(&GetRequestContext, request_context,
- media_request_context, ResourceType::SUB_RESOURCE));
+ media_request_context, RESOURCE_TYPE_SUB_RESOURCE));
AddFilter(
new WebSocketDispatcherHost(GetID(), websocket_request_context_callback));
@@ -828,51 +807,34 @@ void RenderProcessHostImpl::CreateMessageFilters() {
message_port_message_filter_ = new MessagePortMessageFilter(
base::Bind(&RenderWidgetHelper::GetNextRoutingID,
base::Unretained(widget_helper_.get())));
- AddFilter(message_port_message_filter_);
+ AddFilter(message_port_message_filter_.get());
scoped_refptr<ServiceWorkerDispatcherHost> service_worker_filter =
- new ServiceWorkerDispatcherHost(GetID(), message_port_message_filter_);
+ new ServiceWorkerDispatcherHost(
+ GetID(), message_port_message_filter_.get(), resource_context);
service_worker_filter->Init(
storage_partition_impl_->GetServiceWorkerContext());
- AddFilter(service_worker_filter);
+ AddFilter(service_worker_filter.get());
- // If "--enable-embedded-shared-worker" is set, we use
- // SharedWorkerMessageFilter in stead of WorkerMessageFilter.
- if (WorkerService::EmbeddedSharedWorkerEnabled()) {
- AddFilter(new SharedWorkerMessageFilter(
- GetID(),
- resource_context,
- WorkerStoragePartition(
- storage_partition_impl_->GetURLRequestContext(),
- storage_partition_impl_->GetMediaURLRequestContext(),
- storage_partition_impl_->GetAppCacheService(),
- storage_partition_impl_->GetQuotaManager(),
- storage_partition_impl_->GetFileSystemContext(),
- storage_partition_impl_->GetDatabaseTracker(),
- storage_partition_impl_->GetIndexedDBContext(),
- storage_partition_impl_->GetServiceWorkerContext()),
- message_port_message_filter_));
- } else {
- AddFilter(new WorkerMessageFilter(
- GetID(),
- resource_context,
- WorkerStoragePartition(
- storage_partition_impl_->GetURLRequestContext(),
- storage_partition_impl_->GetMediaURLRequestContext(),
- storage_partition_impl_->GetAppCacheService(),
- storage_partition_impl_->GetQuotaManager(),
- storage_partition_impl_->GetFileSystemContext(),
- storage_partition_impl_->GetDatabaseTracker(),
- storage_partition_impl_->GetIndexedDBContext(),
- storage_partition_impl_->GetServiceWorkerContext()),
- message_port_message_filter_));
- }
+ AddFilter(new SharedWorkerMessageFilter(
+ GetID(),
+ resource_context,
+ WorkerStoragePartition(
+ storage_partition_impl_->GetURLRequestContext(),
+ storage_partition_impl_->GetMediaURLRequestContext(),
+ storage_partition_impl_->GetAppCacheService(),
+ storage_partition_impl_->GetQuotaManager(),
+ storage_partition_impl_->GetFileSystemContext(),
+ storage_partition_impl_->GetDatabaseTracker(),
+ storage_partition_impl_->GetIndexedDBContext(),
+ storage_partition_impl_->GetServiceWorkerContext()),
+ message_port_message_filter_.get()));
#if defined(ENABLE_WEBRTC)
p2p_socket_dispatcher_host_ = new P2PSocketDispatcherHost(
resource_context,
browser_context->GetRequestContextForRenderProcess(GetID()));
- AddFilter(p2p_socket_dispatcher_host_);
+ AddFilter(p2p_socket_dispatcher_host_.get());
#endif
AddFilter(new TraceMessageFilter());
@@ -882,38 +844,72 @@ void RenderProcessHostImpl::CreateMessageFilters() {
GetID(),
storage_partition_impl_->GetQuotaManager(),
GetContentClient()->browser()->CreateQuotaPermissionContext()));
+
+ notification_message_filter_ = new NotificationMessageFilter(
+ GetID(),
+ resource_context,
+ browser_context);
+ AddFilter(notification_message_filter_.get());
+
AddFilter(new GamepadBrowserMessageFilter());
+ AddFilter(new DeviceLightMessageFilter());
AddFilter(new DeviceMotionMessageFilter());
AddFilter(new DeviceOrientationMessageFilter());
AddFilter(new ProfilerMessageFilter(PROCESS_TYPE_RENDERER));
AddFilter(new HistogramMessageFilter());
#if defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID))
- if (CommandLine::ForCurrentProcess()->HasSwitch(
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableMemoryBenchmarking))
AddFilter(new MemoryBenchmarkMessageFilter());
#endif
AddFilter(new VibrationMessageFilter());
- AddFilter(new PushMessagingMessageFilter(GetID()));
- AddFilter(new BatteryStatusMessageFilter());
+ AddFilter(new PushMessagingMessageFilter(
+ GetID(), storage_partition_impl_->GetServiceWorkerContext()));
+#if defined(OS_ANDROID)
+ AddFilter(new ScreenOrientationMessageFilterAndroid());
+#endif
+ AddFilter(new GeofencingDispatcherHost(
+ storage_partition_impl_->GetGeofencingManager()));
+}
+
+void RenderProcessHostImpl::RegisterMojoServices() {
+ mojo_application_host_->service_registry()->AddService(
+ base::Bind(&device::BatteryMonitorImpl::Create));
}
int RenderProcessHostImpl::GetNextRoutingID() {
return widget_helper_->GetNextRoutingID();
}
-
void RenderProcessHostImpl::ResumeDeferredNavigation(
const GlobalRequestID& request_id) {
widget_helper_->ResumeDeferredNavigation(request_id);
}
+void RenderProcessHostImpl::ResumeResponseDeferredAtStart(
+ const GlobalRequestID& request_id) {
+ widget_helper_->ResumeResponseDeferredAtStart(request_id);
+}
+
void RenderProcessHostImpl::NotifyTimezoneChange() {
Send(new ViewMsg_TimezoneChange());
}
+ServiceRegistry* RenderProcessHostImpl::GetServiceRegistry() {
+ DCHECK(mojo_application_host_);
+ return mojo_application_host_->service_registry();
+}
+
+const base::TimeTicks& RenderProcessHostImpl::GetInitTimeForNavigationMetrics()
+ const {
+ return init_time_;
+}
+
void RenderProcessHostImpl::AddRoute(
int32 routing_id,
IPC::Listener* listener) {
+ CHECK(!listeners_.Lookup(routing_id))
+ << "Found Routing ID Conflict: " << routing_id;
listeners_.AddWithID(listener, routing_id);
}
@@ -923,8 +919,8 @@ void RenderProcessHostImpl::RemoveRoute(int32 routing_id) {
#if defined(OS_WIN)
// Dump the handle table if handle auditing is enabled.
- const CommandLine& browser_command_line =
- *CommandLine::ForCurrentProcess();
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
if (browser_command_line.HasSwitch(switches::kAuditHandles) ||
browser_command_line.HasSwitch(switches::kAuditAllHandles)) {
DumpHandles();
@@ -948,21 +944,8 @@ void RenderProcessHostImpl::RemoveObserver(
observers_.RemoveObserver(observer);
}
-bool RenderProcessHostImpl::WaitForBackingStoreMsg(
- int render_widget_id,
- const base::TimeDelta& max_delay,
- IPC::Message* msg) {
- // The post task to this thread with the process id could be in queue, and we
- // don't want to dispatch a message before then since it will need the handle.
- if (child_process_launcher_.get() && child_process_launcher_->IsStarting())
- return false;
-
- return widget_helper_->WaitForBackingStoreMsg(render_widget_id,
- max_delay, msg);
-}
-
void RenderProcessHostImpl::ReceivedBadMessage() {
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
return;
@@ -1010,23 +993,24 @@ StoragePartition* RenderProcessHostImpl::GetStoragePartition() const {
return storage_partition_impl_;
}
-static void AppendCompositorCommandLineFlags(CommandLine* command_line) {
+static void AppendCompositorCommandLineFlags(base::CommandLine* command_line) {
if (IsPinchVirtualViewportEnabled())
command_line->AppendSwitch(cc::switches::kEnablePinchVirtualViewport);
- if (IsThreadedCompositingEnabled())
- command_line->AppendSwitch(switches::kEnableThreadedCompositing);
-
if (IsDelegatedRendererEnabled())
command_line->AppendSwitch(switches::kEnableDelegatedRenderer);
- if (IsImplSidePaintingEnabled())
+ if (IsImplSidePaintingEnabled()) {
command_line->AppendSwitch(switches::kEnableImplSidePainting);
+ command_line->AppendSwitchASCII(
+ switches::kNumRasterThreads,
+ base::IntToString(NumberOfRendererRasterThreads()));
+ }
- if (content::IsGpuRasterizationEnabled())
+ if (IsGpuRasterizationEnabled())
command_line->AppendSwitch(switches::kEnableGpuRasterization);
- if (content::IsForceGpuRasterizationEnabled())
+ if (IsForceGpuRasterizationEnabled())
command_line->AppendSwitch(switches::kForceGpuRasterization);
// Appending disable-gpu-feature switches due to software rendering list.
@@ -1036,13 +1020,14 @@ static void AppendCompositorCommandLineFlags(CommandLine* command_line) {
}
void RenderProcessHostImpl::AppendRendererCommandLine(
- CommandLine* command_line) const {
+ base::CommandLine* command_line) const {
// Pass the process type first, so it shows first in process listings.
command_line->AppendSwitchASCII(switches::kProcessType,
switches::kRendererProcess);
// Now send any options from our own command line we want to propagate.
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
PropagateBrowserCommandLineToRenderer(browser_command_line, command_line);
// Pass on the browser locale.
@@ -1063,7 +1048,7 @@ void RenderProcessHostImpl::AppendRendererCommandLine(
GetContentClient()->browser()->AppendExtraCommandLineSwitches(
command_line, GetID());
- if (content::IsPinchToZoomEnabled())
+ if (IsPinchToZoomEnabled())
command_line->AppendSwitch(switches::kEnablePinch);
#if defined(OS_WIN)
@@ -1075,8 +1060,8 @@ void RenderProcessHostImpl::AppendRendererCommandLine(
}
void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
- const CommandLine& browser_cmd,
- CommandLine* renderer_cmd) const {
+ const base::CommandLine& browser_cmd,
+ base::CommandLine* renderer_cmd) const {
// Propagate the following switches to the renderer command line (along
// with any associated values) if present in the browser command line.
static const char* const kSwitchNames[] = {
@@ -1090,18 +1075,16 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kDefaultTileWidth,
switches::kDefaultTileHeight,
switches::kDisable3DAPIs,
- switches::kDisableAcceleratedFixedRootBackground,
- switches::kDisableAcceleratedOverflowScroll,
switches::kDisableAcceleratedVideoDecode,
switches::kDisableApplicationCache,
+ switches::kDisableBlinkScheduler,
switches::kDisableBreakpad,
- switches::kDisableCompositingForFixedPosition,
+ switches::kDisablePreferCompositingToLCDText,
switches::kDisableCompositingForTransition,
switches::kDisableDatabases,
- switches::kDisableDesktopNotifications,
switches::kDisableDirectNPAPIRequests,
+ switches::kDisableDisplayList2dCanvas,
switches::kDisableDistanceFieldText,
- switches::kDisableFastTextAutosizing,
switches::kDisableFileSystem,
switches::kDisableGpuCompositing,
switches::kDisableGpuVsync,
@@ -1112,62 +1095,64 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kDisableLocalStorage,
switches::kDisableLogging,
switches::kDisableMediaSource,
+ switches::kDisableOneCopy,
switches::kDisableOverlayScrollbar,
switches::kDisablePinch,
switches::kDisablePrefixedEncryptedMedia,
- switches::kDisableRepaintAfterLayout,
switches::kDisableSeccompFilterSandbox,
switches::kDisableSessionStorage,
switches::kDisableSharedWorkers,
+ switches::kDisableSVG1DOM,
+ switches::kDisableThreadedCompositing,
+ switches::kDisableThreadedScrolling,
switches::kDisableTouchAdjustment,
switches::kDisableTouchDragDrop,
switches::kDisableTouchEditing,
- switches::kDisableZeroCopy,
+ switches::kDisableV8IdleNotificationAfterCommit,
switches::kDomAutomationController,
- switches::kEnableAcceleratedFixedRootBackground,
- switches::kEnableAcceleratedOverflowScroll,
+ switches::kEnableAcceleratedJpegDecoding,
switches::kEnableBeginFrameScheduling,
switches::kEnableBleedingEdgeRenderingFastPaths,
- switches::kEnableCompositingForFixedPosition,
+ switches::kEnableBrowserSideNavigation,
+ switches::kEnablePreferCompositingToLCDText,
switches::kEnableCompositingForTransition,
+ switches::kEnableCredentialManagerAPI,
switches::kEnableDeferredImageDecoding,
+ switches::kEnableDisplayList2dCanvas,
switches::kEnableDistanceFieldText,
switches::kEnableEncryptedMedia,
switches::kEnableExperimentalCanvasFeatures,
switches::kEnableExperimentalWebPlatformFeatures,
- switches::kEnableFastTextAutosizing,
switches::kEnableGPUClientLogging,
switches::kEnableGpuClientTracing,
switches::kEnableGPUServiceLogging,
- switches::kEnableHighDpiCompositingForFixedPosition,
+ switches::kEnableLinkDisambiguationPopup,
switches::kEnableLowResTiling,
switches::kEnableInbandTextTracks,
switches::kEnableLCDText,
switches::kEnableLayerSquashing,
switches::kEnableLogging,
switches::kEnableMemoryBenchmarking,
+ switches::kEnableNetworkInformation,
switches::kEnableOneCopy,
switches::kEnableOverlayFullscreenVideo,
switches::kEnableOverlayScrollbar,
switches::kEnableOverscrollNotifications,
switches::kEnablePinch,
switches::kEnablePreciseMemoryInfo,
- switches::kEnablePreparsedJsCaching,
- switches::kEnableRepaintAfterLayout,
+ switches::kEnableRendererMojoChannel,
switches::kEnableSeccompFilterSandbox,
- switches::kEnableServiceWorker,
switches::kEnableSkiaBenchmarking,
- switches::kEnableSpeechSynthesis,
+ switches::kEnableSmoothScrolling,
switches::kEnableStatsTable,
switches::kEnableStrictSiteIsolation,
- switches::kEnableTargetedStyleRecalc,
+ switches::kEnableThreadedCompositing,
switches::kEnableTouchDragDrop,
switches::kEnableTouchEditing,
+ switches::kEnableV8IdleNotificationAfterCommit,
switches::kEnableViewport,
switches::kEnableViewportMeta,
- switches::kMainFrameResizesAreOrientationChanges,
switches::kEnableVtune,
- switches::kEnableWebAnimationsSVG,
switches::kEnableWebGLDraftExtensions,
switches::kEnableWebGLImageChromium,
switches::kEnableWebMIDI,
@@ -1178,18 +1163,19 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kIPCConnectionTimeout,
switches::kJavaScriptFlags,
switches::kLoggingLevel,
+ switches::kMainFrameResizesAreOrientationChanges,
switches::kMaxUntiledLayerWidth,
switches::kMaxUntiledLayerHeight,
switches::kMemoryMetrics,
switches::kNoReferrers,
switches::kNoSandbox,
- switches::kNumRasterThreads,
switches::kPpapiInProcess,
switches::kProfilerTiming,
switches::kReduceSecurityForTesting,
switches::kRegisterPepperPlugins,
switches::kRendererAssertTest,
switches::kRendererStartupDialog,
+ switches::kRootLayerScrolls,
switches::kShowPaintRects,
switches::kSitePerProcess,
switches::kStatsCollectionController,
@@ -1208,9 +1194,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
// also be added to chrome/browser/chromeos/login/chrome_restart_request.cc.
cc::switches::kCompositeToMailbox,
cc::switches::kDisableCompositedAntialiasing,
- cc::switches::kDisableCompositorTouchHitTesting,
cc::switches::kDisableMainFrameBeforeActivation,
- cc::switches::kDisableMainFrameBeforeDraw,
cc::switches::kDisableThreadedAnimation,
cc::switches::kEnableGpuBenchmarking,
cc::switches::kEnableMainFrameBeforeActivation,
@@ -1233,31 +1217,38 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
cc::switches::kTopControlsShowThreshold,
#if defined(ENABLE_PLUGINS)
switches::kEnablePepperTesting,
+ switches::kEnablePluginPowerSaver,
#endif
#if defined(ENABLE_WEBRTC)
switches::kDisableAudioTrackProcessing,
- switches::kDisableDeviceEnumeration,
switches::kDisableWebRtcHWDecoding,
switches::kDisableWebRtcHWEncoding,
switches::kEnableWebRtcHWVp8Encoding,
+ switches::kEnableWebRtcHWH264Encoding,
#endif
+ switches::kLowEndDeviceMode,
#if defined(OS_ANDROID)
switches::kDisableGestureRequirementForMediaPlayback,
- switches::kDisableLowEndDeviceMode,
switches::kDisableWebRTC,
- switches::kEnableLowEndDeviceMode,
switches::kEnableSpeechRecognition,
switches::kMediaDrmEnableNonCompositing,
switches::kNetworkCountryIso,
switches::kDisableWebAudio,
+ switches::kRendererWaitForJavaDebugger,
#endif
#if defined(OS_MACOSX)
// Allow this to be set when invoking the browser and relayed along.
switches::kEnableSandboxLogging,
#endif
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ switches::kEnableThreadedEventHandlingMac,
+#endif
#if defined(OS_WIN)
switches::kDisableDirectWrite,
- switches::kEnableHighResolutionTime,
+ switches::kEnableWin32kRendererLockDown,
+#endif
+#if defined(OS_CHROMEOS)
+ switches::kDisableVaapiAcceleratedVideoEncode,
#endif
};
renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
@@ -1282,16 +1273,26 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
if (IsImplSidePaintingEnabled() &&
!browser_cmd.HasSwitch(switches::kEnableDeferredImageDecoding))
renderer_cmd->AppendSwitch(switches::kEnableDeferredImageDecoding);
+
+ // Add kWaitForDebugger to let renderer process wait for a debugger.
+ if (browser_cmd.HasSwitch(switches::kWaitForDebuggerChildren)) {
+ // Look to pass-on the kWaitForDebugger flag.
+ std::string value =
+ browser_cmd.GetSwitchValueASCII(switches::kWaitForDebuggerChildren);
+ if (value.empty() || value == switches::kRendererProcess) {
+ renderer_cmd->AppendSwitch(switches::kWaitForDebugger);
+ }
+ }
}
base::ProcessHandle RenderProcessHostImpl::GetHandle() const {
if (run_renderer_in_process())
- return base::Process::Current().handle();
+ return base::GetCurrentProcessHandle();
if (!child_process_launcher_.get() || child_process_launcher_->IsStarting())
return base::kNullProcessHandle;
- return child_process_launcher_->GetHandle();
+ return child_process_launcher_->GetProcess().Handle();
}
bool RenderProcessHostImpl::FastShutdownIfPossible() {
@@ -1376,9 +1377,6 @@ bool RenderProcessHostImpl::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_UserMetricsRecordAction,
OnUserMetricsRecordAction)
IPC_MESSAGE_HANDLER(ViewHostMsg_SavedPageAsMHTML, OnSavedPageAsMHTML)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(
- ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
- OnAllocateGpuMemoryBuffer)
IPC_MESSAGE_HANDLER(ViewHostMsg_Close_ACK, OnCloseACK)
#if defined(ENABLE_WEBRTC)
IPC_MESSAGE_HANDLER(AecDumpMsg_RegisterAecDumpConsumer,
@@ -1404,13 +1402,6 @@ bool RenderProcessHostImpl::OnMessageReceived(const IPC::Message& msg) {
reply->set_reply_error();
Send(reply);
}
-
- // If this is a SwapBuffers, we need to ack it if we're not going to handle
- // it so that the GPU process doesn't get stuck in unscheduled state.
- IPC_BEGIN_MESSAGE_MAP(RenderProcessHostImpl, msg)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CompositorSurfaceBuffersSwapped,
- OnCompositorSurfaceBuffersSwappedNoHost)
- IPC_END_MESSAGE_MAP()
return true;
}
return listener->OnMessageReceived(msg);
@@ -1585,7 +1576,7 @@ RenderProcessHostImpl::StartRtpDump(
bool incoming,
bool outgoing,
const WebRtcRtpPacketCallback& packet_callback) {
- if (!p2p_socket_dispatcher_host_)
+ if (!p2p_socket_dispatcher_host_.get())
return WebRtcStopRtpDumpCallback();
BrowserThread::PostTask(BrowserThread::IO,
@@ -1736,7 +1727,7 @@ bool RenderProcessHost::run_renderer_in_process() {
void RenderProcessHost::SetRunRendererInProcess(bool value) {
g_run_renderer_in_process_ = value;
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (value) {
if (!command_line->HasSwitch(switches::kLang)) {
// Modify the current process' command line to include the browser locale,
@@ -1773,7 +1764,8 @@ bool RenderProcessHost::ShouldTryToUseExistingProcessHost(
// from the same site to share, if we knew what the given process was
// dedicated to. Allowing no sharing is simpler for now.) This may cause
// resource exhaustion issues if too many sites are open at once.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kEnableStrictSiteIsolation) ||
command_line.HasSwitch(switches::kSitePerProcess))
return false;
@@ -1830,7 +1822,8 @@ bool RenderProcessHost::ShouldUseProcessPerSite(
// the case if the --process-per-site switch is specified, or in
// process-per-site-instance for particular sites (e.g., WebUI).
// Note that --single-process is handled in ShouldTryToUseExistingProcessHost.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kProcessPerSite))
return true;
@@ -1915,6 +1908,11 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead) {
base::TERMINATION_STATUS_NORMAL_TERMINATION;
RendererClosedDetails details(GetHandle(), status, exit_code);
+ mojo_application_host_->WillDestroySoon();
+
+ child_process_launcher_.reset();
+ channel_.reset();
+
within_process_died_observer_ = true;
NotificationService::current()->Notify(
NOTIFICATION_RENDERER_PROCESS_CLOSED,
@@ -1922,11 +1920,9 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead) {
Details<RendererClosedDetails>(&details));
FOR_EACH_OBSERVER(RenderProcessHostObserver,
observers_,
- RenderProcessExited(this, GetHandle(), status, exit_code));
+ RenderProcessExited(this, status, exit_code));
within_process_died_observer_ = false;
- child_process_launcher_.reset();
- channel_.reset();
gpu_message_filter_ = NULL;
message_port_message_filter_ = NULL;
RemoveUserData(kSessionStorageHolderKey);
@@ -1940,7 +1936,7 @@ void RenderProcessHostImpl::ProcessDied(bool already_dead) {
iter.Advance();
}
- mojo_application_host_.reset();
+ mojo_application_host_.reset(new MojoApplicationHost);
// It's possible that one of the calls out to the observers might have caused
// this object to be no longer needed.
@@ -2026,6 +2022,8 @@ void RenderProcessHostImpl::OnShutdownRequest() {
Source<RenderProcessHost>(this),
NotificationService::NoDetails());
+ mojo_application_host_->WillDestroySoon();
+
Send(new ChildProcessMsg_Shutdown());
}
@@ -2082,11 +2080,7 @@ void RenderProcessHostImpl::OnProcessLaunched() {
return;
if (child_process_launcher_) {
- if (!child_process_launcher_->GetHandle()) {
- OnChannelError();
- return;
- }
-
+ DCHECK(child_process_launcher_->GetProcess().IsValid());
SetBackgrounded(backgrounded_);
}
@@ -2105,7 +2099,10 @@ void RenderProcessHostImpl::OnProcessLaunched() {
// 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.
- MaybeActivateMojo();
+ mojo_application_host_->Activate(this, GetHandle());
+
+ if (channel_mojo_host_)
+ channel_mojo_host_->OnClientLaunched(GetHandle());
while (!queued_messages_.empty()) {
Send(queued_messages_.front());
@@ -2140,21 +2137,7 @@ void RenderProcessHostImpl::OnSavedPageAsMHTML(int job_id, int64 data_size) {
MHTMLGenerationManager::GetInstance()->MHTMLGenerated(job_id, data_size);
}
-void RenderProcessHostImpl::OnCompositorSurfaceBuffersSwappedNoHost(
- const ViewHostMsg_CompositorSurfaceBuffersSwapped_Params& params) {
- TRACE_EVENT0("renderer_host",
- "RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwappedNoHost");
- if (!ui::LatencyInfo::Verify(params.latency_info,
- "ViewHostMsg_CompositorSurfaceBuffersSwapped"))
- return;
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.sync_point = 0;
- RenderWidgetHostImpl::AcknowledgeBufferPresent(params.route_id,
- params.gpu_process_host_id,
- ack_params);
-}
-
-void RenderProcessHostImpl::OnGpuSwitching() {
+void RenderProcessHostImpl::OnGpuSwitched() {
// We are updating all widgets including swapped out ones.
scoped_ptr<RenderWidgetHostIterator> widgets(
RenderWidgetHostImpl::GetAllRenderWidgetHosts());
@@ -2167,7 +2150,7 @@ void RenderProcessHostImpl::OnGpuSwitching() {
continue;
RenderViewHost* rvh = RenderViewHost::From(widget);
- rvh->UpdateWebkitPreferences(rvh->GetWebkitPreferences());
+ rvh->OnWebkitPreferencesChanged();
}
}
@@ -2222,7 +2205,7 @@ void RenderProcessHostImpl::EnableAecDumpForId(const base::FilePath& file,
int id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::FilePath unique_file =
- file.AddExtension(IntToStringType(GetID()))
+ file.AddExtension(IntToStringType(base::GetProcId(GetHandle())))
.AddExtension(IntToStringType(id));
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::FILE, FROM_HERE,
@@ -2260,118 +2243,4 @@ void RenderProcessHostImpl::DecrementWorkerRefCount() {
Cleanup();
}
-void RenderProcessHostImpl::ConnectTo(
- const base::StringPiece& service_name,
- mojo::ScopedMessagePipeHandle handle) {
- mojo_activation_required_ = true;
- MaybeActivateMojo();
-
- mojo_application_host_->service_provider()->ConnectToService(
- mojo::String::From(service_name),
- std::string(),
- handle.Pass(),
- mojo::String());
-}
-
-void RenderProcessHostImpl::OnAllocateGpuMemoryBuffer(uint32 width,
- uint32 height,
- uint32 internalformat,
- uint32 usage,
- IPC::Message* reply) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!GpuMemoryBufferImpl::IsFormatValid(internalformat) ||
- !GpuMemoryBufferImpl::IsUsageValid(usage)) {
- GpuMemoryBufferAllocated(reply, gfx::GpuMemoryBufferHandle());
- return;
- }
- base::CheckedNumeric<int> size = width;
- size *= height;
- if (!size.IsValid()) {
- GpuMemoryBufferAllocated(reply, gfx::GpuMemoryBufferHandle());
- return;
- }
-
-#if defined(OS_MACOSX)
- // TODO(reveman): This should be moved to
- // GpuMemoryBufferImpl::AllocateForChildProcess and
- // GpuMemoryBufferImplIOSurface. crbug.com/325045, crbug.com/323304
- if (GpuMemoryBufferImplIOSurface::IsConfigurationSupported(internalformat,
- usage)) {
- base::ScopedCFTypeRef<CFMutableDictionaryRef> properties;
- properties.reset(
- CFDictionaryCreateMutable(kCFAllocatorDefault,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks));
- AddIntegerValue(properties, kIOSurfaceWidth, width);
- AddIntegerValue(properties, kIOSurfaceHeight, height);
- AddIntegerValue(properties,
- kIOSurfaceBytesPerElement,
- GpuMemoryBufferImpl::BytesPerPixel(internalformat));
- AddIntegerValue(
- properties,
- kIOSurfacePixelFormat,
- GpuMemoryBufferImplIOSurface::PixelFormat(internalformat));
- // TODO(reveman): Remove this when using a mach_port_t to transfer
- // IOSurface to renderer process. crbug.com/323304
- AddBooleanValue(
- properties, kIOSurfaceIsGlobal, true);
-
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface(IOSurfaceCreate(properties));
- if (io_surface) {
- gfx::GpuMemoryBufferHandle handle;
- handle.type = gfx::IO_SURFACE_BUFFER;
- handle.io_surface_id = IOSurfaceGetID(io_surface);
-
- // TODO(reveman): This makes the assumption that the renderer will
- // grab a reference to the surface before sending another message.
- // crbug.com/325045
- last_io_surface_ = io_surface;
- GpuMemoryBufferAllocated(reply, handle);
- return;
- }
- }
-#endif
-
-#if defined(OS_ANDROID)
- // TODO(reveman): This should be moved to
- // GpuMemoryBufferImpl::AllocateForChildProcess and
- // GpuMemoryBufferImplSurfaceTexture when adding support for out-of-process
- // GPU service. crbug.com/368716
- if (GpuMemoryBufferImplSurfaceTexture::IsConfigurationSupported(
- internalformat, usage)) {
- // Each surface texture is associated with a render process id. This allows
- // the GPU service and Java Binder IPC to verify that a renderer is not
- // trying to use a surface texture it doesn't own.
- int surface_texture_id = CompositorImpl::CreateSurfaceTexture(GetID());
- if (surface_texture_id != -1) {
- gfx::GpuMemoryBufferHandle handle;
- handle.type = gfx::SURFACE_TEXTURE_BUFFER;
- handle.surface_texture_id =
- gfx::SurfaceTextureId(surface_texture_id, GetID());
- GpuMemoryBufferAllocated(reply, handle);
- return;
- }
- }
-#endif
-
- GpuMemoryBufferImpl::AllocateForChildProcess(
- gfx::Size(width, height),
- internalformat,
- usage,
- GetHandle(),
- base::Bind(&RenderProcessHostImpl::GpuMemoryBufferAllocated,
- weak_factory_.GetWeakPtr(),
- reply));
-}
-
-void RenderProcessHostImpl::GpuMemoryBufferAllocated(
- IPC::Message* reply,
- const gfx::GpuMemoryBufferHandle& handle) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer::WriteReplyParams(reply,
- handle);
- Send(reply);
-}
-
} // 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 2728626246e..b3bdf3bea7f 100644
--- a/chromium/content/browser/renderer_host/render_process_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_process_host_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_RENDERER_HOST_BROWSER_RENDER_PROCESS_HOST_IMPL_H_
-#define CONTENT_BROWSER_RENDERER_HOST_BROWSER_RENDER_PROCESS_HOST_IMPL_H_
+#ifndef CONTENT_BROWSER_RENDERER_HOST_RENDER_PROCESS_HOST_IMPL_H_
+#define CONTENT_BROWSER_RENDERER_HOST_RENDER_PROCESS_HOST_IMPL_H_
#include <map>
#include <queue>
@@ -12,23 +12,17 @@
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/process/process.h"
-#include "base/timer/timer.h"
#include "content/browser/child_process_launcher.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/browser/power_monitor_message_broadcaster.h"
#include "content/common/content_export.h"
-#include "content/public/browser/gpu_data_manager_observer.h"
+#include "content/common/mojo/service_registry_impl.h"
#include "content/public/browser/render_process_host.h"
#include "ipc/ipc_channel_proxy.h"
#include "ipc/ipc_platform_file.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
-
-#if defined(OS_MACOSX)
-#include <IOSurface/IOSurfaceAPI.h>
-#include "base/mac/scoped_cftyperef.h"
-#endif
-
-struct ViewHostMsg_CompositorSurfaceBuffersSwapped_Params;
+#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gl/gpu_switching_observer.h"
namespace base {
class CommandLine;
@@ -37,21 +31,25 @@ class MessageLoop;
namespace gfx {
class Size;
-struct GpuMemoryBufferHandle;
+}
+
+namespace IPC {
+class ChannelMojoHost;
}
namespace content {
class AudioRendererHost;
+class BrowserCdmManager;
class BrowserDemuxerAndroid;
class GpuMessageFilter;
class MessagePortMessageFilter;
class MojoApplicationHost;
+class NotificationMessageFilter;
#if defined(ENABLE_WEBRTC)
class P2PSocketDispatcherHost;
#endif
class PeerConnectionTrackerHost;
class RendererMainThread;
-class RenderProcessHostMojoImpl;
class RenderWidgetHelper;
class RenderWidgetHost;
class RenderWidgetHostImpl;
@@ -84,77 +82,74 @@ typedef base::Thread* (*RendererMainThreadFactoryFunction)(
class CONTENT_EXPORT RenderProcessHostImpl
: public RenderProcessHost,
public ChildProcessLauncher::Client,
- public GpuDataManagerObserver {
+ public ui::GpuSwitchingObserver {
public:
RenderProcessHostImpl(BrowserContext* browser_context,
StoragePartitionImpl* storage_partition_impl,
bool is_isolated_guest);
- virtual ~RenderProcessHostImpl();
+ ~RenderProcessHostImpl() override;
// RenderProcessHost implementation (public portion).
- virtual void EnableSendQueue() OVERRIDE;
- virtual bool Init() OVERRIDE;
- virtual int GetNextRoutingID() OVERRIDE;
- virtual void AddRoute(int32 routing_id, IPC::Listener* listener) OVERRIDE;
- virtual void RemoveRoute(int32 routing_id) OVERRIDE;
- virtual void AddObserver(RenderProcessHostObserver* observer) OVERRIDE;
- virtual void RemoveObserver(RenderProcessHostObserver* observer) OVERRIDE;
- virtual bool WaitForBackingStoreMsg(int render_widget_id,
- const base::TimeDelta& max_delay,
- IPC::Message* msg) OVERRIDE;
- virtual void ReceivedBadMessage() OVERRIDE;
- virtual void WidgetRestored() OVERRIDE;
- virtual void WidgetHidden() OVERRIDE;
- virtual int VisibleWidgetCount() const OVERRIDE;
- virtual bool IsIsolatedGuest() const OVERRIDE;
- virtual StoragePartition* GetStoragePartition() const OVERRIDE;
- virtual bool FastShutdownIfPossible() OVERRIDE;
- virtual void DumpHandles() OVERRIDE;
- virtual base::ProcessHandle GetHandle() const OVERRIDE;
- virtual BrowserContext* GetBrowserContext() const OVERRIDE;
- virtual bool InSameStoragePartition(
- StoragePartition* partition) const OVERRIDE;
- virtual int GetID() const OVERRIDE;
- virtual bool HasConnection() const OVERRIDE;
- virtual void SetIgnoreInputEvents(bool ignore_input_events) OVERRIDE;
- virtual bool IgnoreInputEvents() const OVERRIDE;
- virtual void Cleanup() OVERRIDE;
- virtual void AddPendingView() OVERRIDE;
- virtual void RemovePendingView() OVERRIDE;
- virtual void SetSuddenTerminationAllowed(bool enabled) OVERRIDE;
- virtual bool SuddenTerminationAllowed() const OVERRIDE;
- virtual IPC::ChannelProxy* GetChannel() OVERRIDE;
- virtual void AddFilter(BrowserMessageFilter* filter) OVERRIDE;
- virtual bool FastShutdownForPageCount(size_t count) OVERRIDE;
- virtual bool FastShutdownStarted() const OVERRIDE;
- virtual base::TimeDelta GetChildProcessIdleTime() const OVERRIDE;
- virtual void ResumeRequestsForView(int route_id) OVERRIDE;
- virtual void FilterURL(bool empty_allowed, GURL* url) OVERRIDE;
+ void EnableSendQueue() override;
+ bool Init() override;
+ int GetNextRoutingID() override;
+ void AddRoute(int32 routing_id, IPC::Listener* listener) override;
+ void RemoveRoute(int32 routing_id) override;
+ void AddObserver(RenderProcessHostObserver* observer) override;
+ void RemoveObserver(RenderProcessHostObserver* observer) override;
+ void ReceivedBadMessage() override;
+ void WidgetRestored() override;
+ void WidgetHidden() override;
+ int VisibleWidgetCount() const override;
+ bool IsIsolatedGuest() const override;
+ StoragePartition* GetStoragePartition() const override;
+ bool FastShutdownIfPossible() override;
+ void DumpHandles() override;
+ base::ProcessHandle GetHandle() const override;
+ BrowserContext* GetBrowserContext() const override;
+ bool InSameStoragePartition(StoragePartition* partition) const override;
+ int GetID() const override;
+ bool HasConnection() const override;
+ void SetIgnoreInputEvents(bool ignore_input_events) override;
+ bool IgnoreInputEvents() const override;
+ void Cleanup() override;
+ void AddPendingView() override;
+ void RemovePendingView() override;
+ void SetSuddenTerminationAllowed(bool enabled) override;
+ bool SuddenTerminationAllowed() const override;
+ IPC::ChannelProxy* GetChannel() override;
+ void AddFilter(BrowserMessageFilter* filter) override;
+ 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)
- virtual void EnableAecDump(const base::FilePath& file) OVERRIDE;
- virtual void DisableAecDump() OVERRIDE;
- virtual void SetWebRtcLogMessageCallback(
- base::Callback<void(const std::string&)> callback) OVERRIDE;
- virtual WebRtcStopRtpDumpCallback StartRtpDump(
+ void EnableAecDump(const base::FilePath& file) override;
+ void DisableAecDump() override;
+ void SetWebRtcLogMessageCallback(
+ base::Callback<void(const std::string&)> callback) override;
+ WebRtcStopRtpDumpCallback StartRtpDump(
bool incoming,
bool outgoing,
- const WebRtcRtpPacketCallback& packet_callback) OVERRIDE;
+ const WebRtcRtpPacketCallback& packet_callback) override;
#endif
- virtual void ResumeDeferredNavigation(const GlobalRequestID& request_id)
- OVERRIDE;
- virtual void NotifyTimezoneChange() OVERRIDE;
+ void ResumeDeferredNavigation(const GlobalRequestID& request_id) override;
+ void NotifyTimezoneChange() override;
+ ServiceRegistry* GetServiceRegistry() override;
+ const base::TimeTicks& GetInitTimeForNavigationMetrics() const override;
// IPC::Sender via RenderProcessHost.
- virtual bool Send(IPC::Message* msg) OVERRIDE;
+ bool Send(IPC::Message* msg) override;
// IPC::Listener via RenderProcessHost.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
- virtual void OnChannelError() OVERRIDE;
- virtual void OnBadMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void OnChannelConnected(int32 peer_pid) override;
+ void OnChannelError() override;
+ void OnBadMessageReceived(const IPC::Message& message) override;
// ChildProcessLauncher::Client implementation.
- virtual void OnProcessLaunched() OVERRIDE;
+ void OnProcessLaunched() override;
scoped_refptr<AudioRendererHost> audio_renderer_host() const;
@@ -236,8 +231,18 @@ class CONTENT_EXPORT RenderProcessHostImpl
}
#endif
+#if defined(ENABLE_BROWSER_CDMS)
+ const scoped_refptr<BrowserCdmManager>& browser_cdm_manager() {
+ return browser_cdm_manager_;
+ }
+#endif
+
MessagePortMessageFilter* message_port_message_filter() const {
- return message_port_message_filter_;
+ return message_port_message_filter_.get();
+ }
+
+ NotificationMessageFilter* notification_message_filter() const {
+ return notification_message_filter_.get();
}
void set_is_isolated_guest_for_testing(bool is_isolated_guest) {
@@ -250,24 +255,19 @@ class CONTENT_EXPORT RenderProcessHostImpl
void IncrementWorkerRefCount();
void DecrementWorkerRefCount();
- // Establish a connection to a renderer-provided service. See
- // content/common/mojo/mojo_service_names.h for a list of services.
- void ConnectTo(const base::StringPiece& service_name,
- mojo::ScopedMessagePipeHandle handle);
-
- template <typename Interface>
- void ConnectTo(const base::StringPiece& service_name,
- mojo::InterfacePtr<Interface>* ptr) {
- mojo::MessagePipe pipe;
- ptr->Bind(pipe.handle0.Pass());
- ConnectTo(service_name, pipe.handle1.Pass());
- }
+ // Call this function to resume the navigation when it was deferred
+ // immediately after receiving response headers.
+ void ResumeResponseDeferredAtStart(const GlobalRequestID& request_id);
protected:
// A proxy for our IPC::Channel that lives on the IO thread (see
// browser_process.h)
scoped_ptr<IPC::ChannelProxy> channel_;
+ // A host object ChannelMojo needs. The lifetime is bound to
+ // the RenderProcessHostImpl, not the channel.
+ scoped_ptr<IPC::ChannelMojoHost> channel_mojo_host_;
+
// True if fast shutdown has been performed on this RPH.
bool fast_shutdown_started_;
@@ -287,11 +287,16 @@ class CONTENT_EXPORT RenderProcessHostImpl
private:
friend class VisitRelayingRenderProcessHost;
- void MaybeActivateMojo();
+ bool ShouldUseMojoChannel() const;
+ scoped_ptr<IPC::ChannelProxy> CreateChannelProxy(
+ const std::string& channel_id);
// Creates and adds the IO thread message filters.
void CreateMessageFilters();
+ // Registers Mojo services to be exposed to the renderer.
+ void RegisterMojoServices();
+
// Control message handlers.
void OnShutdownRequest();
void OnDumpHandlesDone();
@@ -300,10 +305,6 @@ class CONTENT_EXPORT RenderProcessHostImpl
void OnSavedPageAsMHTML(int job_id, int64 mhtml_file_size);
void OnCloseACK(int old_route_id);
- // CompositorSurfaceBuffersSwapped handler when there's no RWH.
- void OnCompositorSurfaceBuffersSwappedNoHost(
- const ViewHostMsg_CompositorSurfaceBuffersSwapped_Params& params);
-
// Generates a command line to be used to spawn a renderer and appends the
// results to |*command_line|.
void AppendRendererCommandLine(base::CommandLine* command_line) const;
@@ -321,7 +322,8 @@ class CONTENT_EXPORT RenderProcessHostImpl
// Handle termination of our process.
void ProcessDied(bool already_dead);
- virtual void OnGpuSwitching() OVERRIDE;
+ // GpuSwitchingObserver implementation.
+ void OnGpuSwitched() override;
#if defined(ENABLE_WEBRTC)
void OnRegisterAecDumpConsumer(int id);
@@ -335,17 +337,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
void SendDisableAecDumpToRenderer();
#endif
- // GpuMemoryBuffer allocation handler.
- void OnAllocateGpuMemoryBuffer(uint32 width,
- uint32 height,
- uint32 internalformat,
- uint32 usage,
- IPC::Message* reply);
- void GpuMemoryBufferAllocated(IPC::Message* reply,
- const gfx::GpuMemoryBufferHandle& handle);
-
scoped_ptr<MojoApplicationHost> mojo_application_host_;
- bool mojo_activation_required_;
// The registered IPC listener objects. When this list is empty, we should
// delete ourselves.
@@ -374,6 +366,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
// The filter for MessagePort messages coming from the renderer.
scoped_refptr<MessagePortMessageFilter> message_port_message_filter_;
+ // The filter for Web Notification messages coming from the renderer. Holds a
+ // closure per notification that must be freed when the notification closes.
+ scoped_refptr<NotificationMessageFilter> notification_message_filter_;
+
// Used in single-process mode.
scoped_ptr<base::Thread> in_process_renderer_;
@@ -381,6 +377,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
// also reset that in the case of process termination.
bool is_initialized_;
+ // PlzNavigate
+ // Stores the time at which the first call to Init happened.
+ base::TimeTicks init_time_;
+
// Used to launch and terminate the process without blocking the UI thread.
scoped_ptr<ChildProcessLauncher> child_process_launcher_;
@@ -445,6 +445,10 @@ class CONTENT_EXPORT RenderProcessHostImpl
scoped_refptr<BrowserDemuxerAndroid> browser_demuxer_android_;
#endif
+#if defined(ENABLE_BROWSER_CDMS)
+ scoped_refptr<BrowserCdmManager> browser_cdm_manager_;
+#endif
+
#if defined(ENABLE_WEBRTC)
base::Callback<void(const std::string&)> webrtc_log_message_callback_;
@@ -463,13 +467,9 @@ class CONTENT_EXPORT RenderProcessHostImpl
base::WeakPtrFactory<RenderProcessHostImpl> weak_factory_;
-#if defined(OS_MACOSX)
- base::ScopedCFTypeRef<IOSurfaceRef> last_io_surface_;
-#endif
-
DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImpl);
};
} // namespace content
-#endif // CONTENT_BROWSER_RENDERER_HOST_BROWSER_RENDER_PROCESS_HOST_IMPL_H_
+#endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_PROCESS_HOST_IMPL_H_
diff --git a/chromium/content/browser/renderer_host/render_process_host_unittest.cc b/chromium/content/browser/renderer_host/render_process_host_unittest.cc
index 474a72bd166..e25c53c7307 100644
--- a/chromium/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_process_host_unittest.cc
@@ -2,6 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <limits>
+
+#include "base/command_line.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/test/test_render_view_host.h"
@@ -26,4 +31,60 @@ TEST_F(RenderProcessHostUnitTest, GuestsAreNotSuitableHosts) {
RenderProcessHost::GetExistingProcessHost(browser_context(), test_url));
}
+#if !defined(OS_ANDROID)
+TEST_F(RenderProcessHostUnitTest, RendererProcessLimit) {
+ // This test shouldn't run with --site-per-process or
+ // --enable-strict-site-isolation modes, since they don't allow renderer
+ // process reuse, which this test explicitly exercises.
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kSitePerProcess) ||
+ command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
+ return;
+
+ // Disable any overrides.
+ RenderProcessHostImpl::SetMaxRendererProcessCount(0);
+
+ // Verify that the limit is between 1 and kMaxRendererProcessCount.
+ EXPECT_GT(RenderProcessHostImpl::GetMaxRendererProcessCount(), 0u);
+ EXPECT_LE(RenderProcessHostImpl::GetMaxRendererProcessCount(),
+ kMaxRendererProcessCount);
+
+ // Add dummy process hosts to saturate the limit.
+ ASSERT_NE(0u, kMaxRendererProcessCount);
+ ScopedVector<MockRenderProcessHost> hosts;
+ for (size_t i = 0; i < kMaxRendererProcessCount; ++i) {
+ hosts.push_back(new MockRenderProcessHost(browser_context()));
+ }
+
+ // Verify that the renderer sharing will happen.
+ GURL test_url("http://foo.com");
+ EXPECT_TRUE(RenderProcessHostImpl::ShouldTryToUseExistingProcessHost(
+ browser_context(), test_url));
+}
+#endif
+
+#if defined(OS_ANDROID)
+TEST_F(RenderProcessHostUnitTest, NoRendererProcessLimitOnAndroid) {
+ // Disable any overrides.
+ RenderProcessHostImpl::SetMaxRendererProcessCount(0);
+
+ // Verify that by default the limit on Android returns max size_t.
+ EXPECT_EQ(std::numeric_limits<size_t>::max(),
+ RenderProcessHostImpl::GetMaxRendererProcessCount());
+
+ // Add a few dummy process hosts.
+ ASSERT_NE(0u, kMaxRendererProcessCount);
+ ScopedVector<MockRenderProcessHost> hosts;
+ for (size_t i = 0; i < kMaxRendererProcessCount; ++i) {
+ hosts.push_back(new MockRenderProcessHost(browser_context()));
+ }
+
+ // Verify that the renderer sharing still won't happen.
+ GURL test_url("http://foo.com");
+ EXPECT_FALSE(RenderProcessHostImpl::ShouldTryToUseExistingProcessHost(
+ browser_context(), test_url));
+}
+#endif
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_view_host_browsertest.cc b/chromium/content/browser/renderer_host/render_view_host_browsertest.cc
index 6015c04306e..2fdaf0aa833 100644
--- a/chromium/content/browser/renderer_host/render_view_host_browsertest.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_browsertest.cc
@@ -34,11 +34,10 @@ class RenderViewHostTestWebContentsObserver : public WebContentsObserver {
explicit RenderViewHostTestWebContentsObserver(WebContents* web_contents)
: WebContentsObserver(web_contents),
navigation_count_(0) {}
- virtual ~RenderViewHostTestWebContentsObserver() {}
+ ~RenderViewHostTestWebContentsObserver() override {}
- virtual void DidNavigateMainFrame(
- const LoadCommittedDetails& details,
- const FrameNavigateParams& params) OVERRIDE {
+ void DidNavigateMainFrame(const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override {
observed_socket_address_ = params.socket_address;
base_url_ = params.base_url;
++navigation_count_;
diff --git a/chromium/content/browser/renderer_host/render_view_host_delegate.cc b/chromium/content/browser/renderer_host/render_view_host_delegate.cc
index 88e590b097f..41a110e3f5c 100644
--- a/chromium/content/browser/renderer_host/render_view_host_delegate.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_delegate.cc
@@ -4,8 +4,8 @@
#include "content/browser/renderer_host/render_view_host_delegate.h"
+#include "content/public/common/web_preferences.h"
#include "url/gurl.h"
-#include "webkit/common/webpreferences.h"
namespace content {
@@ -22,7 +22,7 @@ WebContents* RenderViewHostDelegate::GetAsWebContents() {
return NULL;
}
-WebPreferences RenderViewHostDelegate::GetWebkitPrefs() {
+WebPreferences RenderViewHostDelegate::ComputeWebkitPrefs() {
return WebPreferences();
}
diff --git a/chromium/content/browser/renderer_host/render_view_host_delegate.h b/chromium/content/browser/renderer_host/render_view_host_delegate.h
index fd8aeae8625..b7074f5704b 100644
--- a/chromium/content/browser/renderer_host/render_view_host_delegate.h
+++ b/chromium/content/browser/renderer_host/render_view_host_delegate.h
@@ -13,8 +13,6 @@
#include "base/strings/string16.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/common/content_export.h"
-#include "content/public/common/media_stream_request.h"
-#include "content/public/common/page_transition_types.h"
#include "net/base/load_states.h"
#include "third_party/WebKit/public/web/WebPopupType.h"
#include "ui/base/window_open_disposition.h"
@@ -24,7 +22,6 @@ class SkBitmap;
struct ViewHostMsg_CreateWindow_Params;
struct FrameHostMsg_DidCommitProvisionalLoad_Params;
struct ViewMsg_PostMessage_Params;
-struct WebPreferences;
namespace base {
class ListValue;
@@ -53,12 +50,12 @@ class SessionStorageNamespace;
class SiteInstance;
class WebContents;
class WebContentsImpl;
-struct AXEventNotificationDetails;
struct FileChooserParams;
struct GlobalRequestID;
struct NativeWebKeyboardEvent;
struct Referrer;
struct RendererPreferences;
+struct WebPreferences;
//
// RenderViewHostDelegate
@@ -112,8 +109,8 @@ class CONTENT_EXPORT RenderViewHostDelegate {
int32 page_id,
const PageState& state) {}
- // The destination URL has changed should be updated
- virtual void UpdateTargetURL(int32 page_id, const GURL& url) {}
+ // The destination URL has changed should be updated.
+ virtual void UpdateTargetURL(const GURL& url) {}
// The page is trying to close the RenderView's representation in the client.
virtual void Close(RenderViewHost* render_view_host) {}
@@ -141,9 +138,9 @@ class CONTENT_EXPORT RenderViewHostDelegate {
virtual RendererPreferences GetRendererPrefs(
BrowserContext* browser_context) const = 0;
- // Returns a WebPreferences object that will be used by the renderer
+ // Computes a WebPreferences object that will be used by the renderer
// associated with the owning render view host.
- virtual WebPreferences GetWebkitPrefs();
+ virtual WebPreferences ComputeWebkitPrefs();
// Notification the user has made a gesture while focus was on the
// page. This is used to avoid uninitiated user downloads (aka carpet
@@ -158,9 +155,7 @@ class CONTENT_EXPORT RenderViewHostDelegate {
// Notification that the renderer has become unresponsive. The
// delegate can use this notification to show a warning to the user.
- virtual void RendererUnresponsive(RenderViewHost* render_view_host,
- bool is_during_before_unload,
- bool is_during_unload) {}
+ virtual void RendererUnresponsive(RenderViewHost* render_view_host) {}
// Notification that a previously unresponsive renderer has become
// responsive again. The delegate can use this notification to end the
@@ -266,13 +261,6 @@ class CONTENT_EXPORT RenderViewHostDelegate {
// Show the newly created full screen widget. Similar to above.
virtual void ShowCreatedFullscreenWidget(int route_id) {}
- // The render view has requested access to media devices listed in
- // |request|, and the client should grant or deny that permission by
- // calling |callback|.
- virtual void RequestMediaAccessPermission(
- const MediaStreamRequest& request,
- const MediaResponseCallback& callback) {}
-
// Returns the SessionStorageNamespace the render view should use. Might
// create the SessionStorageNamespace on the fly.
virtual SessionStorageNamespace* GetSessionStorageNamespace(
@@ -292,10 +280,6 @@ class CONTENT_EXPORT RenderViewHostDelegate {
// created by the RenderViewHost.
virtual FrameTree* GetFrameTree();
- // Invoked when an accessibility event is received from the renderer.
- virtual void AccessibilityEventReceived(
- const std::vector<AXEventNotificationDetails>& details) {}
-
protected:
virtual ~RenderViewHostDelegate() {}
};
diff --git a/chromium/content/browser/renderer_host/render_view_host_delegate_view.h b/chromium/content/browser/renderer_host/render_view_host_delegate_view.h
index fb2babdc87f..53366ecb3ef 100644
--- a/chromium/content/browser/renderer_host/render_view_host_delegate_view.h
+++ b/chromium/content/browser/renderer_host/render_view_host_delegate_view.h
@@ -8,6 +8,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/callback.h"
#include "content/common/content_export.h"
#include "content/common/drag_event_source_info.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
@@ -20,6 +21,11 @@ class Rect;
class Vector2d;
}
+namespace ui {
+class GestureEvent;
+class MouseEvent;
+}
+
namespace content {
class RenderFrameHost;
struct ContextMenuParams;
@@ -36,20 +42,6 @@ class CONTENT_EXPORT RenderViewHostDelegateView {
virtual void ShowContextMenu(RenderFrameHost* render_frame_host,
const ContextMenuParams& params) {}
- // Shows a popup menu with the specified items.
- // This method should call RenderViewHost::DidSelectPopupMenuItem[s]() or
- // RenderViewHost::DidCancelPopupMenu() based on the user action.
- virtual void ShowPopupMenu(const gfx::Rect& bounds,
- int item_height,
- double item_font_size,
- int selected_item,
- const std::vector<MenuItem>& items,
- bool right_aligned,
- bool allow_multiple_selection) {};
-
- // Hides a popup menu opened by ShowPopupMenu().
- virtual void HidePopupMenu() {};
-
// The user started dragging content of the specified type within the
// RenderView. Contextual information about the dragged content is supplied
// by DropData. If the delegate's view cannot start the drag for /any/
@@ -73,6 +65,39 @@ class CONTENT_EXPORT RenderViewHostDelegateView {
// retrieved by doing a Shift-Tab.
virtual void TakeFocus(bool reverse) {}
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+ // Shows a popup menu with the specified items.
+ // This method should call RenderFrameHost::DidSelectPopupMenuItem[s]() or
+ // RenderFrameHost::DidCancelPopupMenu() based on the user action.
+ virtual void ShowPopupMenu(RenderFrameHost* render_frame_host,
+ const gfx::Rect& bounds,
+ int item_height,
+ double item_font_size,
+ int selected_item,
+ const std::vector<MenuItem>& items,
+ bool right_aligned,
+ bool allow_multiple_selection) {};
+
+ // Hides a popup menu opened by ShowPopupMenu().
+ virtual void HidePopupMenu() {};
+#endif
+
+#if defined(TOOLKIT_VIEWS) || defined(USE_AURA)
+ // Shows a Link Disambiguation Popup. |target_rect| is the area the user
+ // touched that resulted in ambiguity, in DIPs in the host's coordinate
+ // system, |zoomed_bitmap| is an enlarged image of that |target_rect|, and
+ // |callback| is for forwarding on to the original scale web content.
+ virtual void ShowDisambiguationPopup(
+ const gfx::Rect& target_rect,
+ const SkBitmap& zoomed_bitmap,
+ const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
+ const base::Callback<void(ui::MouseEvent*)>& mouse_cb) {}
+
+ // Hides the Link Disambiguation Popup, if it was showing, otherwise does
+ // nothing.
+ virtual void HideDisambiguationPopup() {}
+#endif
+
protected:
virtual ~RenderViewHostDelegateView() {}
};
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 5cffd134b8e..0b2edf21f0d 100644
--- a/chromium/content/browser/renderer_host/render_view_host_factory.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_factory.cc
@@ -26,8 +26,14 @@ RenderViewHost* RenderViewHostFactory::Create(
routing_id, main_frame_routing_id,
swapped_out);
}
- return new RenderViewHostImpl(instance, delegate, widget_delegate, routing_id,
- main_frame_routing_id, swapped_out, hidden);
+ return new RenderViewHostImpl(instance,
+ delegate,
+ widget_delegate,
+ routing_id,
+ main_frame_routing_id,
+ swapped_out,
+ hidden,
+ true /* has_initialized_audio_host */);
}
// static
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 e14b364cadf..01a5e1bb5d8 100644
--- a/chromium/content/browser/renderer_host/render_view_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_impl.cc
@@ -15,6 +15,7 @@
#include "base/i18n/rtl.h"
#include "base/json/json_reader.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -23,9 +24,7 @@
#include "base/time/time.h"
#include "base/values.h"
#include "cc/base/switches.h"
-#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/cross_site_request_manager.h"
#include "content/browser/dom_storage/session_storage_namespace_impl.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/gpu/compositor_util.h"
@@ -35,24 +34,20 @@
#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/input/timeout_monitor.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_view_base.h"
-#include "content/common/accessibility_messages.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
#include "content/common/content_switches_internal.h"
#include "content/common/drag_messages.h"
#include "content/common/frame_messages.h"
#include "content/common/input_messages.h"
#include "content/common/inter_process_time_ticks_converter.h"
-#include "content/common/mojo/mojo_service_names.h"
#include "content/common/speech_recognition_messages.h"
#include "content/common/swapped_out_messages.h"
#include "content/common/view_messages.h"
-#include "content/common/web_ui_setup.mojom.h"
#include "content/public/browser/ax_event_notification_details.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/browser_context.h"
@@ -71,27 +66,26 @@
#include "content/public/common/content_switches.h"
#include "content/public/common/context_menu_params.h"
#include "content/public/common/drop_data.h"
+#include "content/public/common/file_chooser_file_info.h"
+#include "content/public/common/file_chooser_params.h"
#include "content/public/common/result_codes.h"
+#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/network_change_notifier.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"
-#include "ui/accessibility/ax_tree.h"
#include "ui/base/touch/touch_device.h"
#include "ui/base/touch/touch_enabled.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/native_theme/native_theme_switches.h"
-#include "ui/shell_dialogs/selected_file_info.h"
#include "url/url_constants.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#if defined(OS_MACOSX)
-#include "content/browser/renderer_host/popup_menu_helper_mac.h"
-#elif defined(OS_WIN)
+#if defined(OS_WIN)
#include "base/win/win_util.h"
#endif
@@ -137,22 +131,12 @@ void DismissVirtualKeyboardTask() {
} // namespace
// static
-const int RenderViewHostImpl::kUnloadTimeoutMS = 1000;
+const int64 RenderViewHostImpl::kUnloadTimeoutMS = 1000;
///////////////////////////////////////////////////////////////////////////////
// RenderViewHost, public:
// static
-bool RenderViewHostImpl::IsRVHStateActive(RenderViewHostImplState rvh_state) {
- if (rvh_state == STATE_DEFAULT ||
- rvh_state == STATE_WAITING_FOR_UNLOAD_ACK ||
- rvh_state == STATE_WAITING_FOR_COMMIT ||
- rvh_state == STATE_WAITING_FOR_CLOSE)
- return true;
- return false;
-}
-
-// static
RenderViewHost* RenderViewHost::FromID(int render_process_id,
int render_view_id) {
return RenderViewHostImpl::FromID(render_process_id, render_view_id);
@@ -184,7 +168,8 @@ RenderViewHostImpl::RenderViewHostImpl(
int routing_id,
int main_frame_routing_id,
bool swapped_out,
- bool hidden)
+ bool hidden,
+ bool has_initialized_audio_host)
: RenderWidgetHostImpl(widget_delegate,
instance->GetProcess(),
routing_id,
@@ -194,43 +179,46 @@ RenderViewHostImpl::RenderViewHostImpl(
instance_(static_cast<SiteInstanceImpl*>(instance)),
waiting_for_drag_context_response_(false),
enabled_bindings_(0),
- navigations_suspended_(false),
+ page_id_(-1),
+ is_active_(!swapped_out),
+ is_swapped_out_(swapped_out),
main_frame_routing_id_(main_frame_routing_id),
run_modal_reply_msg_(NULL),
run_modal_opener_id_(MSG_ROUTING_NONE),
- is_waiting_for_beforeunload_ack_(false),
- unload_ack_is_for_cross_site_transition_(false),
+ is_waiting_for_close_ack_(false),
sudden_termination_allowed_(false),
render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING),
virtual_keyboard_requested_(false),
- weak_factory_(this),
- is_focused_element_editable_(false) {
+ is_focused_element_editable_(false),
+ updating_web_preferences_(false),
+ weak_factory_(this) {
DCHECK(instance_.get());
CHECK(delegate_); // http://crbug.com/82827
GetProcess()->EnableSendQueue();
- if (swapped_out) {
- rvh_state_ = STATE_SWAPPED_OUT;
- } else {
- rvh_state_ = STATE_DEFAULT;
- instance_->increment_active_view_count();
- }
-
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->RenderViewHasActiveAudio(GetRoutingID());
+ }
BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
+ BrowserThread::IO,
+ FROM_HERE,
base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostCreated,
base::Unretained(ResourceDispatcherHostImpl::Get()),
- GetProcess()->GetID(), GetRoutingID()));
+ GetProcess()->GetID(),
+ GetRoutingID(),
+ !is_hidden(),
+ has_active_audio));
}
-
#if defined(ENABLE_BROWSER_CDMS)
media_web_contents_observer_.reset(new MediaWebContentsObserver(this));
#endif
-
- unload_event_monitor_timeout_.reset(new TimeoutMonitor(base::Bind(
- &RenderViewHostImpl::OnSwappedOut, weak_factory_.GetWeakPtr(), true)));
}
RenderViewHostImpl::~RenderViewHostImpl() {
@@ -243,22 +231,13 @@ RenderViewHostImpl::~RenderViewHostImpl() {
}
delegate_->RenderViewDeleted(this);
-
- // Be sure to clean up any leftover state from cross-site requests.
- CrossSiteRequestManager::GetInstance()->SetHasPendingCrossSiteRequest(
- GetProcess()->GetID(), GetRoutingID(), false);
-
- // If this was swapped out, it already decremented the active view
- // count of the SiteInstance it belongs to.
- if (IsRVHStateActive(rvh_state_))
- instance_->decrement_active_view_count();
}
RenderViewHostDelegate* RenderViewHostImpl::GetDelegate() const {
return delegate_;
}
-SiteInstance* RenderViewHostImpl::GetSiteInstance() const {
+SiteInstanceImpl* RenderViewHostImpl::GetSiteInstance() const {
return instance_.get();
}
@@ -268,7 +247,8 @@ bool RenderViewHostImpl::CreateRenderView(
int proxy_route_id,
int32 max_page_id,
bool window_was_created_with_opener) {
- TRACE_EVENT0("renderer_host", "RenderViewHostImpl::CreateRenderView");
+ TRACE_EVENT0("renderer_host,navigation",
+ "RenderViewHostImpl::CreateRenderView");
DCHECK(!IsRenderViewLive()) << "Creating view twice";
// The process may (if we're sharing a process with another host that already
@@ -294,23 +274,22 @@ bool RenderViewHostImpl::CreateRenderView(
ViewMsg_New_Params params;
params.renderer_preferences =
delegate_->GetRendererPrefs(GetProcess()->GetBrowserContext());
- params.web_preferences = delegate_->GetWebkitPrefs();
+ params.web_preferences = GetWebkitPreferences();
params.view_id = GetRoutingID();
params.main_frame_routing_id = main_frame_routing_id_;
params.surface_id = surface_id();
params.session_storage_namespace_id =
- delegate_->GetSessionStorageNamespace(instance_)->id();
+ delegate_->GetSessionStorageNamespace(instance_.get())->id();
params.frame_name = frame_name;
// Ensure the RenderView sets its opener correctly.
params.opener_route_id = opener_route_id;
- params.swapped_out = !IsRVHStateActive(rvh_state_);
+ params.swapped_out = !is_active_;
params.proxy_routing_id = proxy_route_id;
params.hidden = is_hidden();
params.never_visible = delegate_->IsNeverVisible();
params.window_was_created_with_opener = window_was_created_with_opener;
params.next_page_id = next_page_id;
GetWebScreenInfo(&params.screen_info);
- params.accessibility_mode = accessibility_mode();
Send(new ViewMsg_New(params));
@@ -335,11 +314,12 @@ void RenderViewHostImpl::SyncRendererPrefs() {
GetProcess()->GetBrowserContext())));
}
-WebPreferences RenderViewHostImpl::GetWebkitPrefs(const GURL& url) {
+WebPreferences RenderViewHostImpl::ComputeWebkitPrefs(const GURL& url) {
TRACE_EVENT0("browser", "RenderViewHostImpl::GetWebkitPrefs");
WebPreferences prefs;
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
prefs.javascript_enabled =
!command_line.HasSwitch(switches::kDisableJavaScript);
@@ -387,8 +367,6 @@ WebPreferences RenderViewHostImpl::GetWebkitPrefs(const GURL& url) {
GpuProcessHost::gpu_enabled() &&
!command_line.HasSwitch(switches::kDisableFlashStage3d);
- prefs.site_specific_quirks_enabled =
- !command_line.HasSwitch(switches::kDisableSiteSpecificQuirks);
prefs.allow_file_access_from_file_urls =
command_line.HasSwitch(switches::kAllowFileAccessFromFiles);
@@ -403,13 +381,15 @@ WebPreferences RenderViewHostImpl::GetWebkitPrefs(const GURL& url) {
!command_line.HasSwitch(switches::kDisableAccelerated2dCanvas);
prefs.antialiased_2d_canvas_disabled =
command_line.HasSwitch(switches::kDisable2dCanvasAntialiasing);
+ prefs.antialiased_clips_2d_canvas_enabled =
+ command_line.HasSwitch(switches::kEnable2dCanvasClipAntialiasing);
prefs.accelerated_2d_canvas_msaa_sample_count =
atoi(command_line.GetSwitchValueASCII(
switches::kAcceleratedCanvas2dMSAASampleCount).c_str());
- prefs.deferred_filters_enabled =
- !command_line.HasSwitch(switches::kDisableDeferredFilters);
prefs.container_culling_enabled =
command_line.HasSwitch(switches::kEnableContainerCulling);
+ prefs.text_blobs_enabled =
+ command_line.HasSwitch(switches::kEnableTextBlobs);
prefs.region_based_columns_enabled =
command_line.HasSwitch(switches::kEnableRegionBasedColumns);
@@ -420,8 +400,14 @@ WebPreferences RenderViewHostImpl::GetWebkitPrefs(const GURL& url) {
prefs.use_solid_color_scrollbars = ui::IsOverlayScrollbarEnabled();
#if defined(OS_ANDROID)
+ // On Android, user gestures are normally required, unless that requirement
+ // is disabled with a command-line switch or the equivalent field trial is
+ // is set to "Enabled".
+ const std::string autoplay_group_name = base::FieldTrialList::FindFullName(
+ "MediaElementAutoplay");
prefs.user_gesture_required_for_media_playback = !command_line.HasSwitch(
- switches::kDisableGestureRequirementForMediaPlayback);
+ switches::kDisableGestureRequirementForMediaPlayback) &&
+ (autoplay_group_name.empty() || autoplay_group_name != "Enabled");
#endif
prefs.touch_enabled = ui::AreTouchEventsEnabled();
@@ -435,8 +421,9 @@ WebPreferences RenderViewHostImpl::GetWebkitPrefs(const GURL& url) {
prefs.touch_adjustment_enabled =
!command_line.HasSwitch(switches::kDisableTouchAdjustment);
- prefs.compositor_touch_hit_testing =
- !command_line.HasSwitch(cc::switches::kDisableCompositorTouchHitTesting);
+
+ prefs.slimming_paint_enabled =
+ command_line.HasSwitch(switches::kEnableSlimmingPaint);
#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
bool default_enable_scroll_animator = true;
@@ -462,9 +449,6 @@ WebPreferences RenderViewHostImpl::GetWebkitPrefs(const GURL& url) {
prefs.is_online =
prefs.connection_type != net::NetworkChangeNotifier::CONNECTION_NONE;
- prefs.gesture_tap_highlight_enabled = !command_line.HasSwitch(
- switches::kDisableGestureTapHighlight);
-
prefs.number_of_cpu_cores = base::SysInfo::NumberOfProcessors();
prefs.viewport_meta_enabled =
@@ -481,139 +465,51 @@ WebPreferences RenderViewHostImpl::GetWebkitPrefs(const GURL& url) {
command_line.HasSwitch(switches::kEnableDeferredImageDecoding) ||
content::IsImplSidePaintingEnabled();
+ prefs.image_color_profiles_enabled =
+ command_line.HasSwitch(switches::kEnableImageColorProfiles);
+
prefs.spatial_navigation_enabled = command_line.HasSwitch(
switches::kEnableSpatialNavigation);
- GetContentClient()->browser()->OverrideWebkitPrefs(this, url, &prefs);
- return prefs;
-}
-
-void RenderViewHostImpl::Navigate(const FrameMsg_Navigate_Params& params) {
- TRACE_EVENT0("renderer_host", "RenderViewHostImpl::Navigate");
- delegate_->GetFrameTree()->GetMainFrame()->Navigate(params);
-}
-
-void RenderViewHostImpl::NavigateToURL(const GURL& url) {
- delegate_->GetFrameTree()->GetMainFrame()->NavigateToURL(url);
-}
-
-void RenderViewHostImpl::SetNavigationsSuspended(
- bool suspend,
- const base::TimeTicks& proceed_time) {
- // This should only be called to toggle the state.
- DCHECK(navigations_suspended_ != suspend);
-
- navigations_suspended_ = suspend;
- 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(STATE_DEFAULT);
-
- DCHECK(!proceed_time.is_null());
- suspended_nav_params_->browser_navigation_start = proceed_time;
- Send(new FrameMsg_Navigate(
- main_frame_routing_id_, *suspended_nav_params_.get()));
- suspended_nav_params_.reset();
- }
-}
-
-void RenderViewHostImpl::CancelSuspendedNavigations() {
- // Clear any state if a pending navigation is canceled or pre-empted.
- if (suspended_nav_params_)
- suspended_nav_params_.reset();
- navigations_suspended_ = false;
-}
-
-void RenderViewHostImpl::SuppressDialogsUntilSwapOut() {
- Send(new ViewMsg_SuppressDialogsUntilSwapOut(GetRoutingID()));
-}
-
-void RenderViewHostImpl::OnSwappedOut(bool timed_out) {
- // Ignore spurious swap out ack.
- if (!IsWaitingForUnloadACK())
- return;
- unload_event_monitor_timeout_->Stop();
- if (timed_out) {
- base::ProcessHandle process_handle = GetProcess()->GetHandle();
- int views = 0;
-
- // Count the number of active widget hosts for the process, which
- // is equivalent to views using the process as of this writing.
- scoped_ptr<RenderWidgetHostIterator> widgets(
- RenderWidgetHost::GetRenderWidgetHosts());
- while (RenderWidgetHost* widget = widgets->GetNextHost()) {
- if (widget->GetProcess()->GetID() == GetProcess()->GetID())
- ++views;
- }
-
- if (!RenderProcessHost::run_renderer_in_process() &&
- process_handle && views <= 1) {
- // The process can safely be terminated, only if WebContents sets
- // SuddenTerminationAllowed, which indicates that the timer has expired.
- // This is not the case if we load data URLs or about:blank. The reason
- // is that those have no network requests and this code is hit without
- // setting the unresponsiveness timer. This allows a corner case where a
- // navigation to a data URL will leave a process running, if the
- // beforeunload handler completes fine, but the unload handler hangs.
- // At this time, the complexity to solve this edge case is not worthwhile.
- if (SuddenTerminationAllowed()) {
- // We should kill the process, but for now, just log the data so we can
- // diagnose the kill rate and investigate if separate timer is needed.
- // http://crbug.com/104346.
-
- // Log a histogram point to help us diagnose how many of those kills
- // we have performed. 1 is the enum value for RendererType Normal for
- // the histogram.
- UMA_HISTOGRAM_PERCENTAGE(
- "BrowserRenderProcessHost.ChildKillsUnresponsive", 1);
- }
+ if (command_line.HasSwitch(switches::kV8CacheOptions)) {
+ const std::string v8_cache_options =
+ command_line.GetSwitchValueASCII(switches::kV8CacheOptions);
+ if (v8_cache_options == "parse") {
+ prefs.v8_cache_options = V8_CACHE_OPTIONS_PARSE;
+ } else if (v8_cache_options == "code") {
+ prefs.v8_cache_options = V8_CACHE_OPTIONS_CODE;
+ } else {
+ prefs.v8_cache_options = V8_CACHE_OPTIONS_OFF;
}
}
- switch (rvh_state_) {
- case STATE_WAITING_FOR_UNLOAD_ACK:
- SetState(STATE_WAITING_FOR_COMMIT);
- break;
- case STATE_PENDING_SWAP_OUT:
- SetState(STATE_SWAPPED_OUT);
- break;
- case STATE_PENDING_SHUTDOWN:
- DCHECK(!pending_shutdown_on_swap_out_.is_null());
- pending_shutdown_on_swap_out_.Run();
- break;
- default:
- NOTREACHED();
+ std::string streaming_experiment_group =
+ base::FieldTrialList::FindFullName("V8ScriptStreaming");
+ prefs.v8_script_streaming_enabled =
+ command_line.HasSwitch(switches::kEnableV8ScriptStreaming);
+ if (streaming_experiment_group == "Enabled") {
+ prefs.v8_script_streaming_enabled = true;
+ prefs.v8_script_streaming_mode = V8_SCRIPT_STREAMING_MODE_ALL;
+ } else if (streaming_experiment_group == "OnlyAsyncAndDefer") {
+ prefs.v8_script_streaming_enabled = true;
+ prefs.v8_script_streaming_mode =
+ V8_SCRIPT_STREAMING_MODE_ONLY_ASYNC_AND_DEFER;
+ } else if (streaming_experiment_group == "AllPlusBlockParserBlocking") {
+ prefs.v8_script_streaming_enabled = true;
+ prefs.v8_script_streaming_mode =
+ V8_SCRIPT_STREAMING_MODE_ALL_PLUS_BLOCK_PARSER_BLOCKING;
}
-}
-void RenderViewHostImpl::WasSwappedOut(
- const base::Closure& pending_delete_on_swap_out) {
- Send(new ViewMsg_WasSwappedOut(GetRoutingID()));
- if (rvh_state_ == STATE_WAITING_FOR_UNLOAD_ACK) {
- SetState(STATE_PENDING_SWAP_OUT);
- if (!instance_->active_view_count())
- SetPendingShutdown(pending_delete_on_swap_out);
- } else if (rvh_state_ == STATE_WAITING_FOR_COMMIT) {
- SetState(STATE_SWAPPED_OUT);
- } else if (rvh_state_ == STATE_DEFAULT) {
- // When the RenderView is not live, the RenderFrameHostManager will call
- // CommitPending directly, without calling SwapOut on the old RVH. This will
- // cause WasSwappedOut to be called directly on the live old RVH.
- DCHECK(!IsRenderViewLive());
- SetState(STATE_SWAPPED_OUT);
- } else {
- NOTREACHED();
- }
+ GetContentClient()->browser()->OverrideWebkitPrefs(this, url, &prefs);
+ return prefs;
}
-void RenderViewHostImpl::SetPendingShutdown(const base::Closure& on_swap_out) {
- pending_shutdown_on_swap_out_ = on_swap_out;
- SetState(STATE_PENDING_SHUTDOWN);
+void RenderViewHostImpl::SuppressDialogsUntilSwapOut() {
+ Send(new ViewMsg_SuppressDialogsUntilSwapOut(GetRoutingID()));
}
void RenderViewHostImpl::ClosePage() {
- SetState(STATE_WAITING_FOR_CLOSE);
+ is_waiting_for_close_ack_ = true;
StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
if (IsRenderViewLive()) {
@@ -639,44 +535,12 @@ void RenderViewHostImpl::ClosePage() {
void RenderViewHostImpl::ClosePageIgnoringUnloadEvents() {
StopHangMonitorTimeout();
- is_waiting_for_beforeunload_ack_ = false;
+ is_waiting_for_close_ack_ = false;
sudden_termination_allowed_ = true;
delegate_->Close(this);
}
-bool RenderViewHostImpl::HasPendingCrossSiteRequest() {
- return CrossSiteRequestManager::GetInstance()->HasPendingCrossSiteRequest(
- GetProcess()->GetID(), GetRoutingID());
-}
-
-void RenderViewHostImpl::SetHasPendingCrossSiteRequest(
- bool has_pending_request) {
- CrossSiteRequestManager::GetInstance()->SetHasPendingCrossSiteRequest(
- GetProcess()->GetID(), GetRoutingID(), has_pending_request);
-}
-
-void RenderViewHostImpl::SetWebUIHandle(mojo::ScopedMessagePipeHandle handle) {
- // Never grant any bindings to browser plugin guests.
- if (GetProcess()->IsIsolatedGuest()) {
- NOTREACHED() << "Never grant bindings to a guest process.";
- return;
- }
-
- if ((enabled_bindings_ & BINDINGS_POLICY_WEB_UI) == 0) {
- NOTREACHED() << "You must grant bindings before setting the handle";
- return;
- }
-
- DCHECK(renderer_initialized_);
-
- WebUISetupPtr web_ui_setup;
- static_cast<RenderProcessHostImpl*>(GetProcess())->ConnectTo(
- kRendererService_WebUISetup, &web_ui_setup);
-
- web_ui_setup->SetWebUIHandle(GetRoutingID(), handle.Pass());
-}
-
#if defined(OS_ANDROID)
void RenderViewHostImpl::ActivateNearestFindResult(int request_id,
float x,
@@ -700,6 +564,13 @@ void RenderViewHostImpl::DragTargetDragEnter(
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
+#if defined(OS_CHROMEOS)
+ // The externalfile:// scheme is used in Chrome OS to open external files in a
+ // browser tab.
+ if (drop_data.url.SchemeIs(content::kExternalFileScheme))
+ policy->GrantRequestURL(renderer_id, drop_data.url);
+#endif
+
// The URL could have been cobbled together from any highlighted text string,
// and can't be interpreted as a capability.
DropData filtered_data(drop_data);
@@ -710,7 +581,7 @@ void RenderViewHostImpl::DragTargetDragEnter(
// The filenames vector, on the other hand, does represent a capability to
// access the given files.
- fileapi::IsolatedContext::FileInfoSet files;
+ storage::IsolatedContext::FileInfoSet files;
for (std::vector<ui::FileInfo>::iterator iter(
filtered_data.filenames.begin());
iter != filtered_data.filenames.end();
@@ -743,8 +614,8 @@ void RenderViewHostImpl::DragTargetDragEnter(
policy->GrantReadFile(renderer_id, iter->path);
}
- fileapi::IsolatedContext* isolated_context =
- fileapi::IsolatedContext::GetInstance();
+ storage::IsolatedContext* isolated_context =
+ storage::IsolatedContext::GetInstance();
DCHECK(isolated_context);
std::string filesystem_id = isolated_context->RegisterDraggedFileSystem(
files);
@@ -754,12 +625,12 @@ void RenderViewHostImpl::DragTargetDragEnter(
}
filtered_data.filesystem_id = base::UTF8ToUTF16(filesystem_id);
- fileapi::FileSystemContext* file_system_context =
- BrowserContext::GetStoragePartition(
- GetProcess()->GetBrowserContext(),
- GetSiteInstance())->GetFileSystemContext();
+ storage::FileSystemContext* file_system_context =
+ BrowserContext::GetStoragePartition(GetProcess()->GetBrowserContext(),
+ GetSiteInstance())
+ ->GetFileSystemContext();
for (size_t i = 0; i < filtered_data.file_system_files.size(); ++i) {
- fileapi::FileSystemURL file_system_url =
+ storage::FileSystemURL file_system_url =
file_system_context->CrackURL(filtered_data.file_system_files[i].url);
std::string register_name;
@@ -770,11 +641,10 @@ void RenderViewHostImpl::DragTargetDragEnter(
// Note: We are using the origin URL provided by the sender here. It may be
// different from the receiver's.
- filtered_data.file_system_files[i].url = GURL(
- fileapi::GetIsolatedFileSystemRootURIString(
- file_system_url.origin(),
- filesystem_id,
- std::string()).append(register_name));
+ filtered_data.file_system_files[i].url =
+ GURL(storage::GetIsolatedFileSystemRootURIString(
+ file_system_url.origin(), filesystem_id, std::string())
+ .append(register_name));
}
Send(new DragMsg_TargetDragEnter(GetRoutingID(), filtered_data, client_pt,
@@ -839,7 +709,8 @@ void RenderViewHostImpl::AllowBindings(int bindings_flags) {
static_cast<RenderProcessHostImpl*>(GetProcess());
// --single-process only has one renderer.
if (process->GetActiveViewCount() > 1 &&
- !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess))
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSingleProcess))
return;
}
@@ -896,17 +767,27 @@ void RenderViewHostImpl::SetInitialFocus(bool reverse) {
}
void RenderViewHostImpl::FilesSelectedInChooser(
- const std::vector<ui::SelectedFileInfo>& files,
+ const std::vector<content::FileChooserFileInfo>& files,
FileChooserParams::Mode permissions) {
+ storage::FileSystemContext* const file_system_context =
+ BrowserContext::GetStoragePartition(GetProcess()->GetBrowserContext(),
+ GetSiteInstance())
+ ->GetFileSystemContext();
// Grant the security access requested to the given files.
for (size_t i = 0; i < files.size(); ++i) {
- const ui::SelectedFileInfo& file = files[i];
+ const content::FileChooserFileInfo& file = files[i];
if (permissions == FileChooserParams::Save) {
ChildProcessSecurityPolicyImpl::GetInstance()->GrantCreateReadWriteFile(
- GetProcess()->GetID(), file.local_path);
+ GetProcess()->GetID(), file.file_path);
} else {
ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
- GetProcess()->GetID(), file.local_path);
+ GetProcess()->GetID(), file.file_path);
+ }
+ if (file.file_system_url.is_valid()) {
+ ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFileSystem(
+ GetProcess()->GetID(),
+ file_system_context->CrackURL(file.file_system_url)
+ .mount_filesystem_id());
}
}
Send(new ViewMsg_RunFileChooserResponse(GetRoutingID(), files));
@@ -926,6 +807,20 @@ void RenderViewHostImpl::DirectoryEnumerationFinished(
files));
}
+void RenderViewHostImpl::SetIsLoading(bool is_loading) {
+ if (ResourceDispatcherHostImpl::Get()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostSetIsLoading,
+ base::Unretained(ResourceDispatcherHostImpl::Get()),
+ GetProcess()->GetID(),
+ GetRoutingID(),
+ is_loading));
+ }
+ RenderWidgetHostImpl::SetIsLoading(is_loading);
+}
+
void RenderViewHostImpl::LoadStateChanged(
const GURL& url,
const net::LoadStateWithParam& load_state,
@@ -948,7 +843,7 @@ bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
// Filter out most IPC messages if this renderer is swapped out.
// We still want to handle certain ACKs to keep our state consistent.
- if (IsSwappedOut()) {
+ 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
@@ -977,8 +872,6 @@ bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_RenderProcessGone, OnRenderProcessGone)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateState, OnUpdateState)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateTargetURL, OnUpdateTargetURL)
- IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateInspectorSetting,
- OnUpdateInspectorSetting)
IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnClose)
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnRequestMove)
IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentAvailableInMainFrame,
@@ -986,8 +879,6 @@ bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_ToggleFullscreen, OnToggleFullscreen)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidContentsPreferredSizeChange,
OnDidContentsPreferredSizeChange)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DidChangeScrollOffset,
- OnDidChangeScrollOffset)
IPC_MESSAGE_HANDLER(ViewHostMsg_RouteCloseEvent,
OnRouteCloseEvent)
IPC_MESSAGE_HANDLER(ViewHostMsg_RouteMessageEvent, OnRouteMessageEvent)
@@ -998,14 +889,7 @@ bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeChanged, OnFocusedNodeChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_ClosePage_ACK, OnClosePageACK)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidZoomURL, OnDidZoomURL)
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnShowPopup)
- IPC_MESSAGE_HANDLER(ViewHostMsg_HidePopup, OnHidePopup)
-#endif
IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser)
- IPC_MESSAGE_HANDLER(AccessibilityHostMsg_Events, OnAccessibilityEvents)
- IPC_MESSAGE_HANDLER(AccessibilityHostMsg_LocationChanges,
- OnAccessibilityLocationChanges)
IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeTouched, OnFocusedNodeTouched)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(
@@ -1047,6 +931,30 @@ void RenderViewHostImpl::Shutdown() {
RenderWidgetHostImpl::Shutdown();
}
+void RenderViewHostImpl::WasHidden() {
+ if (ResourceDispatcherHostImpl::Get()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostWasHidden,
+ base::Unretained(ResourceDispatcherHostImpl::Get()),
+ GetProcess()->GetID(), GetRoutingID()));
+ }
+
+ RenderWidgetHostImpl::WasHidden();
+}
+
+void RenderViewHostImpl::WasShown(const ui::LatencyInfo& latency_info) {
+ if (ResourceDispatcherHostImpl::Get()) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ResourceDispatcherHostImpl::OnRenderViewHostWasShown,
+ base::Unretained(ResourceDispatcherHostImpl::Get()),
+ GetProcess()->GetID(), GetRoutingID()));
+ }
+
+ RenderWidgetHostImpl::WasShown(latency_info);
+}
+
bool RenderViewHostImpl::IsRenderView() const {
return true;
}
@@ -1079,7 +987,7 @@ void RenderViewHostImpl::OnShowView(int route_id,
WindowOpenDisposition disposition,
const gfx::Rect& initial_pos,
bool user_gesture) {
- if (IsRVHStateActive(rvh_state_)) {
+ if (is_active_) {
delegate_->ShowCreatedWindow(
route_id, disposition, initial_pos, user_gesture);
}
@@ -1088,13 +996,13 @@ void RenderViewHostImpl::OnShowView(int route_id,
void RenderViewHostImpl::OnShowWidget(int route_id,
const gfx::Rect& initial_pos) {
- if (IsRVHStateActive(rvh_state_))
+ if (is_active_)
delegate_->ShowCreatedWidget(route_id, initial_pos);
Send(new ViewMsg_Move_ACK(route_id));
}
void RenderViewHostImpl::OnShowFullscreenWidget(int route_id) {
- if (IsRVHStateActive(rvh_state_))
+ if (is_active_)
delegate_->ShowCreatedFullscreenWidget(route_id);
Send(new ViewMsg_Move_ACK(route_id));
}
@@ -1146,6 +1054,12 @@ void RenderViewHostImpl::OnRenderProcessGone(int status, int exit_code) {
}
void RenderViewHostImpl::OnUpdateState(int32 page_id, const PageState& state) {
+ // If the following DCHECK fails, you have encountered a tricky edge-case that
+ // has evaded reproduction for a very long time. Please report what you were
+ // doing on http://crbug.com/407376, whether or not you can reproduce the
+ // failure.
+ DCHECK_EQ(page_id, page_id_);
+
// Without this check, the renderer can trick the browser into using
// filenames it can't access in a future session restore.
if (!CanAccessFilesOfPageState(state)) {
@@ -1156,21 +1070,15 @@ void RenderViewHostImpl::OnUpdateState(int32 page_id, const PageState& state) {
delegate_->UpdateState(this, page_id, state);
}
-void RenderViewHostImpl::OnUpdateTargetURL(int32 page_id, const GURL& url) {
- if (IsRVHStateActive(rvh_state_))
- delegate_->UpdateTargetURL(page_id, url);
+void RenderViewHostImpl::OnUpdateTargetURL(const GURL& url) {
+ if (is_active_)
+ delegate_->UpdateTargetURL(url);
// Send a notification back to the renderer that we are ready to
// receive more target urls.
Send(new ViewMsg_UpdateTargetURL_ACK(GetRoutingID()));
}
-void RenderViewHostImpl::OnUpdateInspectorSetting(
- const std::string& key, const std::string& value) {
- GetContentClient()->browser()->UpdateInspectorSetting(
- this, key, value);
-}
-
void RenderViewHostImpl::OnClose() {
// If the renderer is telling us to close, it has already run the unload
// events, and we can take the fast path.
@@ -1178,7 +1086,7 @@ void RenderViewHostImpl::OnClose() {
}
void RenderViewHostImpl::OnRequestMove(const gfx::Rect& pos) {
- if (IsRVHStateActive(rvh_state_))
+ if (is_active_)
delegate_->RequestMove(pos);
Send(new ViewMsg_Move_ACK(GetRoutingID()));
}
@@ -1190,8 +1098,9 @@ void RenderViewHostImpl::OnDocumentAvailableInMainFrame(
if (!uses_temporary_zoom_level)
return;
- HostZoomMapImpl* host_zoom_map = static_cast<HostZoomMapImpl*>(
- HostZoomMap::GetForBrowserContext(GetProcess()->GetBrowserContext()));
+ HostZoomMapImpl* host_zoom_map =
+ static_cast<HostZoomMapImpl*>(HostZoomMap::GetDefaultForBrowserContext(
+ GetProcess()->GetBrowserContext()));
host_zoom_map->SetTemporaryZoomLevel(GetProcess()->GetID(),
GetRoutingID(),
host_zoom_map->GetDefaultZoomLevel());
@@ -1214,11 +1123,6 @@ void RenderViewHostImpl::OnRenderAutoResized(const gfx::Size& new_size) {
delegate_->ResizeDueToAutoResize(new_size);
}
-void RenderViewHostImpl::OnDidChangeScrollOffset() {
- if (view_)
- view_->ScrollOffsetChanged();
-}
-
void RenderViewHostImpl::OnRouteCloseEvent() {
// Have the delegate route this to the active RenderViewHost.
delegate_->RouteCloseEvent(this);
@@ -1266,13 +1170,13 @@ void RenderViewHostImpl::OnStartDragging(
filtered_data.filenames.push_back(*it);
}
- fileapi::FileSystemContext* file_system_context =
- BrowserContext::GetStoragePartition(
- GetProcess()->GetBrowserContext(),
- GetSiteInstance())->GetFileSystemContext();
+ storage::FileSystemContext* file_system_context =
+ BrowserContext::GetStoragePartition(GetProcess()->GetBrowserContext(),
+ GetSiteInstance())
+ ->GetFileSystemContext();
filtered_data.file_system_files.clear();
for (size_t i = 0; i < drop_data.file_system_files.size(); ++i) {
- fileapi::FileSystemURL file_system_url =
+ storage::FileSystemURL file_system_url =
file_system_context->CrackURL(drop_data.file_system_files[i].url);
if (policy->CanReadFileSystemFile(GetProcess()->GetID(), file_system_url))
filtered_data.file_system_files.push_back(drop_data.file_system_files[i]);
@@ -1332,8 +1236,7 @@ void RenderViewHostImpl::OnClosePageACK() {
}
void RenderViewHostImpl::NotifyRendererUnresponsive() {
- delegate_->RendererUnresponsive(
- this, is_waiting_for_beforeunload_ack_, IsWaitingForUnloadACK());
+ delegate_->RendererUnresponsive(this);
}
void RenderViewHostImpl::NotifyRendererResponsive() {
@@ -1407,36 +1310,6 @@ void RenderViewHostImpl::ForwardKeyboardEvent(
RenderWidgetHostImpl::ForwardKeyboardEvent(key_event);
}
-#if defined(OS_ANDROID)
-void RenderViewHostImpl::DidSelectPopupMenuItems(
- const std::vector<int>& selected_indices) {
- Send(new ViewMsg_SelectPopupMenuItems(GetRoutingID(), false,
- selected_indices));
-}
-
-void RenderViewHostImpl::DidCancelPopupMenu() {
- Send(new ViewMsg_SelectPopupMenuItems(GetRoutingID(), true,
- std::vector<int>()));
-}
-#endif
-
-#if defined(OS_MACOSX)
-void RenderViewHostImpl::DidSelectPopupMenuItem(int selected_index) {
- Send(new ViewMsg_SelectPopupMenuItem(GetRoutingID(), selected_index));
-}
-
-void RenderViewHostImpl::DidCancelPopupMenu() {
- Send(new ViewMsg_SelectPopupMenuItem(GetRoutingID(), -1));
-}
-#endif
-
-bool RenderViewHostImpl::IsWaitingForUnloadACK() const {
- return rvh_state_ == STATE_WAITING_FOR_UNLOAD_ACK ||
- rvh_state_ == STATE_WAITING_FOR_CLOSE ||
- rvh_state_ == STATE_PENDING_SHUTDOWN ||
- rvh_state_ == STATE_PENDING_SWAP_OUT;
-}
-
void RenderViewHostImpl::OnTextSurroundingSelectionResponse(
const base::string16& content,
size_t start_offset,
@@ -1453,28 +1326,31 @@ void RenderViewHostImpl::ExitFullscreen() {
}
WebPreferences RenderViewHostImpl::GetWebkitPreferences() {
- return delegate_->GetWebkitPrefs();
-}
-
-void RenderViewHostImpl::DisownOpener() {
- // This should only be called when swapped out.
- DCHECK(IsSwappedOut());
-
- Send(new ViewMsg_DisownOpener(GetRoutingID()));
-}
-
-void RenderViewHostImpl::SetAccessibilityCallbackForTesting(
- const base::Callback<void(ui::AXEvent, int)>& callback) {
- accessibility_testing_callback_ = callback;
+ if (!web_preferences_.get()) {
+ OnWebkitPreferencesChanged();
+ }
+ return *web_preferences_;
}
void RenderViewHostImpl::UpdateWebkitPreferences(const WebPreferences& prefs) {
+ web_preferences_.reset(new WebPreferences(prefs));
Send(new ViewMsg_UpdateWebPreferences(GetRoutingID(), prefs));
}
+void RenderViewHostImpl::OnWebkitPreferencesChanged() {
+ // This is defensive code to avoid infinite loops due to code run inside
+ // UpdateWebkitPreferences() accidentally updating more preferences and thus
+ // calling back into this code. See crbug.com/398751 for one past example.
+ if (updating_web_preferences_)
+ return;
+ updating_web_preferences_ = true;
+ UpdateWebkitPreferences(delegate_->ComputeWebkitPrefs());
+ updating_web_preferences_ = false;
+}
+
void RenderViewHostImpl::GetAudioOutputControllers(
const GetAudioOutputControllersCallback& callback) const {
- AudioRendererHost* audio_host =
+ scoped_refptr<AudioRendererHost> audio_host =
static_cast<RenderProcessHostImpl*>(GetProcess())->audio_renderer_host();
audio_host->GetOutputControllers(GetRoutingID(), callback);
}
@@ -1509,6 +1385,8 @@ void RenderViewHostImpl::EnableAutoResize(const gfx::Size& min_size,
void RenderViewHostImpl::DisableAutoResize(const gfx::Size& new_size) {
SetShouldAutoResize(false);
Send(new ViewMsg_DisableAutoResize(GetRoutingID(), new_size));
+ if (!new_size.IsEmpty())
+ GetView()->SetSize(new_size);
}
void RenderViewHostImpl::CopyImageAt(int x, int y) {
@@ -1533,70 +1411,11 @@ void RenderViewHostImpl::NotifyMoveOrResizeStarted() {
Send(new ViewMsg_MoveOrResizeStarted(GetRoutingID()));
}
-void RenderViewHostImpl::OnAccessibilityEvents(
- const std::vector<AccessibilityHostMsg_EventParams>& params) {
- if ((accessibility_mode() != AccessibilityModeOff) && view_ &&
- IsRVHStateActive(rvh_state_)) {
- if (accessibility_mode() & AccessibilityModeFlagPlatform) {
- view_->CreateBrowserAccessibilityManagerIfNeeded();
- BrowserAccessibilityManager* manager =
- view_->GetBrowserAccessibilityManager();
- if (manager)
- manager->OnAccessibilityEvents(params);
- }
-
- std::vector<AXEventNotificationDetails> details;
- for (unsigned int i = 0; i < params.size(); ++i) {
- const AccessibilityHostMsg_EventParams& param = params[i];
- AXEventNotificationDetails detail(param.update.nodes,
- param.event_type,
- param.id,
- GetProcess()->GetID(),
- GetRoutingID());
- details.push_back(detail);
- }
-
- delegate_->AccessibilityEventReceived(details);
- }
-
- // Always send an ACK or the renderer can be in a bad state.
- Send(new AccessibilityMsg_Events_ACK(GetRoutingID()));
-
- // The rest of this code is just for testing; bail out if we're not
- // in that mode.
- if (accessibility_testing_callback_.is_null())
- return;
-
- for (unsigned i = 0; i < params.size(); i++) {
- const AccessibilityHostMsg_EventParams& param = params[i];
- if (static_cast<int>(param.event_type) < 0)
- continue;
- if (!ax_tree_)
- ax_tree_.reset(new ui::AXTree(param.update));
- else
- CHECK(ax_tree_->Unserialize(param.update)) << ax_tree_->error();
- accessibility_testing_callback_.Run(param.event_type, param.id);
- }
-}
-
-void RenderViewHostImpl::OnAccessibilityLocationChanges(
- const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
- if (view_ && IsRVHStateActive(rvh_state_)) {
- if (accessibility_mode() & AccessibilityModeFlagPlatform) {
- view_->CreateBrowserAccessibilityManagerIfNeeded();
- BrowserAccessibilityManager* manager =
- view_->GetBrowserAccessibilityManager();
- if (manager)
- manager->OnLocationChanges(params);
- }
- // TODO(aboxhall): send location change events to web contents observers too
- }
-}
-
void RenderViewHostImpl::OnDidZoomURL(double zoom_level,
const GURL& url) {
- HostZoomMapImpl* host_zoom_map = static_cast<HostZoomMapImpl*>(
- HostZoomMap::GetForBrowserContext(GetProcess()->GetBrowserContext()));
+ HostZoomMapImpl* host_zoom_map =
+ static_cast<HostZoomMapImpl*>(HostZoomMap::GetDefaultForBrowserContext(
+ GetProcess()->GetBrowserContext()));
host_zoom_map->SetZoomLevelForView(GetProcess()->GetID(),
GetRoutingID(),
@@ -1619,49 +1438,6 @@ void RenderViewHostImpl::OnFocusedNodeTouched(bool editable) {
#endif
}
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-void RenderViewHostImpl::OnShowPopup(
- const ViewHostMsg_ShowPopup_Params& params) {
- RenderViewHostDelegateView* view = delegate_->GetDelegateView();
- if (view) {
- view->ShowPopupMenu(params.bounds,
- params.item_height,
- params.item_font_size,
- params.selected_item,
- params.popup_items,
- params.right_aligned,
- params.allow_multiple_selection);
- }
-}
-
-void RenderViewHostImpl::OnHidePopup() {
- RenderViewHostDelegateView* view = delegate_->GetDelegateView();
- if (view)
- view->HidePopupMenu();
-}
-#endif
-
-void RenderViewHostImpl::SetState(RenderViewHostImplState rvh_state) {
- // We update the number of RenderViews in a SiteInstance when the
- // swapped out status of this RenderView gets flipped to/from live.
- if (!IsRVHStateActive(rvh_state_) && IsRVHStateActive(rvh_state))
- instance_->increment_active_view_count();
- else if (IsRVHStateActive(rvh_state_) && !IsRVHStateActive(rvh_state))
- instance_->decrement_active_view_count();
-
- // Whenever we change the RVH state to and from live or swapped out state, we
- // should not be waiting for beforeunload or unload acks. We clear them here
- // to be safe, since they can cause navigations to be ignored in OnNavigate.
- if (rvh_state == STATE_DEFAULT ||
- rvh_state == STATE_SWAPPED_OUT ||
- rvh_state_ == STATE_DEFAULT ||
- rvh_state_ == STATE_SWAPPED_OUT) {
- is_waiting_for_beforeunload_ack_ = false;
- }
- rvh_state_ = rvh_state;
-
-}
-
bool RenderViewHostImpl::CanAccessFilesOfPageState(
const PageState& state) const {
ChildProcessSecurityPolicyImpl* policy =
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 5f7344f7f5b..c6fdf055b0d 100644
--- a/chromium/content/browser/renderer_host/render_view_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_view_host_impl.h
@@ -25,17 +25,13 @@
#include "third_party/WebKit/public/web/WebConsoleMessage.h"
#include "third_party/WebKit/public/web/WebPopupType.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/accessibility/ax_node_data.h"
#include "ui/base/window_open_disposition.h"
class SkBitmap;
class FrameMsg_Navigate;
-struct AccessibilityHostMsg_EventParams;
-struct AccessibilityHostMsg_LocationChangeParams;
+struct FrameMsg_Navigate_Params;
struct MediaPlayerAction;
struct ViewHostMsg_CreateWindow_Params;
-struct ViewHostMsg_ShowPopup_Params;
-struct FrameMsg_Navigate_Params;
struct ViewMsg_PostMessage_Params;
namespace base {
@@ -48,7 +44,6 @@ class Range;
namespace ui {
class AXTree;
-struct SelectedFileInfo;
}
namespace content {
@@ -60,7 +55,7 @@ class RenderWidgetHostDelegate;
class SessionStorageNamespace;
class SessionStorageNamespaceImpl;
class TestRenderViewHost;
-class TimeoutMonitor;
+struct FileChooserFileInfo;
struct FileChooserParams;
#if defined(COMPILER_MSVC)
@@ -93,39 +88,6 @@ class CONTENT_EXPORT RenderViewHostImpl
: public RenderViewHost,
public RenderWidgetHostImpl {
public:
- // Keeps track of the state of the RenderViewHostImpl, particularly with
- // respect to swap out.
- enum RenderViewHostImplState {
- // The standard state for a RVH handling the communication with a
- // RenderView.
- STATE_DEFAULT = 0,
- // The RVH has sent the SwapOut request to the renderer, but has not
- // received the SwapOutACK yet. The new page has not been committed yet
- // either.
- STATE_WAITING_FOR_UNLOAD_ACK,
- // The RVH received the SwapOutACK from the RenderView, but the new page has
- // not been committed yet.
- STATE_WAITING_FOR_COMMIT,
- // The RVH is waiting for the CloseACK from the RenderView.
- STATE_WAITING_FOR_CLOSE,
- // The RVH has not received the SwapOutACK yet, but the new page has
- // committed in a different RVH. The number of active views of the RVH
- // SiteInstanceImpl is not zero. Upon reception of the SwapOutACK, the RVH
- // will be swapped out.
- STATE_PENDING_SWAP_OUT,
- // The RVH has not received the SwapOutACK yet, but the new page has
- // committed in a different RVH. The number of active views of the RVH
- // SiteInstanceImpl is zero. Upon reception of the SwapOutACK, the RVH will
- // be shutdown.
- STATE_PENDING_SHUTDOWN,
- // The RVH is swapped out, and it is being used as a placeholder to allow
- // for cross-process communication.
- STATE_SWAPPED_OUT,
- };
- // Helper function to determine whether the RVH state should contribute to the
- // number of active views of a SiteInstance or not.
- static bool IsRVHStateActive(RenderViewHostImplState rvh_state);
-
// Convenience function, just like RenderViewHost::FromID.
static RenderViewHostImpl* FromID(int render_process_id, int render_view_id);
@@ -140,83 +102,82 @@ class CONTENT_EXPORT RenderViewHostImpl
// spec) space. This is useful when restoring contentses, but most callers
// should pass in NULL which will cause a new SessionStorageNamespace to be
// created.
- RenderViewHostImpl(
- SiteInstance* instance,
- RenderViewHostDelegate* delegate,
- RenderWidgetHostDelegate* widget_delegate,
- int routing_id,
- int main_frame_routing_id,
- bool swapped_out,
- bool hidden);
- virtual ~RenderViewHostImpl();
+ RenderViewHostImpl(SiteInstance* instance,
+ RenderViewHostDelegate* delegate,
+ RenderWidgetHostDelegate* widget_delegate,
+ int routing_id,
+ int main_frame_routing_id,
+ bool swapped_out,
+ bool hidden,
+ bool has_initialized_audio_host);
+ ~RenderViewHostImpl() override;
// RenderViewHost implementation.
- virtual RenderFrameHost* GetMainFrame() OVERRIDE;
- virtual void AllowBindings(int binding_flags) OVERRIDE;
- virtual void ClearFocusedElement() OVERRIDE;
- virtual bool IsFocusedElementEditable() OVERRIDE;
- virtual void ClosePage() OVERRIDE;
- virtual void CopyImageAt(int x, int y) OVERRIDE;
- virtual void SaveImageAt(int x, int y) OVERRIDE;
- virtual void DirectoryEnumerationFinished(
+ RenderFrameHost* GetMainFrame() override;
+ void AllowBindings(int binding_flags) override;
+ void ClearFocusedElement() override;
+ bool IsFocusedElementEditable() override;
+ void ClosePage() override;
+ void CopyImageAt(int x, int y) override;
+ void SaveImageAt(int x, int y) override;
+ void DirectoryEnumerationFinished(
int request_id,
- const std::vector<base::FilePath>& files) OVERRIDE;
- virtual void DisableScrollbarsForThreshold(const gfx::Size& size) OVERRIDE;
- virtual void DragSourceEndedAt(
- int client_x, int client_y, int screen_x, int screen_y,
- blink::WebDragOperation operation) OVERRIDE;
- virtual void DragSourceSystemDragEnded() OVERRIDE;
- virtual void DragTargetDragEnter(
- const DropData& drop_data,
- const gfx::Point& client_pt,
- const gfx::Point& screen_pt,
- blink::WebDragOperationsMask operations_allowed,
- int key_modifiers) OVERRIDE;
- virtual void DragTargetDragOver(
- const gfx::Point& client_pt,
- const gfx::Point& screen_pt,
- blink::WebDragOperationsMask operations_allowed,
- int key_modifiers) OVERRIDE;
- virtual void DragTargetDragLeave() OVERRIDE;
- virtual void DragTargetDrop(const gfx::Point& client_pt,
- const gfx::Point& screen_pt,
- int key_modifiers) OVERRIDE;
- virtual void EnableAutoResize(const gfx::Size& min_size,
- const gfx::Size& max_size) OVERRIDE;
- virtual void DisableAutoResize(const gfx::Size& new_size) OVERRIDE;
- virtual void EnablePreferredSizeMode() OVERRIDE;
- virtual void ExecuteMediaPlayerActionAtLocation(
+ const std::vector<base::FilePath>& files) override;
+ void DisableScrollbarsForThreshold(const gfx::Size& size) override;
+ void DragSourceEndedAt(int client_x,
+ int client_y,
+ int screen_x,
+ int screen_y,
+ blink::WebDragOperation operation) override;
+ void DragSourceSystemDragEnded() override;
+ void DragTargetDragEnter(const DropData& drop_data,
+ const gfx::Point& client_pt,
+ const gfx::Point& screen_pt,
+ blink::WebDragOperationsMask operations_allowed,
+ int key_modifiers) override;
+ void DragTargetDragOver(const gfx::Point& client_pt,
+ const gfx::Point& screen_pt,
+ blink::WebDragOperationsMask operations_allowed,
+ int key_modifiers) override;
+ void DragTargetDragLeave() override;
+ void DragTargetDrop(const gfx::Point& client_pt,
+ const gfx::Point& screen_pt,
+ int key_modifiers) override;
+ void EnableAutoResize(const gfx::Size& min_size,
+ const gfx::Size& max_size) override;
+ void DisableAutoResize(const gfx::Size& new_size) override;
+ void EnablePreferredSizeMode() override;
+ void ExecuteMediaPlayerActionAtLocation(
const gfx::Point& location,
- const blink::WebMediaPlayerAction& action) OVERRIDE;
- virtual void ExecutePluginActionAtLocation(
+ const blink::WebMediaPlayerAction& action) override;
+ void ExecutePluginActionAtLocation(
const gfx::Point& location,
- const blink::WebPluginAction& action) OVERRIDE;
- virtual void ExitFullscreen() OVERRIDE;
- virtual void FilesSelectedInChooser(
- const std::vector<ui::SelectedFileInfo>& files,
- FileChooserParams::Mode permissions) OVERRIDE;
- virtual RenderViewHostDelegate* GetDelegate() const OVERRIDE;
- virtual int GetEnabledBindings() const OVERRIDE;
- virtual SiteInstance* GetSiteInstance() const OVERRIDE;
- virtual bool IsRenderViewLive() const OVERRIDE;
- virtual void NotifyMoveOrResizeStarted() OVERRIDE;
- virtual void SetWebUIProperty(const std::string& name,
- const std::string& value) OVERRIDE;
- virtual void Zoom(PageZoom zoom) OVERRIDE;
- virtual void SyncRendererPrefs() OVERRIDE;
- virtual WebPreferences GetWebkitPreferences() OVERRIDE;
- virtual void UpdateWebkitPreferences(
- const WebPreferences& prefs) OVERRIDE;
- virtual void GetAudioOutputControllers(
- const GetAudioOutputControllersCallback& callback) const OVERRIDE;
- virtual void SetWebUIHandle(mojo::ScopedMessagePipeHandle handle) OVERRIDE;
- virtual void SelectWordAroundCaret() OVERRIDE;
+ const blink::WebPluginAction& action) override;
+ void ExitFullscreen() override;
+ void FilesSelectedInChooser(
+ const std::vector<content::FileChooserFileInfo>& files,
+ FileChooserParams::Mode permissions) override;
+ RenderViewHostDelegate* GetDelegate() const override;
+ int GetEnabledBindings() const override;
+ SiteInstanceImpl* GetSiteInstance() const override;
+ bool IsRenderViewLive() const override;
+ void NotifyMoveOrResizeStarted() override;
+ void SetWebUIProperty(const std::string& name,
+ const std::string& value) override;
+ void Zoom(PageZoom zoom) override;
+ void SyncRendererPrefs() override;
+ WebPreferences GetWebkitPreferences() override;
+ void UpdateWebkitPreferences(const WebPreferences& prefs) override;
+ void OnWebkitPreferencesChanged() override;
+ void GetAudioOutputControllers(
+ const GetAudioOutputControllersCallback& callback) const override;
+ void SelectWordAroundCaret() override;
#if defined(OS_ANDROID)
virtual void ActivateNearestFindResult(int request_id,
float x,
- float y) OVERRIDE;
- virtual void RequestFindMatchRects(int current_version) OVERRIDE;
+ float y) override;
+ virtual void RequestFindMatchRects(int current_version) override;
#endif
void set_delegate(RenderViewHostDelegate* d) {
@@ -245,54 +206,22 @@ class CONTENT_EXPORT RenderViewHostImpl
}
// Returns the content specific prefs for this RenderViewHost.
- WebPreferences GetWebkitPrefs(const GURL& url);
+ WebPreferences ComputeWebkitPrefs(const GURL& url);
+
+ // Tracks whether this RenderViewHost is in an active state (rather than
+ // pending swap out, pending deletion, or swapped out), according to its main
+ // frame RenderFrameHost.
+ bool is_active() const { return is_active_; }
+ void set_is_active(bool is_active) { is_active_ = is_active; }
+
+ // Tracks whether this RenderViewHost is swapped out, according to its main
+ // frame RenderFrameHost.
+ void set_is_swapped_out(bool is_swapped_out) {
+ is_swapped_out_ = is_swapped_out;
+ }
- // Sends the given navigation message. Use this rather than sending it
- // yourself since this does the internal bookkeeping described below. This
- // function takes ownership of the provided message pointer.
- //
- // If a cross-site request is in progress, we may be suspended while waiting
- // for the onbeforeunload handler, so this function might buffer the message
- // rather than sending it.
- // TODO(nasko): Remove this method once all callers are converted to use
- // RenderFrameHostImpl.
- void Navigate(const FrameMsg_Navigate_Params& message);
-
- // Load the specified URL, this is a shortcut for Navigate().
- // TODO(nasko): Remove this method once all callers are converted to use
- // RenderFrameHostImpl.
- void NavigateToURL(const GURL& url);
-
- // Returns whether navigation messages are currently suspended for this
- // RenderViewHost. Only true during a cross-site navigation, while waiting
- // for the onbeforeunload handler.
- bool are_navigations_suspended() const { return navigations_suspended_; }
-
- // Suspends (or unsuspends) any navigation messages from being sent from this
- // RenderViewHost. This is called when a pending RenderViewHost is created
- // for a cross-site navigation, because we must suspend any navigations until
- // we hear back from the old renderer's onbeforeunload handler. Note that it
- // is important that only one navigation event happen after calling this
- // method with |suspend| equal to true. If |suspend| is false and there is
- // a suspended_nav_message_, this will send the message. This function
- // should only be called to toggle the state; callers should check
- // are_navigations_suspended() first. If |suspend| is false, the time that the
- // user decided the navigation should proceed should be passed as
- // |proceed_time|.
- void SetNavigationsSuspended(bool suspend,
- const base::TimeTicks& proceed_time);
-
- // Clears any suspended navigation state after a cross-site navigation is
- // canceled or suspended. This is important if we later return to this
- // RenderViewHost.
- void CancelSuspendedNavigations();
-
- // Whether this RenderViewHost has been swapped out to be displayed by a
- // different process.
- bool IsSwappedOut() const { return rvh_state_ == STATE_SWAPPED_OUT; }
-
- // The current state of this RVH.
- RenderViewHostImplState rvh_state() const { return rvh_state_; }
+ // 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
@@ -300,36 +229,11 @@ class CONTENT_EXPORT RenderViewHostImpl
// longer on the stack when we attempt to swap it out.
void SuppressDialogsUntilSwapOut();
- // Called when either the SwapOut request has been acknowledged or has timed
- // out.
- void OnSwappedOut(bool timed_out);
-
- // Called when the RenderFrameHostManager has swapped in a new
- // RenderFrameHost. Should |this| RVH switch to the pending shutdown state,
- // |pending_delete_on_swap_out| will be executed upon reception of the
- // SwapOutACK, or when the unload timer times out.
- void WasSwappedOut(const base::Closure& pending_delete_on_swap_out);
-
- // Set |this| as pending shutdown. |on_swap_out| will be called
- // when the SwapOutACK is received, or when the unload timer times out.
- void SetPendingShutdown(const base::Closure& on_swap_out);
-
// Close the page ignoring whether it has unload events registers.
// This is called after the beforeunload and unload events have fired
// and the user has agreed to continue with closing the page.
void ClosePageIgnoringUnloadEvents();
- // Returns whether this RenderViewHost has an outstanding cross-site request.
- // Cleared when we hear the response and start to swap out the old
- // RenderViewHost, or if we hear a commit here without a network request.
- bool HasPendingCrossSiteRequest();
-
- // Sets whether this RenderViewHost has an outstanding cross-site request,
- // for which another renderer will need to run an onunload event handler.
- // This is called before the first navigation event for this RenderViewHost,
- // and cleared when we hear the response or commit.
- void SetHasPendingCrossSiteRequest(bool has_pending_request);
-
// Tells the renderer view to focus the first (last if reverse is true) node.
void SetInitialFocus(bool reverse);
@@ -357,19 +261,20 @@ class CONTENT_EXPORT RenderViewHostImpl
}
// RenderWidgetHost public overrides.
- virtual void Init() OVERRIDE;
- virtual void Shutdown() OVERRIDE;
- virtual bool IsRenderView() const OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
- virtual void GotFocus() OVERRIDE;
- virtual void LostCapture() OVERRIDE;
- virtual void LostMouseLock() OVERRIDE;
- virtual void ForwardMouseEvent(
- const blink::WebMouseEvent& mouse_event) OVERRIDE;
- virtual void OnPointerEventActivate() OVERRIDE;
- virtual void ForwardKeyboardEvent(
- const NativeWebKeyboardEvent& key_event) OVERRIDE;
- virtual gfx::Rect GetRootWindowResizerRect() const OVERRIDE;
+ void Init() override;
+ void Shutdown() override;
+ void WasHidden() override;
+ void WasShown(const ui::LatencyInfo& latency_info) override;
+ bool IsRenderView() const override;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void GotFocus() override;
+ void LostCapture() override;
+ void LostMouseLock() override;
+ void SetIsLoading(bool is_loading) override;
+ void ForwardMouseEvent(const blink::WebMouseEvent& mouse_event) override;
+ void OnPointerEventActivate() override;
+ void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event) override;
+ gfx::Rect GetRootWindowResizerRect() const override;
// Creates a new RenderView with the given route id.
void CreateNewWindow(
@@ -385,61 +290,16 @@ class CONTENT_EXPORT RenderViewHostImpl
// Creates a full screen RenderWidget.
void CreateNewFullscreenWidget(int route_id);
-#if defined(OS_MACOSX)
- // Select popup menu related methods (for external popup menus).
- void DidSelectPopupMenuItem(int selected_index);
- void DidCancelPopupMenu();
-#endif
-
#if defined(ENABLE_BROWSER_CDMS)
MediaWebContentsObserver* media_web_contents_observer() {
return media_web_contents_observer_.get();
}
#endif
-#if defined(OS_ANDROID)
- void DidSelectPopupMenuItems(const std::vector<int>& selected_indices);
- void DidCancelPopupMenu();
-#endif
-
int main_frame_routing_id() const {
return main_frame_routing_id_;
}
- // Set the opener to null in the renderer process.
- void DisownOpener();
-
- // Turn on accessibility testing. The given callback will be run
- // every time an accessibility notification is received from the
- // renderer process, and the accessibility tree it sent can be
- // retrieved using accessibility_tree_for_testing().
- void SetAccessibilityCallbackForTesting(
- const base::Callback<void(ui::AXEvent, int)>& callback);
-
- // Only valid if SetAccessibilityCallbackForTesting was called and
- // the callback was run at least once. Returns a snapshot of the
- // accessibility tree received from the renderer as of the last time
- // an accessibility notification was received.
- const ui::AXTree& ax_tree_for_testing() {
- CHECK(ax_tree_.get());
- return *ax_tree_.get();
- }
-
- // Set accessibility callbacks.
- void SetAccessibilityLayoutCompleteCallbackForTesting(
- const base::Closure& callback);
- void SetAccessibilityLoadCompleteCallbackForTesting(
- const base::Closure& callback);
- void SetAccessibilityOtherCallbackForTesting(
- const base::Closure& callback);
-
- bool is_waiting_for_beforeunload_ack() {
- return is_waiting_for_beforeunload_ack_;
- }
-
- // Whether the RVH is waiting for the unload ack from the renderer.
- bool IsWaitingForUnloadACK() const;
-
void OnTextSurroundingSelectionResponse(const base::string16& content,
size_t start_offset,
size_t end_offset);
@@ -470,15 +330,15 @@ class CONTENT_EXPORT RenderViewHostImpl
protected:
// RenderWidgetHost protected overrides.
- virtual void OnUserGesture() OVERRIDE;
- virtual void NotifyRendererUnresponsive() OVERRIDE;
- virtual void NotifyRendererResponsive() OVERRIDE;
- virtual void OnRenderAutoResized(const gfx::Size& size) OVERRIDE;
- virtual void RequestToLockMouse(bool user_gesture,
- bool last_unlocked_by_target) OVERRIDE;
- virtual bool IsFullscreen() const OVERRIDE;
- virtual void OnFocus() OVERRIDE;
- virtual void OnBlur() OVERRIDE;
+ void OnUserGesture() override;
+ void NotifyRendererUnresponsive() override;
+ void NotifyRendererResponsive() override;
+ void OnRenderAutoResized(const gfx::Size& size) override;
+ void RequestToLockMouse(bool user_gesture,
+ bool last_unlocked_by_target) override;
+ bool IsFullscreen() const override;
+ void OnFocus() override;
+ void OnBlur() override;
// IPC message handlers.
void OnShowView(int route_id,
@@ -491,13 +351,12 @@ class CONTENT_EXPORT RenderViewHostImpl
void OnRenderViewReady();
void OnRenderProcessGone(int status, int error_code);
void OnUpdateState(int32 page_id, const PageState& state);
- void OnUpdateTargetURL(int32 page_id, const GURL& url);
+ void OnUpdateTargetURL(const GURL& url);
void OnClose();
void OnRequestMove(const gfx::Rect& pos);
void OnDocumentAvailableInMainFrame(bool uses_temporary_zoom_level);
void OnToggleFullscreen(bool enter_fullscreen);
void OnDidContentsPreferredSizeChange(const gfx::Size& new_size);
- void OnDidChangeScrollOffset();
void OnPasteFromSelectionClipboard();
void OnRouteCloseEvent();
void OnRouteMessageEvent(const ViewMsg_PostMessage_Params& params);
@@ -510,22 +369,11 @@ class CONTENT_EXPORT RenderViewHostImpl
void OnTargetDropACK();
void OnTakeFocus(bool reverse);
void OnFocusedNodeChanged(bool is_editable_node);
- void OnUpdateInspectorSetting(const std::string& key,
- const std::string& value);
void OnClosePageACK();
- void OnAccessibilityEvents(
- const std::vector<AccessibilityHostMsg_EventParams>& params);
- void OnAccessibilityLocationChanges(
- const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
void OnDidZoomURL(double zoom_level, const GURL& url);
void OnRunFileChooser(const FileChooserParams& params);
void OnFocusedNodeTouched(bool editable);
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
- void OnShowPopup(const ViewHostMsg_ShowPopup_Params& params);
- void OnHidePopup();
-#endif
-
private:
// TODO(nasko): Temporarily friend RenderFrameHostImpl, so we don't duplicate
// utility functions and state needed in both classes, while we move frame
@@ -538,11 +386,7 @@ class CONTENT_EXPORT RenderViewHostImpl
// TODO(creis): Move to a private namespace on RenderFrameHostImpl.
// Delay to wait on closing the WebContents for a beforeunload/unload handler
// to fire.
- static const int kUnloadTimeoutMS;
-
- // Updates the state of this RenderViewHost and clears any waiting state
- // that is no longer relevant.
- void SetState(RenderViewHostImplState rvh_state);
+ static const int64 kUnloadTimeoutMS;
bool CanAccessFilesOfPageState(const PageState& state) const;
@@ -553,7 +397,7 @@ class CONTENT_EXPORT RenderViewHostImpl
RenderViewHostDelegate* delegate_;
// The SiteInstance associated with this RenderViewHost. All pages drawn
- // in this RenderViewHost are part of this SiteInstance. Should not change
+ // in this RenderViewHost are part of this SiteInstance. Cannot change
// over time.
scoped_refptr<SiteInstanceImpl> instance_;
@@ -565,23 +409,21 @@ class CONTENT_EXPORT RenderViewHostImpl
// See BindingsPolicy for details.
int enabled_bindings_;
- // Whether we should buffer outgoing Navigate messages rather than sending
- // them. This will be true when a RenderViewHost is created for a cross-site
- // request, until we hear back from the onbeforeunload handler of the old
- // RenderViewHost.
- // TODO(nasko): Move to RenderFrameHost, as this is per-frame state.
- bool navigations_suspended_;
+ // The most recent page ID we've heard from the renderer process. This is
+ // used as context when other session history related IPCs arrive.
+ // TODO(creis): Allocate this in WebContents/NavigationController instead.
+ int32 page_id_;
- // We only buffer the params for a suspended navigation while we have a
- // pending RVH for a WebContentsImpl. There will only ever be one suspended
- // navigation, because WebContentsImpl will destroy the pending RVH and create
- // a new one if a second navigation occurs.
- // TODO(nasko): Move to RenderFrameHost, as this is per-frame state.
- scoped_ptr<FrameMsg_Navigate_Params> suspended_nav_params_;
+ // Tracks whether this RenderViewHost is in an active state. False if the
+ // main frame is pending swap out, pending deletion, or swapped out, because
+ // it is not visible to the user in any of these cases.
+ bool is_active_;
- // The current state of this RVH.
- // TODO(nasko): Move to RenderFrameHost, as this is per-frame state.
- RenderViewHostImplState rvh_state_;
+ // 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://.
+ // See http://crbug.com/357747.
+ bool is_swapped_out_;
// Routing ID for the main frame's RenderFrameHost.
int main_frame_routing_id_;
@@ -592,28 +434,10 @@ class CONTENT_EXPORT RenderViewHostImpl
// This will hold the routing id of the RenderView that opened us.
int run_modal_opener_id_;
- // Set to true when there is a pending ViewMsg_ShouldClose message. This
- // ensures we don't spam the renderer with multiple beforeunload requests.
- // When either this value or IsWaitingForUnloadACK is true, the value of
- // unload_ack_is_for_cross_site_transition_ indicates whether this is for a
- // cross-site transition or a tab close attempt.
- // TODO(clamy): Remove this boolean and add one more state to the state
- // machine.
- // TODO(nasko): Move to RenderFrameHost, as this is per-frame state.
- bool is_waiting_for_beforeunload_ack_;
-
- // Valid only when is_waiting_for_beforeunload_ack_ or
- // IsWaitingForUnloadACK is true. This tells us if the unload request
- // is for closing the entire tab ( = false), or only this RenderViewHost in
- // the case of a cross-site transition ( = true).
- // TODO(nasko): Move to RenderFrameHost, as this is per-frame state.
- bool unload_ack_is_for_cross_site_transition_;
-
- // Accessibility callback for testing.
- base::Callback<void(ui::AXEvent, int)> accessibility_testing_callback_;
-
- // The most recently received accessibility tree - for testing only.
- scoped_ptr<ui::AXTree> ax_tree_;
+ // Set to true when waiting for a ViewHostMsg_ClosePageACK.
+ // TODO(creis): Move to RenderFrameHost and RenderWidgetHost.
+ // See http://crbug.com/418265.
+ bool is_waiting_for_close_ack_;
// True if the render view can be shut down suddenly.
bool sudden_termination_allowed_;
@@ -629,21 +453,17 @@ class CONTENT_EXPORT RenderViewHostImpl
scoped_ptr<MediaWebContentsObserver> media_web_contents_observer_;
#endif
- // Used to swap out or shutdown this RVH when the unload event is taking too
- // long to execute, depending on the number of active views in the
- // SiteInstance.
- // TODO(nasko): Move to RenderFrameHost, as this is per-frame state.
- scoped_ptr<TimeoutMonitor> unload_event_monitor_timeout_;
+ // True if the current focused element is editable.
+ bool is_focused_element_editable_;
- // Called after receiving the SwapOutACK when the RVH is in state pending
- // shutdown. Also called if the unload timer times out.
- // TODO(nasko): Move to RenderFrameHost, as this is per-frame state.
- base::Closure pending_shutdown_on_swap_out_;
+ // This is updated every time UpdateWebkitPreferences is called. That method
+ // is in turn called when any of the settings change that the WebPreferences
+ // values depend on.
+ scoped_ptr<WebPreferences> web_preferences_;
- base::WeakPtrFactory<RenderViewHostImpl> weak_factory_;
+ bool updating_web_preferences_;
- // True if the current focused element is editable.
- bool is_focused_element_editable_;
+ base::WeakPtrFactory<RenderViewHostImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderViewHostImpl);
};
diff --git a/chromium/content/browser/renderer_host/render_view_host_unittest.cc b/chromium/content/browser/renderer_host/render_view_host_unittest.cc
index 6889cd6f0bd..638442e5f60 100644
--- a/chromium/content/browser/renderer_host/render_view_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_view_host_unittest.cc
@@ -6,13 +6,15 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/render_message_filter.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
+#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/drop_data.h"
-#include "content/public/common/page_transition_types.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/test/test_content_browser_client.h"
@@ -20,15 +22,16 @@
#include "content/test/test_web_contents.h"
#include "net/base/filename_util.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
+#include "ui/base/page_transition_types.h"
namespace content {
class RenderViewHostTestBrowserClient : public TestContentBrowserClient {
public:
RenderViewHostTestBrowserClient() {}
- virtual ~RenderViewHostTestBrowserClient() {}
+ ~RenderViewHostTestBrowserClient() override {}
- virtual bool IsHandledURL(const GURL& url) OVERRIDE {
+ bool IsHandledURL(const GURL& url) override {
return url.scheme() == url::kFileScheme;
}
@@ -39,14 +42,14 @@ class RenderViewHostTestBrowserClient : public TestContentBrowserClient {
class RenderViewHostTest : public RenderViewHostImplTestHarness {
public:
RenderViewHostTest() : old_browser_client_(NULL) {}
- virtual ~RenderViewHostTest() {}
+ ~RenderViewHostTest() override {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
old_browser_client_ = SetBrowserClientForTesting(&test_browser_client_);
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
SetBrowserClientForTesting(old_browser_client_);
RenderViewHostImplTestHarness::TearDown();
}
@@ -61,7 +64,7 @@ class RenderViewHostTest : public RenderViewHostImplTestHarness {
// All about URLs reported by the renderer should get rewritten to about:blank.
// See RenderViewHost::OnNavigate for a discussion.
TEST_F(RenderViewHostTest, FilterAbout) {
- test_rvh()->SendNavigate(1, GURL("about:cache"));
+ contents()->GetMainFrame()->SendNavigate(1, GURL("about:cache"));
ASSERT_TRUE(controller().GetVisibleEntry());
EXPECT_EQ(GURL(url::kAboutBlankURL),
controller().GetVisibleEntry()->GetURL());
@@ -93,14 +96,14 @@ TEST_F(RenderViewHostTest, ResetUnloadOnReload) {
NavigateAndCommit(url1);
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_LINK, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
// Simulate the ClosePage call which is normally sent by the net::URLRequest.
rvh()->ClosePage();
- // Needed so that navigations are not suspended on the RVH.
- test_rvh()->SendBeforeUnloadACK(true);
+ // Needed so that navigations are not suspended on the RFH.
+ main_test_rfh()->SendBeforeUnloadACK(true);
contents()->Stop();
controller().Reload(false);
- EXPECT_FALSE(test_rvh()->IsWaitingForUnloadACK());
+ EXPECT_FALSE(main_test_rfh()->IsWaitingForUnloadACK());
}
// Ensure we do not grant bindings to a process shared with unprivileged views.
@@ -116,18 +119,18 @@ TEST_F(RenderViewHostTest, DontGrantBindingsToSharedProcess) {
class MockDraggingRenderViewHostDelegateView
: public RenderViewHostDelegateView {
public:
- virtual ~MockDraggingRenderViewHostDelegateView() {}
- virtual void StartDragging(const DropData& drop_data,
- blink::WebDragOperationsMask allowed_ops,
- const gfx::ImageSkia& image,
- const gfx::Vector2d& image_offset,
- const DragEventSourceInfo& event_info) OVERRIDE {
+ ~MockDraggingRenderViewHostDelegateView() override {}
+ void StartDragging(const DropData& drop_data,
+ blink::WebDragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const DragEventSourceInfo& event_info) override {
drag_url_ = drop_data.url;
html_base_url_ = drop_data.html_base_url;
}
- virtual void UpdateDragCursor(blink::WebDragOperation operation) OVERRIDE {}
- virtual void GotFocus() OVERRIDE {}
- virtual void TakeFocus(bool reverse) OVERRIDE {}
+ void UpdateDragCursor(blink::WebDragOperation operation) override {}
+ void GotFocus() override {}
+ void TakeFocus(bool reverse) override {}
virtual void UpdatePreferredSize(const gfx::Size& pref_size) {}
GURL drag_url() {
@@ -214,12 +217,12 @@ TEST_F(RenderViewHostTest, MessageWithBadHistoryItemFiles) {
EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file_path));
file_path = file_path.AppendASCII("foo");
EXPECT_EQ(0, process()->bad_msg_count());
- test_rvh()->TestOnUpdateStateWithFile(process()->GetID(), file_path);
+ test_rvh()->TestOnUpdateStateWithFile(-1, file_path);
EXPECT_EQ(1, process()->bad_msg_count());
ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
process()->GetID(), file_path);
- test_rvh()->TestOnUpdateStateWithFile(process()->GetID(), file_path);
+ test_rvh()->TestOnUpdateStateWithFile(-1, file_path);
EXPECT_EQ(1, process()->bad_msg_count());
}
@@ -229,20 +232,89 @@ TEST_F(RenderViewHostTest, NavigationWithBadHistoryItemFiles) {
EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file_path));
file_path = file_path.AppendASCII("bar");
EXPECT_EQ(0, process()->bad_msg_count());
- test_rvh()->SendNavigateWithFile(1, url, file_path);
+ contents()->GetMainFrame()->SendNavigateWithFile(1, url, file_path);
EXPECT_EQ(1, process()->bad_msg_count());
ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
process()->GetID(), file_path);
- test_rvh()->SendNavigateWithFile(process()->GetID(), url, file_path);
+ contents()->GetMainFrame()->SendNavigateWithFile(process()->GetID(), url,
+ file_path);
EXPECT_EQ(1, process()->bad_msg_count());
}
TEST_F(RenderViewHostTest, RoutingIdSane) {
RenderFrameHostImpl* root_rfh =
contents()->GetFrameTree()->root()->current_frame_host();
+ EXPECT_EQ(contents()->GetMainFrame(), root_rfh);
EXPECT_EQ(test_rvh()->GetProcess(), root_rfh->GetProcess());
EXPECT_NE(test_rvh()->GetRoutingID(), root_rfh->routing_id());
}
+class TestSaveImageFromDataURL : public RenderMessageFilter {
+ public:
+ TestSaveImageFromDataURL(
+ BrowserContext* context)
+ : RenderMessageFilter(
+ 0,
+ nullptr,
+ context,
+ context->GetRequestContext(),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr) {
+ Reset();
+ }
+
+ void Reset() {
+ url_string_ = std::string();
+ is_downloaded_ = false;
+ }
+
+ std::string& UrlString() const {
+ return url_string_;
+ }
+
+ bool IsDownloaded() const {
+ return is_downloaded_;
+ }
+
+ void Test(const std::string& url) {
+ OnMessageReceived(ViewHostMsg_SaveImageFromDataURL(0, url));
+ }
+
+ protected:
+ ~TestSaveImageFromDataURL() override {}
+ void DownloadUrl(int render_view_id,
+ const GURL& url,
+ const Referrer& referrer,
+ const base::string16& suggested_name,
+ const bool use_prompt) const override {
+ url_string_ = url.spec();
+ is_downloaded_ = true;
+ }
+
+ private:
+ mutable std::string url_string_;
+ mutable bool is_downloaded_;
+};
+
+TEST_F(RenderViewHostTest, SaveImageFromDataURL) {
+ scoped_refptr<TestSaveImageFromDataURL> tester(
+ new TestSaveImageFromDataURL(browser_context()));
+
+ tester->Reset();
+ tester->Test("http://non-data-url.com");
+ EXPECT_EQ(tester->UrlString(), "");
+ EXPECT_FALSE(tester->IsDownloaded());
+
+ const std::string data_url = "data:image/gif;base64,"
+ "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=";
+
+ tester->Reset();
+ tester->Test(data_url);
+ EXPECT_EQ(tester->UrlString(), data_url);
+ EXPECT_TRUE(tester->IsDownloaded());
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_helper.cc b/chromium/content/browser/renderer_host/render_widget_helper.cc
index 169347f3288..9261de92d62 100644
--- a/chromium/content/browser/renderer_host/render_widget_helper.cc
+++ b/chromium/content/browser/renderer_host/render_widget_helper.cc
@@ -10,11 +10,12 @@
#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
+#include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/loader/resource_dispatcher_host_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/dom_storage/session_storage_namespace_impl.h"
#include "content/common/view_messages.h"
namespace content {
@@ -34,53 +35,8 @@ void AddWidgetHelper(int render_process_id,
} // namespace
-// A helper used with DidReceiveBackingStoreMsg that we hold a pointer to in
-// pending_paints_.
-class RenderWidgetHelper::BackingStoreMsgProxy {
- public:
- BackingStoreMsgProxy(RenderWidgetHelper* h, const IPC::Message& m);
- ~BackingStoreMsgProxy();
- void Run();
- void Cancel() { cancelled_ = true; }
-
- const IPC::Message& message() const { return message_; }
-
- private:
- scoped_refptr<RenderWidgetHelper> helper_;
- IPC::Message message_;
- bool cancelled_; // If true, then the message will not be dispatched.
-
- DISALLOW_COPY_AND_ASSIGN(BackingStoreMsgProxy);
-};
-
-RenderWidgetHelper::BackingStoreMsgProxy::BackingStoreMsgProxy(
- RenderWidgetHelper* h, const IPC::Message& m)
- : helper_(h),
- message_(m),
- cancelled_(false) {
-}
-
-RenderWidgetHelper::BackingStoreMsgProxy::~BackingStoreMsgProxy() {
- // If the paint message was never dispatched, then we need to let the
- // helper know that we are going away.
- if (!cancelled_ && helper_.get())
- helper_->OnDiscardBackingStoreMsg(this);
-}
-
-void RenderWidgetHelper::BackingStoreMsgProxy::Run() {
- if (!cancelled_) {
- helper_->OnDispatchBackingStoreMsg(this);
- helper_ = NULL;
- }
-}
-
RenderWidgetHelper::RenderWidgetHelper()
: render_process_id_(-1),
-#if defined(OS_WIN)
- event_(CreateEvent(NULL, FALSE /* auto-reset */, FALSE, NULL)),
-#elif defined(OS_POSIX)
- event_(false /* auto-reset */, false),
-#endif
resource_dispatcher_host_(NULL) {
}
@@ -93,10 +49,6 @@ RenderWidgetHelper::~RenderWidgetHelper() {
if (it != widget_map.end() && it->second == this)
widget_map.erase(it);
- // The elements of pending_paints_ each hold an owning reference back to this
- // object, so we should not be destroyed unless pending_paints_ is empty!
- DCHECK(pending_paints_.empty());
-
#if defined(OS_POSIX) && !defined(OS_ANDROID)
ClearAllocatedDIBs();
#endif
@@ -136,49 +88,14 @@ void RenderWidgetHelper::ResumeDeferredNavigation(
request_id));
}
-bool RenderWidgetHelper::WaitForBackingStoreMsg(
- int render_widget_id, const base::TimeDelta& max_delay, IPC::Message* msg) {
- base::TimeTicks time_start = base::TimeTicks::Now();
-
- for (;;) {
- BackingStoreMsgProxy* proxy = NULL;
- {
- base::AutoLock lock(pending_paints_lock_);
-
- BackingStoreMsgProxyMap::iterator it =
- pending_paints_.find(render_widget_id);
- if (it != pending_paints_.end()) {
- BackingStoreMsgProxyQueue &queue = it->second;
- DCHECK(!queue.empty());
- proxy = queue.front();
-
- // Flag the proxy as cancelled so that when it is run as a task it will
- // do nothing.
- proxy->Cancel();
-
- queue.pop_front();
- if (queue.empty())
- pending_paints_.erase(it);
- }
- }
-
- if (proxy) {
- *msg = proxy->message();
- DCHECK(msg->routing_id() == render_widget_id);
- return true;
- }
-
- // Calculate the maximum amount of time that we are willing to sleep.
- base::TimeDelta max_sleep_time =
- max_delay - (base::TimeTicks::Now() - time_start);
- if (max_sleep_time <= base::TimeDelta::FromMilliseconds(0))
- break;
-
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- event_.TimedWait(max_sleep_time);
- }
-
- return false;
+void RenderWidgetHelper::ResumeResponseDeferredAtStart(
+ const GlobalRequestID& request_id) {
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&RenderWidgetHelper::OnResumeResponseDeferredAtStart,
+ this,
+ request_id));
}
void RenderWidgetHelper::ResumeRequestsForView(int route_id) {
@@ -192,59 +109,16 @@ void RenderWidgetHelper::ResumeRequestsForView(int route_id) {
}
}
-void RenderWidgetHelper::DidReceiveBackingStoreMsg(const IPC::Message& msg) {
- int render_widget_id = msg.routing_id();
-
- BackingStoreMsgProxy* proxy = new BackingStoreMsgProxy(this, msg);
- {
- base::AutoLock lock(pending_paints_lock_);
-
- pending_paints_[render_widget_id].push_back(proxy);
- }
-
- // Notify anyone waiting on the UI thread that there is a new entry in the
- // proxy map. If they don't find the entry they are looking for, then they
- // will just continue waiting.
- event_.Signal();
-
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&BackingStoreMsgProxy::Run, base::Owned(proxy)));
-}
-
-void RenderWidgetHelper::OnDiscardBackingStoreMsg(BackingStoreMsgProxy* proxy) {
- const IPC::Message& msg = proxy->message();
-
- // Remove the proxy from the map now that we are going to handle it normally.
- {
- base::AutoLock lock(pending_paints_lock_);
-
- BackingStoreMsgProxyMap::iterator it =
- pending_paints_.find(msg.routing_id());
- DCHECK(it != pending_paints_.end());
- BackingStoreMsgProxyQueue &queue = it->second;
- DCHECK(queue.front() == proxy);
-
- queue.pop_front();
- if (queue.empty())
- pending_paints_.erase(it);
- }
-}
-
-void RenderWidgetHelper::OnDispatchBackingStoreMsg(
- BackingStoreMsgProxy* proxy) {
- OnDiscardBackingStoreMsg(proxy);
-
- // It is reasonable for the host to no longer exist.
- RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_);
- if (host)
- host->OnMessageReceived(proxy->message());
-}
-
void RenderWidgetHelper::OnResumeDeferredNavigation(
const GlobalRequestID& request_id) {
resource_dispatcher_host_->ResumeDeferredNavigation(request_id);
}
+void RenderWidgetHelper::OnResumeResponseDeferredAtStart(
+ const GlobalRequestID& request_id) {
+ resource_dispatcher_host_->ResumeResponseDeferredAtStart(request_id);
+}
+
void RenderWidgetHelper::CreateNewWindow(
const ViewHostMsg_CreateWindow_Params& params,
bool no_javascript_access,
diff --git a/chromium/content/browser/renderer_host/render_widget_helper.h b/chromium/content/browser/renderer_host/render_widget_helper.h
index af5c6612b5e..98b3ca6cdb8 100644
--- a/chromium/content/browser/renderer_host/render_widget_helper.h
+++ b/chromium/content/browser/renderer_host/render_widget_helper.h
@@ -5,15 +5,12 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HELPER_H_
#define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HELPER_H_
-#include <deque>
#include <map>
#include "base/atomic_sequence_num.h"
#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
#include "base/process/process.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/global_request_id.h"
@@ -30,7 +27,6 @@ namespace base {
class TimeDelta;
}
-struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
struct ViewHostMsg_CreateWindow_Params;
struct ViewMsg_SwapOut_Params;
@@ -45,38 +41,6 @@ class SessionStorageNamespace;
// the RenderWidgetHost lives.
//
//
-// OPTIMIZED RESIZE
-//
-// RenderWidgetHelper is used to implement optimized resize. When the
-// RenderWidgetHost is resized, it sends a Resize message to its RenderWidget
-// counterpart in the renderer process. In response to the Resize message,
-// the RenderWidget generates a new BackingStore and sends an UpdateRect
-// message (or BuffersSwapped via the GPU process in the case of accelerated
-// compositing), and it sets the IS_RESIZE_ACK flag in the UpdateRect message
-// to true. In the accelerated case, an UpdateRect is still sent from the
-// renderer to the browser with acks and plugin moves even though the GPU
-// BackingStore was sent earlier in the BuffersSwapped message. "BackingStore
-// message" is used throughout this code and documentation to mean either a
-// software UpdateRect or GPU BuffersSwapped message.
-//
-// Back in the browser process, when the RenderProcessHost's MessageFilter
-// sees an UpdateRect message (or when the GpuProcessHost sees a
-// BuffersSwapped message), it directs it to the RenderWidgetHelper by calling
-// the DidReceiveBackingStoreMsg method. That method stores the data for the
-// message in a map, where it can be directly accessed by the RenderWidgetHost
-// on the UI thread during a call to RenderWidgetHost's GetBackingStore
-// method.
-//
-// When the RenderWidgetHost's GetBackingStore method is called, it first
-// checks to see if it is waiting for a resize ack. If it is, then it calls
-// the RenderWidgetHelper's WaitForBackingStoreMsg to check if there is
-// already a resulting BackingStore message (or to wait a short amount of time
-// for one to arrive). The main goal of this mechanism is to short-cut the
-// usual way in which IPC messages are proxied over to the UI thread via
-// InvokeLater. This approach is necessary since window resize is followed up
-// immediately by a request to repaint the window.
-//
-//
// OPTIMIZED TAB SWITCHING
//
// When a RenderWidgetHost is in a background tab, it is flagged as hidden.
@@ -104,6 +68,7 @@ class SessionStorageNamespace;
// allocation and maintains the set of allocated transport DIBs which the
// renderers can refer to.
//
+
class RenderWidgetHelper
: public base::RefCountedThreadSafe<RenderWidgetHelper,
BrowserThread::DeleteOnIOThread> {
@@ -125,22 +90,18 @@ class RenderWidgetHelper
// UI THREAD ONLY -----------------------------------------------------------
- // These three functions provide the backend implementation of the
+ // These four functions provide the backend implementation of the
// corresponding functions in RenderProcessHost. See those declarations
// for documentation.
void ResumeDeferredNavigation(const GlobalRequestID& request_id);
- bool WaitForBackingStoreMsg(int render_widget_id,
- const base::TimeDelta& max_delay,
- IPC::Message* msg);
+ void ResumeResponseDeferredAtStart(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 -----------------------------------------------------------
- // Called on the IO thread when a BackingStore message is received.
- void DidReceiveBackingStoreMsg(const IPC::Message& msg);
-
void CreateNewWindow(
const ViewHostMsg_CreateWindow_Params& params,
bool no_javascript_access,
@@ -169,34 +130,13 @@ class RenderWidgetHelper
void FreeTransportDIB(TransportDIB::Id dib_id);
#endif
-#if defined(OS_MACOSX)
- static void OnNativeSurfaceBuffersSwappedOnIOThread(
- GpuProcessHost* gpu_process_host,
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params);
-#endif
-
private:
- // A class used to proxy a paint message. PaintMsgProxy objects are created
- // on the IO thread and destroyed on the UI thread.
- class BackingStoreMsgProxy;
- friend class BackingStoreMsgProxy;
friend class base::RefCountedThreadSafe<RenderWidgetHelper>;
friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
friend class base::DeleteHelper<RenderWidgetHelper>;
- typedef std::deque<BackingStoreMsgProxy*> BackingStoreMsgProxyQueue;
- // Map from render_widget_id to a queue of live PaintMsgProxy instances.
- typedef base::hash_map<int, BackingStoreMsgProxyQueue >
- BackingStoreMsgProxyMap;
-
~RenderWidgetHelper();
- // Called on the UI thread to discard a paint message.
- void OnDiscardBackingStoreMsg(BackingStoreMsgProxy* proxy);
-
- // Called on the UI thread to dispatch a paint message if necessary.
- void OnDispatchBackingStoreMsg(BackingStoreMsgProxy* proxy);
-
// Called on the UI thread to finish creating a window.
void OnCreateWindowOnUI(
const ViewHostMsg_CreateWindow_Params& params,
@@ -219,6 +159,10 @@ class RenderWidgetHelper
// stack without transferring it to a new renderer process.
void OnResumeDeferredNavigation(const GlobalRequestID& request_id);
+ // Called on the IO thread to resume a navigation paused immediately after
+ // receiving response headers.
+ void OnResumeResponseDeferredAtStart(const GlobalRequestID& request_id);
+
#if defined(OS_POSIX)
// Called on destruction to release all allocated transport DIBs
void ClearAllocatedDIBs();
@@ -229,18 +173,8 @@ class RenderWidgetHelper
std::map<TransportDIB::Id, int> allocated_dibs_;
#endif
- // A map of live paint messages. Must hold pending_paints_lock_ to access.
- // The BackingStoreMsgProxy objects are not owned by this map. (See
- // BackingStoreMsgProxy for details about how the lifetime of instances are
- // managed.)
- BackingStoreMsgProxyMap pending_paints_;
- base::Lock pending_paints_lock_;
-
int render_process_id_;
- // Event used to implement WaitForBackingStoreMsg.
- base::WaitableEvent event_;
-
// The next routing id to use.
base::AtomicSequenceNumber next_routing_id_;
diff --git a/chromium/content/browser/renderer_host/render_widget_helper_mac.mm b/chromium/content/browser/renderer_host/render_widget_helper_mac.mm
deleted file mode 100644
index 824b2265d70..00000000000
--- a/chromium/content/browser/renderer_host/render_widget_helper_mac.mm
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/renderer_host/render_widget_helper.h"
-
-#import <Cocoa/Cocoa.h>
-#include <IOSurface/IOSurfaceAPI.h>
-
-#include "base/bind.h"
-#include "content/browser/compositor/browser_compositor_view_mac.h"
-#include "content/browser/gpu/gpu_process_host.h"
-#include "content/browser/gpu/gpu_surface_tracker.h"
-#include "content/common/gpu/gpu_messages.h"
-
-namespace {
-
-void OnNativeSurfaceBuffersSwappedOnUIThread(
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- gfx::AcceleratedWidget native_widget =
- content::GpuSurfaceTracker::Get()->AcquireNativeWidget(params.surface_id);
- IOSurfaceID io_surface_handle = static_cast<IOSurfaceID>(
- params.surface_handle);
- [native_widget gotAcceleratedIOSurfaceFrame:io_surface_handle
- withOutputSurfaceID:params.surface_id
- withPixelSize:params.size
- withScaleFactor:params.scale_factor];
-}
-
-} // namespace
-
-namespace content {
-
-void RenderWidgetHelper::OnNativeSurfaceBuffersSwappedOnIOThread(
- GpuProcessHost* gpu_process_host,
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- // Immediately acknowledge this frame on the IO thread instead of the UI
- // thread. The UI thread will wait on the GPU process. If the UI thread
- // were to be responsible for acking swaps, then there would be a cycle
- // and a potential deadlock.
- // TODO(ccameron): This immediate ack circumvents GPU back-pressure that
- // is necessary to throttle renderers. Fix that.
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.sync_point = 0;
- ack_params.renderer_id = 0;
- gpu_process_host->Send(new AcceleratedSurfaceMsg_BufferPresented(
- params.route_id, ack_params));
-
- // Open the IOSurface handle before returning, to ensure that it is not
- // closed as soon as the frame is acknowledged.
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface(IOSurfaceLookup(
- static_cast<uint32>(params.surface_handle)));
-
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(&OnNativeSurfaceBuffersSwappedOnUIThread, io_surface, params));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_host_browsertest.cc b/chromium/content/browser/renderer_host/render_widget_host_browsertest.cc
index 483778167b2..e85a4856824 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -19,7 +19,7 @@ class RenderWidgetHostBrowserTest : public ContentBrowserTest {
public:
RenderWidgetHostBrowserTest() {}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir_));
}
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 23687d0f24d..a3a474ffab1 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_delegate.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/basictypes.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
namespace content {
@@ -27,9 +28,19 @@ bool RenderWidgetHostDelegate::HandleGestureEvent(
return false;
}
+BrowserAccessibilityManager*
+ RenderWidgetHostDelegate::GetRootBrowserAccessibilityManager() {
+ return NULL;
+}
+
+BrowserAccessibilityManager*
+ RenderWidgetHostDelegate::GetOrCreateRootBrowserAccessibilityManager() {
+ return NULL;
+}
+
#if defined(OS_WIN)
gfx::NativeViewAccessible
-RenderWidgetHostDelegate::GetParentNativeViewAccessible() {
+ RenderWidgetHostDelegate::GetParentNativeViewAccessible() {
return NULL;
}
#endif
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 91ce94316f9..669dc255ba4 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_delegate.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_RENDER_WIDGET_HOST_DELEGATE_H_
#define CONTENT_BROWSER_RENDER_WIDGET_HOST_DELEGATE_H_
+#include "base/basictypes.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "ui/gfx/native_widget_types.h"
@@ -16,6 +17,7 @@ class WebGestureEvent;
namespace content {
+class BrowserAccessibilityManager;
class RenderWidgetHostImpl;
struct NativeWebKeyboardEvent;
@@ -29,6 +31,9 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
// The RenderWidgetHost is going to be deleted.
virtual void RenderWidgetDeleted(RenderWidgetHostImpl* render_widget_host) {}
+ // The RenderWidgetHost got the focus.
+ virtual void RenderWidgetGotFocus(RenderWidgetHostImpl* render_widget_host) {}
+
// Callback to give the browser a chance to handle the specified keyboard
// event before sending it to the renderer.
// Returns true if the |event| was handled. Otherwise, if the |event| would
@@ -59,11 +64,15 @@ class CONTENT_EXPORT RenderWidgetHostDelegate {
// Notifies that screen rects were sent to renderer process.
virtual void DidSendScreenRects(RenderWidgetHostImpl* rwh) {}
- // Notifies that RenderWidgetHost will toggle touch emulation.
- virtual void OnTouchEmulationEnabled(bool enabled) {}
+ // Get the root BrowserAccessibilityManager for this frame tree.
+ virtual BrowserAccessibilityManager* GetRootBrowserAccessibilityManager();
+
+ // Get the root BrowserAccessibilityManager for this frame tree,
+ // or create it if it doesn't exist.
+ virtual BrowserAccessibilityManager*
+ GetOrCreateRootBrowserAccessibilityManager();
#if defined(OS_WIN)
- // Returns the widget's parent's NativeViewAccessible.
virtual gfx::NativeViewAccessible GetParentNativeViewAccessible();
#endif
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 eb03476699a..9a1d709a2ef 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.cc
@@ -44,7 +44,7 @@
#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_view_base.h"
-#include "content/common/accessibility_messages.h"
+#include "content/browser/renderer_host/render_widget_resize_helper.h"
#include "content/common/content_constants_internal.h"
#include "content/common/cursors/webcursor.h"
#include "content/common/gpu/gpu_messages.h"
@@ -59,16 +59,16 @@
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
+#include "content/public/common/web_preferences.h"
#include "skia/ext/image_operations.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/size_conversions.h"
#include "ui/gfx/skbitmap_operations.h"
-#include "ui/gfx/vector2d_conversions.h"
#include "ui/snapshot/snapshot.h"
-#include "webkit/common/webpreferences.h"
#if defined(OS_WIN)
#include "content/common/plugin_constants_win.h"
@@ -89,11 +89,9 @@ namespace {
bool g_check_for_pending_resize_ack = true;
-// How long to (synchronously) wait for the renderer to respond with a
-// PaintRect message, when our backing-store is invalid, before giving up and
-// returning a null or incorrectly sized backing-store from GetBackingStore.
-// This timeout impacts the "choppiness" of our window resize perf.
-const int kPaintMsgTimeoutMS = 50;
+const size_t kBrowserCompositeLatencyHistorySize = 60;
+const double kBrowserCompositeLatencyEstimationPercentile = 90.0;
+const double kBrowserCompositeLatencyEstimationSlack = 1.1;
typedef std::pair<int32, int32> RenderWidgetHostID;
typedef base::hash_map<RenderWidgetHostID, RenderWidgetHostImpl*>
@@ -108,8 +106,8 @@ int GetInputRouterViewFlagsFromCompositorFrameMetadata(
if (metadata.min_page_scale_factor == metadata.max_page_scale_factor)
view_flags |= InputRouter::FIXED_PAGE_SCALE;
- const float window_width_dip =
- std::ceil(metadata.page_scale_factor * metadata.viewport_size.width());
+ const float window_width_dip = std::ceil(
+ metadata.page_scale_factor * metadata.scrollable_viewport_size.width());
const float content_width_css = metadata.root_layer_size.width();
if (content_width_css <= window_width_dip)
view_flags |= InputRouter::MOBILE_VIEWPORT;
@@ -126,8 +124,7 @@ class RenderWidgetHostIteratorImpl : public RenderWidgetHostIterator {
: current_index_(0) {
}
- virtual ~RenderWidgetHostIteratorImpl() {
- }
+ ~RenderWidgetHostIteratorImpl() override {}
void Add(RenderWidgetHost* host) {
hosts_.push_back(RenderWidgetHostID(host->GetProcess()->GetID(),
@@ -135,7 +132,7 @@ class RenderWidgetHostIteratorImpl : public RenderWidgetHostIterator {
}
// RenderWidgetHostIterator:
- virtual RenderWidgetHost* GetNextHost() OVERRIDE {
+ RenderWidgetHost* GetNextHost() override {
RenderWidgetHost* host = NULL;
while (current_index_ < hosts_.size() && !host) {
RenderWidgetHostID id = hosts_[current_index_];
@@ -174,10 +171,9 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
repaint_ack_pending_(false),
resize_ack_pending_(false),
screen_info_out_of_date_(false),
- overdraw_bottom_height_(0.f),
+ top_controls_layout_height_(0.f),
should_auto_resize_(false),
waiting_for_screen_rects_ack_(false),
- accessibility_mode_(AccessibilityModeOff),
needs_repainting_on_restore_(false),
is_unresponsive_(false),
in_flight_event_count_(0),
@@ -191,8 +187,10 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
pending_mouse_lock_request_(false),
allow_privileged_mouse_lock_(false),
has_touch_handler_(false),
- weak_factory_(this),
- last_input_number_(static_cast<int64>(GetProcess()->GetID()) << 32) {
+ last_input_number_(static_cast<int64>(GetProcess()->GetID()) << 32),
+ next_browser_snapshot_id_(1),
+ browser_composite_latency_history_(kBrowserCompositeLatencyHistorySize),
+ weak_factory_(this) {
CHECK(delegate_);
if (routing_id_ == MSG_ROUTING_NONE) {
routing_id_ = process_->GetNextRoutingID();
@@ -224,9 +222,6 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
if (!hidden)
process_->WidgetRestored();
- accessibility_mode_ =
- BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode();
-
input_router_.reset(new InputRouterImpl(
process_, this, this, routing_id_, GetInputRouterConfigForPlatform()));
@@ -235,7 +230,7 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
IsRenderView() ? RenderViewHost::From(this) : NULL);
if (BrowserPluginGuest::IsGuest(rvh) ||
- !CommandLine::ForCurrentProcess()->HasSwitch(
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableHangMonitor)) {
hang_monitor_timeout_.reset(new TimeoutMonitor(
base::Bind(&RenderWidgetHostImpl::RendererIsUnresponsive,
@@ -244,6 +239,8 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
}
RenderWidgetHostImpl::~RenderWidgetHostImpl() {
+ if (view_weak_)
+ view_weak_->RenderWidgetHostGone();
SetView(NULL);
GpuSurfaceTracker::Get()->RemoveSurface(surface_id_);
@@ -291,8 +288,7 @@ scoped_ptr<RenderWidgetHostIterator> RenderWidgetHost::GetRenderWidgetHosts() {
// Add only active RenderViewHosts.
RenderViewHost* rvh = RenderViewHost::From(widget);
- if (RenderViewHostImpl::IsRVHStateActive(
- static_cast<RenderViewHostImpl*>(rvh)->rvh_state()))
+ if (static_cast<RenderViewHostImpl*>(rvh)->is_active())
hosts->Add(widget);
}
@@ -319,6 +315,10 @@ RenderWidgetHostImpl* RenderWidgetHostImpl::From(RenderWidgetHost* rwh) {
}
void RenderWidgetHostImpl::SetView(RenderWidgetHostViewBase* view) {
+ if (view)
+ view_weak_ = view->GetWeakPtr();
+ else
+ view_weak_.reset();
view_ = view;
GpuSurfaceTracker::Get()->SetSurfaceHandle(
@@ -442,6 +442,8 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostImpl, msg)
IPC_MESSAGE_HANDLER(InputHostMsg_QueueSyntheticGesture,
OnQueueSyntheticGesture)
+ IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
+ OnImeCancelComposition)
IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnRenderViewReady)
IPC_MESSAGE_HANDLER(ViewHostMsg_RenderProcessGone, OnRenderProcessGone)
IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnClose)
@@ -456,12 +458,8 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnFocus)
IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnBlur)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor)
- IPC_MESSAGE_HANDLER(ViewHostMsg_SetTouchEventEmulationEnabled,
- OnSetTouchEventEmulationEnabled)
- IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
- OnTextInputStateChanged)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition,
- OnImeCancelComposition)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
+ OnTextInputTypeChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowDisambiguationPopup,
@@ -475,12 +473,8 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_WindowlessPluginDummyWindowDestroyed,
OnWindowlessPluginDummyWindowDestroyed)
#endif
-#if defined(OS_MACOSX)
- IPC_MESSAGE_HANDLER(ViewHostMsg_CompositorSurfaceBuffersSwapped,
- OnCompositorSurfaceBuffersSwapped)
-#endif
-#if defined(OS_MACOSX) || defined(USE_AURA)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged,
+#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
+ IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
OnImeCompositionRangeChanged)
#endif
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -502,6 +496,13 @@ bool RenderWidgetHostImpl::Send(IPC::Message* msg) {
return process_->Send(msg);
}
+void RenderWidgetHostImpl::SetIsLoading(bool is_loading) {
+ is_loading_ = is_loading;
+ if (!view_)
+ return;
+ view_->SetIsLoading(is_loading);
+}
+
void RenderWidgetHostImpl::WasHidden() {
if (is_hidden_)
return;
@@ -525,7 +526,7 @@ void RenderWidgetHostImpl::WasHidden() {
Details<bool>(&is_visible));
}
-void RenderWidgetHostImpl::WasShown() {
+void RenderWidgetHostImpl::WasShown(const ui::LatencyInfo& latency_info) {
if (!is_hidden_)
return;
is_hidden_ = false;
@@ -535,7 +536,7 @@ void RenderWidgetHostImpl::WasShown() {
// Always repaint on restore.
bool needs_repainting = true;
needs_repainting_on_restore_ = false;
- Send(new ViewMsg_WasShown(routing_id_, needs_repainting));
+ Send(new ViewMsg_WasShown(routing_id_, needs_repainting, latency_info));
process_->WidgetRestored();
@@ -577,8 +578,10 @@ void RenderWidgetHostImpl::WasResized() {
physical_backing_size_ = view_->GetPhysicalBackingSize();
bool was_fullscreen = is_fullscreen_;
is_fullscreen_ = IsFullscreen();
- float old_overdraw_bottom_height = overdraw_bottom_height_;
- overdraw_bottom_height_ = view_->GetOverdrawBottomHeight();
+ float old_top_controls_layout_height =
+ top_controls_layout_height_;
+ top_controls_layout_height_ =
+ view_->GetTopControlsLayoutHeight();
gfx::Size old_visible_viewport_size = visible_viewport_size_;
visible_viewport_size_ = view_->GetVisibleViewportSize();
@@ -587,7 +590,8 @@ void RenderWidgetHostImpl::WasResized() {
screen_info_out_of_date_ ||
old_physical_backing_size != physical_backing_size_ ||
was_fullscreen != is_fullscreen_ ||
- old_overdraw_bottom_height != overdraw_bottom_height_ ||
+ old_top_controls_layout_height !=
+ top_controls_layout_height_ ||
old_visible_viewport_size != visible_viewport_size_;
if (!size_changed && !side_payload_changed)
@@ -607,7 +611,7 @@ void RenderWidgetHostImpl::WasResized() {
params.screen_info = *screen_info_;
params.new_size = new_size;
params.physical_backing_size = physical_backing_size_;
- params.overdraw_bottom_height = overdraw_bottom_height_;
+ params.top_controls_layout_height = top_controls_layout_height_;
params.visible_viewport_size = visible_viewport_size_;
params.resizer_rect = GetRootWindowResizerRect();
params.is_fullscreen = is_fullscreen_;
@@ -624,6 +628,8 @@ void RenderWidgetHostImpl::ResizeRectChanged(const gfx::Rect& new_rect) {
void RenderWidgetHostImpl::GotFocus() {
Focus();
+ if (delegate_)
+ delegate_->RenderWidgetGotFocus(this);
}
void RenderWidgetHostImpl::Focus() {
@@ -666,25 +672,18 @@ void RenderWidgetHostImpl::ViewDestroyed() {
SetView(NULL);
}
-void RenderWidgetHostImpl::SetIsLoading(bool is_loading) {
- is_loading_ = is_loading;
- if (!view_)
- return;
- view_->SetIsLoading(is_loading);
-}
-
void RenderWidgetHostImpl::CopyFromBackingStore(
const gfx::Rect& src_subrect,
const gfx::Size& accelerated_dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config& bitmap_config) {
+ const SkColorType color_type) {
if (view_) {
TRACE_EVENT0("browser",
"RenderWidgetHostImpl::CopyFromBackingStore::FromCompositingSurface");
gfx::Rect accelerated_copy_rect = src_subrect.IsEmpty() ?
gfx::Rect(view_->GetViewBounds().size()) : src_subrect;
view_->CopyFromCompositingSurface(
- accelerated_copy_rect, accelerated_dst_size, callback, bitmap_config);
+ accelerated_copy_rect, accelerated_dst_size, callback, color_type);
return;
}
@@ -709,6 +708,7 @@ void RenderWidgetHostImpl::UnlockBackingStore() {
}
#endif
+#if defined(OS_MACOSX)
void RenderWidgetHostImpl::PauseForPendingResizeOrRepaints() {
TRACE_EVENT0("browser",
"RenderWidgetHostImpl::PauseForPendingResizeOrRepaints");
@@ -734,6 +734,11 @@ bool RenderWidgetHostImpl::CanPauseForPendingResizeOrRepaints() {
void RenderWidgetHostImpl::WaitForSurface() {
TRACE_EVENT0("browser", "RenderWidgetHostImpl::WaitForSurface");
+ // How long to (synchronously) wait for the renderer to respond with a
+ // new frame when our current frame doesn't exist or is the wrong size.
+ // This timeout impacts the "choppiness" of our window resize.
+ const int kPaintMsgTimeoutMS = 50;
+
if (!view_)
return;
@@ -791,8 +796,7 @@ void RenderWidgetHostImpl::WaitForSurface() {
// on a response, block for a little while to see if we can't get a response
// before returning the old (incorrectly sized) backing store.
IPC::Message msg;
- if (process_->WaitForBackingStoreMsg(routing_id_, max_delay, &msg)) {
- OnMessageReceived(msg);
+ if (RenderWidgetResizeHelper::Get()->WaitForSingleTaskToRun(max_delay)) {
// For auto-resized views, current_size_ determines the view_size and it
// may have changed during the handling of an UpdateRect message.
@@ -815,6 +819,7 @@ void RenderWidgetHostImpl::WaitForSurface() {
max_delay = end_time - TimeTicks::Now();
} while (max_delay > TimeDelta::FromSeconds(0));
}
+#endif
bool RenderWidgetHostImpl::ScheduleComposite() {
if (is_hidden_ || current_size_.IsEmpty() || repaint_ack_pending_ ||
@@ -848,22 +853,6 @@ void RenderWidgetHostImpl::StopHangMonitorTimeout() {
RendererIsResponsive();
}
-void RenderWidgetHostImpl::EnableFullAccessibilityMode() {
- AddAccessibilityMode(AccessibilityModeComplete);
-}
-
-bool RenderWidgetHostImpl::IsFullAccessibilityModeForTesting() {
- return accessibility_mode() == AccessibilityModeComplete;
-}
-
-void RenderWidgetHostImpl::EnableTreeOnlyAccessibilityMode() {
- AddAccessibilityMode(AccessibilityModeTreeOnly);
-}
-
-bool RenderWidgetHostImpl::IsTreeOnlyAccessibilityModeForTesting() {
- return accessibility_mode() == AccessibilityModeTreeOnly;
-}
-
void RenderWidgetHostImpl::ForwardMouseEvent(const WebMouseEvent& mouse_event) {
ForwardMouseEventWithLatencyInfo(mouse_event, ui::LatencyInfo());
}
@@ -873,9 +862,11 @@ void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo(
const ui::LatencyInfo& ui_latency) {
TRACE_EVENT2("input", "RenderWidgetHostImpl::ForwardMouseEvent",
"x", mouse_event.x, "y", mouse_event.y);
+ ui::LatencyInfo::InputCoordinate logical_coordinate(mouse_event.x,
+ mouse_event.y);
- ui::LatencyInfo latency_info =
- CreateRWHLatencyInfoIfNotExist(&ui_latency, mouse_event.type);
+ ui::LatencyInfo latency_info = CreateInputEventLatencyInfoIfNotExist(
+ &ui_latency, mouse_event.type, &logical_coordinate, 1);
for (size_t i = 0; i < mouse_event_callbacks_.size(); ++i) {
if (mouse_event_callbacks_[i].Run(mouse_event))
@@ -905,8 +896,11 @@ void RenderWidgetHostImpl::ForwardWheelEventWithLatencyInfo(
const ui::LatencyInfo& ui_latency) {
TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardWheelEvent");
- ui::LatencyInfo latency_info =
- CreateRWHLatencyInfoIfNotExist(&ui_latency, wheel_event.type);
+ ui::LatencyInfo::InputCoordinate logical_coordinate(wheel_event.x,
+ wheel_event.y);
+
+ ui::LatencyInfo latency_info = CreateInputEventLatencyInfoIfNotExist(
+ &ui_latency, wheel_event.type, &logical_coordinate, 1);
if (IgnoreInputEvents())
return;
@@ -934,8 +928,11 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo(
if (delegate_->PreHandleGestureEvent(gesture_event))
return;
- ui::LatencyInfo latency_info =
- CreateRWHLatencyInfoIfNotExist(&ui_latency, gesture_event.type);
+ ui::LatencyInfo::InputCoordinate logical_coordinate(gesture_event.x,
+ gesture_event.y);
+
+ ui::LatencyInfo latency_info = CreateInputEventLatencyInfoIfNotExist(
+ &ui_latency, gesture_event.type, &logical_coordinate, 1);
if (gesture_event.type == blink::WebInputEvent::GestureScrollUpdate) {
latency_info.AddLatencyNumber(
@@ -963,9 +960,24 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo(
input_router_->SendGestureEvent(gesture_with_latency);
}
-void RenderWidgetHostImpl::ForwardTouchEvent(
+void RenderWidgetHostImpl::ForwardEmulatedTouchEvent(
const blink::WebTouchEvent& touch_event) {
- ForwardTouchEventWithLatencyInfo(touch_event, ui::LatencyInfo());
+ TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardEmulatedTouchEvent");
+
+ ui::LatencyInfo::InputCoordinate
+ logical_coordinates[ui::LatencyInfo::kMaxInputCoordinates];
+ size_t logical_coordinates_size =
+ std::min(arraysize(logical_coordinates),
+ static_cast<size_t>(touch_event.touchesLength));
+ for (size_t i = 0; i < logical_coordinates_size; i++) {
+ logical_coordinates[i] = ui::LatencyInfo::InputCoordinate(
+ touch_event.touches[i].position.x, touch_event.touches[i].position.y);
+ }
+
+ ui::LatencyInfo latency_info = CreateInputEventLatencyInfoIfNotExist(
+ NULL, touch_event.type, logical_coordinates, logical_coordinates_size);
+ TouchEventWithLatencyInfo touch_with_latency(touch_event, latency_info);
+ input_router_->SendTouchEvent(touch_with_latency);
}
void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo(
@@ -976,9 +988,32 @@ void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo(
// Always forward TouchEvents for touch stream consistency. They will be
// ignored if appropriate in FilterInputEvent().
- ui::LatencyInfo latency_info =
- CreateRWHLatencyInfoIfNotExist(&ui_latency, touch_event.type);
+ ui::LatencyInfo::InputCoordinate
+ logical_coordinates[ui::LatencyInfo::kMaxInputCoordinates];
+ size_t logical_coordinates_size =
+ std::min(arraysize(logical_coordinates),
+ static_cast<size_t>(touch_event.touchesLength));
+ for (size_t i = 0; i < logical_coordinates_size; i++) {
+ logical_coordinates[i] = ui::LatencyInfo::InputCoordinate(
+ touch_event.touches[i].position.x, touch_event.touches[i].position.y);
+ }
+
+ ui::LatencyInfo latency_info = CreateInputEventLatencyInfoIfNotExist(
+ &ui_latency,
+ touch_event.type,
+ logical_coordinates,
+ logical_coordinates_size);
TouchEventWithLatencyInfo touch_with_latency(touch_event, latency_info);
+
+ if (touch_emulator_ &&
+ touch_emulator_->HandleTouchEvent(touch_with_latency.event)) {
+ if (view_) {
+ view_->ProcessAckedTouchEvent(
+ touch_with_latency, INPUT_EVENT_ACK_STATE_CONSUMED);
+ }
+ return;
+ }
+
input_router_->SendTouchEvent(touch_with_latency);
}
@@ -1048,7 +1083,7 @@ void RenderWidgetHostImpl::ForwardKeyboardEvent(
input_router_->SendKeyboardEvent(
key_event,
- CreateRWHLatencyInfoIfNotExist(NULL, key_event.type),
+ CreateInputEventLatencyInfoIfNotExist(NULL, key_event.type, NULL, 0),
is_shortcut);
}
@@ -1072,11 +1107,16 @@ void RenderWidgetHostImpl::SetCursor(const WebCursor& cursor) {
view_->UpdateCursor(cursor);
}
+void RenderWidgetHostImpl::ShowContextMenuAtPoint(const gfx::Point& point) {
+ Send(new ViewMsg_ShowContextMenu(
+ GetRoutingID(), ui::MENU_SOURCE_MOUSE, point));
+}
+
void RenderWidgetHostImpl::SendCursorVisibilityState(bool is_visible) {
Send(new InputMsg_CursorVisibilityChange(GetRoutingID(), is_visible));
}
-int64 RenderWidgetHostImpl::GetLatencyComponentId() {
+int64 RenderWidgetHostImpl::GetLatencyComponentId() const {
return GetRoutingID() | (static_cast<int64>(GetProcess()->GetID()) << 32);
}
@@ -1085,8 +1125,11 @@ void RenderWidgetHostImpl::DisableResizeAckCheckForTesting() {
g_check_for_pending_resize_ack = false;
}
-ui::LatencyInfo RenderWidgetHostImpl::CreateRWHLatencyInfoIfNotExist(
- const ui::LatencyInfo* original, WebInputEvent::Type type) {
+ui::LatencyInfo RenderWidgetHostImpl::CreateInputEventLatencyInfoIfNotExist(
+ const ui::LatencyInfo* original,
+ WebInputEvent::Type type,
+ const ui::LatencyInfo::InputCoordinate* logical_coordinates,
+ size_t logical_coordinates_size) {
ui::LatencyInfo info;
if (original)
info = *original;
@@ -1099,7 +1142,21 @@ ui::LatencyInfo RenderWidgetHostImpl::CreateRWHLatencyInfoIfNotExist(
GetLatencyComponentId(),
++last_input_number_);
info.TraceEventType(WebInputEventTraits::GetName(type));
+
+ // Convert logical coordinates to physical coordinates, based on the
+ // device scale factor.
+ float device_scale_factor =
+ screen_info_ ? screen_info_->deviceScaleFactor : 1;
+ DCHECK(logical_coordinates_size <= ui::LatencyInfo::kMaxInputCoordinates);
+ info.input_coordinates_size = logical_coordinates_size;
+ for (size_t i = 0; i < info.input_coordinates_size; i++) {
+ info.input_coordinates[i].x =
+ logical_coordinates[i].x * device_scale_factor;
+ info.input_coordinates[i].y =
+ logical_coordinates[i].y * device_scale_factor;
+ }
}
+
return info;
}
@@ -1162,6 +1219,13 @@ void RenderWidgetHostImpl::InvalidateScreenInfo() {
screen_info_.reset();
}
+void RenderWidgetHostImpl::GetSnapshotFromBrowser(
+ const base::Callback<void(const unsigned char*,size_t)> callback) {
+ int id = next_browser_snapshot_id_++;
+ pending_browser_snapshots_.insert(std::make_pair(id, callback));
+ Send(new ViewMsg_ForceRedraw(GetRoutingID(), id));
+}
+
void RenderWidgetHostImpl::OnSelectionChanged(const base::string16& text,
size_t offset,
const gfx::Range& range) {
@@ -1195,7 +1259,18 @@ void RenderWidgetHostImpl::RendererExited(base::TerminationStatus status,
// Reset some fields in preparation for recovering from a crash.
ResetSizeAndRepaintPendingFlags();
current_size_.SetSize(0, 0);
- is_hidden_ = false;
+ // After the renderer crashes, the view is destroyed and so the
+ // RenderWidgetHost cannot track its visibility anymore. We assume such
+ // RenderWidgetHost to be visible for the sake of internal accounting - be
+ // careful about changing this - see http://crbug.com/401859.
+ //
+ // We need to at least make sure that the RenderProcessHost is notified about
+ // the |is_hidden_| change, so that the renderer will have correct visibility
+ // set when respawned.
+ if (is_hidden_) {
+ process_->WidgetRestored();
+ is_hidden_ = false;
+ }
// Reset this to ensure the hung renderer mechanism is working properly.
in_flight_event_count_ = 0;
@@ -1204,7 +1279,8 @@ void RenderWidgetHostImpl::RendererExited(base::TerminationStatus status,
GpuSurfaceTracker::Get()->SetSurfaceHandle(surface_id_,
gfx::GLSurfaceHandle());
view_->RenderProcessGone(status, exit_code);
- view_ = NULL; // The View should be deleted by RenderProcessGone.
+ view_ = NULL; // The View should be deleted by RenderProcessGone.
+ view_weak_.reset();
}
// Reconstruct the input router to ensure that it has fresh state for a new
@@ -1258,7 +1334,7 @@ void RenderWidgetHostImpl::ImeSetComposition(
const std::vector<blink::WebCompositionUnderline>& underlines,
int selection_start,
int selection_end) {
- Send(new ViewMsg_ImeSetComposition(
+ Send(new InputMsg_ImeSetComposition(
GetRoutingID(), text, underlines, selection_start, selection_end));
}
@@ -1266,12 +1342,12 @@ void RenderWidgetHostImpl::ImeConfirmComposition(
const base::string16& text,
const gfx::Range& replacement_range,
bool keep_selection) {
- Send(new ViewMsg_ImeConfirmComposition(
+ Send(new InputMsg_ImeConfirmComposition(
GetRoutingID(), text, replacement_range, keep_selection));
}
void RenderWidgetHostImpl::ImeCancelComposition() {
- Send(new ViewMsg_ImeSetComposition(GetRoutingID(), base::string16(),
+ Send(new InputMsg_ImeSetComposition(GetRoutingID(), base::string16(),
std::vector<blink::WebCompositionUnderline>(), 0, 0));
}
@@ -1408,55 +1484,20 @@ void RenderWidgetHostImpl::OnRequestMove(const gfx::Rect& pos) {
}
}
-#if defined(OS_MACOSX)
-void RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwapped(
- const ViewHostMsg_CompositorSurfaceBuffersSwapped_Params& params) {
- // This trace event is used in
- // chrome/browser/extensions/api/cast_streaming/performance_test.cc
- TRACE_EVENT0("renderer_host",
- "RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwapped");
- // This trace event is used in
- // chrome/browser/extensions/api/cast_streaming/performance_test.cc
- UNSHIPPED_TRACE_EVENT0("test_fps",
- TRACE_DISABLED_BY_DEFAULT("OnSwapCompositorFrame"));
- if (!ui::LatencyInfo::Verify(params.latency_info,
- "ViewHostMsg_CompositorSurfaceBuffersSwapped"))
- return;
- if (!view_) {
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.sync_point = 0;
- RenderWidgetHostImpl::AcknowledgeBufferPresent(params.route_id,
- params.gpu_process_host_id,
- ack_params);
- return;
- }
- GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params gpu_params;
- gpu_params.surface_id = params.surface_id;
- gpu_params.surface_handle = params.surface_handle;
- gpu_params.route_id = params.route_id;
- gpu_params.size = params.size;
- gpu_params.scale_factor = params.scale_factor;
- gpu_params.latency_info = params.latency_info;
- for (size_t i = 0; i < gpu_params.latency_info.size(); i++)
- AddLatencyInfoComponentIds(&gpu_params.latency_info[i]);
- view_->AcceleratedSurfaceBuffersSwapped(gpu_params,
- params.gpu_process_host_id);
- view_->DidReceiveRendererFrame();
-}
-#endif // OS_MACOSX
-
bool RenderWidgetHostImpl::OnSwapCompositorFrame(
const IPC::Message& message) {
// This trace event is used in
// chrome/browser/extensions/api/cast_streaming/performance_test.cc
- UNSHIPPED_TRACE_EVENT0("test_fps",
- TRACE_DISABLED_BY_DEFAULT("OnSwapCompositorFrame"));
+ TRACE_EVENT0("test_fps",
+ TRACE_DISABLED_BY_DEFAULT("OnSwapCompositorFrame"));
ViewHostMsg_SwapCompositorFrame::Param param;
if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
return false;
scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
uint32 output_surface_id = param.a;
param.b.AssignTo(frame.get());
+ std::vector<IPC::Message> messages_to_deliver_with_frame;
+ messages_to_deliver_with_frame.swap(param.c);
for (size_t i = 0; i < frame->metadata.latency_info.size(); i++)
AddLatencyInfoComponentIds(&frame->metadata.latency_info[i]);
@@ -1464,6 +1505,11 @@ bool RenderWidgetHostImpl::OnSwapCompositorFrame(
input_router_->OnViewUpdated(
GetInputRouterViewFlagsFromCompositorFrameMetadata(frame->metadata));
+ for (size_t i = 0; i < frame->metadata.latency_info.size(); ++i) {
+ frame->metadata.latency_info[i].AddLatencyNumber(
+ ui::INPUT_EVENT_BROWSER_COMPOSITE_COMPONENT, 0, 0);
+ }
+
if (view_) {
view_->OnSwapCompositorFrame(output_surface_id, frame.Pass());
view_->DidReceiveRendererFrame();
@@ -1482,6 +1528,18 @@ bool RenderWidgetHostImpl::OnSwapCompositorFrame(
SendSwapCompositorFrameAck(routing_id_, output_surface_id,
process_->GetID(), ack);
}
+
+ RenderProcessHost* rph = GetProcess();
+ for (std::vector<IPC::Message>::const_iterator i =
+ messages_to_deliver_with_frame.begin();
+ i != messages_to_deliver_with_frame.end();
+ ++i) {
+ rph->OnMessageReceived(*i);
+ if (i->dispatch_error())
+ rph->OnBadMessageReceived(*i);
+ }
+ messages_to_deliver_with_frame.clear();
+
return true;
}
@@ -1497,8 +1555,6 @@ void RenderWidgetHostImpl::OnUpdateRect(
// Update our knowledge of the RenderWidget's size.
current_size_ = params.view_size;
- // Update our knowledge of the RenderWidget's scroll offset.
- last_scroll_offset_ = params.scroll_offset;
bool is_resize_ack =
ViewHostMsg_UpdateRect_Flags::is_resize_ack(params.flags);
@@ -1583,7 +1639,7 @@ void RenderWidgetHostImpl::DidUpdateBackingStore(
void RenderWidgetHostImpl::OnQueueSyntheticGesture(
const SyntheticGesturePacket& gesture_packet) {
// Only allow untrustworthy gestures if explicitly enabled.
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
cc::switches::kEnableGpuBenchmarking)) {
RecordAction(base::UserMetricsAction("BadMessageTerminate_RWH7"));
GetProcess()->ReceivedBadMessage();
@@ -1612,28 +1668,27 @@ void RenderWidgetHostImpl::OnSetCursor(const WebCursor& cursor) {
SetCursor(cursor);
}
-void RenderWidgetHostImpl::OnSetTouchEventEmulationEnabled(
- bool enabled, bool allow_pinch) {
- if (delegate_)
- delegate_->OnTouchEmulationEnabled(enabled);
-
+void RenderWidgetHostImpl::SetTouchEventEmulationEnabled(bool enabled) {
if (enabled) {
if (!touch_emulator_)
touch_emulator_.reset(new TouchEmulator(this));
- touch_emulator_->Enable(allow_pinch);
+ touch_emulator_->Enable();
} else {
if (touch_emulator_)
touch_emulator_->Disable();
}
}
-void RenderWidgetHostImpl::OnTextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) {
+void RenderWidgetHostImpl::OnTextInputTypeChanged(
+ ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) {
if (view_)
- view_->TextInputStateChanged(params);
+ view_->TextInputTypeChanged(type, input_mode, can_compose_inline, flags);
}
-#if defined(OS_MACOSX) || defined(USE_AURA)
+#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
void RenderWidgetHostImpl::OnImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
@@ -1673,10 +1728,10 @@ void RenderWidgetHostImpl::OnUnlockMouse() {
}
void RenderWidgetHostImpl::OnShowDisambiguationPopup(
- const gfx::Rect& rect,
+ const gfx::Rect& rect_pixels,
const gfx::Size& size,
const cc::SharedBitmapId& id) {
- DCHECK(!rect.IsEmpty());
+ DCHECK(!rect_pixels.IsEmpty());
DCHECK(!size.IsEmpty());
scoped_ptr<cc::SharedBitmap> bitmap =
@@ -1689,18 +1744,17 @@ void RenderWidgetHostImpl::OnShowDisambiguationPopup(
DCHECK(bitmap->pixels());
+ SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
SkBitmap zoomed_bitmap;
- zoomed_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- size.width(), size.height());
- zoomed_bitmap.setPixels(bitmap->pixels());
+ zoomed_bitmap.installPixels(info, bitmap->pixels(), info.minRowBytes());
-#if defined(OS_ANDROID)
+ // Note that |rect| is in coordinates of pixels relative to the window origin.
+ // Aura-based systems will want to convert this to DIPs.
if (view_)
- view_->ShowDisambiguationPopup(rect, zoomed_bitmap);
-#else
- NOTIMPLEMENTED();
-#endif
+ view_->ShowDisambiguationPopup(rect_pixels, zoomed_bitmap);
+ // It is assumed that the disambiguation popup will make a copy of the
+ // provided zoomed image, so we delete this one.
zoomed_bitmap.setPixels(0);
Send(new ViewMsg_ReleaseDisambiguationPopupBitmap(GetRoutingID(), id));
}
@@ -1794,9 +1848,13 @@ void RenderWidgetHostImpl::IncrementInFlightEventCount() {
void RenderWidgetHostImpl::DecrementInFlightEventCount() {
DCHECK_GE(in_flight_event_count_, 0);
- // Cancel pending hung renderer checks since the renderer is responsive.
- if (decrement_in_flight_event_count() <= 0)
+ if (decrement_in_flight_event_count() <= 0) {
+ // Cancel pending hung renderer checks since the renderer is responsive.
StopHangMonitorTimeout();
+ } else {
+ // The renderer is responsive, but there are in-flight events to wait for.
+ RestartHangMonitorTimeout();
+ }
}
void RenderWidgetHostImpl::OnHasTouchEventHandlers(bool has_handlers) {
@@ -1839,14 +1897,17 @@ void RenderWidgetHostImpl::OnKeyboardEventAck(
void RenderWidgetHostImpl::OnWheelEventAck(
const MouseWheelEventWithLatencyInfo& wheel_event,
InputEventAckState ack_result) {
+ ui::LatencyInfo latency = wheel_event.latency;
+ latency.AddLatencyNumber(
+ ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0);
if (!wheel_event.latency.FindLatency(
ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, NULL)) {
// MouseWheelEvent latency ends when it is acked but does not cause any
// rendering scheduled.
- ui::LatencyInfo latency = wheel_event.latency;
latency.AddLatencyNumber(
ui::INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT, 0, 0);
}
+ ComputeInputLatencyHistograms(blink::WebInputEvent::MouseWheel, latency);
if (!is_hidden() && view_) {
if (ack_result != INPUT_EVENT_ACK_STATE_CONSUMED &&
@@ -1883,17 +1944,20 @@ void RenderWidgetHostImpl::OnTouchEventAck(
InputEventAckState ack_result) {
TouchEventWithLatencyInfo touch_event = event;
touch_event.latency.AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT, 0, 0);
+ ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0);
// TouchEvent latency ends at ack if it didn't cause any rendering.
if (!touch_event.latency.FindLatency(
ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, NULL)) {
touch_event.latency.AddLatencyNumber(
ui::INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT, 0, 0);
}
- ComputeTouchLatency(touch_event.latency);
+ ComputeInputLatencyHistograms(
+ blink::WebInputEvent::TouchTypeFirst, touch_event.latency);
- if (touch_emulator_ && touch_emulator_->HandleTouchEventAck(ack_result))
+ if (touch_emulator_ &&
+ touch_emulator_->HandleTouchEventAck(event.event, ack_result)) {
return;
+ }
if (view_)
view_->ProcessAckedTouchEvent(touch_event, ack_result);
@@ -1913,15 +1977,18 @@ void RenderWidgetHostImpl::OnSyntheticGestureCompleted(
Send(new InputMsg_SyntheticGestureCompleted(GetRoutingID()));
}
-const gfx::Vector2d& RenderWidgetHostImpl::GetLastScrollOffset() const {
- return last_scroll_offset_;
-}
-
bool RenderWidgetHostImpl::IgnoreInputEvents() const {
return ignore_input_events_ || process_->IgnoreInputEvents();
}
bool RenderWidgetHostImpl::ShouldForwardTouchEvent() const {
+ // It's important that the emulator sees a complete native touch stream,
+ // allowing it to perform touch filtering as appropriate.
+ // TODO(dgozman): Remove when touch stream forwarding issues resolved, see
+ // crbug.com/375940.
+ if (touch_emulator_ && touch_emulator_->enabled())
+ return true;
+
return input_router_->ShouldForwardTouchEvent();
}
@@ -1929,10 +1996,6 @@ void RenderWidgetHostImpl::StartUserGesture() {
OnUserGesture();
}
-void RenderWidgetHostImpl::Stop() {
- Send(new ViewMsg_Stop(GetRoutingID()));
-}
-
void RenderWidgetHostImpl::SetBackgroundOpaque(bool opaque) {
Send(new ViewMsg_SetBackgroundOpaque(GetRoutingID(), opaque));
}
@@ -1942,92 +2005,6 @@ void RenderWidgetHostImpl::SetEditCommandsForNextKeyEvent(
Send(new InputMsg_SetEditCommandsForNextKeyEvent(GetRoutingID(), commands));
}
-void RenderWidgetHostImpl::AddAccessibilityMode(AccessibilityMode mode) {
- SetAccessibilityMode(
- content::AddAccessibilityModeTo(accessibility_mode_, mode));
-}
-
-void RenderWidgetHostImpl::RemoveAccessibilityMode(AccessibilityMode mode) {
- SetAccessibilityMode(
- content::RemoveAccessibilityModeFrom(accessibility_mode_, mode));
-}
-
-void RenderWidgetHostImpl::ResetAccessibilityMode() {
- SetAccessibilityMode(
- BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode());
-}
-
-void RenderWidgetHostImpl::SetAccessibilityMode(AccessibilityMode mode) {
- accessibility_mode_ = mode;
- Send(new ViewMsg_SetAccessibilityMode(GetRoutingID(), mode));
-}
-
-void RenderWidgetHostImpl::AccessibilitySetFocus(int object_id) {
- Send(new AccessibilityMsg_SetFocus(GetRoutingID(), object_id));
- view_->OnAccessibilitySetFocus(object_id);
-}
-
-void RenderWidgetHostImpl::AccessibilityDoDefaultAction(int object_id) {
- Send(new AccessibilityMsg_DoDefaultAction(GetRoutingID(), object_id));
-}
-
-void RenderWidgetHostImpl::AccessibilityShowMenu(int object_id) {
- view_->AccessibilityShowMenu(object_id);
-}
-
-void RenderWidgetHostImpl::AccessibilityScrollToMakeVisible(
- int acc_obj_id, gfx::Rect subfocus) {
- Send(new AccessibilityMsg_ScrollToMakeVisible(
- GetRoutingID(), acc_obj_id, subfocus));
-}
-
-void RenderWidgetHostImpl::AccessibilityScrollToPoint(
- int acc_obj_id, gfx::Point point) {
- Send(new AccessibilityMsg_ScrollToPoint(
- GetRoutingID(), acc_obj_id, point));
-}
-
-void RenderWidgetHostImpl::AccessibilitySetTextSelection(
- int object_id, int start_offset, int end_offset) {
- Send(new AccessibilityMsg_SetTextSelection(
- GetRoutingID(), object_id, start_offset, end_offset));
-}
-
-bool RenderWidgetHostImpl::AccessibilityViewHasFocus() const {
- return view_->HasFocus();
-}
-
-gfx::Rect RenderWidgetHostImpl::AccessibilityGetViewBounds() const {
- return view_->GetViewBounds();
-}
-
-gfx::Point RenderWidgetHostImpl::AccessibilityOriginInScreen(
- const gfx::Rect& bounds) const {
- return view_->AccessibilityOriginInScreen(bounds);
-}
-
-void RenderWidgetHostImpl::AccessibilityHitTest(const gfx::Point& point) {
- Send(new AccessibilityMsg_HitTest(GetRoutingID(), point));
-}
-
-void RenderWidgetHostImpl::AccessibilityFatalError() {
- Send(new AccessibilityMsg_FatalError(GetRoutingID()));
- view_->SetBrowserAccessibilityManager(NULL);
-}
-
-#if defined(OS_WIN)
-void RenderWidgetHostImpl::SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) {
- if (view_)
- view_->SetParentNativeViewAccessible(accessible_parent);
-}
-
-gfx::NativeViewAccessible
-RenderWidgetHostImpl::GetParentNativeViewAccessible() const {
- return delegate_->GetParentNativeViewAccessible();
-}
-#endif
-
void RenderWidgetHostImpl::ExecuteEditCommand(const std::string& command,
const std::string& value) {
Send(new InputMsg_ExecuteEditCommand(GetRoutingID(), command, value));
@@ -2065,17 +2042,6 @@ bool RenderWidgetHostImpl::GotResponseToLockMouseRequest(bool allowed) {
}
// static
-void RenderWidgetHostImpl::AcknowledgeBufferPresent(
- int32 route_id, int gpu_host_id,
- const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
- GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(gpu_host_id);
- if (ui_shim) {
- ui_shim->Send(new AcceleratedSurfaceMsg_BufferPresented(route_id,
- params));
- }
-}
-
-// static
void RenderWidgetHostImpl::SendSwapCompositorFrameAck(
int32 route_id,
uint32 output_surface_id,
@@ -2117,49 +2083,73 @@ void RenderWidgetHostImpl::DetachDelegate() {
delegate_ = NULL;
}
-void RenderWidgetHostImpl::ComputeTouchLatency(
- const ui::LatencyInfo& latency_info) {
- ui::LatencyInfo::LatencyComponent ui_component;
+void RenderWidgetHostImpl::ComputeInputLatencyHistograms(
+ blink::WebInputEvent::Type type,
+ const ui::LatencyInfo& latency_info) const {
ui::LatencyInfo::LatencyComponent rwh_component;
- ui::LatencyInfo::LatencyComponent acked_component;
-
- if (!latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_UI_COMPONENT,
- 0,
- &ui_component) ||
- !latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+ if (!latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
GetLatencyComponentId(),
&rwh_component))
return;
+ DCHECK_EQ(rwh_component.event_count, 1u);
- DCHECK(ui_component.event_count == 1);
- DCHECK(rwh_component.event_count == 1);
-
- base::TimeDelta ui_delta =
- rwh_component.event_time - ui_component.event_time;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.Latency.Browser.TouchUI",
- ui_delta.InMicroseconds(),
- 1,
- 20000,
- 100);
+ ui::LatencyInfo::LatencyComponent ui_component;
+ if (latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_UI_COMPONENT,
+ 0,
+ &ui_component)) {
+ DCHECK_EQ(ui_component.event_count, 1u);
+ base::TimeDelta ui_delta =
+ rwh_component.event_time - ui_component.event_time;
+ switch (type) {
+ case blink::WebInputEvent::MouseWheel:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Latency.Browser.WheelUI",
+ ui_delta.InMicroseconds(), 1, 20000, 100);
+ break;
+ case blink::WebInputEvent::TouchTypeFirst:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Latency.Browser.TouchUI",
+ ui_delta.InMicroseconds(), 1, 20000, 100);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
- if (latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT,
+ ui::LatencyInfo::LatencyComponent acked_component;
+ if (latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
0,
&acked_component)) {
- DCHECK(acked_component.event_count == 1);
+ DCHECK_EQ(acked_component.event_count, 1u);
base::TimeDelta acked_delta =
acked_component.event_time - rwh_component.event_time;
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Event.Latency.Browser.TouchAcked",
- acked_delta.InMicroseconds(),
- 1,
- 1000000,
- 100);
+ switch (type) {
+ case blink::WebInputEvent::MouseWheel:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Latency.Browser.WheelAcked",
+ acked_delta.InMicroseconds(), 1, 1000000, 100);
+ break;
+ case blink::WebInputEvent::TouchTypeFirst:
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Latency.Browser.TouchAcked",
+ acked_delta.InMicroseconds(), 1, 1000000, 100);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
}
}
void RenderWidgetHostImpl::FrameSwapped(const ui::LatencyInfo& latency_info) {
ui::LatencyInfo::LatencyComponent window_snapshot_component;
+ if (latency_info.FindLatency(ui::WINDOW_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT,
+ GetLatencyComponentId(),
+ &window_snapshot_component)) {
+ WindowOldSnapshotReachedScreen(
+ static_cast<int>(window_snapshot_component.sequence_number));
+ }
if (latency_info.FindLatency(ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT,
GetLatencyComponentId(),
&window_snapshot_component)) {
@@ -2181,14 +2171,28 @@ void RenderWidgetHostImpl::FrameSwapped(const ui::LatencyInfo& latency_info) {
#endif
}
- ui::LatencyInfo::LatencyComponent rwh_component;
ui::LatencyInfo::LatencyComponent swap_component;
+ if (!latency_info.FindLatency(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT,
+ 0,
+ &swap_component)) {
+ return;
+ }
+ ui::LatencyInfo::LatencyComponent tab_switch_component;
+ if (latency_info.FindLatency(ui::TAB_SHOW_COMPONENT,
+ GetLatencyComponentId(),
+ &tab_switch_component)) {
+ base::TimeDelta delta =
+ swap_component.event_time - tab_switch_component.event_time;
+ for (size_t i = 0; i < tab_switch_component.event_count; i++) {
+ UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta);
+ }
+ }
+
+ ui::LatencyInfo::LatencyComponent rwh_component;
if (!latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
GetLatencyComponentId(),
- &rwh_component) ||
- !latency_info.FindLatency(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT,
- 0, &swap_component)) {
+ &rwh_component)) {
return;
}
@@ -2211,6 +2215,21 @@ void RenderWidgetHostImpl::FrameSwapped(const ui::LatencyInfo& latency_info) {
100);
}
}
+
+ ui::LatencyInfo::LatencyComponent gpu_swap_component;
+ if (!latency_info.FindLatency(
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, &gpu_swap_component)) {
+ return;
+ }
+
+ ui::LatencyInfo::LatencyComponent composite_component;
+ if (latency_info.FindLatency(ui::INPUT_EVENT_BROWSER_COMPOSITE_COMPONENT,
+ 0,
+ &composite_component)) {
+ base::TimeDelta delta =
+ gpu_swap_component.event_time - composite_component.event_time;
+ browser_composite_latency_history_.InsertSample(delta);
+ }
}
void RenderWidgetHostImpl::DidReceiveRendererFrame() {
@@ -2222,7 +2241,7 @@ void RenderWidgetHostImpl::WindowSnapshotAsyncCallback(
int snapshot_id,
gfx::Size snapshot_size,
scoped_refptr<base::RefCountedBytes> png_data) {
- if (!png_data) {
+ if (!png_data.get()) {
std::vector<unsigned char> png_vector;
Send(new ViewMsg_WindowSnapshotCompleted(
routing_id, snapshot_id, gfx::Size(), png_vector));
@@ -2233,14 +2252,15 @@ void RenderWidgetHostImpl::WindowSnapshotAsyncCallback(
routing_id, snapshot_id, snapshot_size, png_data->data()));
}
-void RenderWidgetHostImpl::WindowSnapshotReachedScreen(int snapshot_id) {
+void RenderWidgetHostImpl::WindowOldSnapshotReachedScreen(int snapshot_id) {
DCHECK(base::MessageLoopForUI::IsCurrent());
std::vector<unsigned char> png;
// This feature is behind the kEnableGpuBenchmarking command line switch
// because it poses security concerns and should only be used for testing.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(cc::switches::kEnableGpuBenchmarking)) {
Send(new ViewMsg_WindowSnapshotCompleted(
GetRoutingID(), snapshot_id, gfx::Size(), png));
@@ -2269,6 +2289,53 @@ void RenderWidgetHostImpl::WindowSnapshotReachedScreen(int snapshot_id) {
snapshot_size));
}
+void RenderWidgetHostImpl::WindowSnapshotReachedScreen(int snapshot_id) {
+ DCHECK(base::MessageLoopForUI::IsCurrent());
+
+ gfx::Rect view_bounds = GetView()->GetViewBounds();
+ gfx::Rect snapshot_bounds(view_bounds.size());
+
+ std::vector<unsigned char> png;
+ if (ui::GrabViewSnapshot(
+ GetView()->GetNativeView(), &png, snapshot_bounds)) {
+ OnSnapshotDataReceived(snapshot_id, &png.front(), png.size());
+ return;
+ }
+
+ ui::GrabViewSnapshotAsync(
+ GetView()->GetNativeView(),
+ snapshot_bounds,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::Bind(&RenderWidgetHostImpl::OnSnapshotDataReceivedAsync,
+ weak_factory_.GetWeakPtr(),
+ snapshot_id));
+}
+
+void RenderWidgetHostImpl::OnSnapshotDataReceived(int snapshot_id,
+ const unsigned char* data,
+ size_t size) {
+ // Any pending snapshots with a lower ID than the one received are considered
+ // to be implicitly complete, and returned the same snapshot data.
+ PendingSnapshotMap::iterator it = pending_browser_snapshots_.begin();
+ while(it != pending_browser_snapshots_.end()) {
+ if (it->first <= snapshot_id) {
+ it->second.Run(data, size);
+ pending_browser_snapshots_.erase(it++);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void RenderWidgetHostImpl::OnSnapshotDataReceivedAsync(
+ int snapshot_id,
+ scoped_refptr<base::RefCountedBytes> png_data) {
+ if (png_data.get())
+ OnSnapshotDataReceived(snapshot_id, png_data->front(), png_data->size());
+ else
+ OnSnapshotDataReceived(snapshot_id, NULL, 0);
+}
+
// static
void RenderWidgetHostImpl::CompositorFrameDrawn(
const std::vector<ui::LatencyInfo>& latency_info) {
@@ -2279,7 +2346,9 @@ void RenderWidgetHostImpl::CompositorFrameDrawn(
b != latency_info[i].latency_components.end();
++b) {
if (b->first.first == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT ||
- b->first.first == ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT) {
+ b->first.first == ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT ||
+ b->first.first == ui::WINDOW_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT ||
+ b->first.first == ui::TAB_SHOW_COMPONENT) {
// Matches with GetLatencyComponentId
int routing_id = b->first.second & 0xffffffff;
int process_id = (b->first.second >> 32) & 0xffffffff;
@@ -2303,7 +2372,8 @@ void RenderWidgetHostImpl::AddLatencyInfoComponentIds(
latency_info->latency_components.begin();
while (lc != latency_info->latency_components.end()) {
ui::LatencyComponentType component_type = lc->first.first;
- if (component_type == ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT) {
+ if (component_type == ui::WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT ||
+ component_type == ui::WINDOW_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT) {
// Generate a new component entry with the correct component ID
ui::LatencyInfo::LatencyMap::key_type key =
std::make_pair(component_type, GetLatencyComponentId());
@@ -2322,10 +2392,39 @@ void RenderWidgetHostImpl::AddLatencyInfoComponentIds(
}
}
-SkBitmap::Config RenderWidgetHostImpl::PreferredReadbackFormat() {
+BrowserAccessibilityManager*
+ RenderWidgetHostImpl::GetRootBrowserAccessibilityManager() {
+ return delegate_ ? delegate_->GetRootBrowserAccessibilityManager() : NULL;
+}
+
+BrowserAccessibilityManager*
+ RenderWidgetHostImpl::GetOrCreateRootBrowserAccessibilityManager() {
+ return delegate_ ?
+ delegate_->GetOrCreateRootBrowserAccessibilityManager() : NULL;
+}
+
+base::TimeDelta RenderWidgetHostImpl::GetEstimatedBrowserCompositeTime() {
+ // TODO(orglofch) remove lower bound on estimate once we're sure it won't
+ // cause regressions
+ return std::max(
+ browser_composite_latency_history_.Percentile(
+ kBrowserCompositeLatencyEstimationPercentile) *
+ kBrowserCompositeLatencyEstimationSlack,
+ base::TimeDelta::FromMicroseconds(
+ (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60)));
+}
+
+#if defined(OS_WIN)
+gfx::NativeViewAccessible
+ RenderWidgetHostImpl::GetParentNativeViewAccessible() {
+ return delegate_ ? delegate_->GetParentNativeViewAccessible() : NULL;
+}
+#endif
+
+SkColorType RenderWidgetHostImpl::PreferredReadbackFormat() {
if (view_)
return view_->PreferredReadbackFormat();
- return SkBitmap::kARGB_8888_Config;
+ return kN32_SkColorType;
}
} // 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 65fa860df34..71aa04fcf34 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_impl.h
+++ b/chromium/content/browser/renderer_host/render_widget_host_impl.h
@@ -23,8 +23,8 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
+#include "cc/base/rolling_time_delta_history.h"
#include "cc/resources/shared_bitmap.h"
-#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/renderer_host/event_with_latency_info.h"
#include "content/browser/renderer_host/input/input_ack_handler.h"
#include "content/browser/renderer_host/input/input_router_client.h"
@@ -43,7 +43,6 @@
struct AcceleratedSurfaceMsg_BufferPresented_Params;
struct ViewHostMsg_BeginSmoothScroll_Params;
-struct ViewHostMsg_CompositorSurfaceBuffersSwapped_Params;
struct ViewHostMsg_SelectionBounds_Params;
struct ViewHostMsg_TextInputState_Params;
struct ViewHostMsg_UpdateRect_Params;
@@ -79,6 +78,7 @@ class WebLayer;
#endif
namespace content {
+class BrowserAccessibilityManager;
class InputRouter;
class MockRenderWidgetHost;
class RenderWidgetHostDelegate;
@@ -96,8 +96,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
public InputRouterClient,
public InputAckHandler,
public TouchEmulatorClient,
- public IPC::Listener,
- public BrowserAccessibilityDelegate {
+ public IPC::Listener {
public:
// routing_id can be MSG_ROUTING_NONE, in which case the next available
// routing id is taken from the RenderProcessHost.
@@ -107,7 +106,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
RenderProcessHost* process,
int routing_id,
bool hidden);
- virtual ~RenderWidgetHostImpl();
+ ~RenderWidgetHostImpl() override;
// Similar to RenderWidgetHost::FromID, but returning the Impl object.
static RenderWidgetHostImpl* FromID(int32 process_id, int32 routing_id);
@@ -127,70 +126,46 @@ class CONTENT_EXPORT RenderWidgetHostImpl
}
// RenderWidgetHost implementation.
- virtual void UpdateTextDirection(blink::WebTextDirection direction) OVERRIDE;
- virtual void NotifyTextDirection() OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void Blur() OVERRIDE;
- virtual void SetActive(bool active) OVERRIDE;
- virtual void CopyFromBackingStore(
+ void UpdateTextDirection(blink::WebTextDirection direction) override;
+ void NotifyTextDirection() override;
+ void Focus() override;
+ void Blur() override;
+ void SetActive(bool active) override;
+ void CopyFromBackingStore(
const gfx::Rect& src_rect,
const gfx::Size& accelerated_dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config& bitmap_config) OVERRIDE;
- virtual bool CanCopyFromBackingStore() OVERRIDE;
+ const SkColorType color_type) override;
+ bool CanCopyFromBackingStore() override;
#if defined(OS_ANDROID)
- virtual void LockBackingStore() OVERRIDE;
- virtual void UnlockBackingStore() OVERRIDE;
+ virtual void LockBackingStore() override;
+ virtual void UnlockBackingStore() override;
#endif
- virtual void EnableFullAccessibilityMode() OVERRIDE;
- virtual bool IsFullAccessibilityModeForTesting() OVERRIDE;
- virtual void EnableTreeOnlyAccessibilityMode() OVERRIDE;
- virtual bool IsTreeOnlyAccessibilityModeForTesting() OVERRIDE;
- virtual void ForwardMouseEvent(
- const blink::WebMouseEvent& mouse_event) OVERRIDE;
- virtual void ForwardWheelEvent(
- const blink::WebMouseWheelEvent& wheel_event) OVERRIDE;
- virtual void ForwardKeyboardEvent(
- const NativeWebKeyboardEvent& key_event) OVERRIDE;
- virtual const gfx::Vector2d& GetLastScrollOffset() const OVERRIDE;
- virtual RenderProcessHost* GetProcess() const OVERRIDE;
- virtual int GetRoutingID() const OVERRIDE;
- virtual RenderWidgetHostView* GetView() const OVERRIDE;
- virtual bool IsLoading() const OVERRIDE;
- virtual bool IsRenderView() const OVERRIDE;
- virtual void ResizeRectChanged(const gfx::Rect& new_rect) OVERRIDE;
- virtual void RestartHangMonitorTimeout() OVERRIDE;
- virtual void SetIgnoreInputEvents(bool ignore_input_events) OVERRIDE;
- virtual void Stop() OVERRIDE;
- virtual void WasResized() OVERRIDE;
- virtual void AddKeyPressEventCallback(
- const KeyPressEventCallback& callback) OVERRIDE;
- virtual void RemoveKeyPressEventCallback(
- const KeyPressEventCallback& callback) OVERRIDE;
- virtual void AddMouseEventCallback(
- const MouseEventCallback& callback) OVERRIDE;
- virtual void RemoveMouseEventCallback(
- const MouseEventCallback& callback) OVERRIDE;
- virtual void GetWebScreenInfo(blink::WebScreenInfo* result) OVERRIDE;
-
- virtual SkBitmap::Config PreferredReadbackFormat() OVERRIDE;
-
- // BrowserAccessibilityDelegate
- virtual void AccessibilitySetFocus(int acc_obj_id) OVERRIDE;
- virtual void AccessibilityDoDefaultAction(int acc_obj_id) OVERRIDE;
- virtual void AccessibilityShowMenu(int acc_obj_id) OVERRIDE;
- virtual void AccessibilityScrollToMakeVisible(
- int acc_obj_id, gfx::Rect subfocus) OVERRIDE;
- virtual void AccessibilityScrollToPoint(
- int acc_obj_id, gfx::Point point) OVERRIDE;
- virtual void AccessibilitySetTextSelection(
- int acc_obj_id, int start_offset, int end_offset) OVERRIDE;
- virtual bool AccessibilityViewHasFocus() const OVERRIDE;
- virtual gfx::Rect AccessibilityGetViewBounds() const OVERRIDE;
- virtual gfx::Point AccessibilityOriginInScreen(const gfx::Rect& bounds)
- const OVERRIDE;
- virtual void AccessibilityHitTest(const gfx::Point& point) OVERRIDE;
- virtual void AccessibilityFatalError() OVERRIDE;
+ void ForwardMouseEvent(const blink::WebMouseEvent& mouse_event) override;
+ void ForwardWheelEvent(const blink::WebMouseWheelEvent& wheel_event) override;
+ void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event) override;
+ RenderProcessHost* GetProcess() const override;
+ int GetRoutingID() const override;
+ RenderWidgetHostView* GetView() const override;
+ bool IsLoading() const override;
+ bool IsRenderView() const override;
+ void ResizeRectChanged(const gfx::Rect& new_rect) override;
+ void RestartHangMonitorTimeout() override;
+ void SetIgnoreInputEvents(bool ignore_input_events) override;
+ void WasResized() override;
+ void AddKeyPressEventCallback(const KeyPressEventCallback& callback) override;
+ void RemoveKeyPressEventCallback(
+ const KeyPressEventCallback& callback) override;
+ void AddMouseEventCallback(const MouseEventCallback& callback) override;
+ void RemoveMouseEventCallback(const MouseEventCallback& callback) override;
+ void GetWebScreenInfo(blink::WebScreenInfo* result) override;
+
+ SkColorType PreferredReadbackFormat() override;
+
+ // Forces redraw in the renderer and when the update reaches the browser
+ // grabs snapshot from the compositor. Returns PNG-encoded snapshot.
+ void GetSnapshotFromBrowser(
+ const base::Callback<void(const unsigned char*,size_t)> callback);
const NativeWebKeyboardEvent* GetLastKeyboardEvent() const;
@@ -218,15 +193,18 @@ class CONTENT_EXPORT RenderWidgetHostImpl
virtual void Shutdown();
// IPC::Listener
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
// Sends a message to the corresponding object in the renderer.
- virtual bool Send(IPC::Message* msg) OVERRIDE;
+ bool Send(IPC::Message* msg) override;
+
+ // Indicates if the page has finished loading.
+ virtual void SetIsLoading(bool is_loading);
// Called to notify the RenderWidget that it has been hidden or restored from
// having been hidden.
- void WasHidden();
- void WasShown();
+ virtual void WasHidden();
+ virtual void WasShown(const ui::LatencyInfo& latency_info);
// Returns true if the RenderWidget is hidden.
bool is_hidden() const { return is_hidden_; }
@@ -245,9 +223,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// Notifies the RenderWidgetHost that the View was destroyed.
void ViewDestroyed();
- // Indicates if the page has finished loading.
- void SetIsLoading(bool is_loading);
-
+#if defined(OS_MACOSX)
// Pause for a moment to wait for pending repaint or resize messages sent to
// the renderer to arrive. If pending resize messages are for an old window
// size, then also pump through a new resize message if there is time.
@@ -259,6 +235,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// Wait for a surface matching the size of the widget's view, possibly
// blocking until the renderer sends a new frame.
void WaitForSurface();
+#endif
+
+ bool resize_ack_pending_for_testing() { return resize_ack_pending_; }
// GPU accelerated version of GetBackingStore function. This will
// trigger a re-composite to the view. It may fail if a resize is pending, or
@@ -289,12 +268,16 @@ class CONTENT_EXPORT RenderWidgetHostImpl
const blink::WebMouseWheelEvent& wheel_event,
const ui::LatencyInfo& ui_latency);
- // TouchEmulatorClient overrides.
- virtual void ForwardGestureEvent(
- const blink::WebGestureEvent& gesture_event) OVERRIDE;
- virtual void ForwardTouchEvent(
- const blink::WebTouchEvent& touch_event) OVERRIDE;
- virtual void SetCursor(const WebCursor& cursor) OVERRIDE;
+ // Enables/disables touch emulation using mouse event. See TouchEmulator.
+ void SetTouchEventEmulationEnabled(bool enabled);
+
+ // TouchEmulatorClient implementation.
+ void ForwardGestureEvent(
+ const blink::WebGestureEvent& gesture_event) override;
+ void ForwardEmulatedTouchEvent(
+ const blink::WebTouchEvent& touch_event) override;
+ void SetCursor(const WebCursor& cursor) override;
+ void ShowContextMenuAtPoint(const gfx::Point& point) override;
// Queues a synthetic gesture for testing purposes. Invokes the on_complete
// callback when the gesture is finished running.
@@ -387,30 +370,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
void SetEditCommandsForNextKeyEvent(
const std::vector<EditCommand>& commands);
- // Gets the accessibility mode.
- AccessibilityMode accessibility_mode() const {
- return accessibility_mode_;
- }
-
- // Adds the given accessibility mode to the current accessibility mode bitmap.
- void AddAccessibilityMode(AccessibilityMode mode);
-
- // Removes the given accessibility mode from the current accessibility mode
- // bitmap, managing the bits that are shared with other modes such that a
- // bit will only be turned off when all modes that depend on it have been
- // removed.
- void RemoveAccessibilityMode(AccessibilityMode mode);
-
- // Resets the accessibility mode to the default setting in
- // BrowserStateAccessibilityImpl.
- void ResetAccessibilityMode();
-
-#if defined(OS_WIN)
- void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent);
- gfx::NativeViewAccessible GetParentNativeViewAccessible() const;
-#endif
-
// Executes the edit command on the RenderView.
void ExecuteEditCommand(const std::string& command,
const std::string& value);
@@ -435,13 +394,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
virtual void UpdateVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval);
- // Called by the view in response to AcceleratedSurfaceBuffersSwapped or
- // AcceleratedSurfacePostSubBuffer.
- static void AcknowledgeBufferPresent(
- int32 route_id,
- int gpu_host_id,
- const AcceleratedSurfaceMsg_BufferPresented_Params& params);
-
// Called by the view in response to OnSwapCompositorFrame.
static void SendSwapCompositorFrameAck(
int32 route_id,
@@ -479,19 +431,18 @@ class CONTENT_EXPORT RenderWidgetHostImpl
void FlushInput();
// InputRouterClient
- virtual void SetNeedsFlush() OVERRIDE;
+ void SetNeedsFlush() override;
// Indicates whether the renderer drives the RenderWidgetHosts's size or the
// other way around.
bool should_auto_resize() { return should_auto_resize_; }
- void ComputeTouchLatency(const ui::LatencyInfo& latency_info);
void FrameSwapped(const ui::LatencyInfo& latency_info);
void DidReceiveRendererFrame();
// Returns the ID that uniquely describes this component to the latency
// subsystem.
- int64 GetLatencyComponentId();
+ int64 GetLatencyComponentId() const;
static void CompositorFrameDrawn(
const std::vector<ui::LatencyInfo>& latency_info);
@@ -512,14 +463,35 @@ class CONTENT_EXPORT RenderWidgetHostImpl
InputRouter* input_router() { return input_router_.get(); }
+ // Get the BrowserAccessibilityManager for the root of the frame tree,
+ BrowserAccessibilityManager* GetRootBrowserAccessibilityManager();
+
+ // Get the BrowserAccessibilityManager for the root of the frame tree,
+ // or create it if it doesn't already exist.
+ BrowserAccessibilityManager* GetOrCreateRootBrowserAccessibilityManager();
+
+ base::TimeDelta GetEstimatedBrowserCompositeTime();
+
+#if defined(OS_WIN)
+ gfx::NativeViewAccessible GetParentNativeViewAccessible();
+#endif
+
protected:
- virtual RenderWidgetHostImpl* AsRenderWidgetHostImpl() OVERRIDE;
+ RenderWidgetHostImpl* AsRenderWidgetHostImpl() override;
// Create a LatencyInfo struct with INPUT_EVENT_LATENCY_RWH_COMPONENT
// component if it is not already in |original|. And if |original| is
// not NULL, it is also merged into the resulting LatencyInfo.
- ui::LatencyInfo CreateRWHLatencyInfoIfNotExist(
- const ui::LatencyInfo* original, blink::WebInputEvent::Type type);
+ ui::LatencyInfo CreateInputEventLatencyInfoIfNotExist(
+ const ui::LatencyInfo* original,
+ blink::WebInputEvent::Type type,
+ const ui::LatencyInfo::InputCoordinate* logical_coordinates,
+ size_t logical_coordinates_size);
+ // Add UMA histograms for the latency to the renderer and roundtrip latency
+ // for a given event type.
+ void ComputeInputLatencyHistograms(
+ blink::WebInputEvent::Type type,
+ const ui::LatencyInfo& latency_info) const;
// Called when we receive a notification indicating that the renderer
// process has gone. This will reset our state so that our state will be
@@ -585,13 +557,19 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// doing so).
RenderWidgetHostViewBase* view_;
+ // A weak pointer to the view. The above pointer should be weak, but changing
+ // that to be weak causes crashes on Android.
+ // TODO(ccameron): Fix this.
+ // http://crbug.com/404828
+ base::WeakPtr<RenderWidgetHostViewBase> view_weak_;
+
// true if a renderer has once been valid. We use this flag to display a sad
// tab only when we lose our renderer and not if a paint occurs during
// initialization.
bool renderer_initialized_;
// This value indicates how long to wait before we consider a renderer hung.
- int hung_renderer_delay_ms_;
+ int64 hung_renderer_delay_ms_;
private:
friend class MockRenderWidgetHost;
@@ -615,10 +593,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
void OnRequestMove(const gfx::Rect& pos);
void OnSetTooltipText(const base::string16& tooltip_text,
blink::WebTextDirection text_direction_hint);
-#if defined(OS_MACOSX)
- void OnCompositorSurfaceBuffersSwapped(
- const ViewHostMsg_CompositorSurfaceBuffersSwapped_Params& params);
-#endif
bool OnSwapCompositorFrame(const IPC::Message& message);
void OnFlingingStopped();
void OnUpdateRect(const ViewHostMsg_UpdateRect_Params& params);
@@ -626,11 +600,12 @@ class CONTENT_EXPORT RenderWidgetHostImpl
virtual void OnFocus();
virtual void OnBlur();
void OnSetCursor(const WebCursor& cursor);
- void OnSetTouchEventEmulationEnabled(bool enabled, bool allow_pinch);
- void OnTextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params);
+ void OnTextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags);
-#if defined(OS_MACOSX) || defined(USE_AURA)
+#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
void OnImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds);
@@ -640,7 +615,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
bool last_unlocked_by_target,
bool privileged);
void OnUnlockMouse();
- void OnShowDisambiguationPopup(const gfx::Rect& rect,
+ void OnShowDisambiguationPopup(const gfx::Rect& rect_pixels,
const gfx::Size& size,
const cc::SharedBitmapId& id);
#if defined(OS_WIN)
@@ -667,25 +642,25 @@ class CONTENT_EXPORT RenderWidgetHostImpl
bool KeyPressListenersHandleEvent(const NativeWebKeyboardEvent& event);
// InputRouterClient
- virtual InputEventAckState FilterInputEvent(
+ InputEventAckState FilterInputEvent(
const blink::WebInputEvent& event,
- const ui::LatencyInfo& latency_info) OVERRIDE;
- virtual void IncrementInFlightEventCount() OVERRIDE;
- virtual void DecrementInFlightEventCount() OVERRIDE;
- virtual void OnHasTouchEventHandlers(bool has_handlers) OVERRIDE;
- virtual void DidFlush() OVERRIDE;
- virtual void DidOverscroll(const DidOverscrollParams& params) OVERRIDE;
+ const ui::LatencyInfo& latency_info) override;
+ void IncrementInFlightEventCount() override;
+ void DecrementInFlightEventCount() override;
+ void OnHasTouchEventHandlers(bool has_handlers) override;
+ void DidFlush() override;
+ void DidOverscroll(const DidOverscrollParams& params) override;
// InputAckHandler
- virtual void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void OnUnexpectedEventAck(UnexpectedEventAckType type) OVERRIDE;
+ void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
+ InputEventAckState ack_result) override;
+ void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
+ void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
+ void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override;
+ void OnUnexpectedEventAck(UnexpectedEventAckType type) override;
void OnSyntheticGestureCompleted(SyntheticGesture::Result result);
@@ -693,10 +668,17 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// which may get in recursive loops).
void DelayedAutoResized();
+ void WindowOldSnapshotReachedScreen(int snapshot_id);
+
void WindowSnapshotReachedScreen(int snapshot_id);
- // Send a message to the renderer process to change the accessibility mode.
- void SetAccessibilityMode(AccessibilityMode AccessibilityMode);
+ void OnSnapshotDataReceived(int snapshot_id,
+ const unsigned char* png,
+ size_t size);
+
+ void OnSnapshotDataReceivedAsync(
+ int snapshot_id,
+ scoped_refptr<base::RefCountedBytes> png_data);
// Our delegate, which wants to know mainly about keyboard events.
// It will remain non-NULL until DetachDelegate() is called.
@@ -716,7 +698,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// Indicates whether a page is loading or not.
bool is_loading_;
- // Indicates whether a page is hidden or not.
+ // Indicates whether a page is hidden or not. It has to stay in sync with the
+ // most recent call to process_->WidgetRestored() / WidgetHidden().
bool is_hidden_;
// Indicates whether a page is fullscreen or not.
@@ -742,9 +725,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// The size of the view's backing surface in non-DPI-adjusted pixels.
gfx::Size physical_backing_size_;
- // The height of the physical backing surface that is overdrawn opaquely in
- // the browser, for example by an on-screen-keyboard (in DPI-adjusted pixels).
- float overdraw_bottom_height_;
+ // The amount that the viewport size given to Blink was shrunk by the URL-bar
+ // (always 0 on platforms where URL-bar hiding isn't supported).
+ float top_controls_layout_height_;
// The size of the visible viewport, which may be smaller than the view if the
// view is partially occluded (e.g. by a virtual keyboard). The size is in
@@ -769,8 +752,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
gfx::Rect last_view_screen_rect_;
gfx::Rect last_window_screen_rect_;
- AccessibilityMode accessibility_mode_;
-
// Keyboard event listeners.
std::vector<KeyPressEventCallback> key_press_event_callbacks_;
@@ -834,9 +815,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// changed.
bool suppress_next_char_events_;
- // The last scroll offset of the render widget.
- gfx::Vector2d last_scroll_offset_;
-
bool pending_mouse_lock_request_;
bool allow_privileged_mouse_lock_;
@@ -845,8 +823,6 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// not sent to the renderer.
bool has_touch_handler_;
- base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_;
-
scoped_ptr<SyntheticGestureController> synthetic_gesture_controller_;
scoped_ptr<TouchEmulator> touch_emulator_;
@@ -862,6 +838,15 @@ class CONTENT_EXPORT RenderWidgetHostImpl
int64 last_input_number_;
+ int next_browser_snapshot_id_;
+ typedef std::map<int,
+ base::Callback<void(const unsigned char*, size_t)> > PendingSnapshotMap;
+ PendingSnapshotMap pending_browser_snapshots_;
+
+ cc::RollingTimeDeltaHistory browser_composite_latency_history_;
+
+ base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostImpl);
};
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 710719c7706..830ab01ed0c 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -9,6 +9,7 @@
#include "base/memory/shared_memory.h"
#include "base/timer/timer.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/input/input_router_impl.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
@@ -28,13 +29,15 @@
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#endif
+#if defined(USE_AURA) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
+#endif
+
#if defined(USE_AURA)
-#include "content/browser/compositor/image_transport_factory.h"
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/browser/renderer_host/ui_events_helper.h"
#include "ui/aura/env.h"
#include "ui/aura/test/test_screen.h"
-#include "ui/compositor/test/in_process_context_factory.h"
#include "ui/events/event.h"
#endif
@@ -64,50 +67,45 @@ class MockInputRouter : public InputRouter {
message_received_(false),
client_(client) {
}
- virtual ~MockInputRouter() {}
+ ~MockInputRouter() override {}
// InputRouter
- virtual void Flush() OVERRIDE {
- flush_called_ = true;
- }
- virtual bool SendInput(scoped_ptr<IPC::Message> message) OVERRIDE {
+ void Flush() override { flush_called_ = true; }
+ bool SendInput(scoped_ptr<IPC::Message> message) override {
send_event_called_ = true;
return true;
}
- virtual void SendMouseEvent(
- const MouseEventWithLatencyInfo& mouse_event) OVERRIDE {
+ void SendMouseEvent(const MouseEventWithLatencyInfo& mouse_event) override {
sent_mouse_event_ = true;
}
- virtual void SendWheelEvent(
- const MouseWheelEventWithLatencyInfo& wheel_event) OVERRIDE {
+ void SendWheelEvent(
+ const MouseWheelEventWithLatencyInfo& wheel_event) override {
sent_wheel_event_ = true;
}
- virtual void SendKeyboardEvent(
- const NativeWebKeyboardEvent& key_event,
- const ui::LatencyInfo& latency_info,
- bool is_shortcut) OVERRIDE {
+ void SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
+ const ui::LatencyInfo& latency_info,
+ bool is_shortcut) override {
sent_keyboard_event_ = true;
}
- virtual void SendGestureEvent(
- const GestureEventWithLatencyInfo& gesture_event) OVERRIDE {
+ void SendGestureEvent(
+ const GestureEventWithLatencyInfo& gesture_event) override {
sent_gesture_event_ = true;
}
- virtual void SendTouchEvent(
- const TouchEventWithLatencyInfo& touch_event) OVERRIDE {
+ void SendTouchEvent(const TouchEventWithLatencyInfo& touch_event) override {
send_touch_event_not_cancelled_ =
client_->FilterInputEvent(touch_event.event, touch_event.latency) ==
INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
- virtual const NativeWebKeyboardEvent* GetLastKeyboardEvent() const OVERRIDE {
+ const NativeWebKeyboardEvent* GetLastKeyboardEvent() const override {
NOTREACHED();
return NULL;
}
- virtual bool ShouldForwardTouchEvent() const OVERRIDE { return true; }
- virtual void OnViewUpdated(int view_flags) OVERRIDE {}
- virtual bool HasPendingEvents() const OVERRIDE { return false; }
+ bool ShouldForwardTouchEvent() const override { return true; }
+ void OnViewUpdated(int view_flags) override {}
+ bool HasPendingEvents() const override { return false; }
// IPC::Listener
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ bool OnMessageReceived(const IPC::Message& message) override {
message_received_ = true;
return false;
}
@@ -148,9 +146,8 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl {
using RenderWidgetHostImpl::resize_ack_pending_;
using RenderWidgetHostImpl::input_router_;
- virtual void OnTouchEventAck(
- const TouchEventWithLatencyInfo& event,
- InputEventAckState ack_result) OVERRIDE {
+ void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result) override {
// Sniff touch acks.
acked_touch_event_type_ = event.event.type;
RenderWidgetHostImpl::OnTouchEventAck(event, ack_result);
@@ -160,7 +157,7 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl {
return unresponsive_timer_fired_;
}
- void set_hung_renderer_delay_ms(int delay_ms) {
+ void set_hung_renderer_delay_ms(int64 delay_ms) {
hung_renderer_delay_ms_ = delay_ms;
}
@@ -182,7 +179,7 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl {
}
protected:
- virtual void NotifyRendererUnresponsive() OVERRIDE {
+ void NotifyRendererUnresponsive() override {
unresponsive_timer_fired_ = true;
}
@@ -200,15 +197,10 @@ class RenderWidgetHostProcess : public MockRenderProcessHost {
public:
explicit RenderWidgetHostProcess(BrowserContext* browser_context)
: MockRenderProcessHost(browser_context),
- update_msg_should_reply_(false),
update_msg_reply_flags_(0) {
}
- virtual ~RenderWidgetHostProcess() {
- }
+ ~RenderWidgetHostProcess() override {}
- void set_update_msg_should_reply(bool reply) {
- update_msg_should_reply_ = reply;
- }
void set_update_msg_reply_flags(int flags) {
update_msg_reply_flags_ = flags;
}
@@ -216,17 +208,9 @@ class RenderWidgetHostProcess : public MockRenderProcessHost {
// Fills the given update parameters with resonable default values.
void InitUpdateRectParams(ViewHostMsg_UpdateRect_Params* params);
- virtual bool HasConnection() const OVERRIDE { return true; }
+ bool HasConnection() const override { return true; }
protected:
- virtual bool WaitForBackingStoreMsg(int render_widget_id,
- const base::TimeDelta& max_delay,
- IPC::Message* msg) OVERRIDE;
-
- // Set to true when WaitForBackingStoreMsg should return a successful update
- // message reply. False implies timeout.
- bool update_msg_should_reply_;
-
// Indicates the flags that should be sent with a repaint request. This
// only has an effect when update_msg_should_reply_ is true.
int update_msg_reply_flags_;
@@ -242,22 +226,6 @@ void RenderWidgetHostProcess::InitUpdateRectParams(
params->flags = update_msg_reply_flags_;
}
-bool RenderWidgetHostProcess::WaitForBackingStoreMsg(
- int render_widget_id,
- const base::TimeDelta& max_delay,
- IPC::Message* msg) {
- if (!update_msg_should_reply_)
- return false;
-
- // Construct a fake update reply.
- ViewHostMsg_UpdateRect_Params params;
- InitUpdateRectParams(&params);
-
- ViewHostMsg_UpdateRect message(render_widget_id, params);
- *msg = message;
- return true;
-}
-
// TestView --------------------------------------------------------------------
// This test view allows us to specify the size, and keep track of acked
@@ -303,33 +271,31 @@ class TestView : public TestRenderWidgetHostView {
}
// RenderWidgetHostView override.
- virtual gfx::Rect GetViewBounds() const OVERRIDE {
- return bounds_;
- }
- virtual void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) OVERRIDE {
+ gfx::Rect GetViewBounds() const override { return bounds_; }
+ void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result) override {
acked_event_ = touch.event;
++acked_event_count_;
}
- virtual void WheelEventAck(const WebMouseWheelEvent& event,
- InputEventAckState ack_result) OVERRIDE {
+ void WheelEventAck(const WebMouseWheelEvent& event,
+ InputEventAckState ack_result) override {
if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
return;
unhandled_wheel_event_count_++;
unhandled_wheel_event_ = event;
}
- virtual void GestureEventAck(const WebGestureEvent& event,
- InputEventAckState ack_result) OVERRIDE {
+ void GestureEventAck(const WebGestureEvent& event,
+ InputEventAckState ack_result) override {
gesture_event_type_ = event.type;
ack_result_ = ack_result;
}
- virtual gfx::Size GetPhysicalBackingSize() const OVERRIDE {
+ gfx::Size GetPhysicalBackingSize() const override {
if (use_fake_physical_backing_size_)
return mock_physical_backing_size_;
return TestRenderWidgetHostView::GetPhysicalBackingSize();
}
#if defined(USE_AURA)
- virtual ~TestView() {
+ ~TestView() override {
// Simulate the mouse exit event dispatched when an aura window is
// destroyed. (MakeWebMouseEventFromAuraEvent translates ET_MOUSE_EXITED
// into WebInputEvent::MouseMove.)
@@ -367,7 +333,7 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
handle_wheel_event_(false),
handle_wheel_event_called_(false) {
}
- virtual ~MockRenderWidgetHostDelegate() {}
+ ~MockRenderWidgetHostDelegate() override {}
// Tests that make sure we ignore keyboard event acknowledgments to events we
// didn't send work by making sure we didn't call UnhandledKeyboardEvent().
@@ -400,21 +366,19 @@ class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
}
protected:
- virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
- bool* is_keyboard_shortcut) OVERRIDE {
+ bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) override {
prehandle_keyboard_event_type_ = event.type;
prehandle_keyboard_event_called_ = true;
return prehandle_keyboard_event_;
}
- virtual void HandleKeyboardEvent(
- const NativeWebKeyboardEvent& event) OVERRIDE {
+ void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) override {
unhandled_keyboard_event_type_ = event.type;
unhandled_keyboard_event_called_ = true;
}
- virtual bool HandleWheelEvent(
- const blink::WebMouseWheelEvent& event) OVERRIDE {
+ bool HandleWheelEvent(const blink::WebMouseWheelEvent& event) override {
handle_wheel_event_called_ = true;
return handle_wheel_event_;
}
@@ -443,8 +407,7 @@ class RenderWidgetHostTest : public testing::Test {
last_simulated_event_time_seconds_ =
(base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
}
- virtual ~RenderWidgetHostTest() {
- }
+ ~RenderWidgetHostTest() override {}
bool KeyPressEventCallback(const NativeWebKeyboardEvent& /* event */) {
return handle_key_press_event_;
@@ -455,16 +418,21 @@ class RenderWidgetHostTest : public testing::Test {
protected:
// testing::Test
- virtual void SetUp() {
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ void SetUp() override {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitch(switches::kValidateInputEventStream);
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 (IsDelegatedRendererEnabled()) {
+ ImageTransportFactory::InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactory>(
+ new NoTransportImageTransportFactory));
+ }
+#endif
#if defined(USE_AURA)
- ImageTransportFactory::InitializeForUnitTests(
- scoped_ptr<ui::ContextFactory>(new ui::InProcessContextFactory));
aura::Env::CreateInstance(true);
screen_.reset(aura::TestScreen::Create(gfx::Size()));
gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
@@ -476,7 +444,7 @@ class RenderWidgetHostTest : public testing::Test {
host_->Init();
host_->DisableGestureDebounce();
}
- virtual void TearDown() {
+ void TearDown() override {
view_.reset();
host_.reset();
delegate_.reset();
@@ -486,7 +454,10 @@ class RenderWidgetHostTest : public testing::Test {
#if defined(USE_AURA)
aura::Env::DeleteInstance();
screen_.reset();
- ImageTransportFactory::Terminate();
+#endif
+#if defined(USE_AURA) || (defined(OS_MACOSX) && !defined(OS_IOS))
+ if (IsDelegatedRendererEnabled())
+ ImageTransportFactory::Terminate();
#endif
// Process all pending tasks to avoid leaks.
@@ -779,7 +750,7 @@ TEST_F(RenderWidgetHostTest, ResizeThenCrash) {
TEST_F(RenderWidgetHostTest, Background) {
scoped_ptr<RenderWidgetHostViewBase> view;
#if defined(USE_AURA)
- view.reset(new RenderWidgetHostViewAura(host_.get()));
+ view.reset(new RenderWidgetHostViewAura(host_.get(), false));
// TODO(derat): Call this on all platforms: http://crbug.com/102450.
view->InitAsChild(NULL);
#elif defined(OS_ANDROID)
@@ -788,7 +759,7 @@ TEST_F(RenderWidgetHostTest, Background) {
host_->SetView(view.get());
EXPECT_TRUE(view->GetBackgroundOpaque());
- view->SetBackgroundOpaque(false);
+ view->SetBackgroundColor(SK_ColorTRANSPARENT);
EXPECT_FALSE(view->GetBackgroundOpaque());
const IPC::Message* set_background =
@@ -825,14 +796,14 @@ TEST_F(RenderWidgetHostTest, HiddenPaint) {
// Now unhide.
process_->sink().ClearMessages();
- host_->WasShown();
+ host_->WasShown(ui::LatencyInfo());
EXPECT_FALSE(host_->is_hidden_);
// It should have sent out a restored message with a request to paint.
const IPC::Message* restored = process_->sink().GetUniqueMessageMatching(
ViewMsg_WasShown::ID);
ASSERT_TRUE(restored);
- Tuple1<bool> needs_repaint;
+ Tuple2<bool, ui::LatencyInfo> needs_repaint;
ViewMsg_WasShown::Read(restored, &needs_repaint);
EXPECT_TRUE(needs_repaint.a);
}
@@ -1049,8 +1020,7 @@ TEST_F(RenderWidgetHostTest, TouchEmulator) {
simulated_event_time_delta_seconds_ = 0.1;
// Immediately ack all touches instead of sending them to the renderer.
host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
- host_->OnMessageReceived(
- ViewHostMsg_SetTouchEventEmulationEnabled(0, true, true));
+ host_->SetTouchEventEmulationEnabled(true);
process_->sink().ClearMessages();
view_->set_bounds(gfx::Rect(0, 0, 400, 200));
view_->Show();
@@ -1149,8 +1119,7 @@ TEST_F(RenderWidgetHostTest, TouchEmulator) {
EXPECT_EQ(0U, process_->sink().message_count());
// Turn off emulation during a pinch.
- host_->OnMessageReceived(
- ViewHostMsg_SetTouchEventEmulationEnabled(0, false, false));
+ host_->SetTouchEventEmulationEnabled(false);
EXPECT_EQ(WebInputEvent::TouchCancel, host_->acked_touch_event_type());
EXPECT_EQ("GesturePinchEnd GestureScrollEnd",
GetInputMessageTypes(process_));
@@ -1165,8 +1134,7 @@ TEST_F(RenderWidgetHostTest, TouchEmulator) {
EXPECT_EQ(0U, process_->sink().message_count());
// Turn on emulation.
- host_->OnMessageReceived(
- ViewHostMsg_SetTouchEventEmulationEnabled(0, true, true));
+ host_->SetTouchEventEmulationEnabled(true);
EXPECT_EQ(0U, process_->sink().message_count());
// Another touch.
@@ -1185,8 +1153,7 @@ TEST_F(RenderWidgetHostTest, TouchEmulator) {
INPUT_EVENT_ACK_STATE_CONSUMED);
// Turn off emulation during a scroll.
- host_->OnMessageReceived(
- ViewHostMsg_SetTouchEventEmulationEnabled(0, false, false));
+ host_->SetTouchEventEmulationEnabled(false);
EXPECT_EQ(WebInputEvent::TouchCancel, host_->acked_touch_event_type());
EXPECT_EQ("GestureScrollEnd", GetInputMessageTypes(process_));
@@ -1334,7 +1301,7 @@ TEST_F(RenderWidgetHostTest, InputRouterReceivesHandleInputEvent_ACK) {
TEST_F(RenderWidgetHostTest, InputRouterReceivesMoveCaret_ACK) {
host_->SetupForInputRouterTest();
- host_->OnMessageReceived(ViewHostMsg_MoveCaret_ACK(0));
+ host_->OnMessageReceived(InputHostMsg_MoveCaret_ACK(0));
EXPECT_TRUE(host_->mock_input_router()->message_received_);
}
@@ -1342,7 +1309,7 @@ TEST_F(RenderWidgetHostTest, InputRouterReceivesMoveCaret_ACK) {
TEST_F(RenderWidgetHostTest, InputRouterReceivesSelectRange_ACK) {
host_->SetupForInputRouterTest();
- host_->OnMessageReceived(ViewHostMsg_SelectRange_ACK(0));
+ host_->OnMessageReceived(InputHostMsg_SelectRange_ACK(0));
EXPECT_TRUE(host_->mock_input_router()->message_received_);
}
@@ -1355,21 +1322,24 @@ TEST_F(RenderWidgetHostTest, InputRouterReceivesHasTouchEventHandlers) {
EXPECT_TRUE(host_->mock_input_router()->message_received_);
}
-
-void CheckLatencyInfoComponentInMessage(RenderWidgetHostProcess* process,
- int64 component_id,
- WebInputEvent::Type input_type) {
+ui::LatencyInfo GetLatencyInfoFromInputEvent(RenderWidgetHostProcess* process) {
const IPC::Message* message = process->sink().GetUniqueMessageMatching(
InputMsg_HandleInputEvent::ID);
- ASSERT_TRUE(message);
+ EXPECT_TRUE(message);
InputMsg_HandleInputEvent::Param params;
EXPECT_TRUE(InputMsg_HandleInputEvent::Read(message, &params));
- ui::LatencyInfo latency_info = params.b;
+ process->sink().ClearMessages();
+ return params.b;
+}
+
+void CheckLatencyInfoComponentInMessage(RenderWidgetHostProcess* process,
+ int64 component_id,
+ WebInputEvent::Type input_type) {
+ ui::LatencyInfo latency_info = GetLatencyInfoFromInputEvent(process);
EXPECT_TRUE(latency_info.FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
component_id,
NULL));
- process->sink().ClearMessages();
}
// Tests that after input event passes through RWHI through ForwardXXXEvent()
@@ -1428,6 +1398,79 @@ TEST_F(RenderWidgetHostTest, InputEventRWHLatencyComponent) {
SendInputEventACK(WebInputEvent::TouchStart, INPUT_EVENT_ACK_STATE_CONSUMED);
}
+// Tests that after input event passes through RWHI through
+// ForwardXXXEventWithLatencyInfo(), input event coordinates will be present in
+// the latency info.
+TEST_F(RenderWidgetHostTest, InputEventRWHLatencyInfoCoordinates) {
+ host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+ process_->sink().ClearMessages();
+
+ {
+ WebMouseWheelEvent event =
+ SyntheticWebMouseWheelEventBuilder::Build(-5, 0, 0, true);
+ event.x = 100;
+ event.y = 200;
+ host_->ForwardWheelEvent(event);
+ ui::LatencyInfo latency_info = GetLatencyInfoFromInputEvent(process_);
+ 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);
+ SendInputEventACK(WebInputEvent::MouseWheel,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ }
+
+ {
+ WebMouseEvent event =
+ SyntheticWebMouseEventBuilder::Build(WebInputEvent::MouseMove);
+ event.x = 300;
+ event.y = 400;
+ host_->ForwardMouseEvent(event);
+ ui::LatencyInfo latency_info = GetLatencyInfoFromInputEvent(process_);
+ 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);
+ SendInputEventACK(WebInputEvent::MouseMove, INPUT_EVENT_ACK_STATE_CONSUMED);
+ }
+
+ {
+ WebGestureEvent event = SyntheticWebGestureEventBuilder::Build(
+ WebInputEvent::GestureScrollBegin, blink::WebGestureDeviceTouchscreen);
+ event.x = 500;
+ event.y = 600;
+ host_->ForwardGestureEvent(event);
+ ui::LatencyInfo latency_info = GetLatencyInfoFromInputEvent(process_);
+ 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);
+ SendInputEventACK(WebInputEvent::GestureScrollBegin,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ }
+
+ {
+ PressTouchPoint(700, 800);
+ PressTouchPoint(900, 1000);
+ PressTouchPoint(1100, 1200); // LatencyInfo only holds two coordinates.
+ SendTouchEvent();
+ ui::LatencyInfo latency_info = GetLatencyInfoFromInputEvent(process_);
+ 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);
+ EXPECT_EQ(900, latency_info.input_coordinates[1].x);
+ EXPECT_EQ(1000, latency_info.input_coordinates[1].y);
+ SendInputEventACK(WebInputEvent::TouchStart,
+ INPUT_EVENT_ACK_STATE_CONSUMED);
+ }
+
+ {
+ NativeWebKeyboardEvent event;
+ event.type = WebKeyboardEvent::KeyDown;
+ host_->ForwardKeyboardEvent(event);
+ ui::LatencyInfo latency_info = GetLatencyInfoFromInputEvent(process_);
+ EXPECT_EQ(0u, latency_info.input_coordinates_size);
+ SendInputEventACK(WebInputEvent::KeyDown, INPUT_EVENT_ACK_STATE_CONSUMED);
+ }
+}
+
TEST_F(RenderWidgetHostTest, RendererExitedResetsInputRouter) {
// RendererExited will delete the view.
host_->SetView(new TestView(host_.get()));
@@ -1437,4 +1480,18 @@ TEST_F(RenderWidgetHostTest, RendererExitedResetsInputRouter) {
ASSERT_FALSE(host_->input_router()->HasPendingEvents());
}
+// Regression test for http://crbug.com/401859.
+TEST_F(RenderWidgetHostTest, RendererExitedResetsIsHidden) {
+ // RendererExited will delete the view.
+ host_->SetView(new TestView(host_.get()));
+ host_->WasHidden();
+
+ ASSERT_TRUE(host_->is_hidden());
+ host_->RendererExited(base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
+ ASSERT_FALSE(host_->is_hidden());
+
+ // Make sure the input router is in a fresh state.
+ ASSERT_FALSE(host_->input_router()->HasPendingEvents());
+}
+
} // namespace content
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 f4217357c75..e8a4f55e0c8 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
@@ -6,7 +6,7 @@
#include <android/bitmap.h>
-#include "base/android/sys_utils.h"
+#include "base/android/build_info.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
@@ -15,6 +15,7 @@
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
#include "base/threading/worker_pool.h"
#include "cc/base/latency_info_swap_promise.h"
#include "cc/layers/delegated_frame_provider.h"
@@ -24,10 +25,14 @@
#include "cc/output/compositor_frame_ack.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
+#include "cc/output/viewport_selection_bound.h"
#include "cc/resources/single_release_callback.h"
#include "cc/trees/layer_tree_host.h"
#include "content/browser/accessibility/browser_accessibility_manager_android.h"
+#include "content/browser/android/composited_touch_handle_drawable.h"
#include "content/browser/android/content_view_core_impl.h"
+#include "content/browser/android/edge_effect.h"
+#include "content/browser/android/edge_effect_l.h"
#include "content/browser/android/in_process/synchronous_compositor_impl.h"
#include "content/browser/android/overscroll_glow.h"
#include "content/browser/devtools/render_view_devtools_agent_host.h"
@@ -40,6 +45,8 @@
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/image_transport_factory_android.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_android.h"
+#include "content/browser/renderer_host/input/touch_selection_controller.h"
+#include "content/browser/renderer_host/input/web_input_event_builders_android.h"
#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
@@ -61,10 +68,11 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/android/window_android.h"
#include "ui/base/android/window_android_compositor.h"
-#include "ui/events/gesture_detection/gesture_config_helper.h"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/events/gesture_detection/motion_event.h"
#include "ui/gfx/android/device_display_info.h"
#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/android/view_configuration.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size_conversions.h"
@@ -80,6 +88,9 @@ const int kUndefinedOutputSurfaceId = -1;
// V1 saw errors of ~0.065 between computed window and content widths.
const float kMobileViewportWidthEpsilon = 0.15f;
+// Used for conditional creation of EdgeEffect types for overscroll.
+const int kKitKatMR2SDKVersion = 19;
+
static const char kAsyncReadBackString[] = "Compositing.CopyFromSurfaceTime";
// Sends an acknowledgement to the renderer of a processed IME event.
@@ -94,8 +105,17 @@ void CopyFromCompositingSurfaceFinished(
const base::TimeTicks& start_time,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
bool result) {
+ TRACE_EVENT0(
+ "cc", "RenderWidgetHostViewAndroid::CopyFromCompositingSurfaceFinished");
bitmap_pixels_lock.reset();
- release_callback->Run(0, false);
+ uint32 sync_point = 0;
+ if (result) {
+ GLHelper* gl_helper =
+ ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
+ sync_point = gl_helper->InsertSyncPoint();
+ }
+ bool lost_resource = sync_point == 0;
+ release_callback->Run(sync_point, lost_resource);
UMA_HISTOGRAM_TIMES(kAsyncReadBackString,
base::TimeTicks::Now() - start_time);
callback.Run(result, *bitmap);
@@ -126,28 +146,81 @@ OverscrollGlow::DisplayParameters CreateOverscrollDisplayParameters(
// the viewport and offset by the distance of each viewport edge to the
// respective content edge.
OverscrollGlow::DisplayParameters params;
- params.size = gfx::ScaleSize(frame_metadata.viewport_size, scale_factor);
- params.edge_offsets[EdgeEffect::EDGE_TOP] =
+ params.size = gfx::ScaleSize(
+ frame_metadata.scrollable_viewport_size, scale_factor);
+ params.edge_offsets[OverscrollGlow::EDGE_TOP] =
-frame_metadata.root_scroll_offset.y() * scale_factor;
- params.edge_offsets[EdgeEffect::EDGE_LEFT] =
+ params.edge_offsets[OverscrollGlow::EDGE_LEFT] =
-frame_metadata.root_scroll_offset.x() * scale_factor;
- params.edge_offsets[EdgeEffect::EDGE_BOTTOM] =
+ params.edge_offsets[OverscrollGlow::EDGE_BOTTOM] =
(frame_metadata.root_layer_size.height() -
frame_metadata.root_scroll_offset.y() -
- frame_metadata.viewport_size.height()) * scale_factor;
- params.edge_offsets[EdgeEffect::EDGE_RIGHT] =
+ frame_metadata.scrollable_viewport_size.height()) *
+ scale_factor;
+ params.edge_offsets[OverscrollGlow::EDGE_RIGHT] =
(frame_metadata.root_layer_size.width() -
frame_metadata.root_scroll_offset.x() -
- frame_metadata.viewport_size.width()) * scale_factor;
- params.device_scale_factor = frame_metadata.device_scale_factor;
+ frame_metadata.scrollable_viewport_size.width()) *
+ scale_factor;
return params;
}
+bool UseEdgeEffectL() {
+ static bool use_edge_effect_l =
+ base::android::BuildInfo::GetInstance()->sdk_int() > kKitKatMR2SDKVersion;
+ return use_edge_effect_l;
+}
+
+scoped_ptr<EdgeEffectBase> CreateEdgeEffect(
+ ui::SystemUIResourceManager* resource_manager,
+ float device_scale_factor) {
+ DCHECK(resource_manager);
+ if (UseEdgeEffectL())
+ return scoped_ptr<EdgeEffectBase>(new EdgeEffectL(resource_manager));
+
+ return scoped_ptr<EdgeEffectBase>(
+ new EdgeEffect(resource_manager, device_scale_factor));
+}
+
+scoped_ptr<OverscrollGlow> CreateOverscrollEffect(
+ ContentViewCore* content_view_core) {
+ DCHECK(content_view_core);
+ ui::WindowAndroidCompositor* compositor =
+ content_view_core->GetWindowAndroid()->GetCompositor();
+ DCHECK(compositor);
+ ui::SystemUIResourceManager* system_resource_manager =
+ &compositor->GetSystemUIResourceManager();
+
+ if (UseEdgeEffectL())
+ EdgeEffectL::PreloadResources(system_resource_manager);
+ else
+ EdgeEffect::PreloadResources(system_resource_manager);
+
+ return make_scoped_ptr(
+ new OverscrollGlow(base::Bind(&CreateEdgeEffect,
+ system_resource_manager,
+ content_view_core->GetDpiScale())));
+}
+
+scoped_ptr<TouchSelectionController> CreateSelectionController(
+ TouchSelectionControllerClient* client,
+ ContentViewCore* content_view_core) {
+ DCHECK(client);
+ DCHECK(content_view_core);
+ int tap_timeout_ms = gfx::ViewConfiguration::GetTapTimeoutInMs();
+ int touch_slop_pixels = gfx::ViewConfiguration::GetTouchSlopInPixels();
+ return make_scoped_ptr(new TouchSelectionController(
+ client,
+ base::TimeDelta::FromMilliseconds(tap_timeout_ms),
+ touch_slop_pixels / content_view_core->GetDpiScale()));
+}
+
ui::GestureProvider::Config CreateGestureProviderConfig() {
ui::GestureProvider::Config config = ui::DefaultGestureProviderConfig();
config.disable_click_delay =
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableClickDelay);
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableClickDelay);
return config;
}
@@ -158,13 +231,31 @@ bool HasFixedPageScale(const cc::CompositorFrameMetadata& frame_metadata) {
bool HasMobileViewport(const cc::CompositorFrameMetadata& frame_metadata) {
float window_width_dip =
- frame_metadata.page_scale_factor * frame_metadata.viewport_size.width();
+ frame_metadata.page_scale_factor *
+ frame_metadata.scrollable_viewport_size.width();
float content_width_css = frame_metadata.root_layer_size.width();
return content_width_css <= window_width_dip + kMobileViewportWidthEpsilon;
}
} // anonymous namespace
+ReadbackRequest::ReadbackRequest(
+ float scale,
+ SkColorType color_type,
+ gfx::Rect src_subrect,
+ const base::Callback<void(bool, const SkBitmap&)>& result_callback)
+ : scale_(scale),
+ color_type_(color_type),
+ src_subrect_(src_subrect),
+ result_callback_(result_callback) {
+}
+
+ReadbackRequest::ReadbackRequest() {
+}
+
+ReadbackRequest::~ReadbackRequest() {
+}
+
RenderWidgetHostViewAndroid::LastFrameInfo::LastFrameInfo(
uint32 output_id,
scoped_ptr<cc::CompositorFrame> output_frame)
@@ -176,25 +267,25 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
RenderWidgetHostImpl* widget_host,
ContentViewCoreImpl* content_view_core)
: host_(widget_host),
- needs_begin_frame_(false),
+ outstanding_vsync_requests_(0),
is_showing_(!widget_host->is_hidden()),
content_view_core_(NULL),
ime_adapter_android_(this),
cached_background_color_(SK_ColorWHITE),
last_output_surface_id_(kUndefinedOutputSurfaceId),
- weak_ptr_factory_(this),
- overscroll_effect_enabled_(!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOverscrollEdgeEffect)),
- overscroll_effect_(OverscrollGlow::Create(overscroll_effect_enabled_)),
+ overscroll_effect_enabled_(
+ !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableOverscrollEdgeEffect)),
gesture_provider_(CreateGestureProviderConfig(), this),
- flush_input_requested_(false),
+ gesture_text_selector_(this),
accelerated_surface_route_id_(0),
using_synchronous_compositor_(SynchronousCompositorImpl::FromID(
widget_host->GetProcess()->GetID(),
widget_host->GetRoutingID()) != NULL),
frame_evictor_(new DelegatedFrameEvictor(this)),
locks_on_frame_count_(0),
- observing_root_window_(false) {
+ observing_root_window_(false),
+ weak_ptr_factory_(this) {
host_->SetView(this);
SetContentViewCore(content_view_core);
ImageTransportFactoryAndroid::AddObserver(this);
@@ -204,6 +295,7 @@ RenderWidgetHostViewAndroid::~RenderWidgetHostViewAndroid() {
ImageTransportFactoryAndroid::RemoveObserver(this);
SetContentViewCore(NULL);
DCHECK(ack_callbacks_.empty());
+ DCHECK(readbacks_waiting_for_frame_.empty());
if (resource_collection_.get())
resource_collection_->SetClient(NULL);
}
@@ -218,6 +310,8 @@ bool RenderWidgetHostViewAndroid::OnMessageReceived(
OnDidChangeBodyBackgroundColor)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetNeedsBeginFrame,
OnSetNeedsBeginFrame)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
+ OnTextInputStateChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_SmartClipDataExtracted,
OnSmartClipDataExtracted)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -248,12 +342,11 @@ void RenderWidgetHostViewAndroid::WasShown() {
if (!host_ || !host_->is_hidden())
return;
- host_->WasShown();
+ host_->WasShown(ui::LatencyInfo());
- if (content_view_core_ && !using_synchronous_compositor_) {
- content_view_core_->GetWindowAndroid()->AddObserver(this);
- content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
- observing_root_window_ = true;
+ if (content_view_core_) {
+ StartObservingRootWindow();
+ RequestVSyncUpdate(BEGIN_FRAME);
}
}
@@ -267,10 +360,7 @@ void RenderWidgetHostViewAndroid::WasHidden() {
// utilization.
host_->WasHidden();
- if (content_view_core_ && !using_synchronous_compositor_) {
- content_view_core_->GetWindowAndroid()->RemoveObserver(this);
- observing_root_window_ = false;
- }
+ StopObservingRootWindow();
}
void RenderWidgetHostViewAndroid::WasResized() {
@@ -287,15 +377,31 @@ void RenderWidgetHostViewAndroid::SetBounds(const gfx::Rect& rect) {
SetSize(rect.size());
}
+void RenderWidgetHostViewAndroid::AbortPendingReadbackRequests() {
+ while (!readbacks_waiting_for_frame_.empty()) {
+ ReadbackRequest& readback_request = readbacks_waiting_for_frame_.front();
+ readback_request.GetResultCallback().Run(false, SkBitmap());
+ readbacks_waiting_for_frame_.pop();
+ }
+}
+
void RenderWidgetHostViewAndroid::GetScaledContentBitmap(
float scale,
- SkBitmap::Config bitmap_config,
+ SkColorType color_type,
gfx::Rect src_subrect,
- const base::Callback<void(bool, const SkBitmap&)>& result_callback) {
- if (!IsSurfaceAvailableForCopy()) {
+ CopyFromCompositingSurfaceCallback& result_callback) {
+ if (!host_ || host_->is_hidden()) {
result_callback.Run(false, SkBitmap());
return;
}
+ if (!IsSurfaceAvailableForCopy()) {
+ // The view is visible, probably the frame has not yet arrived.
+ // Just add the ReadbackRequest to queue and wait for frame arrival
+ // to get this request processed.
+ readbacks_waiting_for_frame_.push(
+ ReadbackRequest(scale, color_type, src_subrect, result_callback));
+ return;
+ }
gfx::Size bounds = layer_->bounds();
if (src_subrect.IsEmpty())
@@ -309,24 +415,41 @@ void RenderWidgetHostViewAndroid::GetScaledContentBitmap(
gfx::Size dst_size(
gfx::ToCeiledSize(gfx::ScaleSize(bounds, scale / device_scale_factor)));
CopyFromCompositingSurface(
- src_subrect, dst_size, result_callback, bitmap_config);
+ src_subrect, dst_size, result_callback, color_type);
+}
+
+scoped_refptr<cc::DelegatedRendererLayer>
+RenderWidgetHostViewAndroid::CreateDelegatedLayerForFrameProvider() const {
+ DCHECK(frame_provider_.get());
+
+ scoped_refptr<cc::DelegatedRendererLayer> delegated_layer =
+ cc::DelegatedRendererLayer::Create(frame_provider_);
+ delegated_layer->SetBounds(content_size_in_layer_);
+ delegated_layer->SetIsDrawable(true);
+ delegated_layer->SetContentsOpaque(true);
+
+ return delegated_layer;
}
bool RenderWidgetHostViewAndroid::HasValidFrame() const {
if (!content_view_core_)
return false;
- if (!layer_)
+ if (!layer_.get())
return false;
if (texture_size_in_layer_.IsEmpty())
return false;
-
+ // This tell us whether a valid frame has arrived or not.
if (!frame_evictor_->HasFrame())
return false;
return true;
}
+gfx::Vector2dF RenderWidgetHostViewAndroid::GetLastScrollOffset() const {
+ return last_scroll_offset_;
+}
+
gfx::NativeView RenderWidgetHostViewAndroid::GetNativeView() const {
return content_view_core_->GetViewAndroid();
}
@@ -352,15 +475,15 @@ void RenderWidgetHostViewAndroid::MovePluginWindows(
void RenderWidgetHostViewAndroid::Focus() {
host_->Focus();
host_->SetInputMethodActive(true);
- if (overscroll_effect_enabled_)
+ if (overscroll_effect_)
overscroll_effect_->Enable();
}
void RenderWidgetHostViewAndroid::Blur() {
- host_->ExecuteEditCommand("Unselect", "");
host_->SetInputMethodActive(false);
host_->Blur();
- overscroll_effect_->Disable();
+ if (overscroll_effect_)
+ overscroll_effect_->Disable();
}
bool RenderWidgetHostViewAndroid::HasFocus() const {
@@ -379,7 +502,7 @@ void RenderWidgetHostViewAndroid::Show() {
return;
is_showing_ = true;
- if (layer_)
+ if (layer_.get())
layer_->SetHideLayerAndSubtree(false);
frame_evictor_->SetVisible(true);
@@ -391,10 +514,13 @@ void RenderWidgetHostViewAndroid::Hide() {
return;
is_showing_ = false;
- if (layer_ && locks_on_frame_count_ == 0)
+ if (layer_.get() && locks_on_frame_count_ == 0)
layer_->SetHideLayerAndSubtree(true);
frame_evictor_->SetVisible(false);
+ // We don't know if we will ever get a frame if we are hiding the renderer, so
+ // we need to cancel all requests
+ AbortPendingReadbackRequests();
WasHidden();
}
@@ -428,7 +554,7 @@ void RenderWidgetHostViewAndroid::UnlockCompositingSurface() {
last_frame_info_.reset();
}
- if (!is_showing_ && layer_)
+ if (!is_showing_ && layer_.get())
layer_->SetHideLayerAndSubtree(true);
}
}
@@ -475,11 +601,12 @@ gfx::Size RenderWidgetHostViewAndroid::GetPhysicalBackingSize() const {
return content_view_core_->GetPhysicalBackingSize();
}
-float RenderWidgetHostViewAndroid::GetOverdrawBottomHeight() const {
+float RenderWidgetHostViewAndroid::GetTopControlsLayoutHeight() const {
if (!content_view_core_)
return 0.f;
- return content_view_core_->GetOverdrawBottomHeightDip();
+ // The amount that the viewport size given to Blink is shrunk by the URL-bar.
+ return content_view_core_->GetTopControlsLayoutHeightDip();
}
void RenderWidgetHostViewAndroid::UpdateCursor(const WebCursor& cursor) {
@@ -491,12 +618,29 @@ void RenderWidgetHostViewAndroid::SetIsLoading(bool is_loading) {
// is TabContentsDelegate.
}
+void RenderWidgetHostViewAndroid::TextInputTypeChanged(
+ ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) {
+ // Unused on Android, which uses OnTextInputChanged instead.
+}
+
long RenderWidgetHostViewAndroid::GetNativeImeAdapter() {
return reinterpret_cast<intptr_t>(&ime_adapter_android_);
}
-void RenderWidgetHostViewAndroid::TextInputStateChanged(
+void RenderWidgetHostViewAndroid::OnTextInputStateChanged(
const ViewHostMsg_TextInputState_Params& params) {
+ if (selection_controller_) {
+ // This call is semi-redundant with that in |OnFocusedNodeChanged|. The
+ // latter is guaranteed to be called before |OnSelectionBoundsChanged|,
+ // while this call is present to ensure consistency with IME after
+ // navigation and tab focus changes
+ const bool is_editable_node = params.type != ui::TEXT_INPUT_TYPE_NONE;
+ selection_controller_->OnSelectionEditable(is_editable_node);
+ }
+
// If the change is not originated from IME (e.g. Javascript, autofill),
// send back the renderer an acknowledgement, regardless of how we exit from
// this method.
@@ -509,7 +653,7 @@ void RenderWidgetHostViewAndroid::TextInputStateChanged(
content_view_core_->UpdateImeAdapter(
GetNativeImeAdapter(),
- static_cast<int>(params.type),
+ static_cast<int>(params.type), params.flags,
params.value, params.selection_start, params.selection_end,
params.composition_start, params.composition_end,
params.show_ime_if_needed, params.is_non_ime_change);
@@ -526,15 +670,13 @@ void RenderWidgetHostViewAndroid::OnDidChangeBodyBackgroundColor(
}
void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) {
- if (enabled == needs_begin_frame_)
- return;
-
+ DCHECK(!using_synchronous_compositor_);
TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame",
"enabled", enabled);
- if (content_view_core_ && enabled)
- content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
-
- needs_begin_frame_ = enabled;
+ if (enabled)
+ RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME);
+ else
+ outstanding_vsync_requests_ &= ~PERSISTENT_BEGIN_FRAME;
}
void RenderWidgetHostViewAndroid::OnStartContentIntent(
@@ -544,13 +686,11 @@ void RenderWidgetHostViewAndroid::OnStartContentIntent(
}
void RenderWidgetHostViewAndroid::OnSmartClipDataExtracted(
- const base::string16& result) {
- // Custom serialization over IPC isn't allowed normally for security reasons.
- // Since this feature is only used in (single-process) WebView, there are no
- // security issues. Enforce that it's only called in single process mode.
- CHECK(RenderProcessHost::run_renderer_in_process());
+ const base::string16& text,
+ const base::string16& html,
+ const gfx::Rect rect) {
if (content_view_core_)
- content_view_core_->OnSmartClipDataExtracted(result);
+ content_view_core_->OnSmartClipDataExtracted(text, html, rect);
}
bool RenderWidgetHostViewAndroid::OnTouchEvent(
@@ -558,20 +698,40 @@ bool RenderWidgetHostViewAndroid::OnTouchEvent(
if (!host_)
return false;
+ if (selection_controller_ &&
+ selection_controller_->WillHandleTouchEvent(event))
+ return true;
+
+ if (gesture_text_selector_.OnTouchEvent(event))
+ return true;
+
if (!gesture_provider_.OnTouchEvent(event))
return false;
- // Short-circuit touch forwarding if no touch handlers exist.
- if (!host_->ShouldForwardTouchEvent()) {
+ if (host_->ShouldForwardTouchEvent()) {
+ blink::WebTouchEvent web_event = CreateWebTouchEventFromMotionEvent(event);
+ host_->ForwardTouchEventWithLatencyInfo(web_event,
+ CreateLatencyInfo(web_event));
+ } else {
const bool event_consumed = false;
gesture_provider_.OnTouchEventAck(event_consumed);
- return true;
}
- SendTouchEvent(CreateWebTouchEventFromMotionEvent(event));
+ // Send a proactive BeginFrame on the next vsync to reduce latency.
+ // This is good enough as long as the first touch event has Begin semantics
+ // and the actual scroll happens on the next vsync.
+ if (observing_root_window_)
+ RequestVSyncUpdate(BEGIN_FRAME);
+
return true;
}
+bool RenderWidgetHostViewAndroid::OnTouchHandleEvent(
+ const ui::MotionEvent& event) {
+ return selection_controller_ &&
+ selection_controller_->WillHandleTouchEvent(event);
+}
+
void RenderWidgetHostViewAndroid::ResetGestureDetection() {
const ui::MotionEvent* current_down_event =
gesture_provider_.GetCurrentDownEvent();
@@ -596,8 +756,16 @@ void RenderWidgetHostViewAndroid::ImeCancelComposition() {
ime_adapter_android_.CancelComposition();
}
+void RenderWidgetHostViewAndroid::ImeCompositionRangeChanged(
+ const gfx::Range& range,
+ const std::vector<gfx::Rect>& character_bounds) {
+ ime_adapter_android_.SetCharacterBounds(character_bounds);
+}
+
void RenderWidgetHostViewAndroid::FocusedNodeChanged(bool is_editable_node) {
ime_adapter_android_.FocusedNodeChanged(is_editable_node);
+ if (selection_controller_)
+ selection_controller_->OnSelectionEditable(is_editable_node);
}
void RenderWidgetHostViewAndroid::RenderProcessGone(
@@ -625,8 +793,17 @@ void RenderWidgetHostViewAndroid::SelectionChanged(const base::string16& text,
const gfx::Range& range) {
RenderWidgetHostViewBase::SelectionChanged(text, offset, range);
- if (text.empty() || range.is_empty() || !content_view_core_)
+ if (selection_controller_)
+ selection_controller_->OnSelectionEmpty(text.empty());
+
+ if (!content_view_core_)
+ return;
+ if (range.is_empty()) {
+ content_view_core_->OnSelectionChanged("");
return;
+ }
+
+ DCHECK(!text.empty());
size_t pos = range.GetMin() - offset;
size_t n = range.length();
@@ -643,25 +820,23 @@ void RenderWidgetHostViewAndroid::SelectionChanged(const base::string16& text,
void RenderWidgetHostViewAndroid::SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params) {
- if (content_view_core_) {
- content_view_core_->OnSelectionBoundsChanged(params);
- }
+ NOTREACHED() << "Selection bounds should be routed through the compositor.";
}
-void RenderWidgetHostViewAndroid::ScrollOffsetChanged() {
-}
-
-void RenderWidgetHostViewAndroid::SetBackgroundOpaque(bool opaque) {
- RenderWidgetHostViewBase::SetBackgroundOpaque(opaque);
- host_->SetBackgroundOpaque(opaque);
+void RenderWidgetHostViewAndroid::SetBackgroundColor(SkColor color) {
+ RenderWidgetHostViewBase::SetBackgroundColor(color);
+ host_->SetBackgroundOpaque(GetBackgroundOpaque());
+ OnDidChangeBodyBackgroundColor(color);
}
void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config bitmap_config) {
- if (!IsReadbackConfigSupported(bitmap_config)) {
+ CopyFromCompositingSurfaceCallback& callback,
+ const SkColorType color_type) {
+ TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::CopyFromCompositingSurface");
+ if ((!host_ || host_->is_hidden()) ||
+ !IsReadbackConfigSupported(color_type)) {
callback.Run(false, SkBitmap());
return;
}
@@ -680,7 +855,7 @@ void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
if (using_synchronous_compositor_) {
SynchronousCopyContents(src_subrect_in_pixel, dst_size_in_pixel, callback,
- bitmap_config);
+ color_type);
UMA_HISTOGRAM_TIMES("Compositing.CopyFromSurfaceTimeSynchronous",
base::TimeTicks::Now() - start_time);
return;
@@ -693,13 +868,10 @@ void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
ui::WindowAndroidCompositor* compositor =
content_view_core_->GetWindowAndroid()->GetCompositor();
DCHECK(compositor);
- DCHECK(frame_provider_);
+ DCHECK(frame_provider_.get());
scoped_refptr<cc::DelegatedRendererLayer> delegated_layer =
- cc::DelegatedRendererLayer::Create(frame_provider_);
- delegated_layer->SetBounds(content_size_in_layer_);
+ CreateDelegatedLayerForFrameProvider();
delegated_layer->SetHideLayerAndSubtree(true);
- delegated_layer->SetIsDrawable(true);
- delegated_layer->SetContentsOpaque(true);
compositor->AttachLayerForReadback(delegated_layer);
readback_layer = delegated_layer;
@@ -707,7 +879,7 @@ void RenderWidgetHostViewAndroid::CopyFromCompositingSurface(
base::Bind(&RenderWidgetHostViewAndroid::
PrepareTextureCopyOutputResultForDelegatedReadback,
dst_size_in_pixel,
- bitmap_config,
+ color_type,
start_time,
readback_layer,
callback));
@@ -728,11 +900,11 @@ bool RenderWidgetHostViewAndroid::CanCopyToVideoFrame() const {
}
void RenderWidgetHostViewAndroid::ShowDisambiguationPopup(
- const gfx::Rect& target_rect, const SkBitmap& zoomed_bitmap) {
+ const gfx::Rect& rect_pixels, const SkBitmap& zoomed_bitmap) {
if (!content_view_core_)
return;
- content_view_core_->ShowDisambiguationPopup(target_rect, zoomed_bitmap);
+ content_view_core_->ShowDisambiguationPopup(rect_pixels, zoomed_bitmap);
}
scoped_ptr<SyntheticGestureTarget>
@@ -755,7 +927,7 @@ void RenderWidgetHostViewAndroid::SendDelegatedFrameAck(
void RenderWidgetHostViewAndroid::SendReturnedDelegatedResources(
uint32 output_surface_id) {
- DCHECK(resource_collection_);
+ DCHECK(resource_collection_.get());
cc::CompositorFrameAck ack;
resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
@@ -778,6 +950,9 @@ void RenderWidgetHostViewAndroid::DestroyDelegatedContent() {
RemoveLayers();
frame_provider_ = NULL;
layer_ = NULL;
+ // This gets called when ever any eviction, loosing resources, swapping
+ // problems are encountered and so we abort any pending readbacks here.
+ AbortPendingReadbackRequests();
}
void RenderWidgetHostViewAndroid::SwapDelegatedFrame(
@@ -814,7 +989,7 @@ void RenderWidgetHostViewAndroid::SwapDelegatedFrame(
resource_collection_ = new cc::DelegatedFrameResourceCollection;
resource_collection_->SetClient(this);
}
- if (!frame_provider_ ||
+ if (!frame_provider_.get() ||
texture_size_in_layer_ != frame_provider_->frame_size()) {
RemoveLayers();
frame_provider_ = new cc::DelegatedFrameProvider(
@@ -847,21 +1022,22 @@ void RenderWidgetHostViewAndroid::ComputeContentsSize(
const cc::CompositorFrameMetadata& frame_metadata) {
// Calculate the content size. This should be 0 if the texture_size is 0.
gfx::Vector2dF offset;
- if (texture_size_in_layer_.GetArea() > 0)
- offset = frame_metadata.location_bar_content_translation;
- offset.set_y(offset.y() + frame_metadata.overdraw_bottom_height);
- offset.Scale(frame_metadata.device_scale_factor);
- content_size_in_layer_ =
- gfx::Size(texture_size_in_layer_.width() - offset.x(),
- texture_size_in_layer_.height() - offset.y());
-
- overscroll_effect_->UpdateDisplayParameters(
- CreateOverscrollDisplayParameters(frame_metadata));
+ if (texture_size_in_layer_.IsEmpty())
+ content_size_in_layer_ = gfx::Size();
+ content_size_in_layer_ = gfx::ToCeiledSize(gfx::ScaleSize(
+ frame_metadata.scrollable_viewport_size,
+ frame_metadata.device_scale_factor * frame_metadata.page_scale_factor));
+
+ if (overscroll_effect_) {
+ overscroll_effect_->UpdateDisplayParameters(
+ CreateOverscrollDisplayParameters(frame_metadata));
+ }
}
void RenderWidgetHostViewAndroid::InternalSwapCompositorFrame(
uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) {
+ last_scroll_offset_ = frame->metadata.root_scroll_offset;
if (!frame->delegated_frame_data) {
LOG(ERROR) << "Non-delegated renderer path no longer supported";
return;
@@ -873,7 +1049,7 @@ void RenderWidgetHostViewAndroid::InternalSwapCompositorFrame(
return;
}
- if (layer_ && layer_->layer_tree_host()) {
+ if (layer_.get() && layer_->layer_tree_host()) {
for (size_t i = 0; i < frame->metadata.latency_info.size(); i++) {
scoped_ptr<cc::SwapPromise> swap_promise(
new cc::LatencyInfoSwapPromise(frame->metadata.latency_info[i]));
@@ -891,7 +1067,21 @@ void RenderWidgetHostViewAndroid::InternalSwapCompositorFrame(
SwapDelegatedFrame(output_surface_id, frame->delegated_frame_data.Pass());
frame_evictor_->SwappedFrame(!host_->is_hidden());
+ // As the metadata update may trigger view invalidation, always call it after
+ // any potential compositor scheduling.
OnFrameMetadataUpdated(frame->metadata);
+ // Check if we have any pending readbacks, see if we have a frame available
+ // and process them here.
+ if (!readbacks_waiting_for_frame_.empty()) {
+ while (!readbacks_waiting_for_frame_.empty()) {
+ ReadbackRequest& readback_request = readbacks_waiting_for_frame_.front();
+ GetScaledContentBitmap(readback_request.GetScale(),
+ readback_request.GetColorFormat(),
+ readback_request.GetCaptureRect(),
+ readback_request.GetResultCallback());
+ readbacks_waiting_for_frame_.pop();
+ }
+ }
}
void RenderWidgetHostViewAndroid::OnSwapCompositorFrame(
@@ -923,16 +1113,19 @@ void RenderWidgetHostViewAndroid::RetainFrame(
void RenderWidgetHostViewAndroid::SynchronousFrameMetadata(
const cc::CompositorFrameMetadata& frame_metadata) {
+ if (!content_view_core_)
+ return;
+
// This is a subset of OnSwapCompositorFrame() used in the synchronous
// compositor flow.
OnFrameMetadataUpdated(frame_metadata);
ComputeContentsSize(frame_metadata);
// DevTools ScreenCast support for Android WebView.
- if (DevToolsAgentHost::HasFor(RenderViewHost::From(GetRenderWidgetHost()))) {
+ WebContents* web_contents = content_view_core_->GetWebContents();
+ if (DevToolsAgentHost::HasFor(web_contents)) {
scoped_refptr<DevToolsAgentHost> dtah =
- DevToolsAgentHost::GetOrCreateFor(
- RenderViewHost::From(GetRenderWidgetHost()));
+ DevToolsAgentHost::GetOrCreateFor(web_contents);
// Unblock the compositor.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
@@ -943,15 +1136,64 @@ void RenderWidgetHostViewAndroid::SynchronousFrameMetadata(
}
void RenderWidgetHostViewAndroid::SetOverlayVideoMode(bool enabled) {
- if (layer_)
+ if (layer_.get())
layer_->SetContentsOpaque(!enabled);
}
+bool RenderWidgetHostViewAndroid::SupportsAnimation() const {
+ // The synchronous (WebView) compositor does not have a proper browser
+ // compositor with which to drive animations.
+ return !using_synchronous_compositor_;
+}
+
+void RenderWidgetHostViewAndroid::SetNeedsAnimate() {
+ DCHECK(content_view_core_);
+ DCHECK(!using_synchronous_compositor_);
+ content_view_core_->GetWindowAndroid()->SetNeedsAnimate();
+}
+
+void RenderWidgetHostViewAndroid::MoveCaret(const gfx::PointF& position) {
+ MoveCaret(gfx::Point(position.x(), position.y()));
+}
+
+void RenderWidgetHostViewAndroid::MoveRangeSelectionExtent(
+ const gfx::PointF& extent) {
+ DCHECK(content_view_core_);
+ content_view_core_->MoveRangeSelectionExtent(extent);
+}
+
+void RenderWidgetHostViewAndroid::SelectBetweenCoordinates(
+ const gfx::PointF& base,
+ const gfx::PointF& extent) {
+ DCHECK(content_view_core_);
+ content_view_core_->SelectBetweenCoordinates(base, extent);
+}
+
+void RenderWidgetHostViewAndroid::OnSelectionEvent(
+ SelectionEventType event,
+ const gfx::PointF& position) {
+ DCHECK(content_view_core_);
+ content_view_core_->OnSelectionEvent(event, position);
+}
+
+scoped_ptr<TouchHandleDrawable> RenderWidgetHostViewAndroid::CreateDrawable() {
+ DCHECK(content_view_core_);
+ if (using_synchronous_compositor_)
+ return content_view_core_->CreatePopupTouchHandleDrawable();
+
+ return scoped_ptr<TouchHandleDrawable>(new CompositedTouchHandleDrawable(
+ content_view_core_->GetLayer().get(),
+ content_view_core_->GetDpiScale(),
+ // Use the activity context (instead of the application context) to ensure
+ // proper handle theming.
+ content_view_core_->GetContext().obj()));
+}
+
void RenderWidgetHostViewAndroid::SynchronousCopyContents(
const gfx::Rect& src_subrect_in_pixel,
const gfx::Size& dst_size_in_pixel,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) {
+ const SkColorType color_type) {
SynchronousCompositor* compositor =
SynchronousCompositorImpl::FromID(host_->GetProcess()->GetID(),
host_->GetRoutingID());
@@ -961,10 +1203,10 @@ void RenderWidgetHostViewAndroid::SynchronousCopyContents(
}
SkBitmap bitmap;
- bitmap.setConfig(config,
- dst_size_in_pixel.width(),
- dst_size_in_pixel.height());
- bitmap.allocPixels();
+ bitmap.allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
+ dst_size_in_pixel.height(),
+ color_type,
+ kPremul_SkAlphaType));
SkCanvas canvas(bitmap);
canvas.scale(
(float)dst_size_in_pixel.width() / (float)src_subrect_in_pixel.width(),
@@ -987,6 +1229,12 @@ void RenderWidgetHostViewAndroid::OnFrameMetadataUpdated(
if (!content_view_core_)
return;
+
+ if (selection_controller_) {
+ selection_controller_->OnSelectionBoundsChanged(
+ frame_metadata.selection_start, frame_metadata.selection_end);
+ }
+
// All offsets and sizes are in CSS pixels.
content_view_core_->UpdateFrameInfo(
frame_metadata.root_scroll_offset,
@@ -994,10 +1242,9 @@ void RenderWidgetHostViewAndroid::OnFrameMetadataUpdated(
gfx::Vector2dF(frame_metadata.min_page_scale_factor,
frame_metadata.max_page_scale_factor),
frame_metadata.root_layer_size,
- frame_metadata.viewport_size,
+ frame_metadata.scrollable_viewport_size,
frame_metadata.location_bar_offset,
- frame_metadata.location_bar_content_translation,
- frame_metadata.overdraw_bottom_height);
+ frame_metadata.location_bar_content_translation);
#if defined(VIDEO_HOLE)
if (host_ && host_->IsRenderView()) {
RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
@@ -1007,17 +1254,11 @@ void RenderWidgetHostViewAndroid::OnFrameMetadataUpdated(
#endif // defined(VIDEO_HOLE)
}
-void RenderWidgetHostViewAndroid::AcceleratedSurfaceInitialized(int host_id,
- int route_id) {
+void RenderWidgetHostViewAndroid::AcceleratedSurfaceInitialized(int route_id) {
+ // TODO: remove need for the surface id here
accelerated_surface_route_id_ = route_id;
}
-void RenderWidgetHostViewAndroid::AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id) {
- NOTREACHED() << "Need --composite-to-mailbox or --enable-delegated-renderer";
-}
-
void RenderWidgetHostViewAndroid::AttachLayers() {
if (!content_view_core_)
return;
@@ -1025,7 +1266,7 @@ void RenderWidgetHostViewAndroid::AttachLayers() {
return;
content_view_core_->AttachLayer(layer_);
- if (overscroll_effect_enabled_)
+ if (overscroll_effect_)
overscroll_effect_->Enable();
layer_->SetHideLayerAndSubtree(!is_showing_);
}
@@ -1033,39 +1274,85 @@ void RenderWidgetHostViewAndroid::AttachLayers() {
void RenderWidgetHostViewAndroid::RemoveLayers() {
if (!content_view_core_)
return;
+
if (!layer_.get())
return;
content_view_core_->RemoveLayer(layer_);
- overscroll_effect_->Disable();
+ if (overscroll_effect_)
+ overscroll_effect_->Disable();
}
-void RenderWidgetHostViewAndroid::SetNeedsAnimate() {
- content_view_core_->GetWindowAndroid()->SetNeedsAnimate();
+void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) {
+ // The synchronous compositor does not requre BeginFrame messages.
+ if (using_synchronous_compositor_)
+ requests &= FLUSH_INPUT;
+
+ bool should_request_vsync = !outstanding_vsync_requests_ && requests;
+ outstanding_vsync_requests_ |= requests;
+ // Note that if we're not currently observing the root window, outstanding
+ // vsync requests will be pushed if/when we resume observing in
+ // |StartObservingRootWindow()|.
+ if (observing_root_window_ && should_request_vsync)
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
}
-bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) {
- return overscroll_effect_->Animate(frame_time);
+void RenderWidgetHostViewAndroid::StartObservingRootWindow() {
+ DCHECK(content_view_core_);
+ if (observing_root_window_)
+ return;
+
+ observing_root_window_ = true;
+ content_view_core_->GetWindowAndroid()->AddObserver(this);
+
+ // Clear existing vsync requests to allow a request to the new window.
+ uint32 outstanding_vsync_requests = outstanding_vsync_requests_;
+ outstanding_vsync_requests_ = 0;
+ RequestVSyncUpdate(outstanding_vsync_requests);
}
-void RenderWidgetHostViewAndroid::AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
- int gpu_host_id) {
- NOTREACHED();
+void RenderWidgetHostViewAndroid::StopObservingRootWindow() {
+ if (!content_view_core_) {
+ DCHECK(!observing_root_window_);
+ return;
+ }
+
+ if (!observing_root_window_)
+ return;
+
+ observing_root_window_ = false;
+ content_view_core_->GetWindowAndroid()->RemoveObserver(this);
}
-void RenderWidgetHostViewAndroid::AcceleratedSurfaceSuspend() {
- NOTREACHED();
+void RenderWidgetHostViewAndroid::SendBeginFrame(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) {
+ TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::SendBeginFrame",
+ "frame_time_us", frame_time.ToInternalValue());
+ base::TimeTicks display_time = frame_time + vsync_period;
+
+ base::TimeTicks deadline =
+ display_time - host_->GetEstimatedBrowserCompositeTime();
+
+ host_->Send(new ViewMsg_BeginFrame(
+ host_->GetRoutingID(),
+ cc::BeginFrameArgs::Create(frame_time, deadline, vsync_period)));
}
-void RenderWidgetHostViewAndroid::AcceleratedSurfaceRelease() {
- NOTREACHED();
+bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) {
+ bool needs_animate =
+ overscroll_effect_ ? overscroll_effect_->Animate(frame_time) : false;
+ if (selection_controller_)
+ needs_animate |= selection_controller_->Animate(frame_time);
+ return needs_animate;
}
void RenderWidgetHostViewAndroid::EvictDelegatedFrame() {
if (layer_.get())
DestroyDelegatedContent();
frame_evictor_->DiscardedFrame();
+ // We are evicting the delegated frame,
+ // so there should be no pending readback requests
+ DCHECK(readbacks_waiting_for_frame_.empty());
}
bool RenderWidgetHostViewAndroid::HasAcceleratedSurface(
@@ -1087,7 +1374,7 @@ gfx::Rect RenderWidgetHostViewAndroid::GetBoundsInRootWindow() {
gfx::GLSurfaceHandle RenderWidgetHostViewAndroid::GetCompositingSurface() {
gfx::GLSurfaceHandle handle =
- gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NATIVE_TRANSPORT);
+ gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NULL_TRANSPORT);
if (CompositorImpl::IsInitialized()) {
handle.parent_client_id =
ImageTransportFactoryAndroid::GetInstance()->GetChannelID();
@@ -1104,12 +1391,32 @@ void RenderWidgetHostViewAndroid::ProcessAckedTouchEvent(
void RenderWidgetHostViewAndroid::GestureEventAck(
const blink::WebGestureEvent& event,
InputEventAckState ack_result) {
+ // The overscroll effect requires an explicit release signal that may not be
+ // sent from the renderer compositor.
+ if (event.type == blink::WebInputEvent::GestureScrollEnd ||
+ event.type == blink::WebInputEvent::GestureFlingStart) {
+ DidOverscroll(DidOverscrollParams());
+ }
+
if (content_view_core_)
content_view_core_->OnGestureEventAck(event, ack_result);
}
InputEventAckState RenderWidgetHostViewAndroid::FilterInputEvent(
const blink::WebInputEvent& input_event) {
+ if (selection_controller_) {
+ switch (input_event.type) {
+ case blink::WebInputEvent::GestureLongPress:
+ selection_controller_->OnLongPressEvent();
+ break;
+ case blink::WebInputEvent::GestureTap:
+ selection_controller_->OnTapEvent();
+ break;
+ default:
+ break;
+ }
+ }
+
if (content_view_core_ &&
content_view_core_->FilterInputEvent(input_event))
return INPUT_EVENT_ACK_STATE_CONSUMED;
@@ -1136,27 +1443,30 @@ InputEventAckState RenderWidgetHostViewAndroid::FilterInputEvent(
}
void RenderWidgetHostViewAndroid::OnSetNeedsFlushInput() {
- if (flush_input_requested_ || !content_view_core_)
- return;
TRACE_EVENT0("input", "RenderWidgetHostViewAndroid::OnSetNeedsFlushInput");
- flush_input_requested_ = true;
- content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
-}
-
-void RenderWidgetHostViewAndroid::CreateBrowserAccessibilityManagerIfNeeded() {
- if (!host_ || host_->accessibility_mode() != AccessibilityModeComplete)
- return;
-
- if (!GetBrowserAccessibilityManager()) {
- base::android::ScopedJavaLocalRef<jobject> obj;
- if (content_view_core_)
- obj = content_view_core_->GetJavaObject();
- SetBrowserAccessibilityManager(
- new BrowserAccessibilityManagerAndroid(
- obj,
- BrowserAccessibilityManagerAndroid::GetEmptyDocument(),
- host_));
- }
+ RequestVSyncUpdate(FLUSH_INPUT);
+}
+
+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();
+ return new BrowserAccessibilityManagerAndroid(
+ obj,
+ BrowserAccessibilityManagerAndroid::GetEmptyDocument(),
+ delegate);
}
bool RenderWidgetHostViewAndroid::LockMouse() {
@@ -1176,20 +1486,6 @@ void RenderWidgetHostViewAndroid::SendKeyEvent(
host_->ForwardKeyboardEvent(event);
}
-void RenderWidgetHostViewAndroid::SendTouchEvent(
- const blink::WebTouchEvent& event) {
- if (host_)
- host_->ForwardTouchEventWithLatencyInfo(event, CreateLatencyInfo(event));
-
- // Send a proactive BeginFrame on the next vsync to reduce latency.
- // This is good enough as long as the first touch event has Begin semantics
- // and the actual scroll happens on the next vsync.
- // TODO: Is this actually still needed?
- if (content_view_core_) {
- content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
- }
-}
-
void RenderWidgetHostViewAndroid::SendMouseEvent(
const blink::WebMouseEvent& event) {
if (host_)
@@ -1205,8 +1501,8 @@ void RenderWidgetHostViewAndroid::SendMouseWheelEvent(
void RenderWidgetHostViewAndroid::SendGestureEvent(
const blink::WebGestureEvent& event) {
// Sending a gesture that may trigger overscroll should resume the effect.
- if (overscroll_effect_enabled_)
- overscroll_effect_->Enable();
+ if (overscroll_effect_)
+ overscroll_effect_->Enable();
if (host_)
host_->ForwardGestureEventWithLatencyInfo(event, CreateLatencyInfo(event));
@@ -1217,25 +1513,62 @@ void RenderWidgetHostViewAndroid::MoveCaret(const gfx::Point& point) {
host_->MoveCaret(point);
}
+void RenderWidgetHostViewAndroid::DismissTextHandles() {
+ if (selection_controller_)
+ selection_controller_->HideAndDisallowShowingAutomatically();
+}
+
+void RenderWidgetHostViewAndroid::SetTextHandlesTemporarilyHidden(bool hidden) {
+ if (selection_controller_)
+ selection_controller_->SetTemporarilyHidden(hidden);
+}
+
+void RenderWidgetHostViewAndroid::OnShowingPastePopup(
+ const gfx::PointF& point) {
+ if (!selection_controller_)
+ return;
+
+ // As the paste popup may be triggered *before* the bounds and editability
+ // of the region have been updated, explicitly set the properties now.
+ // TODO(jdduke): Remove this workaround when auxiliary paste popup
+ // notifications are no longer required, crbug.com/398170.
+ cc::ViewportSelectionBound insertion_bound;
+ insertion_bound.type = cc::SELECTION_BOUND_CENTER;
+ insertion_bound.visible = true;
+ insertion_bound.edge_top = point;
+ insertion_bound.edge_bottom = point;
+ DismissTextHandles();
+ ShowSelectionHandlesAutomatically();
+ selection_controller_->OnSelectionEditable(true);
+ selection_controller_->OnSelectionEmpty(true);
+ selection_controller_->OnSelectionBoundsChanged(insertion_bound,
+ insertion_bound);
+}
+
SkColor RenderWidgetHostViewAndroid::GetCachedBackgroundColor() const {
return cached_background_color_;
}
void RenderWidgetHostViewAndroid::DidOverscroll(
const DidOverscrollParams& params) {
- if (!content_view_core_ || !layer_ || !is_showing_)
+ if (!content_view_core_ || !layer_.get() || !is_showing_)
return;
const float device_scale_factor = content_view_core_->GetDpiScale();
- if (overscroll_effect_->OnOverscrolled(
- content_view_core_->GetLayer(),
+
+ if (overscroll_effect_ &&
+ overscroll_effect_->OnOverscrolled(
+ content_view_core_->GetLayer().get(),
base::TimeTicks::Now(),
gfx::ScaleVector2d(params.accumulated_overscroll,
device_scale_factor),
gfx::ScaleVector2d(params.latest_overscroll_delta,
device_scale_factor),
gfx::ScaleVector2d(params.current_fling_velocity,
- device_scale_factor))) {
+ device_scale_factor),
+ gfx::ScaleVector2d(
+ params.causal_event_viewport_point.OffsetFromOrigin(),
+ device_scale_factor))) {
SetNeedsAnimate();
}
}
@@ -1248,37 +1581,44 @@ void RenderWidgetHostViewAndroid::DidStopFlinging() {
void RenderWidgetHostViewAndroid::SetContentViewCore(
ContentViewCoreImpl* content_view_core) {
RemoveLayers();
- if (observing_root_window_ && content_view_core_) {
- content_view_core_->GetWindowAndroid()->RemoveObserver(this);
- observing_root_window_ = false;
- }
+ StopObservingRootWindow();
bool resize = false;
if (content_view_core != content_view_core_) {
+ overscroll_effect_.reset();
+ selection_controller_.reset();
ReleaseLocksOnSurface();
resize = true;
}
content_view_core_ = content_view_core;
- if (GetBrowserAccessibilityManager()) {
+ BrowserAccessibilityManager* manager = NULL;
+ if (host_)
+ manager = host_->GetRootBrowserAccessibilityManager();
+ if (manager) {
base::android::ScopedJavaLocalRef<jobject> obj;
if (content_view_core_)
obj = content_view_core_->GetJavaObject();
- GetBrowserAccessibilityManager()->ToBrowserAccessibilityManagerAndroid()->
- SetContentViewCore(obj);
+ manager->ToBrowserAccessibilityManagerAndroid()->SetContentViewCore(obj);
}
AttachLayers();
- if (content_view_core_ && !using_synchronous_compositor_) {
- content_view_core_->GetWindowAndroid()->AddObserver(this);
- observing_root_window_ = true;
- if (needs_begin_frame_)
- content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
- }
- if (resize && content_view_core_)
+ if (!content_view_core_)
+ return;
+
+ StartObservingRootWindow();
+
+ if (resize)
WasResized();
+
+ if (!selection_controller_)
+ selection_controller_ = CreateSelectionController(this, content_view_core_);
+
+ if (overscroll_effect_enabled_ && !overscroll_effect_ &&
+ content_view_core_->GetWindowAndroid()->GetCompositor())
+ overscroll_effect_ = CreateOverscrollEffect(content_view_core_);
}
void RenderWidgetHostViewAndroid::RunAckCallbacks() {
@@ -1297,10 +1637,17 @@ void RenderWidgetHostViewAndroid::OnCompositingDidCommit() {
RunAckCallbacks();
}
+void RenderWidgetHostViewAndroid::OnAttachCompositor() {
+ DCHECK(content_view_core_);
+ if (overscroll_effect_enabled_ && !overscroll_effect_)
+ overscroll_effect_ = CreateOverscrollEffect(content_view_core_);
+}
+
void RenderWidgetHostViewAndroid::OnDetachCompositor() {
DCHECK(content_view_core_);
DCHECK(!using_synchronous_compositor_);
RunAckCallbacks();
+ overscroll_effect_.reset();
}
void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
@@ -1309,27 +1656,19 @@ void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
if (!host_)
return;
- if (flush_input_requested_) {
- flush_input_requested_ = false;
- host_->FlushInput();
- }
-
- TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
- base::TimeTicks display_time = frame_time + vsync_period;
-
- // TODO(brianderson): Use adaptive draw-time estimation.
- base::TimeDelta estimated_browser_composite_time =
- base::TimeDelta::FromMicroseconds(
- (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60));
+ const uint32 current_vsync_requests = outstanding_vsync_requests_;
+ outstanding_vsync_requests_ = 0;
- base::TimeTicks deadline = display_time - estimated_browser_composite_time;
+ if (current_vsync_requests & FLUSH_INPUT)
+ host_->FlushInput();
- host_->Send(new ViewMsg_BeginFrame(
- host_->GetRoutingID(),
- cc::BeginFrameArgs::Create(frame_time, deadline, vsync_period)));
+ if (current_vsync_requests & BEGIN_FRAME ||
+ current_vsync_requests & PERSISTENT_BEGIN_FRAME) {
+ SendBeginFrame(frame_time, vsync_period);
+ }
- if (needs_begin_frame_)
- content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+ if (current_vsync_requests & PERSISTENT_BEGIN_FRAME)
+ RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME);
}
void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) {
@@ -1342,41 +1681,44 @@ void RenderWidgetHostViewAndroid::OnLostResources() {
if (layer_.get())
DestroyDelegatedContent();
DCHECK(ack_callbacks_.empty());
+ // We should not loose a frame if we have readback requests pending.
+ DCHECK(readbacks_waiting_for_frame_.empty());
}
// static
void
RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResultForDelegatedReadback(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config config,
+ const SkColorType color_type,
const base::TimeTicks& start_time,
scoped_refptr<cc::Layer> readback_layer,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result) {
readback_layer->RemoveFromParent();
PrepareTextureCopyOutputResult(
- dst_size_in_pixel, config, start_time, callback, result.Pass());
+ dst_size_in_pixel, color_type, start_time, callback, result.Pass());
}
// static
void RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config bitmap_config,
+ const SkColorType color_type,
const base::TimeTicks& start_time,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result) {
base::ScopedClosureRunner scoped_callback_runner(
base::Bind(callback, false, SkBitmap()));
+ TRACE_EVENT0("cc",
+ "RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult");
if (!result->HasTexture() || result->IsEmpty() || result->size().IsEmpty())
return;
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- bitmap->setConfig(bitmap_config,
- dst_size_in_pixel.width(),
- dst_size_in_pixel.height(),
- 0, kOpaque_SkAlphaType);
- if (!bitmap->allocPixels())
+ if (!bitmap->tryAllocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
+ dst_size_in_pixel.height(),
+ color_type,
+ kOpaque_SkAlphaType)))
return;
ImageTransportFactoryAndroid* factory =
@@ -1406,7 +1748,7 @@ void RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult(
gfx::Rect(result->size()),
dst_size_in_pixel,
pixels,
- bitmap_config,
+ color_type,
base::Bind(&CopyFromCompositingSurfaceFinished,
callback,
base::Passed(&release_callback),
@@ -1417,24 +1759,45 @@ void RenderWidgetHostViewAndroid::PrepareTextureCopyOutputResult(
}
bool RenderWidgetHostViewAndroid::IsReadbackConfigSupported(
- SkBitmap::Config bitmap_config) {
+ SkColorType color_type) {
ImageTransportFactoryAndroid* factory =
ImageTransportFactoryAndroid::GetInstance();
GLHelper* gl_helper = factory->GetGLHelper();
if (!gl_helper)
return false;
- return gl_helper->IsReadbackConfigSupported(bitmap_config);
+ return gl_helper->IsReadbackConfigSupported(color_type);
}
-SkBitmap::Config RenderWidgetHostViewAndroid::PreferredReadbackFormat() {
+SkColorType RenderWidgetHostViewAndroid::PreferredReadbackFormat() {
// Define the criteria here. If say the 16 texture readback is
// supported we should go with that (this degrades quality)
// or stick back to the default format.
- if (base::android::SysUtils::IsLowEndDevice()) {
- if (IsReadbackConfigSupported(SkBitmap::kRGB_565_Config))
- return SkBitmap::kRGB_565_Config;
+ if (base::SysInfo::IsLowEndDevice()) {
+ if (IsReadbackConfigSupported(kRGB_565_SkColorType))
+ return kRGB_565_SkColorType;
}
- return SkBitmap::kARGB_8888_Config;
+ return kN32_SkColorType;
+}
+
+void RenderWidgetHostViewAndroid::ShowSelectionHandlesAutomatically() {
+ // Fake a long press to allow automatic selection handle showing.
+ if (selection_controller_)
+ selection_controller_->OnLongPressEvent();
+}
+
+void RenderWidgetHostViewAndroid::SelectRange(
+ float x1, float y1, float x2, float y2) {
+ if (content_view_core_)
+ static_cast<WebContentsImpl*>(content_view_core_->GetWebContents())->
+ SelectRange(gfx::Point(x1, y1), gfx::Point(x2, y2));
+}
+
+void RenderWidgetHostViewAndroid::LongPress(
+ base::TimeTicks time, float x, float y) {
+ blink::WebGestureEvent long_press = WebGestureEventBuilder::Build(
+ blink::WebInputEvent::GestureLongPress,
+ (time - base::TimeTicks()).InSecondsF(), x, y);
+ SendGestureEvent(long_press);
}
// static
@@ -1447,6 +1810,8 @@ void RenderWidgetHostViewBase::GetDefaultScreenInfo(
results->availableRect = display.work_area();
results->deviceScaleFactor = display.device_scale_factor();
results->orientationAngle = display.RotationAsDegree();
+ results->orientationType =
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display);
gfx::DeviceDisplayInfo info;
results->depth = info.GetBitsPerPixel();
results->depthPerComponent = info.GetBitsPerComponent();
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 4707734a8e8..129b773fbfc 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
@@ -20,6 +20,8 @@
#include "content/browser/renderer_host/delegated_frame_evictor.h"
#include "content/browser/renderer_host/image_transport_factory_android.h"
#include "content/browser/renderer_host/ime_adapter_android.h"
+#include "content/browser/renderer_host/input/gesture_text_selector.h"
+#include "content/browser/renderer_host/input/touch_selection_controller.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
#include "gpu/command_buffer/common/mailbox.h"
@@ -32,9 +34,6 @@
struct ViewHostMsg_TextInputState_Params;
-struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
-struct GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params;
-
namespace cc {
class CopyOutputResult;
class DelegatedFrameProvider;
@@ -56,6 +55,29 @@ class RenderWidgetHostImpl;
struct DidOverscrollParams;
struct NativeWebKeyboardEvent;
+class ReadbackRequest {
+ public:
+ explicit ReadbackRequest(
+ float scale,
+ SkColorType color_type,
+ gfx::Rect src_subrect,
+ const base::Callback<void(bool, const SkBitmap&)>& result_callback);
+ ~ReadbackRequest();
+ float GetScale() { return scale_; }
+ SkColorType GetColorFormat() { return color_type_; }
+ const gfx::Rect GetCaptureRect() { return src_subrect_; }
+ const base::Callback<void(bool, const SkBitmap&)>& GetResultCallback() {
+ return result_callback_;
+ }
+
+ private:
+ ReadbackRequest();
+ float scale_;
+ SkColorType color_type_;
+ gfx::Rect src_subrect_;
+ base::Callback<void(bool, const SkBitmap&)> result_callback_;
+};
+
// -----------------------------------------------------------------------------
// See comments in render_widget_host_view.h about this class and its members.
// -----------------------------------------------------------------------------
@@ -65,142 +87,149 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
public ImageTransportFactoryAndroidObserver,
public ui::GestureProviderClient,
public ui::WindowAndroidObserver,
- public DelegatedFrameEvictorClient {
+ public DelegatedFrameEvictorClient,
+ public GestureTextSelectorClient,
+ public TouchSelectionControllerClient {
public:
RenderWidgetHostViewAndroid(RenderWidgetHostImpl* widget,
ContentViewCoreImpl* content_view_core);
virtual ~RenderWidgetHostViewAndroid();
// RenderWidgetHostView implementation.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
- virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& msg) override;
+ virtual void InitAsChild(gfx::NativeView parent_view) override;
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) OVERRIDE;
+ const gfx::Rect& pos) override;
virtual void InitAsFullscreen(
- RenderWidgetHostView* reference_host_view) OVERRIDE;
- virtual RenderWidgetHost* GetRenderWidgetHost() const OVERRIDE;
- virtual void WasShown() OVERRIDE;
- virtual void WasHidden() OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void SetBounds(const gfx::Rect& rect) OVERRIDE;
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeViewId GetNativeViewId() const OVERRIDE;
- virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
+ RenderWidgetHostView* reference_host_view) override;
+ virtual RenderWidgetHost* GetRenderWidgetHost() const override;
+ virtual void WasShown() override;
+ virtual void WasHidden() override;
+ virtual void SetSize(const gfx::Size& size) override;
+ virtual void SetBounds(const gfx::Rect& rect) override;
+ virtual gfx::Vector2dF GetLastScrollOffset() const override;
+ virtual gfx::NativeView GetNativeView() const override;
+ virtual gfx::NativeViewId GetNativeViewId() const override;
+ virtual gfx::NativeViewAccessible GetNativeViewAccessible() override;
virtual void MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void Blur() OVERRIDE;
- virtual bool HasFocus() const OVERRIDE;
- virtual bool IsSurfaceAvailableForCopy() const OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual bool IsShowing() OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
- virtual gfx::Size GetPhysicalBackingSize() const OVERRIDE;
- virtual float GetOverdrawBottomHeight() const OVERRIDE;
- virtual void UpdateCursor(const WebCursor& cursor) OVERRIDE;
- virtual void SetIsLoading(bool is_loading) OVERRIDE;
- virtual void TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) OVERRIDE;
- virtual void ImeCancelComposition() OVERRIDE;
- virtual void FocusedNodeChanged(bool is_editable_node) OVERRIDE;
+ const std::vector<WebPluginGeometry>& moves) override;
+ virtual void Focus() override;
+ virtual void Blur() override;
+ virtual bool HasFocus() const override;
+ virtual bool IsSurfaceAvailableForCopy() const override;
+ virtual void Show() override;
+ virtual void Hide() override;
+ virtual bool IsShowing() override;
+ virtual gfx::Rect GetViewBounds() const override;
+ virtual gfx::Size GetPhysicalBackingSize() const override;
+ virtual float GetTopControlsLayoutHeight() const override;
+ virtual void UpdateCursor(const WebCursor& cursor) override;
+ virtual void SetIsLoading(bool is_loading) override;
+ virtual void TextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) override;
+ virtual void ImeCancelComposition() override;
+ virtual void ImeCompositionRangeChanged(
+ const gfx::Range& range,
+ const std::vector<gfx::Rect>& character_bounds) override;
+ virtual void FocusedNodeChanged(bool is_editable_node) override;
virtual void RenderProcessGone(base::TerminationStatus status,
- int error_code) OVERRIDE;
- virtual void Destroy() OVERRIDE;
- virtual void SetTooltipText(const base::string16& tooltip_text) OVERRIDE;
+ int error_code) override;
+ virtual void Destroy() override;
+ virtual void SetTooltipText(const base::string16& tooltip_text) override;
virtual void SelectionChanged(const base::string16& text,
size_t offset,
- const gfx::Range& range) OVERRIDE;
+ const gfx::Range& range) override;
virtual void SelectionBoundsChanged(
- const ViewHostMsg_SelectionBounds_Params& params) OVERRIDE;
- virtual void ScrollOffsetChanged() OVERRIDE;
- virtual void AcceleratedSurfaceInitialized(int host_id,
- int route_id) OVERRIDE;
- virtual void AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfaceSuspend() OVERRIDE;
- virtual void AcceleratedSurfaceRelease() OVERRIDE;
- virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE;
- virtual void SetBackgroundOpaque(bool transparent) OVERRIDE;
+ const ViewHostMsg_SelectionBounds_Params& params) override;
+ virtual void AcceleratedSurfaceInitialized(int route_id) override;
+ virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
+ virtual void SetBackgroundColor(SkColor color) override;
virtual void CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) OVERRIDE;
+ CopyFromCompositingSurfaceCallback& callback,
+ const SkColorType color_type) override;
virtual void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) OVERRIDE;
- virtual bool CanCopyToVideoFrame() const OVERRIDE;
- virtual void GetScreenInfo(blink::WebScreenInfo* results) OVERRIDE;
- virtual gfx::Rect GetBoundsInRootWindow() OVERRIDE;
- virtual gfx::GLSurfaceHandle GetCompositingSurface() OVERRIDE;
+ const base::Callback<void(bool)>& callback) override;
+ virtual bool CanCopyToVideoFrame() const override;
+ virtual void GetScreenInfo(blink::WebScreenInfo* results) override;
+ virtual gfx::Rect GetBoundsInRootWindow() override;
+ virtual gfx::GLSurfaceHandle GetCompositingSurface() override;
virtual void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) OVERRIDE;
+ InputEventAckState ack_result) override;
virtual InputEventAckState FilterInputEvent(
- const blink::WebInputEvent& input_event) OVERRIDE;
- virtual void OnSetNeedsFlushInput() OVERRIDE;
+ const blink::WebInputEvent& input_event) override;
+ virtual void OnSetNeedsFlushInput() override;
virtual void GestureEventAck(const blink::WebGestureEvent& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void CreateBrowserAccessibilityManagerIfNeeded() OVERRIDE;
- virtual bool LockMouse() OVERRIDE;
- virtual void UnlockMouse() OVERRIDE;
+ InputEventAckState ack_result) override;
+ virtual BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) override;
+ virtual bool LockMouse() override;
+ virtual void UnlockMouse() override;
virtual void OnSwapCompositorFrame(
uint32 output_surface_id,
- scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
- virtual void DidOverscroll(const DidOverscrollParams& params) OVERRIDE;
- virtual void DidStopFlinging() OVERRIDE;
- virtual void ShowDisambiguationPopup(const gfx::Rect& target_rect,
- const SkBitmap& zoomed_bitmap) OVERRIDE;
+ scoped_ptr<cc::CompositorFrame> frame) override;
+ virtual void DidOverscroll(const DidOverscrollParams& params) override;
+ virtual void DidStopFlinging() override;
+ virtual void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
+ const SkBitmap& zoomed_bitmap) override;
virtual scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget()
- OVERRIDE;
- virtual void LockCompositingSurface() OVERRIDE;
- virtual void UnlockCompositingSurface() OVERRIDE;
+ override;
+ virtual void LockCompositingSurface() override;
+ virtual void UnlockCompositingSurface() override;
virtual void OnTextSurroundingSelectionResponse(const base::string16& content,
size_t start_offset,
- size_t end_offset) OVERRIDE;
+ size_t end_offset) override;
// cc::DelegatedFrameResourceCollectionClient implementation.
- virtual void UnusedResourcesAreAvailable() OVERRIDE;
+ virtual void UnusedResourcesAreAvailable() override;
// ui::GestureProviderClient implementation.
- virtual void OnGestureEvent(const ui::GestureEventData& gesture) OVERRIDE;
+ virtual void OnGestureEvent(const ui::GestureEventData& gesture) override;
// ui::WindowAndroidObserver implementation.
- virtual void OnCompositingDidCommit() OVERRIDE;
- virtual void OnAttachCompositor() OVERRIDE {}
- virtual void OnDetachCompositor() OVERRIDE;
+ virtual void OnCompositingDidCommit() override;
+ virtual void OnAttachCompositor() override;
+ virtual void OnDetachCompositor() override;
virtual void OnVSync(base::TimeTicks frame_time,
- base::TimeDelta vsync_period) OVERRIDE;
- virtual void OnAnimate(base::TimeTicks begin_frame_time) OVERRIDE;
+ base::TimeDelta vsync_period) override;
+ virtual void OnAnimate(base::TimeTicks begin_frame_time) override;
// ImageTransportFactoryAndroidObserver implementation.
- virtual void OnLostResources() OVERRIDE;
+ virtual void OnLostResources() override;
// DelegatedFrameEvictor implementation
- virtual void EvictDelegatedFrame() OVERRIDE;
+ virtual void EvictDelegatedFrame() override;
+
+ virtual SkColorType PreferredReadbackFormat() override;
- virtual SkBitmap::Config PreferredReadbackFormat() OVERRIDE;
+ // GestureTextSelectorClient implementation.
+ virtual void ShowSelectionHandlesAutomatically() override;
+ virtual void SelectRange(float x1, float y1, float x2, float y2) override;
+ virtual void LongPress(base::TimeTicks time, float x, float y) override;
// Non-virtual methods
void SetContentViewCore(ContentViewCoreImpl* content_view_core);
SkColor GetCachedBackgroundColor() const;
void SendKeyEvent(const NativeWebKeyboardEvent& event);
- void SendTouchEvent(const blink::WebTouchEvent& event);
void SendMouseEvent(const blink::WebMouseEvent& event);
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event);
void SendGestureEvent(const blink::WebGestureEvent& event);
+ void OnTextInputStateChanged(const ViewHostMsg_TextInputState_Params& params);
void OnDidChangeBodyBackgroundColor(SkColor color);
void OnStartContentIntent(const GURL& content_url);
void OnSetNeedsBeginFrame(bool enabled);
- void OnSmartClipDataExtracted(const base::string16& result);
+ void OnSmartClipDataExtracted(const base::string16& text,
+ const base::string16& html,
+ const gfx::Rect rect);
bool OnTouchEvent(const ui::MotionEvent& event);
+ bool OnTouchHandleEvent(const ui::MotionEvent& event);
void ResetGestureDetection();
void SetDoubleTapSupportEnabled(bool enabled);
void SetMultiTouchZoomSupportEnabled(bool enabled);
@@ -211,13 +240,19 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void GetScaledContentBitmap(
float scale,
- SkBitmap::Config bitmap_config,
+ SkColorType color_type,
gfx::Rect src_subrect,
const base::Callback<void(bool, const SkBitmap&)>& result_callback);
+ scoped_refptr<cc::DelegatedRendererLayer>
+ CreateDelegatedLayerForFrameProvider() const;
+
bool HasValidFrame() const;
void MoveCaret(const gfx::Point& point);
+ void DismissTextHandles();
+ void SetTextHandlesTemporarilyHidden(bool hidden);
+ void OnShowingPastePopup(const gfx::PointF& point);
void SynchronousFrameMetadata(
const cc::CompositorFrameMetadata& frame_metadata);
@@ -231,6 +266,17 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
const TextSurroundingSelectionCallback& callback);
private:
+ // TouchSelectionControllerClient implementation.
+ virtual bool SupportsAnimation() const override;
+ virtual void SetNeedsAnimate() override;
+ virtual void MoveCaret(const gfx::PointF& position) override;
+ virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
+ virtual void SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) override;
+ virtual void OnSelectionEvent(SelectionEventType event,
+ const gfx::PointF& anchor_position) override;
+ virtual scoped_ptr<TouchHandleDrawable> CreateDrawable() override;
+
void RunAckCallbacks();
void DestroyDelegatedContent();
@@ -242,8 +288,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void OnFrameMetadataUpdated(
const cc::CompositorFrameMetadata& frame_metadata);
void ComputeContentsSize(const cc::CompositorFrameMetadata& frame_metadata);
- void ResetClipping();
- void ClipContents(const gfx::Rect& clipping, const gfx::Size& content_size);
void AttachLayers();
void RemoveLayers();
@@ -252,13 +296,13 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
// of the copy.
static void PrepareTextureCopyOutputResult(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config config,
+ const SkColorType color_type,
const base::TimeTicks& start_time,
const base::Callback<void(bool, const SkBitmap&)>& callback,
scoped_ptr<cc::CopyOutputResult> result);
static void PrepareTextureCopyOutputResultForDelegatedReadback(
const gfx::Size& dst_size_in_pixel,
- const SkBitmap::Config config,
+ const SkColorType color_type,
const base::TimeTicks& start_time,
scoped_refptr<cc::Layer> readback_layer,
const base::Callback<void(bool, const SkBitmap&)>& callback,
@@ -269,9 +313,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
const gfx::Rect& src_subrect_in_pixel,
const gfx::Size& dst_size_in_pixel,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config);
+ const SkColorType color_type);
- bool IsReadbackConfigSupported(SkBitmap::Config bitmap_config);
+ bool IsReadbackConfigSupported(SkColorType color_type);
// If we have locks on a frame during a ContentViewCore swap or a context
// lost, the frame is no longer valid and we can safely release all the locks.
@@ -286,14 +330,25 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
void InternalSwapCompositorFrame(uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame);
- void SetNeedsAnimate();
+ enum VSyncRequestType {
+ FLUSH_INPUT = 1 << 0,
+ BEGIN_FRAME = 1 << 1,
+ PERSISTENT_BEGIN_FRAME = 1 << 2
+ };
+ void RequestVSyncUpdate(uint32 requests);
+ void StartObservingRootWindow();
+ void StopObservingRootWindow();
+ void SendBeginFrame(base::TimeTicks frame_time, base::TimeDelta vsync_period);
bool Animate(base::TimeTicks frame_time);
+ // Handles all unprocessed and pending readback requests.
+ void AbortPendingReadbackRequests();
+
// The model object.
RenderWidgetHostImpl* host_;
- // Used to track whether this render widget needs a BeginFrame.
- bool needs_begin_frame_;
+ // Used to control action dispatch at the next |OnVSync()| call.
+ uint32 outstanding_vsync_requests_;
bool is_showing_;
@@ -315,26 +370,26 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
// The most recent content size that was pushed to the texture layer.
gfx::Size content_size_in_layer_;
- // The device scale of the last received frame.
- float device_scale_factor_;
-
// The output surface id of the last received frame.
uint32_t last_output_surface_id_;
- base::WeakPtrFactory<RenderWidgetHostViewAndroid> weak_ptr_factory_;
std::queue<base::Closure> ack_callbacks_;
const bool overscroll_effect_enabled_;
// Used to render overscroll overlays.
- // Note: |overscroll_effect_| will never be NULL, even if it's never enabled.
scoped_ptr<OverscrollGlow> overscroll_effect_;
// Provides gesture synthesis given a stream of touch events (derived from
// Android MotionEvent's) and touch event acks.
ui::FilteredGestureProvider gesture_provider_;
- bool flush_input_requested_;
+ // Handles gesture based text selection
+ GestureTextSelector gesture_text_selector_;
+
+ // Manages selection handle rendering and manipulation.
+ // This will always be NULL if |content_view_core_| is NULL.
+ scoped_ptr<TouchSelectionController> selection_controller_;
int accelerated_surface_route_id_;
@@ -360,6 +415,14 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
TextSurroundingSelectionCallback text_surrounding_selection_callback_;
+ // List of readbackrequests waiting for arrival of a valid frame.
+ std::queue<ReadbackRequest> readbacks_waiting_for_frame_;
+
+ // The last scroll offset of the view.
+ gfx::Vector2dF last_scroll_offset_;
+
+ base::WeakPtrFactory<RenderWidgetHostViewAndroid> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAndroid);
};
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 3c10f51e145..074a309e045 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
@@ -29,6 +29,7 @@
#include "content/browser/renderer_host/input/synthetic_gesture_target_aura.h"
#include "content/browser/renderer_host/overscroll_controller.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_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/ui_events_helper.h"
@@ -62,6 +63,7 @@
#include "ui/base/ime/input_method.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/compositor_vsync_manager.h"
+#include "ui/compositor/dip_util.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/gestures/gesture_recognizer.h"
@@ -233,12 +235,15 @@ void UpdateWebTouchEventAfterDispatch(blink::WebTouchEvent* event,
if (point->state != blink::WebTouchPoint::StateReleased &&
point->state != blink::WebTouchPoint::StateCancelled)
return;
- --event->touchesLength;
- for (unsigned i = point - event->touches;
- i < event->touchesLength;
- ++i) {
+
+ const unsigned new_length = event->touchesLength - 1;
+ // Work around a gcc 4.9 bug. crbug.com/392872
+ if (new_length >= event->touchesLengthCap)
+ return;
+
+ for (unsigned i = point - event->touches; i < new_length; ++i)
event->touches[i] = event->touches[i + 1];
- }
+ event->touchesLength = new_length;
}
bool CanRendererHandleEvent(const ui::MouseEvent* event) {
@@ -316,6 +321,9 @@ void GetScreenInfoForWindow(WebScreenInfo* results, aura::Window* window) {
results->orientationAngle = 270;
else if (results->orientationAngle == 270)
results->orientationAngle = 90;
+
+ results->orientationType =
+ RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
}
bool PointerEventActivates(const ui::Event& event) {
@@ -344,16 +352,16 @@ class RenderWidgetHostViewAura::EventFilterForPopupExit
aura::Env::GetInstance()->AddPreTargetHandler(this);
}
- virtual ~EventFilterForPopupExit() {
+ ~EventFilterForPopupExit() override {
aura::Env::GetInstance()->RemovePreTargetHandler(this);
}
// Overridden from ui::EventHandler
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ void OnMouseEvent(ui::MouseEvent* event) override {
rwhva_->ApplyEventFilterForPopupExit(event);
}
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
+ void OnTouchEvent(ui::TouchEvent* event) override {
rwhva_->ApplyEventFilterForPopupExit(event);
}
@@ -379,8 +387,7 @@ void RenderWidgetHostViewAura::ApplyEventFilterForPopupExit(
target != popup_parent_host_view_->window_)) {
// Note: popup_parent_host_view_ may be NULL when there are multiple
// popup children per view. See: RenderWidgetHostViewAura::InitAsPopup().
- in_shutdown_ = true;
- host_->Shutdown();
+ Shutdown();
}
}
@@ -395,18 +402,16 @@ class RenderWidgetHostViewAura::WindowObserver : public aura::WindowObserver {
view_->window_->AddObserver(this);
}
- virtual ~WindowObserver() {
- view_->window_->RemoveObserver(this);
- }
+ ~WindowObserver() override { view_->window_->RemoveObserver(this); }
// Overridden from aura::WindowObserver:
- virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE {
+ void OnWindowAddedToRootWindow(aura::Window* window) override {
if (window == view_->window_)
view_->AddedToRootWindow();
}
- virtual void OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) OVERRIDE {
+ void OnWindowRemovingFromRootWindow(aura::Window* window,
+ aura::Window* new_root) override {
if (window == view_->window_)
view_->RemovingFromRootWindow();
}
@@ -420,7 +425,8 @@ class RenderWidgetHostViewAura::WindowObserver : public aura::WindowObserver {
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, public:
-RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host)
+RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host,
+ bool is_guest_view_hack)
: host_(RenderWidgetHostImpl::From(host)),
window_(new aura::Window(this)),
delegated_frame_host_(new DelegatedFrameHost(this)),
@@ -432,6 +438,7 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host)
is_loading_(false),
text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
+ text_input_flags_(0),
can_compose_inline_(true),
has_composition_text_(false),
accept_return_character_(false),
@@ -439,9 +446,16 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host)
paint_canvas_(NULL),
synthetic_move_sent_(false),
cursor_visibility_state_in_renderer_(UNKNOWN),
+#if defined(OS_WIN)
+ legacy_render_widget_host_HWND_(NULL),
+#endif
+ has_snapped_to_boundary_(false),
touch_editing_client_(NULL),
+ is_guest_view_hack_(is_guest_view_hack),
weak_ptr_factory_(this) {
- host_->SetView(this);
+ if (!is_guest_view_hack_)
+ host_->SetView(this);
+
window_observer_.reset(new WindowObserver(this));
aura::client::SetTooltipText(window_, &tooltip_);
aura::client::SetActivationDelegate(window_, this);
@@ -450,7 +464,7 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host)
window_->set_layer_owner_delegate(delegated_frame_host_.get());
gfx::Screen::GetScreenFor(window_)->AddObserver(this);
- bool overscroll_enabled = CommandLine::ForCurrentProcess()->
+ bool overscroll_enabled = base::CommandLine::ForCurrentProcess()->
GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
SetOverscrollControllerEnabled(overscroll_enabled);
}
@@ -458,11 +472,26 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host)
////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, RenderWidgetHostView implementation:
+bool RenderWidgetHostViewAura::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostViewAura, message)
+ // TODO(kevers): Move to RenderWidgetHostViewImpl and consolidate IPC
+ // messages for TextInput<State|Type>Changed. Corresponding code in
+ // RenderWidgetHostViewAndroid should also be moved at the same time.
+ IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
+ OnTextInputStateChanged)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
void RenderWidgetHostViewAura::InitAsChild(
gfx::NativeView parent_view) {
window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
- window_->Init(aura::WINDOW_LAYER_TEXTURED);
+ window_->Init(aura::WINDOW_LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
+ window_->layer()->SetColor(background_color_);
}
void RenderWidgetHostViewAura::InitAsPopup(
@@ -489,25 +518,26 @@ void RenderWidgetHostViewAura::InitAsPopup(
}
popup_parent_host_view_->popup_child_host_view_ = this;
window_->SetType(ui::wm::WINDOW_TYPE_MENU);
- window_->Init(aura::WINDOW_LAYER_TEXTURED);
+ window_->Init(aura::WINDOW_LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
+ window_->layer()->SetColor(background_color_);
- aura::Window* root = popup_parent_host_view_->window_->GetRootWindow();
- aura::client::ParentWindowWithContext(window_, root, bounds_in_screen);
// Setting the transient child allows for the popup to get mouse events when
- // in a system modal dialog.
+ // in a system modal dialog. Do this before calling ParentWindowWithContext
+ // below so that the transient parent is visible to WindowTreeClient.
// This fixes crbug.com/328593.
if (transient_window_client) {
transient_window_client->AddTransientChild(
popup_parent_host_view_->window_, window_);
}
+ aura::Window* root = popup_parent_host_view_->window_->GetRootWindow();
+ aura::client::ParentWindowWithContext(window_, root, bounds_in_screen);
+
SetBounds(bounds_in_screen);
Show();
-#if !defined(OS_WIN) && !defined(OS_CHROMEOS)
- if (NeedsInputGrab())
+ if (NeedsMouseCapture())
window_->SetCapture();
-#endif
event_filter_for_popup_exit_.reset(new EventFilterForPopupExit(this));
}
@@ -516,9 +546,10 @@ void RenderWidgetHostViewAura::InitAsFullscreen(
RenderWidgetHostView* reference_host_view) {
is_fullscreen_ = true;
window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
- window_->Init(aura::WINDOW_LAYER_TEXTURED);
+ window_->Init(aura::WINDOW_LAYER_SOLID_COLOR);
window_->SetName("RenderWidgetHostViewAura");
window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
+ window_->layer()->SetColor(background_color_);
aura::Window* parent = NULL;
gfx::Rect bounds;
@@ -547,7 +578,17 @@ void RenderWidgetHostViewAura::WasShown() {
DCHECK(host_);
if (!host_->is_hidden())
return;
- host_->WasShown();
+
+ bool has_saved_frame = delegated_frame_host_->HasSavedFrame();
+ ui::LatencyInfo renderer_latency_info, browser_latency_info;
+ if (has_saved_frame) {
+ browser_latency_info.AddLatencyNumber(
+ ui::TAB_SHOW_COMPONENT, host_->GetLatencyComponentId(), 0);
+ } else {
+ renderer_latency_info.AddLatencyNumber(
+ ui::TAB_SHOW_COMPONENT, host_->GetLatencyComponentId(), 0);
+ }
+ host_->WasShown(renderer_latency_info);
aura::Window* root = window_->GetRootWindow();
if (root) {
@@ -557,19 +598,9 @@ void RenderWidgetHostViewAura::WasShown() {
NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible());
}
- delegated_frame_host_->WasShown();
+ delegated_frame_host_->WasShown(browser_latency_info);
#if defined(OS_WIN)
- if (legacy_render_widget_host_HWND_) {
- // Reparent the legacy Chrome_RenderWidgetHostHWND window to the parent
- // window before reparenting any plugins. This ensures that the plugin
- // windows stay on top of the child Zorder in the parent and receive
- // mouse events, etc.
- legacy_render_widget_host_HWND_->UpdateParent(
- GetNativeView()->GetHost()->GetAcceleratedWidget());
- legacy_render_widget_host_HWND_->SetBounds(
- window_->GetBoundsInRootWindow());
- }
LPARAM lparam = reinterpret_cast<LPARAM>(this);
EnumChildWindows(ui::GetHiddenWindow(), ShowWindowsCallback, lparam);
#endif
@@ -588,10 +619,6 @@ void RenderWidgetHostViewAura::WasHidden() {
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_)
- legacy_render_widget_host_HWND_->UpdateParent(ui::GetHiddenWindow());
}
#endif
}
@@ -621,6 +648,10 @@ void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect) {
InternalSetBounds(gfx::Rect(relative_origin, rect.size()));
}
+gfx::Vector2dF RenderWidgetHostViewAura::GetLastScrollOffset() const {
+ return last_scroll_offset_;
+}
+
gfx::NativeView RenderWidgetHostViewAura::GetNativeView() const {
return window_;
}
@@ -640,9 +671,8 @@ gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible() {
if (!host)
return static_cast<gfx::NativeViewAccessible>(NULL);
HWND hwnd = host->GetAcceleratedWidget();
-
- CreateBrowserAccessibilityManagerIfNeeded();
- BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager();
+ BrowserAccessibilityManager* manager =
+ host_->GetOrCreateRootBrowserAccessibilityManager();
if (manager)
return manager->GetRoot()->ToBrowserAccessibilityWin();
#endif
@@ -753,19 +783,11 @@ bool RenderWidgetHostViewAura::IsSurfaceAvailableForCopy() const {
void RenderWidgetHostViewAura::Show() {
window_->Show();
WasShown();
-#if defined(OS_WIN)
- if (legacy_render_widget_host_HWND_)
- legacy_render_widget_host_HWND_->Show();
-#endif
}
void RenderWidgetHostViewAura::Hide() {
window_->Hide();
WasHidden();
-#if defined(OS_WIN)
- if (legacy_render_widget_host_HWND_)
- legacy_render_widget_host_HWND_->Hide();
-#endif
}
bool RenderWidgetHostViewAura::IsShowing() {
@@ -776,10 +798,12 @@ gfx::Rect RenderWidgetHostViewAura::GetViewBounds() const {
return window_->GetBoundsInScreen();
}
-void RenderWidgetHostViewAura::SetBackgroundOpaque(bool opaque) {
- RenderWidgetHostViewBase::SetBackgroundOpaque(opaque);
+void RenderWidgetHostViewAura::SetBackgroundColor(SkColor color) {
+ RenderWidgetHostViewBase::SetBackgroundColor(color);
+ bool opaque = GetBackgroundOpaque();
host_->SetBackgroundOpaque(opaque);
window_->layer()->SetFillsBoundsOpaquely(opaque);
+ window_->layer()->SetColor(color);
}
gfx::Size RenderWidgetHostViewAura::GetVisibleViewportSize() const {
@@ -808,19 +832,29 @@ void RenderWidgetHostViewAura::SetIsLoading(bool is_loading) {
UpdateCursorIfOverSelf();
}
-void RenderWidgetHostViewAura::TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) {
- if (text_input_type_ != params.type ||
- text_input_mode_ != params.mode ||
- can_compose_inline_ != params.can_compose_inline) {
- text_input_type_ = params.type;
- text_input_mode_ = params.mode;
- can_compose_inline_ = params.can_compose_inline;
+void RenderWidgetHostViewAura::TextInputTypeChanged(
+ ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) {
+ if (text_input_type_ != type ||
+ text_input_mode_ != input_mode ||
+ can_compose_inline_ != can_compose_inline ||
+ text_input_flags_ != flags) {
+ text_input_type_ = type;
+ text_input_mode_ = input_mode;
+ can_compose_inline_ = can_compose_inline;
+ text_input_flags_ = flags;
if (GetInputMethod())
GetInputMethod()->OnTextInputTypeChanged(this);
if (touch_editing_client_)
touch_editing_client_->OnTextInputTypeChanged(text_input_type_);
}
+}
+
+void RenderWidgetHostViewAura::OnTextInputStateChanged(
+ const ViewHostMsg_TextInputState_Params& params) {
+ text_input_flags_ = params.flags;
if (params.show_ime_if_needed && params.type != ui::TEXT_INPUT_TYPE_NONE) {
if (GetInputMethod())
GetInputMethod()->ShowImeIfNeeded();
@@ -884,9 +918,7 @@ void RenderWidgetHostViewAura::SelectionChanged(const base::string16& text,
}
// Set the CLIPBOARD_TYPE_SELECTION to the ui::Clipboard.
- ui::ScopedClipboardWriter clipboard_writer(
- ui::Clipboard::GetForCurrentThread(),
- ui::CLIPBOARD_TYPE_SELECTION);
+ ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_SELECTION);
clipboard_writer.WriteText(text.substr(pos, n));
#endif // defined(USE_X11) && !defined(OS_CHROMEOS)
}
@@ -913,23 +945,13 @@ void RenderWidgetHostViewAura::SelectionBoundsChanged(
}
}
-void RenderWidgetHostViewAura::ScrollOffsetChanged() {
- aura::Window* root = window_->GetRootWindow();
- if (!root)
- return;
- aura::client::CursorClient* cursor_client =
- aura::client::GetCursorClient(root);
- if (cursor_client && !cursor_client->IsCursorVisible())
- cursor_client->DisableMouseEvents();
-}
-
void RenderWidgetHostViewAura::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) {
+ CopyFromCompositingSurfaceCallback& callback,
+ const SkColorType color_type) {
delegated_frame_host_->CopyFromCompositingSurface(
- src_subrect, dst_size, callback, config);
+ src_subrect, dst_size, callback, color_type);
}
void RenderWidgetHostViewAura::CopyFromCompositingSurfaceToVideoFrame(
@@ -957,74 +979,6 @@ void RenderWidgetHostViewAura::EndFrameSubscription() {
delegated_frame_host_->EndFrameSubscription();
}
-void RenderWidgetHostViewAura::AcceleratedSurfaceInitialized(int host_id,
- int route_id) {
-}
-
-void RenderWidgetHostViewAura::SnapToPhysicalPixelBoundary() {
- // The top left corner of our view in window coordinates might not land on a
- // device pixel boundary if we have a non-integer device scale. In that case,
- // 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.
- gfx::Point view_offset_dips = window_->GetBoundsInRootWindow().origin();
- gfx::PointF view_offset = view_offset_dips;
- view_offset.Scale(current_device_scale_factor_);
- gfx::PointF view_offset_snapped(std::ceil(view_offset.x()),
- std::ceil(view_offset.y()));
-
- gfx::Vector2dF fudge = view_offset_snapped - view_offset;
- fudge.Scale(1.0 / current_device_scale_factor_);
- GetLayer()->SetSubpixelPositionOffset(fudge);
-}
-
-void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
- if (HasDisplayPropertyChanged(window_))
- host_->InvalidateScreenInfo();
-
- SnapToPhysicalPixelBoundary();
- // Don't recursively call SetBounds if this bounds update is the result of
- // a Window::SetBoundsInternal call.
- if (!in_bounds_changed_)
- window_->SetBounds(rect);
- host_->WasResized();
- delegated_frame_host_->WasResized();
- if (touch_editing_client_) {
- touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_,
- selection_focus_rect_);
- }
-#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.
- if (GetNativeViewId()) {
- if (!legacy_render_widget_host_HWND_) {
- legacy_render_widget_host_HWND_ = LegacyRenderWidgetHostHWND::Create(
- reinterpret_cast<HWND>(GetNativeViewId()));
- BrowserAccessibilityManagerWin* manager =
- static_cast<BrowserAccessibilityManagerWin*>(
- GetBrowserAccessibilityManager());
- if (manager)
- manager->SetAccessibleHWND(legacy_render_widget_host_HWND_.get());
- }
- if (legacy_render_widget_host_HWND_) {
- legacy_render_widget_host_HWND_->SetBounds(
- window_->GetBoundsInRootWindow());
- }
- }
-
- if (mouse_locked_)
- UpdateMouseLockRegion();
-#endif
-}
-
#if defined(OS_WIN)
bool RenderWidgetHostViewAura::UsesNativeWindowFrame() const {
return (legacy_render_widget_host_HWND_ != NULL);
@@ -1058,18 +1012,14 @@ void RenderWidgetHostViewAura::UpdateMouseLockRegion() {
::ClipCursor(&window_rect);
}
}
-#endif
-
-void RenderWidgetHostViewAura::AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel,
- int gpu_host_id) {
- // Oldschool composited mode is no longer supported.
-}
+#endif // defined(OS_WIN)
void RenderWidgetHostViewAura::OnSwapCompositorFrame(
uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) {
TRACE_EVENT0("content", "RenderWidgetHostViewAura::OnSwapCompositorFrame");
+
+ last_scroll_offset_ = frame->metadata.root_scroll_offset;
if (frame->delegated_frame_data) {
delegated_frame_host_->SwapDelegatedFrame(
output_surface_id,
@@ -1088,37 +1038,32 @@ void RenderWidgetHostViewAura::OnSwapCompositorFrame(
}
}
+void RenderWidgetHostViewAura::DidStopFlinging() {
+ if (touch_editing_client_)
+ touch_editing_client_->DidStopFlinging();
+}
+
#if defined(OS_WIN)
+void RenderWidgetHostViewAura::SetLegacyRenderWidgetHostHWND(
+ LegacyRenderWidgetHostHWND* legacy_hwnd) {
+ legacy_render_widget_host_HWND_ = legacy_hwnd;
+}
+
void RenderWidgetHostViewAura::SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) {
- if (GetBrowserAccessibilityManager()) {
- GetBrowserAccessibilityManager()->ToBrowserAccessibilityManagerWin()
- ->set_parent_iaccessible(accessible_parent);
- }
}
gfx::NativeViewId RenderWidgetHostViewAura::GetParentForWindowlessPlugin()
const {
if (legacy_render_widget_host_HWND_) {
- return reinterpret_cast<gfx::NativeViewId>(
- legacy_render_widget_host_HWND_->hwnd());
+ HWND hwnd = legacy_render_widget_host_HWND_->hwnd();
+ if (::IsWindow(hwnd))
+ return reinterpret_cast<gfx::NativeViewId>(hwnd);
}
return NULL;
}
#endif
-void RenderWidgetHostViewAura::AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel,
- int gpu_host_id) {
- // Oldschool composited mode is no longer supported.
-}
-
-void RenderWidgetHostViewAura::AcceleratedSurfaceSuspend() {
-}
-
-void RenderWidgetHostViewAura::AcceleratedSurfaceRelease() {
-}
-
bool RenderWidgetHostViewAura::HasAcceleratedSurface(
const gfx::Size& desired_size) {
// Aura doesn't use GetBackingStore for accelerated pages, so it doesn't
@@ -1239,30 +1184,129 @@ InputEventAckState RenderWidgetHostViewAura::FilterInputEvent(
: INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}
-void RenderWidgetHostViewAura::CreateBrowserAccessibilityManagerIfNeeded() {
+BrowserAccessibilityManager*
+RenderWidgetHostViewAura::CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) {
+ BrowserAccessibilityManager* manager = NULL;
#if defined(OS_WIN)
- if (!GetBrowserAccessibilityManager()) {
- gfx::NativeViewAccessible accessible_parent =
- host_->GetParentNativeViewAccessible();
- LegacyRenderWidgetHostHWND* parent_hwnd =
- legacy_render_widget_host_HWND_.get();
- SetBrowserAccessibilityManager(new BrowserAccessibilityManagerWin(
- legacy_render_widget_host_HWND_.get(), accessible_parent,
- BrowserAccessibilityManagerWin::GetEmptyDocument(), host_));
- }
+ manager = new BrowserAccessibilityManagerWin(
+ BrowserAccessibilityManagerWin::GetEmptyDocument(), delegate);
#else
- if (!GetBrowserAccessibilityManager()) {
- SetBrowserAccessibilityManager(
- BrowserAccessibilityManager::Create(
- BrowserAccessibilityManager::GetEmptyDocument(), host_));
+ manager = BrowserAccessibilityManager::Create(
+ BrowserAccessibilityManager::GetEmptyDocument(), delegate);
+#endif
+ return manager;
+}
+
+gfx::AcceleratedWidget
+RenderWidgetHostViewAura::AccessibilityGetAcceleratedWidget() {
+#if defined(OS_WIN)
+ if (legacy_render_widget_host_HWND_) {
+ HWND hwnd = legacy_render_widget_host_HWND_->hwnd();
+ if (::IsWindow(hwnd))
+ return hwnd;
}
#endif
+ return gfx::kNullAcceleratedWidget;
+}
+
+gfx::NativeViewAccessible
+RenderWidgetHostViewAura::AccessibilityGetNativeViewAccessible() {
+#if defined(OS_WIN)
+ if (legacy_render_widget_host_HWND_)
+ return legacy_render_widget_host_HWND_->window_accessible();
+#endif
+ return NULL;
+
}
gfx::GLSurfaceHandle RenderWidgetHostViewAura::GetCompositingSurface() {
return ImageTransportFactory::GetInstance()->GetSharedSurfaceHandle();
}
+void RenderWidgetHostViewAura::ShowDisambiguationPopup(
+ const gfx::Rect& rect_pixels,
+ const SkBitmap& zoomed_bitmap) {
+ // |target_rect| is provided in pixels, not DIPs. So we convert it to DIPs
+ // by scaling it by the inverse of the device scale factor.
+ gfx::RectF screen_target_rect_f(rect_pixels);
+ screen_target_rect_f.Scale(1.0f / current_device_scale_factor_);
+ disambiguation_target_rect_ = gfx::ToEnclosingRect(screen_target_rect_f);
+
+ float scale = static_cast<float>(zoomed_bitmap.width()) /
+ static_cast<float>(rect_pixels.width());
+ gfx::Size zoomed_size(gfx::ToCeiledSize(
+ gfx::ScaleSize(disambiguation_target_rect_.size(), scale)));
+
+ // Save of a copy of the |last_scroll_offset_| for comparison when the copy
+ // callback fires, to ensure that we haven't scrolled.
+ disambiguation_scroll_offset_ = last_scroll_offset_;
+
+ CopyFromCompositingSurface(
+ disambiguation_target_rect_,
+ zoomed_size,
+ base::Bind(&RenderWidgetHostViewAura::DisambiguationPopupRendered,
+ base::internal::SupportsWeakPtrBase::StaticAsWeakPtr
+ <RenderWidgetHostViewAura>(this)),
+ kN32_SkColorType);
+}
+
+void RenderWidgetHostViewAura::DisambiguationPopupRendered(
+ bool success,
+ const SkBitmap& result) {
+ if (!success || disambiguation_scroll_offset_ != last_scroll_offset_)
+ return;
+
+ // Use RenderViewHostDelegate to get to the WebContentsViewAura, which will
+ // actually show the delegate.
+ RenderViewHostDelegate* delegate = NULL;
+ if (host_->IsRenderView())
+ delegate = RenderViewHost::From(host_)->GetDelegate();
+ RenderViewHostDelegateView* delegate_view = NULL;
+ if (delegate)
+ delegate_view = delegate->GetDelegateView();
+ if (delegate_view) {
+ delegate_view->ShowDisambiguationPopup(
+ disambiguation_target_rect_,
+ result,
+ base::Bind(&RenderWidgetHostViewAura::ProcessDisambiguationGesture,
+ base::internal::SupportsWeakPtrBase::StaticAsWeakPtr
+ <RenderWidgetHostViewAura>(this)),
+ base::Bind(&RenderWidgetHostViewAura::ProcessDisambiguationMouse,
+ base::internal::SupportsWeakPtrBase::StaticAsWeakPtr
+ <RenderWidgetHostViewAura>(this)));
+ }
+}
+
+void RenderWidgetHostViewAura::HideDisambiguationPopup() {
+ RenderViewHostDelegate* delegate = NULL;
+ if (host_->IsRenderView())
+ delegate = RenderViewHost::From(host_)->GetDelegate();
+ RenderViewHostDelegateView* delegate_view = NULL;
+ if (delegate)
+ delegate_view = delegate->GetDelegateView();
+ if (delegate_view)
+ delegate_view->HideDisambiguationPopup();
+}
+
+void RenderWidgetHostViewAura::ProcessDisambiguationGesture(
+ ui::GestureEvent* event) {
+ blink::WebGestureEvent web_gesture = content::MakeWebGestureEvent(event);
+ // If we fail to make a WebGestureEvent that is a Tap from the provided event,
+ // don't forward it to Blink.
+ if (web_gesture.type < blink::WebInputEvent::Type::GestureTap ||
+ web_gesture.type > blink::WebInputEvent::Type::GestureTapCancel)
+ return;
+
+ host_->ForwardGestureEvent(web_gesture);
+}
+
+void RenderWidgetHostViewAura::ProcessDisambiguationMouse(
+ ui::MouseEvent* event) {
+ blink::WebMouseEvent web_mouse = content::MakeWebMouseEvent(event);
+ host_->ForwardMouseEvent(web_mouse);
+}
+
bool RenderWidgetHostViewAura::LockMouse() {
aura::Window* root_window = window_->GetRootWindow();
if (!root_window)
@@ -1400,6 +1444,10 @@ ui::TextInputMode RenderWidgetHostViewAura::GetTextInputMode() const {
return text_input_mode_;
}
+int RenderWidgetHostViewAura::GetTextInputFlags() const {
+ return text_input_flags_;
+}
+
bool RenderWidgetHostViewAura::CanComposeInline() const {
return can_compose_inline_;
}
@@ -1651,16 +1699,12 @@ void RenderWidgetHostViewAura::OnCaptureLost() {
}
void RenderWidgetHostViewAura::OnPaint(gfx::Canvas* canvas) {
- // For non-opaque windows, we don't draw anything, since we depend on the
- // canvas coming from the compositor to already be initialized as
- // transparent.
- if (window_->layer()->fills_bounds_opaquely())
- canvas->DrawColor(SK_ColorWHITE);
+ NOTREACHED();
}
void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged(
float device_scale_factor) {
- if (!host_)
+ if (!host_ || !window_->GetRootWindow())
return;
UpdateScreenInfo(window_);
@@ -1669,6 +1713,7 @@ void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged(
GetDisplayNearestWindow(window_);
DCHECK_EQ(device_scale_factor, display.device_scale_factor());
current_cursor_.SetDisplayInfo(display);
+ SnapToPhysicalPixelBoundary();
}
void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window) {
@@ -1683,6 +1728,7 @@ void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window) {
}
LPARAM lparam = reinterpret_cast<LPARAM>(this);
EnumChildWindows(parent, WindowDestroyingCallback, lparam);
+ legacy_render_widget_host_HWND_ = NULL;
#endif
// Make sure that the input method no longer references to this object before
@@ -1697,7 +1743,10 @@ void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window) {
}
void RenderWidgetHostViewAura::OnWindowDestroyed(aura::Window* window) {
- host_->ViewDestroyed();
+ // Ask the RWH to drop reference to us.
+ if (!is_guest_view_hack_)
+ host_->ViewDestroyed();
+
delete this;
}
@@ -1744,10 +1793,7 @@ void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event) {
}
}
}
- if (!in_shutdown_) {
- in_shutdown_ = true;
- host_->Shutdown();
- }
+ Shutdown();
} else {
if (event->key_code() == ui::VKEY_RETURN) {
// Do not forward return key release events if no press event was handled.
@@ -1864,12 +1910,21 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
reinterpret_cast<LPARAM>(toplevel_hwnd));
}
#endif
+ // The Disambiguation popup does not parent itself from this window, so we
+ // manually dismiss it.
+ HideDisambiguationPopup();
+
blink::WebMouseWheelEvent mouse_wheel_event =
MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent*>(event));
if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0)
host_->ForwardWheelEvent(mouse_wheel_event);
} else if (CanRendererHandleEvent(event) &&
!(event->flags() & ui::EF_FROM_TOUCH)) {
+ // Confirm existing composition text on mouse press, to make sure
+ // the input caret won't be moved with an ongoing composition text.
+ if (event->type() == ui::ET_MOUSE_PRESSED)
+ FinishImeCompositionSession();
+
blink::WebMouseEvent mouse_event = MakeWebMouseEvent(event);
ModifyEventMovementAndCoords(&mouse_event);
host_->ForwardMouseEvent(mouse_event);
@@ -1882,12 +1937,10 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
switch (event->type()) {
case ui::ET_MOUSE_PRESSED:
window_->SetCapture();
- // Confirm existing composition text on mouse click events, to make sure
- // the input caret won't be moved with an ongoing composition text.
- FinishImeCompositionSession();
break;
case ui::ET_MOUSE_RELEASED:
- window_->ReleaseCapture();
+ if (!NeedsMouseCapture())
+ window_->ReleaseCapture();
break;
default:
break;
@@ -1899,7 +1952,7 @@ void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event) {
// 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()->delegate() &&
+ if (!is_fullscreen_ && window_->parent() && window_->parent()->delegate() &&
!(event->flags() & ui::EF_FROM_TOUCH)) {
event->ConvertLocationToTarget(window_, window_->parent());
window_->parent()->delegate()->OnMouseEvent(event);
@@ -1977,6 +2030,11 @@ void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event) {
if (touch_editing_client_ && touch_editing_client_->HandleInputEvent(event))
return;
+ // Confirm existing composition text on TAP gesture, to make sure the input
+ // caret won't be moved with an ongoing composition text.
+ if (event->type() == ui::ET_GESTURE_TAP)
+ FinishImeCompositionSession();
+
RenderViewHostDelegate* delegate = NULL;
if (host_->IsRenderView())
delegate = RenderViewHost::From(host_)->GetDelegate();
@@ -2083,7 +2141,8 @@ void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
host_->SetInputMethodActive(false);
}
- BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager();
+ BrowserAccessibilityManager* manager =
+ host_->GetRootBrowserAccessibilityManager();
if (manager)
manager->OnWindowFocused();
} else if (window_ == lost_focus) {
@@ -2099,7 +2158,8 @@ void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
if (overscroll_controller_)
overscroll_controller_->Cancel();
- BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager();
+ BrowserAccessibilityManager* manager =
+ host_->GetRootBrowserAccessibilityManager();
if (manager)
manager->OnWindowBlurred();
@@ -2123,9 +2183,15 @@ void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
return;
}
#endif
- in_shutdown_ = true;
- host_->Shutdown();
+ Shutdown();
+ return;
}
+
+ // Close the child popup window if we lose focus (e.g. due to a JS alert or
+ // system modal dialog). This is particularly important if
+ // |popup_child_host_view_| has mouse capture.
+ if (popup_child_host_view_)
+ popup_child_host_view_->Shutdown();
}
}
@@ -2170,10 +2236,6 @@ RenderWidgetHostViewAura::~RenderWidgetHostViewAura() {
// Aura root window and we don't have a way to get an input method object
// associated with the window, but just in case.
DetachFromInputMethod();
-
-#if defined(OS_WIN)
- legacy_render_widget_host_HWND_.reset(NULL);
-#endif
}
void RenderWidgetHostViewAura::UpdateCursorIfOverSelf() {
@@ -2213,10 +2275,24 @@ ui::InputMethod* RenderWidgetHostViewAura::GetInputMethod() const {
return root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
}
+void RenderWidgetHostViewAura::Shutdown() {
+ if (!in_shutdown_) {
+ in_shutdown_ = true;
+ host_->Shutdown();
+ }
+}
+
bool RenderWidgetHostViewAura::NeedsInputGrab() {
return popup_type_ == blink::WebPopupTypeSelect;
}
+bool RenderWidgetHostViewAura::NeedsMouseCapture() {
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ return NeedsInputGrab();
+#endif
+ return false;
+}
+
void RenderWidgetHostViewAura::FinishImeCompositionSession() {
if (!has_composition_text_)
return;
@@ -2279,6 +2355,48 @@ void RenderWidgetHostViewAura::SetOverscrollControllerEnabled(bool enabled) {
overscroll_controller_.reset(new OverscrollController());
}
+void RenderWidgetHostViewAura::SnapToPhysicalPixelBoundary() {
+ // The top left corner of our view in window coordinates might not land on a
+ // device pixel boundary if we have a non-integer device scale. In that case,
+ // 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();
+ }
+ if (snapped && snapped != window_)
+ ui::SnapLayerToPhysicalPixelBoundary(snapped->layer(), window_->layer());
+
+ has_snapped_to_boundary_ = true;
+}
+
+void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect) {
+ if (HasDisplayPropertyChanged(window_))
+ host_->InvalidateScreenInfo();
+
+ SnapToPhysicalPixelBoundary();
+ // Don't recursively call SetBounds if this bounds update is the result of
+ // a Window::SetBoundsInternal call.
+ if (!in_bounds_changed_)
+ window_->SetBounds(rect);
+ host_->WasResized();
+ delegated_frame_host_->WasResized();
+ if (touch_editing_client_) {
+ touch_editing_client_->OnSelectionOrCursorChanged(selection_anchor_rect_,
+ selection_focus_rect_);
+ }
+#if defined(OS_WIN)
+ if (mouse_locked_)
+ UpdateMouseLockRegion();
+#endif
+}
+
void RenderWidgetHostViewAura::SchedulePaintIfNotInClip(
const gfx::Rect& rect,
const gfx::Rect& clip) {
@@ -2319,14 +2437,6 @@ void RenderWidgetHostViewAura::AddedToRootWindow() {
input_method->SetFocusedTextInputClient(this);
}
-#if defined(OS_WIN)
- // The parent may have changed here. Ensure that the legacy window is
- // reparented accordingly.
- if (legacy_render_widget_host_HWND_)
- legacy_render_widget_host_HWND_->UpdateParent(
- reinterpret_cast<HWND>(GetNativeViewId()));
-#endif
-
delegated_frame_host_->AddedToWindow();
}
@@ -2340,13 +2450,6 @@ void RenderWidgetHostViewAura::RemovingFromRootWindow() {
window_->GetHost()->RemoveObserver(this);
delegated_frame_host_->RemovingFromWindow();
-
-#if defined(OS_WIN)
- // Update the legacy window's parent temporarily to the desktop window. It
- // will eventually get reparented to the right root.
- if (legacy_render_widget_host_HWND_)
- legacy_render_widget_host_HWND_->UpdateParent(::GetDesktopWindow());
-#endif
}
void RenderWidgetHostViewAura::DetachFromInputMethod() {
@@ -2384,8 +2487,8 @@ void RenderWidgetHostViewAura::ForwardKeyboardEvent(
host_->ForwardKeyboardEvent(event);
}
-SkBitmap::Config RenderWidgetHostViewAura::PreferredReadbackFormat() {
- return SkBitmap::kARGB_8888_Config;
+SkColorType RenderWidgetHostViewAura::PreferredReadbackFormat() {
+ return kN32_SkColorType;
}
////////////////////////////////////////////////////////////////////////////////
@@ -2404,11 +2507,6 @@ RenderWidgetHostImpl* RenderWidgetHostViewAura::GetHost() {
return host_;
}
-void RenderWidgetHostViewAura::SchedulePaintInRect(
- const gfx::Rect& damage_rect_in_dip) {
- window_->SchedulePaintInRect(damage_rect_in_dip);
-}
-
bool RenderWidgetHostViewAura::IsVisible() {
return IsShowing();
}
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 8eab68b8851..ee70b04cac9 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
@@ -35,8 +35,6 @@
#include "ui/wm/public/activation_change_observer.h"
#include "ui/wm/public/activation_delegate.h"
-struct ViewHostMsg_TextInputState_Params;
-
namespace aura {
class WindowTracker;
namespace client {
@@ -116,6 +114,10 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Notifies the client that a gesture event ack was received.
virtual void GestureEventAck(int gesture_event_type) = 0;
+ // Notifies the client that the fling has ended, so it can activate touch
+ // editing if needed.
+ virtual void DidStopFlinging() = 0;
+
// This is called when the view is destroyed, so that the client can
// perform any necessary clean-up.
virtual void OnViewDestroyed() = 0;
@@ -128,192 +130,193 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
touch_editing_client_ = client;
}
- explicit RenderWidgetHostViewAura(RenderWidgetHost* host);
+ // When |is_guest_view_hack| is true, this view isn't really the view for
+ // the |widget|, a RenderWidgetHostViewGuest is.
+ //
+ // TODO(lazyboy): Remove |is_guest_view_hack| once BrowserPlugin has migrated
+ // to use RWHVChildFrame (http://crbug.com/330264).
+ RenderWidgetHostViewAura(RenderWidgetHost* host, bool is_guest_view_hack);
// RenderWidgetHostView implementation.
- virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE;
- virtual RenderWidgetHost* GetRenderWidgetHost() const OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void SetBounds(const gfx::Rect& rect) OVERRIDE;
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeViewId GetNativeViewId() const OVERRIDE;
- virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
- virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
- virtual bool HasFocus() const OVERRIDE;
- virtual bool IsSurfaceAvailableForCopy() const OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual bool IsShowing() OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
- virtual void SetBackgroundOpaque(bool opaque) OVERRIDE;
- virtual gfx::Size GetVisibleViewportSize() const OVERRIDE;
- virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void InitAsChild(gfx::NativeView parent_view) override;
+ RenderWidgetHost* GetRenderWidgetHost() const override;
+ void SetSize(const gfx::Size& size) override;
+ void SetBounds(const gfx::Rect& rect) override;
+ gfx::Vector2dF GetLastScrollOffset() const override;
+ gfx::NativeView GetNativeView() const override;
+ gfx::NativeViewId GetNativeViewId() const override;
+ gfx::NativeViewAccessible GetNativeViewAccessible() override;
+ ui::TextInputClient* GetTextInputClient() override;
+ bool HasFocus() const override;
+ bool IsSurfaceAvailableForCopy() const override;
+ void Show() override;
+ void Hide() override;
+ bool IsShowing() override;
+ gfx::Rect GetViewBounds() const override;
+ void SetBackgroundColor(SkColor color) override;
+ gfx::Size GetVisibleViewportSize() const override;
+ void SetInsets(const gfx::Insets& insets) override;
// Overridden from RenderWidgetHostViewBase:
- virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) OVERRIDE;
- virtual void InitAsFullscreen(
- RenderWidgetHostView* reference_host_view) OVERRIDE;
- virtual void WasShown() OVERRIDE;
- virtual void WasHidden() OVERRIDE;
- virtual void MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void Blur() OVERRIDE;
- virtual void UpdateCursor(const WebCursor& cursor) OVERRIDE;
- virtual void SetIsLoading(bool is_loading) OVERRIDE;
- virtual void TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) OVERRIDE;
- virtual void ImeCancelComposition() OVERRIDE;
- virtual void ImeCompositionRangeChanged(
+ void InitAsPopup(RenderWidgetHostView* parent_host_view,
+ const gfx::Rect& pos) override;
+ void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
+ void WasShown() override;
+ void WasHidden() override;
+ void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
+ void Focus() override;
+ void Blur() override;
+ void UpdateCursor(const WebCursor& cursor) override;
+ void SetIsLoading(bool is_loading) override;
+ void TextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) override;
+ void ImeCancelComposition() override;
+ void ImeCompositionRangeChanged(
const gfx::Range& range,
- const std::vector<gfx::Rect>& character_bounds) OVERRIDE;
- virtual void RenderProcessGone(base::TerminationStatus status,
- int error_code) OVERRIDE;
- virtual void Destroy() OVERRIDE;
- virtual void SetTooltipText(const base::string16& tooltip_text) OVERRIDE;
- virtual void SelectionChanged(const base::string16& text,
- size_t offset,
- const gfx::Range& range) OVERRIDE;
- virtual gfx::Size GetRequestedRendererSize() const OVERRIDE;
- virtual void SelectionBoundsChanged(
- const ViewHostMsg_SelectionBounds_Params& params) OVERRIDE;
- virtual void ScrollOffsetChanged() OVERRIDE;
- virtual void CopyFromCompositingSurface(
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) OVERRIDE;
- virtual void CopyFromCompositingSurfaceToVideoFrame(
+ const std::vector<gfx::Rect>& character_bounds) override;
+ void RenderProcessGone(base::TerminationStatus status,
+ int error_code) override;
+ void Destroy() override;
+ void SetTooltipText(const base::string16& tooltip_text) override;
+ void SelectionChanged(const base::string16& text,
+ size_t offset,
+ const gfx::Range& range) override;
+ gfx::Size GetRequestedRendererSize() const override;
+ void SelectionBoundsChanged(
+ const ViewHostMsg_SelectionBounds_Params& params) override;
+ void CopyFromCompositingSurface(const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ CopyFromCompositingSurfaceCallback& callback,
+ const SkColorType color_type) override;
+ void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) OVERRIDE;
- virtual bool CanCopyToVideoFrame() const OVERRIDE;
- virtual bool CanSubscribeFrame() const OVERRIDE;
- virtual void BeginFrameSubscription(
- scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) OVERRIDE;
- virtual void EndFrameSubscription() OVERRIDE;
- virtual void AcceleratedSurfaceInitialized(int host_id,
- int route_id) OVERRIDE;
- virtual void AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfaceSuspend() OVERRIDE;
- virtual void AcceleratedSurfaceRelease() OVERRIDE;
- virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE;
- virtual void GetScreenInfo(blink::WebScreenInfo* results) OVERRIDE;
- virtual gfx::Rect GetBoundsInRootWindow() OVERRIDE;
- virtual void WheelEventAck(const blink::WebMouseWheelEvent& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void GestureEventAck(const blink::WebGestureEvent& event,
- InputEventAckState ack_result) OVERRIDE;
- virtual void ProcessAckedTouchEvent(
- const TouchEventWithLatencyInfo& touch,
- InputEventAckState ack_result) OVERRIDE;
- virtual scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget()
- OVERRIDE;
- virtual InputEventAckState FilterInputEvent(
- const blink::WebInputEvent& input_event) OVERRIDE;
- virtual gfx::GLSurfaceHandle GetCompositingSurface() OVERRIDE;
- virtual void CreateBrowserAccessibilityManagerIfNeeded() OVERRIDE;
- virtual bool LockMouse() OVERRIDE;
- virtual void UnlockMouse() OVERRIDE;
- virtual void OnSwapCompositorFrame(
- uint32 output_surface_id,
- scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
+ const base::Callback<void(bool)>& callback) override;
+ bool CanCopyToVideoFrame() const override;
+ bool CanSubscribeFrame() const override;
+ void BeginFrameSubscription(
+ scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) override;
+ void EndFrameSubscription() override;
+ bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
+ void GetScreenInfo(blink::WebScreenInfo* results) override;
+ gfx::Rect GetBoundsInRootWindow() override;
+ void WheelEventAck(const blink::WebMouseWheelEvent& event,
+ InputEventAckState ack_result) override;
+ void GestureEventAck(const blink::WebGestureEvent& event,
+ InputEventAckState ack_result) override;
+ void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
+ InputEventAckState ack_result) override;
+ scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget() override;
+ InputEventAckState FilterInputEvent(
+ const blink::WebInputEvent& input_event) override;
+ gfx::GLSurfaceHandle GetCompositingSurface() override;
+ BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) override;
+ gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget() override;
+ gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible() override;
+ void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
+ const SkBitmap& zoomed_bitmap) override;
+ bool LockMouse() override;
+ void UnlockMouse() override;
+ void OnSwapCompositorFrame(uint32 output_surface_id,
+ scoped_ptr<cc::CompositorFrame> frame) override;
+ void DidStopFlinging() override;
#if defined(OS_WIN)
+ void SetLegacyRenderWidgetHostHWND(LegacyRenderWidgetHostHWND* legacy_hwnd);
virtual void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) OVERRIDE;
- virtual gfx::NativeViewId GetParentForWindowlessPlugin() const OVERRIDE;
+ gfx::NativeViewAccessible accessible_parent) override;
+ virtual gfx::NativeViewId GetParentForWindowlessPlugin() const override;
#endif
// Overridden from ui::TextInputClient:
- virtual void SetCompositionText(
- const ui::CompositionText& composition) OVERRIDE;
- virtual void ConfirmCompositionText() OVERRIDE;
- virtual void ClearCompositionText() OVERRIDE;
- virtual void InsertText(const base::string16& text) OVERRIDE;
- virtual void InsertChar(base::char16 ch, int flags) OVERRIDE;
- virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE;
- virtual ui::TextInputType GetTextInputType() const OVERRIDE;
- virtual ui::TextInputMode GetTextInputMode() const OVERRIDE;
- virtual bool CanComposeInline() const OVERRIDE;
- virtual gfx::Rect GetCaretBounds() const OVERRIDE;
- virtual bool GetCompositionCharacterBounds(uint32 index,
- gfx::Rect* rect) const OVERRIDE;
- virtual bool HasCompositionText() const OVERRIDE;
- virtual bool GetTextRange(gfx::Range* range) const OVERRIDE;
- virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE;
- virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE;
- virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE;
- virtual bool DeleteRange(const gfx::Range& range) OVERRIDE;
- virtual bool GetTextFromRange(const gfx::Range& range,
- base::string16* text) const OVERRIDE;
- virtual void OnInputMethodChanged() OVERRIDE;
- virtual bool ChangeTextDirectionAndLayoutAlignment(
- base::i18n::TextDirection direction) OVERRIDE;
- virtual void ExtendSelectionAndDelete(size_t before, size_t after) OVERRIDE;
- virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE;
- virtual void OnCandidateWindowShown() OVERRIDE;
- virtual void OnCandidateWindowUpdated() OVERRIDE;
- virtual void OnCandidateWindowHidden() OVERRIDE;
- virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE;
- virtual void ExecuteEditingCommand(int command_id) OVERRIDE;
+ void SetCompositionText(const ui::CompositionText& composition) override;
+ void ConfirmCompositionText() override;
+ void ClearCompositionText() override;
+ void InsertText(const base::string16& text) override;
+ void InsertChar(base::char16 ch, int flags) override;
+ gfx::NativeWindow GetAttachedWindow() const override;
+ ui::TextInputType GetTextInputType() const override;
+ ui::TextInputMode GetTextInputMode() const override;
+ int GetTextInputFlags() const override;
+ bool CanComposeInline() const override;
+ gfx::Rect GetCaretBounds() const override;
+ bool GetCompositionCharacterBounds(uint32 index,
+ gfx::Rect* rect) const override;
+ bool HasCompositionText() const override;
+ bool GetTextRange(gfx::Range* range) const override;
+ bool GetCompositionTextRange(gfx::Range* range) const override;
+ bool GetSelectionRange(gfx::Range* range) const override;
+ bool SetSelectionRange(const gfx::Range& range) override;
+ bool DeleteRange(const gfx::Range& range) override;
+ bool GetTextFromRange(const gfx::Range& range,
+ base::string16* text) const override;
+ void OnInputMethodChanged() override;
+ bool ChangeTextDirectionAndLayoutAlignment(
+ base::i18n::TextDirection direction) override;
+ void ExtendSelectionAndDelete(size_t before, size_t after) override;
+ void EnsureCaretInRect(const gfx::Rect& rect) override;
+ void OnCandidateWindowShown() override;
+ void OnCandidateWindowUpdated() override;
+ void OnCandidateWindowHidden() override;
+ bool IsEditingCommandEnabled(int command_id) override;
+ void ExecuteEditingCommand(int command_id) override;
// Overridden from gfx::DisplayObserver:
- virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE;
- virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE;
- virtual void OnDisplayMetricsChanged(const gfx::Display& display,
- uint32_t metrics) OVERRIDE;
+ void OnDisplayAdded(const gfx::Display& new_display) override;
+ void OnDisplayRemoved(const gfx::Display& old_display) override;
+ void OnDisplayMetricsChanged(const gfx::Display& display,
+ uint32_t metrics) override;
// Overridden from aura::WindowDelegate:
- virtual gfx::Size GetMinimumSize() const OVERRIDE;
- virtual gfx::Size GetMaximumSize() const OVERRIDE;
- virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) OVERRIDE;
- virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE;
- virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
- virtual bool ShouldDescendIntoChildForEventHandling(
+ gfx::Size GetMinimumSize() const override;
+ gfx::Size GetMaximumSize() const override;
+ void OnBoundsChanged(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) override;
+ gfx::NativeCursor GetCursor(const gfx::Point& point) override;
+ int GetNonClientComponent(const gfx::Point& point) const override;
+ bool ShouldDescendIntoChildForEventHandling(
aura::Window* child,
- const gfx::Point& location) OVERRIDE;
- virtual bool CanFocus() OVERRIDE;
- virtual void OnCaptureLost() OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
- virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE;
- virtual bool HasHitTestMask() const OVERRIDE;
- virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
+ const gfx::Point& location) override;
+ bool CanFocus() override;
+ void OnCaptureLost() override;
+ void OnPaint(gfx::Canvas* canvas) override;
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override;
+ void OnWindowDestroying(aura::Window* window) override;
+ void OnWindowDestroyed(aura::Window* window) override;
+ void OnWindowTargetVisibilityChanged(bool visible) override;
+ bool HasHitTestMask() const override;
+ void GetHitTestMask(gfx::Path* mask) const override;
// Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+ void OnKeyEvent(ui::KeyEvent* event) override;
+ void OnMouseEvent(ui::MouseEvent* event) override;
+ void OnScrollEvent(ui::ScrollEvent* event) override;
+ void OnTouchEvent(ui::TouchEvent* event) override;
+ void OnGestureEvent(ui::GestureEvent* event) override;
// Overridden from aura::client::ActivationDelegate:
- virtual bool ShouldActivate() const OVERRIDE;
+ bool ShouldActivate() const override;
// Overridden from aura::client::ActivationChangeObserver:
- virtual void OnWindowActivated(aura::Window* gained_activation,
- aura::Window* lost_activation) OVERRIDE;
+ void OnWindowActivated(aura::Window* gained_activation,
+ aura::Window* lost_activation) override;
// Overridden from aura::client::CursorClientObserver:
- virtual void OnCursorVisibilityChanged(bool is_visible) OVERRIDE;
+ void OnCursorVisibilityChanged(bool is_visible) override;
// Overridden from aura::client::FocusChangeObserver:
- virtual void OnWindowFocused(aura::Window* gained_focus,
- aura::Window* lost_focus) OVERRIDE;
+ void OnWindowFocused(aura::Window* gained_focus,
+ aura::Window* lost_focus) override;
// Overridden from aura::WindowTreeHostObserver:
- virtual void OnHostMoved(const aura::WindowTreeHost* host,
- const gfx::Point& new_origin) OVERRIDE;
+ void OnHostMoved(const aura::WindowTreeHost* host,
+ const gfx::Point& new_origin) override;
+
+ void OnTextInputStateChanged(const ViewHostMsg_TextInputState_Params& params);
#if defined(OS_WIN)
// Sets the cutout rects from constrained windows. These are rectangles that
@@ -325,6 +328,14 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void UpdateMouseLockRegion();
#endif
+ void DisambiguationPopupRendered(bool success, const SkBitmap& result);
+
+ void HideDisambiguationPopup();
+
+ void ProcessDisambiguationGesture(ui::GestureEvent* event);
+
+ void ProcessDisambiguationMouse(ui::MouseEvent* event);
+
// Method to indicate if this instance is shutting down or closing.
// TODO(shrikant): Discuss around to see if it makes sense to add this method
// as part of RenderWidgetHostView.
@@ -333,25 +344,30 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
// Sets whether the overscroll controller should be enabled for this page.
void SetOverscrollControllerEnabled(bool enabled);
+ void SnapToPhysicalPixelBoundary();
+
OverscrollController* overscroll_controller() const {
return overscroll_controller_.get();
}
protected:
- virtual ~RenderWidgetHostViewAura();
+ ~RenderWidgetHostViewAura() override;
// Exposed for tests.
aura::Window* window() { return window_; }
- virtual SkBitmap::Config PreferredReadbackFormat() OVERRIDE;
- virtual DelegatedFrameHost* GetDelegatedFrameHost() const OVERRIDE;
+ SkColorType PreferredReadbackFormat() override;
+ DelegatedFrameHost* GetDelegatedFrameHost() const override;
private:
+ FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
+ PopupRetainsCaptureAfterMouseRelease);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, SetCompositionText);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, TouchEventState);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
TouchEventPositionsArentRounded);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, TouchEventSyncAsync);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, SwapNotifiesWindow);
+ FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, RecreateLayers);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
SkippedDelegatedFrames);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange);
@@ -368,13 +384,19 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
VisibleViewportTest);
FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
OverscrollResetsOnBlur);
+ FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraTest,
+ FinishCompositionByMouse);
+ FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest,
+ WebContentsViewReparent);
class WindowObserver;
friend class WindowObserver;
void UpdateCursorIfOverSelf();
- void SnapToPhysicalPixelBoundary();
+ // Tracks whether SnapToPhysicalPixelBoundary() has been called.
+ bool has_snapped_to_boundary() { return has_snapped_to_boundary_; }
+ void ResetHasSnappedToBoundary() { has_snapped_to_boundary_ = false; }
// Set the bounds of the window and handle size changes. Assumes the caller
// has already adjusted the origin of |rect| to conform to whatever coordinate
@@ -387,9 +409,15 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
ui::InputMethod* GetInputMethod() const;
+ // Sends shutdown request.
+ void Shutdown();
+
// Returns whether the widget needs an input grab to work properly.
bool NeedsInputGrab();
+ // Returns whether the widget needs to grab mouse capture to work properly.
+ bool NeedsMouseCapture();
+
// Confirm existing composition text in the webpage and ask the input method
// to cancel its ongoing composition session.
void FinishImeCompositionSession();
@@ -417,17 +445,14 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
void RemovingFromRootWindow();
// DelegatedFrameHostClient implementation.
- virtual ui::Compositor* GetCompositor() const OVERRIDE;
- virtual ui::Layer* GetLayer() OVERRIDE;
- virtual RenderWidgetHostImpl* GetHost() OVERRIDE;
- virtual void SchedulePaintInRect(
- const gfx::Rect& damage_rect_in_dip) OVERRIDE;
- virtual bool IsVisible() OVERRIDE;
- virtual scoped_ptr<ResizeLock> CreateResizeLock(
- bool defer_compositor_lock) OVERRIDE;
- virtual gfx::Size DesiredFrameSize() OVERRIDE;
- virtual float CurrentDeviceScaleFactor() OVERRIDE;
- virtual gfx::Size ConvertViewSizeToPixel(const gfx::Size& size) OVERRIDE;
+ ui::Compositor* GetCompositor() const override;
+ ui::Layer* GetLayer() override;
+ RenderWidgetHostImpl* GetHost() override;
+ bool IsVisible() override;
+ scoped_ptr<ResizeLock> CreateResizeLock(bool defer_compositor_lock) override;
+ gfx::Size DesiredFrameSize() override;
+ float CurrentDeviceScaleFactor() override;
+ gfx::Size ConvertViewSizeToPixel(const gfx::Size& size) override;
// Detaches |this| from the input method object.
void DetachFromInputMethod();
@@ -497,6 +522,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
ui::TextInputType text_input_type_;
// The current text input mode corresponding to HTML5 inputmode attribute.
ui::TextInputMode text_input_mode_;
+ // The current text input flags.
+ int text_input_flags_;
bool can_compose_inline_;
// Rectangles for the selection anchor and focus.
@@ -531,7 +558,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
gfx::Point unlocked_global_mouse_position_;
// Last cursor position relative to screen. Used to compute movementX/Y.
gfx::Point global_mouse_position_;
- // In mouse locked mode, we syntheticaly move the mouse cursor to the center
+ // In mouse locked mode, we synthetically move the mouse cursor to the center
// of the window when it reaches the window borders to avoid it going outside.
// This flag is used to differentiate between these synthetic mouse move
// events vs. normal mouse move events.
@@ -557,32 +584,46 @@ class CONTENT_EXPORT RenderWidgetHostViewAura
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 windoiws
+ // 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,
+ // etc.
+ content::LegacyRenderWidgetHostHWND* legacy_render_widget_host_HWND_;
#endif
+ bool has_snapped_to_boundary_;
+
TouchEditingClient* touch_editing_client_;
scoped_ptr<OverscrollController> overscroll_controller_;
+ // The last scroll offset of the view.
+ gfx::Vector2dF last_scroll_offset_;
+
gfx::Insets insets_;
std::vector<ui::LatencyInfo> software_latency_info_;
scoped_ptr<aura::client::ScopedTooltipDisabler> tooltip_disabler_;
+ // True when this view acts as a platform view hack for a
+ // RenderWidgetHostViewGuest.
+ bool is_guest_view_hack_;
+
base::WeakPtrFactory<RenderWidgetHostViewAura> weak_ptr_factory_;
-#if defined(OS_WIN)
- // 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,
- // etc.
- scoped_ptr<content::LegacyRenderWidgetHostHWND>
- legacy_render_widget_host_HWND_;
-#endif
+ gfx::Rect disambiguation_target_rect_;
+
+ // The last scroll offset when we start to render the link disambiguation
+ // view, so we can ensure the window hasn't moved between copying from the
+ // compositing surface and showing the disambiguation popup.
+ gfx::Vector2dF disambiguation_scroll_offset_;
+
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 d05bd44da8b..511c68cec11 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
@@ -13,8 +13,12 @@
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/copy_output_request.h"
+#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/test/no_transport_image_transport_factory.h"
+#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
@@ -38,7 +42,6 @@
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/test/aura_test_helper.h"
-#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_cursor_client.h"
#include "ui/aura/test/test_screen.h"
#include "ui/aura/test/test_window_delegate.h"
@@ -47,12 +50,15 @@
#include "ui/aura/window_observer.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/compositor.h"
+#include "ui/compositor/layer_tree_owner.h"
#include "ui/compositor/test/draw_waiter_for_test.h"
-#include "ui/compositor/test/in_process_context_factory.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
-#include "ui/events/gestures/gesture_configuration.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
+#include "ui/events/test/event_generator.h"
#include "ui/wm/core/default_activation_client.h"
+#include "ui/wm/core/default_screen_position_client.h"
+#include "ui/wm/core/window_util.h"
using testing::_;
@@ -66,35 +72,6 @@ using blink::WebTouchPoint;
namespace content {
namespace {
-// Simple screen position client to test coordinate system conversion.
-class TestScreenPositionClient
- : public aura::client::ScreenPositionClient {
- public:
- TestScreenPositionClient() {}
- virtual ~TestScreenPositionClient() {}
-
- // aura::client::ScreenPositionClient overrides:
- virtual void ConvertPointToScreen(const aura::Window* window,
- gfx::Point* point) OVERRIDE {
- point->Offset(-1, -1);
- }
-
- virtual void ConvertPointFromScreen(const aura::Window* window,
- gfx::Point* point) OVERRIDE {
- point->Offset(1, 1);
- }
-
- virtual void ConvertHostPointToScreen(aura::Window* window,
- gfx::Point* point) OVERRIDE {
- ConvertPointToScreen(window, point);
- }
-
- virtual void SetBounds(aura::Window* window,
- const gfx::Rect& bounds,
- const gfx::Display& display) OVERRIDE {
- }
-};
-
class TestOverscrollDelegate : public OverscrollControllerDelegate {
public:
explicit TestOverscrollDelegate(RenderWidgetHostView* view)
@@ -104,7 +81,7 @@ class TestOverscrollDelegate : public OverscrollControllerDelegate {
delta_x_(0.f),
delta_y_(0.f) {}
- virtual ~TestOverscrollDelegate() {}
+ ~TestOverscrollDelegate() override {}
OverscrollMode current_mode() const { return current_mode_; }
OverscrollMode completed_mode() const { return completed_mode_; }
@@ -119,23 +96,24 @@ class TestOverscrollDelegate : public OverscrollControllerDelegate {
private:
// Overridden from OverscrollControllerDelegate:
- virtual gfx::Rect GetVisibleBounds() const OVERRIDE {
+ gfx::Rect GetVisibleBounds() const override {
return view_->IsShowing() ? view_->GetViewBounds() : gfx::Rect();
}
- virtual void OnOverscrollUpdate(float delta_x, float delta_y) OVERRIDE {
+ bool OnOverscrollUpdate(float delta_x, float delta_y) override {
delta_x_ = delta_x;
delta_y_ = delta_y;
+ return true;
}
- virtual void OnOverscrollComplete(OverscrollMode overscroll_mode) OVERRIDE {
+ void OnOverscrollComplete(OverscrollMode overscroll_mode) override {
EXPECT_EQ(current_mode_, overscroll_mode);
completed_mode_ = overscroll_mode;
current_mode_ = OVERSCROLL_NONE;
}
- virtual void OnOverscrollModeChange(OverscrollMode old_mode,
- OverscrollMode new_mode) OVERRIDE {
+ void OnOverscrollModeChange(OverscrollMode old_mode,
+ OverscrollMode new_mode) override {
EXPECT_EQ(current_mode_, old_mode);
current_mode_ = new_mode;
delta_x_ = delta_y_ = 0.f;
@@ -153,7 +131,7 @@ class TestOverscrollDelegate : public OverscrollControllerDelegate {
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
MockRenderWidgetHostDelegate() {}
- virtual ~MockRenderWidgetHostDelegate() {}
+ ~MockRenderWidgetHostDelegate() override {}
};
// Simple observer that keeps track of changes to a window for tests.
@@ -163,7 +141,7 @@ class TestWindowObserver : public aura::WindowObserver {
: window_(window_to_observe) {
window_->AddObserver(this);
}
- virtual ~TestWindowObserver() {
+ ~TestWindowObserver() override {
if (window_)
window_->RemoveObserver(this);
}
@@ -171,7 +149,7 @@ class TestWindowObserver : public aura::WindowObserver {
bool destroyed() const { return destroyed_; }
// aura::WindowObserver overrides:
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
+ void OnWindowDestroyed(aura::Window* window) override {
CHECK_EQ(window, window_);
destroyed_ = true;
window_ = NULL;
@@ -192,9 +170,10 @@ class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
FakeFrameSubscriber(gfx::Size size, base::Callback<void(bool)> callback)
: size_(size), callback_(callback) {}
- virtual bool ShouldCaptureFrame(base::TimeTicks present_time,
- scoped_refptr<media::VideoFrame>* storage,
- DeliverFrameCallback* callback) OVERRIDE {
+ bool ShouldCaptureFrame(const gfx::Rect& damage_rect,
+ base::TimeTicks present_time,
+ scoped_refptr<media::VideoFrame>* storage,
+ DeliverFrameCallback* callback) override {
*storage = media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
size_,
gfx::Rect(size_),
@@ -217,13 +196,14 @@ class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
public:
- FakeRenderWidgetHostViewAura(RenderWidgetHost* widget)
- : RenderWidgetHostViewAura(widget), has_resize_lock_(false) {}
+ FakeRenderWidgetHostViewAura(RenderWidgetHost* widget,
+ bool is_guest_view_hack)
+ : RenderWidgetHostViewAura(widget, is_guest_view_hack),
+ has_resize_lock_(false) {}
- virtual ~FakeRenderWidgetHostViewAura() {}
+ ~FakeRenderWidgetHostViewAura() override {}
- virtual scoped_ptr<ResizeLock> CreateResizeLock(
- bool defer_compositor_lock) OVERRIDE {
+ scoped_ptr<ResizeLock> CreateResizeLock(bool defer_compositor_lock) override {
gfx::Size desired_size = window()->bounds().size();
return scoped_ptr<ResizeLock>(
new FakeResizeLock(desired_size, defer_compositor_lock));
@@ -234,12 +214,11 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
window()->GetHost()->compositor());
}
- virtual bool ShouldCreateResizeLock() OVERRIDE {
+ bool ShouldCreateResizeLock() override {
return GetDelegatedFrameHost()->ShouldCreateResizeLockForTesting();
}
- virtual void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request)
- OVERRIDE {
+ void RequestCopyOfOutput(scoped_ptr<cc::CopyOutputRequest> request) override {
last_copy_request_ = request.Pass();
if (last_copy_request_->has_texture_mailbox()) {
// Give the resulting texture a size.
@@ -256,6 +235,18 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
return GetDelegatedFrameHost()->FrameProviderForTesting();
}
+ cc::SurfaceId surface_id() const {
+ return GetDelegatedFrameHost()->SurfaceIdForTesting();
+ }
+
+ bool HasFrameData() const {
+ return frame_provider() || !surface_id().is_null();
+ }
+
+ bool released_front_lock_active() const {
+ return GetDelegatedFrameHost()->ReleasedFrontLockActiveForTesting();
+ }
+
// A lock that doesn't actually do anything to the compositor, and does not
// time out.
class FakeResizeLock : public ResizeLock {
@@ -273,24 +264,24 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura {
class FullscreenLayoutManager : public aura::LayoutManager {
public:
explicit FullscreenLayoutManager(aura::Window* owner) : owner_(owner) {}
- virtual ~FullscreenLayoutManager() {}
+ ~FullscreenLayoutManager() override {}
// Overridden from aura::LayoutManager:
- virtual void OnWindowResized() OVERRIDE {
+ void OnWindowResized() override {
aura::Window::Windows::const_iterator i;
for (i = owner_->children().begin(); i != owner_->children().end(); ++i) {
(*i)->SetBounds(gfx::Rect());
}
}
- virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE {
+ void OnWindowAddedToLayout(aura::Window* child) override {
child->SetBounds(gfx::Rect());
}
- virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {}
- virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {}
- virtual void OnChildWindowVisibilityChanged(aura::Window* child,
- bool visible) OVERRIDE {}
- virtual void SetChildBounds(aura::Window* child,
- const gfx::Rect& requested_bounds) OVERRIDE {
+ void OnWillRemoveWindowFromLayout(aura::Window* child) override {}
+ void OnWindowRemovedFromLayout(aura::Window* child) override {}
+ void OnChildWindowVisibilityChanged(aura::Window* child,
+ bool visible) override {}
+ void SetChildBounds(aura::Window* child,
+ const gfx::Rect& requested_bounds) override {
SetChildBoundsDirect(child, gfx::Rect(owner_->bounds().size()));
}
@@ -301,7 +292,7 @@ class FullscreenLayoutManager : public aura::LayoutManager {
class MockWindowObserver : public aura::WindowObserver {
public:
- MOCK_METHOD2(OnWindowPaintScheduled, void(aura::Window*, const gfx::Rect&));
+ MOCK_METHOD2(OnDelegatedFrameDamage, void(aura::Window*, const gfx::Rect&));
};
} // namespace
@@ -309,14 +300,17 @@ class MockWindowObserver : public aura::WindowObserver {
class RenderWidgetHostViewAuraTest : public testing::Test {
public:
RenderWidgetHostViewAuraTest()
- : browser_thread_for_ui_(BrowserThread::UI, &message_loop_) {}
+ : widget_host_uses_shutdown_to_destroy_(false),
+ is_guest_view_hack_(false),
+ browser_thread_for_ui_(BrowserThread::UI, &message_loop_) {}
void SetUpEnvironment() {
- ui::ContextFactory* context_factory = new ui::InProcessContextFactory;
ImageTransportFactory::InitializeForUnitTests(
- scoped_ptr<ui::ContextFactory>(context_factory));
+ scoped_ptr<ImageTransportFactory>(
+ new NoTransportImageTransportFactory));
aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
- aura_test_helper_->SetUp(context_factory);
+ aura_test_helper_->SetUp(
+ ImageTransportFactory::GetInstance()->GetContextFactory());
new wm::DefaultActivationClient(aura_test_helper_->root_window());
browser_context_.reset(new TestBrowserContext);
@@ -326,7 +320,8 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
parent_host_ = new RenderWidgetHostImpl(
&delegate_, process_host_, MSG_ROUTING_NONE, false);
- parent_view_ = new RenderWidgetHostViewAura(parent_host_);
+ parent_view_ = new RenderWidgetHostViewAura(parent_host_,
+ is_guest_view_hack_);
parent_view_->InitAsChild(NULL);
aura::client::ParentWindowWithContext(parent_view_->GetNativeView(),
aura_test_helper_->root_window(),
@@ -335,7 +330,7 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
widget_host_ = new RenderWidgetHostImpl(
&delegate_, process_host_, MSG_ROUTING_NONE, false);
widget_host_->Init();
- view_ = new FakeRenderWidgetHostViewAura(widget_host_);
+ view_ = new FakeRenderWidgetHostViewAura(widget_host_, is_guest_view_hack_);
}
void TearDownEnvironment() {
@@ -343,7 +338,11 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
process_host_ = NULL;
if (view_)
view_->Destroy();
- delete widget_host_;
+
+ if (widget_host_uses_shutdown_to_destroy_)
+ widget_host_->Shutdown();
+ else
+ delete widget_host_;
parent_view_->Destroy();
delete parent_host_;
@@ -356,11 +355,20 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
ImageTransportFactory::Terminate();
}
- virtual void SetUp() { SetUpEnvironment(); }
+ void SetUp() override { SetUpEnvironment(); }
- virtual void TearDown() { TearDownEnvironment(); }
+ void TearDown() override { TearDownEnvironment(); }
+
+ void set_widget_host_uses_shutdown_to_destroy(bool use) {
+ widget_host_uses_shutdown_to_destroy_ = use;
+ }
protected:
+ // If true, then calls RWH::Shutdown() instead of deleting RWH.
+ bool widget_host_uses_shutdown_to_destroy_;
+
+ bool is_guest_view_hack_;
+
base::MessageLoopForUI message_loop_;
BrowserThreadImpl browser_thread_for_ui_;
scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_;
@@ -384,13 +392,47 @@ class RenderWidgetHostViewAuraTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAuraTest);
};
+// Helper class to instantiate RenderWidgetHostViewGuest which is backed
+// by an aura platform view.
+class RenderWidgetHostViewGuestAuraTest : public RenderWidgetHostViewAuraTest {
+ public:
+ RenderWidgetHostViewGuestAuraTest() {
+ // Use RWH::Shutdown to destroy RWH, instead of deleting.
+ // This will ensure that the RenderWidgetHostViewGuest is not leaked and
+ // is deleted properly upon RWH going away.
+ set_widget_host_uses_shutdown_to_destroy(true);
+ }
+
+ // We explicitly invoke SetUp to allow gesture debounce customization.
+ void SetUp() override {
+ is_guest_view_hack_ = true;
+
+ RenderWidgetHostViewAuraTest::SetUp();
+
+ guest_view_weak_ = (new RenderWidgetHostViewGuest(
+ widget_host_, NULL, view_->GetWeakPtr()))->GetWeakPtr();
+ }
+
+ void TearDown() override {
+ // Internal override to do nothing, we clean up ourselves in the test body.
+ // This helps us test that |guest_view_weak_| does not leak.
+ }
+
+ protected:
+ base::WeakPtr<RenderWidgetHostViewBase> guest_view_weak_;
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewGuestAuraTest);
+};
+
class RenderWidgetHostViewAuraOverscrollTest
: public RenderWidgetHostViewAuraTest {
public:
RenderWidgetHostViewAuraOverscrollTest() {}
// We explicitly invoke SetUp to allow gesture debounce customization.
- virtual void SetUp() {}
+ void SetUp() override {}
protected:
void SetUpOverscrollEnvironmentWithDebounce(int debounce_interval_in_ms) {
@@ -400,7 +442,7 @@ class RenderWidgetHostViewAuraOverscrollTest
void SetUpOverscrollEnvironment() { SetUpOverscrollEnvironmentImpl(0); }
void SetUpOverscrollEnvironmentImpl(int debounce_interval_in_ms) {
- ui::GestureConfiguration::set_scroll_debounce_interval_in_ms(
+ ui::GestureConfiguration::GetInstance()->set_scroll_debounce_interval_in_ms(
debounce_interval_in_ms);
RenderWidgetHostViewAuraTest::SetUp();
@@ -610,7 +652,7 @@ class RenderWidgetHostViewAuraShutdownTest
public:
RenderWidgetHostViewAuraShutdownTest() {}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
// No TearDownEnvironment here, we do this explicitly during the test.
}
@@ -638,7 +680,7 @@ TEST_F(RenderWidgetHostViewAuraTest, FocusFullscreen) {
// Checks that a popup is positioned correctly relative to its parent using
// screen coordinates.
TEST_F(RenderWidgetHostViewAuraTest, PositionChildPopup) {
- TestScreenPositionClient screen_position_client;
+ wm::DefaultScreenPositionClient screen_position_client;
aura::Window* window = parent_view_->GetNativeView();
aura::Window* root = window->GetRootWindow();
@@ -714,7 +756,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupClickOutsidePopup) {
EXPECT_FALSE(parent_window->GetBoundsInRootWindow().Contains(click_point));
TestWindowObserver observer(window);
- aura::test::EventGenerator generator(window->GetRootWindow(), click_point);
+ ui::test::EventGenerator generator(window->GetRootWindow(), click_point);
generator.ClickLeftButton();
ASSERT_TRUE(parent_view_->HasFocus());
ASSERT_TRUE(observer.destroyed());
@@ -741,7 +783,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupTapOutsidePopup) {
EXPECT_FALSE(parent_window->GetBoundsInRootWindow().Contains(tap_point));
TestWindowObserver observer(window);
- aura::test::EventGenerator generator(window->GetRootWindow(), tap_point);
+ ui::test::EventGenerator generator(window->GetRootWindow(), tap_point);
generator.GestureTapAt(tap_point);
ASSERT_TRUE(parent_view_->HasFocus());
ASSERT_TRUE(observer.destroyed());
@@ -750,6 +792,60 @@ TEST_F(RenderWidgetHostViewAuraTest, DestroyPopupTapOutsidePopup) {
view_ = NULL;
}
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+
+// On Desktop Linux, select boxes need mouse capture in order to work. Test that
+// when a select box is opened via a mouse press that it retains mouse capture
+// after the mouse is released.
+TEST_F(RenderWidgetHostViewAuraTest, PopupRetainsCaptureAfterMouseRelease) {
+ parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400));
+ parent_view_->Focus();
+ EXPECT_TRUE(parent_view_->HasFocus());
+
+ ui::test::EventGenerator generator(
+ parent_view_->GetNativeView()->GetRootWindow(), gfx::Point(300, 300));
+ generator.PressLeftButton();
+
+ view_->SetPopupType(blink::WebPopupTypeSelect);
+ view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100));
+ ASSERT_TRUE(view_->NeedsMouseCapture());
+ aura::Window* window = view_->GetNativeView();
+ EXPECT_TRUE(window->HasCapture());
+
+ generator.ReleaseLeftButton();
+ EXPECT_TRUE(window->HasCapture());
+}
+#endif
+
+// Test that select boxes close when their parent window loses focus (e.g. due
+// to an alert or system modal dialog).
+TEST_F(RenderWidgetHostViewAuraTest, PopupClosesWhenParentLosesFocus) {
+ parent_view_->SetBounds(gfx::Rect(10, 10, 400, 400));
+ parent_view_->Focus();
+ EXPECT_TRUE(parent_view_->HasFocus());
+
+ view_->SetPopupType(blink::WebPopupTypeSelect);
+ view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100));
+
+ aura::Window* popup_window = view_->GetNativeView();
+ TestWindowObserver observer(popup_window);
+
+ aura::test::TestWindowDelegate delegate;
+ scoped_ptr<aura::Window> dialog_window(new aura::Window(&delegate));
+ dialog_window->Init(aura::WINDOW_LAYER_TEXTURED);
+ aura::client::ParentWindowWithContext(
+ dialog_window.get(), popup_window, gfx::Rect());
+ dialog_window->Show();
+ wm::ActivateWindow(dialog_window.get());
+ dialog_window->Focus();
+
+ ASSERT_TRUE(wm::IsActiveWindow(dialog_window.get()));
+ EXPECT_TRUE(observer.destroyed());
+
+ widget_host_ = NULL;
+ view_ = NULL;
+}
+
// Checks that IME-composition-event state is maintained correctly.
TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) {
view_->InitAsChild(NULL);
@@ -776,11 +872,11 @@ TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) {
EXPECT_TRUE(view_->has_composition_text_);
{
const IPC::Message* msg =
- sink_->GetFirstMessageMatching(ViewMsg_ImeSetComposition::ID);
+ sink_->GetFirstMessageMatching(InputMsg_ImeSetComposition::ID);
ASSERT_TRUE(msg != NULL);
- ViewMsg_ImeSetComposition::Param params;
- ViewMsg_ImeSetComposition::Read(msg, &params);
+ InputMsg_ImeSetComposition::Param params;
+ InputMsg_ImeSetComposition::Read(msg, &params);
// composition text
EXPECT_EQ(composition_text.text, params.a);
// underlines
@@ -801,6 +897,49 @@ TEST_F(RenderWidgetHostViewAuraTest, SetCompositionText) {
EXPECT_FALSE(view_->has_composition_text_);
}
+// Checks that sequence of IME-composition-event and mouse-event when mouse
+// clicking to cancel the composition.
+TEST_F(RenderWidgetHostViewAuraTest, FinishCompositionByMouse) {
+ view_->InitAsChild(NULL);
+ view_->Show();
+
+ ui::CompositionText composition_text;
+ composition_text.text = base::ASCIIToUTF16("|a|b");
+
+ // Focused segment
+ composition_text.underlines.push_back(
+ ui::CompositionUnderline(0, 3, 0xff000000, true, 0x78563412));
+
+ // Non-focused segment, with different background color.
+ composition_text.underlines.push_back(
+ ui::CompositionUnderline(3, 4, 0xff000000, false, 0xefcdab90));
+
+ // Caret is at the end. (This emulates Japanese MSIME 2007 and later)
+ composition_text.selection = gfx::Range(4);
+
+ view_->SetCompositionText(composition_text);
+ EXPECT_TRUE(view_->has_composition_text_);
+ sink_->ClearMessages();
+
+ // Simulates the mouse press.
+ ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED,
+ gfx::Point(), gfx::Point(),
+ ui::EF_LEFT_MOUSE_BUTTON, 0);
+ view_->OnMouseEvent(&mouse_event);
+
+ EXPECT_FALSE(view_->has_composition_text_);
+
+ EXPECT_EQ(2U, sink_->message_count());
+
+ if (sink_->message_count() == 2) {
+ // Verify mouse event happens after the confirm-composition event.
+ EXPECT_EQ(InputMsg_ImeConfirmComposition::ID,
+ sink_->GetMessageAt(0)->type());
+ EXPECT_EQ(InputMsg_HandleInputEvent::ID,
+ sink_->GetMessageAt(1)->type());
+ }
+}
+
// Checks that touch-event state is maintained correctly.
TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) {
view_->InitAsChild(NULL);
@@ -882,6 +1021,13 @@ TEST_F(RenderWidgetHostViewAuraTest, TouchEventState) {
view_->touch_event_.touches[0].state);
widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
+ EXPECT_TRUE(widget_host_->ShouldForwardTouchEvent());
+
+ // Ack'ing the outstanding event should flush the pending touch queue.
+ InputHostMsg_HandleInputEvent_ACK_Params ack;
+ ack.type = blink::WebInputEvent::TouchStart;
+ ack.state = INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
+ widget_host_->OnMessageReceived(InputHostMsg_HandleInputEvent_ACK(0, ack));
EXPECT_FALSE(widget_host_->ShouldForwardTouchEvent());
ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 0,
@@ -1147,13 +1293,14 @@ scoped_ptr<cc::CompositorFrame> MakeDelegatedFrame(float scale_factor,
scoped_ptr<cc::RenderPass> pass = cc::RenderPass::Create();
pass->SetNew(
- cc::RenderPass::Id(1, 1), gfx::Rect(size), damage, gfx::Transform());
+ cc::RenderPassId(1, 1), gfx::Rect(size), damage, gfx::Transform());
frame->delegated_frame_data->render_pass_list.push_back(pass.Pass());
return frame.Pass();
}
// Resizing in fullscreen mode should send the up-to-date screen info.
-TEST_F(RenderWidgetHostViewAuraTest, FullscreenResize) {
+// http://crbug.com/324350
+TEST_F(RenderWidgetHostViewAuraTest, DISABLED_FullscreenResize) {
aura::Window* root_window = aura_test_helper_->root_window();
root_window->SetLayoutManager(new FullscreenLayoutManager(root_window));
view_->InitAsFullscreen(parent_view_);
@@ -1223,12 +1370,12 @@ TEST_F(RenderWidgetHostViewAuraTest, SwapNotifiesWindow) {
view_->window_->AddObserver(&observer);
// Delegated renderer path
- EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(view_->window_, view_rect));
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, view_size, view_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
- EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_,
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(view_->window_,
gfx::Rect(5, 5, 5, 5)));
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, view_size, gfx::Rect(5, 5, 5, 5)));
@@ -1237,6 +1384,35 @@ TEST_F(RenderWidgetHostViewAuraTest, SwapNotifiesWindow) {
view_->window_->RemoveObserver(&observer);
}
+// Recreating the layers for a window should cause Surface destruction to
+// depend on both layers.
+TEST_F(RenderWidgetHostViewAuraTest, RecreateLayers) {
+ gfx::Size view_size(100, 100);
+ gfx::Rect view_rect(view_size);
+
+ view_->InitAsChild(NULL);
+ aura::client::ParentWindowWithContext(
+ view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(),
+ gfx::Rect());
+ view_->SetSize(view_size);
+ view_->WasShown();
+
+ view_->OnSwapCompositorFrame(0,
+ MakeDelegatedFrame(1.f, view_size, view_rect));
+ scoped_ptr<ui::LayerTreeOwner> cloned_owner(
+ wm::RecreateLayers(view_->GetNativeView()));
+
+ cc::SurfaceId id = view_->GetDelegatedFrameHost()->SurfaceIdForTesting();
+ if (!id.is_null()) {
+ ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
+ cc::SurfaceManager* manager = factory->GetSurfaceManager();
+ cc::Surface* surface = manager->GetSurfaceForId(id);
+ EXPECT_TRUE(surface);
+ // Should be a SurfaceSequence for both the original and new layers.
+ EXPECT_EQ(2u, surface->GetDestructionDependencyCount());
+ }
+}
+
TEST_F(RenderWidgetHostViewAuraTest, Resize) {
gfx::Size size1(100, 100);
gfx::Size size2(200, 200);
@@ -1254,7 +1430,6 @@ TEST_F(RenderWidgetHostViewAuraTest, Resize) {
root_window->GetHost()->compositor());
ViewHostMsg_UpdateRect_Params update_params;
update_params.view_size = size1;
- update_params.scale_factor = 1.f;
update_params.flags = ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK;
widget_host_->OnMessageReceived(
ViewHostMsg_UpdateRect(widget_host_->GetRoutingID(), update_params));
@@ -1308,10 +1483,23 @@ TEST_F(RenderWidgetHostViewAuraTest, Resize) {
ui::DrawWaiterForTest::WaitForCommit(
root_window->GetHost()->compositor());
EXPECT_EQ(size3.ToString(), view_->GetRequestedRendererSize().ToString());
+ cc::SurfaceId surface_id = view_->surface_id();
+ int swap_index = 0;
+ int resize_index = 1;
+ if (!surface_id.is_null()) {
+ // Frame ack is sent only due to a draw callback with surfaces.
+ ImageTransportFactory::GetInstance()
+ ->GetSurfaceManager()
+ ->GetSurfaceForId(surface_id)
+ ->RunDrawCallbacks();
+ swap_index = 1;
+ resize_index = 0;
+ }
EXPECT_EQ(2u, sink_->message_count());
- EXPECT_EQ(ViewMsg_SwapCompositorFrameAck::ID, sink_->GetMessageAt(0)->type());
+ EXPECT_EQ(ViewMsg_SwapCompositorFrameAck::ID,
+ sink_->GetMessageAt(swap_index)->type());
{
- const IPC::Message* msg = sink_->GetMessageAt(1);
+ const IPC::Message* msg = sink_->GetMessageAt(resize_index);
EXPECT_EQ(ViewMsg_Resize::ID, msg->type());
ViewMsg_Resize::Param params;
ViewMsg_Resize::Read(msg, &params);
@@ -1339,7 +1527,7 @@ TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
view_->window_->AddObserver(&observer);
// A full frame of damage.
- EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(view_->window_, view_rect));
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, frame_size, view_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
@@ -1348,7 +1536,7 @@ TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
// A partial damage frame.
gfx::Rect partial_view_rect(30, 30, 20, 20);
EXPECT_CALL(observer,
- OnWindowPaintScheduled(view_->window_, partial_view_rect));
+ OnDelegatedFrameDamage(view_->window_, partial_view_rect));
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, frame_size, partial_view_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
@@ -1360,14 +1548,14 @@ TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
// This frame is dropped.
gfx::Rect dropped_damage_rect_1(10, 20, 30, 40);
- EXPECT_CALL(observer, OnWindowPaintScheduled(_, _)).Times(0);
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(_, _)).Times(0);
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, frame_size, dropped_damage_rect_1));
testing::Mock::VerifyAndClearExpectations(&observer);
view_->RunOnCompositingDidCommit();
gfx::Rect dropped_damage_rect_2(40, 50, 10, 20);
- EXPECT_CALL(observer, OnWindowPaintScheduled(_, _)).Times(0);
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(_, _)).Times(0);
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, frame_size, dropped_damage_rect_2));
testing::Mock::VerifyAndClearExpectations(&observer);
@@ -1378,7 +1566,7 @@ TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
gfx::Rect new_damage_rect(5, 6, 10, 10);
EXPECT_CALL(observer,
- OnWindowPaintScheduled(view_->window_, view_rect));
+ OnDelegatedFrameDamage(view_->window_, view_rect));
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, frame_size, new_damage_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
@@ -1386,7 +1574,7 @@ TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
// A partial damage frame, this should not be dropped.
EXPECT_CALL(observer,
- OnWindowPaintScheduled(view_->window_, partial_view_rect));
+ OnDelegatedFrameDamage(view_->window_, partial_view_rect));
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, frame_size, partial_view_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
@@ -1402,7 +1590,7 @@ TEST_F(RenderWidgetHostViewAuraTest, SkippedDelegatedFrames) {
view_->SetSize(view_rect.size());
// This frame should not be dropped.
- EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(view_->window_, view_rect));
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, view_rect.size(), view_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
@@ -1426,14 +1614,14 @@ TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) {
view_->window_->AddObserver(&observer);
// Swap a frame.
- EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(view_->window_, view_rect));
view_->OnSwapCompositorFrame(
0, MakeDelegatedFrame(1.f, frame_size, view_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
view_->RunOnCompositingDidCommit();
// Swap a frame with a different surface id.
- EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(view_->window_, view_rect));
view_->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
@@ -1446,7 +1634,7 @@ TEST_F(RenderWidgetHostViewAuraTest, OutputSurfaceIdChange) {
view_->RunOnCompositingDidCommit();
// Swap another frame, with a different surface id.
- EXPECT_CALL(observer, OnWindowPaintScheduled(view_->window_, view_rect));
+ EXPECT_CALL(observer, OnDelegatedFrameDamage(view_->window_, view_rect));
view_->OnSwapCompositorFrame(3,
MakeDelegatedFrame(1.f, frame_size, view_rect));
testing::Mock::VerifyAndClearExpectations(&observer);
@@ -1474,7 +1662,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
hosts[i] = new RenderWidgetHostImpl(
&delegate_, process_host_, MSG_ROUTING_NONE, false);
hosts[i]->Init();
- views[i] = new FakeRenderWidgetHostViewAura(hosts[i]);
+ views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false);
views[i]->InitAsChild(NULL);
aura::client::ParentWindowWithContext(
views[i]->GetNativeView(),
@@ -1488,64 +1676,99 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
views[i]->WasShown();
views[i]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
- EXPECT_TRUE(views[i]->frame_provider());
+ EXPECT_TRUE(views[i]->HasFrameData());
views[i]->WasHidden();
}
// There should be max_renderer_frames with a frame in it, and one without it.
// Since the logic is LRU eviction, the first one should be without.
- EXPECT_FALSE(views[0]->frame_provider());
+ EXPECT_FALSE(views[0]->HasFrameData());
for (size_t i = 1; i < renderer_count; ++i)
- EXPECT_TRUE(views[i]->frame_provider());
+ EXPECT_TRUE(views[i]->HasFrameData());
// LRU renderer is [0], make it visible, it shouldn't evict anything yet.
views[0]->WasShown();
- EXPECT_FALSE(views[0]->frame_provider());
- EXPECT_TRUE(views[1]->frame_provider());
+ EXPECT_FALSE(views[0]->HasFrameData());
+ EXPECT_TRUE(views[1]->HasFrameData());
+ // Since [0] doesn't have a frame, it should be waiting for the renderer to
+ // give it one.
+ EXPECT_TRUE(views[0]->released_front_lock_active());
// Swap a frame on it, it should evict the next LRU [1].
views[0]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
- EXPECT_TRUE(views[0]->frame_provider());
- EXPECT_FALSE(views[1]->frame_provider());
+ EXPECT_TRUE(views[0]->HasFrameData());
+ EXPECT_FALSE(views[1]->HasFrameData());
+ // Now that [0] got a frame, it shouldn't be waiting any more.
+ EXPECT_FALSE(views[0]->released_front_lock_active());
views[0]->WasHidden();
// LRU renderer is [1], still hidden. Swap a frame on it, it should evict
// the next LRU [2].
views[1]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
- EXPECT_TRUE(views[0]->frame_provider());
- EXPECT_TRUE(views[1]->frame_provider());
- EXPECT_FALSE(views[2]->frame_provider());
+ EXPECT_TRUE(views[0]->HasFrameData());
+ EXPECT_TRUE(views[1]->HasFrameData());
+ EXPECT_FALSE(views[2]->HasFrameData());
for (size_t i = 3; i < renderer_count; ++i)
- EXPECT_TRUE(views[i]->frame_provider());
+ EXPECT_TRUE(views[i]->HasFrameData());
// Make all renderers but [0] visible and swap a frame on them, keep [0]
// hidden, it becomes the LRU.
for (size_t i = 1; i < renderer_count; ++i) {
views[i]->WasShown();
+ // The renderers who don't have a frame should be waiting. The ones that
+ // have a frame should not.
+ // In practice, [1] has a frame, but anything after has its frame evicted.
+ EXPECT_EQ(!views[i]->HasFrameData(),
+ views[i]->released_front_lock_active());
views[i]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
- EXPECT_TRUE(views[i]->frame_provider());
+ // Now everyone has a frame.
+ EXPECT_FALSE(views[i]->released_front_lock_active());
+ EXPECT_TRUE(views[i]->HasFrameData());
}
- EXPECT_FALSE(views[0]->frame_provider());
+ EXPECT_FALSE(views[0]->HasFrameData());
// Swap a frame on [0], it should be evicted immediately.
views[0]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
- EXPECT_FALSE(views[0]->frame_provider());
+ EXPECT_FALSE(views[0]->HasFrameData());
// Make [0] visible, and swap a frame on it. Nothing should be evicted
// although we're above the limit.
views[0]->WasShown();
+ // We don't have a frame, wait.
+ EXPECT_TRUE(views[0]->released_front_lock_active());
views[0]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
+ EXPECT_FALSE(views[0]->released_front_lock_active());
for (size_t i = 0; i < renderer_count; ++i)
- EXPECT_TRUE(views[i]->frame_provider());
+ EXPECT_TRUE(views[i]->HasFrameData());
// Make [0] hidden, it should evict its frame.
views[0]->WasHidden();
- EXPECT_FALSE(views[0]->frame_provider());
+ EXPECT_FALSE(views[0]->HasFrameData());
+
+ // Make [0] visible, don't give it a frame, it should be waiting.
+ views[0]->WasShown();
+ EXPECT_TRUE(views[0]->released_front_lock_active());
+ // Make [0] hidden, it should stop waiting.
+ views[0]->WasHidden();
+ EXPECT_FALSE(views[0]->released_front_lock_active());
+
+ // Make [1] hidden, resize it. It should drop its frame.
+ views[1]->WasHidden();
+ EXPECT_TRUE(views[1]->HasFrameData());
+ gfx::Size size2(200, 200);
+ views[1]->SetSize(size2);
+ EXPECT_FALSE(views[1]->HasFrameData());
+ // Show it, it should block until we give it a frame.
+ views[1]->WasShown();
+ EXPECT_TRUE(views[1]->released_front_lock_active());
+ views[1]->OnSwapCompositorFrame(
+ 1, MakeDelegatedFrame(1.f, size2, gfx::Rect(size2)));
+ EXPECT_FALSE(views[1]->released_front_lock_active());
for (size_t i = 0; i < renderer_count - 1; ++i)
views[i]->WasHidden();
@@ -1567,9 +1790,9 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFrames) {
views[renderer_count - 1]->WasHidden();
for (size_t i = 0; i < renderer_count; ++i) {
if (i + 2 < renderer_count)
- EXPECT_FALSE(views[i]->frame_provider());
+ EXPECT_FALSE(views[i]->HasFrameData());
else
- EXPECT_TRUE(views[i]->frame_provider());
+ EXPECT_TRUE(views[i]->HasFrameData());
}
HostSharedBitmapManager::current()->ProcessRemoved(
base::GetCurrentProcessHandle());
@@ -1601,7 +1824,7 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
hosts[i] = new RenderWidgetHostImpl(
&delegate_, process_host_, MSG_ROUTING_NONE, false);
hosts[i]->Init();
- views[i] = new FakeRenderWidgetHostViewAura(hosts[i]);
+ views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false);
views[i]->InitAsChild(NULL);
aura::client::ParentWindowWithContext(
views[i]->GetNativeView(),
@@ -1616,25 +1839,25 @@ TEST_F(RenderWidgetHostViewAuraTest, DiscardDelegatedFramesWithLocking) {
views[i]->WasShown();
views[i]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
- EXPECT_TRUE(views[i]->frame_provider());
+ EXPECT_TRUE(views[i]->HasFrameData());
}
// If we hide [0], then [0] should be evicted.
views[0]->WasHidden();
- EXPECT_FALSE(views[0]->frame_provider());
+ EXPECT_FALSE(views[0]->HasFrameData());
// If we lock [0] before hiding it, then [0] should not be evicted.
views[0]->WasShown();
views[0]->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, frame_size, view_rect));
- EXPECT_TRUE(views[0]->frame_provider());
+ EXPECT_TRUE(views[0]->HasFrameData());
views[0]->GetDelegatedFrameHost()->LockResources();
views[0]->WasHidden();
- EXPECT_TRUE(views[0]->frame_provider());
+ EXPECT_TRUE(views[0]->HasFrameData());
// If we unlock [0] now, then [0] should be evicted.
views[0]->GetDelegatedFrameHost()->UnlockResources();
- EXPECT_FALSE(views[0]->frame_provider());
+ EXPECT_FALSE(views[0]->HasFrameData());
for (size_t i = 0; i < renderer_count; ++i) {
views[i]->Destroy();
@@ -1661,6 +1884,7 @@ TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) {
// 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
// scale on it.
@@ -1670,7 +1894,10 @@ TEST_F(RenderWidgetHostViewAuraTest, SoftwareDPIChange) {
// 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.
- EXPECT_NE(frame_provider.get(), view_->frame_provider());
+ if (frame_provider.get())
+ EXPECT_NE(frame_provider.get(), view_->frame_provider());
+ else
+ EXPECT_NE(surface_id, view_->surface_id());
}
class RenderWidgetHostViewAuraCopyRequestTest
@@ -1715,8 +1942,7 @@ TEST_F(RenderWidgetHostViewAuraCopyRequestTest, DestroyedAfterCopyRequest) {
EXPECT_EQ(0, callback_count_);
EXPECT_FALSE(view_->last_copy_request_);
- view_->BeginFrameSubscription(
- frame_subscriber.PassAs<RenderWidgetHostViewFrameSubscriber>());
+ view_->BeginFrameSubscription(frame_subscriber.Pass());
view_->OnSwapCompositorFrame(
1, MakeDelegatedFrame(1.f, view_rect.size(), gfx::Rect(view_rect)));
@@ -2492,9 +2718,10 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollDirectionChange) {
EXPECT_EQ(0U, sink_->message_count());
// Send another update event, but in the reverse direction. The overscroll
- // controller will consume the event, and reset the overscroll mode.
+ // controller will not consume the event, because it is not triggering
+ // gesture-nav.
SimulateGestureScrollUpdateEvent(-260, 0, 0);
- EXPECT_EQ(0U, sink_->message_count());
+ EXPECT_EQ(1U, sink_->message_count());
EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
// Since the overscroll mode has been reset, the next scroll update events
@@ -2504,6 +2731,33 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollDirectionChange) {
EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
}
+TEST_F(RenderWidgetHostViewAuraOverscrollTest,
+ OverscrollDirectionChangeMouseWheel) {
+ SetUpOverscrollEnvironment();
+
+ // 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);
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode());
+ EXPECT_EQ(OVERSCROLL_EAST, overscroll_delegate()->current_mode());
+ EXPECT_EQ(0U, sink_->message_count());
+
+ // 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, sink_->message_count());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+
+ // Since the overscroll mode has been reset, the next wheel event should reach
+ // the renderer.
+ SimulateWheelEvent(-20, 0, 0, true);
+ EXPECT_EQ(1U, sink_->message_count());
+ EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode());
+}
+
// Tests that if a mouse-move event completes the overscroll gesture, future
// move events do reach the renderer.
TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollMouseMoveCompletion) {
@@ -2682,4 +2936,11 @@ TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollResetsOnBlur) {
EXPECT_EQ(3U, sink_->message_count());
}
+// 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(RenderWidgetHostViewGuestAuraTest, GuestViewDoesNotLeak) {
+ TearDownEnvironment();
+ ASSERT_FALSE(guest_view_weak_.get());
+}
+
} // 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 d5f58e0aab7..b11990ae990 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
@@ -12,7 +12,6 @@
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/content_switches_internal.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
-#include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/size_conversions.h"
@@ -367,7 +366,7 @@ const int kFlushInputRateInUs = 16666;
RenderWidgetHostViewBase::RenderWidgetHostViewBase()
: popup_type_(blink::WebPopupTypeNone),
- background_opaque_(true),
+ background_color_(SK_ColorWHITE),
mouse_locked_(false),
showing_context_menu_(false),
selection_text_offset_(0),
@@ -375,7 +374,8 @@ RenderWidgetHostViewBase::RenderWidgetHostViewBase()
current_device_scale_factor_(0),
current_display_rotation_(gfx::Display::ROTATE_0),
pinch_zoom_enabled_(content::IsPinchToZoomEnabled()),
- renderer_frame_number_(0) {
+ renderer_frame_number_(0),
+ weak_factory_(this) {
}
RenderWidgetHostViewBase::~RenderWidgetHostViewBase() {
@@ -386,12 +386,16 @@ bool RenderWidgetHostViewBase::OnMessageReceived(const IPC::Message& msg){
return false;
}
-void RenderWidgetHostViewBase::SetBackgroundOpaque(bool opaque) {
- background_opaque_ = opaque;
+void RenderWidgetHostViewBase::SetBackgroundColor(SkColor color) {
+ background_color_ = color;
+}
+
+void RenderWidgetHostViewBase::SetBackgroundColorToDefault() {
+ SetBackgroundColor(SK_ColorWHITE);
}
bool RenderWidgetHostViewBase::GetBackgroundOpaque() {
- return background_opaque_;
+ return SkColorGetA(background_color_) == SK_AlphaOPAQUE;
}
gfx::Size RenderWidgetHostViewBase::GetPhysicalBackingSize() const {
@@ -402,7 +406,7 @@ gfx::Size RenderWidgetHostViewBase::GetPhysicalBackingSize() const {
display.device_scale_factor()));
}
-float RenderWidgetHostViewBase::GetOverdrawBottomHeight() const {
+float RenderWidgetHostViewBase::GetTopControlsLayoutHeight() const {
return 0.f;
}
@@ -485,27 +489,28 @@ blink::WebPopupType RenderWidgetHostViewBase::GetPopupType() {
}
BrowserAccessibilityManager*
- RenderWidgetHostViewBase::GetBrowserAccessibilityManager() const {
- return browser_accessibility_manager_.get();
-}
-
-void RenderWidgetHostViewBase::CreateBrowserAccessibilityManagerIfNeeded() {
+RenderWidgetHostViewBase::CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) {
+ NOTREACHED();
+ return NULL;
}
-void RenderWidgetHostViewBase::SetBrowserAccessibilityManager(
- BrowserAccessibilityManager* manager) {
- browser_accessibility_manager_.reset(manager);
+void RenderWidgetHostViewBase::AccessibilityShowMenu(const gfx::Point& point) {
}
-void RenderWidgetHostViewBase::OnAccessibilitySetFocus(int acc_obj_id) {
+gfx::Point RenderWidgetHostViewBase::AccessibilityOriginInScreen(
+ const gfx::Rect& bounds) {
+ return bounds.origin();
}
-void RenderWidgetHostViewBase::AccessibilityShowMenu(int acc_obj_id) {
+gfx::AcceleratedWidget
+ RenderWidgetHostViewBase::AccessibilityGetAcceleratedWidget() {
+ return gfx::kNullAcceleratedWidget;
}
-gfx::Point RenderWidgetHostViewBase::AccessibilityOriginInScreen(
- const gfx::Rect& bounds) {
- return bounds.origin();
+gfx::NativeViewAccessible
+ RenderWidgetHostViewBase::AccessibilityGetNativeViewAccessible() {
+ return NULL;
}
void RenderWidgetHostViewBase::UpdateScreenInfo(gfx::NativeView view) {
@@ -535,6 +540,10 @@ bool RenderWidgetHostViewBase::HasDisplayPropertyChanged(gfx::NativeView view) {
return true;
}
+base::WeakPtr<RenderWidgetHostViewBase> RenderWidgetHostViewBase::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
scoped_ptr<SyntheticGestureTarget>
RenderWidgetHostViewBase::CreateSyntheticGestureTarget() {
RenderWidgetHostImpl* host =
@@ -596,8 +605,21 @@ void RenderWidgetHostViewBase::FlushInput() {
impl->FlushInput();
}
-SkBitmap::Config RenderWidgetHostViewBase::PreferredReadbackFormat() {
- return SkBitmap::kARGB_8888_Config;
+SkColorType RenderWidgetHostViewBase::PreferredReadbackFormat() {
+ return kN32_SkColorType;
+}
+
+void RenderWidgetHostViewBase::OnTextSurroundingSelectionResponse(
+ const base::string16& content,
+ size_t start_offset,
+ size_t end_offset) {
+ NOTIMPLEMENTED();
+}
+
+void RenderWidgetHostViewBase::ShowDisambiguationPopup(
+ const gfx::Rect& rect_pixels,
+ const SkBitmap& zoomed_bitmap) {
+ NOTIMPLEMENTED();
}
gfx::Size RenderWidgetHostViewBase::GetVisibleViewportSize() const {
@@ -608,4 +630,65 @@ void RenderWidgetHostViewBase::SetInsets(const gfx::Insets& insets) {
NOTIMPLEMENTED();
}
+// static
+blink::WebScreenOrientationType
+RenderWidgetHostViewBase::GetOrientationTypeForMobile(
+ const gfx::Display& display) {
+ int angle = display.RotationAsDegree();
+ const gfx::Rect& bounds = display.bounds();
+
+ // Whether the device's natural orientation is portrait.
+ bool natural_portrait = false;
+ if (angle == 0 || angle == 180) // The device is in its natural orientation.
+ natural_portrait = bounds.height() >= bounds.width();
+ else
+ natural_portrait = bounds.height() <= bounds.width();
+
+ switch (angle) {
+ case 0:
+ return natural_portrait ? blink::WebScreenOrientationPortraitPrimary
+ : blink::WebScreenOrientationLandscapePrimary;
+ case 90:
+ return natural_portrait ? blink::WebScreenOrientationLandscapePrimary
+ : blink::WebScreenOrientationPortraitSecondary;
+ case 180:
+ return natural_portrait ? blink::WebScreenOrientationPortraitSecondary
+ : blink::WebScreenOrientationLandscapeSecondary;
+ case 270:
+ return natural_portrait ? blink::WebScreenOrientationLandscapeSecondary
+ : blink::WebScreenOrientationPortraitPrimary;
+ default:
+ NOTREACHED();
+ return blink::WebScreenOrientationPortraitPrimary;
+ }
+}
+
+// static
+blink::WebScreenOrientationType
+RenderWidgetHostViewBase::GetOrientationTypeForDesktop(
+ const gfx::Display& display) {
+ static int primary_landscape_angle = -1;
+ static int primary_portrait_angle = -1;
+
+ int angle = display.RotationAsDegree();
+ const gfx::Rect& bounds = display.bounds();
+ bool is_portrait = bounds.height() >= bounds.width();
+
+ if (is_portrait && primary_portrait_angle == -1)
+ primary_portrait_angle = angle;
+
+ if (!is_portrait && primary_landscape_angle == -1)
+ primary_landscape_angle = angle;
+
+ if (is_portrait) {
+ return primary_portrait_angle == angle
+ ? blink::WebScreenOrientationPortraitPrimary
+ : blink::WebScreenOrientationPortraitSecondary;
+ }
+
+ return primary_landscape_angle == angle
+ ? blink::WebScreenOrientationLandscapePrimary
+ : blink::WebScreenOrientationLandscapeSecondary;
+}
+
} // 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 9bf2e60a48a..9e3a4f384ca 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
@@ -22,6 +22,7 @@
#include "content/common/input/input_event_ack_state.h"
#include "content/public/browser/render_widget_host_view.h"
#include "ipc/ipc_listener.h"
+#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
#include "third_party/WebKit/public/web/WebPopupType.h"
#include "third_party/WebKit/public/web/WebTextDirection.h"
#include "ui/base/ime/text_input_mode.h"
@@ -35,10 +36,7 @@
class SkBitmap;
struct AccessibilityHostMsg_EventParams;
-struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
-struct GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params;
struct ViewHostMsg_SelectionBounds_Params;
-struct ViewHostMsg_TextInputState_Params;
namespace media {
class VideoFrame;
@@ -49,6 +47,7 @@ struct WebScreenInfo;
}
namespace content {
+class BrowserAccessibilityDelegate;
class BrowserAccessibilityManager;
class SyntheticGesture;
class SyntheticGestureTarget;
@@ -57,28 +56,35 @@ struct DidOverscrollParams;
struct NativeWebKeyboardEvent;
struct WebPluginGeometry;
+// TODO(Sikugu): Though we have the return status of the result here,
+// we should add the reason for failure as a new parameter to handle cases
+// efficiently.
+typedef const base::Callback<void(bool, const SkBitmap&)>
+ CopyFromCompositingSurfaceCallback;
+
// Basic implementation shared by concrete RenderWidgetHostView subclasses.
class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
public IPC::Listener {
public:
- virtual ~RenderWidgetHostViewBase();
+ ~RenderWidgetHostViewBase() override;
// RenderWidgetHostView implementation.
- virtual void SetBackgroundOpaque(bool opaque) OVERRIDE;
- virtual bool GetBackgroundOpaque() OVERRIDE;
- virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
- virtual bool IsShowingContextMenu() const OVERRIDE;
- virtual void SetShowingContextMenu(bool showing_menu) OVERRIDE;
- virtual base::string16 GetSelectedText() const OVERRIDE;
- virtual bool IsMouseLocked() OVERRIDE;
- virtual gfx::Size GetVisibleViewportSize() const OVERRIDE;
- virtual void SetInsets(const gfx::Insets& insets) OVERRIDE;
- virtual void BeginFrameSubscription(
- scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) OVERRIDE;
- virtual void EndFrameSubscription() OVERRIDE;
+ void SetBackgroundColor(SkColor color) override;
+ void SetBackgroundColorToDefault() final;
+ bool GetBackgroundOpaque() override;
+ ui::TextInputClient* GetTextInputClient() override;
+ bool IsShowingContextMenu() const override;
+ void SetShowingContextMenu(bool showing_menu) override;
+ base::string16 GetSelectedText() const override;
+ bool IsMouseLocked() override;
+ gfx::Size GetVisibleViewportSize() const override;
+ void SetInsets(const gfx::Insets& insets) override;
+ void BeginFrameSubscription(
+ scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) override;
+ void EndFrameSubscription() override;
// IPC::Listener implementation:
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
// Called by the host when the input flush has completed.
void OnDidFlushInput();
@@ -87,11 +93,6 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
blink::WebPopupType GetPopupType();
- // Get the BrowserAccessibilityManager if it exists, may return NULL.
- BrowserAccessibilityManager* GetBrowserAccessibilityManager() const;
-
- void SetBrowserAccessibilityManager(BrowserAccessibilityManager* manager);
-
// Return a value that is incremented each time the renderer swaps a new frame
// to the view.
uint32 RendererFrameNumber();
@@ -107,6 +108,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// changed since the last time.
bool HasDisplayPropertyChanged(gfx::NativeView view);
+ base::WeakPtr<RenderWidgetHostViewBase> GetWeakPtr();
+
//----------------------------------------------------------------------------
// The following methods can be overridden by derived classes.
@@ -122,9 +125,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// The size of the view's backing surface in non-DPI-adjusted pixels.
virtual gfx::Size GetPhysicalBackingSize() const;
- // The height of the physical backing surface that is overdrawn opaquely in
- // the browser, for example by an on-screen-keyboard (in DPI-adjusted pixels).
- virtual float GetOverdrawBottomHeight() const;
+ // The amount that the viewport size given to Blink is shrunk by the URL-bar.
+ virtual float GetTopControlsLayoutHeight() const;
// Called prior to forwarding input event messages to the renderer, giving
// the view a chance to perform in-process event filtering or processing.
@@ -150,16 +152,16 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// Return true if frame subscription is supported on this platform.
virtual bool CanSubscribeFrame() const;
- // Create a BrowserAccessibilityManager for this view if it's possible to
- // create one and if one doesn't exist already. Some ports may not create
- // one depending on the current state.
- virtual void CreateBrowserAccessibilityManagerIfNeeded();
+ // Create a BrowserAccessibilityManager for this view.
+ virtual BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate);
- virtual void OnAccessibilitySetFocus(int acc_obj_id);
- virtual void AccessibilityShowMenu(int acc_obj_id);
+ virtual void AccessibilityShowMenu(const gfx::Point& point);
virtual gfx::Point AccessibilityOriginInScreen(const gfx::Rect& bounds);
+ virtual gfx::AcceleratedWidget AccessibilityGetAcceleratedWidget();
+ virtual gfx::NativeViewAccessible AccessibilityGetNativeViewAccessible();
- virtual SkBitmap::Config PreferredReadbackFormat();
+ virtual SkColorType PreferredReadbackFormat();
// Informs that the focused DOM node has changed.
virtual void FocusedNodeChanged(bool is_editable_node) {}
@@ -219,8 +221,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
virtual void SetIsLoading(bool is_loading) = 0;
// Updates the type of the input method attached to the view.
- virtual void TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) = 0;
+ virtual void TextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode mode,
+ bool can_compose_inline,
+ int flags) = 0;
// Cancel the ongoing composition of the input method attached to the view.
virtual void ImeCancelComposition() = 0;
@@ -229,6 +233,13 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
virtual void RenderProcessGone(base::TerminationStatus status,
int error_code) = 0;
+ // Notifies the View that the renderer's host has ceased to exist.
+ // The default implementation of this is a no-op. This hack exists to fix
+ // a crash on the branch.
+ // TODO(ccameron): Clean this up.
+ // http://crbug.com/404828
+ virtual void RenderWidgetHostGone() {}
+
// Tells the View to destroy itself.
virtual void Destroy() = 0;
@@ -243,30 +254,27 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
virtual void SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params) = 0;
- // Notifies the view that the scroll offset has changed.
- virtual void ScrollOffsetChanged() = 0;
-
- // Copies the contents of the compositing surface into the given
- // (uninitialized) PlatformCanvas if any.
- // The rectangle region specified with |src_subrect| is copied from the
- // contents, scaled to |dst_size|, and written to |output|.
- // |callback| is invoked with true on success, false otherwise. |output| can
- // be initialized even on failure.
- // A smaller region than |src_subrect| may be copied if the underlying surface
- // is smaller than |src_subrect|.
- // NOTE: |callback| is called asynchronously.
+ // Copies the contents of the compositing surface, providing a new SkBitmap
+ // result via an asynchronously-run |callback|. |src_subrect| is specified in
+ // layer space coordinates for the current platform (e.g., DIP for Aura/Mac,
+ // physical for Android), and is the region to be copied from this view. The
+ // copy is then scaled to a SkBitmap of size |dst_size|. |callback| is run
+ // with true on success, false otherwise. A smaller region than |src_subrect|
+ // may be copied if the underlying surface is smaller than |src_subrect|.
virtual void CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
- const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) = 0;
-
- // Copies a given subset of the compositing surface's content into a YV12
- // VideoFrame, and invokes a callback with a success/fail parameter. |target|
- // must contain an allocated, YV12 video frame of the intended size. If the
- // copy rectangle does not match |target|'s size, the copied content will be
- // scaled and letterboxed with black borders. The copy will happen
- // asynchronously. This operation will fail if there is no available
+ CopyFromCompositingSurfaceCallback& callback,
+ const SkColorType color_type) = 0;
+
+ // Copies the contents of the compositing surface, populating the given
+ // |target| with YV12 image data. |src_subrect| is specified in layer space
+ // coordinates for the current platform (e.g., DIP for Aura/Mac, physical for
+ // Android), and is the region to be copied from this view. The copy is then
+ // scaled and letterboxed with black borders to fit |target|. Finally,
+ // |callback| is asynchronously run with true/false for
+ // success/failure. |target| must point to an allocated, YV12 video frame of
+ // the intended size. This operation will fail if there is no available
// compositing surface.
virtual void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
@@ -281,33 +289,22 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// IsSurfaceAvailableForCopy() and HasAcceleratedSurface().
virtual bool CanCopyToVideoFrame() const = 0;
- // Called when an accelerated compositing surface is initialized.
- virtual void AcceleratedSurfaceInitialized(int host_id, int route_id) = 0;
- // |params.window| and |params.surface_id| indicate which accelerated
- // surface's buffers swapped. |params.renderer_id| and |params.route_id|
- // are used to formulate a reply to the GPU process to prevent it from getting
- // too far ahead. They may all be zero, in which case no flow control is
- // enforced; this case is currently used for accelerated plugins.
- virtual void AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel,
- int gpu_host_id) = 0;
- // Similar to above, except |params.(x|y|width|height)| define the region
- // of the surface that changed.
- virtual void AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel,
- int gpu_host_id) = 0;
-
- // Release the accelerated surface temporarily. It will be recreated on the
- // next swap buffers or post sub buffer.
- virtual void AcceleratedSurfaceSuspend() = 0;
-
- virtual void AcceleratedSurfaceRelease() = 0;
+ // DEPRECATED. Called when an accelerated compositing surface is initialized.
+ virtual void AcceleratedSurfaceInitialized(int route_id) {}
// Return true if the view has an accelerated surface that contains the last
// presented frame for the view. If |desired_size| is non-empty, true is
// returned only if the accelerated surface size matches.
virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) = 0;
+ // Compute the orientation type of the display assuming it is a mobile device.
+ static blink::WebScreenOrientationType GetOrientationTypeForMobile(
+ const gfx::Display& display);
+
+ // Compute the orientation type of the display assuming it is a desktop.
+ static blink::WebScreenOrientationType GetOrientationTypeForDesktop(
+ const gfx::Display& display);
+
virtual void GetScreenInfo(blink::WebScreenInfo* results) = 0;
// Gets the bounds of the window, in screen coordinates.
@@ -315,14 +312,18 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
virtual gfx::GLSurfaceHandle GetCompositingSurface() = 0;
+ // Called by the RenderFrameHost when it receives an IPC response to a
+ // TextSurroundingSelectionRequest.
virtual void OnTextSurroundingSelectionResponse(const base::string16& content,
size_t start_offset,
- size_t end_offset) {};
+ size_t end_offset);
-#if defined(OS_ANDROID)
- virtual void ShowDisambiguationPopup(const gfx::Rect& target_rect,
- const SkBitmap& zoomed_bitmap) = 0;
+ // Called by the RenderWidgetHost when an ambiguous gesture is detected to
+ // show the disambiguation popup bubble.
+ virtual void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
+ const SkBitmap& zoomed_bitmap);
+#if defined(OS_ANDROID)
// Instructs the view to not drop the surface even when the view is hidden.
virtual void LockCompositingSurface() = 0;
virtual void UnlockCompositingSurface() = 0;
@@ -337,7 +338,7 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
const NativeWebKeyboardEvent& event) = 0;
#endif
-#if defined(OS_MACOSX) || defined(USE_AURA)
+#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_ANDROID)
// Updates the range of the marked text in an IME composition.
virtual void ImeCompositionRangeChanged(
const gfx::Range& range,
@@ -380,8 +381,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
// autofill...).
blink::WebPopupType popup_type_;
- // When false, the background of the web content is not fully opaque.
- bool background_opaque_;
+ // The background color of the web content.
+ SkColor background_color_;
// While the mouse is locked, the cursor is hidden from the user. Mouse events
// are still generated. However, the position they report is the last known
@@ -417,15 +418,14 @@ protected:
private:
void FlushInput();
- // Manager of the tree representation of the WebKit render tree.
- scoped_ptr<BrowserAccessibilityManager> browser_accessibility_manager_;
-
gfx::Rect current_display_area_;
uint32 renderer_frame_number_;
base::OneShotTimer<RenderWidgetHostViewBase> flush_input_timer_;
+ base::WeakPtrFactory<RenderWidgetHostViewBase> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewBase);
};
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base_unittest.cc b/chromium/content/browser/renderer_host/render_widget_host_view_base_unittest.cc
new file mode 100644
index 00000000000..6cc861d8927
--- /dev/null
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_base_unittest.cc
@@ -0,0 +1,124 @@
+// 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/renderer_host/render_widget_host_view_base.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "ui/gfx/display.h"
+
+namespace content {
+
+namespace {
+
+gfx::Display CreateDisplay(int width, int height, int angle) {
+ gfx::Display display;
+ display.SetRotationAsDegree(angle);
+ display.set_bounds(gfx::Rect(width, height));
+
+ return display;
+}
+
+} // anonymous namespace
+
+TEST(RenderWidgetHostViewBaseTest, OrientationTypeForMobile) {
+ // Square display (width == height).
+ {
+ gfx::Display display = CreateDisplay(100, 100, 0);
+ EXPECT_EQ(blink::WebScreenOrientationPortraitPrimary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(200, 200, 90);
+ EXPECT_EQ(blink::WebScreenOrientationLandscapePrimary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(0, 0, 180);
+ EXPECT_EQ(blink::WebScreenOrientationPortraitSecondary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(10000, 10000, 270);
+ EXPECT_EQ(blink::WebScreenOrientationLandscapeSecondary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+ }
+
+ // natural width > natural height.
+ {
+ gfx::Display display = CreateDisplay(1, 0, 0);
+ EXPECT_EQ(blink::WebScreenOrientationLandscapePrimary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(19999, 20000, 90);
+ EXPECT_EQ(blink::WebScreenOrientationPortraitSecondary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(200, 100, 180);
+ EXPECT_EQ(blink::WebScreenOrientationLandscapeSecondary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(1, 10000, 270);
+ EXPECT_EQ(blink::WebScreenOrientationPortraitPrimary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+ }
+
+ // natural width < natural height.
+ {
+ gfx::Display display = CreateDisplay(0, 1, 0);
+ EXPECT_EQ(blink::WebScreenOrientationPortraitPrimary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(20000, 19999, 90);
+ EXPECT_EQ(blink::WebScreenOrientationLandscapePrimary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(100, 200, 180);
+ EXPECT_EQ(blink::WebScreenOrientationPortraitSecondary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+
+ display = CreateDisplay(10000, 1, 270);
+ EXPECT_EQ(blink::WebScreenOrientationLandscapeSecondary,
+ RenderWidgetHostViewBase::GetOrientationTypeForMobile(display));
+ }
+}
+
+TEST(RenderWidgetHostViewBaseTest, OrientationTypeForDesktop) {
+ // On Desktop, the primary orientation is the first computed one so a test
+ // similar to OrientationTypeForMobile is not possible.
+ // Instead this test will only check one configuration and verify that the
+ // method reports two landscape and two portrait orientations with one primary
+ // and one secondary for each.
+
+ // natural width > natural height.
+ {
+ gfx::Display display = CreateDisplay(1, 0, 0);
+ blink::WebScreenOrientationType landscape_1 =
+ RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
+ EXPECT_TRUE(landscape_1 == blink::WebScreenOrientationLandscapePrimary ||
+ landscape_1 == blink::WebScreenOrientationLandscapeSecondary);
+
+ display = CreateDisplay(200, 100, 180);
+ blink::WebScreenOrientationType landscape_2 =
+ RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
+ EXPECT_TRUE(landscape_2 == blink::WebScreenOrientationLandscapePrimary ||
+ landscape_2 == blink::WebScreenOrientationLandscapeSecondary);
+
+ EXPECT_NE(landscape_1, landscape_2);
+
+ display = CreateDisplay(19999, 20000, 90);
+ blink::WebScreenOrientationType portrait_1 =
+ RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
+ EXPECT_TRUE(portrait_1 == blink::WebScreenOrientationPortraitPrimary ||
+ portrait_1 == blink::WebScreenOrientationPortraitSecondary);
+
+ display = CreateDisplay(1, 10000, 270);
+ blink::WebScreenOrientationType portrait_2 =
+ RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
+ EXPECT_TRUE(portrait_2 == blink::WebScreenOrientationPortraitPrimary ||
+ portrait_2 == blink::WebScreenOrientationPortraitSecondary);
+
+ EXPECT_NE(portrait_1, portrait_2);
+
+ }
+}
+
+} // namespace content
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 34327a164fb..a04a117f292 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
@@ -29,7 +29,7 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/base/layout.h"
#include "ui/base/ui_base_switches.h"
-#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/switches.h"
#include "ui/gl/gl_switches.h"
@@ -61,7 +61,7 @@ class RenderWidgetHostViewBrowserTest : public ContentBrowserTest {
callback_invoke_count_(0),
frames_captured_(0) {}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &test_dir_));
}
@@ -157,7 +157,7 @@ class RenderWidgetHostViewBrowserTest : public ContentBrowserTest {
&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
base::Unretained(this),
run_loop.QuitClosure()),
- SkBitmap::kARGB_8888_Config);
+ kN32_SkColorType);
run_loop.Run();
if (frames_captured())
@@ -207,7 +207,7 @@ class CompositingRenderWidgetHostViewBrowserTest
explicit CompositingRenderWidgetHostViewBrowserTest()
: compositing_mode_(GetParam()) {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
if (compositing_mode_ == SOFTWARE_COMPOSITING)
UseSoftwareCompositing();
RenderWidgetHostViewBrowserTest::SetUp();
@@ -218,7 +218,7 @@ class CompositingRenderWidgetHostViewBrowserTest
test_dir().AppendASCII("rwhv_compositing_animation.html"));
}
- virtual bool SetUpSourceSurface(const char* wait_message) OVERRIDE {
+ bool SetUpSourceSurface(const char* wait_message) override {
content::DOMMessageQueue message_queue;
NavigateToURL(shell(), TestUrl());
if (wait_message != NULL) {
@@ -247,9 +247,10 @@ class FakeFrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
: callback_(callback) {
}
- virtual bool ShouldCaptureFrame(base::TimeTicks present_time,
- scoped_refptr<media::VideoFrame>* storage,
- DeliverFrameCallback* callback) OVERRIDE {
+ bool ShouldCaptureFrame(const gfx::Rect& damage_rect,
+ base::TimeTicks present_time,
+ scoped_refptr<media::VideoFrame>* storage,
+ DeliverFrameCallback* callback) override {
// Only allow one frame capture to be made. Otherwise, the compositor could
// start multiple captures, unbounded, and eventually its own limiter logic
// will begin invoking |callback| with a |false| result. This flakes out
@@ -291,9 +292,7 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
base::Bind(&RenderWidgetHostViewBrowserTest::FinishCopyFromBackingStore,
base::Unretained(this),
run_loop.QuitClosure()),
- SkBitmap::kARGB_8888_Config);
- // Delete the surface before the callback is run.
- GetRenderWidgetHostView()->AcceleratedSurfaceRelease();
+ kN32_SkColorType);
run_loop.Run();
EXPECT_EQ(1, callback_invoke_count());
@@ -329,8 +328,6 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
gfx::Rect(view->GetViewBounds().size()), dest, base::Bind(
&RenderWidgetHostViewBrowserTest::FinishCopyFromCompositingSurface,
base::Unretained(this), run_loop.QuitClosure()));
- // Delete the surface before the callback is run.
- view->AcceleratedSurfaceRelease();
run_loop.Run();
EXPECT_EQ(1, callback_invoke_count());
@@ -411,7 +408,7 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
allowable_error_(0),
test_url_("data:text/html,<!doctype html>") {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
EnablePixelOutput();
CompositingRenderWidgetHostViewBrowserTest::SetUp();
}
@@ -429,7 +426,7 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
expected_copy_from_compositing_surface_bitmap_;
EXPECT_EQ(expected_bitmap.width(), bitmap.width());
EXPECT_EQ(expected_bitmap.height(), bitmap.height());
- EXPECT_EQ(expected_bitmap.config(), bitmap.config());
+ EXPECT_EQ(expected_bitmap.colorType(), bitmap.colorType());
SkAutoLockPixels expected_bitmap_lock(expected_bitmap);
SkAutoLockPixels bitmap_lock(bitmap);
int fails = 0;
@@ -488,17 +485,11 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
media::SkCanvasVideoRenderer video_renderer;
SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::Make(video_frame->visible_rect().width(),
- video_frame->visible_rect().height(),
- kPMColor_SkColorType,
- kPremul_SkAlphaType));
- bitmap.eraseColor(SK_ColorTRANSPARENT);
+ bitmap.allocN32Pixels(video_frame->visible_rect().width(),
+ video_frame->visible_rect().height());
+ // Don't clear the canvas because drawing a video frame by Src mode.
SkCanvas canvas(bitmap);
-
- video_renderer.Paint(video_frame.get(),
- &canvas,
- video_frame->visible_rect(),
- 0xff);
+ video_renderer.Copy(video_frame, &canvas);
CopyFromCompositingSurfaceCallback(quit_callback,
result,
@@ -514,24 +505,19 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
void SetAllowableError(int amount) { allowable_error_ = amount; }
void SetExcludeRect(gfx::Rect exclude) { exclude_rect_ = exclude; }
- virtual GURL TestUrl() OVERRIDE {
- return GURL(test_url_);
- }
+ GURL TestUrl() override { return GURL(test_url_); }
void SetTestUrl(std::string url) { test_url_ = url; }
// Loads a page two boxes side-by-side, each half the width of
// |html_rect_size|, and with different background colors. The test then
// copies from |copy_rect| region of the page into a bitmap of size
- // |output_size|, and compares that with a bitmap of size
- // |expected_bitmap_size|.
+ // |output_size|, and examines the resulting bitmap/VideoFrame.
// Note that |output_size| may not have the same size as |copy_rect| (e.g.
- // when the output is scaled). Also note that |expected_bitmap_size| may not
- // be the same as |output_size| (e.g. when the device scale factor is not 1).
+ // when the output is scaled).
void PerformTestWithLeftRightRects(const gfx::Size& html_rect_size,
const gfx::Rect& copy_rect,
const gfx::Size& output_size,
- const gfx::Size& expected_bitmap_size,
bool video_frame) {
const gfx::Size box_size(html_rect_size.width() / 2,
html_rect_size.height());
@@ -592,7 +578,7 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
GiveItSomeTime();
SkBitmap expected_bitmap;
- SetupLeftRightBitmap(expected_bitmap_size, &expected_bitmap);
+ SetupLeftRightBitmap(output_size, &expected_bitmap);
SetExpectedCopyFromCompositingSurfaceResult(true, expected_bitmap);
base::RunLoop run_loop;
@@ -605,9 +591,9 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
scoped_refptr<media::VideoFrame> video_frame =
media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
- expected_bitmap_size,
- gfx::Rect(expected_bitmap_size),
- expected_bitmap_size,
+ output_size,
+ gfx::Rect(output_size),
+ output_size,
base::TimeDelta());
base::Callback<void(bool success)> callback =
@@ -620,16 +606,16 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
video_frame,
callback);
} else {
-#if defined(USE_AURA)
- if (!content::GpuDataManager::GetInstance()
- ->CanUseGpuBrowserCompositor()) {
- // Skia rendering can cause color differences, particularly in the
- // middle two columns.
- SetAllowableError(2);
- SetExcludeRect(
- gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
+ if (IsDelegatedRendererEnabled()) {
+ if (!content::GpuDataManager::GetInstance()
+ ->CanUseGpuBrowserCompositor()) {
+ // Skia rendering can cause color differences, particularly in the
+ // middle two columns.
+ SetAllowableError(2);
+ SetExcludeRect(gfx::Rect(
+ output_size.width() / 2 - 1, 0, 2, output_size.height()));
+ }
}
-#endif
base::Callback<void(bool, const SkBitmap&)> callback =
base::Bind(&CompositingRenderWidgetHostViewBrowserTestTabCapture::
@@ -639,7 +625,7 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
rwhvp->CopyFromCompositingSurface(copy_rect,
output_size,
callback,
- SkBitmap::kARGB_8888_Config);
+ kN32_SkColorType);
}
run_loop.Run();
}
@@ -647,9 +633,7 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
// Sets up |bitmap| to have size |copy_size|. It floods the left half with
// #0ff and the right half with #ff0.
void SetupLeftRightBitmap(const gfx::Size& copy_size, SkBitmap* bitmap) {
- bitmap->setConfig(
- SkBitmap::kARGB_8888_Config, copy_size.width(), copy_size.height());
- bitmap->allocPixels();
+ bitmap->allocN32Pixels(copy_size.width(), copy_size.height());
// Left half is #0ff.
bitmap->eraseARGB(255, 0, 255, 255);
// Right half is #ff0.
@@ -681,13 +665,11 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
CopyFromCompositingSurface_Origin_Unscaled) {
gfx::Rect copy_rect(400, 300);
gfx::Size output_size = copy_rect.size();
- gfx::Size expected_bitmap_size = output_size;
gfx::Size html_rect_size(400, 300);
bool video_frame = false;
PerformTestWithLeftRightRects(html_rect_size,
copy_rect,
output_size,
- expected_bitmap_size,
video_frame);
}
@@ -695,13 +677,11 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
CopyFromCompositingSurface_Origin_Scaled) {
gfx::Rect copy_rect(400, 300);
gfx::Size output_size(200, 100);
- gfx::Size expected_bitmap_size = output_size;
gfx::Size html_rect_size(400, 300);
bool video_frame = false;
PerformTestWithLeftRightRects(html_rect_size,
copy_rect,
output_size,
- expected_bitmap_size,
video_frame);
}
@@ -712,13 +692,11 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
gfx::Size(60, 60));
gfx::Size output_size = copy_rect.size();
- gfx::Size expected_bitmap_size = output_size;
gfx::Size html_rect_size(400, 300);
bool video_frame = false;
PerformTestWithLeftRightRects(html_rect_size,
copy_rect,
output_size,
- expected_bitmap_size,
video_frame);
}
@@ -729,13 +707,11 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(30, 30),
gfx::Size(60, 60));
gfx::Size output_size(20, 10);
- gfx::Size expected_bitmap_size = output_size;
gfx::Size html_rect_size(400, 300);
bool video_frame = false;
PerformTestWithLeftRightRects(html_rect_size,
copy_rect,
output_size,
- expected_bitmap_size,
video_frame);
}
@@ -746,13 +722,11 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
copy_rect = gfx::Rect(copy_rect.CenterPoint() - gfx::Vector2d(45, 30),
gfx::Size(90, 60));
gfx::Size output_size = copy_rect.size();
- gfx::Size expected_bitmap_size = output_size;
gfx::Size html_rect_size(400, 300);
bool video_frame = true;
PerformTestWithLeftRightRects(html_rect_size,
copy_rect,
output_size,
- expected_bitmap_size,
video_frame);
}
@@ -764,101 +738,176 @@ IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
gfx::Size(90, 60));
// Scale to 30 x 20 (preserve aspect ratio).
gfx::Size output_size(30, 20);
- gfx::Size expected_bitmap_size = output_size;
gfx::Size html_rect_size(400, 300);
bool video_frame = true;
PerformTestWithLeftRightRects(html_rect_size,
copy_rect,
output_size,
- expected_bitmap_size,
video_frame);
}
-class CompositingRenderWidgetHostViewTabCaptureHighDPI
+class CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
: public CompositingRenderWidgetHostViewBrowserTestTabCapture {
public:
- CompositingRenderWidgetHostViewTabCaptureHighDPI() : kScale(2.f) {}
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI() {}
- virtual void SetUpOnMainThread() OVERRIDE {
- CommandLine* cmd = CommandLine::ForCurrentProcess();
+ protected:
+ void SetUpCommandLine(base::CommandLine* cmd) override {
+ CompositingRenderWidgetHostViewBrowserTestTabCapture::SetUpCommandLine(cmd);
cmd->AppendSwitchASCII(switches::kForceDeviceScaleFactor,
base::StringPrintf("%f", scale()));
-#if defined(OS_WIN)
- gfx::ForceHighDPISupportForTesting(scale());
- gfx::EnableHighDPISupport();
-#endif
}
- float scale() const { return kScale; }
-
- private:
- virtual bool ShouldContinueAfterTestURLLoad() OVERRIDE {
+ bool ShouldContinueAfterTestURLLoad() override {
// Short-circuit a pass for platforms where setting up high-DPI fails.
- if (ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactor(
- GetScaleFactorForView(GetRenderWidgetHostView()))) != scale()) {
- LOG(WARNING) << "Blindly passing this test: failed to set up "
- "scale factor: " << scale();
+ const float actual_scale_factor =
+ GetScaleFactorForView(GetRenderWidgetHostView());
+ if (actual_scale_factor != scale()) {
+ LOG(WARNING) << "Blindly passing this test; unable to force device scale "
+ << "factor: seems to be " << actual_scale_factor
+ << " but expected " << scale();
return false;
}
+ VLOG(1) << ("Successfully forced device scale factor. Moving forward with "
+ "this test! :-)");
return true;
}
- const float kScale;
+ static float scale() { return 2.0f; }
- DISALLOW_COPY_AND_ASSIGN(CompositingRenderWidgetHostViewTabCaptureHighDPI);
+ private:
+ DISALLOW_COPY_AND_ASSIGN(
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI);
};
-IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewTabCaptureHighDPI,
- CopyFromCompositingSurface) {
+// ImageSkia (related to ResourceBundle) implementation crashes the process on
+// Windows when this content_browsertest forces a device scale factor.
+// http://crbug.com/399349
+//
+// These tests are flaky on ChromeOS builders. See http://crbug.com/406018.
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#define MAYBE_CopyToBitmap_EntireRegion DISABLED_CopyToBitmap_EntireRegion
+#define MAYBE_CopyToBitmap_CenterRegion DISABLED_CopyToBitmap_CenterRegion
+#define MAYBE_CopyToBitmap_ScaledResult DISABLED_CopyToBitmap_ScaledResult
+#define MAYBE_CopyToVideoFrame_EntireRegion \
+ DISABLED_CopyToVideoFrame_EntireRegion
+#define MAYBE_CopyToVideoFrame_CenterRegion \
+ DISABLED_CopyToVideoFrame_CenterRegion
+#define MAYBE_CopyToVideoFrame_ScaledResult \
+ DISABLED_CopyToVideoFrame_ScaledResult
+#else
+#define MAYBE_CopyToBitmap_EntireRegion CopyToBitmap_EntireRegion
+#define MAYBE_CopyToBitmap_CenterRegion CopyToBitmap_CenterRegion
+#define MAYBE_CopyToBitmap_ScaledResult CopyToBitmap_ScaledResult
+#define MAYBE_CopyToVideoFrame_EntireRegion CopyToVideoFrame_EntireRegion
+#define MAYBE_CopyToVideoFrame_CenterRegion CopyToVideoFrame_CenterRegion
+#define MAYBE_CopyToVideoFrame_ScaledResult CopyToVideoFrame_ScaledResult
+#endif
+
+IN_PROC_BROWSER_TEST_P(
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
+ MAYBE_CopyToBitmap_EntireRegion) {
+ gfx::Size html_rect_size(200, 150);
gfx::Rect copy_rect(200, 150);
- gfx::Size output_size = copy_rect.size();
- gfx::Size expected_bitmap_size =
- gfx::ToFlooredSize(gfx::ScaleSize(output_size, scale(), scale()));
+ // Scale the output size so that, internally, scaling is not occurring.
+ gfx::Size output_size =
+ gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
+ bool video_frame = false;
+ PerformTestWithLeftRightRects(html_rect_size,
+ copy_rect,
+ output_size,
+ video_frame);
+}
+
+IN_PROC_BROWSER_TEST_P(
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
+ MAYBE_CopyToBitmap_CenterRegion) {
gfx::Size html_rect_size(200, 150);
+ // Grab 90x60 pixels from the center of the tab contents.
+ gfx::Rect copy_rect =
+ gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
+ gfx::Size(90, 60));
+ // Scale the output size so that, internally, scaling is not occurring.
+ gfx::Size output_size =
+ gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
bool video_frame = false;
PerformTestWithLeftRightRects(html_rect_size,
copy_rect,
output_size,
- expected_bitmap_size,
video_frame);
}
-IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewTabCaptureHighDPI,
- CopyFromCompositingSurfaceVideoFrame) {
+IN_PROC_BROWSER_TEST_P(
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
+ MAYBE_CopyToBitmap_ScaledResult) {
+ gfx::Size html_rect_size(200, 100);
+ gfx::Rect copy_rect(200, 100);
+ // Output is being down-scaled since output_size is in phyiscal pixels.
+ gfx::Size output_size(200, 100);
+ bool video_frame = false;
+ PerformTestWithLeftRightRects(html_rect_size,
+ copy_rect,
+ output_size,
+ video_frame);
+}
+
+IN_PROC_BROWSER_TEST_P(
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
+ MAYBE_CopyToVideoFrame_EntireRegion) {
+ gfx::Size html_rect_size(200, 150);
+ gfx::Rect copy_rect(200, 150);
+ // Scale the output size so that, internally, scaling is not occurring.
+ gfx::Size output_size =
+ gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
+ bool video_frame = true;
+ PerformTestWithLeftRightRects(html_rect_size,
+ copy_rect,
+ output_size,
+ video_frame);
+}
+
+IN_PROC_BROWSER_TEST_P(
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
+ MAYBE_CopyToVideoFrame_CenterRegion) {
gfx::Size html_rect_size(200, 150);
// Grab 90x60 pixels from the center of the tab contents.
gfx::Rect copy_rect =
gfx::Rect(gfx::Rect(html_rect_size).CenterPoint() - gfx::Vector2d(45, 30),
gfx::Size(90, 60));
- gfx::Size output_size = copy_rect.size();
- gfx::Size expected_bitmap_size =
- gfx::ToFlooredSize(gfx::ScaleSize(output_size, scale(), scale()));
+ // Scale the output size so that, internally, scaling is not occurring.
+ gfx::Size output_size =
+ gfx::ToRoundedSize(gfx::ScaleSize(copy_rect.size(), scale()));
bool video_frame = true;
PerformTestWithLeftRightRects(html_rect_size,
copy_rect,
output_size,
- expected_bitmap_size,
video_frame);
}
-#if !defined(USE_AURA) && !defined(OS_MACOSX)
-// TODO(danakj): Remove this case when GTK linux is no more and move the
-// values inline to testing::Values() below.
-static const CompositingMode kAllCompositingModes[] = {GL_COMPOSITING};
-#else
-static const CompositingMode kAllCompositingModes[] = {GL_COMPOSITING,
- SOFTWARE_COMPOSITING};
-#endif
+IN_PROC_BROWSER_TEST_P(
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
+ MAYBE_CopyToVideoFrame_ScaledResult) {
+ gfx::Size html_rect_size(200, 100);
+ gfx::Rect copy_rect(200, 100);
+ // Output is being down-scaled since output_size is in phyiscal pixels.
+ gfx::Size output_size(200, 100);
+ bool video_frame = true;
+ PerformTestWithLeftRightRects(html_rect_size,
+ copy_rect,
+ output_size,
+ video_frame);
+}
INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
CompositingRenderWidgetHostViewBrowserTest,
- testing::ValuesIn(kAllCompositingModes));
+ testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
CompositingRenderWidgetHostViewBrowserTestTabCapture,
- testing::ValuesIn(kAllCompositingModes));
-INSTANTIATE_TEST_CASE_P(GLAndSoftwareCompositing,
- CompositingRenderWidgetHostViewTabCaptureHighDPI,
- testing::ValuesIn(kAllCompositingModes));
+ testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
+INSTANTIATE_TEST_CASE_P(
+ GLAndSoftwareCompositing,
+ CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
+ testing::Values(GL_COMPOSITING, SOFTWARE_COMPOSITING));
#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
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 8fb2e4a5fe8..2be8d87df02 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
@@ -19,7 +19,7 @@
#include "base/time/time.h"
#include "content/browser/compositor/browser_compositor_view_mac.h"
#include "content/browser/compositor/delegated_frame_host.h"
-#include "content/browser/renderer_host/compositing_iosurface_layer_mac.h"
+#include "content/browser/compositor/io_surface_layer_mac.h"
#include "content/browser/renderer_host/display_link_mac.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/renderer_host/software_frame_manager.h"
@@ -30,12 +30,11 @@
#include "ipc/ipc_sender.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "ui/base/cocoa/base_view.h"
-
-struct ViewHostMsg_TextInputState_Params;
+#include "ui/base/cocoa/remote_layer_api.h"
+#include "ui/gfx/display_observer.h"
namespace content {
-class CompositingIOSurfaceMac;
-class CompositingIOSurfaceContext;
+class BrowserCompositorviewMac;
class RenderWidgetHostViewMac;
class RenderWidgetHostViewMacEditCommandHelper;
class WebContents;
@@ -46,11 +45,8 @@ class Compositor;
class Layer;
}
-@class BrowserCompositorViewMac;
-@class CompositingIOSurfaceLayer;
@class FullscreenWindowManager;
@protocol RenderWidgetHostViewMacDelegate;
-@class SoftwareLayer;
@class ToolTip;
@protocol RenderWidgetHostViewMacOwner
@@ -71,7 +67,6 @@ class Layer;
base::scoped_nsobject<NSObject<RenderWidgetHostViewMacDelegate>>
responderDelegate_;
BOOL canBeKeyView_;
- BOOL takesFocusOnlyOnMouseDown_;
BOOL closeOnDeactivate_;
scoped_ptr<content::RenderWidgetHostViewMacEditCommandHelper>
editCommand_helper_;
@@ -153,14 +148,6 @@ class Layer;
// Event monitor for scroll wheel end event.
id endWheelMonitor_;
- // OpenGL Support:
-
- // recursive globalFrameDidChange protection:
- BOOL handlingGlobalFrameDidChange_;
-
- // The scale factor of the display this view is in.
- float deviceScaleFactor_;
-
// If true then escape key down events are suppressed until the first escape
// key up event. (The up event is suppressed as well). This is used by the
// flash fullscreen code to avoid sending a key up event without a matching
@@ -172,7 +159,6 @@ class Layer;
@property(nonatomic, readonly) BOOL suppressNextEscapeKeyUp;
- (void)setCanBeKeyView:(BOOL)can;
-- (void)setTakesFocusOnlyOnMouseDown:(BOOL)b;
- (void)setCloseOnDeactivate:(BOOL)b;
- (void)setToolTipAtMousePoint:(NSString *)string;
// True for always-on-top special windows (e.g. Balloons and Panels).
@@ -215,15 +201,20 @@ class RenderWidgetHostImpl;
class CONTENT_EXPORT RenderWidgetHostViewMac
: public RenderWidgetHostViewBase,
public DelegatedFrameHostClient,
+ public BrowserCompositorViewMacClient,
public IPC::Sender,
- public SoftwareFrameManagerClient,
- public CompositingIOSurfaceLayerClient {
+ public gfx::DisplayObserver {
public:
// The view will associate itself with the given widget. The native view must
// be hooked up immediately to the view hierarchy, or else when it is
// deleted it will delete this out from under the caller.
- explicit RenderWidgetHostViewMac(RenderWidgetHost* widget);
- virtual ~RenderWidgetHostViewMac();
+ //
+ // When |is_guest_view_hack| is true, this view isn't really the view for
+ // the |widget|, a RenderWidgetHostViewGuest is.
+ // TODO(lazyboy): Remove |is_guest_view_hack| once BrowserPlugin has migrated
+ // to use RWHVChildFrame (http://crbug.com/330264).
+ RenderWidgetHostViewMac(RenderWidgetHost* widget, bool is_guest_view_hack);
+ ~RenderWidgetHostViewMac() override;
RenderWidgetHostViewCocoa* cocoa_view() const { return cocoa_view_; }
@@ -232,120 +223,107 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// |delegate| should be set at most once.
CONTENT_EXPORT void SetDelegate(
NSObject<RenderWidgetHostViewMacDelegate>* delegate);
- void SetAllowOverlappingViews(bool overlapping);
+ void SetAllowPauseForResizeOrRepaint(bool allow);
// RenderWidgetHostView implementation.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
- virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE;
- virtual RenderWidgetHost* GetRenderWidgetHost() const OVERRIDE;
- virtual void SetSize(const gfx::Size& size) OVERRIDE;
- virtual void SetBounds(const gfx::Rect& rect) OVERRIDE;
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeViewId GetNativeViewId() const OVERRIDE;
- virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
- virtual bool HasFocus() const OVERRIDE;
- virtual bool IsSurfaceAvailableForCopy() const OVERRIDE;
- virtual void Show() OVERRIDE;
- virtual void Hide() OVERRIDE;
- virtual bool IsShowing() OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
- virtual void SetShowingContextMenu(bool showing) OVERRIDE;
- virtual void SetActive(bool active) OVERRIDE;
- virtual void SetTakesFocusOnlyOnMouseDown(bool flag) OVERRIDE;
- virtual void SetWindowVisibility(bool visible) OVERRIDE;
- virtual void WindowFrameChanged() OVERRIDE;
- virtual void ShowDefinitionForSelection() OVERRIDE;
- virtual bool SupportsSpeech() const OVERRIDE;
- virtual void SpeakSelection() OVERRIDE;
- virtual bool IsSpeaking() const OVERRIDE;
- virtual void StopSpeaking() OVERRIDE;
- virtual void SetBackgroundOpaque(bool opaque) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
+ void InitAsChild(gfx::NativeView parent_view) override;
+ RenderWidgetHost* GetRenderWidgetHost() const override;
+ void SetSize(const gfx::Size& size) override;
+ void SetBounds(const gfx::Rect& rect) override;
+ gfx::Vector2dF GetLastScrollOffset() const override;
+ gfx::NativeView GetNativeView() const override;
+ gfx::NativeViewId GetNativeViewId() const override;
+ gfx::NativeViewAccessible GetNativeViewAccessible() override;
+ bool HasFocus() const override;
+ bool IsSurfaceAvailableForCopy() const override;
+ void Show() override;
+ void Hide() override;
+ bool IsShowing() override;
+ 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;
+ bool IsSpeaking() const override;
+ void StopSpeaking() override;
+ void SetBackgroundColor(SkColor color) override;
// Implementation of RenderWidgetHostViewBase.
- virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
- const gfx::Rect& pos) OVERRIDE;
- virtual void InitAsFullscreen(
- RenderWidgetHostView* reference_host_view) OVERRIDE;
- virtual void WasShown() OVERRIDE;
- virtual void WasHidden() OVERRIDE;
- virtual void MovePluginWindows(
- const std::vector<WebPluginGeometry>& moves) OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void Blur() OVERRIDE;
- virtual void UpdateCursor(const WebCursor& cursor) OVERRIDE;
- virtual void SetIsLoading(bool is_loading) OVERRIDE;
- virtual void TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) OVERRIDE;
- virtual void ImeCancelComposition() OVERRIDE;
- virtual void ImeCompositionRangeChanged(
+ void InitAsPopup(RenderWidgetHostView* parent_host_view,
+ const gfx::Rect& pos) override;
+ void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
+ void WasShown() override;
+ void WasHidden() override;
+ void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
+ void Focus() override;
+ void Blur() override;
+ void UpdateCursor(const WebCursor& cursor) override;
+ void SetIsLoading(bool is_loading) override;
+ void TextInputTypeChanged(ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) override;
+ void ImeCancelComposition() override;
+ void ImeCompositionRangeChanged(
const gfx::Range& range,
- const std::vector<gfx::Rect>& character_bounds) OVERRIDE;
- virtual void RenderProcessGone(base::TerminationStatus status,
- int error_code) OVERRIDE;
- virtual void Destroy() OVERRIDE;
- virtual void SetTooltipText(const base::string16& tooltip_text) OVERRIDE;
- virtual void SelectionChanged(const base::string16& text,
- size_t offset,
- const gfx::Range& range) OVERRIDE;
- virtual void SelectionBoundsChanged(
- const ViewHostMsg_SelectionBounds_Params& params) OVERRIDE;
- virtual void ScrollOffsetChanged() OVERRIDE;
- virtual void CopyFromCompositingSurface(
+ const std::vector<gfx::Rect>& character_bounds) override;
+ void RenderProcessGone(base::TerminationStatus status,
+ int error_code) override;
+ void RenderWidgetHostGone() override;
+ void Destroy() override;
+ void SetTooltipText(const base::string16& tooltip_text) override;
+ void SelectionChanged(const base::string16& text,
+ size_t offset,
+ const gfx::Range& range) override;
+ void SelectionBoundsChanged(
+ const ViewHostMsg_SelectionBounds_Params& params) override;
+ void CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- SkBitmap::Config config) OVERRIDE;
- virtual void CopyFromCompositingSurfaceToVideoFrame(
+ SkColorType color_type) override;
+ void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) OVERRIDE;
- virtual bool CanCopyToVideoFrame() const OVERRIDE;
- virtual bool CanSubscribeFrame() const OVERRIDE;
- virtual void BeginFrameSubscription(
- scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) OVERRIDE;
- virtual void EndFrameSubscription() OVERRIDE;
- virtual void OnSwapCompositorFrame(
- uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
- virtual void AcceleratedSurfaceInitialized(int host_id,
- int route_id) OVERRIDE;
- virtual void CreateBrowserAccessibilityManagerIfNeeded() OVERRIDE;
- virtual gfx::Point AccessibilityOriginInScreen(const gfx::Rect& bounds)
- OVERRIDE;
- virtual void OnAccessibilitySetFocus(int acc_obj_id) OVERRIDE;
- virtual void AccessibilityShowMenu(int acc_obj_id) OVERRIDE;
- virtual bool PostProcessEventForPluginIme(
- const NativeWebKeyboardEvent& event) OVERRIDE;
-
- virtual void AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
- int gpu_host_id) OVERRIDE;
- virtual void AcceleratedSurfaceSuspend() OVERRIDE;
- virtual void AcceleratedSurfaceRelease() OVERRIDE;
- virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE;
- virtual void GetScreenInfo(blink::WebScreenInfo* results) OVERRIDE;
- virtual gfx::Rect GetBoundsInRootWindow() OVERRIDE;
- virtual gfx::GLSurfaceHandle GetCompositingSurface() OVERRIDE;
-
- virtual bool LockMouse() OVERRIDE;
- virtual void UnlockMouse() OVERRIDE;
- virtual void WheelEventAck(const blink::WebMouseWheelEvent& event,
- InputEventAckState ack_result) OVERRIDE;
+ const base::Callback<void(bool)>& callback) override;
+ bool CanCopyToVideoFrame() const override;
+ bool CanSubscribeFrame() const override;
+ void BeginFrameSubscription(
+ scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) override;
+ void EndFrameSubscription() override;
+ void OnSwapCompositorFrame(uint32 output_surface_id,
+ scoped_ptr<cc::CompositorFrame> frame) override;
+ BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) override;
+ gfx::Point AccessibilityOriginInScreen(const gfx::Rect& bounds) override;
+ void AccessibilityShowMenu(const gfx::Point& point) override;
+ bool PostProcessEventForPluginIme(
+ const NativeWebKeyboardEvent& event) override;
+
+ bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
+ void GetScreenInfo(blink::WebScreenInfo* results) override;
+ gfx::Rect GetBoundsInRootWindow() override;
+ gfx::GLSurfaceHandle GetCompositingSurface() override;
+
+ bool LockMouse() override;
+ void UnlockMouse() override;
+ void WheelEventAck(const blink::WebMouseWheelEvent& event,
+ InputEventAckState ack_result) override;
// IPC::Sender implementation.
- virtual bool Send(IPC::Message* message) OVERRIDE;
-
- // SoftwareFrameManagerClient implementation:
- virtual void SoftwareFrameWasFreed(
- uint32 output_surface_id, unsigned frame_id) OVERRIDE;
- virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE;
+ bool Send(IPC::Message* message) override;
- virtual SkBitmap::Config PreferredReadbackFormat() OVERRIDE;
+ SkColorType PreferredReadbackFormat() override;
- // CompositingIOSurfaceLayerClient implementation.
- virtual void AcceleratedLayerDidDrawFrame(bool succeeded) OVERRIDE;
+ // gfx::DisplayObserver implementation.
+ void OnDisplayAdded(const gfx::Display& new_display) override;
+ void OnDisplayRemoved(const gfx::Display& old_display) override;
+ void OnDisplayMetricsChanged(const gfx::Display& display,
+ uint32_t metrics) override;
// Forwards the mouse event to the renderer.
void ForwardMouseEvent(const blink::WebMouseEvent& event);
@@ -359,26 +337,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
const std::string& selected_text() const { return selected_text_; }
- // Update the IOSurface to be drawn and call setNeedsDisplay on
- // |cocoa_view_|.
- void CompositorSwapBuffers(IOSurfaceID surface_handle,
- const gfx::Size& size,
- float scale_factor,
- const std::vector<ui::LatencyInfo>& latency_info);
-
- // Called when a GPU error is detected. Posts a task to destroy all
- // compositing state.
- void GotAcceleratedCompositingError();
-
- // Sets the overlay view, which should be drawn in the same IOSurface
- // atop of this view, if both views are drawing accelerated content.
- // Overlay is stored as a weak ptr.
- void SetOverlayView(RenderWidgetHostViewMac* overlay,
- const gfx::Point& offset);
-
- // Removes the previously set overlay view.
- void RemoveOverlayView();
-
// Returns true and stores first rectangle for character range if the
// requested |range| is already cached, otherwise returns false.
// Exposed for testing.
@@ -417,30 +375,52 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
bool can_compose_inline_;
// The background CoreAnimation layer which is hosted by |cocoa_view_|.
- // The compositing or software layers will be added as sublayers to this.
base::scoped_nsobject<CALayer> background_layer_;
- // The CoreAnimation layer for software compositing. This should be NULL
- // when software compositing is not in use.
- base::scoped_nsobject<SoftwareLayer> software_layer_;
-
- // Accelerated compositing structures. These may be dynamically created and
- // destroyed together in Create/DestroyCompositedIOSurfaceAndLayer.
- base::scoped_nsobject<CompositingIOSurfaceLayer> compositing_iosurface_layer_;
- scoped_refptr<CompositingIOSurfaceMac> compositing_iosurface_;
- scoped_refptr<CompositingIOSurfaceContext> compositing_iosurface_context_;
+ // The state of |delegated_frame_host_| and |browser_compositor_view_| to
+ // manage being visible, hidden, or occluded.
+ enum BrowserCompositorViewState {
+ // Effects:
+ // - |browser_compositor_view_| exists and |delegated_frame_host_| is
+ // visible.
+ // Happens when:
+ // - |render_widet_host_| is in the visible state (this includes when
+ // the tab isn't visible, but tab capture is enabled).
+ BrowserCompositorActive,
+ // Effects:
+ // - |browser_compositor_view_| exists, but |delegated_frame_host_| has
+ // been hidden.
+ // Happens when:
+ // - The |render_widget_host_| is hidden, but |cocoa_view_| is still in the
+ // NSWindow hierarchy.
+ // - This happens when |cocoa_view_| is hidden (minimized, on another
+ // occluded by other windows, etc). The |browser_compositor_view_| and
+ // its CALayers are kept around so that we will have content to show when
+ // we are un-occluded.
+ BrowserCompositorSuspended,
+ // Effects:
+ // - |browser_compositor_view_| has been destroyed and
+ // |delegated_frame_host_| has been hidden.
+ // Happens when:
+ // - The |render_widget_host_| is hidden or dead, and |cocoa_view_| is not
+ // attached to a NSWindow.
+ // - This happens for backgrounded tabs.
+ BrowserCompositorDestroyed,
+ };
+ BrowserCompositorViewState browser_compositor_state_;
// Delegated frame management and compositior.
- base::scoped_nsobject<BrowserCompositorViewMac> browser_compositor_view_;
scoped_ptr<DelegatedFrameHost> delegated_frame_host_;
scoped_ptr<ui::Layer> root_layer_;
- // This holds the current software compositing framebuffer, if any.
- scoped_ptr<SoftwareFrameManager> software_frame_manager_;
+ // Container for the CALayer tree drawn by the browser compositor.
+ scoped_ptr<BrowserCompositorViewMac> browser_compositor_view_;
- // Latency info to send back when the next frame appears on the
- // screen.
- std::vector<ui::LatencyInfo> pending_latency_info_;
+ // Placeholder that is allocated while browser_compositor_view_ is NULL,
+ // indicating that a BrowserCompositorViewMac may be allocated. This is to
+ // help in recycling the internals of BrowserCompositorViewMac.
+ scoped_ptr<BrowserCompositorViewPlaceholderMac>
+ browser_compositor_view_placeholder_;
NSWindow* pepper_fullscreen_window() const {
return pepper_fullscreen_window_;
@@ -452,10 +432,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
return fullscreen_parent_host_view_;
}
- RenderWidgetHostViewFrameSubscriber* frame_subscriber() const {
- return frame_subscriber_.get();
- }
-
int window_number() const;
// The scale factor for the screen that the view is currently on.
@@ -467,53 +443,31 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// Ensure that the display link is associated with the correct display.
void UpdateDisplayLink();
- // The scale factor of the backing store. Note that this is updated based on
- // ViewScaleFactor with some delay.
- float backing_store_scale_factor_;
-
- void AddPendingLatencyInfo(
- const std::vector<ui::LatencyInfo>& latency_info);
- void SendPendingLatencyInfoToHost();
-
- void SendPendingSwapAck();
-
void PauseForPendingResizeOrRepaintsAndDraw();
- // The geometric arrangement of the layers depends on cocoa_view's size, the
- // compositing IOSurface's rounded size, and the software frame size. Update
- // all of them using this function when any of those parameters changes. Also
- // update the scale factor of the layers.
- void LayoutLayers();
-
// DelegatedFrameHostClient implementation.
- virtual ui::Compositor* GetCompositor() const OVERRIDE;
- virtual ui::Layer* GetLayer() OVERRIDE;
- virtual RenderWidgetHostImpl* GetHost() OVERRIDE;
- virtual void SchedulePaintInRect(
- const gfx::Rect& damage_rect_in_dip) OVERRIDE;
- virtual bool IsVisible() OVERRIDE;
- virtual scoped_ptr<ResizeLock> CreateResizeLock(
- bool defer_compositor_lock) OVERRIDE;
- virtual gfx::Size DesiredFrameSize() OVERRIDE;
- virtual float CurrentDeviceScaleFactor() OVERRIDE;
- virtual gfx::Size ConvertViewSizeToPixel(const gfx::Size& size) OVERRIDE;
- virtual DelegatedFrameHost* GetDelegatedFrameHost() const OVERRIDE;
+ ui::Compositor* GetCompositor() const override;
+ ui::Layer* GetLayer() override;
+ RenderWidgetHostImpl* GetHost() override;
+ bool IsVisible() override;
+ scoped_ptr<ResizeLock> CreateResizeLock(bool defer_compositor_lock) override;
+ gfx::Size DesiredFrameSize() override;
+ float CurrentDeviceScaleFactor() override;
+ gfx::Size ConvertViewSizeToPixel(const gfx::Size& size) override;
+ DelegatedFrameHost* GetDelegatedFrameHost() const override;
+
+ // BrowserCompositorViewMacClient implementation.
+ bool BrowserCompositorViewShouldAckImmediately() const override;
+ void BrowserCompositorViewFrameSwapped(
+ const std::vector<ui::LatencyInfo>& latency_info) override;
+
+ // Transition from being in the Suspended state to being in the Destroyed
+ // state, if appropriate (see BrowserCompositorViewState for details).
+ void DestroySuspendedBrowserCompositorViewIfNeeded();
private:
friend class RenderWidgetHostViewMacTest;
- struct PendingSwapAck {
- PendingSwapAck(int32 route_id, int gpu_host_id, int32 renderer_id)
- : route_id(route_id),
- gpu_host_id(gpu_host_id),
- renderer_id(renderer_id) {}
- int32 route_id;
- int gpu_host_id;
- int32 renderer_id;
- };
- scoped_ptr<PendingSwapAck> pending_swap_ack_;
- void AddPendingSwapAck(int32 route_id, int gpu_host_id, int32 renderer_id);
-
// Returns whether this render view is a popup (autocomplete window).
bool IsPopup() const;
@@ -521,38 +475,27 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// invoke it from the message loop.
void ShutdownHost();
- void EnsureSoftwareLayer();
- void DestroySoftwareLayer();
-
- bool EnsureCompositedIOSurface() WARN_UNUSED_RESULT;
- void EnsureCompositedIOSurfaceLayer();
- enum DestroyCompositedIOSurfaceLayerBehavior {
- kLeaveLayerInHierarchy,
- kRemoveLayerFromHierarchy,
- };
- void DestroyCompositedIOSurfaceLayer(
- DestroyCompositedIOSurfaceLayerBehavior destroy_layer_behavior);
- void DestroyCompositedIOSurfaceAndLayer();
-
- void DestroyCompositingStateOnError();
-
- // Called when a GPU SwapBuffers is received.
- void GotAcceleratedFrame();
+ // Tear down all components of the browser compositor in an order that will
+ // ensure no dangling references.
+ void ShutdownBrowserCompositor();
- // Called when a software DIB is received.
- void GotSoftwareFrame();
+ // The state of the the browser compositor and delegated frame host. See
+ // BrowserCompositorViewState for details.
+ void EnsureBrowserCompositorView();
+ void SuspendBrowserCompositorView();
+ void DestroyBrowserCompositorView();
// IPC message handlers.
void OnPluginFocusChanged(bool focused, int plugin_id);
void OnStartPluginIme();
-
- // Convert |rect| from the views coordinate (upper-left origin) into
- // the OpenGL coordinate (lower-left origin) and scale for HiDPI displays.
- gfx::Rect GetScaledOpenGLPixelRect(const gfx::Rect& rect);
+ void OnGetRenderedTextCompleted(const std::string& text);
// Send updated vsync parameters to the renderer.
void SendVSyncParametersToRenderer();
+ // Dispatches a TTS session.
+ void SpeakText(const std::string& text);
+
// The associated view. This is weak and is inserted into the view hierarchy
// to own this RenderWidgetHostViewMac object. Set to nil at the start of the
// destructor.
@@ -561,9 +504,19 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// Indicates if the page is loading.
bool is_loading_;
+ // Whether it's allowed to pause waiting for a new frame.
+ bool allow_pause_for_resize_or_repaint_;
+
+ // The last scroll offset of the view.
+ gfx::Vector2dF last_scroll_offset_;
+
// The text to be shown in the tooltip, supplied by the renderer.
base::string16 tooltip_text_;
+ // True when this view acts as a platform view hack for a
+ // RenderWidgetHostViewGuest.
+ bool is_guest_view_hack_;
+
// Factory used to safely scope delayed calls to ShutdownHost().
base::WeakPtrFactory<RenderWidgetHostViewMac> weak_factory_;
@@ -579,23 +532,14 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// Our parent host view, if this is fullscreen. NULL otherwise.
RenderWidgetHostViewMac* fullscreen_parent_host_view_;
- // The overlay view which is rendered above this one in the same
- // accelerated IOSurface.
- // Overlay view has |underlay_view_| set to this view.
- base::WeakPtr<RenderWidgetHostViewMac> overlay_view_;
-
- // The underlay view which this view is rendered above in the same
- // accelerated IOSurface.
- // Underlay view has |overlay_view_| set to this view.
- base::WeakPtr<RenderWidgetHostViewMac> underlay_view_;
-
- // Factory used to safely reference overlay view set in SetOverlayView.
- base::WeakPtrFactory<RenderWidgetHostViewMac>
- overlay_view_weak_factory_;
-
// Display link for getting vsync info.
scoped_refptr<DisplayLinkMac> display_link_;
+ // The current VSync timebase and interval. This is zero until the first call
+ // to SendVSyncParametersToRenderer(), and refreshed regularly thereafter.
+ base::TimeTicks vsync_timebase_;
+ base::TimeDelta vsync_interval_;
+
// The current composition character range and its bounds.
gfx::Range composition_range_;
std::vector<gfx::Rect> composition_bounds_;
@@ -603,11 +547,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// The current caret bounds.
gfx::Rect caret_rect_;
- // Subscriber that listens to frame presentation events.
- scoped_ptr<RenderWidgetHostViewFrameSubscriber> frame_subscriber_;
-
- base::WeakPtrFactory<RenderWidgetHostViewMac>
- software_frame_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac);
};
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 375833cec29..84a6008c5a0 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
@@ -28,22 +28,24 @@
#include "base/sys_info.h"
#import "content/browser/accessibility/browser_accessibility_cocoa.h"
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
+#import "content/browser/cocoa/system_hotkey_helper_mac.h"
+#import "content/browser/cocoa/system_hotkey_map.h"
+#include "content/browser/compositor/io_surface_layer_mac.h"
#include "content/browser/compositor/resize_lock.h"
+#include "content/browser/compositor/software_layer_mac.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/renderer_host/compositing_iosurface_context_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_layer_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_mac.h"
+#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/browser/renderer_host/render_view_host_impl.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"
-#import "content/browser/renderer_host/software_layer_mac.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/gpu/surface_handle_types_mac.h"
#include "content/common/input_messages.h"
#include "content/common/view_messages.h"
#include "content/common/webplugin_geometry.h"
@@ -56,6 +58,7 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.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"
#include "third_party/WebKit/public/web/mac/WebInputEventFactory.h"
@@ -68,6 +71,7 @@
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/display.h"
+#include "ui/gfx/frame_time.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
@@ -94,6 +98,17 @@ using blink::WebMouseEvent;
using blink::WebMouseWheelEvent;
using blink::WebGestureEvent;
+namespace {
+
+// Whether a keyboard event has been reserved by OSX.
+BOOL EventIsReservedBySystem(NSEvent* event) {
+ content::SystemHotkeyHelperMac* helper =
+ content::SystemHotkeyHelperMac::GetInstance();
+ return helper->map()->IsEventReserved(event);
+}
+
+} // namespace
+
// These are not documented, so use only after checking -respondsToSelector:.
@interface NSApplication (UndocumentedSpeechMethods)
- (void)speakString:(NSString*)string;
@@ -101,15 +116,6 @@ using blink::WebGestureEvent;
- (BOOL)isSpeaking;
@end
-// Declare things that are part of the 10.7 SDK.
-#if !defined(MAC_OS_X_VERSION_10_7) || \
- MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-
-static NSString* const NSWindowDidChangeBackingPropertiesNotification =
- @"NSWindowDidChangeBackingPropertiesNotification";
-
-#endif // 10.7
-
// This method will return YES for OS X versions 10.7.3 and later, and NO
// otherwise.
// Used to prevent a crash when building with the 10.7 SDK and accessing the
@@ -375,17 +381,12 @@ blink::WebScreenInfo GetWebScreenInfo(NSView* view) {
results.rect = display.bounds();
results.availableRect = display.work_area();
results.orientationAngle = display.RotationAsDegree();
+ results.orientationType =
+ content::RenderWidgetHostViewBase::GetOrientationTypeForDesktop(display);
return results;
}
-void RemoveLayerFromSuperlayer(
- base::scoped_nsobject<CompositingIOSurfaceLayer> layer) {
- // Disable the fade-out animation as the layer is removed.
- ScopedCAActionDisabler disabler;
- [layer removeFromSuperlayer];
-}
-
} // namespace
namespace content {
@@ -394,7 +395,11 @@ namespace content {
// DelegatedFrameHost, public:
ui::Compositor* RenderWidgetHostViewMac::GetCompositor() const {
- return [browser_compositor_view_ compositor];
+ // When |browser_compositor_view_| is suspended or destroyed, the connection
+ // between its ui::Compositor and |delegated_frame_host_| has been severed.
+ if (browser_compositor_state_ == BrowserCompositorActive)
+ return browser_compositor_view_->GetCompositor();
+ return NULL;
}
ui::Layer* RenderWidgetHostViewMac::GetLayer() {
@@ -405,11 +410,6 @@ RenderWidgetHostImpl* RenderWidgetHostViewMac::GetHost() {
return render_widget_host_;
}
-void RenderWidgetHostViewMac::SchedulePaintInRect(
- const gfx::Rect& damage_rect_in_dip) {
- [browser_compositor_view_ compositor]->ScheduleFullRedraw();
-}
-
bool RenderWidgetHostViewMac::IsVisible() {
return !render_widget_host_->is_hidden();
}
@@ -439,6 +439,62 @@ DelegatedFrameHost* RenderWidgetHostViewMac::GetDelegatedFrameHost() const {
return delegated_frame_host_.get();
}
+////////////////////////////////////////////////////////////////////////////////
+// BrowserCompositorViewMacClient, public:
+
+bool RenderWidgetHostViewMac::BrowserCompositorViewShouldAckImmediately()
+ const {
+ // If vsync is disabled, then always draw and ack frames immediately.
+ static bool is_vsync_disabled =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuVsync);
+ if (is_vsync_disabled)
+ return true;
+
+ // If the window is occluded, then this frame's display call may be severely
+ // throttled. This is a good thing, unless tab capture may be active, because
+ // the broadcast will be inappropriately throttled.
+ // http://crbug.com/350410
+
+ // If tab capture isn't active then only ack frames when we draw them.
+ if (delegated_frame_host_ && !delegated_frame_host_->HasFrameSubscriber())
+ return false;
+
+ NSWindow* window = [cocoa_view_ window];
+ // If the view isn't even in the heirarchy then frames will never be drawn,
+ // so ack them immediately.
+ if (!window)
+ return true;
+
+ // Check the window occlusion API.
+ if ([window respondsToSelector:@selector(occlusionState)]) {
+ if ([window occlusionState] & NSWindowOcclusionStateVisible) {
+ // If the window is visible then it is safe to wait until frames are
+ // drawn to ack them.
+ return false;
+ } else {
+ // If the window is occluded then frames may never be drawn, so ack them
+ // immediately.
+ return true;
+ }
+ }
+
+ // If the window occlusion API is not present then ack frames when we draw
+ // them.
+ return false;
+}
+
+void RenderWidgetHostViewMac::BrowserCompositorViewFrameSwapped(
+ const std::vector<ui::LatencyInfo>& all_latency_info) {
+ if (!render_widget_host_)
+ return;
+ for (auto latency_info : all_latency_info) {
+ latency_info.AddLatencyNumber(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
+ render_widget_host_->FrameSwapped(latency_info);
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewBase, public:
@@ -451,49 +507,66 @@ void RenderWidgetHostViewBase::GetDefaultScreenInfo(
///////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewMac, public:
-RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
+RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
+ bool is_guest_view_hack)
: render_widget_host_(RenderWidgetHostImpl::From(widget)),
text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
can_compose_inline_(true),
- backing_store_scale_factor_(1),
+ browser_compositor_state_(BrowserCompositorDestroyed),
+ browser_compositor_view_placeholder_(
+ new BrowserCompositorViewPlaceholderMac),
is_loading_(false),
+ allow_pause_for_resize_or_repaint_(true),
+ is_guest_view_hack_(is_guest_view_hack),
weak_factory_(this),
- fullscreen_parent_host_view_(NULL),
- overlay_view_weak_factory_(this),
- software_frame_weak_ptr_factory_(this) {
- software_frame_manager_.reset(new SoftwareFrameManager(
- software_frame_weak_ptr_factory_.GetWeakPtr()));
+ fullscreen_parent_host_view_(NULL) {
// |cocoa_view_| owns us and we will be deleted when |cocoa_view_|
// goes away. Since we autorelease it, our caller must put
// |GetNativeView()| into the view hierarchy right after calling us.
cocoa_view_ = [[[RenderWidgetHostViewCocoa alloc]
initWithRenderWidgetHostViewMac:this] autorelease];
+ // Paint this view host with |background_color_| when there is no content
+ // ready to draw.
background_layer_.reset([[CALayer alloc] init]);
[background_layer_
- setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
+ setBackgroundColor:gfx::CGColorCreateFromSkColor(background_color_)];
[cocoa_view_ setLayer:background_layer_];
[cocoa_view_ setWantsLayer:YES];
- render_widget_host_->SetView(this);
+ if (IsDelegatedRendererEnabled()) {
+ root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
+ delegated_frame_host_.reset(new DelegatedFrameHost(this));
+ }
+
+ gfx::Screen::GetScreenFor(cocoa_view_)->AddObserver(this);
+
+ if (!is_guest_view_hack_)
+ render_widget_host_->SetView(this);
}
RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
+ gfx::Screen::GetScreenFor(cocoa_view_)->RemoveObserver(this);
+
// This is being called from |cocoa_view_|'s destructor, so invalidate the
// pointer.
cocoa_view_ = nil;
UnlockMouse();
- // Make sure that the layer doesn't reach into the now-invalid object.
- DestroyCompositedIOSurfaceAndLayer();
- DestroySoftwareLayer();
+ // Ensure that the browser compositor is destroyed in a safe order.
+ ShutdownBrowserCompositor();
// We are owned by RenderWidgetHostViewCocoa, so if we go away before the
// RenderWidgetHost does we need to tell it not to hold a stale pointer to
// us.
- if (render_widget_host_)
- render_widget_host_->SetView(NULL);
+ if (render_widget_host_) {
+ // If this is a RenderWidgetHostViewGuest's platform_view_, we're not the
+ // RWH's view, the RenderWidgetHostViewGuest is. So don't reset the RWH's
+ // view, the RenderWidgetHostViewGuest will do it.
+ if (!is_guest_view_hack_)
+ render_widget_host_->SetView(NULL);
+ }
}
void RenderWidgetHostViewMac::SetDelegate(
@@ -501,130 +574,74 @@ void RenderWidgetHostViewMac::SetDelegate(
[cocoa_view_ setResponderDelegate:delegate];
}
-void RenderWidgetHostViewMac::SetAllowOverlappingViews(bool overlapping) {
- // TODO(ccameron): Remove callers of this function.
+void RenderWidgetHostViewMac::SetAllowPauseForResizeOrRepaint(bool allow) {
+ allow_pause_for_resize_or_repaint_ = allow;
}
///////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewMac, RenderWidgetHostView implementation:
-bool RenderWidgetHostViewMac::EnsureCompositedIOSurface() {
- // If the context or the IOSurface's context has had an error, re-build
- // everything from scratch.
- if (compositing_iosurface_context_ &&
- compositing_iosurface_context_->HasBeenPoisoned()) {
- LOG(ERROR) << "Failing EnsureCompositedIOSurface because "
- << "context was poisoned";
- return false;
- }
- if (compositing_iosurface_ &&
- compositing_iosurface_->HasBeenPoisoned()) {
- LOG(ERROR) << "Failing EnsureCompositedIOSurface because "
- << "surface was poisoned";
- return false;
- }
-
- int current_window_number =
- CompositingIOSurfaceContext::kOffscreenContextWindowNumber;
- bool new_surface_needed = !compositing_iosurface_;
- bool new_context_needed =
- !compositing_iosurface_context_ ||
- (compositing_iosurface_context_ &&
- compositing_iosurface_context_->window_number() !=
- current_window_number);
-
- if (!new_surface_needed && !new_context_needed)
- return true;
+void RenderWidgetHostViewMac::EnsureBrowserCompositorView() {
+ TRACE_EVENT0("browser",
+ "RenderWidgetHostViewMac::EnsureBrowserCompositorView");
- // Create the GL context and shaders.
- if (new_context_needed) {
- scoped_refptr<CompositingIOSurfaceContext> new_context =
- CompositingIOSurfaceContext::Get(current_window_number);
- // Un-bind the GL context from this view before binding the new GL
- // context. Having two GL contexts bound to a view will result in
- // crashes and corruption.
- // http://crbug.com/230883
- if (!new_context) {
- LOG(ERROR) << "Failed to create CompositingIOSurfaceContext";
- return false;
- }
- compositing_iosurface_context_ = new_context;
+ // Create the view, to transition from Destroyed -> Suspended.
+ if (browser_compositor_state_ == BrowserCompositorDestroyed) {
+ browser_compositor_view_.reset(
+ new BrowserCompositorViewMac(this, cocoa_view_, root_layer_.get()));
+ browser_compositor_state_ = BrowserCompositorSuspended;
}
- // Create the IOSurface texture.
- if (new_surface_needed) {
- compositing_iosurface_ = CompositingIOSurfaceMac::Create();
- if (!compositing_iosurface_) {
- LOG(ERROR) << "Failed to create CompositingIOSurface";
- return false;
- }
+ // Show the DelegatedFrameHost to transition from Suspended -> Active.
+ if (browser_compositor_state_ == BrowserCompositorSuspended) {
+ delegated_frame_host_->AddedToWindow();
+ delegated_frame_host_->WasShown(ui::LatencyInfo());
+ browser_compositor_state_ = BrowserCompositorActive;
}
-
- return true;
}
-void RenderWidgetHostViewMac::EnsureSoftwareLayer() {
- TRACE_EVENT0("browser", "RenderWidgetHostViewMac::EnsureSoftwareLayer");
- if (software_layer_)
- return;
-
- software_layer_.reset([[SoftwareLayer alloc] init]);
- DCHECK(software_layer_);
-
- // Disable the fade-in animation as the layer is added.
- ScopedCAActionDisabler disabler;
- [background_layer_ addSublayer:software_layer_];
-}
-
-void RenderWidgetHostViewMac::DestroySoftwareLayer() {
- if (!software_layer_)
- return;
+void RenderWidgetHostViewMac::SuspendBrowserCompositorView() {
+ TRACE_EVENT0("browser",
+ "RenderWidgetHostViewMac::SuspendBrowserCompositorView");
- // Disable the fade-out animation as the layer is removed.
- ScopedCAActionDisabler disabler;
- [software_layer_ removeFromSuperlayer];
- software_layer_.reset();
+ // Hide the DelegatedFrameHost to transition from Active -> Suspended.
+ if (browser_compositor_state_ == BrowserCompositorActive) {
+ // Marking the DelegatedFrameHost as removed from the window hierarchy is
+ // necessary to remove all connections to its old ui::Compositor.
+ delegated_frame_host_->WasHidden();
+ delegated_frame_host_->RemovingFromWindow();
+ browser_compositor_state_ = BrowserCompositorSuspended;
+ }
}
-void RenderWidgetHostViewMac::EnsureCompositedIOSurfaceLayer() {
+void RenderWidgetHostViewMac::DestroyBrowserCompositorView() {
TRACE_EVENT0("browser",
- "RenderWidgetHostViewMac::EnsureCompositedIOSurfaceLayer");
- DCHECK(compositing_iosurface_context_);
- if (compositing_iosurface_layer_)
- return;
+ "RenderWidgetHostViewMac::DestroyBrowserCompositorView");
- compositing_iosurface_layer_.reset([[CompositingIOSurfaceLayer alloc]
- initWithIOSurface:compositing_iosurface_
- withScaleFactor:compositing_iosurface_->scale_factor()
- withClient:this]);
- DCHECK(compositing_iosurface_layer_);
+ // Transition from Active -> Suspended if need be.
+ SuspendBrowserCompositorView();
- // Disable the fade-in animation as the layer is added.
- ScopedCAActionDisabler disabler;
- [background_layer_ addSublayer:compositing_iosurface_layer_];
+ // Destroy the BrowserCompositorView to transition Suspended -> Destroyed.
+ if (browser_compositor_state_ == BrowserCompositorSuspended) {
+ browser_compositor_view_.reset();
+ browser_compositor_state_ = BrowserCompositorDestroyed;
+ }
}
-void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceLayer(
- DestroyCompositedIOSurfaceLayerBehavior destroy_layer_behavior) {
- if (!compositing_iosurface_layer_)
+void RenderWidgetHostViewMac::DestroySuspendedBrowserCompositorViewIfNeeded() {
+ if (browser_compositor_state_ != BrowserCompositorSuspended)
return;
- if (destroy_layer_behavior == kRemoveLayerFromHierarchy) {
- // Disable the fade-out animation as the layer is removed.
- ScopedCAActionDisabler disabler;
- [compositing_iosurface_layer_ removeFromSuperlayer];
- }
- [compositing_iosurface_layer_ resetClient];
- compositing_iosurface_layer_.reset();
-}
-
-void RenderWidgetHostViewMac::DestroyCompositedIOSurfaceAndLayer() {
- // Any pending frames will not be displayed, so ack them now.
- SendPendingSwapAck();
+ // If this view is in a window that is visible, keep around the suspended
+ // BrowserCompositorView in case |cocoa_view_| is suddenly revealed (so that
+ // we don't flash white).
+ NSWindow* window = [cocoa_view_ window];
+ if (window)
+ return;
- DestroyCompositedIOSurfaceLayer(kRemoveLayerFromHierarchy);
- compositing_iosurface_ = NULL;
- compositing_iosurface_context_ = NULL;
+ // This should only be reached if |render_widget_host_| is hidden, destroyed,
+ // or in the process of being destroyed.
+ DestroyBrowserCompositorView();
}
bool RenderWidgetHostViewMac::OnMessageReceived(const IPC::Message& message) {
@@ -632,6 +649,8 @@ bool RenderWidgetHostViewMac::OnMessageReceived(const IPC::Message& message) {
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)
IPC_END_MESSAGE_MAP()
return handled;
@@ -742,7 +761,8 @@ float RenderWidgetHostViewMac::ViewScaleFactor() const {
void RenderWidgetHostViewMac::UpdateDisplayLink() {
static bool is_vsync_disabled =
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync);
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuVsync);
if (is_vsync_disabled)
return;
@@ -752,7 +772,7 @@ void RenderWidgetHostViewMac::UpdateDisplayLink() {
CGDirectDisplayID display_id = [screen_number unsignedIntValue];
display_link_ = DisplayLinkMac::GetForDisplay(display_id);
- if (!display_link_) {
+ if (!display_link_.get()) {
// Note that on some headless systems, the display link will fail to be
// created, so this should not be a fatal error.
LOG(ERROR) << "Failed to create display link.";
@@ -760,26 +780,25 @@ void RenderWidgetHostViewMac::UpdateDisplayLink() {
}
void RenderWidgetHostViewMac::SendVSyncParametersToRenderer() {
- if (!render_widget_host_ || !display_link_)
+ if (!render_widget_host_ || !display_link_.get())
return;
- base::TimeTicks timebase;
- base::TimeDelta interval;
- if (!display_link_->GetVSyncParameters(&timebase, &interval))
+ if (!display_link_->GetVSyncParameters(&vsync_timebase_, &vsync_interval_)) {
+ vsync_timebase_ = base::TimeTicks();
+ vsync_interval_ = base::TimeDelta();
return;
+ }
+
+ render_widget_host_->UpdateVSyncParameters(vsync_timebase_, vsync_interval_);
+}
- render_widget_host_->UpdateVSyncParameters(timebase, interval);
+void RenderWidgetHostViewMac::SpeakText(const std::string& text) {
+ [NSApp speakString:base::SysUTF8ToNSString(text)];
}
void RenderWidgetHostViewMac::UpdateBackingStoreScaleFactor() {
if (!render_widget_host_)
return;
-
- float new_scale_factor = ui::GetScaleFactorForNativeView(cocoa_view_);
- if (new_scale_factor == backing_store_scale_factor_)
- return;
- backing_store_scale_factor_ = new_scale_factor;
-
render_widget_host_->NotifyScreenInfoChanged();
}
@@ -791,17 +810,16 @@ void RenderWidgetHostViewMac::WasShown() {
if (!render_widget_host_->is_hidden())
return;
- render_widget_host_->WasShown();
- software_frame_manager_->SetVisibility(true);
- if (delegated_frame_host_)
- delegated_frame_host_->WasShown();
-
- // Call setNeedsDisplay before pausing for new frames to come in -- if any
- // do, and are drawn, then the needsDisplay bit will be cleared.
- // Workaround for crbug.com/395827
- if ([compositing_iosurface_layer_ isAsynchronous])
- [compositing_iosurface_layer_ setAsynchronous:NO];
- [compositing_iosurface_layer_ setNeedsDisplay];
+ ui::LatencyInfo renderer_latency_info;
+ renderer_latency_info.AddLatencyNumber(
+ ui::TAB_SHOW_COMPONENT,
+ render_widget_host_->GetLatencyComponentId(),
+ 0);
+ render_widget_host_->WasShown(renderer_latency_info);
+
+ // If there is not a frame being currently drawn, kick one, so that the below
+ // pause will have a frame to wait on.
+ render_widget_host_->ScheduleComposite();
PauseForPendingResizeOrRepaintsAndDraw();
}
@@ -809,16 +827,12 @@ void RenderWidgetHostViewMac::WasHidden() {
if (render_widget_host_->is_hidden())
return;
- // Any pending frames will not be displayed until this is shown again. Ack
- // them now.
- SendPendingSwapAck();
-
// If we have a renderer, then inform it that we are being hidden so it can
// reduce its resource utilization.
render_widget_host_->WasHidden();
- software_frame_manager_->SetVisibility(false);
- if (delegated_frame_host_)
- delegated_frame_host_->WasHidden();
+
+ SuspendBrowserCompositorView();
+ DestroySuspendedBrowserCompositorViewIfNeeded();
}
void RenderWidgetHostViewMac::SetSize(const gfx::Size& size) {
@@ -875,6 +889,10 @@ void RenderWidgetHostViewMac::SetBounds(const gfx::Rect& rect) {
}
}
+gfx::Vector2dF RenderWidgetHostViewMac::GetLastScrollOffset() const {
+ return last_scroll_offset_;
+}
+
gfx::NativeView RenderWidgetHostViewMac::GetNativeView() const {
return cocoa_view_;
}
@@ -912,9 +930,7 @@ bool RenderWidgetHostViewMac::HasFocus() const {
bool RenderWidgetHostViewMac::IsSurfaceAvailableForCopy() const {
if (delegated_frame_host_)
return delegated_frame_host_->CanCopyToBitmap();
-
- return software_frame_manager_->HasCurrentFrame() ||
- (compositing_iosurface_ && compositing_iosurface_->HasIOSurface());
+ return false;
}
void RenderWidgetHostViewMac::Show() {
@@ -958,12 +974,15 @@ void RenderWidgetHostViewMac::SetIsLoading(bool is_loading) {
// like Chrome does on Windows, call |UpdateCursor()| here.
}
-void RenderWidgetHostViewMac::TextInputStateChanged(
- const ViewHostMsg_TextInputState_Params& params) {
- if (text_input_type_ != params.type ||
- can_compose_inline_ != params.can_compose_inline) {
- text_input_type_ = params.type;
- can_compose_inline_ = params.can_compose_inline;
+void RenderWidgetHostViewMac::TextInputTypeChanged(
+ ui::TextInputType type,
+ ui::TextInputMode input_mode,
+ bool can_compose_inline,
+ int flags) {
+ if (text_input_type_ != type
+ || can_compose_inline_ != can_compose_inline) {
+ text_input_type_ = type;
+ can_compose_inline_ = can_compose_inline;
if (HasFocus()) {
SetTextInputActive(true);
@@ -997,6 +1016,13 @@ void RenderWidgetHostViewMac::RenderProcessGone(base::TerminationStatus status,
Destroy();
}
+void RenderWidgetHostViewMac::RenderWidgetHostGone() {
+ // Destroy the DelegatedFrameHost, to prevent crashes when Destroy is never
+ // called on the view.
+ // http://crbug.com/404828
+ ShutdownBrowserCompositor();
+}
+
void RenderWidgetHostViewMac::Destroy() {
[[NSNotificationCenter defaultCenter]
removeObserver:cocoa_view_
@@ -1022,9 +1048,7 @@ void RenderWidgetHostViewMac::Destroy() {
// Delete the delegated frame state, which will reach back into
// render_widget_host_.
- [browser_compositor_view_ resetClient];
- delegated_frame_host_.reset();
- root_layer_.reset();
+ ShutdownBrowserCompositor();
// We get this call just before |render_widget_host_| deletes
// itself. But we are owned by |cocoa_view_|, which may be retained
@@ -1061,8 +1085,19 @@ bool RenderWidgetHostViewMac::SupportsSpeech() const {
}
void RenderWidgetHostViewMac::SpeakSelection() {
- if ([NSApp respondsToSelector:@selector(speakString:)])
- [NSApp speakString:base::SysUTF8ToNSString(selected_text_)];
+ if (![NSApp respondsToSelector:@selector(speakString:)])
+ return;
+
+ if (selected_text_.empty() && render_widget_host_) {
+ // If there's no selection, speak all text. Send an asynchronous IPC
+ // request for fetching all the text for a webcontent.
+ // ViewMsg_GetRenderedTextCompleted is sent back to IPC Message receiver.
+ render_widget_host_->Send(new ViewMsg_GetRenderedText(
+ render_widget_host_->GetRoutingID()));
+ return;
+ }
+
+ SpeakText(selected_text_);
}
bool RenderWidgetHostViewMac::IsSpeaking() const {
@@ -1113,9 +1148,6 @@ void RenderWidgetHostViewMac::SelectionBoundsChanged(
caret_rect_ = params.anchor_rect;
}
-void RenderWidgetHostViewMac::ScrollOffsetChanged() {
-}
-
void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) {
RenderWidgetHostViewBase::SetShowingContextMenu(showing);
@@ -1152,65 +1184,10 @@ void RenderWidgetHostViewMac::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
- const SkBitmap::Config config) {
+ const SkColorType color_type) {
if (delegated_frame_host_) {
delegated_frame_host_->CopyFromCompositingSurface(
- src_subrect, dst_size, callback, config);
- return;
- }
-
- if (config != SkBitmap::kARGB_8888_Config) {
- NOTIMPLEMENTED();
- callback.Run(false, SkBitmap());
- }
- base::ScopedClosureRunner scoped_callback_runner(
- base::Bind(callback, false, SkBitmap()));
- float scale = ui::GetScaleFactorForNativeView(cocoa_view_);
- gfx::Size dst_pixel_size = gfx::ToFlooredSize(
- gfx::ScaleSize(dst_size, scale));
- if (compositing_iosurface_ && compositing_iosurface_->HasIOSurface()) {
- ignore_result(scoped_callback_runner.Release());
- compositing_iosurface_->CopyTo(GetScaledOpenGLPixelRect(src_subrect),
- dst_pixel_size,
- callback);
- } else if (software_frame_manager_->HasCurrentFrame()) {
- gfx::Rect src_pixel_rect = gfx::ToEnclosingRect(gfx::ScaleRect(
- src_subrect,
- software_frame_manager_->GetCurrentFrameDeviceScaleFactor()));
- SkBitmap source_bitmap;
- source_bitmap.setConfig(
- SkBitmap::kARGB_8888_Config,
- software_frame_manager_->GetCurrentFrameSizeInPixels().width(),
- software_frame_manager_->GetCurrentFrameSizeInPixels().height(),
- 0,
- kOpaque_SkAlphaType);
- source_bitmap.setPixels(software_frame_manager_->GetCurrentFramePixels());
-
- SkBitmap target_bitmap;
- target_bitmap.setConfig(
- SkBitmap::kARGB_8888_Config,
- dst_pixel_size.width(),
- dst_pixel_size.height(),
- 0,
- kOpaque_SkAlphaType);
- if (!target_bitmap.allocPixels())
- return;
-
- SkCanvas target_canvas(target_bitmap);
- SkRect src_pixel_skrect = SkRect::MakeXYWH(
- src_pixel_rect.x(), src_pixel_rect.y(),
- src_pixel_rect.width(), src_pixel_rect.height());
- target_canvas.drawBitmapRectToRect(
- source_bitmap,
- &src_pixel_skrect,
- SkRect::MakeXYWH(0, 0, dst_pixel_size.width(), dst_pixel_size.height()),
- NULL,
- SkCanvas::kNone_DrawBitmapRectFlag);
-
- ignore_result(scoped_callback_runner.Release());
- callback.Run(true, target_bitmap);
- } else {
- callback.Run(false, SkBitmap());
+ src_subrect, dst_size, callback, color_type);
}
}
@@ -1221,71 +1198,30 @@ void RenderWidgetHostViewMac::CopyFromCompositingSurfaceToVideoFrame(
if (delegated_frame_host_) {
delegated_frame_host_->CopyFromCompositingSurfaceToVideoFrame(
src_subrect, target, callback);
- return;
- }
-
- base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false));
- if (!compositing_iosurface_ || !compositing_iosurface_->HasIOSurface())
- return;
-
- if (!target.get()) {
- NOTREACHED();
- return;
}
-
- if (target->format() != media::VideoFrame::YV12 &&
- target->format() != media::VideoFrame::I420) {
- NOTREACHED();
- return;
- }
-
- if (src_subrect.IsEmpty())
- return;
-
- ignore_result(scoped_callback_runner.Release());
- compositing_iosurface_->CopyToVideoFrame(
- GetScaledOpenGLPixelRect(src_subrect),
- target,
- callback);
}
bool RenderWidgetHostViewMac::CanCopyToVideoFrame() const {
if (delegated_frame_host_)
return delegated_frame_host_->CanCopyToVideoFrame();
-
- return (!software_frame_manager_->HasCurrentFrame() &&
- compositing_iosurface_ &&
- compositing_iosurface_->HasIOSurface());
+ return false;
}
bool RenderWidgetHostViewMac::CanSubscribeFrame() const {
if (delegated_frame_host_)
return delegated_frame_host_->CanSubscribeFrame();
-
- return !software_frame_manager_->HasCurrentFrame();
+ return false;
}
void RenderWidgetHostViewMac::BeginFrameSubscription(
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
- if (delegated_frame_host_) {
+ if (delegated_frame_host_)
delegated_frame_host_->BeginFrameSubscription(subscriber.Pass());
- return;
- }
- frame_subscriber_ = subscriber.Pass();
}
void RenderWidgetHostViewMac::EndFrameSubscription() {
- if (delegated_frame_host_) {
+ if (delegated_frame_host_)
delegated_frame_host_->EndFrameSubscription();
- return;
- }
-
- frame_subscriber_.reset();
-}
-
-// Sets whether or not to accept first responder status.
-void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) {
- [cocoa_view_ setTakesFocusOnlyOnMouseDown:flag];
}
void RenderWidgetHostViewMac::ForwardMouseEvent(const WebMouseEvent& event) {
@@ -1328,205 +1264,6 @@ void RenderWidgetHostViewMac::PluginImeCompositionCompleted(
}
}
-void RenderWidgetHostViewMac::CompositorSwapBuffers(
- IOSurfaceID surface_handle,
- const gfx::Size& size,
- float surface_scale_factor,
- const std::vector<ui::LatencyInfo>& latency_info) {
- // Ensure that the frame be acked unless it is explicitly passed to a
- // display function.
- base::ScopedClosureRunner scoped_ack(
- base::Bind(&RenderWidgetHostViewMac::SendPendingSwapAck,
- weak_factory_.GetWeakPtr()));
-
- if (render_widget_host_->is_hidden())
- return;
-
- // Ensure that if this function exits before the frame is set up (but not
- // necessarily drawn) then it is treated as an error.
- base::ScopedClosureRunner scoped_error(
- base::Bind(&RenderWidgetHostViewMac::GotAcceleratedCompositingError,
- weak_factory_.GetWeakPtr()));
-
- AddPendingLatencyInfo(latency_info);
-
- // If compositing_iosurface_ exists and has been poisoned, destroy it
- // and allow EnsureCompositedIOSurface to recreate it below. Keep a
- // reference to the destroyed layer around until after the below call
- // to LayoutLayers, to avoid flickers.
- base::ScopedClosureRunner scoped_layer_remover;
- if (compositing_iosurface_context_ &&
- compositing_iosurface_context_->HasBeenPoisoned()) {
- scoped_layer_remover.Reset(
- base::Bind(RemoveLayerFromSuperlayer, compositing_iosurface_layer_));
- DestroyCompositedIOSurfaceLayer(kLeaveLayerInHierarchy);
- DestroyCompositedIOSurfaceAndLayer();
- }
-
- // Ensure compositing_iosurface_ and compositing_iosurface_context_ be
- // allocated.
- if (!EnsureCompositedIOSurface()) {
- LOG(ERROR) << "Failed EnsureCompositingIOSurface";
- return;
- }
-
- // Make the context current and update the IOSurface with the handle
- // passed in by the swap command.
- {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- compositing_iosurface_context_->cgl_context());
- if (!compositing_iosurface_->SetIOSurfaceWithContextCurrent(
- compositing_iosurface_context_, surface_handle, size,
- surface_scale_factor)) {
- LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
- return;
- }
- }
-
- // Grab video frames now that the IOSurface has been set up. Note that this
- // will be done in an offscreen context, so it is necessary to re-set the
- // current context afterward.
- bool frame_was_captured = false;
- if (frame_subscriber_) {
- const base::TimeTicks present_time = base::TimeTicks::Now();
- scoped_refptr<media::VideoFrame> frame;
- RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
- if (frame_subscriber_->ShouldCaptureFrame(present_time,
- &frame, &callback)) {
- // Flush the context that updated the IOSurface, to ensure that the
- // context that does the copy picks up the correct version.
- {
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- compositing_iosurface_context_->cgl_context());
- glFlush();
- }
- compositing_iosurface_->CopyToVideoFrame(
- gfx::Rect(size), frame,
- base::Bind(callback, present_time));
- frame_was_captured = true;
- }
- }
-
- // At this point the surface, its context, and its layer have been set up, so
- // don't generate an error (one may be generated when drawing).
- ignore_result(scoped_error.Release());
-
- GotAcceleratedFrame();
-
- gfx::Size window_size(NSSizeToCGSize([cocoa_view_ frame].size));
- if (window_size.IsEmpty()) {
- // setNeedsDisplay will never display and we'll never ack if the window is
- // empty, so ack now and don't bother calling setNeedsDisplay below.
- return;
- }
- if (window_number() <= 0) {
- // It's normal for a backgrounded tab that is being captured to have no
- // window but not be hidden. Immediately ack the frame, and don't try to
- // draw it.
- if (frame_was_captured)
- return;
-
- // If this frame was not captured, there is likely some sort of bug. Ack
- // the frame and hope for the best. Because the IOSurface and layer are
- // populated, it will likely be displayed when the view is added to a
- // window's hierarchy.
-
- // TODO(shess) If the view does not have a window, or the window
- // does not have backing, the IOSurface will log "invalid drawable"
- // in -setView:. It is not clear how this code is reached with such
- // a case, so record some info into breakpad (some subset of
- // browsers are likely to crash later for unrelated reasons).
- // http://crbug.com/148882
- const char* const kCrashKey = "rwhvm_window";
- NSWindow* window = [cocoa_view_ window];
- if (!window) {
- base::debug::SetCrashKeyValue(kCrashKey, "Missing window");
- } else {
- std::string value =
- base::StringPrintf("window %s delegate %s controller %s",
- object_getClassName(window),
- object_getClassName([window delegate]),
- object_getClassName([window windowController]));
- base::debug::SetCrashKeyValue(kCrashKey, value);
- }
- return;
- }
-
- // If the window is occluded, then this frame's display call may be severely
- // throttled. This is a good thing, unless tab capture may be active,
- // because the broadcast will be inappropriately throttled.
- // http://crbug.com/350410
- NSWindow* window = [cocoa_view_ window];
- if (window && [window respondsToSelector:@selector(occlusionState)]) {
- bool window_is_occluded =
- !([window occlusionState] & NSWindowOcclusionStateVisible);
- // Note that we aggressively ack even if this particular frame is not being
- // captured.
- if (window_is_occluded && frame_subscriber_)
- scoped_ack.Reset();
- }
-
- // If we reach here, then the frame will be displayed by a future draw
- // call, so don't make the callback.
- ignore_result(scoped_ack.Release());
- DCHECK(compositing_iosurface_layer_);
- [compositing_iosurface_layer_ gotNewFrame];
-
- // Try to finish previous copy requests after draw to get better pipelining.
- if (compositing_iosurface_)
- compositing_iosurface_->CheckIfAllCopiesAreFinished(false);
-
- // The IOSurface's size may have changed, so re-layout the layers to take
- // this into account. This may force an immediate draw.
- LayoutLayers();
-}
-
-void RenderWidgetHostViewMac::GotAcceleratedCompositingError() {
- LOG(ERROR) << "Encountered accelerated compositing error";
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&RenderWidgetHostViewMac::DestroyCompositingStateOnError,
- weak_factory_.GetWeakPtr()));
-}
-
-void RenderWidgetHostViewMac::DestroyCompositingStateOnError() {
- // This should be called with a clean stack. Make sure that no context is
- // current.
- DCHECK(!CGLGetCurrentContext());
-
- // The existing GL contexts may be in a bad state, so don't re-use any of the
- // existing ones anymore, rather, allocate new ones.
- if (compositing_iosurface_context_)
- compositing_iosurface_context_->PoisonContextAndSharegroup();
-
- DestroyCompositedIOSurfaceAndLayer();
-
- // Request that a new frame be generated and dirty the view.
- if (render_widget_host_)
- render_widget_host_->ScheduleComposite();
- [cocoa_view_ setNeedsDisplay:YES];
-
- // TODO(ccameron): It may be a good idea to request that the renderer recreate
- // its GL context as well, and fall back to software if this happens
- // repeatedly.
-}
-
-void RenderWidgetHostViewMac::SetOverlayView(
- RenderWidgetHostViewMac* overlay, const gfx::Point& offset) {
- if (overlay_view_)
- overlay_view_->underlay_view_.reset();
-
- overlay_view_ = overlay->overlay_view_weak_factory_.GetWeakPtr();
- overlay_view_->underlay_view_ = overlay_view_weak_factory_.GetWeakPtr();
-}
-
-void RenderWidgetHostViewMac::RemoveOverlayView() {
- if (overlay_view_) {
- overlay_view_->underlay_view_.reset();
- overlay_view_.reset();
- }
-}
-
bool RenderWidgetHostViewMac::GetLineBreakIndex(
const std::vector<gfx::Rect>& bounds,
const gfx::Range& range,
@@ -1660,65 +1397,10 @@ bool RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange(
return true;
}
-void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped(
- const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
- int gpu_host_id) {
- TRACE_EVENT0("browser",
- "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped");
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- IOSurfaceID io_surface_handle =
- static_cast<IOSurfaceID>(params.surface_handle);
- AddPendingSwapAck(params.route_id,
- gpu_host_id,
- compositing_iosurface_ ?
- compositing_iosurface_->GetRendererID() : 0);
- CompositorSwapBuffers(io_surface_handle,
- params.size,
- params.scale_factor,
- params.latency_info);
-}
-
-void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer(
- const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
- int gpu_host_id) {
- TRACE_EVENT0("browser",
- "RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer");
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- IOSurfaceID io_surface_handle =
- static_cast<IOSurfaceID>(params.surface_handle);
- AddPendingSwapAck(params.route_id,
- gpu_host_id,
- compositing_iosurface_ ?
- compositing_iosurface_->GetRendererID() : 0);
- CompositorSwapBuffers(io_surface_handle,
- params.surface_size,
- params.surface_scale_factor,
- params.latency_info);
-}
-
-void RenderWidgetHostViewMac::AcceleratedSurfaceSuspend() {
- if (!render_widget_host_->is_hidden())
- DestroyCompositedIOSurfaceAndLayer();
-}
-
-void RenderWidgetHostViewMac::AcceleratedSurfaceRelease() {
- DestroyCompositedIOSurfaceAndLayer();
-}
-
bool RenderWidgetHostViewMac::HasAcceleratedSurface(
const gfx::Size& desired_size) {
- if (compositing_iosurface_) {
- return compositing_iosurface_->HasIOSurface() &&
- (desired_size.IsEmpty() ||
- compositing_iosurface_->dip_io_surface_size() == desired_size);
- }
- if (software_frame_manager_->HasCurrentFrame()) {
- return (desired_size.IsEmpty() ||
- software_frame_manager_->GetCurrentFrameSizeInDIP() ==
- desired_size);
- }
+ if (browser_compositor_view_)
+ return browser_compositor_view_->HasFrameOfSize(desired_size);
return false;
}
@@ -1726,72 +1408,31 @@ void RenderWidgetHostViewMac::OnSwapCompositorFrame(
uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) {
TRACE_EVENT0("browser", "RenderWidgetHostViewMac::OnSwapCompositorFrame");
+ last_scroll_offset_ = frame->metadata.root_scroll_offset;
if (frame->delegated_frame_data) {
- if (!browser_compositor_view_) {
- browser_compositor_view_.reset(
- [[BrowserCompositorViewMac alloc] initWithSuperview:cocoa_view_]);
- root_layer_.reset(new ui::Layer(ui::LAYER_TEXTURED));
- delegated_frame_host_.reset(new DelegatedFrameHost(this));
- [browser_compositor_view_ compositor]->SetRootLayer(root_layer_.get());
- }
-
float scale_factor = frame->metadata.device_scale_factor;
- gfx::Size dip_size = ToCeiledSize(frame->metadata.viewport_size);
- gfx::Size pixel_size = ConvertSizeToPixel(
- scale_factor, dip_size);
- [browser_compositor_view_ compositor]->SetScaleAndSize(
- scale_factor, pixel_size);
+
+ // Compute the frame size based on the root render pass rect size.
+ cc::RenderPass* root_pass =
+ frame->delegated_frame_data->render_pass_list.back();
+ gfx::Size pixel_size = root_pass->output_rect.size();
+ gfx::Size dip_size =
+ ConvertSizeToDIP(scale_factor, pixel_size);
+
root_layer_->SetBounds(gfx::Rect(dip_size));
+ if (!render_widget_host_->is_hidden()) {
+ EnsureBrowserCompositorView();
+ browser_compositor_view_->GetCompositor()->SetScaleAndSize(
+ scale_factor, pixel_size);
+ }
+
+ SendVSyncParametersToRenderer();
delegated_frame_host_->SwapDelegatedFrame(
output_surface_id,
frame->delegated_frame_data.Pass(),
frame->metadata.device_scale_factor,
frame->metadata.latency_info);
- } else if (frame->software_frame_data) {
- if (!software_frame_manager_->SwapToNewFrame(
- output_surface_id,
- frame->software_frame_data.get(),
- frame->metadata.device_scale_factor,
- render_widget_host_->GetProcess()->GetHandle())) {
- render_widget_host_->GetProcess()->ReceivedBadMessage();
- return;
- }
-
- // Add latency info to report when the frame finishes drawing.
- AddPendingLatencyInfo(frame->metadata.latency_info);
-
- const void* pixels = software_frame_manager_->GetCurrentFramePixels();
- gfx::Size size_in_pixels =
- software_frame_manager_->GetCurrentFrameSizeInPixels();
-
- EnsureSoftwareLayer();
- [software_layer_ setContentsToData:pixels
- withRowBytes:4 * size_in_pixels.width()
- withPixelSize:size_in_pixels
- withScaleFactor:frame->metadata.device_scale_factor];
-
- // Send latency information to the host immediately, as there will be no
- // subsequent draw call in which to do so.
- SendPendingLatencyInfoToHost();
-
- GotSoftwareFrame();
-
- cc::CompositorFrameAck ack;
- RenderWidgetHostImpl::SendSwapCompositorFrameAck(
- render_widget_host_->GetRoutingID(),
- software_frame_manager_->GetCurrentFrameOutputSurfaceId(),
- render_widget_host_->GetProcess()->GetID(),
- ack);
- software_frame_manager_->SwapToNewFrameComplete(
- !render_widget_host_->is_hidden());
-
- // Notify observers, tab capture observers in particular, that a new
- // software frame has come in.
- NotificationService::current()->Notify(
- NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
- Source<RenderWidgetHost>(render_widget_host_),
- NotificationService::NoDetails());
} else {
DLOG(ERROR) << "Received unexpected frame type.";
RecordAction(
@@ -1800,10 +1441,6 @@ void RenderWidgetHostViewMac::OnSwapCompositorFrame(
}
}
-void RenderWidgetHostViewMac::AcceleratedSurfaceInitialized(int host_id,
- int route_id) {
-}
-
void RenderWidgetHostViewMac::GetScreenInfo(blink::WebScreenInfo* results) {
*results = GetWebScreenInfo(GetNativeView());
}
@@ -1823,7 +1460,7 @@ gfx::Rect RenderWidgetHostViewMac::GetBoundsInRootWindow() {
gfx::GLSurfaceHandle RenderWidgetHostViewMac::GetCompositingSurface() {
// TODO(kbr): may be able to eliminate PluginWindowHandle argument
// completely on Mac OS.
- return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NATIVE_TRANSPORT);
+ return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NULL_TRANSPORT);
}
bool RenderWidgetHostViewMac::LockMouse() {
@@ -1872,54 +1509,17 @@ bool RenderWidgetHostViewMac::Send(IPC::Message* message) {
return false;
}
-void RenderWidgetHostViewMac::SoftwareFrameWasFreed(
- uint32 output_surface_id, unsigned frame_id) {
- if (!render_widget_host_)
- return;
- cc::CompositorFrameAck ack;
- ack.last_software_frame_id = frame_id;
- RenderWidgetHostImpl::SendReclaimCompositorResources(
- render_widget_host_->GetRoutingID(),
- output_surface_id,
- render_widget_host_->GetProcess()->GetID(),
- ack);
-}
-
-void RenderWidgetHostViewMac::ReleaseReferencesToSoftwareFrame() {
- DestroySoftwareLayer();
-}
-
void RenderWidgetHostViewMac::ShutdownHost() {
weak_factory_.InvalidateWeakPtrs();
render_widget_host_->Shutdown();
// Do not touch any members at this point, |this| has been deleted.
}
-void RenderWidgetHostViewMac::GotAcceleratedFrame() {
- EnsureCompositedIOSurfaceLayer();
- SendVSyncParametersToRenderer();
-
- // Delete software backingstore and layer.
- software_frame_manager_->DiscardCurrentFrame();
- DestroySoftwareLayer();
-}
-
-void RenderWidgetHostViewMac::GotSoftwareFrame() {
- TRACE_EVENT0("browser", "RenderWidgetHostViewMac::GotSoftwareFrame");
-
- if (!render_widget_host_)
- return;
-
- EnsureSoftwareLayer();
- LayoutLayers();
- SendVSyncParametersToRenderer();
-
- // Draw the contents of the frame immediately. It is critical that this
- // happen before the frame be acked, otherwise the new frame will likely be
- // ready before the drawing is complete, thrashing the browser main thread.
- [software_layer_ displayIfNeeded];
-
- DestroyCompositedIOSurfaceAndLayer();
+void RenderWidgetHostViewMac::ShutdownBrowserCompositor() {
+ DestroyBrowserCompositorView();
+ delegated_frame_host_.reset();
+ root_layer_.reset();
+ browser_compositor_view_placeholder_.reset();
}
void RenderWidgetHostViewMac::SetActive(bool active) {
@@ -1960,22 +1560,26 @@ void RenderWidgetHostViewMac::ShowDefinitionForSelection() {
helper.ShowDefinitionForSelection();
}
-void RenderWidgetHostViewMac::SetBackgroundOpaque(bool opaque) {
- RenderWidgetHostViewBase::SetBackgroundOpaque(opaque);
+void RenderWidgetHostViewMac::SetBackgroundColor(SkColor color) {
+ RenderWidgetHostViewBase::SetBackgroundColor(color);
if (render_widget_host_)
- render_widget_host_->SetBackgroundOpaque(opaque);
-}
+ render_widget_host_->SetBackgroundOpaque(GetBackgroundOpaque());
-void RenderWidgetHostViewMac::CreateBrowserAccessibilityManagerIfNeeded() {
- if (!GetBrowserAccessibilityManager()) {
- SetBrowserAccessibilityManager(
- new BrowserAccessibilityManagerMac(
- cocoa_view_,
- BrowserAccessibilityManagerMac::GetEmptyDocument(),
- render_widget_host_));
+ if (background_layer_) {
+ [background_layer_
+ setBackgroundColor:gfx::CGColorCreateFromSkColor(background_color_)];
}
}
+BrowserAccessibilityManager*
+ RenderWidgetHostViewMac::CreateBrowserAccessibilityManager(
+ BrowserAccessibilityDelegate* delegate) {
+ return new BrowserAccessibilityManagerMac(
+ cocoa_view_,
+ BrowserAccessibilityManagerMac::GetEmptyDocument(),
+ delegate);
+}
+
gfx::Point RenderWidgetHostViewMac::AccessibilityOriginInScreen(
const gfx::Rect& bounds) {
NSPoint origin = NSMakePoint(bounds.x(), bounds.y());
@@ -1988,33 +1592,9 @@ gfx::Point RenderWidgetHostViewMac::AccessibilityOriginInScreen(
return gfx::Point(originInScreen.x, originInScreen.y);
}
-void RenderWidgetHostViewMac::OnAccessibilitySetFocus(int accObjId) {
- // Immediately set the focused item even though we have not officially set
- // focus on it as VoiceOver expects to get the focused item after this
- // method returns.
- BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager();
- if (manager)
- manager->SetFocus(manager->GetFromID(accObjId), false);
-}
-
-void RenderWidgetHostViewMac::AccessibilityShowMenu(int accObjId) {
- BrowserAccessibilityManager* manager = GetBrowserAccessibilityManager();
- if (!manager)
- return;
- BrowserAccessibilityCocoa* obj =
- manager->GetFromID(accObjId)->ToBrowserAccessibilityCocoa();
-
- // Performs a right click copying WebKit's
- // accessibilityPerformShowMenuAction.
- NSPoint objOrigin = [obj origin];
- NSSize size = [[obj size] sizeValue];
- gfx::Point origin = AccessibilityOriginInScreen(
- gfx::Rect(objOrigin.x, objOrigin.y, size.width, size.height));
- NSPoint location = NSMakePoint(origin.x(), origin.y());
+void RenderWidgetHostViewMac::AccessibilityShowMenu(const gfx::Point& point) {
+ NSPoint location = NSMakePoint(point.x(), point.y());
location = [[cocoa_view_ window] convertScreenToBase:location];
- location.x += size.width/2;
- location.y += size.height/2;
-
NSEvent* fakeRightClick = [NSEvent
mouseEventWithType:NSRightMouseDown
location:location
@@ -2029,8 +1609,6 @@ void RenderWidgetHostViewMac::AccessibilityShowMenu(int accObjId) {
[cocoa_view_ mouseEvent:fakeRightClick];
}
-
-
void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
if (active) {
if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD)
@@ -2052,159 +1630,48 @@ void RenderWidgetHostViewMac::OnStartPluginIme() {
[cocoa_view_ setPluginImeActive:YES];
}
-gfx::Rect RenderWidgetHostViewMac::GetScaledOpenGLPixelRect(
- const gfx::Rect& rect) {
- gfx::Rect src_gl_subrect = rect;
- src_gl_subrect.set_y(GetViewBounds().height() - rect.bottom());
-
- return gfx::ToEnclosingRect(gfx::ScaleRect(src_gl_subrect,
- ViewScaleFactor()));
-}
-
-void RenderWidgetHostViewMac::AddPendingLatencyInfo(
- const std::vector<ui::LatencyInfo>& latency_info) {
- for (size_t i = 0; i < latency_info.size(); i++) {
- pending_latency_info_.push_back(latency_info[i]);
- }
-}
-
-void RenderWidgetHostViewMac::SendPendingLatencyInfoToHost() {
- for (size_t i = 0; i < pending_latency_info_.size(); i++) {
- pending_latency_info_[i].AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
- render_widget_host_->FrameSwapped(pending_latency_info_[i]);
- }
- pending_latency_info_.clear();
-}
-
-void RenderWidgetHostViewMac::AddPendingSwapAck(
- int32 route_id, int gpu_host_id, int32 renderer_id) {
- // Note that multiple un-acked swaps can come in the event of a GPU process
- // loss. Drop the old acks.
- pending_swap_ack_.reset(new PendingSwapAck(
- route_id, gpu_host_id, renderer_id));
-}
-
-void RenderWidgetHostViewMac::SendPendingSwapAck() {
- if (!pending_swap_ack_)
- return;
-
- AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
- ack_params.sync_point = 0;
- ack_params.renderer_id = pending_swap_ack_->renderer_id;
- RenderWidgetHostImpl::AcknowledgeBufferPresent(pending_swap_ack_->route_id,
- pending_swap_ack_->gpu_host_id,
- ack_params);
- pending_swap_ack_.reset();
+void RenderWidgetHostViewMac::OnGetRenderedTextCompleted(
+ const std::string& text) {
+ SpeakText(text);
}
void RenderWidgetHostViewMac::PauseForPendingResizeOrRepaintsAndDraw() {
if (!render_widget_host_ || render_widget_host_->is_hidden())
return;
- // Pausing for the overlay/underlay view prevents the other one from receiving
- // frames. This may lead to large delays, causing overlaps.
- // See crbug.com/352020.
- if (underlay_view_ || overlay_view_)
+ // Pausing for one view prevents others from receiving frames.
+ // This may lead to large delays, causing overlaps. See crbug.com/352020.
+ if (!allow_pause_for_resize_or_repaint_)
return;
- // Ensure that all frames are acked before waiting for a frame to come in.
- // Note that we will draw a frame at the end of this function, so it is safe
- // to ack a never-drawn frame here.
- SendPendingSwapAck();
-
// Wait for a frame of the right size to come in.
+ if (browser_compositor_view_)
+ browser_compositor_view_->BeginPumpingFrames();
render_widget_host_->PauseForPendingResizeOrRepaints();
-
- // Immediately draw any frames that haven't been drawn yet. This is necessary
- // to keep the window and the window's contents in sync.
- [cocoa_view_ displayIfNeeded];
- [software_layer_ displayIfNeeded];
- [compositing_iosurface_layer_ displayIfNeededAndAck];
+ if (browser_compositor_view_)
+ browser_compositor_view_->EndPumpingFrames();
}
-void RenderWidgetHostViewMac::LayoutLayers() {
- if (browser_compositor_view_) {
- [browser_compositor_view_ layoutLayers];
- return;
- }
-
- // Disable animation of the layer's resizing or change in contents scale.
- ScopedCAActionDisabler disabler;
-
- CGRect new_background_frame = NSRectToCGRect([cocoa_view() bounds]);
+SkColorType RenderWidgetHostViewMac::PreferredReadbackFormat() {
+ return kN32_SkColorType;
+}
- // Dynamically calling setContentsScale on a CAOpenGLLayer for which
- // setAsynchronous is dynamically toggled can result in flashes of corrupt
- // content. Work around this by replacing the entire layer when the scale
- // factor changes.
- if (compositing_iosurface_ &&
- [compositing_iosurface_layer_
- respondsToSelector:(@selector(contentsScale))]) {
- if (compositing_iosurface_->scale_factor() !=
- [compositing_iosurface_layer_ contentsScale]) {
- DestroyCompositedIOSurfaceLayer(kRemoveLayerFromHierarchy);
- EnsureCompositedIOSurfaceLayer();
- }
- }
- if (compositing_iosurface_ &&
- compositing_iosurface_->HasIOSurface() &&
- compositing_iosurface_layer_) {
- CGRect layer_bounds = CGRectMake(
- 0,
- 0,
- compositing_iosurface_->dip_io_surface_size().width(),
- compositing_iosurface_->dip_io_surface_size().height());
- CGPoint layer_position = CGPointMake(
- 0,
- CGRectGetHeight(new_background_frame) - CGRectGetHeight(layer_bounds));
- bool bounds_changed = !CGRectEqualToRect(
- layer_bounds, [compositing_iosurface_layer_ bounds]);
- [compositing_iosurface_layer_ setPosition:layer_position];
- [compositing_iosurface_layer_ setBounds:layer_bounds];
-
- // If the bounds changed, then draw the frame immediately, to ensure that
- // content displayed is in sync with the window size.
- if (bounds_changed) {
- // Also, sometimes, especially when infobars are being removed, the
- // setNeedsDisplay calls are dropped on the floor, and stale content is
- // displayed. Calling displayIfNeeded will ensure that the right size
- // frame is drawn to the screen.
- // http://crbug.com/350817
- // Workaround for crbug.com/395827
- if ([compositing_iosurface_layer_ isAsynchronous])
- [compositing_iosurface_layer_ setAsynchronous:NO];
- [compositing_iosurface_layer_ setNeedsDisplayAndDisplayAndAck];
- }
- }
+////////////////////////////////////////////////////////////////////////////////
+// gfx::DisplayObserver, public:
- // Changing the software layer's bounds and position doesn't always result
- // in the layer being anchored to the top-left. Set the layer's frame
- // explicitly, since this is more reliable in practice.
- if (software_layer_) {
- bool frame_changed = !CGRectEqualToRect(
- new_background_frame, [software_layer_ frame]);
- if (frame_changed) {
- [software_layer_ setFrame:new_background_frame];
- }
- }
+void RenderWidgetHostViewMac::OnDisplayAdded(const gfx::Display& display) {
}
-SkBitmap::Config RenderWidgetHostViewMac::PreferredReadbackFormat() {
- return SkBitmap::kARGB_8888_Config;
+void RenderWidgetHostViewMac::OnDisplayRemoved(const gfx::Display& display) {
}
-////////////////////////////////////////////////////////////////////////////////
-// CompositingIOSurfaceLayerClient, public:
-
-void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
- if (!render_widget_host_)
+void RenderWidgetHostViewMac::OnDisplayMetricsChanged(
+ const gfx::Display& display, uint32_t metrics) {
+ gfx::Screen* screen = gfx::Screen::GetScreenFor(cocoa_view_);
+ if (display.id() != screen->GetDisplayNearestWindow(cocoa_view_).id())
return;
- SendPendingLatencyInfoToHost();
- SendPendingSwapAck();
- if (!succeeded)
- GotAcceleratedCompositingError();
+ UpdateScreenInfo(cocoa_view_);
}
} // namespace content
@@ -2226,15 +1693,12 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
renderWidgetHostView_.reset(r);
canBeKeyView_ = YES;
focusedPluginIdentifier_ = -1;
- renderWidgetHostView_->backing_store_scale_factor_ =
- ui::GetScaleFactorForNativeView(self);
// OpenGL support:
if ([self respondsToSelector:
@selector(setWantsBestResolutionOpenGLSurface:)]) {
[self setWantsBestResolutionOpenGLSurface:YES];
}
- handlingGlobalFrameDidChange_ = NO;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(didChangeScreenParameters:)
@@ -2245,13 +1709,6 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
}
- (void)dealloc {
- // Unbind the GL context from this view. If this is not done before super's
- // dealloc is called then the GL context will crash when it reaches into
- // the view in its destructor.
- // http://crbug.com/255608
- if (renderWidgetHostView_)
- renderWidgetHostView_->AcceleratedSurfaceRelease();
-
if (responderDelegate_ &&
[responderDelegate_ respondsToSelector:@selector(viewGone:)])
[responderDelegate_ viewGone:self];
@@ -2319,10 +1776,6 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
return [self acceptsMouseEventsWhenInactive];
}
-- (void)setTakesFocusOnlyOnMouseDown:(BOOL)b {
- takesFocusOnlyOnMouseDown_ = b;
-}
-
- (void)setCloseOnDeactivate:(BOOL)b {
closeOnDeactivate_ = b;
}
@@ -2403,16 +1856,6 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
}
mouseEventWasIgnored_ = NO;
- // TODO(rohitrao): Probably need to handle other mouse down events here.
- if ([theEvent type] == NSLeftMouseDown && takesFocusOnlyOnMouseDown_) {
- if (renderWidgetHostView_->render_widget_host_)
- renderWidgetHostView_->render_widget_host_->OnPointerEventActivate();
-
- // Manually take focus after the click but before forwarding it to the
- // renderer.
- [[self window] makeFirstResponder:self];
- }
-
// Don't cancel child popups; killing them on a mouse click would prevent the
// user from positioning the insertion point in the text field spawning the
// popup. A click outside the text field would cause the text field to drop
@@ -2449,6 +1892,10 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
if ([[self window] firstResponder] != self)
return NO;
+ // If the event is reserved by the system, then do not pass it to web content.
+ if (EventIsReservedBySystem(theEvent))
+ return NO;
+
// If we return |NO| from this function, cocoa will send the key event to
// the menu and only if the menu does not process the event to |keyDown:|. We
// want to send the event to a renderer _before_ sending it to the menu, so
@@ -2496,6 +1943,19 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
- (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv {
TRACE_EVENT0("browser", "RenderWidgetHostViewCocoa::keyEvent");
+
+ // If the user changes the system hotkey mapping after Chrome has been
+ // launched, then it is possible that a formerly reserved system hotkey is no
+ // longer reserved. The hotkey would have skipped the renderer, but would
+ // also have not been handled by the system. If this is the case, immediately
+ // return.
+ // TODO(erikchen): SystemHotkeyHelperMac should use the File System Events
+ // api to monitor changes to system hotkeys. This logic will have to be
+ // updated.
+ // http://crbug.com/383558.
+ if (EventIsReservedBySystem(theEvent))
+ return;
+
DCHECK([theEvent type] != NSKeyDown ||
!equiv == !([theEvent modifierFlags] & NSCommandKeyMask));
@@ -2931,11 +2391,6 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
if (!renderWidgetHostView_->render_widget_host_)
return;
- // Move the CALayers to their positions in the new view size. Note that
- // this will not draw anything because the non-background layers' sizes
- // didn't actually change.
- renderWidgetHostView_->LayoutLayers();
-
renderWidgetHostView_->render_widget_host_->SendScreenRects();
renderWidgetHostView_->render_widget_host_->WasResized();
if (renderWidgetHostView_->delegated_frame_host_)
@@ -2959,7 +2414,7 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
if (!renderWidgetHostView_->render_widget_host_)
return NO;
- return canBeKeyView_ && !takesFocusOnlyOnMouseDown_;
+ return canBeKeyView_;
}
- (BOOL)becomeFirstResponder {
@@ -3077,7 +2532,7 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
- (id)accessibilityAttributeValue:(NSString *)attribute {
BrowserAccessibilityManager* manager =
- renderWidgetHostView_->GetBrowserAccessibilityManager();
+ renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
// Contents specifies document view of RenderWidgetHostViewCocoa provided by
// BrowserAccessibilityManager. Children includes all subviews in addition to
@@ -3102,25 +2557,28 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
}
- (id)accessibilityHitTest:(NSPoint)point {
- if (!renderWidgetHostView_->GetBrowserAccessibilityManager())
+ BrowserAccessibilityManager* manager =
+ renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
+ if (!manager)
return self;
NSPoint pointInWindow = [[self window] convertScreenToBase:point];
NSPoint localPoint = [self convertPoint:pointInWindow fromView:nil];
localPoint.y = NSHeight([self bounds]) - localPoint.y;
- BrowserAccessibilityCocoa* root = renderWidgetHostView_->
- GetBrowserAccessibilityManager()->
- GetRoot()->ToBrowserAccessibilityCocoa();
+ BrowserAccessibilityCocoa* root =
+ manager->GetRoot()->ToBrowserAccessibilityCocoa();
id obj = [root accessibilityHitTest:localPoint];
return obj;
}
- (BOOL)accessibilityIsIgnored {
- return !renderWidgetHostView_->GetBrowserAccessibilityManager();
+ BrowserAccessibilityManager* manager =
+ renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
+ return !manager;
}
- (NSUInteger)accessibilityGetIndexOf:(id)child {
BrowserAccessibilityManager* manager =
- renderWidgetHostView_->GetBrowserAccessibilityManager();
+ renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
// Only child is root.
if (manager &&
manager->GetRoot()->ToBrowserAccessibilityCocoa() == child) {
@@ -3132,7 +2590,7 @@ void RenderWidgetHostViewMac::AcceleratedLayerDidDrawFrame(bool succeeded) {
- (id)accessibilityFocusedUIElement {
BrowserAccessibilityManager* manager =
- renderWidgetHostView_->GetBrowserAccessibilityManager();
+ renderWidgetHostView_->GetHost()->GetRootBrowserAccessibilityManager();
if (manager) {
BrowserAccessibility* focused_item = manager->GetFocus(NULL);
DCHECK(focused_item);
@@ -3627,8 +3085,13 @@ extern NSString *NSTextInputReplacementRangeAttributeName;
}
- (void)viewDidMoveToWindow {
- if ([self window])
+ if ([self window]) {
[self updateScreenProperties];
+ } else {
+ // If the RenderWidgetHostViewCocoa is being removed from its window, tear
+ // down its browser compositor resources, if needed.
+ renderWidgetHostView_->DestroySuspendedBrowserCompositorViewIfNeeded();
+ }
if (canBeKeyView_) {
NSWindow* newWindow = [self window];
diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm b/chromium/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
index 94f499e7c32..6ecb6698d52 100644
--- a/chromium/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
+++ b/chromium/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
@@ -8,6 +8,8 @@
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/message_loop/message_loop.h"
+#include "content/browser/compositor/test/no_transport_image_transport_factory.h"
+#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/input_messages.h"
@@ -70,7 +72,7 @@ bool CheckObjectRespondsToEditCommands(NSArray* edit_commands, id test_obj) {
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
MockRenderWidgetHostDelegate() {}
- virtual ~MockRenderWidgetHostDelegate() {}
+ ~MockRenderWidgetHostDelegate() override {}
};
// Create a RenderWidget for which we can filter messages.
@@ -84,7 +86,7 @@ class RenderWidgetHostEditCommandCounter : public RenderWidgetHostImpl {
edit_command_message_count_(0) {
}
- virtual bool Send(IPC::Message* message) OVERRIDE {
+ bool Send(IPC::Message* message) override {
if (message->type() == InputMsg_ExecuteEditCommand::ID)
edit_command_message_count_++;
return RenderWidgetHostImpl::Send(message);
@@ -94,6 +96,18 @@ class RenderWidgetHostEditCommandCounter : public RenderWidgetHostImpl {
};
class RenderWidgetHostViewMacEditCommandHelperTest : public PlatformTest {
+ protected:
+ virtual void SetUp() {
+ if (IsDelegatedRendererEnabled()) {
+ ImageTransportFactory::InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactory>(
+ new NoTransportImageTransportFactory));
+ }
+ }
+ virtual void TearDown() {
+ if (IsDelegatedRendererEnabled())
+ ImageTransportFactory::Terminate();
+ }
};
} // namespace
@@ -119,7 +133,7 @@ TEST_F(RenderWidgetHostViewMacEditCommandHelperTest,
// Owned by its |cocoa_view()|, i.e. |rwhv_cocoa|.
RenderWidgetHostViewMac* rwhv_mac = new RenderWidgetHostViewMac(
- render_widget);
+ render_widget, false);
base::scoped_nsobject<RenderWidgetHostViewCocoa> rwhv_cocoa(
[rwhv_mac->cocoa_view() retain]);
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 da766eac4ad..685039aefcd 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
@@ -9,6 +9,9 @@
#include "base/mac/sdk_forward_declarations.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/browser_thread_impl.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/render_widget_host_delegate.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/input_messages.h"
@@ -88,7 +91,7 @@ namespace {
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
MockRenderWidgetHostDelegate() {}
- virtual ~MockRenderWidgetHostDelegate() {}
+ ~MockRenderWidgetHostDelegate() override {}
};
class MockRenderWidgetHostImpl : public RenderWidgetHostImpl {
@@ -165,6 +168,11 @@ class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
virtual void SetUp() {
RenderViewHostImplTestHarness::SetUp();
+ if (IsDelegatedRendererEnabled()) {
+ ImageTransportFactory::InitializeForUnitTests(
+ scoped_ptr<ImageTransportFactory>(
+ new NoTransportImageTransportFactory));
+ }
// TestRenderViewHost's destruction assumes that its view is a
// TestRenderWidgetHostView, so store its view and reset it back to the
@@ -172,21 +180,27 @@ class RenderWidgetHostViewMacTest : public RenderViewHostImplTestHarness {
old_rwhv_ = rvh()->GetView();
// Owned by its |cocoa_view()|, i.e. |rwhv_cocoa_|.
- rwhv_mac_ = new RenderWidgetHostViewMac(rvh());
+ rwhv_mac_ = new RenderWidgetHostViewMac(rvh(), false);
rwhv_cocoa_.reset([rwhv_mac_->cocoa_view() retain]);
}
virtual void TearDown() {
// Make sure the rwhv_mac_ is gone once the superclass's |TearDown()| runs.
rwhv_cocoa_.reset();
- pool_.Recycle();
- base::MessageLoop::current()->RunUntilIdle();
- pool_.Recycle();
+ RecycleAndWait();
// See comment in SetUp().
test_rvh()->SetView(static_cast<RenderWidgetHostViewBase*>(old_rwhv_));
+ if (IsDelegatedRendererEnabled())
+ ImageTransportFactory::Terminate();
RenderViewHostImplTestHarness::TearDown();
}
+
+ void RecycleAndWait() {
+ pool_.Recycle();
+ base::MessageLoop::current()->RunUntilIdle();
+ pool_.Recycle();
+ }
protected:
private:
// This class isn't derived from PlatformTest.
@@ -208,34 +222,6 @@ TEST_F(RenderWidgetHostViewMacTest, Basic) {
TEST_F(RenderWidgetHostViewMacTest, AcceptsFirstResponder) {
// The RWHVCocoa should normally accept first responder status.
EXPECT_TRUE([rwhv_cocoa_.get() acceptsFirstResponder]);
-
- // Unless we tell it not to.
- rwhv_mac_->SetTakesFocusOnlyOnMouseDown(true);
- EXPECT_FALSE([rwhv_cocoa_.get() acceptsFirstResponder]);
-
- // But we can set things back to the way they were originally.
- rwhv_mac_->SetTakesFocusOnlyOnMouseDown(false);
- EXPECT_TRUE([rwhv_cocoa_.get() acceptsFirstResponder]);
-}
-
-TEST_F(RenderWidgetHostViewMacTest, TakesFocusOnMouseDown) {
- base::scoped_nsobject<CocoaTestHelperWindow> window(
- [[CocoaTestHelperWindow alloc] init]);
- [[window contentView] addSubview:rwhv_cocoa_.get()];
-
- // Even if the RWHVCocoa disallows first responder, clicking on it gives it
- // focus.
- [window setPretendIsKeyWindow:YES];
- [window makeFirstResponder:nil];
- ASSERT_NE(rwhv_cocoa_.get(), [window firstResponder]);
-
- rwhv_mac_->SetTakesFocusOnlyOnMouseDown(true);
- EXPECT_FALSE([rwhv_cocoa_.get() acceptsFirstResponder]);
-
- std::pair<NSEvent*, NSEvent*> clicks =
- cocoa_test_event_utils::MouseClickInView(rwhv_cocoa_.get(), 1);
- [rwhv_cocoa_.get() mouseDown:clicks.first];
- EXPECT_EQ(rwhv_cocoa_.get(), [window firstResponder]);
}
TEST_F(RenderWidgetHostViewMacTest, Fullscreen) {
@@ -259,7 +245,7 @@ TEST_F(RenderWidgetHostViewMacTest, FullscreenCloseOnEscape) {
// Owned by its |cocoa_view()|.
RenderWidgetHostImpl* rwh = new RenderWidgetHostImpl(
&delegate, process_host, MSG_ROUTING_NONE, false);
- RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(rwh);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(rwh, false);
view->InitAsFullscreen(rwhv_mac_);
@@ -292,7 +278,7 @@ TEST_F(RenderWidgetHostViewMacTest, AcceleratorDestroy) {
// Owned by its |cocoa_view()|.
RenderWidgetHostImpl* rwh = new RenderWidgetHostImpl(
&delegate, process_host, MSG_ROUTING_NONE, false);
- RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(rwh);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(rwh, false);
view->InitAsFullscreen(rwhv_mac_);
@@ -646,7 +632,7 @@ TEST_F(RenderWidgetHostViewMacTest, BlurAndFocusOnSetActive) {
// Owned by its |cocoa_view()|.
MockRenderWidgetHostImpl* rwh = new MockRenderWidgetHostImpl(
&delegate, process_host, MSG_ROUTING_NONE);
- RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(rwh);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(rwh, false);
base::scoped_nsobject<CocoaTestHelperWindow> window(
[[CocoaTestHelperWindow alloc] init]);
@@ -692,7 +678,7 @@ TEST_F(RenderWidgetHostViewMacTest, ScrollWheelEndEventDelivery) {
MockRenderWidgetHostDelegate delegate;
MockRenderWidgetHostImpl* host = new MockRenderWidgetHostImpl(
&delegate, process_host, MSG_ROUTING_NONE);
- RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
// Send an initial wheel event with NSEventPhaseBegan to the view.
NSEvent* event1 = MockScrollWheelEventWithPhase(@selector(phaseBegan), 0);
@@ -732,7 +718,7 @@ TEST_F(RenderWidgetHostViewMacTest, IgnoreEmptyUnhandledWheelEvent) {
MockRenderWidgetHostDelegate delegate;
MockRenderWidgetHostImpl* host = new MockRenderWidgetHostImpl(
&delegate, process_host, MSG_ROUTING_NONE);
- RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(host, false);
// Add a delegate to the view.
base::scoped_nsobject<MockRenderWidgetHostViewMacDelegate> view_delegate(
@@ -774,4 +760,45 @@ TEST_F(RenderWidgetHostViewMacTest, IgnoreEmptyUnhandledWheelEvent) {
host->Shutdown();
}
+// 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) {
+ MockRenderWidgetHostDelegate delegate;
+ TestBrowserContext browser_context;
+ MockRenderProcessHost* process_host =
+ new MockRenderProcessHost(&browser_context);
+
+ // Owned by its |cocoa_view()|.
+ MockRenderWidgetHostImpl* rwh = new MockRenderWidgetHostImpl(
+ &delegate, process_host, MSG_ROUTING_NONE);
+ RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(rwh, true);
+
+ // Add a delegate to the view.
+ base::scoped_nsobject<MockRenderWidgetHostViewMacDelegate> view_delegate(
+ [[MockRenderWidgetHostViewMacDelegate alloc] init]);
+ view->SetDelegate(view_delegate.get());
+
+ base::WeakPtr<RenderWidgetHostViewBase> guest_rwhv_weak =
+ (new RenderWidgetHostViewGuest(
+ rwh, NULL, view->GetWeakPtr()))->GetWeakPtr();
+
+ // Remove the cocoa_view() so |view| also goes away before |rwh|.
+ {
+ base::scoped_nsobject<RenderWidgetHostViewCocoa> rwhv_cocoa;
+ rwhv_cocoa.reset([view->cocoa_view() retain]);
+ }
+ RecycleAndWait();
+
+ // Clean up.
+ rwh->Shutdown();
+
+ // Let |guest_rwhv_weak| have a chance to delete itself.
+ base::RunLoop run_loop;
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE, run_loop.QuitClosure());
+ run_loop.Run();
+
+ ASSERT_FALSE(guest_rwhv_weak.get());
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/render_widget_resize_helper.cc b/chromium/content/browser/renderer_host/render_widget_resize_helper.cc
new file mode 100644
index 00000000000..3cc329d71ee
--- /dev/null
+++ b/chromium/content/browser/renderer_host/render_widget_resize_helper.cc
@@ -0,0 +1,356 @@
+// 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/renderer_host/render_widget_resize_helper.h"
+
+#include <list>
+
+#include "content/browser/gpu/gpu_process_host_ui_shim.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+namespace {
+
+class WrappedTask;
+class PumpableTaskRunner;
+typedef std::list<WrappedTask*> WrappedTaskQueue;
+typedef base::Callback<void(base::WaitableEvent*, base::TimeDelta)>
+ EventTimedWaitCallback;
+
+// A wrapper for IPCs and tasks that we may potentially execute in
+// WaitForSingleTaskToRun. Because these tasks are sent to two places to run,
+// we to wrap them in this structure and track whether or not they have run
+// yet, to avoid running them twice.
+class WrappedTask {
+ public:
+ WrappedTask(
+ const base::Closure& closure,
+ base::TimeDelta delay);
+ ~WrappedTask();
+ bool ShouldRunBefore(const WrappedTask& other);
+ void Run();
+ void AddToTaskRunnerQueue(PumpableTaskRunner* pumpable_task_runner);
+ void RemoveFromTaskRunnerQueue();
+ const base::TimeTicks& can_run_time() const { return can_run_time_; }
+
+ private:
+ base::Closure closure_;
+ base::TimeTicks can_run_time_;
+ bool has_run_;
+ uint64 sequence_number_;
+ WrappedTaskQueue::iterator iterator_;
+
+ // Back pointer to the pumpable task runner that this task is enqueued in.
+ scoped_refptr<PumpableTaskRunner> pumpable_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(WrappedTask);
+};
+
+// The PumpableTaskRunner is a task runner that will wrap tasks in an
+// WrappedTask, enqueues that wrapped task in the queue to be pumped via
+// WaitForSingleWrappedTaskToRun during resizes, and posts the task to a
+// target task runner. The posted task will run only once, either through a
+// WaitForSingleWrappedTaskToRun call or through the target task runner.
+class PumpableTaskRunner
+ : public base::SingleThreadTaskRunner {
+ public:
+ explicit PumpableTaskRunner(
+ const EventTimedWaitCallback& event_timed_wait_callback);
+
+ // Enqueue WrappedTask and post it to |target_task_runner_|.
+ bool EnqueueAndPostWrappedTask(
+ const tracked_objects::Location& from_here,
+ WrappedTask* task,
+ base::TimeDelta delay);
+
+ // Wait at most |max_delay| to run an enqueued task.
+ bool WaitForSingleWrappedTaskToRun(const base::TimeDelta& max_delay);
+
+ // Remove a wrapped task from the queue.
+ void RemoveWrappedTaskFromQueue(WrappedTask* task);
+
+ // base::SingleThreadTaskRunner implementation:
+ bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override;
+
+ bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) override;
+
+ bool RunsTasksOnCurrentThread() const override;
+
+ private:
+ friend class WrappedTask;
+
+ ~PumpableTaskRunner() override;
+
+ // A queue of live messages. Must hold |task_queue_lock_| to access. Tasks
+ // are added only on the IO thread and removed only on the UI thread. The
+ // WrappedTask objects are removed from the queue when they are run (by
+ // |target_task_runner_| or by a call to WaitForSingleWrappedTaskToRun
+ // removing them out of the queue, or by TaskRunner when it is destroyed).
+ WrappedTaskQueue task_queue_;
+ base::Lock task_queue_lock_;
+
+ // Event used to wake up the UI thread if it is sleeping in
+ // WaitForSingleTaskToRun.
+ base::WaitableEvent event_;
+
+ // Callback to call TimedWait on |event_| from an appropriate class.
+ EventTimedWaitCallback event_timed_wait_callback_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(PumpableTaskRunner);
+};
+
+void HandleGpuIPC(int gpu_host_id, const IPC::Message& message) {
+ GpuProcessHostUIShim* host = GpuProcessHostUIShim::FromID(gpu_host_id);
+ if (host)
+ host->OnMessageReceived(message);
+}
+
+void HandleRendererIPC(int render_process_id, const IPC::Message& message) {
+ RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
+ if (host)
+ host->OnMessageReceived(message);
+}
+
+base::LazyInstance<RenderWidgetResizeHelper> g_render_widget_task_runner =
+ LAZY_INSTANCE_INITIALIZER;
+
+////////////////////////////////////////////////////////////////////////////////
+// WrappedTask
+
+WrappedTask::WrappedTask(
+ const base::Closure& closure,
+ base::TimeDelta delay)
+ : closure_(closure),
+ can_run_time_(base::TimeTicks::Now() + delay),
+ has_run_(false),
+ sequence_number_(0) {
+}
+
+WrappedTask::~WrappedTask() {
+ RemoveFromTaskRunnerQueue();
+}
+
+bool WrappedTask::ShouldRunBefore(const WrappedTask& other) {
+ if (can_run_time_ < other.can_run_time_)
+ return true;
+ if (can_run_time_ > other.can_run_time_)
+ return false;
+ if (sequence_number_ < other.sequence_number_)
+ return true;
+ if (sequence_number_ > other.sequence_number_)
+ return false;
+ // Sequence numbers are unique, so this should never happen.
+ NOTREACHED();
+ return false;
+}
+
+void WrappedTask::Run() {
+ if (has_run_)
+ return;
+ RemoveFromTaskRunnerQueue();
+ has_run_ = true;
+ closure_.Run();
+}
+
+void WrappedTask::AddToTaskRunnerQueue(
+ PumpableTaskRunner* pumpable_task_runner) {
+ pumpable_task_runner_ = pumpable_task_runner;
+ base::AutoLock lock(pumpable_task_runner_->task_queue_lock_);
+ static uint64 last_sequence_number = 0;
+ last_sequence_number += 1;
+ sequence_number_ = last_sequence_number;
+ iterator_ = pumpable_task_runner_->task_queue_.insert(
+ pumpable_task_runner_->task_queue_.end(), this);
+}
+
+void WrappedTask::RemoveFromTaskRunnerQueue() {
+ if (!pumpable_task_runner_.get())
+ return;
+ // The scope of the task runner's lock must be limited because removing
+ // this reference to the task runner may destroy it.
+ {
+ base::AutoLock lock(pumpable_task_runner_->task_queue_lock_);
+ pumpable_task_runner_->task_queue_.erase(iterator_);
+ iterator_ = pumpable_task_runner_->task_queue_.end();
+ }
+ pumpable_task_runner_ = NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PumpableTaskRunner
+
+PumpableTaskRunner::PumpableTaskRunner(
+ const EventTimedWaitCallback& event_timed_wait_callback)
+ : event_(false /* auto-reset */, false /* initially signalled */),
+ event_timed_wait_callback_(event_timed_wait_callback),
+ target_task_runner_(BrowserThread::GetMessageLoopProxyForThread(
+ BrowserThread::UI)) {}
+
+PumpableTaskRunner::~PumpableTaskRunner() {
+ // Because tasks hold a reference to the task runner, the task queue must
+ // be empty when it is destroyed.
+ DCHECK(task_queue_.empty());
+}
+
+bool PumpableTaskRunner::WaitForSingleWrappedTaskToRun(
+ const base::TimeDelta& max_delay) {
+ base::TimeTicks stop_waiting_time = base::TimeTicks::Now() + max_delay;
+
+ for (;;) {
+ base::TimeTicks current_time = base::TimeTicks::Now();
+ base::TimeTicks next_task_time = stop_waiting_time;
+
+ // Find the first task to execute in the list. This lookup takes O(n) time,
+ // but n is rarely more than 2, and has never been observed to be more than
+ // 12.
+ WrappedTask* task_to_execute = NULL;
+ {
+ base::AutoLock lock(task_queue_lock_);
+
+ for (WrappedTaskQueue::iterator it = task_queue_.begin(); it !=
+ task_queue_.end(); ++it) {
+ WrappedTask* potential_task = *it;
+
+ // If this task is scheduled for the future, take it into account when
+ // deciding how long to sleep, and continue on to the next task.
+ if (potential_task->can_run_time() > current_time) {
+ if (potential_task->can_run_time() < next_task_time)
+ next_task_time = potential_task->can_run_time();
+ continue;
+ }
+ // If there is a better candidate than this task, continue to the next
+ // task.
+ if (task_to_execute &&
+ task_to_execute->ShouldRunBefore(*potential_task)) {
+ continue;
+ }
+ task_to_execute = potential_task;
+ }
+ }
+
+ if (task_to_execute) {
+ task_to_execute->Run();
+ return true;
+ }
+
+ // Calculate how much time we have left before we have to stop waiting or
+ // until a currently-enqueued task will be ready to run.
+ base::TimeDelta max_sleep_time = next_task_time - current_time;
+ if (max_sleep_time <= base::TimeDelta::FromMilliseconds(0))
+ break;
+
+ event_timed_wait_callback_.Run(&event_, max_sleep_time);
+ }
+
+ return false;
+}
+
+bool PumpableTaskRunner::EnqueueAndPostWrappedTask(
+ const tracked_objects::Location& from_here,
+ WrappedTask* task,
+ base::TimeDelta delay) {
+ task->AddToTaskRunnerQueue(this);
+
+ // Notify anyone waiting on the UI thread that there is a new entry in the
+ // task map. If they don't find the entry they are looking for, then they
+ // will just continue waiting.
+ event_.Signal();
+
+ return target_task_runner_->PostDelayedTask(
+ from_here, base::Bind(&WrappedTask::Run, base::Owned(task)), delay);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PumpableTaskRunner, base::SingleThreadTaskRunner implementation:
+
+bool PumpableTaskRunner::PostDelayedTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) {
+ return EnqueueAndPostWrappedTask(
+ from_here,
+ new WrappedTask(task, delay),
+ delay);
+}
+
+bool PumpableTaskRunner::PostNonNestableDelayedTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) {
+ // The correctness of non-nestable events hasn't been proven for this
+ // structure.
+ NOTREACHED();
+ return false;
+}
+
+bool PumpableTaskRunner::RunsTasksOnCurrentThread() const {
+ return target_task_runner_->RunsTasksOnCurrentThread();
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// RenderWidgetResizeHelper
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ RenderWidgetResizeHelper::task_runner() const {
+ return task_runner_;
+}
+
+// static
+RenderWidgetResizeHelper* RenderWidgetResizeHelper::Get() {
+ return g_render_widget_task_runner.Pointer();
+}
+
+bool RenderWidgetResizeHelper::WaitForSingleTaskToRun(
+ const base::TimeDelta& max_delay) {
+ PumpableTaskRunner* pumpable_task_runner =
+ reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
+ return pumpable_task_runner->WaitForSingleWrappedTaskToRun(max_delay);
+}
+
+void RenderWidgetResizeHelper::PostRendererProcessMsg(
+ int render_process_id, const IPC::Message& msg) {
+ PumpableTaskRunner* pumpable_task_runner =
+ reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
+ pumpable_task_runner->EnqueueAndPostWrappedTask(
+ FROM_HERE,
+ new WrappedTask(base::Bind(HandleRendererIPC, render_process_id, msg),
+ base::TimeDelta()),
+ base::TimeDelta());
+}
+
+void RenderWidgetResizeHelper::PostGpuProcessMsg(
+ int gpu_host_id, const IPC::Message& msg) {
+ PumpableTaskRunner* pumpable_task_runner =
+ reinterpret_cast<PumpableTaskRunner*>(task_runner_.get());
+ pumpable_task_runner->EnqueueAndPostWrappedTask(
+ FROM_HERE,
+ new WrappedTask(base::Bind(HandleGpuIPC, gpu_host_id, msg),
+ base::TimeDelta()),
+ base::TimeDelta());
+}
+
+RenderWidgetResizeHelper::RenderWidgetResizeHelper() {
+ task_runner_ = new PumpableTaskRunner(base::Bind(&EventTimedWait));
+}
+
+RenderWidgetResizeHelper::~RenderWidgetResizeHelper() {}
+
+// static
+void RenderWidgetResizeHelper::EventTimedWait(
+ base::WaitableEvent* event, base::TimeDelta delay) {
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
+ event->TimedWait(delay);
+}
+
+} // namespace content
+
diff --git a/chromium/content/browser/renderer_host/render_widget_resize_helper.h b/chromium/content/browser/renderer_host/render_widget_resize_helper.h
new file mode 100644
index 00000000000..92e2cd2676e
--- /dev/null
+++ b/chromium/content/browser/renderer_host/render_widget_resize_helper.h
@@ -0,0 +1,92 @@
+// 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_RENDERER_HOST_RENDER_WIDGET_RESIZE_HELPER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_RESIZE_HELPER_H_
+
+#include "base/lazy_instance.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "ipc/ipc_message.h"
+
+namespace content {
+
+// RenderWidgetResizeHelper is used to make resize appear smooth. That is to
+// say, make sure that the window size and the size of the content being drawn
+// in that window are resized in lock-step. This is accomplished by waiting
+// inside -[RenderWidgetHostViewCocoa setFrameSize:] for the renderer (and
+// potentially browser compositor as well) to produce a frame of same size
+// as the RenderWidgetHostViewCocoa.
+//
+// The function of waiting for a frame of the correct size is done inside
+// RenderWidgetHostImpl::WaitForSurface. That function will call
+// RenderWidgetResizeHelper::WaitForSingleTaskToRun until a timeout occurs,
+// or the corresponding RenderWidgetHostViewCocoa has a renderer frame of the
+// same size as its NSView.
+//
+// This is somewhat complicated because waiting for frames requires that
+// that the browser handle the IPCs (from the renderer and the GPU processes)
+// that are required to pick up a new frame. In the ordinary run of things
+// (ignoring RenderWidgetResizeHelper), those IPCs arrive on the IO thread
+// and are posted as tasks to the UI thread either by the RenderMessageFilter
+// (for renderer processes) or the GpuProcessHostUIShim (for the GPU process).
+// The IPCs that are required to create new frames for smooth resize are sent
+// to the RenderWidgetResizeHelper using the PostRendererProcessMsg and
+// PostGpuProcessMsg methods. These functions will post them as tasks to the UI
+// thread (as usual), and will also enqueue them into a queue which will be
+// read and run in RenderWidgetResizeHelper::WaitForSingleTaskToRun, potentially
+// before the task posted to the UI thread is run. Some care is taken (see
+// WrappedTask) to make sure that the messages are only executed once.
+//
+// This is further complicated because, in order for a frame to appear, it is
+// necessary to run tasks posted by the ui::Compositor. To accomplish this, the
+// RenderWidgetResizeHelper provides a base::SingleThreadTaskRunner which,
+// when a task is posted to it, enqueues the task in the aforementioned queue,
+// which may be pumped by RenderWidgetResizeHelper::WaitForSingleTaskToRun.
+//
+class RenderWidgetResizeHelper {
+ public:
+ static RenderWidgetResizeHelper* Get();
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner() const;
+
+ // UI THREAD ONLY -----------------------------------------------------------
+
+ // Waits at most |max_delay| for a task to run. Returns true if a task ran,
+ // false if no task ran.
+ bool WaitForSingleTaskToRun(const base::TimeDelta& max_delay);
+
+ // IO THREAD ONLY -----------------------------------------------------------
+
+ // This will cause |msg| to be handled by the RenderProcessHost corresponding
+ // to |render_process_id|, on the UI thread. This will either happen when the
+ // ordinary message loop would run it, or potentially earlier in a call to
+ // WaitForSingleTaskToRun .
+ void PostRendererProcessMsg(int render_process_id, const IPC::Message& msg);
+
+ // This is similar to PostRendererProcessMsg, but will handle the message in
+ // the GpuProcessHostUIShim corresponding to |gpu_host_id|.
+ void PostGpuProcessMsg(int gpu_host_id, const IPC::Message& msg);
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<RenderWidgetResizeHelper>;
+ RenderWidgetResizeHelper();
+ ~RenderWidgetResizeHelper();
+
+ // This helper is needed to create a ScopedAllowWait inside the scope of a
+ // class where it is allowed.
+ static void EventTimedWait(
+ base::WaitableEvent* event,
+ base::TimeDelta delay);
+
+ // The task runner to which the helper will post tasks. This also maintains
+ // the task queue and does the actual work for WaitForSingleTaskToRun.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetResizeHelper);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_RESIZE_HELPER_H_
diff --git a/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc b/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
index 7598bdbcc13..b2e024e1e8c 100644
--- a/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
+++ b/chromium/content/browser/renderer_host/sandbox_ipc_linux.cc
@@ -5,20 +5,22 @@
#include "content/browser/renderer_host/sandbox_ipc_linux.h"
#include <fcntl.h>
-#include <fontconfig/fontconfig.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/files/scoped_file.h"
#include "base/linux_util.h"
+#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/shared_memory.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket_linux.h"
#include "base/process/launch.h"
#include "base/strings/string_number_conversions.h"
+#include "content/browser/renderer_host/font_utils_linux.h"
#include "content/common/font_config_ipc_linux.h"
#include "content/common/sandbox_linux/sandbox_linux.h"
#include "content/common/set_process_title.h"
@@ -28,122 +30,52 @@
#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_render_params_linux.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/font_render_params.h"
using blink::WebCString;
using blink::WebFontInfo;
using blink::WebUChar;
using blink::WebUChar32;
+namespace content {
+
namespace {
-// MSCharSetToFontconfig translates a Microsoft charset identifier to a
-// fontconfig language set by appending to |langset|.
-// Returns true if |langset| is Latin/Greek/Cyrillic.
-bool MSCharSetToFontconfig(FcLangSet* langset, unsigned fdwCharSet) {
- // We have need to translate raw fdwCharSet values into terms that
- // fontconfig can understand. (See the description of fdwCharSet in the MSDN
- // documentation for CreateFont:
- // http://msdn.microsoft.com/en-us/library/dd183499(VS.85).aspx )
- //
- // Although the argument is /called/ 'charset', the actual values conflate
- // character sets (which are sets of Unicode code points) and character
- // encodings (which are algorithms for turning a series of bits into a
- // series of code points.) Sometimes the values will name a language,
- // sometimes they'll name an encoding. In the latter case I'm assuming that
- // they mean the set of code points in the domain of that encoding.
- //
- // fontconfig deals with ISO 639-1 language codes:
- // http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
- //
- // So, for each of the documented fdwCharSet values I've had to take a
- // guess at the set of ISO 639-1 languages intended.
-
- bool is_lgc = false;
- switch (fdwCharSet) {
- case NPCharsetAnsi:
- // 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:
- is_lgc = true;
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("en"));
- break;
- case NPCharsetBaltic:
- // 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:
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-tw"));
- break;
- case NPCharsetGB2312:
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-cn"));
- break;
- case NPCharsetEastEurope:
- // A scattering of eastern European languages.
- is_lgc = true;
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("pl"));
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("cs"));
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("sk"));
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hu"));
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hr"));
- break;
- case NPCharsetGreek:
- is_lgc = true;
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("el"));
- break;
- case NPCharsetHangul:
- case NPCharsetJohab:
- // Korean
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ko"));
- break;
- case NPCharsetRussian:
- is_lgc = true;
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ru"));
- break;
- case NPCharsetShiftJIS:
- // Japanese
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ja"));
- break;
- case NPCharsetTurkish:
- is_lgc = true;
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("tr"));
- break;
- case NPCharsetVietnamese:
- is_lgc = true;
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("vi"));
- break;
- case NPCharsetArabic:
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ar"));
- break;
- case NPCharsetHebrew:
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("he"));
- break;
- case NPCharsetThai:
- FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("th"));
- break;
- // default:
- // Don't add any languages in that case that we don't recognise the
- // constant.
+// Converts gfx::FontRenderParams::Hinting to WebFontRenderStyle::hintStyle.
+// Returns an int for serialization, but the underlying Blink type is a char.
+int ConvertHinting(gfx::FontRenderParams::Hinting hinting) {
+ switch (hinting) {
+ case gfx::FontRenderParams::HINTING_NONE: return 0;
+ case gfx::FontRenderParams::HINTING_SLIGHT: return 1;
+ case gfx::FontRenderParams::HINTING_MEDIUM: return 2;
+ case gfx::FontRenderParams::HINTING_FULL: return 3;
}
- return is_lgc;
+ NOTREACHED() << "Unexpected hinting value " << hinting;
+ return 0;
}
-} // namespace
+// Converts gfx::FontRenderParams::SubpixelRendering to
+// WebFontRenderStyle::useSubpixelRendering. Returns an int for serialization,
+// but the underlying Blink type is a char.
+int ConvertSubpixelRendering(
+ gfx::FontRenderParams::SubpixelRendering rendering) {
+ switch (rendering) {
+ case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE: return 0;
+ case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB: return 1;
+ case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR: return 1;
+ case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB: return 1;
+ case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR: return 1;
+ }
+ NOTREACHED() << "Unexpected subpixel rendering value " << rendering;
+ return 0;
+}
-namespace content {
+} // namespace
SandboxIPCHandler::SandboxIPCHandler(int lifeline_fd, int browser_socket)
- : lifeline_fd_(lifeline_fd), browser_socket_(browser_socket) {
- // FontConfig doesn't provide a standard property to control subpixel
- // positioning, so we pass the current setting through to WebKit.
- WebFontInfo::setSubpixelPositioning(
- gfx::GetDefaultWebkitSubpixelPositioning());
+ : lifeline_fd_(lifeline_fd),
+ browser_socket_(browser_socket) {
}
void SandboxIPCHandler::Run() {
@@ -331,6 +263,9 @@ void SandboxIPCHandler::HandleGetFallbackFontForChar(
blink::WebFallbackFont fallbackFont;
WebFontInfo::fallbackFontForChar(c, preferred_locale.c_str(), &fallbackFont);
+ int pathIndex = FindOrAddPath(SkString(fallbackFont.filename.data()));
+ fallbackFont.fontconfigInterfaceId = pathIndex;
+
Pickle reply;
if (fallbackFont.name.data()) {
reply.WriteString(fallbackFont.name.data());
@@ -342,6 +277,7 @@ void SandboxIPCHandler::HandleGetFallbackFontForChar(
} else {
reply.WriteString(std::string());
}
+ reply.WriteInt(fallbackFont.fontconfigInterfaceId);
reply.WriteInt(fallbackFont.ttcIndex);
reply.WriteBool(fallbackFont.isBold);
reply.WriteBool(fallbackFont.isItalic);
@@ -354,25 +290,35 @@ void SandboxIPCHandler::HandleGetStyleForStrike(
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
std::string family;
- int sizeAndStyle;
+ bool bold, italic;
+ uint16 pixel_size;
if (!pickle.ReadString(&iter, &family) ||
- !pickle.ReadInt(&iter, &sizeAndStyle)) {
+ !pickle.ReadBool(&iter, &bold) ||
+ !pickle.ReadBool(&iter, &italic) ||
+ !pickle.ReadUInt16(&iter, &pixel_size)) {
return;
}
EnsureWebKitInitialized();
- blink::WebFontRenderStyle style;
- WebFontInfo::renderStyleForStrike(family.c_str(), sizeAndStyle, &style);
+ gfx::FontRenderParamsQuery query(true);
+ query.families.push_back(family);
+ query.pixel_size = pixel_size;
+ query.style = gfx::Font::NORMAL |
+ (bold ? gfx::Font::BOLD : 0) | (italic ? gfx::Font::ITALIC : 0);
+ const gfx::FontRenderParams params = gfx::GetFontRenderParams(query, NULL);
+
+ // These are passed as ints since they're interpreted as tri-state chars in
+ // Blink.
Pickle reply;
- reply.WriteInt(style.useBitmaps);
- reply.WriteInt(style.useAutoHint);
- reply.WriteInt(style.useHinting);
- reply.WriteInt(style.hintStyle);
- reply.WriteInt(style.useAntiAlias);
- reply.WriteInt(style.useSubpixelRendering);
- reply.WriteInt(style.useSubpixelPositioning);
+ reply.WriteInt(params.use_bitmaps);
+ reply.WriteInt(params.autohinter);
+ reply.WriteInt(params.hinting != gfx::FontRenderParams::HINTING_NONE);
+ reply.WriteInt(ConvertHinting(params.hinting));
+ reply.WriteInt(params.antialiasing);
+ reply.WriteInt(ConvertSubpixelRendering(params.subpixel_rendering));
+ reply.WriteInt(params.subpixel_positioning);
SendRendererReply(fds, reply, -1);
}
@@ -435,10 +381,6 @@ void SandboxIPCHandler::HandleMatchWithFallback(
const Pickle& pickle,
PickleIterator iter,
const std::vector<base::ScopedFD*>& fds) {
- // Unlike the other calls, for which we are an indirection in front of
- // WebKit or Skia, this call is always made via this sandbox helper
- // process. Therefore the fontconfig code goes in here directly.
-
std::string face;
bool is_bold, is_italic;
uint32 charset, fallback_family;
@@ -451,138 +393,8 @@ void SandboxIPCHandler::HandleMatchWithFallback(
return;
}
- FcLangSet* langset = FcLangSetCreate();
- bool is_lgc = MSCharSetToFontconfig(langset, charset);
-
- FcPattern* pattern = FcPatternCreate();
- FcPatternAddString(
- pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(face.c_str()));
-
- // TODO(thestig) Check if we can access Chrome's per-script font preference
- // here and select better default fonts for non-LGC case.
- std::string generic_font_name;
- if (is_lgc) {
- switch (fallback_family) {
- case PP_BROWSERFONT_TRUSTED_FAMILY_SERIF:
- generic_font_name = "Times New Roman";
- break;
- case PP_BROWSERFONT_TRUSTED_FAMILY_SANSSERIF:
- generic_font_name = "Arial";
- break;
- case PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE:
- generic_font_name = "Courier New";
- break;
- }
- }
- if (!generic_font_name.empty()) {
- const FcChar8* fc_generic_font_name =
- reinterpret_cast<const FcChar8*>(generic_font_name.c_str());
- FcPatternAddString(pattern, FC_FAMILY, fc_generic_font_name);
- }
-
- if (is_bold)
- FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
- if (is_italic)
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
- FcPatternAddLangSet(pattern, FC_LANG, langset);
- FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
- FcConfigSubstitute(NULL, pattern, FcMatchPattern);
- FcDefaultSubstitute(pattern);
-
- FcResult result;
- FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
- int font_fd = -1;
- int good_enough_index = -1;
- bool good_enough_index_set = false;
-
- if (font_set) {
- for (int i = 0; i < font_set->nfont; ++i) {
- FcPattern* current = font_set->fonts[i];
-
- // Older versions of fontconfig have a bug where they cannot select
- // only scalable fonts so we have to manually filter the results.
- FcBool is_scalable;
- if (FcPatternGetBool(current, FC_SCALABLE, 0, &is_scalable) !=
- FcResultMatch ||
- !is_scalable) {
- continue;
- }
-
- FcChar8* c_filename;
- if (FcPatternGetString(current, FC_FILE, 0, &c_filename) !=
- FcResultMatch) {
- continue;
- }
-
- // We only want to return sfnt (TrueType) based fonts. We don't have a
- // very good way of detecting this so we'll filter based on the
- // filename.
- bool is_sfnt = false;
- static const char kSFNTExtensions[][5] = {".ttf", ".otc", ".TTF", ".ttc",
- ""};
- const size_t filename_len = strlen(reinterpret_cast<char*>(c_filename));
- for (unsigned j = 0;; j++) {
- if (kSFNTExtensions[j][0] == 0) {
- // None of the extensions matched.
- break;
- }
- const size_t ext_len = strlen(kSFNTExtensions[j]);
- if (filename_len > ext_len &&
- memcmp(c_filename + filename_len - ext_len,
- kSFNTExtensions[j],
- ext_len) == 0) {
- is_sfnt = true;
- break;
- }
- }
-
- if (!is_sfnt)
- continue;
-
- // This font is good enough to pass muster, but we might be able to do
- // better with subsequent ones.
- if (!good_enough_index_set) {
- good_enough_index = i;
- good_enough_index_set = true;
- }
-
- FcValue matrix;
- bool have_matrix = FcPatternGet(current, FC_MATRIX, 0, &matrix) == 0;
-
- if (is_italic && have_matrix) {
- // we asked for an italic font, but fontconfig is giving us a
- // non-italic font with a transformation matrix.
- continue;
- }
-
- FcValue embolden;
- const bool have_embolden =
- FcPatternGet(current, FC_EMBOLDEN, 0, &embolden) == 0;
-
- if (is_bold && have_embolden) {
- // we asked for a bold font, but fontconfig gave us a non-bold font
- // and asked us to apply fake bolding.
- continue;
- }
-
- font_fd = open(reinterpret_cast<char*>(c_filename), O_RDONLY);
- if (font_fd >= 0)
- break;
- }
- }
-
- if (font_fd == -1 && good_enough_index_set) {
- // We didn't find a font that we liked, so we fallback to something
- // acceptable.
- FcPattern* current = font_set->fonts[good_enough_index];
- FcChar8* c_filename;
- FcPatternGetString(current, FC_FILE, 0, &c_filename);
- font_fd = open(reinterpret_cast<char*>(c_filename), O_RDONLY);
- }
-
- if (font_set)
- FcFontSetDestroy(font_set);
- FcPatternDestroy(pattern);
+ int font_fd = MatchFontFaceWithFallback(
+ face, is_bold, is_italic, charset, fallback_family);
Pickle reply;
SendRendererReply(fds, reply, font_fd);
@@ -631,7 +443,7 @@ void SandboxIPCHandler::SendRendererReply(
SandboxIPCHandler::~SandboxIPCHandler() {
paths_.deleteAll();
- if (webkit_platform_support_)
+ if (blink_platform_impl_)
blink::shutdownWithoutV8();
if (IGNORE_EINTR(close(lifeline_fd_)) < 0)
@@ -641,10 +453,10 @@ SandboxIPCHandler::~SandboxIPCHandler() {
}
void SandboxIPCHandler::EnsureWebKitInitialized() {
- if (webkit_platform_support_)
+ if (blink_platform_impl_)
return;
- webkit_platform_support_.reset(new BlinkPlatformImpl);
- blink::initializeWithoutV8(webkit_platform_support_.get());
+ 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 fc986a6189c..e6ac19bbfac 100644
--- a/chromium/content/browser/renderer_host/sandbox_ipc_linux.h
+++ b/chromium/content/browser/renderer_host/sandbox_ipc_linux.h
@@ -24,9 +24,9 @@ class SandboxIPCHandler : public base::DelegateSimpleThread::Delegate {
// the other end of.
// browser_socket: the browser's end of the sandbox IPC socketpair.
SandboxIPCHandler(int lifeline_fd, int browser_socket);
- virtual ~SandboxIPCHandler();
+ ~SandboxIPCHandler() override;
- virtual void Run() OVERRIDE;
+ void Run() override;
private:
void EnsureWebKitInitialized();
@@ -76,7 +76,7 @@ class SandboxIPCHandler : public base::DelegateSimpleThread::Delegate {
const int lifeline_fd_;
const int browser_socket_;
- scoped_ptr<BlinkPlatformImpl> webkit_platform_support_;
+ scoped_ptr<BlinkPlatformImpl> blink_platform_impl_;
SkTDArray<SkString*> paths_;
DISALLOW_COPY_AND_ASSIGN(SandboxIPCHandler);
diff --git a/chromium/content/browser/renderer_host/socket_stream_dispatcher_host.cc b/chromium/content/browser/renderer_host/socket_stream_dispatcher_host.cc
deleted file mode 100644
index b08b119ed92..00000000000
--- a/chromium/content/browser/renderer_host/socket_stream_dispatcher_host.cc
+++ /dev/null
@@ -1,307 +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/renderer_host/socket_stream_dispatcher_host.h"
-
-#include <string>
-
-#include "base/logging.h"
-#include "content/browser/renderer_host/socket_stream_host.h"
-#include "content/browser/ssl/ssl_manager.h"
-#include "content/common/resource_messages.h"
-#include "content/common/socket_stream.h"
-#include "content/common/socket_stream_messages.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/global_request_id.h"
-#include "net/base/net_errors.h"
-#include "net/cookies/canonical_cookie.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/websockets/websocket_job.h"
-#include "net/websockets/websocket_throttle.h"
-
-namespace content {
-
-namespace {
-
-const size_t kMaxSocketStreamHosts = 16 * 1024;
-
-} // namespace
-
-SocketStreamDispatcherHost::SocketStreamDispatcherHost(
- int render_process_id,
- const GetRequestContextCallback& request_context_callback,
- ResourceContext* resource_context)
- : BrowserMessageFilter(SocketStreamMsgStart),
- render_process_id_(render_process_id),
- request_context_callback_(request_context_callback),
- resource_context_(resource_context),
- weak_ptr_factory_(this),
- on_shutdown_(false) {
- net::WebSocketJob::EnsureInit();
-}
-
-bool SocketStreamDispatcherHost::OnMessageReceived(
- const IPC::Message& message) {
- if (on_shutdown_)
- return false;
-
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(SocketStreamDispatcherHost, message)
- IPC_MESSAGE_HANDLER(SocketStreamHostMsg_Connect, OnConnect)
- IPC_MESSAGE_HANDLER(SocketStreamHostMsg_SendData, OnSendData)
- IPC_MESSAGE_HANDLER(SocketStreamHostMsg_Close, OnCloseReq)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-// SocketStream::Delegate methods implementations.
-void SocketStreamDispatcherHost::OnConnected(net::SocketStream* socket,
- int max_pending_send_allowed) {
- int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
- DVLOG(2) << "SocketStreamDispatcherHost::OnConnected socket_id=" << socket_id
- << " max_pending_send_allowed=" << max_pending_send_allowed;
- if (socket_id == kNoSocketId) {
- DVLOG(1) << "NoSocketId in OnConnected";
- return;
- }
- if (!Send(new SocketStreamMsg_Connected(
- socket_id, max_pending_send_allowed))) {
- DVLOG(1) << "SocketStreamMsg_Connected failed.";
- DeleteSocketStreamHost(socket_id);
- }
-}
-
-void SocketStreamDispatcherHost::OnSentData(net::SocketStream* socket,
- int amount_sent) {
- int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
- DVLOG(2) << "SocketStreamDispatcherHost::OnSentData socket_id=" << socket_id
- << " amount_sent=" << amount_sent;
- if (socket_id == kNoSocketId) {
- DVLOG(1) << "NoSocketId in OnSentData";
- return;
- }
- if (!Send(new SocketStreamMsg_SentData(socket_id, amount_sent))) {
- DVLOG(1) << "SocketStreamMsg_SentData failed.";
- DeleteSocketStreamHost(socket_id);
- }
-}
-
-void SocketStreamDispatcherHost::OnReceivedData(
- net::SocketStream* socket, const char* data, int len) {
- int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
- DVLOG(2) << "SocketStreamDispatcherHost::OnReceiveData socket_id="
- << socket_id;
- if (socket_id == kNoSocketId) {
- DVLOG(1) << "NoSocketId in OnReceivedData";
- return;
- }
- if (!Send(new SocketStreamMsg_ReceivedData(
- socket_id, std::vector<char>(data, data + len)))) {
- DVLOG(1) << "SocketStreamMsg_ReceivedData failed.";
- DeleteSocketStreamHost(socket_id);
- }
-}
-
-void SocketStreamDispatcherHost::OnClose(net::SocketStream* socket) {
- int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
- DVLOG(2) << "SocketStreamDispatcherHost::OnClosed socket_id=" << socket_id;
- if (socket_id == kNoSocketId) {
- DVLOG(1) << "NoSocketId in OnClose";
- return;
- }
- DeleteSocketStreamHost(socket_id);
-}
-
-void SocketStreamDispatcherHost::OnError(const net::SocketStream* socket,
- int error) {
- int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
- DVLOG(2) << "SocketStreamDispatcherHost::OnError socket_id=" << socket_id;
- if (socket_id == content::kNoSocketId) {
- DVLOG(1) << "NoSocketId in OnError";
- return;
- }
- // SocketStream::Delegate::OnError() events are handled as WebSocket error
- // event when user agent was required to fail WebSocket connection or the
- // WebSocket connection is closed with prejudice.
- if (!Send(new SocketStreamMsg_Failed(socket_id, error))) {
- DVLOG(1) << "SocketStreamMsg_Failed failed.";
- DeleteSocketStreamHost(socket_id);
- }
-}
-
-void SocketStreamDispatcherHost::OnSSLCertificateError(
- net::SocketStream* socket, const net::SSLInfo& ssl_info, bool fatal) {
- int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
- DVLOG(2) << "SocketStreamDispatcherHost::OnSSLCertificateError socket_id="
- << socket_id;
- if (socket_id == kNoSocketId) {
- DVLOG(1) << "NoSocketId in OnSSLCertificateError";
- return;
- }
- SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
- DCHECK(socket_stream_host);
- GlobalRequestID request_id(-1, socket_id);
- SSLManager::OnSSLCertificateError(
- weak_ptr_factory_.GetWeakPtr(), request_id, ResourceType::SUB_RESOURCE,
- socket->url(), render_process_id_, socket_stream_host->render_frame_id(),
- ssl_info, fatal);
-}
-
-bool SocketStreamDispatcherHost::CanGetCookies(net::SocketStream* socket,
- const GURL& url) {
- int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket);
- if (socket_id == kNoSocketId) {
- return false;
- }
- SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
- DCHECK(socket_stream_host);
- return GetContentClient()->browser()->AllowGetCookie(
- url,
- url,
- net::CookieList(),
- resource_context_,
- render_process_id_,
- socket_stream_host->render_frame_id());
-}
-
-bool SocketStreamDispatcherHost::CanSetCookie(net::SocketStream* request,
- const GURL& url,
- const std::string& cookie_line,
- net::CookieOptions* options) {
- int socket_id = SocketStreamHost::SocketIdFromSocketStream(request);
- if (socket_id == kNoSocketId) {
- return false;
- }
- SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
- DCHECK(socket_stream_host);
- return GetContentClient()->browser()->AllowSetCookie(
- url,
- url,
- cookie_line,
- resource_context_,
- render_process_id_,
- socket_stream_host->render_frame_id(),
- options);
-}
-
-void SocketStreamDispatcherHost::CancelSSLRequest(
- const GlobalRequestID& id,
- int error,
- const net::SSLInfo* ssl_info) {
- int socket_id = id.request_id;
- DVLOG(2) << "SocketStreamDispatcherHost::CancelSSLRequest socket_id="
- << socket_id;
- DCHECK_NE(kNoSocketId, socket_id);
- SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
- DCHECK(socket_stream_host);
- if (ssl_info)
- socket_stream_host->CancelWithSSLError(*ssl_info);
- else
- socket_stream_host->CancelWithError(error);
-}
-
-void SocketStreamDispatcherHost::ContinueSSLRequest(
- const GlobalRequestID& id) {
- int socket_id = id.request_id;
- DVLOG(2) << "SocketStreamDispatcherHost::ContinueSSLRequest socket_id="
- << socket_id;
- DCHECK_NE(kNoSocketId, socket_id);
- SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
- DCHECK(socket_stream_host);
- socket_stream_host->ContinueDespiteError();
-}
-
-SocketStreamDispatcherHost::~SocketStreamDispatcherHost() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- Shutdown();
-}
-
-// Message handlers called by OnMessageReceived.
-void SocketStreamDispatcherHost::OnConnect(int render_frame_id,
- const GURL& url,
- int socket_id) {
- DVLOG(2) << "SocketStreamDispatcherHost::OnConnect"
- << " render_frame_id=" << render_frame_id
- << " url=" << url
- << " socket_id=" << socket_id;
- DCHECK_NE(kNoSocketId, socket_id);
-
- if (hosts_.size() >= kMaxSocketStreamHosts) {
- if (!Send(new SocketStreamMsg_Failed(socket_id,
- net::ERR_TOO_MANY_SOCKET_STREAMS))) {
- DVLOG(1) << "SocketStreamMsg_Failed failed.";
- }
- if (!Send(new SocketStreamMsg_Closed(socket_id))) {
- DVLOG(1) << "SocketStreamMsg_Closed failed.";
- }
- return;
- }
-
- if (hosts_.Lookup(socket_id)) {
- DVLOG(1) << "socket_id=" << socket_id << " already registered.";
- return;
- }
-
- // Note that the SocketStreamHost is responsible for checking that |url|
- // is valid.
- SocketStreamHost* socket_stream_host =
- new SocketStreamHost(this, render_process_id_, render_frame_id,
- socket_id);
- hosts_.AddWithID(socket_stream_host, socket_id);
- socket_stream_host->Connect(url, GetURLRequestContext());
- DVLOG(2) << "SocketStreamDispatcherHost::OnConnect -> " << socket_id;
-}
-
-void SocketStreamDispatcherHost::OnSendData(
- int socket_id, const std::vector<char>& data) {
- DVLOG(2) << "SocketStreamDispatcherHost::OnSendData socket_id=" << socket_id;
- SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
- if (!socket_stream_host) {
- DVLOG(1) << "socket_id=" << socket_id << " already closed.";
- return;
- }
- if (!socket_stream_host->SendData(data)) {
- // Cannot accept more data to send.
- socket_stream_host->Close();
- }
-}
-
-void SocketStreamDispatcherHost::OnCloseReq(int socket_id) {
- DVLOG(2) << "SocketStreamDispatcherHost::OnCloseReq socket_id=" << socket_id;
- SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
- if (!socket_stream_host)
- return;
- socket_stream_host->Close();
-}
-
-void SocketStreamDispatcherHost::DeleteSocketStreamHost(int socket_id) {
- SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id);
- DCHECK(socket_stream_host);
- delete socket_stream_host;
- hosts_.Remove(socket_id);
- if (!Send(new SocketStreamMsg_Closed(socket_id))) {
- DVLOG(1) << "SocketStreamMsg_Closed failed.";
- }
-}
-
-net::URLRequestContext* SocketStreamDispatcherHost::GetURLRequestContext() {
- return request_context_callback_.Run(ResourceType::SUB_RESOURCE);
-}
-
-void SocketStreamDispatcherHost::Shutdown() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // TODO(ukai): Implement IDMap::RemoveAll().
- for (IDMap<SocketStreamHost>::const_iterator iter(&hosts_);
- !iter.IsAtEnd();
- iter.Advance()) {
- int socket_id = iter.GetCurrentKey();
- const SocketStreamHost* socket_stream_host = iter.GetCurrentValue();
- delete socket_stream_host;
- hosts_.Remove(socket_id);
- }
- on_shutdown_ = true;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/socket_stream_dispatcher_host.h b/chromium/content/browser/renderer_host/socket_stream_dispatcher_host.h
deleted file mode 100644
index c0836138826..00000000000
--- a/chromium/content/browser/renderer_host/socket_stream_dispatcher_host.h
+++ /dev/null
@@ -1,99 +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_SOCKET_STREAM_DISPATCHER_HOST_H_
-#define CONTENT_BROWSER_RENDERER_HOST_SOCKET_STREAM_DISPATCHER_HOST_H_
-
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/id_map.h"
-#include "base/memory/weak_ptr.h"
-#include "content/browser/ssl/ssl_error_handler.h"
-#include "content/public/browser/browser_message_filter.h"
-#include "net/socket_stream/socket_stream.h"
-
-class GURL;
-
-namespace net {
-class SSLInfo;
-}
-
-namespace content {
-class ResourceContext;
-class SocketStreamHost;
-
-// Dispatches ViewHostMsg_SocketStream_* messages sent from renderer.
-// It also acts as SocketStream::Delegate so that it sends
-// ViewMsg_SocketStream_* messages back to renderer.
-class SocketStreamDispatcherHost
- : public BrowserMessageFilter,
- public net::SocketStream::Delegate,
- public SSLErrorHandler::Delegate {
- public:
- typedef base::Callback<net::URLRequestContext*(ResourceType::Type)>
- GetRequestContextCallback;
- SocketStreamDispatcherHost(
- int render_process_id,
- const GetRequestContextCallback& request_context_callback,
- ResourceContext* resource_context);
-
- // BrowserMessageFilter:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- // Make this object inactive.
- // Remove all active SocketStreamHost objects.
- void Shutdown();
-
- // SocketStream::Delegate:
- virtual void OnConnected(net::SocketStream* socket,
- int max_pending_send_allowed) OVERRIDE;
- virtual void OnSentData(net::SocketStream* socket, int amount_sent) OVERRIDE;
- virtual void OnReceivedData(net::SocketStream* socket,
- const char* data, int len) OVERRIDE;
- virtual void OnClose(net::SocketStream* socket) OVERRIDE;
- virtual void OnError(const net::SocketStream* socket, int error) OVERRIDE;
- virtual void OnSSLCertificateError(net::SocketStream* socket,
- const net::SSLInfo& ssl_info,
- bool fatal) OVERRIDE;
- virtual bool CanGetCookies(net::SocketStream* socket,
- const GURL& url) OVERRIDE;
- virtual bool CanSetCookie(net::SocketStream* request,
- const GURL& url,
- const std::string& cookie_line,
- net::CookieOptions* options) OVERRIDE;
-
- // SSLErrorHandler::Delegate methods:
- virtual void CancelSSLRequest(const GlobalRequestID& id,
- int error,
- const net::SSLInfo* ssl_info) OVERRIDE;
- virtual void ContinueSSLRequest(const GlobalRequestID& id) OVERRIDE;
-
- protected:
- virtual ~SocketStreamDispatcherHost();
-
- private:
- // Message handlers called by OnMessageReceived.
- void OnConnect(int render_frame_id, const GURL& url, int socket_id);
- void OnSendData(int socket_id, const std::vector<char>& data);
- void OnCloseReq(int socket_id);
-
- void DeleteSocketStreamHost(int socket_id);
-
- net::URLRequestContext* GetURLRequestContext();
-
- IDMap<SocketStreamHost> hosts_;
- int render_process_id_;
- GetRequestContextCallback request_context_callback_;
- ResourceContext* resource_context_;
-
- base::WeakPtrFactory<SocketStreamDispatcherHost> weak_ptr_factory_;
- bool on_shutdown_;
-
- DISALLOW_COPY_AND_ASSIGN(SocketStreamDispatcherHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_SOCKET_STREAM_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/renderer_host/socket_stream_host.cc b/chromium/content/browser/renderer_host/socket_stream_host.cc
deleted file mode 100644
index 364b8d09dde..00000000000
--- a/chromium/content/browser/renderer_host/socket_stream_host.cc
+++ /dev/null
@@ -1,107 +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/renderer_host/socket_stream_host.h"
-
-#include "base/logging.h"
-#include "content/common/socket_stream.h"
-#include "content/public/browser/content_browser_client.h"
-#include "net/socket_stream/socket_stream_job.h"
-#include "net/url_request/url_request_context.h"
-
-namespace content {
-namespace {
-
-const char* kSocketIdKey = "socketId";
-
-class SocketStreamId : public net::SocketStream::UserData {
- public:
- explicit SocketStreamId(int socket_id) : socket_id_(socket_id) {}
- virtual ~SocketStreamId() {}
- int socket_id() const { return socket_id_; }
-
- private:
- int socket_id_;
-};
-
-} // namespace
-
-SocketStreamHost::SocketStreamHost(
- net::SocketStream::Delegate* delegate,
- int child_id,
- int render_frame_id,
- int socket_id)
- : delegate_(delegate),
- child_id_(child_id),
- render_frame_id_(render_frame_id),
- socket_id_(socket_id) {
- DCHECK_NE(socket_id_, kNoSocketId);
- VLOG(1) << "SocketStreamHost: render_frame_id=" << render_frame_id
- << " socket_id=" << socket_id_;
-}
-
-/* static */
-int SocketStreamHost::SocketIdFromSocketStream(
- const net::SocketStream* socket) {
- net::SocketStream::UserData* d = socket->GetUserData(kSocketIdKey);
- if (d) {
- SocketStreamId* socket_stream_id = static_cast<SocketStreamId*>(d);
- return socket_stream_id->socket_id();
- }
- return kNoSocketId;
-}
-
-SocketStreamHost::~SocketStreamHost() {
- VLOG(1) << "SocketStreamHost destructed socket_id=" << socket_id_;
- job_->DetachContext();
- job_->DetachDelegate();
-}
-
-void SocketStreamHost::Connect(const GURL& url,
- net::URLRequestContext* request_context) {
- VLOG(1) << "SocketStreamHost::Connect url=" << url;
- job_ = net::SocketStreamJob::CreateSocketStreamJob(
- url, delegate_, request_context->transport_security_state(),
- request_context->ssl_config_service(),
- request_context,
- GetContentClient()->browser()->OverrideCookieStoreForRenderProcess(
- child_id_));
- job_->SetUserData(kSocketIdKey, new SocketStreamId(socket_id_));
- job_->Connect();
-}
-
-bool SocketStreamHost::SendData(const std::vector<char>& data) {
- VLOG(1) << "SocketStreamHost::SendData";
- return job_.get() && job_->SendData(&data[0], data.size());
-}
-
-void SocketStreamHost::Close() {
- VLOG(1) << "SocketStreamHost::Close";
- if (!job_.get())
- return;
- job_->Close();
-}
-
-void SocketStreamHost::CancelWithError(int error) {
- VLOG(1) << "SocketStreamHost::CancelWithError: error=" << error;
- if (!job_.get())
- return;
- job_->CancelWithError(error);
-}
-
-void SocketStreamHost::CancelWithSSLError(const net::SSLInfo& ssl_info) {
- VLOG(1) << "SocketStreamHost::CancelWithSSLError";
- if (!job_.get())
- return;
- job_->CancelWithSSLError(ssl_info);
-}
-
-void SocketStreamHost::ContinueDespiteError() {
- VLOG(1) << "SocketStreamHost::ContinueDespiteError";
- if (!job_.get())
- return;
- job_->ContinueDespiteError();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/renderer_host/socket_stream_host.h b/chromium/content/browser/renderer_host/socket_stream_host.h
deleted file mode 100644
index da4716c00af..00000000000
--- a/chromium/content/browser/renderer_host/socket_stream_host.h
+++ /dev/null
@@ -1,81 +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_SOCKET_STREAM_HOST_H_
-#define CONTENT_BROWSER_RENDERER_HOST_SOCKET_STREAM_HOST_H_
-
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "net/socket_stream/socket_stream.h"
-
-class GURL;
-
-namespace net {
-class SocketStreamJob;
-class URLRequestContext;
-class SSLInfo;
-} // namespace net
-
-namespace content {
-
-// Host of SocketStreamHandle. Each SocketStreamHandle will have an unique
-// socket_id assigned by SocketStreamHost constructor. If socket id is
-// kNoSocketId, there is no SocketStreamHost. Each SocketStreamHost has
-// SocketStream to manage bi-directional communication over socket stream. The
-// lifetime of an instance of this class is completely controlled by the
-// SocketStreamDispatcherHost.
-class SocketStreamHost {
- public:
- SocketStreamHost(net::SocketStream::Delegate* delegate,
- int child_id,
- int render_frame_id,
- int socket_id);
- ~SocketStreamHost();
-
- // Gets socket_id associated with |socket|.
- static int SocketIdFromSocketStream(const net::SocketStream* socket);
-
- int render_frame_id() const { return render_frame_id_; }
- int socket_id() const { return socket_id_; }
-
- // Starts to open connection to |url|.
- void Connect(const GURL& url, net::URLRequestContext* request_context);
-
- // Sends |data| over the socket stream.
- // socket stream must be open to send data.
- // Returns true if the data is put in transmit buffer in socket stream.
- // Returns false otherwise (transmit buffer exceeds limit, or socket
- // stream is closed).
- bool SendData(const std::vector<char>& data);
-
- // Closes the socket stream.
- void Close();
-
- // Following CancelWithError, CancelWithSSLError, and ContinueDespiteError
- // will be called by net::SocketStream::Delegate in OnSSLCertificateError.
- // CancelWithError Cancels the connection because of an error.
- // |error| is net::Error which represents the error.
- void CancelWithError(int error);
-
- // Cancels the connection because of receiving a certificate with an error.
- void CancelWithSSLError(const net::SSLInfo& ssl_info);
-
- // Continue to establish the connection in spite of an error.
- void ContinueDespiteError();
-
- private:
- net::SocketStream::Delegate* delegate_;
- int child_id_;
- int render_frame_id_;
- int socket_id_;
-
- scoped_refptr<net::SocketStreamJob> job_;
-
- DISALLOW_COPY_AND_ASSIGN(SocketStreamHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_RENDERER_HOST_SOCKET_STREAM_HOST_H_
diff --git a/chromium/content/browser/renderer_host/software_frame_manager.h b/chromium/content/browser/renderer_host/software_frame_manager.h
index 6d19afd972f..55729857080 100644
--- a/chromium/content/browser/renderer_host/software_frame_manager.h
+++ b/chromium/content/browser/renderer_host/software_frame_manager.h
@@ -39,7 +39,7 @@ class CONTENT_EXPORT SoftwareFrameManager : public RendererFrameManagerClient {
public:
explicit SoftwareFrameManager(
base::WeakPtr<SoftwareFrameManagerClient> client);
- virtual ~SoftwareFrameManager();
+ ~SoftwareFrameManager() override;
// Swaps to a new frame from shared memory. This frame is guaranteed to
// not be evicted until SwapToNewFrameComplete is called.
@@ -64,7 +64,7 @@ class CONTENT_EXPORT SoftwareFrameManager : public RendererFrameManagerClient {
private:
// Called by SoftwareFrameMemoryManager to demand that the current frame
// be evicted.
- virtual void EvictCurrentFrame() OVERRIDE;
+ void EvictCurrentFrame() override;
base::WeakPtr<SoftwareFrameManagerClient> client_;
diff --git a/chromium/content/browser/renderer_host/software_frame_manager_unittest.cc b/chromium/content/browser/renderer_host/software_frame_manager_unittest.cc
index e700f69f155..0569f259f1b 100644
--- a/chromium/content/browser/renderer_host/software_frame_manager_unittest.cc
+++ b/chromium/content/browser/renderer_host/software_frame_manager_unittest.cc
@@ -25,13 +25,11 @@ class FakeSoftwareFrameManagerClient : public SoftwareFrameManagerClient {
HostSharedBitmapManager::current()->ProcessRemoved(
base::GetCurrentProcessHandle());
}
- virtual void SoftwareFrameWasFreed(uint32 output_surface_id,
- unsigned frame_id) OVERRIDE {
+ void SoftwareFrameWasFreed(uint32 output_surface_id,
+ unsigned frame_id) override {
freed_frames_.push_back(std::make_pair(output_surface_id, frame_id));
}
- virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE {
- ++evicted_count_;
- }
+ void ReleaseReferencesToSoftwareFrame() override { ++evicted_count_; }
bool SwapToNewFrame(uint32 output_surface, unsigned frame_id) {
cc::SoftwareFrameData frame;
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 eddff7b3764..e208ccd953e 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
@@ -26,7 +26,7 @@ const int64 kTaskDelayMs = 200;
class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate {
public:
MockRenderWidgetHostDelegate() {}
- virtual ~MockRenderWidgetHostDelegate() {}
+ ~MockRenderWidgetHostDelegate() override {}
};
// This test does not test the WebKit side of the dictionary system (which
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 4706346202e..1918620644d 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
@@ -25,10 +25,10 @@ class CONTENT_EXPORT TextInputClientMessageFilter
explicit TextInputClientMessageFilter(int child_id);
// BrowserMessageFilter override:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
protected:
- virtual ~TextInputClientMessageFilter();
+ ~TextInputClientMessageFilter() override;
private:
// IPC Message handlers:
diff --git a/chromium/content/browser/renderer_host/ui_events_helper.cc b/chromium/content/browser/renderer_host/ui_events_helper.cc
index c521ee60452..b514425cc88 100644
--- a/chromium/content/browser/renderer_host/ui_events_helper.cc
+++ b/chromium/content/browser/renderer_host/ui_events_helper.cc
@@ -4,6 +4,7 @@
#include "content/browser/renderer_host/ui_events_helper.h"
+#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/common/input/web_touch_event_traits.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/events/event.h"
@@ -20,6 +21,8 @@ int WebModifiersToUIFlags(int modifiers) {
flags |= ui::EF_CONTROL_DOWN;
if (modifiers & blink::WebInputEvent::AltKey)
flags |= ui::EF_ALT_DOWN;
+ if (modifiers & blink::WebInputEvent::MetaKey)
+ flags |= ui::EF_COMMAND_DOWN;
if (modifiers & blink::WebInputEvent::LeftButtonDown)
flags |= ui::EF_LEFT_MOUSE_BUTTON;
@@ -240,27 +243,6 @@ blink::WebGestureEvent MakeWebGestureEventFromUIEvent(
return gesture_event;
}
-int EventFlagsToWebEventModifiers(int flags) {
- int modifiers = 0;
-
- if (flags & ui::EF_SHIFT_DOWN)
- modifiers |= blink::WebInputEvent::ShiftKey;
- if (flags & ui::EF_CONTROL_DOWN)
- modifiers |= blink::WebInputEvent::ControlKey;
- if (flags & ui::EF_ALT_DOWN)
- modifiers |= blink::WebInputEvent::AltKey;
- // TODO(beng): MetaKey/META_MASK
- if (flags & ui::EF_LEFT_MOUSE_BUTTON)
- modifiers |= blink::WebInputEvent::LeftButtonDown;
- if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
- modifiers |= blink::WebInputEvent::MiddleButtonDown;
- if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
- modifiers |= blink::WebInputEvent::RightButtonDown;
- if (flags & ui::EF_CAPS_LOCK_DOWN)
- modifiers |= blink::WebInputEvent::CapsLockOn;
- return modifiers;
-}
-
blink::WebTouchPoint* UpdateWebTouchEventFromUIEvent(
const ui::TouchEvent& event,
blink::WebTouchEvent* web_event) {
@@ -304,13 +286,6 @@ blink::WebTouchPoint* UpdateWebTouchEventFromUIEvent(
// Update the location and state of the point.
point->state = TouchPointStateFromEvent(event);
- if (point->state == blink::WebTouchPoint::StateMoved) {
- // It is possible for badly written touch drivers to emit Move events even
- // when the touch location hasn't changed. In such cases, consume the event
- // and pretend nothing happened.
- if (point->position.x == event.x() && point->position.y == event.y())
- return NULL;
- }
point->position.x = event.x();
point->position.y = event.y();
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 b754b494c81..4fe79c16dd1 100644
--- a/chromium/content/browser/renderer_host/web_input_event_aura.cc
+++ b/chromium/content/browser/renderer_host/web_input_event_aura.cc
@@ -4,63 +4,18 @@
#include "content/browser/renderer_host/web_input_event_aura.h"
+#include "content/browser/renderer_host/input/web_input_event_util.h"
#include "content/browser/renderer_host/ui_events_helper.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
-#if defined(USE_OZONE)
-#include "ui/events/keycodes/keyboard_code_conversion.h"
+#if defined(USE_X11) || defined(USE_OZONE)
+#include "ui/events/keycodes/dom4/keycode_converter.h"
#endif
namespace content {
-#if defined(USE_X11) || defined(USE_OZONE)
-// From third_party/WebKit/Source/web/gtk/WebInputEventFactory.cpp:
-blink::WebUChar GetControlCharacter(int windows_key_code, bool shift) {
- if (windows_key_code >= ui::VKEY_A &&
- windows_key_code <= ui::VKEY_Z) {
- // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
- return windows_key_code - ui::VKEY_A + 1;
- }
- if (shift) {
- // following graphics chars require shift key to input.
- switch (windows_key_code) {
- // ctrl-@ maps to \x00 (Null byte)
- case ui::VKEY_2:
- return 0;
- // ctrl-^ maps to \x1E (Record separator, Information separator two)
- case ui::VKEY_6:
- return 0x1E;
- // ctrl-_ maps to \x1F (Unit separator, Information separator one)
- case ui::VKEY_OEM_MINUS:
- return 0x1F;
- // Returns 0 for all other keys to avoid inputting unexpected chars.
- default:
- break;
- }
- } else {
- switch (windows_key_code) {
- // ctrl-[ maps to \x1B (Escape)
- case ui::VKEY_OEM_4:
- return 0x1B;
- // ctrl-\ maps to \x1C (File separator, Information separator four)
- case ui::VKEY_OEM_5:
- return 0x1C;
- // ctrl-] maps to \x1D (Group separator, Information separator three)
- case ui::VKEY_OEM_6:
- return 0x1D;
- // ctrl-Enter maps to \x0A (Line feed)
- case ui::VKEY_RETURN:
- return 0x0A;
- // Returns 0 for all other keys to avoid inputting unexpected chars.
- default:
- break;
- }
- }
- return 0;
-}
-#endif
#if defined(OS_WIN)
blink::WebMouseEvent MakeUntranslatedWebMouseEventFromNativeEvent(
const base::NativeEvent& native_event);
@@ -70,20 +25,16 @@ blink::WebKeyboardEvent MakeWebKeyboardEventFromNativeEvent(
const base::NativeEvent& native_event);
blink::WebGestureEvent MakeWebGestureEventFromNativeEvent(
const base::NativeEvent& native_event);
-#elif defined(USE_X11)
-blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
- ui::KeyEvent* event);
-#elif defined(USE_OZONE)
+#endif
+#if defined(USE_X11) || defined(USE_OZONE)
blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
ui::KeyEvent* event) {
- const base::NativeEvent& native_event = event->native_event();
- ui::EventType type = ui::EventTypeFromNative(native_event);
blink::WebKeyboardEvent webkit_event;
webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
- switch (type) {
+ switch (event->type()) {
case ui::ET_KEY_PRESSED:
webkit_event.type = event->is_char() ? blink::WebInputEvent::Char :
blink::WebInputEvent::RawKeyDown;
@@ -98,32 +49,17 @@ blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
if (webkit_event.modifiers & blink::WebInputEvent::AltKey)
webkit_event.isSystemKey = true;
- wchar_t character = ui::KeyboardCodeFromNative(native_event);
- webkit_event.windowsKeyCode = character;
- webkit_event.nativeKeyCode = character;
-
- if (webkit_event.windowsKeyCode == ui::VKEY_RETURN)
- webkit_event.unmodifiedText[0] = '\r';
- else
- webkit_event.unmodifiedText[0] = ui::GetCharacterFromKeyCode(
- ui::KeyboardCodeFromNative(native_event),
- ui::EventFlagsFromNative(native_event));
-
- if (webkit_event.modifiers & blink::WebInputEvent::ControlKey) {
- webkit_event.text[0] =
- GetControlCharacter(
- webkit_event.windowsKeyCode,
- webkit_event.modifiers & blink::WebInputEvent::ShiftKey);
- } else {
- webkit_event.text[0] = webkit_event.unmodifiedText[0];
- }
+ webkit_event.windowsKeyCode = event->GetLocatedWindowsKeyboardCode();
+ webkit_event.nativeKeyCode =
+ ui::KeycodeConverter::CodeToNativeKeycode(event->code().c_str());
+ webkit_event.unmodifiedText[0] = event->GetUnmodifiedText();
+ webkit_event.text[0] = event->GetText();
webkit_event.setKeyIdentifierFromWindowsKeyCode();
return webkit_event;
}
-#endif
-#if defined(USE_X11) || defined(USE_OZONE)
+
blink::WebMouseWheelEvent MakeWebMouseWheelEventFromAuraEvent(
ui::ScrollEvent* event) {
blink::WebMouseWheelEvent webkit_event;
@@ -287,9 +223,6 @@ blink::WebMouseWheelEvent MakeWebMouseWheelEvent(ui::ScrollEvent* event) {
}
blink::WebKeyboardEvent MakeWebKeyboardEvent(ui::KeyEvent* event) {
- if (!event->HasNativeEvent())
- return blink::WebKeyboardEvent();
-
// Windows can figure out whether or not to construct a RawKeyDown or a Char
// WebInputEvent based on the type of message carried in
// event->native_event(). X11 is not so fortunate, there is no separate
@@ -297,6 +230,9 @@ blink::WebKeyboardEvent MakeWebKeyboardEvent(ui::KeyEvent* event) {
// is_char() == true. We need to pass the ui::KeyEvent to the X11 function
// to detect this case so the right event type can be constructed.
#if defined(OS_WIN)
+ if (!event->HasNativeEvent())
+ return blink::WebKeyboardEvent();
+
// Key events require no translation by the aura system.
return MakeWebKeyboardEventFromNativeEvent(event->native_event());
#else
@@ -360,11 +296,20 @@ blink::WebMouseEvent MakeWebMouseEventFromAuraEvent(ui::MouseEvent* event) {
webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
webkit_event.button = blink::WebMouseEvent::ButtonNone;
- if (event->flags() & ui::EF_LEFT_MOUSE_BUTTON)
+ int button_flags = event->flags();
+ if (event->type() == ui::ET_MOUSE_PRESSED ||
+ event->type() == ui::ET_MOUSE_RELEASED) {
+ // We want to use changed_button_flags() for mouse pressed & released.
+ // These flags can be used only if they are set which is not always the case
+ // (see e.g. GetChangedMouseButtonFlagsFromNative() in events_win.cc).
+ if (event->changed_button_flags())
+ button_flags = event->changed_button_flags();
+ }
+ if (button_flags & ui::EF_LEFT_MOUSE_BUTTON)
webkit_event.button = blink::WebMouseEvent::ButtonLeft;
- if (event->flags() & ui::EF_MIDDLE_MOUSE_BUTTON)
+ if (button_flags & ui::EF_MIDDLE_MOUSE_BUTTON)
webkit_event.button = blink::WebMouseEvent::ButtonMiddle;
- if (event->flags() & ui::EF_RIGHT_MOUSE_BUTTON)
+ if (button_flags & ui::EF_RIGHT_MOUSE_BUTTON)
webkit_event.button = blink::WebMouseEvent::ButtonRight;
switch (event->type()) {
diff --git a/chromium/content/browser/renderer_host/web_input_event_aura.h b/chromium/content/browser/renderer_host/web_input_event_aura.h
index eeff8866a82..7d6e6ca1bf3 100644
--- a/chromium/content/browser/renderer_host/web_input_event_aura.h
+++ b/chromium/content/browser/renderer_host/web_input_event_aura.h
@@ -22,10 +22,6 @@ namespace content {
// Used for scrolling. This matches Firefox behavior.
const int kPixelsPerTick = 53;
-#if defined(USE_X11) || defined(USE_OZONE)
-CONTENT_EXPORT blink::WebUChar GetControlCharacter(
- int windows_key_code, bool shift);
-#endif
CONTENT_EXPORT blink::WebMouseEvent MakeWebMouseEvent(
ui::MouseEvent* event);
CONTENT_EXPORT blink::WebMouseWheelEvent MakeWebMouseWheelEvent(
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 d67d0cd2278..5a86f734d69 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
@@ -25,7 +25,7 @@ TEST(WebInputEventAuraTest, TestMakeWebKeyboardEvent) {
{
// Press Ctrl.
xev.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, 0);
- ui::KeyEvent event(xev, false /* is_char */);
+ ui::KeyEvent event(xev);
blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
// However, modifier bit for Control in |webkit_event| should be set.
EXPECT_EQ(webkit_event.modifiers, blink::WebInputEvent::ControlKey);
@@ -33,7 +33,7 @@ TEST(WebInputEventAuraTest, TestMakeWebKeyboardEvent) {
{
// Release Ctrl.
xev.InitKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL, ControlMask);
- ui::KeyEvent event(xev, false /* is_char */);
+ ui::KeyEvent event(xev);
blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
// However, modifier bit for Control in |webkit_event| shouldn't be set.
EXPECT_EQ(webkit_event.modifiers, 0);
@@ -50,7 +50,7 @@ TEST(WebInputEventAuraTest, TestMakeWebKeyboardEventWindowsKeyCode) {
xev.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, 0);
XEvent* xevent = xev;
xevent->xkey.keycode = XKeysymToKeycode(gfx::GetXDisplay(), XK_Control_L);
- ui::KeyEvent event(xev, false /* is_char */);
+ ui::KeyEvent event(xev);
blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
// ui::VKEY_LCONTROL, instead of ui::VKEY_CONTROL, should be filled.
EXPECT_EQ(ui::VKEY_LCONTROL, webkit_event.windowsKeyCode);
@@ -60,7 +60,7 @@ TEST(WebInputEventAuraTest, TestMakeWebKeyboardEventWindowsKeyCode) {
xev.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, 0);
XEvent* xevent = xev;
xevent->xkey.keycode = XKeysymToKeycode(gfx::GetXDisplay(), XK_Control_R);
- ui::KeyEvent event(xev, false /* is_char */);
+ ui::KeyEvent event(xev);
blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
// ui::VKEY_RCONTROL, instead of ui::VKEY_CONTROL, should be filled.
EXPECT_EQ(ui::VKEY_RCONTROL, webkit_event.windowsKeyCode);
@@ -73,4 +73,71 @@ TEST(WebInputEventAuraTest, TestMakeWebKeyboardEventWindowsKeyCode) {
#endif
}
+// Checks that MakeWebKeyboardEvent fills a correct keypard modifier.
+TEST(WebInputEventAuraTest, TestMakeWebKeyboardEventKeyPadKeyCode) {
+#if defined(USE_X11)
+ struct TestCase {
+ ui::KeyboardCode ui_keycode; // The virtual key code.
+ uint32 x_keycode; // The platform key code.
+ bool expected_result; // true if the event has "isKeyPad" modifier.
+ } kTesCases[] = {
+ {ui::VKEY_0, XK_0, false},
+ {ui::VKEY_1, XK_1, false},
+ {ui::VKEY_2, XK_2, false},
+ {ui::VKEY_3, XK_3, false},
+ {ui::VKEY_4, XK_4, false},
+ {ui::VKEY_5, XK_5, false},
+ {ui::VKEY_6, XK_6, false},
+ {ui::VKEY_7, XK_7, false},
+ {ui::VKEY_8, XK_8, false},
+ {ui::VKEY_9, XK_9, false},
+
+ {ui::VKEY_NUMPAD0, XK_KP_0, true},
+ {ui::VKEY_NUMPAD1, XK_KP_1, true},
+ {ui::VKEY_NUMPAD2, XK_KP_2, true},
+ {ui::VKEY_NUMPAD3, XK_KP_3, true},
+ {ui::VKEY_NUMPAD4, XK_KP_4, true},
+ {ui::VKEY_NUMPAD5, XK_KP_5, true},
+ {ui::VKEY_NUMPAD6, XK_KP_6, true},
+ {ui::VKEY_NUMPAD7, XK_KP_7, true},
+ {ui::VKEY_NUMPAD8, XK_KP_8, true},
+ {ui::VKEY_NUMPAD9, XK_KP_9, true},
+
+ {ui::VKEY_MULTIPLY, XK_KP_Multiply, true},
+ {ui::VKEY_SUBTRACT, XK_KP_Subtract, true},
+ {ui::VKEY_ADD, XK_KP_Add, true},
+ {ui::VKEY_DIVIDE, XK_KP_Divide, true},
+ {ui::VKEY_DECIMAL, XK_KP_Decimal, true},
+ {ui::VKEY_DELETE, XK_KP_Delete, true},
+ {ui::VKEY_INSERT, XK_KP_Insert, true},
+ {ui::VKEY_END, XK_KP_End, true},
+ {ui::VKEY_DOWN, XK_KP_Down, true},
+ {ui::VKEY_NEXT, XK_KP_Page_Down, true},
+ {ui::VKEY_LEFT, XK_KP_Left, true},
+ {ui::VKEY_CLEAR, XK_KP_Begin, true},
+ {ui::VKEY_RIGHT, XK_KP_Right, true},
+ {ui::VKEY_HOME, XK_KP_Home, true},
+ {ui::VKEY_UP, XK_KP_Up, true},
+ {ui::VKEY_PRIOR, XK_KP_Page_Up, true},
+ };
+ ui::ScopedXI2Event xev;
+ for (size_t i = 0; i < arraysize(kTesCases); ++i) {
+ const TestCase& test_case = kTesCases[i];
+
+ xev.InitKeyEvent(ui::ET_KEY_PRESSED, test_case.ui_keycode, 0);
+ XEvent* xevent = xev;
+ xevent->xkey.keycode = XKeysymToKeycode(gfx::GetXDisplay(),
+ test_case.x_keycode);
+ ui::KeyEvent event(xev);
+ blink::WebKeyboardEvent webkit_event = MakeWebKeyboardEvent(&event);
+ EXPECT_EQ(test_case.expected_result,
+ (webkit_event.modifiers & blink::WebInputEvent::IsKeyPad) != 0)
+ << "Failed in " << i << "th test case: "
+ << "{ui_keycode:" << test_case.ui_keycode
+ << ", x_keycode:" << test_case.x_keycode
+ << "}, expect: " << test_case.expected_result;
+ }
+#endif
+}
+
} // namespace content
diff --git a/chromium/content/browser/renderer_host/web_input_event_aurax11.cc b/chromium/content/browser/renderer_host/web_input_event_aurax11.cc
deleted file mode 100644
index 6a9430a62d6..00000000000
--- a/chromium/content/browser/renderer_host/web_input_event_aurax11.cc
+++ /dev/null
@@ -1,140 +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.
-
-// Portions based heavily on:
-// third_party/WebKit/public/web/gtk/WebInputEventFactory.cpp
-//
-/*
- * Copyright (C) 2006-2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "content/browser/renderer_host/web_input_event_aura.h"
-
-#include <X11/keysym.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <cstdlib>
-
-#include "base/event_types.h"
-#include "base/logging.h"
-#include "content/browser/renderer_host/ui_events_helper.h"
-#include "ui/events/event.h"
-#include "ui/events/event_constants.h"
-#include "ui/events/keycodes/keyboard_code_conversion_x.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-
-namespace content {
-
-// chromium WebKit does not provide a WebInputEventFactory for X11, so we have
-// to do the work here ourselves.
-
-namespace {
-
-int XKeyEventToWindowsKeyCode(XKeyEvent* event) {
- int windows_key_code =
- ui::KeyboardCodeFromXKeyEvent(reinterpret_cast<XEvent*>(event));
- if (windows_key_code == ui::VKEY_SHIFT ||
- windows_key_code == ui::VKEY_CONTROL ||
- windows_key_code == ui::VKEY_MENU) {
- // To support DOM3 'location' attribute, we need to lookup an X KeySym and
- // set ui::VKEY_[LR]XXX instead of ui::VKEY_XXX.
- KeySym keysym = XK_VoidSymbol;
- XLookupString(event, NULL, 0, &keysym, NULL);
- switch (keysym) {
- case XK_Shift_L:
- return ui::VKEY_LSHIFT;
- case XK_Shift_R:
- return ui::VKEY_RSHIFT;
- case XK_Control_L:
- return ui::VKEY_LCONTROL;
- case XK_Control_R:
- return ui::VKEY_RCONTROL;
- case XK_Meta_L:
- case XK_Alt_L:
- return ui::VKEY_LMENU;
- case XK_Meta_R:
- case XK_Alt_R:
- return ui::VKEY_RMENU;
- }
- }
- return windows_key_code;
-}
-
-} // namespace
-
-blink::WebKeyboardEvent MakeWebKeyboardEventFromAuraEvent(
- ui::KeyEvent* event) {
- const base::NativeEvent& native_event = event->native_event();
- blink::WebKeyboardEvent webkit_event;
- XKeyEvent* native_key_event = &native_event->xkey;
-
- webkit_event.timeStampSeconds = event->time_stamp().InSecondsF();
- webkit_event.modifiers = EventFlagsToWebEventModifiers(event->flags());
-
- switch (native_event->type) {
- case KeyPress:
- webkit_event.type = event->is_char() ? blink::WebInputEvent::Char :
- blink::WebInputEvent::RawKeyDown;
- break;
- case KeyRelease:
- webkit_event.type = blink::WebInputEvent::KeyUp;
- break;
- default:
- NOTREACHED();
- }
-
- if (webkit_event.modifiers & blink::WebInputEvent::AltKey)
- webkit_event.isSystemKey = true;
-
- webkit_event.windowsKeyCode = XKeyEventToWindowsKeyCode(native_key_event);
- webkit_event.nativeKeyCode = native_key_event->keycode;
-
- if (webkit_event.windowsKeyCode == ui::VKEY_RETURN)
- webkit_event.unmodifiedText[0] = '\r';
- else
- webkit_event.unmodifiedText[0] = ui::GetCharacterFromXEvent(native_event);
-
- if (webkit_event.modifiers & blink::WebInputEvent::ControlKey) {
- webkit_event.text[0] =
- GetControlCharacter(
- webkit_event.windowsKeyCode,
- webkit_event.modifiers & blink::WebInputEvent::ShiftKey);
- } else {
- webkit_event.text[0] = webkit_event.unmodifiedText[0];
- }
-
- webkit_event.setKeyIdentifierFromWindowsKeyCode();
-
- // TODO: IsAutoRepeat/IsKeyPad?
-
- return webkit_event;
-}
-
-} // 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 2af2f0814c8..d49199a7cb8 100644
--- a/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc
+++ b/chromium/content/browser/renderer_host/websocket_dispatcher_host.cc
@@ -5,6 +5,7 @@
#include "content/browser/renderer_host/websocket_dispatcher_host.h"
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/logging.h"
@@ -178,6 +179,21 @@ WebSocketHostState WebSocketDispatcherHost::DoDropChannel(
}
WebSocketDispatcherHost::~WebSocketDispatcherHost() {
+ std::vector<WebSocketHost*> hosts;
+ for (base::hash_map<int, WebSocketHost*>::const_iterator i = hosts_.begin();
+ i != hosts_.end(); ++i) {
+ // In order to avoid changing the container while iterating, we copy
+ // the hosts.
+ hosts.push_back(i->second);
+ }
+
+ for (size_t i = 0; i < hosts.size(); ++i) {
+ // Note that some calls to GoAway could fail. In that case hosts[i] will be
+ // deleted and removed from |hosts_| in |DoDropChannel|.
+ hosts[i]->GoAway();
+ hosts[i] = NULL;
+ }
+
STLDeleteContainerPairSecondPointers(hosts_.begin(), hosts_.end());
}
diff --git a/chromium/content/browser/renderer_host/websocket_dispatcher_host.h b/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
index 4179b71b2e2..b9cdd343837 100644
--- a/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
+++ b/chromium/content/browser/renderer_host/websocket_dispatcher_host.h
@@ -56,7 +56,7 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
const WebSocketHostFactory& websocket_host_factory);
// BrowserMessageFilter:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
// The following methods are used by WebSocketHost::EventInterface to send
// IPCs from the browser to the renderer or child process. Any of them may
@@ -116,7 +116,7 @@ class CONTENT_EXPORT WebSocketDispatcherHost : public BrowserMessageFilter {
private:
typedef base::hash_map<int, WebSocketHost*> WebSocketHostTable;
- virtual ~WebSocketDispatcherHost();
+ ~WebSocketDispatcherHost() override;
WebSocketHost* CreateWebSocketHost(int routing_id);
diff --git a/chromium/content/browser/renderer_host/websocket_dispatcher_host_unittest.cc b/chromium/content/browser/renderer_host/websocket_dispatcher_host_unittest.cc
index e1506d99dd1..0d2e7057bbc 100644
--- a/chromium/content/browser/renderer_host/websocket_dispatcher_host_unittest.cc
+++ b/chromium/content/browser/renderer_host/websocket_dispatcher_host_unittest.cc
@@ -4,11 +4,13 @@
#include "content/browser/renderer_host/websocket_dispatcher_host.h"
+#include <algorithm>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "content/browser/renderer_host/websocket_host.h"
#include "content/common/websocket.h"
#include "content/common/websocket_messages.h"
@@ -23,28 +25,33 @@ namespace {
// This number is unlikely to occur by chance.
static const int kMagicRenderProcessId = 506116062;
+class WebSocketDispatcherHostTest;
+
// A mock of WebsocketHost which records received messages.
class MockWebSocketHost : public WebSocketHost {
public:
MockWebSocketHost(int routing_id,
WebSocketDispatcherHost* dispatcher,
- net::URLRequestContext* url_request_context)
- : WebSocketHost(routing_id, dispatcher, url_request_context) {
- }
+ net::URLRequestContext* url_request_context,
+ WebSocketDispatcherHostTest* owner);
- virtual ~MockWebSocketHost() {}
+ ~MockWebSocketHost() override {}
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE{
+ bool OnMessageReceived(const IPC::Message& message) override {
received_messages_.push_back(message);
return true;
}
+ void GoAway() override;
+
std::vector<IPC::Message> received_messages_;
+ base::WeakPtr<WebSocketDispatcherHostTest> owner_;
};
class WebSocketDispatcherHostTest : public ::testing::Test {
public:
- WebSocketDispatcherHostTest() {
+ WebSocketDispatcherHostTest()
+ : weak_ptr_factory_(this) {
dispatcher_host_ = new WebSocketDispatcherHost(
kMagicRenderProcessId,
base::Bind(&WebSocketDispatcherHostTest::OnGetRequestContext,
@@ -53,7 +60,19 @@ class WebSocketDispatcherHostTest : public ::testing::Test {
base::Unretained(this)));
}
- virtual ~WebSocketDispatcherHostTest() {}
+ ~WebSocketDispatcherHostTest() override {
+ // We need to invalidate the issued WeakPtrs at the beginning of the
+ // destructor in order not to access destructed member variables.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ }
+
+ void GoAway(int routing_id) {
+ gone_hosts_.push_back(routing_id);
+ }
+
+ base::WeakPtr<WebSocketDispatcherHostTest> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
protected:
scoped_refptr<WebSocketDispatcherHost> dispatcher_host_;
@@ -61,6 +80,9 @@ class WebSocketDispatcherHostTest : public ::testing::Test {
// Stores allocated MockWebSocketHost instances. Doesn't take ownership of
// them.
std::vector<MockWebSocketHost*> mock_hosts_;
+ std::vector<int> gone_hosts_;
+
+ base::WeakPtrFactory<WebSocketDispatcherHostTest> weak_ptr_factory_;
private:
net::URLRequestContext* OnGetRequestContext() {
@@ -69,12 +91,25 @@ class WebSocketDispatcherHostTest : public ::testing::Test {
WebSocketHost* CreateWebSocketHost(int routing_id) {
MockWebSocketHost* host =
- new MockWebSocketHost(routing_id, dispatcher_host_.get(), NULL);
+ new MockWebSocketHost(routing_id, dispatcher_host_.get(), NULL, this);
mock_hosts_.push_back(host);
return host;
}
};
+MockWebSocketHost::MockWebSocketHost(
+ int routing_id,
+ WebSocketDispatcherHost* dispatcher,
+ net::URLRequestContext* url_request_context,
+ WebSocketDispatcherHostTest* owner)
+ : WebSocketHost(routing_id, dispatcher, url_request_context),
+ owner_(owner->GetWeakPtr()) {}
+
+void MockWebSocketHost::GoAway() {
+ if (owner_)
+ owner_->GoAway(routing_id());
+}
+
TEST_F(WebSocketDispatcherHostTest, Construct) {
// Do nothing.
}
@@ -156,5 +191,29 @@ TEST_F(WebSocketDispatcherHostTest, SendFrame) {
}
}
+TEST_F(WebSocketDispatcherHostTest, Destruct) {
+ WebSocketHostMsg_AddChannelRequest message1(
+ 123, GURL("ws://example.com/test"), std::vector<std::string>(),
+ url::Origin("http://example.com"), -1);
+ WebSocketHostMsg_AddChannelRequest message2(
+ 456, GURL("ws://example.com/test2"), std::vector<std::string>(),
+ url::Origin("http://example.com"), -1);
+
+ ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message1));
+ ASSERT_TRUE(dispatcher_host_->OnMessageReceived(message2));
+
+ ASSERT_EQ(2u, mock_hosts_.size());
+
+ mock_hosts_.clear();
+ dispatcher_host_ = NULL;
+
+ ASSERT_EQ(2u, gone_hosts_.size());
+ // The gone_hosts_ ordering is not predictable because it depends on the
+ // hash_map ordering.
+ std::sort(gone_hosts_.begin(), gone_hosts_.end());
+ EXPECT_EQ(123, gone_hosts_[0]);
+ EXPECT_EQ(456, gone_hosts_[1]);
+}
+
} // namespace
} // namespace content
diff --git a/chromium/content/browser/renderer_host/websocket_host.cc b/chromium/content/browser/renderer_host/websocket_host.cc
index 7f639180372..9b557fedab3 100644
--- a/chromium/content/browser/renderer_host/websocket_host.cc
+++ b/chromium/content/browser/renderer_host/websocket_host.cc
@@ -17,6 +17,7 @@
#include "net/http/http_util.h"
#include "net/ssl/ssl_info.h"
#include "net/websockets/websocket_channel.h"
+#include "net/websockets/websocket_errors.h"
#include "net/websockets/websocket_event_interface.h"
#include "net/websockets/websocket_frame.h" // for WebSocketFrameHeader::OpCode
#include "net/websockets/websocket_handshake_request_info.h"
@@ -87,47 +88,44 @@ class WebSocketEventHandler : public net::WebSocketEventInterface {
WebSocketEventHandler(WebSocketDispatcherHost* dispatcher,
int routing_id,
int render_frame_id);
- virtual ~WebSocketEventHandler();
+ ~WebSocketEventHandler() override;
// net::WebSocketEventInterface implementation
- virtual ChannelState OnAddChannelResponse(
- bool fail,
- const std::string& selected_subprotocol,
- const std::string& extensions) OVERRIDE;
- virtual ChannelState OnDataFrame(bool fin,
- WebSocketMessageType type,
- const std::vector<char>& data) OVERRIDE;
- virtual ChannelState OnClosingHandshake() OVERRIDE;
- virtual ChannelState OnFlowControl(int64 quota) OVERRIDE;
- virtual ChannelState OnDropChannel(bool was_clean,
- uint16 code,
- const std::string& reason) OVERRIDE;
- virtual ChannelState OnFailChannel(const std::string& message) OVERRIDE;
- virtual ChannelState OnStartOpeningHandshake(
- scoped_ptr<net::WebSocketHandshakeRequestInfo> request) OVERRIDE;
- virtual ChannelState OnFinishOpeningHandshake(
- scoped_ptr<net::WebSocketHandshakeResponseInfo> response) OVERRIDE;
- virtual ChannelState OnSSLCertificateError(
+ ChannelState OnAddChannelResponse(bool fail,
+ const std::string& selected_subprotocol,
+ const std::string& extensions) override;
+ ChannelState OnDataFrame(bool fin,
+ WebSocketMessageType type,
+ const std::vector<char>& data) override;
+ ChannelState OnClosingHandshake() override;
+ ChannelState OnFlowControl(int64 quota) override;
+ ChannelState OnDropChannel(bool was_clean,
+ uint16 code,
+ const std::string& reason) override;
+ ChannelState OnFailChannel(const std::string& message) override;
+ ChannelState OnStartOpeningHandshake(
+ scoped_ptr<net::WebSocketHandshakeRequestInfo> request) override;
+ ChannelState OnFinishOpeningHandshake(
+ scoped_ptr<net::WebSocketHandshakeResponseInfo> response) override;
+ ChannelState OnSSLCertificateError(
scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks,
const GURL& url,
const net::SSLInfo& ssl_info,
- bool fatal) OVERRIDE;
+ bool fatal) override;
private:
class SSLErrorHandlerDelegate : public SSLErrorHandler::Delegate {
public:
SSLErrorHandlerDelegate(
scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks);
- virtual ~SSLErrorHandlerDelegate();
+ ~SSLErrorHandlerDelegate() override;
base::WeakPtr<SSLErrorHandler::Delegate> GetWeakPtr();
// SSLErrorHandler::Delegate methods
- virtual void CancelSSLRequest(const GlobalRequestID& id,
- int error,
- const net::SSLInfo* ssl_info) OVERRIDE;
- virtual void ContinueSSLRequest(const GlobalRequestID& id) OVERRIDE;
+ void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) override;
+ void ContinueSSLRequest() override;
private:
scoped_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks_;
@@ -275,11 +273,8 @@ ChannelState WebSocketEventHandler::OnSSLCertificateError(
<< " cert_status=" << ssl_info.cert_status << " fatal=" << fatal;
ssl_error_handler_delegate_.reset(
new SSLErrorHandlerDelegate(callbacks.Pass()));
- // We don't need request_id to be unique so just make a fake one.
- GlobalRequestID request_id(-1, -1);
SSLManager::OnSSLCertificateError(ssl_error_handler_delegate_->GetWeakPtr(),
- request_id,
- ResourceType::SUB_RESOURCE,
+ RESOURCE_TYPE_SUB_RESOURCE,
url,
dispatcher_->render_process_id(),
render_frame_id_,
@@ -301,7 +296,6 @@ WebSocketEventHandler::SSLErrorHandlerDelegate::GetWeakPtr() {
}
void WebSocketEventHandler::SSLErrorHandlerDelegate::CancelSSLRequest(
- const GlobalRequestID& id,
int error,
const net::SSLInfo* ssl_info) {
DVLOG(3) << "SSLErrorHandlerDelegate::CancelSSLRequest"
@@ -311,8 +305,7 @@ void WebSocketEventHandler::SSLErrorHandlerDelegate::CancelSSLRequest(
callbacks_->CancelSSLRequest(error, ssl_info);
}
-void WebSocketEventHandler::SSLErrorHandlerDelegate::ContinueSSLRequest(
- const GlobalRequestID& id) {
+void WebSocketEventHandler::SSLErrorHandlerDelegate::ContinueSSLRequest() {
DVLOG(3) << "SSLErrorHandlerDelegate::ContinueSSLRequest";
callbacks_->ContinueSSLRequest();
}
@@ -330,6 +323,10 @@ WebSocketHost::WebSocketHost(int routing_id,
WebSocketHost::~WebSocketHost() {}
+void WebSocketHost::GoAway() {
+ OnDropChannel(false, static_cast<uint16>(net::kWebSocketErrorGoingAway), "");
+}
+
bool WebSocketHost::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebSocketHost, message)
diff --git a/chromium/content/browser/renderer_host/websocket_host.h b/chromium/content/browser/renderer_host/websocket_host.h
index 21c77dcbbd5..39c1e41edbe 100644
--- a/chromium/content/browser/renderer_host/websocket_host.h
+++ b/chromium/content/browser/renderer_host/websocket_host.h
@@ -40,10 +40,16 @@ class CONTENT_EXPORT WebSocketHost {
net::URLRequestContext* url_request_context);
virtual ~WebSocketHost();
+ // The renderer process is going away.
+ // This function is virtual for testing.
+ virtual void GoAway();
+
// General message dispatch. WebSocketDispatcherHost::OnMessageReceived
// delegates to this method after looking up the |routing_id|.
virtual bool OnMessageReceived(const IPC::Message& message);
+ int routing_id() const { return routing_id_; }
+
private:
// Handlers for each message type, dispatched by OnMessageReceived(), as
// defined in content/common/websocket_messages.h
diff --git a/chromium/content/browser/resolve_proxy_msg_helper.cc b/chromium/content/browser/resolve_proxy_msg_helper.cc
index 5f0a6cd52d7..e189f1c83d3 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper.cc
+++ b/chromium/content/browser/resolve_proxy_msg_helper.cc
@@ -8,6 +8,7 @@
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "content/common/view_messages.h"
+#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
@@ -91,10 +92,10 @@ void ResolveProxyMsgHelper::StartPendingRequest() {
// Start the request.
int result = proxy_service_->ResolveProxy(
- req.url, &proxy_info_,
+ req.url, net::LOAD_NORMAL, &proxy_info_,
base::Bind(&ResolveProxyMsgHelper::OnResolveProxyCompleted,
base::Unretained(this)),
- &req.pac_req, net::BoundNetLog());
+ &req.pac_req, NULL, net::BoundNetLog());
// Completed synchronously.
if (result != net::ERR_IO_PENDING)
diff --git a/chromium/content/browser/resolve_proxy_msg_helper.h b/chromium/content/browser/resolve_proxy_msg_helper.h
index 167d946e545..f076d97d64f 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper.h
+++ b/chromium/content/browser/resolve_proxy_msg_helper.h
@@ -38,14 +38,14 @@ class CONTENT_EXPORT ResolveProxyMsgHelper : public BrowserMessageFilter {
explicit ResolveProxyMsgHelper(net::ProxyService* proxy_service);
// BrowserMessageFilter implementation
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
void OnResolveProxy(const GURL& url, IPC::Message* reply_msg);
protected:
// Destruction cancels the current outstanding request, and clears the
// pending queue.
- virtual ~ResolveProxyMsgHelper();
+ ~ResolveProxyMsgHelper() override;
private:
// Callback for the ProxyService (bound to |callback_|).
diff --git a/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc b/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
index 023fe43567a..1a19018e711 100644
--- a/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
+++ b/chromium/content/browser/resolve_proxy_msg_helper_unittest.cc
@@ -18,10 +18,9 @@ namespace content {
// This ProxyConfigService always returns "http://pac" as the PAC url to use.
class MockProxyConfigService : public net::ProxyConfigService {
public:
- virtual void AddObserver(Observer* observer) OVERRIDE {}
- virtual void RemoveObserver(Observer* observer) OVERRIDE {}
- virtual ConfigAvailability GetLatestProxyConfig(
- net::ProxyConfig* results) OVERRIDE {
+ void AddObserver(Observer* observer) override {}
+ void RemoveObserver(Observer* observer) override {}
+ ConfigAvailability GetLatestProxyConfig(net::ProxyConfig* results) override {
*results = net::ProxyConfig::CreateFromCustomPacURL(GURL("http://pac"));
return CONFIG_VALID;
}
@@ -34,14 +33,14 @@ class TestResolveProxyMsgHelper : public ResolveProxyMsgHelper {
IPC::Listener* listener)
: ResolveProxyMsgHelper(proxy_service),
listener_(listener) {}
- virtual bool Send(IPC::Message* message) OVERRIDE {
+ bool Send(IPC::Message* message) override {
listener_->OnMessageReceived(*message);
delete message;
return true;
}
protected:
- virtual ~TestResolveProxyMsgHelper() {}
+ ~TestResolveProxyMsgHelper() override {}
IPC::Listener* listener_;
};
@@ -87,7 +86,7 @@ class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener {
scoped_ptr<PendingResult> pending_result_;
private:
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
+ bool OnMessageReceived(const IPC::Message& msg) override {
TupleTypes<ViewHostMsg_ResolveProxy::ReplyParam>::ValueTuple reply_data;
EXPECT_TRUE(ViewHostMsg_ResolveProxy::ReadReplyParam(&msg, &reply_data));
DCHECK(!pending_result_.get());
diff --git a/chromium/content/browser/resource_context_impl.cc b/chromium/content/browser/resource_context_impl.cc
index 14115a4887c..f9f3bc890a7 100644
--- a/chromium/content/browser/resource_context_impl.cc
+++ b/chromium/content/browser/resource_context_impl.cc
@@ -94,8 +94,11 @@ StreamContext* GetStreamContextForResourceContext(
HostZoomMap* GetHostZoomMapForResourceContext(ResourceContext* context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- return static_cast<NonOwningZoomData*>(
- context->GetUserData(kHostZoomMapKeyName))->host_zoom_map();
+ NonOwningZoomData* result = static_cast<NonOwningZoomData*>(
+ context->GetUserData(kHostZoomMapKeyName));
+ if (!result)
+ return NULL;
+ return result->host_zoom_map();
}
URLDataManagerBackend* GetURLDataManagerForResourceContext(
@@ -128,7 +131,7 @@ void InitializeResourceContext(BrowserContext* browser_context) {
resource_context->SetUserData(
kHostZoomMapKeyName,
new NonOwningZoomData(
- HostZoomMap::GetForBrowserContext(browser_context)));
+ HostZoomMap::GetDefaultForBrowserContext(browser_context)));
resource_context->DetachUserDataThread();
}
diff --git a/chromium/content/browser/resources/gpu/gpu_internals.html b/chromium/content/browser/resources/gpu/gpu_internals.html
index a54861b404a..709af4326f9 100644
--- a/chromium/content/browser/resources/gpu/gpu_internals.html
+++ b/chromium/content/browser/resources/gpu/gpu_internals.html
@@ -40,6 +40,7 @@ tabbox tabpanels {
<script src="chrome://resources/js/cr/ui.js"></script>
<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
<script src="chrome://resources/js/cr/ui/tabs.js"></script>
+<script src="chrome://resources/js/load_time_data.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="gpu_internals.js"></script>
<script src="strings.js"></script>
@@ -48,8 +49,7 @@ tabbox tabpanels {
<div id="debug-div">
</div>
<include src="info_view.html">
- <script src="chrome://resources/js/i18n_template.js"></script>
- <script src="chrome://resources/js/i18n_process.js"></script>
+ <script src="chrome://resources/js/i18n_template2.js"></script>
<script src="chrome://resources/js/jstemplate_compiled.js"></script>
</body>
</html>
diff --git a/chromium/content/browser/resources/gpu/info_view.css b/chromium/content/browser/resources/gpu/info_view.css
index b78ab1974a6..39e8d6b6e7f 100644
--- a/chromium/content/browser/resources/gpu/info_view.css
+++ b/chromium/content/browser/resources/gpu/info_view.css
@@ -19,12 +19,12 @@
#info-view h3,
#info-view ul {
- -webkit-margin-after: 0;
- -webkit-margin-before: 0;
+ margin-bottom: 0;
+ margin-top: 0;
}
#info-view > div {
- -webkit-margin-after: 1em;
+ margin-bottom: 1em;
}
#info-view .row-title {
diff --git a/chromium/content/browser/resources/gpu/info_view.js b/chromium/content/browser/resources/gpu/info_view.js
index 2dbe5a174b2..e4d1795cf99 100644
--- a/chromium/content/browser/resources/gpu/info_view.js
+++ b/chromium/content/browser/resources/gpu/info_view.js
@@ -94,6 +94,7 @@ cr.define('gpu', function() {
'panel_fitting': 'Panel Fitting',
'rasterization': 'Rasterization',
'threaded_rasterization': 'Threaded Rasterization',
+ 'multiple_raster_threads': 'Multiple Raster Threads',
};
var statusMap = {
@@ -101,10 +102,6 @@ cr.define('gpu', function() {
'label': 'Software only. Hardware acceleration disabled',
'class': 'feature-yellow'
},
- 'disabled_software_threaded': {
- 'label': 'Software only, threaded. Hardware acceleration disabled',
- 'class': 'feature-yellow'
- },
'disabled_off': {
'label': 'Disabled',
'class': 'feature-red'
@@ -117,10 +114,6 @@ cr.define('gpu', function() {
'label': 'Software only, hardware acceleration unavailable',
'class': 'feature-yellow'
},
- 'unavailable_software_threaded': {
- 'label': 'Software only, threaded. Hardware acceleration unavailable',
- 'class': 'feature-yellow'
- },
'unavailable_off': {
'label': 'Unavailable',
'class': 'feature-red'
@@ -137,10 +130,6 @@ cr.define('gpu', function() {
'label': 'Hardware accelerated on all pages',
'class': 'feature-green'
},
- 'enabled_threaded': {
- 'label': 'Hardware accelerated and threaded',
- 'class': 'feature-green'
- },
'enabled': {
'label': 'Hardware accelerated',
'class': 'feature-green'
@@ -148,7 +137,11 @@ cr.define('gpu', function() {
'enabled_on': {
'label': 'Enabled',
'class': 'feature-green'
- }
+ },
+ 'enabled_force_on': {
+ 'label': 'Force enabled',
+ 'class': 'feature-green'
+ },
};
// GPU info, basic
diff --git a/chromium/content/browser/resources/gpu/timeline_test.html b/chromium/content/browser/resources/gpu/timeline_test.html
index e21f90e705e..107840a8dd8 100644
--- a/chromium/content/browser/resources/gpu/timeline_test.html
+++ b/chromium/content/browser/resources/gpu/timeline_test.html
@@ -8,7 +8,7 @@ found in the LICENSE file.
<head>
<title></title>
<link rel="stylesheet" href="timeline.css">
-<!--<script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>-->
+<!--<script src="https://cdn.rawgit.com/google/closure-library/master/closure/goog/base.js"></script>-->
<script src="../../../../ui/webui/resources/js/cr.js"></script>
<script src="../../../../ui/webui/resources/js/cr/event_target.js"></script>
<script src="../../../../ui/webui/resources/js/cr/ui.js"></script>
diff --git a/chromium/content/browser/resources/indexed_db/OWNERS b/chromium/content/browser/resources/indexed_db/OWNERS
index b106dad853f..95724907398 100644
--- a/chromium/content/browser/resources/indexed_db/OWNERS
+++ b/chromium/content/browser/resources/indexed_db/OWNERS
@@ -1,4 +1,3 @@
dgrogan@chromium.org
michaeln@chromium.org
jsbell@chromium.org
-alecflett@chromium.org
diff --git a/chromium/content/browser/resources/indexed_db/indexeddb_internals.html b/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
index bf7fa1ce78a..f389e9fbc89 100644
--- a/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
+++ b/chromium/content/browser/resources/indexed_db/indexeddb_internals.html
@@ -13,8 +13,13 @@
<div id="indexeddb-list-template"
jsvalues="$partition_path:$this.partition_path">
<div class="indexeddb-summary">
- <span>Instances in: </span>
- <span jscontent="$this.partition_path"></span>
+ <span jsdisplay="$this.partition_path">
+ <span>Instances in: </span>
+ <span jscontent="$this.partition_path"></span>
+ </span>
+ <span jsdisplay="!$this.partition_path">
+ <span>Instances: Incognito </span>
+ </span>
<span jscontent="'(' + $this.idbs.length + ')'"></span>
</div>
<div class="indexeddb-item" jsselect="$this.idbs">
@@ -181,4 +186,3 @@
<script src="chrome://resources/js/i18n_template2.js"></script>
</body>
</html>
-
diff --git a/chromium/content/browser/resources/media/OWNERS b/chromium/content/browser/resources/media/OWNERS
index bcb6c2496fd..ad545785604 100644
--- a/chromium/content/browser/resources/media/OWNERS
+++ b/chromium/content/browser/resources/media/OWNERS
@@ -1,8 +1,6 @@
-acolwell@chromium.org
dalecurtis@chromium.org
ddorwin@chromium.org
scherkus@chromium.org
-shadi@chromium.org
tommi@chromium.org
vrk@chromium.org
wjia@chromium.org
diff --git a/chromium/content/browser/resources/media/client_renderer.js b/chromium/content/browser/resources/media/client_renderer.js
index 5cdedaabb47..0eedb35df46 100644
--- a/chromium/content/browser/resources/media/client_renderer.js
+++ b/chromium/content/browser/resources/media/client_renderer.js
@@ -122,6 +122,67 @@ var ClientRenderer = (function() {
}
},
+ createVideoCaptureFormatTable: function(formats) {
+ if (!formats || formats.length == 0)
+ return document.createTextNode('No formats');
+
+ var table = document.createElement('table');
+ var thead = document.createElement('thead');
+ var theadRow = document.createElement('tr');
+ for (var key in formats[0]) {
+ var th = document.createElement('th');
+ th.appendChild(document.createTextNode(key));
+ theadRow.appendChild(th);
+ }
+ thead.appendChild(theadRow);
+ table.appendChild(thead);
+ var tbody = document.createElement('tbody');
+ for (var i=0; i < formats.length; ++i) {
+ var tr = document.createElement('tr')
+ for (var key in formats[i]) {
+ var td = document.createElement('td');
+ td.appendChild(document.createTextNode(formats[i][key]));
+ tr.appendChild(td);
+ }
+ tbody.appendChild(tr);
+ }
+ table.appendChild(tbody);
+ table.classList.add('video-capture-formats-table');
+ return table;
+ },
+
+ redrawVideoCaptureCapabilities: function(videoCaptureCapabilities, keys) {
+ var copyButtonElement =
+ document.getElementById('video-capture-capabilities-copy-button');
+ copyButtonElement.onclick = function() {
+ window.prompt('Copy to clipboard: Ctrl+C, Enter',
+ JSON.stringify(videoCaptureCapabilities))
+ }
+
+ var videoTableBodyElement =
+ document.getElementById('video-capture-capabilities-tbody');
+ removeChildren(videoTableBodyElement);
+
+ for (var component in videoCaptureCapabilities) {
+ var tableRow = document.createElement('tr');
+ var device = videoCaptureCapabilities[ component ];
+ for (var i in keys) {
+ var value = device[keys[i]];
+ var tableCell = document.createElement('td');
+ var cellElement;
+ if ((typeof value) == (typeof [])) {
+ cellElement = this.createVideoCaptureFormatTable(value);
+ } else {
+ cellElement = document.createTextNode(
+ ((typeof value) == 'undefined') ? 'n/a' : value);
+ }
+ tableCell.appendChild(cellElement)
+ tableRow.appendChild(tableCell);
+ }
+ videoTableBodyElement.appendChild(tableRow);
+ }
+ },
+
redrawAudioComponentList_: function(componentType, components) {
function redrawList(renderer, baseName, element) {
var fragment = document.createDocumentFragment();
diff --git a/chromium/content/browser/resources/media/disjoint_range_set_test.html b/chromium/content/browser/resources/media/disjoint_range_set_test.html
index 39db9b34b45..7f2d128a79d 100644
--- a/chromium/content/browser/resources/media/disjoint_range_set_test.html
+++ b/chromium/content/browser/resources/media/disjoint_range_set_test.html
@@ -7,7 +7,7 @@ found in the LICENSE file.
-->
<head>
<title></title>
- <script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
+ <script src="https://cdn.rawgit.com/google/closure-library/master/closure/goog/base.js"></script>
<script src="../../../../ui/webui/resources/js/cr.js"></script>
<script src="disjoint_range_set.js"></script>
<script>
diff --git a/chromium/content/browser/resources/media/dump_creator.js b/chromium/content/browser/resources/media/dump_creator.js
index 24f6d6a18fa..15d708b3daf 100644
--- a/chromium/content/browser/resources/media/dump_creator.js
+++ b/chromium/content/browser/resources/media/dump_creator.js
@@ -40,11 +40,11 @@ var DumpCreator = (function() {
' 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. Recordings in multiple tabs is supported as well as multiple' +
- ' recordings in the same tab. When enabling, you select a base' +
- ' filename to save the dump(s) to. The base filename will have a' +
- ' suffix appended to it as &lt;base filename&gt;.&lt;unique ID for' +
- ' the render process&gt;.&lt;recording ID&gt;. If recordings are' +
+ ' calls. Recordings in multiple tabs are supported as well as' +
+ ' multiple recordings in the same tab. When enabling, you select a' +
+ ' base filename to save the dump(s) to. The base filename will have a' +
+ ' suffix appended to it as &lt;base filename&gt;.&lt;render process' +
+ ' ID&gt;.&lt;recording ID&gt;. If recordings are' +
' disabled and then enabled using the same base filename, the' +
' file(s) will be appended to and may become invalid. It is' +
' recommended to choose a new base filename each time or move' +
@@ -86,7 +86,9 @@ var DumpCreator = (function() {
{type: 'octet/stream'});
var URL = window.URL.createObjectURL(textBlob);
- this.root_.getElementsByTagName('a')[0].href = URL;
+ var anchor = this.root_.getElementsByTagName('a')[0];
+ anchor.href = URL;
+ anchor.download = 'webrtc_internals_dump.txt';
// The default action of the anchor will download the URL.
},
diff --git a/chromium/content/browser/resources/media/main.js b/chromium/content/browser/resources/media/main.js
index cb239da2d54..7045197ebe9 100644
--- a/chromium/content/browser/resources/media/main.js
+++ b/chromium/content/browser/resources/media/main.js
@@ -39,12 +39,16 @@ var media = (function() {
manager = theManager;
};
- media.onReceiveEverything = function(everything) {
- for (var component in everything) {
- media.updateAudioComponent(everything[component]);
+ media.onReceiveAudioStreamData = function(audioStreamData) {
+ for (var component in audioStreamData) {
+ media.updateAudioComponent(audioStreamData[component]);
}
};
+ media.onReceiveVideoCaptureCapabilities = function(videoCaptureCapabilities) {
+ manager.updateVideoCaptureCapabilities(videoCaptureCapabilities)
+ }
+
media.onReceiveConstants = function(constants) {
for (var key in constants.eventTypes) {
var value = constants.eventTypes[key];
diff --git a/chromium/content/browser/resources/media/manager.js b/chromium/content/browser/resources/media/manager.js
index 80cd03273b7..5508c66cd79 100644
--- a/chromium/content/browser/resources/media/manager.js
+++ b/chromium/content/browser/resources/media/manager.js
@@ -109,6 +109,49 @@ var Manager = (function() {
this.players_[id],
key,
value);
+ },
+
+ parseVideoCaptureFormat_: function(format) {
+ /**
+ * Example:
+ *
+ * format:
+ * "resolution: 1280x720, fps: 30.000000, pixel format: I420"
+ *
+ * formatDict:
+ * {'resolution':'1280x720', 'fps': '30.00'}
+ */
+ var parts = format.split(', ');
+ var formatDict = {};
+ for (var i in parts) {
+ var kv = parts[i].split(': ');
+ formatDict[kv[0]] = kv[1];
+ }
+
+ // Round down the FPS to 2 decimals.
+ formatDict['fps'] = parseFloat(formatDict['fps']).toFixed(2);
+
+ // The camera does not actually output I420 so this info is misleading.
+ delete formatDict['pixel format'];
+
+ return formatDict;
+ },
+
+ updateVideoCaptureCapabilities: function(videoCaptureCapabilities) {
+ // Parse the video formats to be structured for the table.
+ for (var i in videoCaptureCapabilities) {
+ for (var j in videoCaptureCapabilities[i]['formats']) {
+ videoCaptureCapabilities[i]['formats'][j] =
+ this.parseVideoCaptureFormat_(
+ videoCaptureCapabilities[i]['formats'][j]);
+ }
+ }
+
+ // The keys of each device to be shown in order of appearance.
+ var videoCaptureDeviceKeys = ['name','formats','captureApi','id'];
+
+ this.clientRenderer_.redrawVideoCaptureCapabilities(
+ videoCaptureCapabilities, videoCaptureDeviceKeys);
}
};
diff --git a/chromium/content/browser/resources/media/media_internals.css b/chromium/content/browser/resources/media/media_internals.css
index 041527f951c..0165c3f4010 100644
--- a/chromium/content/browser/resources/media/media_internals.css
+++ b/chromium/content/browser/resources/media/media_internals.css
@@ -9,6 +9,7 @@ body,
padding: 0;
width: 100%;
height: 100%;
+ font-family:Arial;
}
table {
@@ -86,6 +87,12 @@ h3 {
#property-wrapper,
#log-wrapper {
display:block;
+ flex-grow: 0.25;
+ align-self: stretch;
+ overflow: auto;
+}
+
+#video-capture-capabilities-wrapper {
flex-grow: 0.5;
align-self: stretch;
overflow: auto;
@@ -114,4 +121,39 @@ h3 {
.timestamp {
min-width: 115px;
-} \ No newline at end of file
+}
+
+#video-capture-capabilities-table {
+ margin-bottom:30px;
+}
+
+#video-capture-capabilities-table th,
+#video-capture-capabilities-table td {
+ min-width:120px;
+}
+
+#video-capture-capabilities-table td {
+ padding:5px;
+}
+
+#video-capture-capabilities-table tr td {
+ font-size:13px;
+ text-align:center;
+}
+
+#video-capture-capabilities-table .video-capture-formats-table th,
+#video-capture-capabilities-table .video-capture-formats-table td {
+ text-align:right;
+ min-width:80px;
+}
+
+#video-capture-capabilities-table .video-capture-formats-table th {
+ background:none;
+ color:#666;
+ font-size:13px;
+ font-weight:bold;
+}
+
+#video-capture-capabilities-table .video-capture-formats-table td {
+ padding:2px;
+}
diff --git a/chromium/content/browser/resources/media/media_internals.html b/chromium/content/browser/resources/media/media_internals.html
index 1f762305598..d271082d2da 100644
--- a/chromium/content/browser/resources/media/media_internals.html
+++ b/chromium/content/browser/resources/media/media_internals.html
@@ -36,7 +36,7 @@ found in the LICENSE file.
<div id="property-wrapper">
<h2>
<span id="property-name"></span> Properties
- <button id="copy-button">copy to clipboard</button>
+ <button id="copy-button">Copy to clipboard</button>
</h2>
<table id="property-table">
<thead>
@@ -64,6 +64,24 @@ found in the LICENSE file.
<tbody></tbody>
</table>
</div>
+ <div id="video-capture-capabilities-wrapper">
+ <h2>Video Capture Device Capabilities</h2>
+ <button id="video-capture-capabilities-copy-button">
+ Copy to clipboard</button>
+ <table id="video-capture-capabilities-table">
+ <thead>
+ <tr>
+ <th>Device Name</th>
+ <th>Formats</th>
+ <th>Capture API</th>
+ <th>Device ID</th>
+ </tr>
+ </thead>
+ <tbody id="video-capture-capabilities-tbody">
+
+ <tbody>
+ </table>
+ </div>
</div>
<script src="media_internals.js"></script>
</body>
diff --git a/chromium/content/browser/resources/media/peer_connection_update_table.js b/chromium/content/browser/resources/media/peer_connection_update_table.js
index 0f4cc0cde90..f5e58b5be0c 100644
--- a/chromium/content/browser/resources/media/peer_connection_update_table.js
+++ b/chromium/content/browser/resources/media/peer_connection_update_table.js
@@ -81,7 +81,8 @@ var PeerConnectionUpdateTable = (function() {
var row = document.createElement('tr');
tableElement.firstChild.appendChild(row);
- row.innerHTML = '<td>' + (new Date()).toLocaleString() + '</td>';
+ var time = new Date(parseFloat(update.time));
+ row.innerHTML = '<td>' + time.toLocaleString() + '</td>';
if (update.value.length == 0) {
row.innerHTML += '<td>' + update.type + '</td>';
diff --git a/chromium/content/browser/resources/media/stats_table.js b/chromium/content/browser/resources/media/stats_table.js
index 418be756c65..07b5687fb33 100644
--- a/chromium/content/browser/resources/media/stats_table.js
+++ b/chromium/content/browser/resources/media/stats_table.js
@@ -114,7 +114,7 @@ var StatsTable = (function(ssrcInfoManager) {
* @private
*/
addStatsToTable_: function(statsTable, time, statsData) {
- var date = Date(time);
+ var date = new Date(time);
this.updateStatsTableRow_(statsTable, 'timestamp', date.toLocaleString());
for (var i = 0; i < statsData.length - 1; i = i + 2) {
this.updateStatsTableRow_(statsTable, statsData[i], statsData[i + 1]);
diff --git a/chromium/content/browser/resources/media/tab_view.js b/chromium/content/browser/resources/media/tab_view.js
index 6fc8d73410d..274336ee465 100644
--- a/chromium/content/browser/resources/media/tab_view.js
+++ b/chromium/content/browser/resources/media/tab_view.js
@@ -50,9 +50,9 @@ var TabView = (function() {
if (this.tabElements_[id])
throw 'Tab already exists: ' + id;
- var head = document.createElement('div');
+ var head = document.createElement('span');
head.className = this.TAB_HEAD_CLASS_;
- head.textContent = title + ' [' + id + ']';
+ head.textContent = title;
head.title = title;
this.headBar_.appendChild(head);
head.addEventListener('click', this.switchTab_.bind(this, id));
diff --git a/chromium/content/browser/resources/media/webrtc_internals.css b/chromium/content/browser/resources/media/webrtc_internals.css
index cc976ebd931..e98d3995e98 100644
--- a/chromium/content/browser/resources/media/webrtc_internals.css
+++ b/chromium/content/browser/resources/media/webrtc_internals.css
@@ -88,8 +88,9 @@ th {
text-decoration: underline;
cursor: pointer;
display: inline-block;
- word-break: break-all;
+ overflow: hidden;
width: 20em;
+ height: 3em;
}
.active-tab-head {
@@ -107,3 +108,12 @@ th {
.active-tab-body {
display: block;
}
+
+.user-media-request-div-class {
+ background-color: lightgray;
+ margin: 10px 0 10px 0;
+}
+
+.user-media-request-div-class > div {
+ margin: 5px 0 5px 0;
+}
diff --git a/chromium/content/browser/resources/media/webrtc_internals.js b/chromium/content/browser/resources/media/webrtc_internals.js
index 52ab9f711f4..3a1f9cd25c1 100644
--- a/chromium/content/browser/resources/media/webrtc_internals.js
+++ b/chromium/content/browser/resources/media/webrtc_internals.js
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+var USER_MEDIA_TAB_ID = 'user-media-tab-id';
+
var tabView = null;
var ssrcInfoManager = null;
var peerConnectionUpdateTable = null;
@@ -19,7 +21,7 @@ var PeerConnectionRecord = (function() {
/** @private */
this.record_ = {
constraints: {},
- servers: [],
+ rtcConfiguration: [],
stats: {},
updateLog: [],
url: '',
@@ -35,12 +37,12 @@ var PeerConnectionRecord = (function() {
/**
* Adds the initilization info of the peer connection.
* @param {string} url The URL of the web page owning the peer connection.
- * @param {Array} servers STUN servers used by the peer connection.
+ * @param {Array} rtcConfiguration
* @param {!Object} constraints Media constraints.
*/
- initialize: function(url, servers, constraints) {
+ initialize: function(url, rtcConfiguration, constraints) {
this.record_.url = url;
- this.record_.servers = servers;
+ this.record_.rtcConfiguration = rtcConfiguration;
this.record_.constraints = constraints;
},
@@ -61,14 +63,15 @@ var PeerConnectionRecord = (function() {
},
/**
- * @param {string} type The type of the update.
- * @param {string} value The value of the update.
+ * @param {!Object} update The object contains keys "time", "type", and
+ * "value".
*/
- addUpdate: function(type, value) {
+ addUpdate: function(update) {
+ var time = new Date(parseFloat(update.time));
this.record_.updateLog.push({
- time: (new Date()).toLocaleString(),
- type: type,
- value: value,
+ time: time.toLocaleString(),
+ type: update.type,
+ value: update.value,
});
},
};
@@ -137,6 +140,21 @@ function extractSsrcInfo(data) {
/**
+ * A helper function for appending a child element to |parent|.
+ *
+ * @param {!Element} parent The parent element.
+ * @param {string} tag The child element tag.
+ * @param {string} text The textContent of the new DIV.
+ * @return {!Element} the new DIV element.
+ */
+function appendChildWithText(parent, tag, text) {
+ var child = document.createElement(tag);
+ child.textContent = text;
+ parent.appendChild(child);
+ return child;
+}
+
+/**
* Helper for adding a peer connection update.
*
* @param {Element} peerConnectionElement
@@ -146,8 +164,7 @@ function addPeerConnectionUpdate(peerConnectionElement, update) {
peerConnectionUpdateTable.addPeerConnectionUpdate(peerConnectionElement,
update);
extractSsrcInfo(update);
- peerConnectionDataStore[peerConnectionElement.id].addUpdate(
- update.type, update.value);
+ peerConnectionDataStore[peerConnectionElement.id].addUpdate(update);
}
@@ -172,8 +189,8 @@ function removePeerConnection(data) {
/**
* Adds a peer connection.
*
- * @param {!Object} data The object containing the pid, lid, url, servers, and
- * constraints of a peer connection.
+ * @param {!Object} data The object containing the pid, lid, url,
+ * rtcConfiguration, and constraints of a peer connection.
*/
function addPeerConnection(data) {
var id = getPeerConnectionId(data);
@@ -182,14 +199,14 @@ function addPeerConnection(data) {
peerConnectionDataStore[id] = new PeerConnectionRecord();
}
peerConnectionDataStore[id].initialize(
- data.url, data.servers, data.constraints);
+ data.url, data.rtcConfiguration, data.constraints);
var peerConnectionElement = $(id);
if (!peerConnectionElement) {
- peerConnectionElement = tabView.addTab(id, data.url);
+ peerConnectionElement = tabView.addTab(id, data.url + ' [' + id + ']');
}
peerConnectionElement.innerHTML =
- '<p>' + data.url + ' ' + data.servers + ' ' + data.constraints +
+ '<p>' + data.url + ' ' + data.rtcConfiguration + ' ' + data.constraints +
'</p>';
return peerConnectionElement;
@@ -211,7 +228,7 @@ function updatePeerConnection(data) {
* Adds the information of all peer connections created so far.
*
* @param {Array.<!Object>} data An array of the information of all peer
- * connections. Each array item contains pid, lid, url, servers,
+ * connections. Each array item contains pid, lid, url, rtcConfiguration,
* constraints, and an array of updates as the log.
*/
function updateAllPeerConnections(data) {
@@ -258,8 +275,26 @@ function addStats(data) {
* origin {string}, audio {string}, video {string}.
*/
function addGetUserMedia(data) {
- // TODO(jiayl): add the getUserMedia info to the tabbed UI.
userMediaRequests.push(data);
+
+ if (!$(USER_MEDIA_TAB_ID)) {
+ tabView.addTab(USER_MEDIA_TAB_ID, 'GetUserMedia Requests');
+ }
+
+ var requestDiv = document.createElement('div');
+ requestDiv.className = 'user-media-request-div-class';
+ requestDiv.rid = data.rid;
+ $(USER_MEDIA_TAB_ID).appendChild(requestDiv);
+
+ appendChildWithText(requestDiv, 'div', 'Caller origin: ' + data.origin);
+ appendChildWithText(requestDiv, 'div', 'Caller process id: ' + data.pid);
+ appendChildWithText(requestDiv, 'span', 'Audio Constraints').style.fontWeight
+ = 'bold';
+ appendChildWithText(requestDiv, 'div', data.audio);
+
+ appendChildWithText(requestDiv, 'span', 'Video Constraints').style.fontWeight
+ = 'bold';
+ appendChildWithText(requestDiv, 'div', data.video);
}
@@ -269,11 +304,19 @@ function addGetUserMedia(data) {
* @param {!Object} data The object containing rid {number}, the render id.
*/
function removeGetUserMediaForRenderer(data) {
- // TODO(jiayl): remove the getUserMedia info from the tabbed UI.
for (var i = userMediaRequests.length - 1; i >= 0; --i) {
if (userMediaRequests[i].rid == data.rid)
userMediaRequests.splice(i, 1);
}
+
+ var requests = $(USER_MEDIA_TAB_ID).childNodes;
+ for (var i = 0; i < requests.length; ++i) {
+ if (requests[i].rid == data.rid)
+ $(USER_MEDIA_TAB_ID).removeChild(requests[i]);
+
+ }
+ if ($(USER_MEDIA_TAB_ID).childNodes.length == 0)
+ tabView.removeTab(USER_MEDIA_TAB_ID);
}
diff --git a/chromium/content/browser/resources/service_worker/OWNERS b/chromium/content/browser/resources/service_worker/OWNERS
index a143cc76541..df9c7767103 100644
--- a/chromium/content/browser/resources/service_worker/OWNERS
+++ b/chromium/content/browser/resources/service_worker/OWNERS
@@ -1,5 +1,7 @@
michaeln@chromium.org
horo@chromium.org
+falken@chromium.org
+nhiroki@chromium.org
# may not be available
kinuko@chromium.org
diff --git a/chromium/content/browser/resources/service_worker/serviceworker_internals.css b/chromium/content/browser/resources/service_worker/serviceworker_internals.css
index 0ac2528098c..760c993ab16 100644
--- a/chromium/content/browser/resources/service_worker/serviceworker_internals.css
+++ b/chromium/content/browser/resources/service_worker/serviceworker_internals.css
@@ -24,12 +24,9 @@
.serviceworker-scope {
color: rgb(85, 102, 221);
display: inline-block;
- max-width: 500px;
- overflow: hidden;
padding-bottom: 1px;
padding-top: 4px;
text-decoration: none;
- text-overflow: ellipsis;
white-space: nowrap;
}
diff --git a/chromium/content/browser/resources/service_worker/serviceworker_internals.html b/chromium/content/browser/resources/service_worker/serviceworker_internals.html
index 85e70454664..8c4e6afbd58 100644
--- a/chromium/content/browser/resources/service_worker/serviceworker_internals.html
+++ b/chromium/content/browser/resources/service_worker/serviceworker_internals.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!DOCTYPE html>
<html i18n-values="dir:textdirection;">
<head>
<meta charset="utf-8">
@@ -19,6 +19,10 @@
<span>Running Status:</span>
<span jscontent="$this.running_status"></span>
</div>
+ <div class="serviceworker-script_url">
+ <span>Script:</span>
+ <span jscontent="$this.script_url"></span>
+ </div>
<div class="serviceworker-vid">
<span>Version ID:</span>
<span jscontent="$this.version_id"></span>
@@ -63,10 +67,6 @@
<span>Scope:</span>
<span jscontent="scope"></span>
</div>
- <div class="serviceworker-script_url">
- <span>Script:</span>
- <span jscontent="script_url"></span>
- </div>
<div class="serviceworker-rid">
<span>Registration ID:</span>
<span jscontent="registration_id"></span>
@@ -97,8 +97,13 @@
jsvalues="$partition_id:$this.partition_id;.partition_id:$this.partition_id"
jsdisplay="$this.stored_registrations.length + $this.unregistered_registrations.length + $this.unregistered_versions.length > 0">
<div class="serviceworker-summary">
- <span>Registrations in: </span>
- <span jscontent="$this.partition_path"></span>
+ <span jsdisplay="$this.partition_path">
+ <span>Registrations in: </span>
+ <span jscontent="$this.partition_path"></span>
+ </span>
+ <span jsdisplay="!$this.partition_path">
+ <span>Registrations: Incognito </span>
+ </span>
<span jscontent="'(' + $this.stored_registrations.length + ')'"></span>
</div>
<div class="serviceworker-item" jsselect="$this.stored_registrations">
@@ -115,13 +120,15 @@
</div>
<div id="serviceworker-options-template">
<div>
- <span>
- <input type="checkbox" class="debug_on_start"
- jsvalues=".checked:$this.debug_on_start">
- </span>
- <span>
- Opens the DevTools window for ServiceWorker on start for debugging.
- </span>
+ <label>
+ <span>
+ <input type="checkbox" class="debug_on_start"
+ jsvalues=".checked:$this.debug_on_start">
+ </span>
+ <span>
+ Opens the DevTools window for ServiceWorker on start for debugging.
+ </span>
+ </label>
</div>
</div>
</div>
diff --git a/chromium/content/browser/resources/service_worker/serviceworker_internals.js b/chromium/content/browser/resources/service_worker/serviceworker_internals.js
index 5e698b80d5c..93bf437fbc5 100644
--- a/chromium/content/browser/resources/service_worker/serviceworker_internals.js
+++ b/chromium/content/browser/resources/service_worker/serviceworker_internals.js
@@ -6,20 +6,9 @@ cr.define('serviceworker', function() {
'use strict';
function initialize() {
- if (window.location.hash == "#iframe") {
- // This page is loaded from chrome://inspect.
- window.addEventListener('message', onMessage.bind(this), false);
- }
update();
}
- function onMessage(event) {
- if (event.origin != 'chrome://inspect') {
- return;
- }
- sendCommand(event.data.action, event.data.worker);
- }
-
function update() {
chrome.send('GetOptions');
chrome.send('getAllRegistrations');
@@ -85,34 +74,9 @@ cr.define('serviceworker', function() {
update();
}
- // Send the active ServiceWorker information to chrome://inspect.
- function sendToInspectPage(live_registrations,
- partition_id) {
- var workers = [];
- live_registrations.forEach(function(registration) {
- [registration.active, registration.waiting].forEach(function(version) {
- if (!version || version.running_status != 'RUNNING') {
- return;
- }
- workers.push({
- 'scope': registration.scope,
- 'url': registration.script_url,
- 'partition_id': partition_id,
- 'version_id': version.version_id,
- 'process_id': version.process_id,
- 'devtools_agent_route_id':
- version.devtools_agent_route_id
- });
- });
- });
- window.parent.postMessage(
- {'partition_id': partition_id, 'workers': workers},
- 'chrome://inspect');
- }
-
var allLogMessages = {};
// Set log for a worker version.
- function fillLogForVersion(partition_id, version) {
+ function fillLogForVersion(container, partition_id, version) {
if (!version) {
return;
}
@@ -125,6 +89,14 @@ cr.define('serviceworker', function() {
} else {
version.log = '';
}
+ var logAreas = container.querySelectorAll('textarea.serviceworker-log');
+ for (var i = 0; i < logAreas.length; ++i) {
+ var logArea = logAreas[i];
+ if (logArea.partition_id == partition_id &&
+ logArea.version_id == version.version_id) {
+ logArea.value = version.log;
+ }
+ }
}
// Get the unregistered workers.
@@ -171,11 +143,6 @@ cr.define('serviceworker', function() {
stored_registrations,
partition_id,
partition_path) {
- if (window.location.hash == "#iframe") {
- // This page is loaded from chrome://inspect.
- sendToInspectPage(live_registrations, partition_id);
- return;
- }
var unregistered_registrations = [];
var unregistered_versions = [];
getUnregisteredWorkers(stored_registrations,
@@ -198,7 +165,7 @@ cr.define('serviceworker', function() {
template = jstGetTemplate('serviceworker-list-template');
container.appendChild(template);
}
- var fillLogFunc = fillLogForVersion.bind(this, partition_id);
+ var fillLogFunc = fillLogForVersion.bind(this, container, partition_id);
stored_registrations.forEach(function(registration) {
[registration.active, registration.waiting].forEach(fillLogFunc);
});
@@ -280,7 +247,7 @@ cr.define('serviceworker', function() {
for (var i = 0; i < logAreas.length; ++i) {
var logArea = logAreas[i];
if (logArea.partition_id == partition_id &&
- logArea.version_id == version_id) {
+ logArea.version_id == version_id) {
logArea.value += message;
}
}
diff --git a/chromium/content/browser/safe_util_win.cc b/chromium/content/browser/safe_util_win.cc
index e5843fd2bca..2a1f18c7679 100644
--- a/chromium/content/browser/safe_util_win.cc
+++ b/chromium/content/browser/safe_util_win.cc
@@ -9,7 +9,6 @@
#include "base/files/file_path.h"
#include "base/logging.h"
-#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_comptr.h"
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc b/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc
new file mode 100644
index 00000000000..33b026cf5bb
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -0,0 +1,239 @@
+// 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 <stdlib.h>
+
+#include "base/command_line.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/common/view_messages.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.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/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/common/shell_switches.h"
+#include "third_party/WebKit/public/platform/WebScreenInfo.h"
+#include "ui/compositor/compositor_switches.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif // OS_WIN
+
+namespace content {
+
+class ScreenOrientationBrowserTest : public ContentBrowserTest {
+ public:
+ ScreenOrientationBrowserTest() {
+ }
+
+ void SetUp() override {
+ // Painting has to happen otherwise the Resize messages will be added on top
+ // of each other without properly ack-painting which will fail and crash.
+ UseSoftwareCompositing();
+
+ ContentBrowserTest::SetUp();
+ }
+
+ protected:
+ void SendFakeScreenOrientation(unsigned angle, const std::string& strType) {
+ RenderWidgetHost* rwh = shell()->web_contents()->GetRenderWidgetHostView()
+ ->GetRenderWidgetHost();
+ blink::WebScreenInfo screen_info;
+ rwh->GetWebScreenInfo(&screen_info);
+ screen_info.orientationAngle = angle;
+
+ blink::WebScreenOrientationType type = blink::WebScreenOrientationUndefined;
+ if (strType == "portrait-primary") {
+ type = blink::WebScreenOrientationPortraitPrimary;
+ } else if (strType == "portrait-secondary") {
+ type = blink::WebScreenOrientationPortraitSecondary;
+ } else if (strType == "landscape-primary") {
+ type = blink::WebScreenOrientationLandscapePrimary;
+ } else if (strType == "landscape-secondary") {
+ type = blink::WebScreenOrientationLandscapeSecondary;
+ }
+ ASSERT_NE(blink::WebScreenOrientationUndefined, type);
+ screen_info.orientationType = type;
+
+ ViewMsg_Resize_Params params;
+ params.screen_info = screen_info;
+ params.new_size = gfx::Size(0, 0);
+ params.physical_backing_size = gfx::Size(300, 300);
+ params.top_controls_layout_height = 0.f;
+ params.resizer_rect = gfx::Rect();
+ params.is_fullscreen = false;
+ rwh->Send(new ViewMsg_Resize(rwh->GetRoutingID(), params));
+ }
+
+ int GetOrientationAngle() {
+ int angle;
+ ExecuteScriptAndGetValue(shell()->web_contents()->GetMainFrame(),
+ "screen.orientation.angle")->GetAsInteger(&angle);
+ return angle;
+ }
+
+ std::string GetOrientationType() {
+ std::string type;
+ ExecuteScriptAndGetValue(shell()->web_contents()->GetMainFrame(),
+ "screen.orientation.type")->GetAsString(&type);
+ return type;
+ }
+
+ bool ScreenOrientationSupported() {
+ bool support;
+ ExecuteScriptAndGetValue(shell()->web_contents()->GetMainFrame(),
+ "'orientation' in screen")->GetAsBoolean(&support);
+ return support;
+ }
+
+ bool WindowOrientationSupported() {
+ bool support;
+ ExecuteScriptAndGetValue(shell()->web_contents()->GetMainFrame(),
+ "'orientation' in window")->GetAsBoolean(&support);
+ return support;
+ }
+
+ int GetWindowOrientationAngle() {
+ int angle;
+ ExecuteScriptAndGetValue(shell()->web_contents()->GetMainFrame(),
+ "window.orientation")->GetAsInteger(&angle);
+ return angle;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScreenOrientationBrowserTest);
+};
+
+// This test doesn't work on MacOS X but the reason is mostly because it is not
+// used Aura. It could be set as !defined(OS_MACOSX) but the rule below will
+// actually support MacOS X if and when it switches to Aura.
+#if defined(USE_AURA) || defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, ScreenOrientationChange) {
+ std::string types[] = { "portrait-primary",
+ "portrait-secondary",
+ "landscape-primary",
+ "landscape-secondary" };
+ GURL test_url = GetTestUrl("screen_orientation",
+ "screen_orientation_screenorientationchange.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+#if USE_AURA
+ WaitForResizeComplete(shell()->web_contents());
+#endif // USE_AURA
+
+#if defined(OS_WIN)
+ // Screen Orientation is currently disabled on Windows 8.
+ // This test will break, requiring an update when the API will be enabled.
+ if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_WIN8) {
+ EXPECT_EQ(false, ScreenOrientationSupported());
+ return;
+ }
+#endif // defined(OS_WIN)
+
+ int angle = GetOrientationAngle();
+
+ for (int i = 0; i < 4; ++i) {
+ angle = (angle + 90) % 360;
+ SendFakeScreenOrientation(angle, types[i]);
+
+ TestNavigationObserver navigation_observer(shell()->web_contents());
+ navigation_observer.Wait();
+ EXPECT_EQ(angle, GetOrientationAngle());
+ EXPECT_EQ(types[i], GetOrientationType());
+ }
+}
+#endif // defined(USE_AURA) || defined(OS_ANDROID)
+
+IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, WindowOrientationChange) {
+ GURL test_url = GetTestUrl("screen_orientation",
+ "screen_orientation_windoworientationchange.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ shell()->LoadURL(test_url);
+ navigation_observer.Wait();
+#if USE_AURA
+ WaitForResizeComplete(shell()->web_contents());
+#endif // USE_AURA
+
+ if (!WindowOrientationSupported())
+ return;
+
+ int angle = GetWindowOrientationAngle();
+
+ for (int i = 0; i < 4; ++i) {
+ angle = (angle + 90) % 360;
+ SendFakeScreenOrientation(angle, "portrait-primary");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+ navigation_observer.Wait();
+ EXPECT_EQ(angle == 270 ? -90 : angle, GetWindowOrientationAngle());
+ }
+}
+
+// Chromium Android does not support fullscreen
+IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, LockSmoke) {
+ GURL test_url = GetTestUrl("screen_orientation",
+ "screen_orientation_lock_smoke.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 2);
+ shell()->LoadURL(test_url);
+
+#if defined(OS_WIN)
+ // Screen Orientation is currently disabled on Windows 8.
+ // This test will break, requiring an update when the API will be enabled.
+ if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_WIN8) {
+ EXPECT_EQ(false, ScreenOrientationSupported());
+ return;
+ }
+#endif // defined(OS_WIN)
+
+ navigation_observer.Wait();
+#if USE_AURA
+ WaitForResizeComplete(shell()->web_contents());
+#endif // USE_AURA
+
+ std::string expected =
+#if defined(OS_ANDROID)
+ "SecurityError"; // WebContents need to be fullscreen.
+#else
+ "NotSupportedError"; // Locking isn't supported.
+#endif
+
+ EXPECT_EQ(expected, shell()->web_contents()->GetLastCommittedURL().ref());
+}
+
+// Check that using screen orientation after a frame is detached doesn't crash
+// the renderer process.
+// This could be a LayoutTest if they were not using a mock screen orientation
+// controller.
+IN_PROC_BROWSER_TEST_F(ScreenOrientationBrowserTest, CrashTest_UseAfterDetach) {
+ GURL test_url = GetTestUrl("screen_orientation",
+ "screen_orientation_use_after_detach.html");
+
+ TestNavigationObserver navigation_observer(shell()->web_contents(), 2);
+ shell()->LoadURL(test_url);
+
+#if defined(OS_WIN)
+ // Screen Orientation is currently disabled on Windows 8.
+ // When implemented, this test will break, requiring an update.
+ if (base::win::OSInfo::GetInstance()->version() >= base::win::VERSION_WIN8) {
+ EXPECT_EQ(false, ScreenOrientationSupported());
+ return;
+ }
+#endif // defined(OS_WIN)
+
+ navigation_observer.Wait();
+
+ // This is a success if the renderer process did not crash, thus, we end up
+ // here.
+}
+
+} // namespace content
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.cc b/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.cc
new file mode 100644
index 00000000000..bb2f5bc61f9
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/screen_orientation/screen_orientation_delegate_android.h"
+
+#include "content/browser/android/content_view_core_impl.h"
+#include "jni/ScreenOrientationProvider_jni.h"
+
+namespace content {
+
+ScreenOrientationDelegateAndroid::ScreenOrientationDelegateAndroid() {
+}
+
+ScreenOrientationDelegateAndroid::~ScreenOrientationDelegateAndroid() {
+}
+
+// static
+bool ScreenOrientationDelegateAndroid::Register(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+// static
+void ScreenOrientationDelegateAndroid::StartAccurateListening() {
+ Java_ScreenOrientationProvider_startAccurateListening(
+ base::android::AttachCurrentThread());
+}
+
+// static
+void ScreenOrientationDelegateAndroid::StopAccurateListening() {
+ Java_ScreenOrientationProvider_stopAccurateListening(
+ base::android::AttachCurrentThread());
+}
+
+bool ScreenOrientationDelegateAndroid::FullScreenRequired(
+ WebContents* web_contents) {
+ ContentViewCoreImpl* cvc =
+ ContentViewCoreImpl::FromWebContents(web_contents);
+ bool fullscreen_required = cvc ? cvc->IsFullscreenRequiredForOrientationLock()
+ : true;
+ return fullscreen_required;
+}
+
+void ScreenOrientationDelegateAndroid::Lock(
+ blink::WebScreenOrientationLockType lock_orientation) {
+ Java_ScreenOrientationProvider_lockOrientation(
+ base::android::AttachCurrentThread(), lock_orientation);
+}
+
+bool ScreenOrientationDelegateAndroid::ScreenOrientationProviderSupported() {
+ // Always supported on Android
+ return true;
+}
+
+void ScreenOrientationDelegateAndroid::Unlock() {
+ Java_ScreenOrientationProvider_unlockOrientation(
+ base::android::AttachCurrentThread());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.h b/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.h
new file mode 100644
index 00000000000..fa3ee6e2211
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_delegate_android.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_H_
+#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_H_
+
+#include <jni.h>
+
+#include "base/macros.h"
+#include "content/public/browser/screen_orientation_delegate.h"
+#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+
+namespace content {
+
+class WebContents;
+
+// Android implementation of ScreenOrientationDelegate. The functionality of
+// ScreenOrientationProvider is always supported.
+class ScreenOrientationDelegateAndroid : public ScreenOrientationDelegate {
+ public:
+ ScreenOrientationDelegateAndroid();
+ virtual ~ScreenOrientationDelegateAndroid();
+
+ static bool Register(JNIEnv* env);
+
+ // Ask the ScreenOrientationListener (Java) to start accurately listening to
+ // the screen orientation. It keep track of the number of start request if it
+ // is already running an accurate listening.
+ static void StartAccurateListening();
+
+ // Ask the ScreenOrientationListener (Java) to stop accurately listening to
+ // the screen orientation. It will actually stop only if the number of stop
+ // requests matches the number of start requests.
+ static void StopAccurateListening();
+
+ // ScreenOrientationDelegate:
+ virtual bool FullScreenRequired(WebContents* web_contents) override;
+ virtual void Lock(
+ blink::WebScreenOrientationLockType lock_orientation) override;
+ virtual bool ScreenOrientationProviderSupported() override;
+ virtual void Unlock() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScreenOrientationDelegateAndroid);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DELEGATE_H_
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host.cc b/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host.cc
deleted file mode 100644
index 67174d028ea..00000000000
--- a/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host.cc
+++ /dev/null
@@ -1,85 +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/screen_orientation/screen_orientation_dispatcher_host.h"
-
-#include "content/browser/screen_orientation/screen_orientation_provider.h"
-#include "content/common/screen_orientation_messages.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-
-namespace content {
-
-ScreenOrientationDispatcherHost::ScreenOrientationDispatcherHost(
- WebContents* web_contents)
- : WebContentsObserver(web_contents) {
- if (!provider_.get())
- provider_.reset(CreateProvider());
-}
-
-ScreenOrientationDispatcherHost::~ScreenOrientationDispatcherHost() {
-}
-
-bool ScreenOrientationDispatcherHost::OnMessageReceived(
- const IPC::Message& message,
- RenderFrameHost* render_frame_host) {
- bool handled = true;
-
- IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ScreenOrientationDispatcherHost, message,
- render_frame_host)
- IPC_MESSAGE_HANDLER(ScreenOrientationHostMsg_LockRequest, OnLockRequest)
- IPC_MESSAGE_HANDLER(ScreenOrientationHostMsg_Unlock, OnUnlockRequest)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-void ScreenOrientationDispatcherHost::OnOrientationChange(
- blink::WebScreenOrientationType orientation) {
- Send(new ScreenOrientationMsg_OrientationChange(orientation));
-}
-
-void ScreenOrientationDispatcherHost::SetProviderForTests(
- ScreenOrientationProvider* provider) {
- provider_.reset(provider);
-}
-
-void ScreenOrientationDispatcherHost::OnLockRequest(
- RenderFrameHost* render_frame_host,
- blink::WebScreenOrientationLockType orientation,
- int request_id) {
- if (!provider_) {
- render_frame_host->Send(new ScreenOrientationMsg_LockError(
- render_frame_host->GetRoutingID(),
- request_id,
- blink::WebLockOrientationCallback::ErrorTypeNotAvailable));
- return;
- }
-
- // TODO(mlamouri): pass real values.
- render_frame_host->Send(new ScreenOrientationMsg_LockSuccess(
- render_frame_host->GetRoutingID(),
- request_id,
- 0,
- blink::WebScreenOrientationPortraitPrimary));
- provider_->LockOrientation(orientation);
-}
-
-void ScreenOrientationDispatcherHost::OnUnlockRequest(
- RenderFrameHost* render_frame_host) {
- if (!provider_.get())
- return;
-
- provider_->UnlockOrientation();
-}
-
-#if !defined(OS_ANDROID)
-// static
-ScreenOrientationProvider* ScreenOrientationDispatcherHost::CreateProvider() {
- return NULL;
-}
-#endif
-
-} // namespace content
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host.h b/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host.h
deleted file mode 100644
index c86854a83ad..00000000000
--- a/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host.h
+++ /dev/null
@@ -1,50 +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_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_HOST_H_
-#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_HOST_H_
-
-#include "content/public/browser/web_contents_observer.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
-
-namespace content {
-
-class RenderFrameHost;
-class ScreenOrientationProvider;
-class WebContents;
-
-// ScreenOrientationDispatcherHost receives lock and unlock requests from the
-// RenderFrames and dispatch them to the ScreenOrientationProvider. It also
-// make sure that the right RenderFrame get replied for each lock request.
-class CONTENT_EXPORT ScreenOrientationDispatcherHost
- : public WebContentsObserver {
- public:
- explicit ScreenOrientationDispatcherHost(WebContents* web_contents);
- virtual ~ScreenOrientationDispatcherHost();
-
- // WebContentsObserver
- virtual bool OnMessageReceived(const IPC::Message&,
- RenderFrameHost* render_frame_host) OVERRIDE;
-
- void OnOrientationChange(blink::WebScreenOrientationType orientation);
-
- void SetProviderForTests(ScreenOrientationProvider* provider);
-
- private:
- void OnLockRequest(RenderFrameHost* render_frame_host,
- blink::WebScreenOrientationLockType orientation,
- int request_id);
- void OnUnlockRequest(RenderFrameHost* render_frame_host);
-
- static ScreenOrientationProvider* CreateProvider();
-
- scoped_ptr<ScreenOrientationProvider> provider_;
-
- DISALLOW_COPY_AND_ASSIGN(ScreenOrientationDispatcherHost);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_HOST_H_
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.cc b/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.cc
new file mode 100644
index 00000000000..1e5240d9b97
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.cc
@@ -0,0 +1,146 @@
+// 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/screen_orientation/screen_orientation_dispatcher_host_impl.h"
+
+#include "content/common/screen_orientation_messages.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/screen_orientation_provider.h"
+#include "content/public/browser/web_contents.h"
+#include "third_party/WebKit/public/platform/WebScreenInfo.h"
+
+namespace content {
+
+ScreenOrientationDispatcherHostImpl::LockInformation::LockInformation(
+ int request_id, int process_id, int routing_id)
+ : request_id(request_id),
+ process_id(process_id),
+ routing_id(routing_id) {
+}
+
+ScreenOrientationDispatcherHostImpl::ScreenOrientationDispatcherHostImpl(
+ WebContents* web_contents)
+ : WebContentsObserver(web_contents),
+ current_lock_(NULL) {
+ provider_.reset(new ScreenOrientationProvider(this, web_contents));
+}
+
+ScreenOrientationDispatcherHostImpl::~ScreenOrientationDispatcherHostImpl() {
+ ResetCurrentLock();
+}
+
+void ScreenOrientationDispatcherHostImpl::ResetCurrentLock() {
+ if (current_lock_) {
+ delete current_lock_;
+ current_lock_ = 0;
+ }
+}
+
+bool ScreenOrientationDispatcherHostImpl::OnMessageReceived(
+ const IPC::Message& message,
+ RenderFrameHost* render_frame_host) {
+ bool handled = true;
+
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ScreenOrientationDispatcherHostImpl, message,
+ render_frame_host)
+ IPC_MESSAGE_HANDLER(ScreenOrientationHostMsg_LockRequest, OnLockRequest)
+ IPC_MESSAGE_HANDLER(ScreenOrientationHostMsg_Unlock, OnUnlockRequest)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void ScreenOrientationDispatcherHostImpl::DidNavigateMainFrame(
+ const LoadCommittedDetails& details, const FrameNavigateParams& params) {
+ if (!provider_ || details.is_in_page)
+ return;
+ provider_->UnlockOrientation();
+}
+
+RenderFrameHost*
+ScreenOrientationDispatcherHostImpl::GetRenderFrameHostForRequestID(
+ int request_id) {
+ if (!current_lock_ || current_lock_->request_id != request_id)
+ return NULL;
+
+ return RenderFrameHost::FromID(current_lock_->process_id,
+ current_lock_->routing_id);
+}
+
+void ScreenOrientationDispatcherHostImpl::NotifyLockSuccess(int request_id) {
+ RenderFrameHost* render_frame_host =
+ GetRenderFrameHostForRequestID(request_id);
+ if (!render_frame_host)
+ return;
+
+ render_frame_host->Send(new ScreenOrientationMsg_LockSuccess(
+ render_frame_host->GetRoutingID(), request_id));
+ ResetCurrentLock();
+}
+
+void ScreenOrientationDispatcherHostImpl::NotifyLockError(
+ int request_id, blink::WebLockOrientationError error) {
+ RenderFrameHost* render_frame_host =
+ GetRenderFrameHostForRequestID(request_id);
+ if (!render_frame_host)
+ return;
+
+ NotifyLockError(request_id, render_frame_host, error);
+}
+
+void ScreenOrientationDispatcherHostImpl::NotifyLockError(
+ int request_id,
+ RenderFrameHost* render_frame_host,
+ blink::WebLockOrientationError error) {
+ render_frame_host->Send(new ScreenOrientationMsg_LockError(
+ render_frame_host->GetRoutingID(), request_id, error));
+ ResetCurrentLock();
+}
+
+void ScreenOrientationDispatcherHostImpl::OnOrientationChange() {
+ if (provider_)
+ provider_->OnOrientationChange();
+}
+
+void ScreenOrientationDispatcherHostImpl::OnLockRequest(
+ RenderFrameHost* render_frame_host,
+ blink::WebScreenOrientationLockType orientation,
+ int request_id) {
+ if (current_lock_) {
+ NotifyLockError(current_lock_->request_id, render_frame_host,
+ blink::WebLockOrientationErrorCanceled);
+ }
+
+ if (!provider_) {
+ NotifyLockError(request_id, render_frame_host,
+ blink::WebLockOrientationErrorNotAvailable);
+ return;
+ }
+
+ current_lock_ = new LockInformation(request_id,
+ render_frame_host->GetProcess()->GetID(),
+ render_frame_host->GetRoutingID());
+
+ provider_->LockOrientation(request_id, orientation);
+}
+
+void ScreenOrientationDispatcherHostImpl::OnUnlockRequest(
+ RenderFrameHost* render_frame_host) {
+ if (current_lock_) {
+ NotifyLockError(current_lock_->request_id, render_frame_host,
+ blink::WebLockOrientationErrorCanceled);
+ }
+
+ if (!provider_)
+ return;
+
+ provider_->UnlockOrientation();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h b/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h
new file mode 100644
index 00000000000..a8840837883
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h
@@ -0,0 +1,72 @@
+// 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_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_HOST_IMPL_H_
+#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_HOST_IMPL_H_
+
+#include "content/public/browser/screen_orientation_dispatcher_host.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "third_party/WebKit/public/platform/WebLockOrientationError.h"
+#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+
+namespace content {
+
+class RenderFrameHost;
+class ScreenOrientationProvider;
+class WebContents;
+
+// ScreenOrientationDispatcherHost receives lock and unlock requests from the
+// RenderFrames and dispatch them to the ScreenOrientationProvider. It also
+// make sure that the right RenderFrame get replied for each lock request.
+class CONTENT_EXPORT ScreenOrientationDispatcherHostImpl
+ : public ScreenOrientationDispatcherHost,
+ public WebContentsObserver {
+ public:
+ explicit ScreenOrientationDispatcherHostImpl(WebContents* web_contents);
+ ~ScreenOrientationDispatcherHostImpl() override;
+
+ // ScreenOrientationDispatcherHost:
+ void NotifyLockSuccess(int request_id) override;
+ void NotifyLockError(int request_id,
+ blink::WebLockOrientationError error) override;
+ void OnOrientationChange() override;
+
+ // WebContentsObserver:
+ bool OnMessageReceived(const IPC::Message&,
+ RenderFrameHost* render_frame_host) override;
+ void DidNavigateMainFrame(const LoadCommittedDetails& details,
+ const FrameNavigateParams& params) override;
+
+ private:
+ void OnLockRequest(RenderFrameHost* render_frame_host,
+ blink::WebScreenOrientationLockType orientation,
+ int request_id);
+ void OnUnlockRequest(RenderFrameHost* render_frame_host);
+
+ // Returns a RenderFrameHost if the request_id is still valid and the
+ // associated RenderFrameHost still exists. Returns NULL otherwise.
+ RenderFrameHost* GetRenderFrameHostForRequestID(int request_id);
+
+ void ResetCurrentLock();
+ void NotifyLockError(int request_id,
+ RenderFrameHost* render_frame_host,
+ blink::WebLockOrientationError error);
+
+ scoped_ptr<ScreenOrientationProvider> provider_;
+
+ struct LockInformation {
+ LockInformation(int request_id, int process_id, int routing_id);
+ int request_id;
+ int process_id;
+ int routing_id;
+ };
+ // current_lock_ will be NULL if there are no current lock.
+ LockInformation* current_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenOrientationDispatcherHostImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_DISPATCHER_HOST_IMPL_H_
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.cc b/chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.cc
new file mode 100644
index 00000000000..cd7bd186a22
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.cc
@@ -0,0 +1,49 @@
+// 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/screen_orientation/screen_orientation_message_filter_android.h"
+
+#include "content/browser/screen_orientation/screen_orientation_delegate_android.h"
+#include "content/common/screen_orientation_messages.h"
+
+namespace content {
+
+ScreenOrientationMessageFilterAndroid::ScreenOrientationMessageFilterAndroid()
+ : BrowserMessageFilter(ScreenOrientationMsgStart)
+ , listeners_count_(0) {
+}
+
+ScreenOrientationMessageFilterAndroid::~ScreenOrientationMessageFilterAndroid()
+{
+ if (listeners_count_ > 0)
+ ScreenOrientationDelegateAndroid::StopAccurateListening();
+}
+
+bool ScreenOrientationMessageFilterAndroid::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ScreenOrientationMessageFilterAndroid, message)
+ IPC_MESSAGE_HANDLER(ScreenOrientationHostMsg_StartListening,
+ OnStartListening)
+ IPC_MESSAGE_HANDLER(ScreenOrientationHostMsg_StopListening,
+ OnStopListening)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void ScreenOrientationMessageFilterAndroid::OnStartListening() {
+ ++listeners_count_;
+ if (listeners_count_ == 1)
+ ScreenOrientationDelegateAndroid::StartAccurateListening();
+}
+
+void ScreenOrientationMessageFilterAndroid::OnStopListening() {
+ DCHECK(listeners_count_ > 0);
+ --listeners_count_;
+ if (listeners_count_ == 0)
+ ScreenOrientationDelegateAndroid::StopAccurateListening();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.h b/chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.h
new file mode 100644
index 00000000000..9a01ed4e866
--- /dev/null
+++ b/chromium/content/browser/screen_orientation/screen_orientation_message_filter_android.h
@@ -0,0 +1,32 @@
+// 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_SCREEN_ORIENTATION_SCREEN_ORIENTATION_MESSAGE_FILTER_ANDROID_H_
+#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_MESSAGE_FILTER_ANDROID_H_
+
+#include "content/public/browser/browser_message_filter.h"
+
+namespace content {
+
+class ScreenOrientationMessageFilterAndroid : public BrowserMessageFilter {
+ public:
+ ScreenOrientationMessageFilterAndroid();
+
+ // BrowserMessageFilter implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message) override;
+
+ private:
+ virtual ~ScreenOrientationMessageFilterAndroid();
+
+ void OnStartListening();
+ void OnStopListening();
+
+ int listeners_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenOrientationMessageFilterAndroid);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_MESSAGE_FILTER_ANDROID_H_
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_provider.h b/chromium/content/browser/screen_orientation/screen_orientation_provider.h
deleted file mode 100644
index 4ae858805b0..00000000000
--- a/chromium/content/browser/screen_orientation/screen_orientation_provider.h
+++ /dev/null
@@ -1,28 +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_SCREEN_ORIENTATION_SCREEN_ORIENTATION_PROVIDER_H_
-#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_PROVIDER_H_
-
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
-
-namespace content {
-
-// Interface that needs to be implemented by any backend that wants to handle
-// screen orientation lock/unlock.
-class ScreenOrientationProvider {
- public:
- // Lock the screen orientation to |orientations|.
- virtual void LockOrientation(
- blink::WebScreenOrientationLockType orientations) = 0;
-
- // Unlock the screen orientation.
- virtual void UnlockOrientation() = 0;
-
- virtual ~ScreenOrientationProvider() {}
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_PROVIDER_H_
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_provider_android.cc b/chromium/content/browser/screen_orientation/screen_orientation_provider_android.cc
deleted file mode 100644
index e8961bc4726..00000000000
--- a/chromium/content/browser/screen_orientation/screen_orientation_provider_android.cc
+++ /dev/null
@@ -1,51 +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/screen_orientation/screen_orientation_provider_android.h"
-
-#include "content/browser/screen_orientation/screen_orientation_dispatcher_host.h"
-#include "jni/ScreenOrientationProvider_jni.h"
-
-namespace content {
-
-ScreenOrientationProviderAndroid::ScreenOrientationProviderAndroid() {
-}
-
-ScreenOrientationProviderAndroid::~ScreenOrientationProviderAndroid() {
-}
-
-// static
-bool ScreenOrientationProviderAndroid::Register(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
-void ScreenOrientationProviderAndroid::LockOrientation(
- blink::WebScreenOrientationLockType orientation) {
- if (j_screen_orientation_provider_.is_null()) {
- j_screen_orientation_provider_.Reset(Java_ScreenOrientationProvider_create(
- base::android::AttachCurrentThread()));
- }
-
- Java_ScreenOrientationProvider_lockOrientation(
- base::android::AttachCurrentThread(),
- j_screen_orientation_provider_.obj(), orientation);
-}
-
-void ScreenOrientationProviderAndroid::UnlockOrientation() {
- // j_screen_orientation_provider_ is set when locking. If the screen
- // orientation was not locked, unlocking should be a no-op.
- if (j_screen_orientation_provider_.is_null())
- return;
-
- Java_ScreenOrientationProvider_unlockOrientation(
- base::android::AttachCurrentThread(),
- j_screen_orientation_provider_.obj());
-}
-
-// static
-ScreenOrientationProvider* ScreenOrientationDispatcherHost::CreateProvider() {
- return new ScreenOrientationProviderAndroid();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/screen_orientation/screen_orientation_provider_android.h b/chromium/content/browser/screen_orientation/screen_orientation_provider_android.h
deleted file mode 100644
index a526e24596c..00000000000
--- a/chromium/content/browser/screen_orientation/screen_orientation_provider_android.h
+++ /dev/null
@@ -1,34 +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_SCREEN_ORIENTATION_SCREEN_ORIENTATION_PROVIDER_ANDROID_H_
-#define CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_PROVIDER_ANDROID_H_
-
-#include "base/android/jni_android.h"
-#include "base/compiler_specific.h"
-#include "content/browser/screen_orientation/screen_orientation_provider.h"
-
-namespace content {
-
-class ScreenOrientationProviderAndroid : public ScreenOrientationProvider {
- public:
- ScreenOrientationProviderAndroid();
-
- static bool Register(JNIEnv* env);
-
- // ScreenOrientationProvider
- virtual void LockOrientation(blink::WebScreenOrientationLockType) OVERRIDE;
- virtual void UnlockOrientation() OVERRIDE;
-
- private:
- virtual ~ScreenOrientationProviderAndroid();
-
- base::android::ScopedJavaGlobalRef<jobject> j_screen_orientation_provider_;
-
- DISALLOW_COPY_AND_ASSIGN(ScreenOrientationProviderAndroid);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_SCREEN_ORIENTATION_SCREEN_ORIENTATION_PROVIDER_ANDROID_H_
diff --git a/chromium/content/browser/security_exploit_browsertest.cc b/chromium/content/browser/security_exploit_browsertest.cc
index 9fadec049a7..2a1be07b9a9 100644
--- a/chromium/content/browser/security_exploit_browsertest.cc
+++ b/chromium/content/browser/security_exploit_browsertest.cc
@@ -84,7 +84,7 @@ RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell,
class SecurityExploitBrowserTest : public ContentBrowserTest {
public:
SecurityExploitBrowserTest() {}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
ASSERT_TRUE(test_server()->Start());
// Add a host resolver rule to map all outgoing requests to the test server.
@@ -139,8 +139,10 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
new SessionStorageNamespaceImpl(dom_storage_context));
// Cause a deliberate collision in routing ids.
int main_frame_routing_id = duplicate_routing_id + 1;
- pending_rvh->CreateNewWindow(
- duplicate_routing_id, main_frame_routing_id, params, session_storage);
+ pending_rvh->CreateNewWindow(duplicate_routing_id,
+ main_frame_routing_id,
+ params,
+ session_storage.get());
// If the above operation doesn't cause a crash, the test has succeeded!
}
diff --git a/chromium/content/browser/service_worker/BUILD.gn b/chromium/content/browser/service_worker/BUILD.gn
index d9f206615fb..43a2ff1b435 100644
--- a/chromium/content/browser/service_worker/BUILD.gn
+++ b/chromium/content/browser/service_worker/BUILD.gn
@@ -4,8 +4,9 @@
import("//third_party/protobuf/proto_library.gni")
-proto_library("database_proto") {
+proto_library("proto") {
sources = [
+ "service_worker_cache.proto",
"service_worker_database.proto",
]
}
diff --git a/chromium/content/browser/service_worker/OWNERS b/chromium/content/browser/service_worker/OWNERS
index f9916062308..c84704de993 100644
--- a/chromium/content/browser/service_worker/OWNERS
+++ b/chromium/content/browser/service_worker/OWNERS
@@ -1,12 +1,7 @@
michaeln@chromium.org
falken@chromium.org
+horo@chromium.org
+nhiroki@chromium.org
# may not be available
kinuko@chromium.org
-
-# per-file owners
-per-file embedded_worker*=horo@chromium.org
-per-file service_worker_process_manager*=horo@chromium.org
-per-file service_worker_internals_ui*=horo@chromium.org
-per-file service_worker_database*=nhiroki@chromium.org
-per-file service_worker_storage*=nhiroki@chromium.org
diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.cc b/chromium/content/browser/service_worker/embedded_worker_instance.cc
index fd2d201a660..3eb9bda1c5f 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_instance.cc
@@ -4,11 +4,16 @@
#include "content/browser/service_worker/embedded_worker_instance.h"
+#include <algorithm>
+#include <utility>
+
#include "base/bind_helpers.h"
+#include "base/debug/trace_event.h"
#include "content/browser/devtools/embedded_worker_devtools_manager.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "ipc/ipc_message.h"
@@ -26,16 +31,17 @@ struct SecondGreater {
}
};
-void NotifyWorkerContextStarted(int worker_process_id, int worker_route_id) {
+void NotifyWorkerReadyForInspection(int worker_process_id,
+ int worker_route_id) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- NotifyWorkerContextStarted, worker_process_id, worker_route_id));
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(NotifyWorkerReadyForInspection,
+ worker_process_id,
+ worker_route_id));
return;
}
- EmbeddedWorkerDevToolsManager::GetInstance()->WorkerContextStarted(
+ EmbeddedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
worker_process_id, worker_route_id);
}
@@ -53,36 +59,43 @@ void NotifyWorkerDestroyed(int worker_process_id, int worker_route_id) {
void RegisterToWorkerDevToolsManager(
int process_id,
- const ServiceWorkerContextCore* const service_worker_context,
+ const ServiceWorkerContextCore* service_worker_context,
+ base::WeakPtr<ServiceWorkerContextCore> service_worker_context_weak,
int64 service_worker_version_id,
+ const GURL& url,
const base::Callback<void(int worker_devtools_agent_route_id,
- bool pause_on_start)>& callback) {
+ bool wait_for_debugger)>& callback) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(RegisterToWorkerDevToolsManager,
process_id,
service_worker_context,
+ service_worker_context_weak,
service_worker_version_id,
+ url,
callback));
return;
}
int worker_devtools_agent_route_id = MSG_ROUTING_NONE;
- bool pause_on_start = false;
+ bool wait_for_debugger = false;
if (RenderProcessHost* rph = RenderProcessHost::FromID(process_id)) {
// |rph| may be NULL in unit tests.
worker_devtools_agent_route_id = rph->GetNextRoutingID();
- pause_on_start =
+ wait_for_debugger =
EmbeddedWorkerDevToolsManager::GetInstance()->ServiceWorkerCreated(
process_id,
worker_devtools_agent_route_id,
EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier(
- service_worker_context, service_worker_version_id));
+ service_worker_context,
+ service_worker_context_weak,
+ service_worker_version_id,
+ url));
}
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
- base::Bind(callback, worker_devtools_agent_route_id, pause_on_start));
+ base::Bind(callback, worker_devtools_agent_route_id, wait_for_debugger));
}
} // namespace
@@ -100,7 +113,7 @@ EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
void EmbeddedWorkerInstance::Start(int64 service_worker_version_id,
const GURL& scope,
const GURL& script_url,
- const std::vector<int>& possible_process_ids,
+ bool pause_after_download,
const StatusCallback& callback) {
if (!context_) {
callback.Run(SERVICE_WORKER_ERROR_ABORT);
@@ -110,15 +123,21 @@ void EmbeddedWorkerInstance::Start(int64 service_worker_version_id,
status_ = STARTING;
scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
new EmbeddedWorkerMsg_StartWorker_Params());
+ TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
+ "EmbeddedWorkerInstance::ProcessAllocate",
+ params.get(),
+ "Scope", scope.spec(),
+ "Script URL", script_url.spec());
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->pause_on_start = false;
+ params->pause_after_download = pause_after_download;
+ params->wait_for_debugger = false;
context_->process_manager()->AllocateWorkerProcess(
embedded_worker_id_,
- SortProcesses(possible_process_ids),
+ scope,
script_url,
base::Bind(&EmbeddedWorkerInstance::RunProcessAllocated,
weak_factory_.GetWeakPtr(),
@@ -136,31 +155,23 @@ ServiceWorkerStatusCode EmbeddedWorkerInstance::Stop() {
return status;
}
+void EmbeddedWorkerInstance::ResumeAfterDownload() {
+ DCHECK_EQ(STARTING, status_);
+ registry_->Send(
+ process_id_,
+ new EmbeddedWorkerMsg_ResumeAfterDownload(embedded_worker_id_));
+}
+
ServiceWorkerStatusCode EmbeddedWorkerInstance::SendMessage(
const IPC::Message& message) {
- DCHECK(status_ == RUNNING);
+ DCHECK_NE(kInvalidEmbeddedWorkerThreadId, thread_id_);
+ if (status_ != RUNNING && status_ != STARTING)
+ return SERVICE_WORKER_ERROR_IPC_FAILED;
return registry_->Send(process_id_,
new EmbeddedWorkerContextMsg_MessageToWorker(
thread_id_, embedded_worker_id_, message));
}
-void EmbeddedWorkerInstance::AddProcessReference(int process_id) {
- ProcessRefMap::iterator found = process_refs_.find(process_id);
- if (found == process_refs_.end())
- found = process_refs_.insert(std::make_pair(process_id, 0)).first;
- ++found->second;
-}
-
-void EmbeddedWorkerInstance::ReleaseProcessReference(int process_id) {
- ProcessRefMap::iterator found = process_refs_.find(process_id);
- if (found == process_refs_.end()) {
- NOTREACHED() << "Releasing unknown process ref " << process_id;
- return;
- }
- if (--found->second == 0)
- process_refs_.erase(found);
-}
-
EmbeddedWorkerInstance::EmbeddedWorkerInstance(
base::WeakPtr<ServiceWorkerContextCore> context,
int embedded_worker_id)
@@ -169,7 +180,7 @@ EmbeddedWorkerInstance::EmbeddedWorkerInstance(
embedded_worker_id_(embedded_worker_id),
status_(STOPPED),
process_id_(-1),
- thread_id_(-1),
+ thread_id_(kInvalidEmbeddedWorkerThreadId),
worker_devtools_agent_route_id_(MSG_ROUTING_NONE),
weak_factory_(this) {
}
@@ -204,6 +215,10 @@ void EmbeddedWorkerInstance::ProcessAllocated(
int process_id,
ServiceWorkerStatusCode status) {
DCHECK_EQ(process_id_, -1);
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "EmbeddedWorkerInstance::ProcessAllocate",
+ params.get(),
+ "Status", status);
if (status != SERVICE_WORKER_OK) {
status_ = STOPPED;
callback.Run(status);
@@ -211,10 +226,13 @@ void EmbeddedWorkerInstance::ProcessAllocated(
}
const int64 service_worker_version_id = params->service_worker_version_id;
process_id_ = process_id;
+ GURL script_url(params->script_url);
RegisterToWorkerDevToolsManager(
process_id,
context_.get(),
+ context_,
service_worker_version_id,
+ script_url,
base::Bind(&EmbeddedWorkerInstance::SendStartWorker,
weak_factory_.GetWeakPtr(),
base::Passed(&params),
@@ -225,28 +243,46 @@ void EmbeddedWorkerInstance::SendStartWorker(
scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
const StatusCallback& callback,
int worker_devtools_agent_route_id,
- bool pause_on_start) {
+ bool wait_for_debugger) {
worker_devtools_agent_route_id_ = worker_devtools_agent_route_id;
params->worker_devtools_agent_route_id = worker_devtools_agent_route_id;
- params->pause_on_start = pause_on_start;
- registry_->SendStartWorker(params.Pass(), callback, process_id_);
+ params->wait_for_debugger = wait_for_debugger;
+ ServiceWorkerStatusCode status =
+ registry_->SendStartWorker(params.Pass(), process_id_);
+ if (status != SERVICE_WORKER_OK) {
+ callback.Run(status);
+ return;
+ }
+ DCHECK(start_callback_.is_null());
+ start_callback_ = callback;
}
-void EmbeddedWorkerInstance::OnScriptLoaded() {
+void EmbeddedWorkerInstance::OnReadyForInspection() {
if (worker_devtools_agent_route_id_ != MSG_ROUTING_NONE)
- NotifyWorkerContextStarted(process_id_, worker_devtools_agent_route_id_);
+ NotifyWorkerReadyForInspection(process_id_,
+ worker_devtools_agent_route_id_);
+}
+
+void EmbeddedWorkerInstance::OnScriptLoaded(int thread_id) {
+ thread_id_ = thread_id;
}
void EmbeddedWorkerInstance::OnScriptLoadFailed() {
}
-void EmbeddedWorkerInstance::OnStarted(int thread_id) {
+void EmbeddedWorkerInstance::OnScriptEvaluated(bool success) {
+ DCHECK(!start_callback_.is_null());
+ start_callback_.Run(success ? SERVICE_WORKER_OK
+ : SERVICE_WORKER_ERROR_START_WORKER_FAILED);
+ start_callback_.Reset();
+}
+
+void EmbeddedWorkerInstance::OnStarted() {
// Stop is requested before OnStarted is sent back from the worker.
if (status_ == STOPPING)
return;
DCHECK(status_ == STARTING);
status_ = RUNNING;
- thread_id_ = thread_id;
FOR_EACH_OBSERVER(Listener, listener_list_, OnStarted());
}
@@ -259,9 +295,18 @@ void EmbeddedWorkerInstance::OnStopped() {
process_id_ = -1;
thread_id_ = -1;
worker_devtools_agent_route_id_ = MSG_ROUTING_NONE;
+ start_callback_.Reset();
FOR_EACH_OBSERVER(Listener, listener_list_, OnStopped());
}
+void EmbeddedWorkerInstance::OnPausedAfterDownload() {
+ // Stop can be requested before getting this far.
+ if (status_ == STOPPING)
+ return;
+ DCHECK(status_ == STARTING);
+ FOR_EACH_OBSERVER(Listener, listener_list_, OnPausedAfterDownload());
+}
+
bool EmbeddedWorkerInstance::OnMessageReceived(const IPC::Message& message) {
ListenerList::Iterator it(listener_list_);
while (Listener* listener = it.GetNext()) {
@@ -303,26 +348,4 @@ void EmbeddedWorkerInstance::RemoveListener(Listener* listener) {
listener_list_.RemoveObserver(listener);
}
-std::vector<int> EmbeddedWorkerInstance::SortProcesses(
- const std::vector<int>& possible_process_ids) const {
- // Add the |possible_process_ids| to the existing process_refs_ since each one
- // is likely to take a reference once the SW starts up.
- ProcessRefMap refs_with_new_ids = process_refs_;
- for (std::vector<int>::const_iterator it = possible_process_ids.begin();
- it != possible_process_ids.end();
- ++it) {
- refs_with_new_ids[*it]++;
- }
-
- std::vector<std::pair<int, int> > counted(refs_with_new_ids.begin(),
- refs_with_new_ids.end());
- // Sort descending by the reference count.
- std::sort(counted.begin(), counted.end(), SecondGreater());
-
- std::vector<int> result(counted.size());
- for (size_t i = 0; i < counted.size(); ++i)
- result[i] = counted[i].first;
- return result;
-}
-
} // namespace content
diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.h b/chromium/content/browser/service_worker/embedded_worker_instance.h
index 9e404ff4640..75813248ff6 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance.h
+++ b/chromium/content/browser/service_worker/embedded_worker_instance.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
@@ -48,8 +49,9 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
class Listener {
public:
virtual ~Listener() {}
- virtual void OnStarted() = 0;
- virtual void OnStopped() = 0;
+ virtual void OnStarted() {}
+ virtual void OnStopped() {}
+ virtual void OnPausedAfterDownload() {}
virtual void OnReportException(const base::string16& error_message,
int line_number,
int column_number,
@@ -74,7 +76,7 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
void Start(int64 service_worker_version_id,
const GURL& scope,
const GURL& script_url,
- const std::vector<int>& possible_process_ids,
+ bool pause_after_download,
const StatusCallback& callback);
// Stops the worker. It is invalid to call this when the worker is
@@ -87,11 +89,7 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
// It is invalid to call this while the worker is not in RUNNING status.
ServiceWorkerStatusCode SendMessage(const IPC::Message& message);
- // Add or remove |process_id| to the internal process set where this
- // worker can be started.
- void AddProcessReference(int process_id);
- void ReleaseProcessReference(int process_id);
- bool HasProcessToRun() const { return !process_refs_.empty(); }
+ void ResumeAfterDownload();
int embedded_worker_id() const { return embedded_worker_id_; }
Status status() const { return status_; }
@@ -109,9 +107,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
friend class EmbeddedWorkerRegistry;
FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, StartAndStop);
- FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, SortProcesses);
-
- typedef std::map<int, int> ProcessRefMap;
// Constructor is called via EmbeddedWorkerRegistry::CreateWorker().
// This instance holds a ref of |registry|.
@@ -136,21 +131,30 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
void SendStartWorker(scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
const StatusCallback& callback,
int worker_devtools_agent_route_id,
- bool pause_on_start);
+ bool wait_for_debugger);
+
+ // Called back from Registry when the worker instance has ack'ed that
+ // it is ready for inspection.
+ void OnReadyForInspection();
// Called back from Registry when the worker instance has ack'ed that
- // it finished loading the script.
- void OnScriptLoaded();
+ // it finished loading the script and has started a worker thread.
+ void OnScriptLoaded(int thread_id);
// Called back from Registry when the worker instance has ack'ed that
// it failed to load the script.
void OnScriptLoadFailed();
// Called back from Registry when the worker instance has ack'ed that
- // its WorkerGlobalScope is actually started and parsed on |thread_id| in the
- // child process.
+ // it finished evaluating the script.
+ void OnScriptEvaluated(bool success);
+
+ // Called back from Registry when the worker instance has ack'ed that
+ // its WorkerGlobalScope is actually started and parsed.
// This will change the internal status from STARTING to RUNNING.
- void OnStarted(int thread_id);
+ void OnStarted();
+
+ void OnPausedAfterDownload();
// Called back from Registry when the worker instance has ack'ed that
// its WorkerGlobalScope is actually stopped in the child process.
@@ -176,11 +180,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
int line_number,
const GURL& source_url);
- // Chooses a list of processes to try to start this worker in, ordered by how
- // many clients are currently in those processes.
- std::vector<int> SortProcesses(
- const std::vector<int>& possible_process_ids) const;
-
base::WeakPtr<ServiceWorkerContextCore> context_;
scoped_refptr<EmbeddedWorkerRegistry> registry_;
const int embedded_worker_id_;
@@ -191,7 +190,8 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
int thread_id_;
int worker_devtools_agent_route_id_;
- ProcessRefMap process_refs_;
+ StatusCallback start_callback_;
+
ListenerList listener_list_;
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 d14ccd22f25..c5f190eef42 100644
--- a/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -24,13 +24,11 @@ class EmbeddedWorkerInstanceTest : public testing::Test {
EmbeddedWorkerInstanceTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
}
- virtual void TearDown() OVERRIDE {
- helper_.reset();
- }
+ void TearDown() override { helper_.reset(); }
ServiceWorkerContextCore* context() { return helper_->context(); }
@@ -44,6 +42,7 @@ class EmbeddedWorkerInstanceTest : public testing::Test {
TestBrowserThreadBundle thread_bundle_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ private:
DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
};
@@ -59,29 +58,28 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
embedded_worker_registry()->CreateWorker();
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
- const int embedded_worker_id = worker->embedded_worker_id();
const int64 service_worker_version_id = 55L;
- const GURL scope("http://example.com/*");
+ const GURL pattern("http://example.com/");
const GURL url("http://example.com/worker.js");
- // Simulate adding one process to the worker.
- helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId);
+ // Simulate adding one process to the pattern.
+ helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId);
// Start should succeed.
ServiceWorkerStatusCode status;
base::RunLoop run_loop;
worker->Start(
service_worker_version_id,
- scope,
+ pattern,
url,
- std::vector<int>(),
+ false,
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::STARTING, worker->status());
- base::RunLoop().RunUntilIdle();
- // Worker started message should be notified (by EmbeddedWorkerTestHelper).
+ // The 'WorkerStarted' message should have been sent by
+ // EmbeddedWorkerTestHelper.
EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
EXPECT_EQ(kRenderProcessId, worker->process_id());
@@ -90,7 +88,8 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, worker->status());
base::RunLoop().RunUntilIdle();
- // Worker stopped message should be notified (by EmbeddedWorkerTestHelper).
+ // The 'WorkerStopped' message should have been sent by
+ // EmbeddedWorkerTestHelper.
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
// Verify that we've sent two messages to start and terminate the worker.
@@ -106,19 +105,19 @@ TEST_F(EmbeddedWorkerInstanceTest, InstanceDestroyedBeforeStartFinishes) {
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
const int64 service_worker_version_id = 55L;
- const GURL scope("http://example.com/*");
+ const GURL pattern("http://example.com/");
const GURL url("http://example.com/worker.js");
ServiceWorkerStatusCode status;
base::RunLoop run_loop;
// Begin starting the worker.
- std::vector<int> available_process;
- available_process.push_back(kRenderProcessId);
+ context()->process_manager()->AddProcessReferenceToPattern(
+ pattern, kRenderProcessId);
worker->Start(
service_worker_version_id,
- scope,
+ pattern,
url,
- available_process,
+ false,
base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
// But destroy it before it gets a chance to complete.
worker.reset();
@@ -130,38 +129,4 @@ TEST_F(EmbeddedWorkerInstanceTest, InstanceDestroyedBeforeStartFinishes) {
ipc_sink()->GetUniqueMessageMatching(EmbeddedWorkerMsg_StartWorker::ID));
}
-TEST_F(EmbeddedWorkerInstanceTest, SortProcesses) {
- scoped_ptr<EmbeddedWorkerInstance> worker =
- embedded_worker_registry()->CreateWorker();
- EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
-
- // Simulate adding processes to the worker.
- // Process 1 has 1 ref, 2 has 2 refs and 3 has 3 refs.
- const int embedded_worker_id = worker->embedded_worker_id();
- helper_->SimulateAddProcessToWorker(embedded_worker_id, 1);
- helper_->SimulateAddProcessToWorker(embedded_worker_id, 2);
- helper_->SimulateAddProcessToWorker(embedded_worker_id, 2);
- helper_->SimulateAddProcessToWorker(embedded_worker_id, 3);
- helper_->SimulateAddProcessToWorker(embedded_worker_id, 3);
- helper_->SimulateAddProcessToWorker(embedded_worker_id, 3);
-
- // Process 3 has the biggest # of references and it should be chosen.
- EXPECT_THAT(worker->SortProcesses(std::vector<int>()),
- testing::ElementsAre(3, 2, 1));
- EXPECT_EQ(-1, worker->process_id());
-
- // Argument processes are added to the existing set, but only for a single
- // call.
- std::vector<int> registering_processes;
- registering_processes.push_back(1);
- registering_processes.push_back(1);
- registering_processes.push_back(1);
- registering_processes.push_back(4);
- EXPECT_THAT(worker->SortProcesses(registering_processes),
- testing::ElementsAre(1, 3, 2, 4));
-
- EXPECT_THAT(worker->SortProcesses(std::vector<int>()),
- testing::ElementsAre(3, 2, 1));
-}
-
} // namespace content
diff --git a/chromium/content/browser/service_worker/embedded_worker_registry.cc b/chromium/content/browser/service_worker/embedded_worker_registry.cc
index 988b0563f42..adf2579d733 100644
--- a/chromium/content/browser/service_worker/embedded_worker_registry.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_registry.cc
@@ -17,9 +17,22 @@
namespace content {
-EmbeddedWorkerRegistry::EmbeddedWorkerRegistry(
- base::WeakPtr<ServiceWorkerContextCore> context)
- : context_(context), next_embedded_worker_id_(0) {
+// static
+scoped_refptr<EmbeddedWorkerRegistry> EmbeddedWorkerRegistry::Create(
+ const base::WeakPtr<ServiceWorkerContextCore>& context) {
+ return make_scoped_refptr(new EmbeddedWorkerRegistry(context, 0));
+}
+
+// static
+scoped_refptr<EmbeddedWorkerRegistry> EmbeddedWorkerRegistry::Create(
+ const base::WeakPtr<ServiceWorkerContextCore>& context,
+ EmbeddedWorkerRegistry* old_registry) {
+ scoped_refptr<EmbeddedWorkerRegistry> registry =
+ new EmbeddedWorkerRegistry(
+ context,
+ old_registry->next_embedded_worker_id_);
+ registry->process_sender_map_.swap(old_registry->process_sender_map_);
+ return registry;
}
scoped_ptr<EmbeddedWorkerInstance> EmbeddedWorkerRegistry::CreateWorker() {
@@ -40,10 +53,9 @@ bool EmbeddedWorkerRegistry::OnMessageReceived(const IPC::Message& message) {
// ServiceWorkerDispatcherHost.
WorkerInstanceMap::iterator found = worker_map_.find(message.routing_id());
- if (found == worker_map_.end()) {
- LOG(ERROR) << "Worker " << message.routing_id() << " not registered";
+ DCHECK(found != worker_map_.end());
+ if (found == worker_map_.end())
return false;
- }
return found->second->OnMessageReceived(message);
}
@@ -55,66 +67,91 @@ void EmbeddedWorkerRegistry::Shutdown() {
}
}
-void EmbeddedWorkerRegistry::OnWorkerScriptLoaded(int process_id,
- int embedded_worker_id) {
+void EmbeddedWorkerRegistry::OnWorkerReadyForInspection(
+ int process_id,
+ int embedded_worker_id) {
WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
- if (found == worker_map_.end()) {
- LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
+ DCHECK(found != worker_map_.end());
+ DCHECK_EQ(found->second->process_id(), process_id);
+ if (found == worker_map_.end() || found->second->process_id() != process_id)
return;
- }
- if (found->second->process_id() != process_id) {
- LOG(ERROR) << "Incorrect embedded_worker_id";
+ found->second->OnReadyForInspection();
+}
+
+void EmbeddedWorkerRegistry::OnWorkerScriptLoaded(
+ int process_id,
+ int thread_id,
+ int embedded_worker_id ) {
+ WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
+ DCHECK(found != worker_map_.end());
+ DCHECK_EQ(found->second->process_id(), process_id);
+ if (found == worker_map_.end() || found->second->process_id() != process_id)
return;
- }
- found->second->OnScriptLoaded();
+ found->second->OnScriptLoaded(thread_id);
}
void EmbeddedWorkerRegistry::OnWorkerScriptLoadFailed(int process_id,
int embedded_worker_id) {
WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
- if (found == worker_map_.end()) {
- LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
- return;
- }
- if (found->second->process_id() != process_id) {
- LOG(ERROR) << "Incorrect embedded_worker_id";
+ DCHECK(found != worker_map_.end());
+ DCHECK_EQ(found->second->process_id(), process_id);
+ if (found == worker_map_.end() || found->second->process_id() != process_id)
return;
- }
found->second->OnScriptLoadFailed();
}
+void EmbeddedWorkerRegistry::OnWorkerScriptEvaluated(int process_id,
+ int embedded_worker_id,
+ bool success) {
+ WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
+ DCHECK(found != worker_map_.end());
+ DCHECK_EQ(found->second->process_id(), process_id);
+ if (found == worker_map_.end() || found->second->process_id() != process_id)
+ return;
+ found->second->OnScriptEvaluated(success);
+}
+
void EmbeddedWorkerRegistry::OnWorkerStarted(
- int process_id, int thread_id, int embedded_worker_id) {
- DCHECK(!ContainsKey(worker_process_map_, process_id) ||
- worker_process_map_[process_id].count(embedded_worker_id) == 0);
+ int process_id, int embedded_worker_id) {
WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
- if (found == worker_map_.end()) {
- LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
+ // TODO(falken): Instead of DCHECK, we should terminate the process on
+ // unexpected message. Same with most of the DCHECKs in this file.
+ DCHECK(found != worker_map_.end());
+ DCHECK_EQ(found->second->process_id(), process_id);
+ if (found == worker_map_.end() || found->second->process_id() != process_id)
return;
- }
- if (found->second->process_id() != process_id) {
- LOG(ERROR) << "Incorrect embedded_worker_id";
+
+ DCHECK(ContainsKey(worker_process_map_, process_id) &&
+ worker_process_map_[process_id].count(embedded_worker_id) == 1);
+ if (!ContainsKey(worker_process_map_, process_id) ||
+ worker_process_map_[process_id].count(embedded_worker_id) == 0) {
return;
}
- worker_process_map_[process_id].insert(embedded_worker_id);
- found->second->OnStarted(thread_id);
+
+ found->second->OnStarted();
}
void EmbeddedWorkerRegistry::OnWorkerStopped(
int process_id, int embedded_worker_id) {
WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
- if (found == worker_map_.end()) {
- LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
+ DCHECK(found != worker_map_.end());
+ DCHECK_EQ(found->second->process_id(), process_id);
+ if (found == worker_map_.end() || found->second->process_id() != process_id)
return;
- }
- if (found->second->process_id() != process_id) {
- LOG(ERROR) << "Incorrect embedded_worker_id";
- return;
- }
worker_process_map_[process_id].erase(embedded_worker_id);
found->second->OnStopped();
}
+void EmbeddedWorkerRegistry::OnPausedAfterDownload(
+ int process_id, int embedded_worker_id) {
+ WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
+ DCHECK(found != worker_map_.end());
+ DCHECK_EQ(found->second->process_id(), process_id);
+ if (found == worker_map_.end() || found->second->process_id() != process_id)
+ return;
+ found->second->OnPausedAfterDownload();
+}
+
void EmbeddedWorkerRegistry::OnReportException(
int embedded_worker_id,
const base::string16& error_message,
@@ -122,10 +159,9 @@ void EmbeddedWorkerRegistry::OnReportException(
int column_number,
const GURL& source_url) {
WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
- if (found == worker_map_.end()) {
- LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
+ DCHECK(found != worker_map_.end());
+ if (found == worker_map_.end())
return;
- }
found->second->OnReportException(
error_message, line_number, column_number, source_url);
}
@@ -138,10 +174,9 @@ void EmbeddedWorkerRegistry::OnReportConsoleMessage(
int line_number,
const GURL& source_url) {
WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
- if (found == worker_map_.end()) {
- LOG(ERROR) << "Worker " << embedded_worker_id << " not registered";
+ DCHECK(found != worker_map_.end());
+ if (found == worker_map_.end())
return;
- }
found->second->OnReportConsoleMessage(
source_identifier, message_level, message, line_number, source_url);
}
@@ -177,19 +212,47 @@ EmbeddedWorkerInstance* EmbeddedWorkerRegistry::GetWorker(
return found->second;
}
+bool EmbeddedWorkerRegistry::CanHandle(int embedded_worker_id) const {
+ if (embedded_worker_id < initial_embedded_worker_id_ ||
+ next_embedded_worker_id_ <= embedded_worker_id) {
+ return false;
+ }
+ return true;
+}
+
+EmbeddedWorkerRegistry::EmbeddedWorkerRegistry(
+ const base::WeakPtr<ServiceWorkerContextCore>& context,
+ int initial_embedded_worker_id)
+ : context_(context),
+ next_embedded_worker_id_(initial_embedded_worker_id),
+ initial_embedded_worker_id_(initial_embedded_worker_id) {
+}
+
EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {
Shutdown();
}
-void EmbeddedWorkerRegistry::SendStartWorker(
+ServiceWorkerStatusCode EmbeddedWorkerRegistry::SendStartWorker(
scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
- const StatusCallback& callback,
int process_id) {
// The ServiceWorkerDispatcherHost is supposed to be created when the process
// is created, and keep an entry in process_sender_map_ for its whole
// lifetime.
DCHECK(ContainsKey(process_sender_map_, process_id));
- callback.Run(Send(process_id, new EmbeddedWorkerMsg_StartWorker(*params)));
+
+ int embedded_worker_id = params->embedded_worker_id;
+ WorkerInstanceMap::iterator found = worker_map_.find(embedded_worker_id);
+ DCHECK(found != worker_map_.end());
+ DCHECK_EQ(found->second->process_id(), process_id);
+
+ DCHECK(!ContainsKey(worker_process_map_, process_id) ||
+ worker_process_map_[process_id].count(embedded_worker_id) == 0);
+
+ ServiceWorkerStatusCode status =
+ Send(process_id, new EmbeddedWorkerMsg_StartWorker(*params));
+ if (status == SERVICE_WORKER_OK)
+ worker_process_map_[process_id].insert(embedded_worker_id);
+ return status;
}
ServiceWorkerStatusCode EmbeddedWorkerRegistry::Send(
diff --git a/chromium/content/browser/service_worker/embedded_worker_registry.h b/chromium/content/browser/service_worker/embedded_worker_registry.h
index 3df2e238071..31ed59d0020 100644
--- a/chromium/content/browser/service_worker/embedded_worker_registry.h
+++ b/chromium/content/browser/service_worker/embedded_worker_registry.h
@@ -40,8 +40,14 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
public:
typedef base::Callback<void(ServiceWorkerStatusCode)> StatusCallback;
- explicit EmbeddedWorkerRegistry(
- base::WeakPtr<ServiceWorkerContextCore> context);
+ static scoped_refptr<EmbeddedWorkerRegistry> Create(
+ const base::WeakPtr<ServiceWorkerContextCore>& contxet);
+
+ // Used for DeleteAndStartOver. Creates a new registry which takes over
+ // |next_embedded_worker_id_| and |process_sender_map_| from |old_registry|.
+ static scoped_refptr<EmbeddedWorkerRegistry> Create(
+ const base::WeakPtr<ServiceWorkerContextCore>& context,
+ EmbeddedWorkerRegistry* old_registry);
bool OnMessageReceived(const IPC::Message& message);
@@ -50,9 +56,9 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
scoped_ptr<EmbeddedWorkerInstance> CreateWorker();
// Called from EmbeddedWorkerInstance, relayed to the child process.
- void SendStartWorker(scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
- const StatusCallback& callback,
- int process_id);
+ ServiceWorkerStatusCode SendStartWorker(
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
+ int process_id);
ServiceWorkerStatusCode StopWorker(int process_id,
int embedded_worker_id);
@@ -61,10 +67,17 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
// Called back from EmbeddedWorker in the child process, relayed via
// ServiceWorkerDispatcherHost.
- void OnWorkerScriptLoaded(int process_id, int embedded_worker_id);
+ void OnWorkerReadyForInspection(int process_id, int embedded_worker_id);
+ void OnWorkerScriptLoaded(int process_id,
+ int thread_id,
+ int embedded_worker_id);
void OnWorkerScriptLoadFailed(int process_id, int embedded_worker_id);
- void OnWorkerStarted(int process_id, int thread_id, int embedded_worker_id);
+ void OnWorkerScriptEvaluated(int process_id,
+ int embedded_worker_id,
+ bool success);
+ void OnWorkerStarted(int process_id, int embedded_worker_id);
void OnWorkerStopped(int process_id, int embedded_worker_id);
+ void OnPausedAfterDownload(int process_id, int embedded_worker_id);
void OnReportException(int embedded_worker_id,
const base::string16& error_message,
int line_number,
@@ -84,6 +97,9 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
// Returns an embedded worker instance for given |embedded_worker_id|.
EmbeddedWorkerInstance* GetWorker(int embedded_worker_id);
+ // Returns true if |embedded_worker_id| is managed by this registry.
+ bool CanHandle(int embedded_worker_id) const;
+
private:
friend class base::RefCounted<EmbeddedWorkerRegistry>;
friend class EmbeddedWorkerInstance;
@@ -91,6 +107,9 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
typedef std::map<int, EmbeddedWorkerInstance*> WorkerInstanceMap;
typedef std::map<int, IPC::Sender*> ProcessToSenderMap;
+ EmbeddedWorkerRegistry(
+ const base::WeakPtr<ServiceWorkerContextCore>& context,
+ int initial_embedded_worker_id);
~EmbeddedWorkerRegistry();
ServiceWorkerStatusCode Send(int process_id, IPC::Message* message);
@@ -105,10 +124,11 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
ProcessToSenderMap process_sender_map_;
// Map from process_id to embedded_worker_id.
- // This map only contains running workers.
+ // This map only contains starting and running workers.
std::map<int, std::set<int> > worker_process_map_;
int next_embedded_worker_id_;
+ const int initial_embedded_worker_id_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerRegistry);
};
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 82d206142a1..abc0c2b5c88 100644
--- a/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -4,6 +4,9 @@
#include "content/browser/service_worker/embedded_worker_test_helper.h"
+#include <map>
+#include <string>
+
#include "base/bind.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
@@ -18,27 +21,32 @@ namespace content {
EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(int mock_render_process_id)
: wrapper_(new ServiceWorkerContextWrapper(NULL)),
next_thread_id_(0),
+ mock_render_process_id_(mock_render_process_id),
weak_factory_(this) {
+ scoped_ptr<MockServiceWorkerDatabaseTaskManager> database_task_manager(
+ new MockServiceWorkerDatabaseTaskManager(
+ base::MessageLoopProxy::current()));
wrapper_->InitInternal(base::FilePath(),
base::MessageLoopProxy::current(),
+ database_task_manager.Pass(),
base::MessageLoopProxy::current(),
+ NULL,
NULL);
wrapper_->process_manager()->SetProcessIdForTest(mock_render_process_id);
registry()->AddChildProcessSender(mock_render_process_id, this);
}
EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() {
- if (wrapper_)
+ if (wrapper_.get())
wrapper_->Shutdown();
}
-void EmbeddedWorkerTestHelper::SimulateAddProcessToWorker(
- int embedded_worker_id,
+void EmbeddedWorkerTestHelper::SimulateAddProcessToPattern(
+ const GURL& pattern,
int process_id) {
- EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
- ASSERT_TRUE(worker);
registry()->AddChildProcessSender(process_id, this);
- worker->AddProcessReference(process_id);
+ wrapper_->process_manager()->AddProcessReferenceToPattern(
+ pattern, process_id);
}
bool EmbeddedWorkerTestHelper::Send(IPC::Message* message) {
@@ -54,6 +62,8 @@ bool EmbeddedWorkerTestHelper::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(EmbeddedWorkerMsg_StopWorker, OnStopWorkerStub)
IPC_MESSAGE_HANDLER(EmbeddedWorkerContextMsg_MessageToWorker,
OnMessageToWorkerStub)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerMsg_ResumeAfterDownload,
+ OnResumeAfterDownloadStub)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -77,9 +87,23 @@ void EmbeddedWorkerTestHelper::OnStartWorker(
int embedded_worker_id,
int64 service_worker_version_id,
const GURL& scope,
- const GURL& script_url) {
- // By default just notify the sender that the worker is started.
- SimulateWorkerStarted(next_thread_id_++, embedded_worker_id);
+ const GURL& script_url,
+ bool pause_after_download) {
+ if (pause_after_download) {
+ SimulatePausedAfterDownload(embedded_worker_id);
+ return;
+ }
+ SimulateWorkerReadyForInspection(embedded_worker_id);
+ SimulateWorkerScriptLoaded(next_thread_id_++, embedded_worker_id);
+ SimulateWorkerScriptEvaluated(embedded_worker_id);
+ SimulateWorkerStarted(embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::OnResumeAfterDownload(int embedded_worker_id) {
+ SimulateWorkerReadyForInspection(embedded_worker_id);
+ SimulateWorkerScriptLoaded(next_thread_id_++, embedded_worker_id);
+ SimulateWorkerScriptEvaluated(embedded_worker_id);
+ SimulateWorkerStarted(embedded_worker_id);
}
void EmbeddedWorkerTestHelper::OnStopWorker(int embedded_worker_id) {
@@ -125,23 +149,56 @@ void EmbeddedWorkerTestHelper::OnFetchEvent(
int embedded_worker_id,
int request_id,
const ServiceWorkerFetchRequest& request) {
- SimulateSend(
- new ServiceWorkerHostMsg_FetchEventFinished(
- embedded_worker_id,
- request_id,
- SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
- ServiceWorkerResponse(200, "OK",
- std::map<std::string, std::string>(),
- std::string())));
+ SimulateSend(new ServiceWorkerHostMsg_FetchEventFinished(
+ embedded_worker_id,
+ request_id,
+ SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
+ ServiceWorkerResponse(GURL(""),
+ 200,
+ "OK",
+ blink::WebServiceWorkerResponseTypeDefault,
+ ServiceWorkerHeaderMap(),
+ std::string(),
+ 0)));
}
-void EmbeddedWorkerTestHelper::SimulateWorkerStarted(
+void EmbeddedWorkerTestHelper::SimulatePausedAfterDownload(
+ int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ registry()->OnPausedAfterDownload(worker->process_id(), embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::SimulateWorkerReadyForInspection(
+ int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ registry()->OnWorkerReadyForInspection(worker->process_id(),
+ embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::SimulateWorkerScriptLoaded(
int thread_id, int embedded_worker_id) {
EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
ASSERT_TRUE(worker != NULL);
+ registry()->OnWorkerScriptLoaded(
+ worker->process_id(), thread_id, embedded_worker_id);
+}
+
+void EmbeddedWorkerTestHelper::SimulateWorkerScriptEvaluated(
+ int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ registry()->OnWorkerScriptEvaluated(
+ worker->process_id(), embedded_worker_id, true /* success */);
+}
+
+void EmbeddedWorkerTestHelper::SimulateWorkerStarted(
+ int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
registry()->OnWorkerStarted(
worker->process_id(),
- thread_id,
embedded_worker_id);
}
@@ -167,11 +224,23 @@ void EmbeddedWorkerTestHelper::OnStartWorkerStub(
base::MessageLoopProxy::current()->PostTask(
FROM_HERE,
base::Bind(&EmbeddedWorkerTestHelper::OnStartWorker,
+ weak_factory_.GetWeakPtr(),
+ params.embedded_worker_id,
+ params.service_worker_version_id,
+ params.scope,
+ params.script_url,
+ params.pause_after_download));
+}
+
+void EmbeddedWorkerTestHelper::OnResumeAfterDownloadStub(
+ int embedded_worker_id) {
+ EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
+ ASSERT_TRUE(worker != NULL);
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&EmbeddedWorkerTestHelper::OnResumeAfterDownload,
weak_factory_.GetWeakPtr(),
- params.embedded_worker_id,
- params.service_worker_version_id,
- params.scope,
- params.script_url));
+ embedded_worker_id));
}
void EmbeddedWorkerTestHelper::OnStopWorkerStub(int embedded_worker_id) {
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 7cd817df6b9..6640d853fd6 100644
--- a/chromium/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.h
@@ -45,18 +45,18 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
public:
// Initialize this helper for |context|, and enable this as an IPC
// sender for |mock_render_process_id|.
- EmbeddedWorkerTestHelper(int mock_render_process_id);
- virtual ~EmbeddedWorkerTestHelper();
+ explicit EmbeddedWorkerTestHelper(int mock_render_process_id);
+ ~EmbeddedWorkerTestHelper() override;
- // Call this to simulate add/associate a process to a worker.
+ // Call this to simulate add/associate a process to a pattern.
// This also registers this sender for the process.
- void SimulateAddProcessToWorker(int embedded_worker_id, int process_id);
+ void SimulateAddProcessToPattern(const GURL& pattern, int process_id);
// IPC::Sender implementation.
- virtual bool Send(IPC::Message* message) OVERRIDE;
+ bool Send(IPC::Message* message) override;
// IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& msg) override;
// IPC sink for EmbeddedWorker messages.
IPC::TestSink* ipc_sink() { return &sink_; }
@@ -67,6 +67,8 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
ServiceWorkerContextWrapper* context_wrapper() { return wrapper_.get(); }
void ShutdownContext();
+ int mock_render_process_id() const { return mock_render_process_id_;}
+
protected:
// Called when StartWorker, StopWorker and SendMessageToWorker message
// is sent to the embedded worker. Override if necessary. By default
@@ -77,7 +79,9 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
virtual void OnStartWorker(int embedded_worker_id,
int64 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,
@@ -97,15 +101,19 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
// These functions simulate sending an EmbeddedHostMsg message to the
// browser.
- void SimulateWorkerStarted(int thread_id, int embedded_worker_id);
+ void SimulatePausedAfterDownload(int embedded_worker_id);
+ void SimulateWorkerReadyForInspection(int embedded_worker_id);
+ void SimulateWorkerScriptLoaded(int thread_id, int embedded_worker_id);
+ void SimulateWorkerScriptEvaluated(int embedded_worker_id);
+ void SimulateWorkerStarted(int embedded_worker_id);
void SimulateWorkerStopped(int embedded_worker_id);
void SimulateSend(IPC::Message* message);
- protected:
EmbeddedWorkerRegistry* registry();
private:
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,
@@ -121,6 +129,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
IPC::TestSink inner_sink_;
int next_thread_id_;
+ int mock_render_process_id_;
// Updated each time MessageToWorker message is received.
int current_embedded_worker_id_;
diff --git a/chromium/content/browser/service_worker/service_worker_browsertest.cc b/chromium/content/browser/service_worker/service_worker_browsertest.cc
index 8e5b8871f9e..0a67c102206 100644
--- a/chromium/content/browser/service_worker/service_worker_browsertest.cc
+++ b/chromium/content/browser/service_worker/service_worker_browsertest.cc
@@ -6,10 +6,12 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#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_registration.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
@@ -23,13 +25,19 @@
#include "content/public/browser/storage_partition.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/shell/browser/shell.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/common/blob/blob_data.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_interceptor.h"
+#include "net/url_request/url_request_test_job.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/common/blob/blob_data.h"
namespace content {
@@ -39,7 +47,7 @@ struct FetchResult {
ServiceWorkerStatusCode status;
ServiceWorkerFetchEventResult result;
ServiceWorkerResponse response;
- scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
};
void RunAndQuit(const base::Closure& closure,
@@ -72,6 +80,14 @@ void RunOnIOThread(
run_loop.Run();
}
+void ReceivePrepareResult(bool* is_prepared) {
+ *is_prepared = true;
+}
+
+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.
@@ -105,24 +121,156 @@ ServiceWorkerVersion::FetchCallback CreateResponseReceiver(
}
void ReadResponseBody(std::string* body,
- webkit_blob::BlobDataHandle* blob_data_handle) {
+ storage::BlobDataHandle* blob_data_handle) {
ASSERT_TRUE(blob_data_handle);
ASSERT_EQ(1U, blob_data_handle->data()->items().size());
*body = std::string(blob_data_handle->data()->items()[0].bytes(),
blob_data_handle->data()->items()[0].length());
}
+void ExpectResultAndRun(bool expected,
+ const base::Closure& continuation,
+ bool actual) {
+ EXPECT_EQ(expected, actual);
+ continuation.Run();
+}
+
+class WorkerActivatedObserver
+ : public ServiceWorkerContextObserver,
+ public base::RefCountedThreadSafe<WorkerActivatedObserver> {
+ public:
+ explicit WorkerActivatedObserver(ServiceWorkerContextWrapper* context)
+ : context_(context) {}
+ void Init() {
+ RunOnIOThread(base::Bind(&WorkerActivatedObserver::InitOnIOThread, this));
+ }
+ // ServiceWorkerContextObserver overrides.
+ void OnVersionStateChanged(int64 version_id) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ const ServiceWorkerVersion* version =
+ context_->context()->GetLiveVersion(version_id);
+ if (version->status() == ServiceWorkerVersion::ACTIVATED) {
+ context_->RemoveObserver(this);
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&WorkerActivatedObserver::Quit, this));
+ }
+ }
+ void Wait() { run_loop_.Run(); }
+
+ private:
+ friend class base::RefCountedThreadSafe<WorkerActivatedObserver>;
+ ~WorkerActivatedObserver() override {}
+ void InitOnIOThread() { context_->AddObserver(this); }
+ void Quit() { run_loop_.Quit(); }
+
+ base::RunLoop run_loop_;
+ ServiceWorkerContextWrapper* context_;
+ DISALLOW_COPY_AND_ASSIGN(WorkerActivatedObserver);
+};
+
+scoped_ptr<net::test_server::HttpResponse> VerifyServiceWorkerHeaderInRequest(
+ const net::test_server::HttpRequest& request) {
+ EXPECT_EQ(request.relative_url, "/service_worker/generated_sw.js");
+ std::map<std::string, std::string>::const_iterator it =
+ request.headers.find("Service-Worker");
+ EXPECT_TRUE(it != request.headers.end());
+ EXPECT_EQ("script", it->second);
+
+ scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+ new net::test_server::BasicHttpResponse());
+ http_response->set_content_type("text/javascript");
+ return http_response.Pass();
+}
+
+// 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
+// to do that. This interceptor injects headers that give the import
+// an experiration far in the future.
+class LongLivedResourceInterceptor : public net::URLRequestInterceptor {
+ public:
+ LongLivedResourceInterceptor(const std::string& body)
+ : body_(body) {}
+ ~LongLivedResourceInterceptor() override {}
+
+ // net::URLRequestInterceptor implementation
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ const char kHeaders[] =
+ "HTTP/1.1 200 OK\0"
+ "Content-Type: text/javascript\0"
+ "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
+ "\0";
+ std::string headers(kHeaders, arraysize(kHeaders));
+ return new net::URLRequestTestJob(
+ request, network_delegate, headers, body_, true);
+ }
+
+ private:
+ std::string body_;
+ DISALLOW_COPY_AND_ASSIGN(LongLivedResourceInterceptor);
+};
+
+void CreateLongLivedResourceInterceptors(
+ const GURL& worker_url, const GURL& import_url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ scoped_ptr<net::URLRequestInterceptor> interceptor;
+
+ interceptor.reset(new LongLivedResourceInterceptor(
+ "importScripts('long_lived_import.js');"));
+ net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+ worker_url, interceptor.Pass());
+
+ interceptor.reset(new LongLivedResourceInterceptor(
+ "// the imported script does nothing"));
+ net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+ import_url, interceptor.Pass());
+}
+
+void CountScriptResources(
+ ServiceWorkerContextWrapper* wrapper,
+ const GURL& scope,
+ int* num_resources) {
+ *num_resources = -1;
+
+ std::vector<ServiceWorkerRegistrationInfo> infos =
+ wrapper->context()->GetAllLiveRegistrationInfo();
+ if (infos.empty())
+ return;
+
+ int version_id;
+ size_t index = infos.size() - 1;
+ if (infos[index].installing_version.version_id !=
+ kInvalidServiceWorkerVersionId)
+ version_id = infos[index].installing_version.version_id;
+ else if (infos[index].waiting_version.version_id !=
+ kInvalidServiceWorkerVersionId)
+ version_id = infos[1].waiting_version.version_id;
+ else if (infos[index].active_version.version_id !=
+ kInvalidServiceWorkerVersionId)
+ version_id = infos[index].active_version.version_id;
+ else
+ return;
+
+ ServiceWorkerVersion* version =
+ wrapper->context()->GetLiveVersion(version_id);
+ *num_resources = static_cast<int>(version->script_cache_map()->size());
+}
+
} // namespace
class ServiceWorkerBrowserTest : public ContentBrowserTest {
protected:
typedef ServiceWorkerBrowserTest self;
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
- command_line->AppendSwitch(switches::kEnableServiceWorker);
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
shell()->web_contents()->GetBrowserContext());
@@ -138,7 +286,7 @@ class ServiceWorkerBrowserTest : public ContentBrowserTest {
RunOnIOThread(base::Bind(&self::SetUpOnIOThread, this));
}
- virtual void TearDownOnMainThread() OVERRIDE {
+ void TearDownOnMainThread() override {
RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this));
wrapper_ = NULL;
}
@@ -149,9 +297,9 @@ class ServiceWorkerBrowserTest : public ContentBrowserTest {
ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
ServiceWorkerContext* public_context() { return wrapper(); }
- void AssociateRendererProcessToWorker(EmbeddedWorkerInstance* worker) {
- worker->AddProcessReference(
- shell()->web_contents()->GetRenderProcessHost()->GetID());
+ void AssociateRendererProcessToPattern(const GURL& pattern) {
+ wrapper_->process_manager()->AddProcessReferenceToPattern(
+ pattern, shell()->web_contents()->GetRenderProcessHost()->GetID());
}
private:
@@ -164,10 +312,11 @@ class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
typedef EmbeddedWorkerBrowserTest self;
EmbeddedWorkerBrowserTest()
- : last_worker_status_(EmbeddedWorkerInstance::STOPPED) {}
- virtual ~EmbeddedWorkerBrowserTest() {}
+ : last_worker_status_(EmbeddedWorkerInstance::STOPPED),
+ pause_mode_(DONT_PAUSE) {}
+ ~EmbeddedWorkerBrowserTest() override {}
- virtual void TearDownOnIOThread() OVERRIDE {
+ void TearDownOnIOThread() override {
if (worker_) {
worker_->RemoveListener(this);
worker_.reset();
@@ -180,20 +329,20 @@ class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
worker_->AddListener(this);
- AssociateRendererProcessToWorker(worker_.get());
const int64 service_worker_version_id = 33L;
- const GURL scope = embedded_test_server()->GetURL("/*");
+ const GURL pattern = embedded_test_server()->GetURL("/");
const GURL script_url = embedded_test_server()->GetURL(
"/service_worker/worker.js");
- std::vector<int> processes;
- processes.push_back(
- shell()->web_contents()->GetRenderProcessHost()->GetID());
+ AssociateRendererProcessToPattern(pattern);
+ int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
+ wrapper()->process_manager()->AddProcessReferenceToPattern(
+ pattern, process_id);
worker_->Start(
service_worker_version_id,
- scope,
+ pattern,
script_url,
- processes,
+ pause_mode_ != DONT_PAUSE,
base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
}
void StartOnIOThread2(ServiceWorkerStatusCode status) {
@@ -221,34 +370,46 @@ class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
protected:
// EmbeddedWorkerInstance::Observer overrides:
- virtual void OnStarted() OVERRIDE {
+ void OnStarted() override {
ASSERT_TRUE(worker_ != NULL);
ASSERT_FALSE(done_closure_.is_null());
last_worker_status_ = worker_->status();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
}
- virtual void OnStopped() OVERRIDE {
+ void OnStopped() override {
ASSERT_TRUE(worker_ != NULL);
ASSERT_FALSE(done_closure_.is_null());
last_worker_status_ = worker_->status();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
}
- virtual void OnReportException(const base::string16& error_message,
- int line_number,
- int column_number,
- const GURL& source_url) OVERRIDE {}
- virtual void OnReportConsoleMessage(int source_identifier,
- int message_level,
- const base::string16& message,
- int line_number,
- const GURL& source_url) OVERRIDE {}
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
- return false;
- }
+ void OnPausedAfterDownload() override {
+ if (pause_mode_ == PAUSE_THEN_RESUME)
+ worker_->ResumeAfterDownload();
+ else if (pause_mode_ == PAUSE_THEN_STOP)
+ worker_->Stop();
+ else
+ ASSERT_TRUE(false);
+ }
+ void OnReportException(const base::string16& error_message,
+ int line_number,
+ int column_number,
+ const GURL& source_url) override {}
+ void OnReportConsoleMessage(int source_identifier,
+ int message_level,
+ const base::string16& message,
+ int line_number,
+ const GURL& source_url) override {}
+ bool OnMessageReceived(const IPC::Message& message) override { return false; }
scoped_ptr<EmbeddedWorkerInstance> worker_;
EmbeddedWorkerInstance::Status last_worker_status_;
+ enum {
+ DONT_PAUSE,
+ PAUSE_THEN_RESUME,
+ PAUSE_THEN_STOP,
+ } pause_mode_;
+
// Called by EmbeddedWorkerInstance::Observer overrides so that
// test code can wait for the worker status notifications.
base::Closure done_closure_;
@@ -258,9 +419,9 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
public:
typedef ServiceWorkerVersionBrowserTest self;
- virtual ~ServiceWorkerVersionBrowserTest() {}
+ ~ServiceWorkerVersionBrowserTest() override {}
- virtual void TearDownOnIOThread() OVERRIDE {
+ void TearDownOnIOThread() override {
registration_ = NULL;
version_ = NULL;
}
@@ -296,7 +457,6 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
ServiceWorkerStatusCode expected_status) {
RunOnIOThread(
base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
- version_->SetStatus(ServiceWorkerVersion::INSTALLED);
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
base::RunLoop run_loop;
BrowserThread::PostTask(
@@ -311,9 +471,10 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
void FetchOnRegisteredWorker(
ServiceWorkerFetchEventResult* result,
ServiceWorkerResponse* response,
- scoped_ptr<webkit_blob::BlobDataHandle>* blob_data_handle) {
+ scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
blob_context_ = ChromeBlobStorageContext::GetFor(
shell()->web_contents()->GetBrowserContext());
+ bool prepare_result = false;
FetchResult fetch_result;
fetch_result.status = SERVICE_WORKER_ERROR_FAILED;
base::RunLoop fetch_run_loop;
@@ -322,35 +483,37 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
base::Bind(&self::FetchOnIOThread,
this,
fetch_run_loop.QuitClosure(),
+ &prepare_result,
&fetch_result));
fetch_run_loop.Run();
+ ASSERT_TRUE(prepare_result);
*result = fetch_result.result;
*response = fetch_result.response;
*blob_data_handle = fetch_result.blob_data_handle.Pass();
ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status);
}
- void FetchTestHelper(
- const std::string& worker_url,
- ServiceWorkerFetchEventResult* result,
- ServiceWorkerResponse* response,
- scoped_ptr<webkit_blob::BlobDataHandle>* blob_data_handle) {
+ void FetchTestHelper(const std::string& worker_url,
+ ServiceWorkerFetchEventResult* result,
+ ServiceWorkerResponse* response,
+ scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
RunOnIOThread(
base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
FetchOnRegisteredWorker(result, response, blob_data_handle);
}
void SetUpRegistrationOnIOThread(const std::string& worker_url) {
+ const GURL pattern = embedded_test_server()->GetURL("/");
registration_ = new ServiceWorkerRegistration(
- embedded_test_server()->GetURL("/*"),
- embedded_test_server()->GetURL(worker_url),
+ pattern,
wrapper()->context()->storage()->NewRegistrationId(),
wrapper()->context()->AsWeakPtr());
version_ = new ServiceWorkerVersion(
- registration_,
+ registration_.get(),
+ embedded_test_server()->GetURL(worker_url),
wrapper()->context()->storage()->NewVersionId(),
wrapper()->context()->AsWeakPtr());
- AssociateRendererProcessToWorker(version_->embedded_worker());
+ AssociateRendererProcessToPattern(pattern);
}
void StartOnIOThread(const base::Closure& done,
@@ -362,6 +525,7 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
void InstallOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ version_->SetStatus(ServiceWorkerVersion::INSTALLING);
version_->DispatchInstallEvent(
-1, CreateReceiver(BrowserThread::UI, done, result));
}
@@ -369,33 +533,39 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
void ActivateOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
- version_->SetStatus(ServiceWorkerVersion::INSTALLED);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
version_->DispatchActivateEvent(
CreateReceiver(BrowserThread::UI, done, result));
}
- void FetchOnIOThread(const base::Closure& done, FetchResult* result) {
+ 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",
- std::map<std::string, std::string>());
- version_->SetStatus(ServiceWorkerVersion::ACTIVE);
+ ServiceWorkerHeaderMap(),
+ GURL(""),
+ false);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
version_->DispatchFetchEvent(
- request, CreateResponseReceiver(BrowserThread::UI, done,
- blob_context_, result));
+ request,
+ CreatePrepareReceiver(prepare_result),
+ CreateResponseReceiver(
+ BrowserThread::UI, done, blob_context_.get(), result));
}
void StopOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
- ASSERT_TRUE(version_);
+ ASSERT_TRUE(version_.get());
version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
}
void SyncEventOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
- version_->SetStatus(ServiceWorkerVersion::ACTIVE);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
version_->DispatchSyncEvent(
CreateReceiver(BrowserThread::UI, done, result));
}
@@ -426,6 +596,27 @@ IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
}
+IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartPaused_ThenResume) {
+ pause_mode_ = PAUSE_THEN_RESUME;
+ base::RunLoop start_run_loop;
+ done_closure_ = start_run_loop.QuitClosure();
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StartOnIOThread, this));
+ start_run_loop.Run();
+ ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
+}
+
+IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
+ StartPaused_ThenStop) {
+ pause_mode_ = PAUSE_THEN_STOP;
+ base::RunLoop start_run_loop;
+ done_closure_ = start_run_loop.QuitClosure();
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StartOnIOThread, this));
+ start_run_loop.Run();
+ ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
+}
+
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
"/service_worker/worker.js"));
@@ -476,10 +667,19 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
SERVICE_WORKER_OK);
}
+// Check that ServiceWorker script requests set a "Service-Worker: script"
+// header.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+ ServiceWorkerScriptHeader) {
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&VerifyServiceWorkerHeaderInRequest));
+ InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
+}
+
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
Activate_NoEventListener) {
ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
- ASSERT_EQ(ServiceWorkerVersion::ACTIVE, version_->status());
+ ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
@@ -496,15 +696,15 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
ServiceWorkerFetchEventResult result;
ServiceWorkerResponse response;
- scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
FetchTestHelper("/service_worker/fetch_event.js",
&result, &response, &blob_data_handle);
ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
EXPECT_EQ(301, response.status_code);
EXPECT_EQ("Moved Permanently", response.status_text);
- std::map<std::string, std::string> expected_headers;
- expected_headers["Content-Language"] = "fi";
- expected_headers["Content-Type"] = "text/html; charset=UTF-8";
+ ServiceWorkerHeaderMap expected_headers;
+ expected_headers["content-language"] = "fi";
+ expected_headers["content-type"] = "text/html; charset=UTF-8";
EXPECT_EQ(expected_headers, response.headers);
std::string body;
@@ -533,14 +733,14 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
- CommandLine* command_line = CommandLine::ForCurrentProcess();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitch(switches::kEnableServiceWorkerSync);
RunOnIOThread(base::Bind(
&self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
ServiceWorkerFetchEventResult result;
ServiceWorkerResponse response;
- scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
// Should 404 before sync event.
FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
EXPECT_EQ(404, response.status_code);
@@ -562,42 +762,94 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
EXPECT_EQ(200, response.status_code);
}
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, Reload) {
+ const std::string kPageUrl = "/service_worker/reload.html";
+ const std::string kWorkerUrl = "/service_worker/fetch_event_reload.js";
+ {
+ 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("reload=false");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ }
+ {
+ const base::string16 title = base::ASCIIToUTF16("reload=true");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ ReloadBlockUntilNavigationsComplete(shell(), 1);
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ }
+ 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, ImportsBustMemcache) {
+ const std::string kScopeUrl = "/service_worker/imports_bust_memcache_scope/";
+ const std::string kPageUrl = "/service_worker/imports_bust_memcache.html";
+ const std::string kScriptUrl = "/service_worker/worker_with_one_import.js";
+ const std::string kImportUrl = "/service_worker/long_lived_import.js";
+ const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
+ const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
+
+ RunOnIOThread(
+ base::Bind(&CreateLongLivedResourceInterceptors,
+ embedded_test_server()->GetURL(kScriptUrl),
+ embedded_test_server()->GetURL(kImportUrl)));
+
+ TitleWatcher title_watcher(shell()->web_contents(), kOKTitle);
+ title_watcher.AlsoWaitForTitle(kFailTitle);
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+ base::string16 title = title_watcher.WaitAndGetTitle();
+ EXPECT_EQ(kOKTitle, title);
+
+ // Verify the number of resources in the implicit script cache is correct.
+ const int kExpectedNumResources = 2;
+ int num_resources = 0;
+ RunOnIOThread(
+ base::Bind(&CountScriptResources,
+ base::Unretained(wrapper()),
+ embedded_test_server()->GetURL(kScopeUrl),
+ &num_resources));
+ EXPECT_EQ(kExpectedNumResources, num_resources);
+}
+
class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
public:
typedef ServiceWorkerBlackBoxBrowserTest self;
- static void ExpectResultAndRun(bool expected,
- const base::Closure& continuation,
- bool actual) {
- EXPECT_EQ(expected, actual);
- continuation.Run();
- }
-
void FindRegistrationOnIO(const GURL& document_url,
ServiceWorkerStatusCode* status,
- GURL* script_url,
const base::Closure& continuation) {
wrapper()->context()->storage()->FindRegistrationForDocument(
document_url,
base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
this,
status,
- script_url,
continuation));
}
void FindRegistrationOnIO2(
ServiceWorkerStatusCode* out_status,
- GURL* script_url,
const base::Closure& continuation,
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
*out_status = status;
- if (registration) {
- *script_url = registration->script_url();
- } else {
+ if (!registration.get())
EXPECT_NE(SERVICE_WORKER_OK, status);
- }
continuation.Run();
}
};
@@ -612,8 +864,8 @@ static int CountRenderProcessHosts() {
return result;
}
-// Crashes on Android: http://crbug.com/387045
-#if defined(OS_ANDROID)
+// Flaky timeouts on CrOS: http://crbug.com/387045
+#if defined(OS_CHROMEOS)
#define MAYBE_Registration DISABLED_Registration
#else
#define MAYBE_Registration Registration
@@ -625,14 +877,12 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
const std::string kWorkerUrl = "/service_worker/fetch_event.js";
- // Unregistering nothing should return true.
+ // Unregistering nothing should return false.
{
base::RunLoop run_loop;
public_context()->UnregisterServiceWorker(
- embedded_test_server()->GetURL("/*"),
- base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
- true,
- run_loop.QuitClosure()));
+ embedded_test_server()->GetURL("/"),
+ base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
run_loop.Run();
}
@@ -640,11 +890,9 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
{
base::RunLoop run_loop;
public_context()->RegisterServiceWorker(
- embedded_test_server()->GetURL("/*"),
+ embedded_test_server()->GetURL("/"),
embedded_test_server()->GetURL("/does/not/exist"),
- base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
- false,
- run_loop.QuitClosure()));
+ base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
run_loop.Run();
}
EXPECT_EQ(0, CountRenderProcessHosts());
@@ -653,11 +901,9 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
{
base::RunLoop run_loop;
public_context()->RegisterServiceWorker(
- embedded_test_server()->GetURL("/*"),
+ embedded_test_server()->GetURL("/"),
embedded_test_server()->GetURL(kWorkerUrl),
- base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
- true,
- run_loop.QuitClosure()));
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
run_loop.Run();
}
EXPECT_EQ(1, CountRenderProcessHosts());
@@ -667,11 +913,9 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
{
base::RunLoop run_loop;
public_context()->RegisterServiceWorker(
- embedded_test_server()->GetURL("/*"),
+ embedded_test_server()->GetURL("/"),
embedded_test_server()->GetURL(kWorkerUrl),
- base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
- true,
- run_loop.QuitClosure()));
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
run_loop.Run();
}
@@ -683,10 +927,8 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
{
base::RunLoop run_loop;
public_context()->UnregisterServiceWorker(
- embedded_test_server()->GetURL("/*"),
- base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
- true,
- run_loop.QuitClosure()));
+ embedded_test_server()->GetURL("/"),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
run_loop.Run();
}
EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
@@ -696,13 +938,11 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
// Should not be able to find it.
{
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- GURL script_url;
RunOnIOThread(
base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
this,
embedded_test_server()->GetURL("/service_worker/empty.html"),
- &status,
- &script_url));
+ &status));
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
}
}
diff --git a/chromium/content/browser/service_worker/service_worker_cache.cc b/chromium/content/browser/service_worker/service_worker_cache.cc
new file mode 100644
index 00000000000..c19793af49e
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache.cc
@@ -0,0 +1,1259 @@
+// 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/service_worker/service_worker_cache.h"
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/guid.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/strings/string_util.h"
+#include "content/browser/service_worker/service_worker_cache.pb.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/url_request/url_request_context.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_url_request_job_factory.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
+
+namespace content {
+
+namespace {
+
+typedef scoped_ptr<disk_cache::Backend> ScopedBackendPtr;
+typedef base::Callback<void(bool)> BoolCallback;
+typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
+ EntryBoolCallback;
+typedef base::Callback<void(scoped_ptr<ServiceWorkerCacheMetadata>)>
+ 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;
+
+// Buffer size for cache and blob reading/writing.
+const int kBufferSize = 1024 * 512;
+
+void NotReachedCompletionCallback(int rv) {
+ NOTREACHED();
+}
+
+blink::WebServiceWorkerResponseType ProtoResponseTypeToWebResponseType(
+ ServiceWorkerCacheResponse::ResponseType response_type) {
+ switch (response_type) {
+ case ServiceWorkerCacheResponse::BASIC_TYPE:
+ return blink::WebServiceWorkerResponseTypeBasic;
+ case ServiceWorkerCacheResponse::CORS_TYPE:
+ return blink::WebServiceWorkerResponseTypeCORS;
+ case ServiceWorkerCacheResponse::DEFAULT_TYPE:
+ return blink::WebServiceWorkerResponseTypeDefault;
+ case ServiceWorkerCacheResponse::ERROR_TYPE:
+ return blink::WebServiceWorkerResponseTypeError;
+ case ServiceWorkerCacheResponse::OPAQUE_TYPE:
+ return blink::WebServiceWorkerResponseTypeOpaque;
+ }
+ NOTREACHED();
+ return blink::WebServiceWorkerResponseTypeOpaque;
+}
+
+ServiceWorkerCacheResponse::ResponseType WebResponseTypeToProtoResponseType(
+ blink::WebServiceWorkerResponseType response_type) {
+ switch (response_type) {
+ case blink::WebServiceWorkerResponseTypeBasic:
+ return ServiceWorkerCacheResponse::BASIC_TYPE;
+ case blink::WebServiceWorkerResponseTypeCORS:
+ return ServiceWorkerCacheResponse::CORS_TYPE;
+ case blink::WebServiceWorkerResponseTypeDefault:
+ return ServiceWorkerCacheResponse::DEFAULT_TYPE;
+ case blink::WebServiceWorkerResponseTypeError:
+ return ServiceWorkerCacheResponse::ERROR_TYPE;
+ case blink::WebServiceWorkerResponseTypeOpaque:
+ return ServiceWorkerCacheResponse::OPAQUE_TYPE;
+ }
+ NOTREACHED();
+ return ServiceWorkerCacheResponse::OPAQUE_TYPE;
+}
+
+struct ResponseReadContext {
+ ResponseReadContext(scoped_refptr<net::IOBufferWithSize> buff,
+ scoped_refptr<storage::BlobData> blob)
+ : buffer(buff), blob_data(blob), total_bytes_read(0) {}
+
+ scoped_refptr<net::IOBufferWithSize> buffer;
+ scoped_refptr<storage::BlobData> blob_data;
+ int total_bytes_read;
+
+ DISALLOW_COPY_AND_ASSIGN(ResponseReadContext);
+};
+
+// Match callbacks
+void MatchDidOpenEntry(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage,
+ scoped_ptr<disk_cache::Entry*> entryptr,
+ int rv);
+void MatchDidReadMetadata(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage,
+ disk_cache::ScopedEntryPtr entry,
+ scoped_ptr<ServiceWorkerCacheMetadata> headers);
+void MatchDidReadResponseBodyData(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage,
+ disk_cache::ScopedEntryPtr entry,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<ResponseReadContext> response_context,
+ int rv);
+void MatchDoneWithBody(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<ResponseReadContext> response_context);
+
+// Delete callbacks
+void DeleteDidOpenEntry(
+ const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ErrorCallback& callback,
+ scoped_ptr<disk_cache::Entry*> entryptr,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ int rv);
+
+// 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);
+
+// CreateBackend callbacks
+void CreateBackendDidCreate(const ServiceWorkerCache::ErrorCallback& callback,
+ scoped_ptr<ScopedBackendPtr> backend_ptr,
+ base::WeakPtr<ServiceWorkerCache> cache,
+ int rv);
+
+void MatchDidOpenEntry(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage,
+ scoped_ptr<disk_cache::Entry*> entryptr,
+ int rv) {
+ if (rv != net::OK) {
+ callback.Run(ServiceWorkerCache::ErrorTypeNotFound,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ DCHECK(entryptr);
+ disk_cache::ScopedEntryPtr entry(*entryptr);
+
+ // Copy the entry pointer before passing it in base::Bind.
+ disk_cache::Entry* tmp_entry_ptr = entry.get();
+
+ MetadataCallback headers_callback = base::Bind(MatchDidReadMetadata,
+ base::Passed(request.Pass()),
+ callback,
+ blob_storage,
+ base::Passed(entry.Pass()));
+
+ ReadMetadata(tmp_entry_ptr, headers_callback);
+}
+
+bool VaryMatches(const ServiceWorkerHeaderMap& request,
+ const ServiceWorkerHeaderMap& cached_request,
+ const ServiceWorkerHeaderMap& response) {
+ ServiceWorkerHeaderMap::const_iterator vary_iter = response.find("vary");
+ if (vary_iter == response.end())
+ return true;
+
+ std::vector<std::string> vary_keys;
+ Tokenize(vary_iter->second, ",", &vary_keys);
+ for (std::vector<std::string>::const_iterator it = vary_keys.begin();
+ it != vary_keys.end();
+ ++it) {
+ std::string trimmed;
+ base::TrimWhitespaceASCII(*it, base::TRIM_ALL, &trimmed);
+ if (trimmed == "*")
+ return false;
+
+ ServiceWorkerHeaderMap::const_iterator request_iter = request.find(trimmed);
+ ServiceWorkerHeaderMap::const_iterator cached_request_iter =
+ cached_request.find(trimmed);
+
+ // If the header exists in one but not the other, no match.
+ if ((request_iter == request.end()) !=
+ (cached_request_iter == cached_request.end()))
+ return false;
+
+ // If the header exists in one, it exists in both. Verify that the values
+ // are equal.
+ if (request_iter != request.end() &&
+ request_iter->second != cached_request_iter->second)
+ return false;
+ }
+
+ return true;
+}
+
+void MatchDidReadMetadata(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage,
+ disk_cache::ScopedEntryPtr entry,
+ scoped_ptr<ServiceWorkerCacheMetadata> metadata) {
+ if (!metadata) {
+ callback.Run(ServiceWorkerCache::ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ scoped_ptr<ServiceWorkerResponse> response(new ServiceWorkerResponse(
+ request->url,
+ metadata->response().status_code(),
+ metadata->response().status_text(),
+ ProtoResponseTypeToWebResponseType(metadata->response().response_type()),
+ ServiceWorkerHeaderMap(),
+ "",
+ 0));
+
+ if (metadata->response().has_url())
+ response->url = GURL(metadata->response().url());
+
+ for (int i = 0; i < metadata->response().headers_size(); ++i) {
+ const ServiceWorkerCacheHeaderMap header = metadata->response().headers(i);
+ response->headers.insert(std::make_pair(header.name(), header.value()));
+ }
+
+ ServiceWorkerHeaderMap cached_request_headers;
+ for (int i = 0; i < metadata->request().headers_size(); ++i) {
+ const ServiceWorkerCacheHeaderMap header = metadata->request().headers(i);
+ cached_request_headers[header.name()] = header.value();
+ }
+
+ if (!VaryMatches(
+ request->headers, cached_request_headers, response->headers)) {
+ callback.Run(ServiceWorkerCache::ErrorTypeNotFound,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ if (entry->GetDataSize(INDEX_RESPONSE_BODY) == 0) {
+ callback.Run(ServiceWorkerCache::ErrorTypeOK,
+ response.Pass(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ // Stream the response body into a blob.
+ if (!blob_storage) {
+ callback.Run(ServiceWorkerCache::ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ response->blob_uuid = base::GenerateGUID();
+
+ scoped_refptr<storage::BlobData> blob_data =
+ new storage::BlobData(response->blob_uuid);
+ scoped_refptr<net::IOBufferWithSize> response_body_buffer(
+ new net::IOBufferWithSize(kBufferSize));
+
+ scoped_ptr<ResponseReadContext> read_context(
+ new ResponseReadContext(response_body_buffer, blob_data));
+
+ // Copy the entry pointer before passing it in base::Bind.
+ disk_cache::Entry* tmp_entry_ptr = entry.get();
+
+ net::CompletionCallback read_callback =
+ base::Bind(MatchDidReadResponseBodyData,
+ base::Passed(request.Pass()),
+ callback,
+ blob_storage,
+ base::Passed(entry.Pass()),
+ base::Passed(response.Pass()),
+ base::Passed(read_context.Pass()));
+
+ int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY,
+ 0,
+ response_body_buffer.get(),
+ response_body_buffer->size(),
+ read_callback);
+
+ if (read_rv != net::ERR_IO_PENDING)
+ read_callback.Run(read_rv);
+}
+
+void MatchDidReadResponseBodyData(
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage,
+ disk_cache::ScopedEntryPtr entry,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<ResponseReadContext> response_context,
+ int rv) {
+ if (rv < 0) {
+ callback.Run(ServiceWorkerCache::ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ if (rv == 0) {
+ response->blob_uuid = response_context->blob_data->uuid();
+ response->blob_size = response_context->total_bytes_read;
+ MatchDoneWithBody(request.Pass(),
+ callback,
+ blob_storage,
+ response.Pass(),
+ response_context.Pass());
+ return;
+ }
+
+ // TODO(jkarlin): This copying of the the entire cache response into memory is
+ // awful. Create a new interface around SimpleCache that provides access the
+ // data directly from the file. See bug http://crbug.com/403493.
+ response_context->blob_data->AppendData(response_context->buffer->data(), rv);
+ response_context->total_bytes_read += rv;
+ int total_bytes_read = response_context->total_bytes_read;
+
+ // Grab some pointers before passing them in bind.
+ net::IOBufferWithSize* buffer = response_context->buffer.get();
+ disk_cache::Entry* tmp_entry_ptr = entry.get();
+
+ net::CompletionCallback read_callback =
+ base::Bind(MatchDidReadResponseBodyData,
+ base::Passed(request.Pass()),
+ callback,
+ blob_storage,
+ base::Passed(entry.Pass()),
+ base::Passed(response.Pass()),
+ base::Passed(response_context.Pass()));
+
+ int read_rv = tmp_entry_ptr->ReadData(INDEX_RESPONSE_BODY,
+ total_bytes_read,
+ buffer,
+ buffer->size(),
+ read_callback);
+
+ if (read_rv != net::ERR_IO_PENDING)
+ read_callback.Run(read_rv);
+}
+
+void MatchDoneWithBody(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<ResponseReadContext> response_context) {
+ if (!blob_storage) {
+ callback.Run(ServiceWorkerCache::ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle(
+ blob_storage->AddFinishedBlob(response_context->blob_data.get()));
+
+ callback.Run(ServiceWorkerCache::ErrorTypeOK,
+ response.Pass(),
+ blob_data_handle.Pass());
+}
+
+void DeleteDidOpenEntry(
+ const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ServiceWorkerCache::ErrorCallback& callback,
+ scoped_ptr<disk_cache::Entry*> entryptr,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ int rv) {
+ if (rv != net::OK) {
+ callback.Run(ServiceWorkerCache::ErrorTypeNotFound);
+ return;
+ }
+
+ DCHECK(entryptr);
+ disk_cache::ScopedEntryPtr entry(*entryptr);
+
+ 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();
+ callback.Run(ServiceWorkerCache::ErrorTypeOK);
+}
+
+void ReadMetadata(disk_cache::Entry* entry, const MetadataCallback& callback) {
+ DCHECK(entry);
+
+ scoped_refptr<net::IOBufferWithSize> buffer(
+ new net::IOBufferWithSize(entry->GetDataSize(INDEX_HEADERS)));
+
+ net::CompletionCallback read_header_callback =
+ base::Bind(ReadMetadataDidReadMetadata, entry, callback, buffer);
+
+ int read_rv = entry->ReadData(
+ INDEX_HEADERS, 0, buffer.get(), buffer->size(), read_header_callback);
+
+ if (read_rv != net::ERR_IO_PENDING)
+ read_header_callback.Run(read_rv);
+}
+
+void ReadMetadataDidReadMetadata(
+ disk_cache::Entry* entry,
+ const MetadataCallback& callback,
+ const scoped_refptr<net::IOBufferWithSize>& buffer,
+ int rv) {
+ if (rv != buffer->size()) {
+ callback.Run(scoped_ptr<ServiceWorkerCacheMetadata>());
+ return;
+ }
+
+ scoped_ptr<ServiceWorkerCacheMetadata> metadata(
+ new ServiceWorkerCacheMetadata());
+
+ if (!metadata->ParseFromArray(buffer->data(), buffer->size())) {
+ callback.Run(scoped_ptr<ServiceWorkerCacheMetadata>());
+ return;
+ }
+
+ callback.Run(metadata.Pass());
+}
+
+void CreateBackendDidCreate(const ServiceWorkerCache::ErrorCallback& callback,
+ scoped_ptr<ScopedBackendPtr> backend_ptr,
+ base::WeakPtr<ServiceWorkerCache> cache,
+ int rv) {
+ if (rv != net::OK || !cache) {
+ callback.Run(ServiceWorkerCache::ErrorTypeStorage);
+ return;
+ }
+
+ cache->set_backend(backend_ptr->Pass());
+ callback.Run(ServiceWorkerCache::ErrorTypeOK);
+}
+
+} // namespace
+
+// Streams data from a blob and writes it to a given disk_cache::Entry.
+class ServiceWorkerCache::BlobReader : public net::URLRequest::Delegate {
+ public:
+ typedef base::Callback<void(disk_cache::ScopedEntryPtr, bool)>
+ EntryAndBoolCallback;
+
+ BlobReader()
+ : cache_entry_offset_(0),
+ buffer_(new net::IOBufferWithSize(kBufferSize)),
+ weak_ptr_factory_(this) {}
+
+ // |entry| is passed to the callback once complete.
+ void StreamBlobToCache(disk_cache::ScopedEntryPtr entry,
+ net::URLRequestContext* request_context,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle,
+ const EntryAndBoolCallback& callback) {
+ DCHECK(entry);
+ entry_ = entry.Pass();
+ callback_ = callback;
+ blob_request_ = storage::BlobProtocolHandler::CreateBlobRequest(
+ blob_data_handle.Pass(), request_context, this);
+ blob_request_->Start();
+ }
+
+ // net::URLRequest::Delegate overrides for reading blobs.
+ void OnReceivedRedirect(net::URLRequest* request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) override {
+ NOTREACHED();
+ }
+ void OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info) override {
+ NOTREACHED();
+ }
+ void OnCertificateRequested(
+ net::URLRequest* request,
+ net::SSLCertRequestInfo* cert_request_info) override {
+ NOTREACHED();
+ }
+ void OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) override {
+ NOTREACHED();
+ }
+ void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override {
+ NOTREACHED();
+ }
+
+ void OnResponseStarted(net::URLRequest* request) override {
+ if (!request->status().is_success()) {
+ callback_.Run(entry_.Pass(), false);
+ return;
+ }
+ ReadFromBlob();
+ }
+
+ virtual void ReadFromBlob() {
+ int bytes_read = 0;
+ bool done =
+ blob_request_->Read(buffer_.get(), buffer_->size(), &bytes_read);
+ if (done)
+ OnReadCompleted(blob_request_.get(), bytes_read);
+ }
+
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
+ if (!request->status().is_success()) {
+ callback_.Run(entry_.Pass(), false);
+ return;
+ }
+
+ if (bytes_read == 0) {
+ callback_.Run(entry_.Pass(), true);
+ return;
+ }
+
+ net::CompletionCallback cache_write_callback =
+ base::Bind(&BlobReader::DidWriteDataToEntry,
+ weak_ptr_factory_.GetWeakPtr(),
+ bytes_read);
+
+ int rv = entry_->WriteData(INDEX_RESPONSE_BODY,
+ cache_entry_offset_,
+ buffer_.get(),
+ bytes_read,
+ cache_write_callback,
+ true /* truncate */);
+ if (rv != net::ERR_IO_PENDING)
+ cache_write_callback.Run(rv);
+ }
+
+ void DidWriteDataToEntry(int expected_bytes, int rv) {
+ if (rv != expected_bytes) {
+ callback_.Run(entry_.Pass(), false);
+ return;
+ }
+
+ cache_entry_offset_ += rv;
+ ReadFromBlob();
+ }
+
+ private:
+ int cache_entry_offset_;
+ disk_cache::ScopedEntryPtr entry_;
+ scoped_ptr<net::URLRequest> blob_request_;
+ EntryAndBoolCallback callback_;
+ scoped_refptr<net::IOBufferWithSize> buffer_;
+ base::WeakPtrFactory<BlobReader> weak_ptr_factory_;
+};
+
+// The state needed to pass between ServiceWorkerCache::Keys callbacks.
+struct ServiceWorkerCache::KeysContext {
+ KeysContext(const ServiceWorkerCache::RequestsCallback& callback,
+ base::WeakPtr<ServiceWorkerCache> cache)
+ : original_callback(callback),
+ cache(cache),
+ out_keys(new ServiceWorkerCache::Requests()),
+ enumerated_entry(NULL) {}
+
+ ~KeysContext() {
+ for (size_t i = 0, max = entries.size(); i < max; ++i)
+ entries[i]->Close();
+ if (enumerated_entry)
+ enumerated_entry->Close();
+ }
+
+ // The callback passed to the Keys() function.
+ ServiceWorkerCache::RequestsCallback original_callback;
+
+ // The ServiceWorkerCache that Keys was called on.
+ base::WeakPtr<ServiceWorkerCache> cache;
+
+ // The vector of open entries in the backend.
+ Entries entries;
+
+ // The output of the Keys function.
+ scoped_ptr<ServiceWorkerCache::Requests> out_keys;
+
+ // Used for enumerating cache entries.
+ scoped_ptr<disk_cache::Backend::Iterator> backend_iterator;
+ disk_cache::Entry* enumerated_entry;
+
+ DISALLOW_COPY_AND_ASSIGN(KeysContext);
+};
+
+// The state needed to pass between ServiceWorkerCache::Put callbacks.
+struct ServiceWorkerCache::PutContext {
+ PutContext(
+ const GURL& origin,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle,
+ const ServiceWorkerCache::ResponseCallback& callback,
+ base::WeakPtr<ServiceWorkerCache> cache,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
+ : origin(origin),
+ request(request.Pass()),
+ response(response.Pass()),
+ blob_data_handle(blob_data_handle.Pass()),
+ callback(callback),
+ cache(cache),
+ request_context(request_context),
+ quota_manager_proxy(quota_manager_proxy),
+ cache_entry(NULL) {}
+ ~PutContext() {
+ if (cache_entry)
+ cache_entry->Close();
+ }
+
+ // Input parameters to the Put function.
+ GURL origin;
+ scoped_ptr<ServiceWorkerFetchRequest> request;
+ scoped_ptr<ServiceWorkerResponse> response;
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
+ ServiceWorkerCache::ResponseCallback callback;
+ base::WeakPtr<ServiceWorkerCache> cache;
+ net::URLRequestContext* request_context;
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy;
+
+ // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
+ // CreateEntry.
+ disk_cache::Entry* cache_entry;
+
+ // The BlobDataHandle for the output ServiceWorkerResponse.
+ scoped_ptr<storage::BlobDataHandle> out_blob_data_handle;
+
+ DISALLOW_COPY_AND_ASSIGN(PutContext);
+};
+
+// static
+scoped_refptr<ServiceWorkerCache> ServiceWorkerCache::CreateMemoryCache(
+ const GURL& origin,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context) {
+ return make_scoped_refptr(new ServiceWorkerCache(origin,
+ base::FilePath(),
+ request_context,
+ quota_manager_proxy,
+ blob_context));
+}
+
+// static
+scoped_refptr<ServiceWorkerCache> ServiceWorkerCache::CreatePersistentCache(
+ const GURL& origin,
+ const base::FilePath& path,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context) {
+ return make_scoped_refptr(new ServiceWorkerCache(
+ origin, path, request_context, quota_manager_proxy, blob_context));
+}
+
+ServiceWorkerCache::~ServiceWorkerCache() {
+}
+
+base::WeakPtr<ServiceWorkerCache> ServiceWorkerCache::AsWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+void ServiceWorkerCache::Put(scoped_ptr<ServiceWorkerFetchRequest> request,
+ scoped_ptr<ServiceWorkerResponse> response,
+ const ResponseCallback& callback) {
+ IncPendingOps();
+ ResponseCallback pending_callback =
+ base::Bind(&ServiceWorkerCache::PendingResponseCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle;
+
+ if (!response->blob_uuid.empty()) {
+ if (!blob_storage_context_) {
+ pending_callback.Run(ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+ blob_data_handle =
+ blob_storage_context_->GetBlobDataFromUUID(response->blob_uuid);
+ if (!blob_data_handle) {
+ pending_callback.Run(ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+ }
+
+ scoped_ptr<PutContext> put_context(new PutContext(
+ origin_, request.Pass(), response.Pass(), blob_data_handle.Pass(),
+ pending_callback, weak_ptr_factory_.GetWeakPtr(), request_context_,
+ quota_manager_proxy_));
+
+ if (put_context->blob_data_handle) {
+ // Grab another handle to the blob for the callback response.
+ put_context->out_blob_data_handle =
+ blob_storage_context_->GetBlobDataFromUUID(
+ put_context->response->blob_uuid);
+ }
+
+ base::Closure continuation = base::Bind(&ServiceWorkerCache::PutImpl,
+ base::Passed(put_context.Pass()));
+
+ if (!initialized_) {
+ Init(continuation);
+ return;
+ }
+
+ continuation.Run();
+}
+
+void ServiceWorkerCache::Match(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ResponseCallback& callback) {
+ IncPendingOps();
+ ResponseCallback pending_callback =
+ base::Bind(&ServiceWorkerCache::PendingResponseCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+
+ if (!initialized_) {
+ Init(base::Bind(&ServiceWorkerCache::Match, weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(request.Pass()), pending_callback));
+ return;
+ }
+ if (!backend_) {
+ pending_callback.Run(ErrorTypeStorage, scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*);
+
+ disk_cache::Entry** entry_ptr = entry.get();
+
+ ServiceWorkerFetchRequest* request_ptr = request.get();
+
+ net::CompletionCallback open_entry_callback = base::Bind(
+ MatchDidOpenEntry, base::Passed(request.Pass()), pending_callback,
+ blob_storage_context_, base::Passed(entry.Pass()));
+
+ int rv = backend_->OpenEntry(
+ request_ptr->url.spec(), entry_ptr, open_entry_callback);
+ if (rv != net::ERR_IO_PENDING)
+ open_entry_callback.Run(rv);
+}
+
+void ServiceWorkerCache::Delete(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ErrorCallback& callback) {
+ IncPendingOps();
+ ErrorCallback pending_callback =
+ base::Bind(&ServiceWorkerCache::PendingErrorCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+
+ if (!initialized_) {
+ Init(base::Bind(&ServiceWorkerCache::Delete, weak_ptr_factory_.GetWeakPtr(),
+ base::Passed(request.Pass()), pending_callback));
+ return;
+ }
+ if (!backend_) {
+ pending_callback.Run(ErrorTypeStorage);
+ return;
+ }
+
+ scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*);
+
+ disk_cache::Entry** entry_ptr = entry.get();
+
+ ServiceWorkerFetchRequest* request_ptr = request.get();
+
+ net::CompletionCallback open_entry_callback = base::Bind(
+ DeleteDidOpenEntry, origin_, base::Passed(request.Pass()),
+ pending_callback, base::Passed(entry.Pass()), quota_manager_proxy_);
+
+ int rv = backend_->OpenEntry(
+ request_ptr->url.spec(), entry_ptr, open_entry_callback);
+ if (rv != net::ERR_IO_PENDING)
+ open_entry_callback.Run(rv);
+}
+
+void ServiceWorkerCache::Keys(const RequestsCallback& callback) {
+ IncPendingOps();
+ RequestsCallback pending_callback =
+ base::Bind(&ServiceWorkerCache::PendingRequestsCallback,
+ weak_ptr_factory_.GetWeakPtr(), callback);
+ if (!initialized_) {
+ Init(base::Bind(&ServiceWorkerCache::Keys, weak_ptr_factory_.GetWeakPtr(),
+ pending_callback));
+ return;
+ }
+ if (!backend_) {
+ pending_callback.Run(ErrorTypeStorage, scoped_ptr<Requests>());
+ return;
+ }
+
+ // 1. Iterate through all of the entries, open them, and add them to a vector.
+ // 2. For each open entry:
+ // 2.1. Read the headers into a protobuf.
+ // 2.2. Copy the protobuf into a ServiceWorkerFetchRequest (a "key").
+ // 2.3. Push the response into a vector of requests to be returned.
+ // 3. Return the vector of requests (keys).
+
+ // The entries have to be loaded into a vector first because enumeration loops
+ // forever if you read data from a cache entry while enumerating.
+
+ scoped_ptr<KeysContext> keys_context(
+ new KeysContext(pending_callback, weak_ptr_factory_.GetWeakPtr()));
+
+ keys_context->backend_iterator = backend_->CreateIterator();
+ disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator;
+ disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry;
+
+ net::CompletionCallback open_entry_callback =
+ base::Bind(KeysDidOpenNextEntry, base::Passed(keys_context.Pass()));
+
+ int rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
+
+ if (rv != net::ERR_IO_PENDING)
+ open_entry_callback.Run(rv);
+}
+
+void ServiceWorkerCache::Close(const base::Closure& callback) {
+ DCHECK(!initialized_ || backend_)
+ << "Don't call ServiceWorkerCache::Close() twice.";
+
+ if (pending_ops_ > 0) {
+ DCHECK(ops_complete_callback_.is_null());
+ initialized_ = true; // So that future operations halt.
+ ops_complete_callback_ = base::Bind(
+ &ServiceWorkerCache::Close, weak_ptr_factory_.GetWeakPtr(), callback);
+ return;
+ }
+
+ initialized_ = true;
+ backend_.reset();
+ callback.Run();
+}
+
+int64 ServiceWorkerCache::MemoryBackedSize() const {
+ if (!backend_ || !memory_only_)
+ return 0;
+
+ scoped_ptr<disk_cache::Backend::Iterator> backend_iter =
+ backend_->CreateIterator();
+ disk_cache::Entry* entry = nullptr;
+
+ int64 sum = 0;
+
+ 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.
+ }
+ DCHECK(rv !=
+ net::ERR_IO_PENDING); // Expect all memory ops to be synchronous.
+
+ for (disk_cache::Entry* entry : entries) {
+ sum += entry->GetDataSize(INDEX_HEADERS) +
+ entry->GetDataSize(INDEX_RESPONSE_BODY);
+ entry->Close();
+ }
+
+ return sum;
+}
+
+ServiceWorkerCache::ServiceWorkerCache(
+ const GURL& origin,
+ const base::FilePath& path,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context)
+ : origin_(origin),
+ path_(path),
+ request_context_(request_context),
+ quota_manager_proxy_(quota_manager_proxy),
+ blob_storage_context_(blob_context),
+ initialized_(false),
+ memory_only_(path.empty()),
+ pending_ops_(0),
+ weak_ptr_factory_(this) {
+}
+
+// static
+void ServiceWorkerCache::PutImpl(scoped_ptr<PutContext> put_context) {
+ if (!put_context->cache || !put_context->cache->backend_) {
+ put_context->callback.Run(ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ scoped_ptr<ServiceWorkerFetchRequest> request_copy(
+ new ServiceWorkerFetchRequest(*put_context->request));
+ ServiceWorkerCache* cache_ptr = put_context->cache.get();
+
+ cache_ptr->Delete(request_copy.Pass(),
+ base::Bind(PutDidDelete, base::Passed(put_context.Pass())));
+}
+
+// static
+void ServiceWorkerCache::PutDidDelete(scoped_ptr<PutContext> put_context,
+ ErrorType delete_error) {
+ if (!put_context->cache || !put_context->cache->backend_) {
+ put_context->callback.Run(ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ disk_cache::Entry** entry_ptr = &put_context->cache_entry;
+ ServiceWorkerFetchRequest* request_ptr = put_context->request.get();
+ disk_cache::Backend* backend_ptr = put_context->cache->backend_.get();
+
+ net::CompletionCallback create_entry_callback =
+ base::Bind(PutDidCreateEntry, base::Passed(put_context.Pass()));
+
+ int create_rv = backend_ptr->CreateEntry(
+ request_ptr->url.spec(), entry_ptr, create_entry_callback);
+
+ if (create_rv != net::ERR_IO_PENDING)
+ create_entry_callback.Run(create_rv);
+}
+
+// static
+void ServiceWorkerCache::PutDidCreateEntry(scoped_ptr<PutContext> put_context,
+ int rv) {
+ if (rv != net::OK) {
+ put_context->callback.Run(ServiceWorkerCache::ErrorTypeExists,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ DCHECK(put_context->cache_entry);
+
+ ServiceWorkerCacheMetadata metadata;
+ ServiceWorkerCacheRequest* request_metadata = metadata.mutable_request();
+ request_metadata->set_method(put_context->request->method);
+ for (ServiceWorkerHeaderMap::const_iterator it =
+ put_context->request->headers.begin();
+ it != put_context->request->headers.end();
+ ++it) {
+ ServiceWorkerCacheHeaderMap* header_map = request_metadata->add_headers();
+ header_map->set_name(it->first);
+ header_map->set_value(it->second);
+ }
+
+ ServiceWorkerCacheResponse* response_metadata = metadata.mutable_response();
+ response_metadata->set_status_code(put_context->response->status_code);
+ response_metadata->set_status_text(put_context->response->status_text);
+ response_metadata->set_response_type(
+ WebResponseTypeToProtoResponseType(put_context->response->response_type));
+ response_metadata->set_url(put_context->response->url.spec());
+ for (ServiceWorkerHeaderMap::const_iterator it =
+ put_context->response->headers.begin();
+ it != put_context->response->headers.end();
+ ++it) {
+ ServiceWorkerCacheHeaderMap* header_map = response_metadata->add_headers();
+ header_map->set_name(it->first);
+ header_map->set_value(it->second);
+ }
+
+ scoped_ptr<std::string> serialized(new std::string());
+ if (!metadata.SerializeToString(serialized.get())) {
+ put_context->callback.Run(ServiceWorkerCache::ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ scoped_refptr<net::StringIOBuffer> buffer(
+ new net::StringIOBuffer(serialized.Pass()));
+
+ // Get a temporary copy of the entry pointer before passing it in base::Bind.
+ disk_cache::Entry* tmp_entry_ptr = put_context->cache_entry;
+
+ net::CompletionCallback write_headers_callback = base::Bind(
+ PutDidWriteHeaders, base::Passed(put_context.Pass()), buffer->size());
+
+ rv = tmp_entry_ptr->WriteData(INDEX_HEADERS,
+ 0 /* offset */,
+ buffer.get(),
+ buffer->size(),
+ write_headers_callback,
+ true /* truncate */);
+
+ if (rv != net::ERR_IO_PENDING)
+ write_headers_callback.Run(rv);
+}
+
+// static
+void ServiceWorkerCache::PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
+ int expected_bytes,
+ int rv) {
+ if (rv != expected_bytes) {
+ put_context->cache_entry->Doom();
+ put_context->callback.Run(ServiceWorkerCache::ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ // The metadata is written, now for the response content. The data is streamed
+ // 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));
+ }
+
+ put_context->callback.Run(ServiceWorkerCache::ErrorTypeOK,
+ put_context->response.Pass(),
+ scoped_ptr<storage::BlobDataHandle>());
+ return;
+ }
+
+ DCHECK(put_context->blob_data_handle);
+
+ disk_cache::ScopedEntryPtr entry(put_context->cache_entry);
+ put_context->cache_entry = NULL;
+ scoped_ptr<BlobReader> reader(new BlobReader());
+ BlobReader* reader_ptr = reader.get();
+
+ // Grab some pointers before passing put_context in Bind.
+ net::URLRequestContext* request_context = put_context->request_context;
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle =
+ put_context->blob_data_handle.Pass();
+
+ reader_ptr->StreamBlobToCache(entry.Pass(),
+ request_context,
+ blob_data_handle.Pass(),
+ base::Bind(PutDidWriteBlobToCache,
+ base::Passed(put_context.Pass()),
+ base::Passed(reader.Pass())));
+}
+
+// static
+void ServiceWorkerCache::PutDidWriteBlobToCache(
+ scoped_ptr<PutContext> put_context,
+ scoped_ptr<BlobReader> blob_reader,
+ disk_cache::ScopedEntryPtr entry,
+ bool success) {
+ DCHECK(entry);
+ put_context->cache_entry = entry.release();
+
+ if (!success) {
+ put_context->cache_entry->Doom();
+ put_context->callback.Run(ServiceWorkerCache::ErrorTypeStorage,
+ scoped_ptr<ServiceWorkerResponse>(),
+ scoped_ptr<storage::BlobDataHandle>());
+ 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));
+ }
+
+ put_context->callback.Run(ServiceWorkerCache::ErrorTypeOK,
+ put_context->response.Pass(),
+ put_context->out_blob_data_handle.Pass());
+}
+
+// static
+void ServiceWorkerCache::KeysDidOpenNextEntry(
+ scoped_ptr<KeysContext> keys_context,
+ int rv) {
+ if (rv == net::ERR_FAILED) {
+ DCHECK(!keys_context->enumerated_entry);
+ // Enumeration is complete, extract the requests from the entries.
+ Entries::iterator iter = keys_context->entries.begin();
+ KeysProcessNextEntry(keys_context.Pass(), iter);
+ return;
+ }
+
+ base::WeakPtr<ServiceWorkerCache> cache = keys_context->cache;
+ if (rv < 0 || !cache) {
+ keys_context->original_callback.Run(ErrorTypeStorage,
+ scoped_ptr<Requests>());
+ return;
+ }
+
+ if (!cache->backend_) {
+ keys_context->original_callback.Run(ErrorTypeNotFound,
+ scoped_ptr<Requests>());
+ return;
+ }
+
+ // Store the entry.
+ keys_context->entries.push_back(keys_context->enumerated_entry);
+ keys_context->enumerated_entry = NULL;
+
+ // Enumerate the next entry.
+ disk_cache::Backend::Iterator& iterator = *keys_context->backend_iterator;
+ disk_cache::Entry** enumerated_entry = &keys_context->enumerated_entry;
+ net::CompletionCallback open_entry_callback =
+ base::Bind(KeysDidOpenNextEntry, base::Passed(keys_context.Pass()));
+
+ rv = iterator.OpenNextEntry(enumerated_entry, open_entry_callback);
+
+ if (rv != net::ERR_IO_PENDING)
+ open_entry_callback.Run(rv);
+}
+
+// static
+void ServiceWorkerCache::KeysProcessNextEntry(
+ scoped_ptr<KeysContext> keys_context,
+ const Entries::iterator& iter) {
+ if (iter == keys_context->entries.end()) {
+ // All done. Return all of the keys.
+ keys_context->original_callback.Run(ErrorTypeOK,
+ keys_context->out_keys.Pass());
+ return;
+ }
+
+ ReadMetadata(
+ *iter,
+ base::Bind(KeysDidReadMetadata, base::Passed(keys_context.Pass()), iter));
+}
+
+// static
+void ServiceWorkerCache::KeysDidReadMetadata(
+ scoped_ptr<KeysContext> keys_context,
+ const Entries::iterator& iter,
+ scoped_ptr<ServiceWorkerCacheMetadata> metadata) {
+ disk_cache::Entry* entry = *iter;
+
+ if (metadata) {
+ keys_context->out_keys->push_back(
+ ServiceWorkerFetchRequest(GURL(entry->GetKey()),
+ metadata->request().method(),
+ ServiceWorkerHeaderMap(),
+ GURL(),
+ false));
+
+ ServiceWorkerHeaderMap& req_headers =
+ keys_context->out_keys->back().headers;
+
+ for (int i = 0; i < metadata->request().headers_size(); ++i) {
+ const ServiceWorkerCacheHeaderMap header = metadata->request().headers(i);
+ req_headers.insert(std::make_pair(header.name(), header.value()));
+ }
+ } else {
+ entry->Doom();
+ }
+
+ KeysProcessNextEntry(keys_context.Pass(), iter + 1);
+}
+
+void ServiceWorkerCache::CreateBackend(const ErrorCallback& callback) {
+ DCHECK(!backend_);
+
+ // Use APP_CACHE as opposed to DISK_CACHE to prevent cache eviction.
+ net::CacheType cache_type = memory_only_ ? net::MEMORY_CACHE : net::APP_CACHE;
+
+ scoped_ptr<ScopedBackendPtr> backend_ptr(new ScopedBackendPtr());
+
+ // Temporary pointer so that backend_ptr can be Pass()'d in Bind below.
+ ScopedBackendPtr* backend = backend_ptr.get();
+
+ net::CompletionCallback create_cache_callback =
+ base::Bind(CreateBackendDidCreate,
+ callback,
+ base::Passed(backend_ptr.Pass()),
+ weak_ptr_factory_.GetWeakPtr());
+
+ // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
+ // has for disk caches.
+ int rv = disk_cache::CreateCacheBackend(
+ cache_type,
+ net::CACHE_BACKEND_SIMPLE,
+ path_,
+ kMaxCacheBytes,
+ false, /* force */
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE).get(),
+ NULL,
+ backend,
+ create_cache_callback);
+ if (rv != net::ERR_IO_PENDING)
+ create_cache_callback.Run(rv);
+}
+
+void ServiceWorkerCache::Init(const base::Closure& callback) {
+ DCHECK(!initialized_);
+ init_callbacks_.push_back(callback);
+
+ // If this isn't the first call to Init then return as the initialization
+ // has already started.
+ if (init_callbacks_.size() > 1u)
+ return;
+
+ CreateBackend(base::Bind(&ServiceWorkerCache::InitDone,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ServiceWorkerCache::InitDone(ErrorType error) {
+ initialized_ = true;
+ for (std::vector<base::Closure>::iterator it = init_callbacks_.begin();
+ it != init_callbacks_.end();
+ ++it) {
+ it->Run();
+ }
+ init_callbacks_.clear();
+}
+
+void ServiceWorkerCache::DecPendingOps() {
+ DCHECK(pending_ops_ > 0);
+ pending_ops_--;
+ if (pending_ops_ == 0 && !ops_complete_callback_.is_null()) {
+ ops_complete_callback_.Run();
+ ops_complete_callback_.Reset();
+ }
+}
+
+void ServiceWorkerCache::PendingErrorCallback(const ErrorCallback& callback,
+ ErrorType error) {
+ callback.Run(error);
+ DecPendingOps();
+}
+
+void ServiceWorkerCache::PendingResponseCallback(
+ const ResponseCallback& callback,
+ ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ callback.Run(error, response.Pass(), blob_data_handle.Pass());
+ DecPendingOps();
+}
+
+void ServiceWorkerCache::PendingRequestsCallback(
+ const RequestsCallback& callback,
+ ErrorType error,
+ scoped_ptr<Requests> requests) {
+ callback.Run(error, requests.Pass());
+ DecPendingOps();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_cache.h b/chromium/content/browser/service_worker/service_worker_cache.h
new file mode 100644
index 00000000000..6683797e992
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache.h
@@ -0,0 +1,195 @@
+// 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_SERVICE_WORKER_SERVICE_WORKER_CACHE_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_H_
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "net/base/completion_callback.h"
+#include "net/disk_cache/disk_cache.h"
+
+namespace net {
+class URLRequestContext;
+class IOBufferWithSize;
+}
+
+namespace storage {
+class BlobData;
+class BlobDataHandle;
+class BlobStorageContext;
+class QuotaManagerProxy;
+}
+
+namespace content {
+class ChromeBlobStorageContext;
+class ServiceWorkerCacheMetadata;
+class TestServiceWorkerCache;
+
+// Represents a ServiceWorker Cache as seen in
+// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html.
+// Callbacks to the public functions will be called so long as the cache object
+// lives.
+class CONTENT_EXPORT ServiceWorkerCache
+ : public base::RefCounted<ServiceWorkerCache> {
+ public:
+ enum ErrorType {
+ ErrorTypeOK = 0,
+ ErrorTypeExists,
+ ErrorTypeStorage,
+ ErrorTypeNotFound
+ };
+
+ enum EntryIndex { INDEX_HEADERS = 0, INDEX_RESPONSE_BODY };
+ typedef base::Callback<void(ErrorType)> ErrorCallback;
+ typedef base::Callback<void(ErrorType,
+ scoped_ptr<ServiceWorkerResponse>,
+ scoped_ptr<storage::BlobDataHandle>)>
+ ResponseCallback;
+ typedef std::vector<ServiceWorkerFetchRequest> Requests;
+ typedef base::Callback<void(ErrorType, scoped_ptr<Requests>)>
+ RequestsCallback;
+
+ static scoped_refptr<ServiceWorkerCache> CreateMemoryCache(
+ const GURL& origin,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context);
+ static scoped_refptr<ServiceWorkerCache> CreatePersistentCache(
+ const GURL& origin,
+ const base::FilePath& path,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context);
+
+ // Returns ErrorTypeNotFound if not found.
+ void Match(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ResponseCallback& callback);
+
+ // Puts the request and response object in the cache. The response body (if
+ // present) is stored in the cache, but not the request body. Returns
+ // ErrorTypeOK on success.
+ void Put(scoped_ptr<ServiceWorkerFetchRequest> request,
+ scoped_ptr<ServiceWorkerResponse> response,
+ const ResponseCallback& callback);
+
+ // Returns ErrorNotFound if not found. Otherwise deletes and returns
+ // ErrorTypeOK.
+ void Delete(scoped_ptr<ServiceWorkerFetchRequest> request,
+ const ErrorCallback& callback);
+
+ // TODO(jkarlin): Have keys take an optional ServiceWorkerFetchRequest.
+ // Returns ErrorTypeOK and a vector of requests if there are no errors.
+ void Keys(const RequestsCallback& callback);
+
+ // Prevents further operations from starting on this object, waits for
+ // existing operations to finish, and then deletes the backend. Close should
+ // only be called once per ServiceWorkerCache.
+ 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 MemoryBackedSize() const;
+
+ void set_backend(scoped_ptr<disk_cache::Backend> backend) {
+ backend_ = backend.Pass();
+ }
+
+ base::WeakPtr<ServiceWorkerCache> AsWeakPtr();
+
+ private:
+ friend class base::RefCounted<ServiceWorkerCache>;
+ friend class TestServiceWorkerCache;
+
+ class BlobReader;
+ struct KeysContext;
+ struct PutContext;
+ typedef std::vector<disk_cache::Entry*> Entries;
+
+ ServiceWorkerCache(
+ const GURL& origin,
+ const base::FilePath& path,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context);
+
+ // Operations in progress will complete after the cache is deleted but pending
+ // operations (those operations waiting for init to finish) won't.
+ virtual ~ServiceWorkerCache();
+
+ // Put callbacks.
+ static void PutImpl(scoped_ptr<PutContext> put_context);
+ static void PutDidDelete(scoped_ptr<PutContext> put_context,
+ ErrorType delete_error);
+ static void PutDidCreateEntry(scoped_ptr<PutContext> put_context, int rv);
+ static void PutDidWriteHeaders(scoped_ptr<PutContext> put_context,
+ int expected_bytes,
+ int rv);
+ static void PutDidWriteBlobToCache(scoped_ptr<PutContext> put_context,
+ scoped_ptr<BlobReader> blob_reader,
+ disk_cache::ScopedEntryPtr entry,
+ bool success);
+
+ // Static callbacks for the Keys function.
+ static void KeysDidOpenNextEntry(scoped_ptr<KeysContext> keys_context,
+ int rv);
+ static void KeysProcessNextEntry(scoped_ptr<KeysContext> keys_context,
+ const Entries::iterator& iter);
+ static void KeysDidReadMetadata(
+ scoped_ptr<KeysContext> keys_context,
+ const Entries::iterator& iter,
+ scoped_ptr<ServiceWorkerCacheMetadata> metadata);
+
+ // 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);
+
+ void Init(const base::Closure& callback);
+ void InitDone(ErrorType error);
+
+ void IncPendingOps() { pending_ops_++; }
+ void DecPendingOps();
+ void PendingErrorCallback(const ErrorCallback& callback, ErrorType error);
+ void PendingResponseCallback(
+ const ResponseCallback& callback,
+ ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+ void PendingRequestsCallback(const RequestsCallback& callback,
+ ErrorType error,
+ scoped_ptr<Requests> requests);
+
+ // The backend can be deleted via the Close function at any time so always
+ // check for its existence before use.
+ scoped_ptr<disk_cache::Backend> backend_;
+ GURL origin_;
+ base::FilePath path_;
+ net::URLRequestContext* request_context_;
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
+ bool initialized_;
+ std::vector<base::Closure> init_callbacks_;
+
+ // Whether or not to store data in disk or memory.
+ bool memory_only_;
+
+ // The number of started operations that have yet to complete.
+ // TODO(jkarlin): pending_ops_ gets double counted on lazy initialization (say
+ // in ::Put). The counting still works but pending_ops_ doesn't accurately
+ // represent the number of operations in flight. Fix this by having the lazy
+ // init callback call a different function than the original caller (::Put).
+ size_t pending_ops_;
+ base::Closure ops_complete_callback_;
+
+ base::WeakPtrFactory<ServiceWorkerCache> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCache);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_H_
diff --git a/chromium/content/browser/service_worker/service_worker_cache.proto b/chromium/content/browser/service_worker/service_worker_cache.proto
new file mode 100644
index 00000000000..37b429b0618
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache.proto
@@ -0,0 +1,48 @@
+// 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package content;
+
+message ServiceWorkerCacheStorageIndex {
+ message Cache {
+ required string name = 1;
+ }
+ repeated Cache cache = 1;
+ optional string origin = 2;
+}
+
+message ServiceWorkerCacheHeaderMap {
+ required string name = 1;
+ required string value = 2;
+}
+
+message ServiceWorkerCacheRequest {
+ required string method = 1;
+ repeated ServiceWorkerCacheHeaderMap headers = 2;
+}
+
+message ServiceWorkerCacheResponse {
+ enum ResponseType {
+ BASIC_TYPE = 0;
+ CORS_TYPE = 1;
+ DEFAULT_TYPE = 2;
+ ERROR_TYPE = 3;
+ OPAQUE_TYPE = 4;
+ }
+
+ required int32 status_code = 1;
+ required string status_text = 2;
+ required ResponseType response_type = 3;
+ repeated ServiceWorkerCacheHeaderMap headers = 4;
+ optional string url = 5;
+}
+
+message ServiceWorkerCacheMetadata {
+ required ServiceWorkerCacheRequest request = 1;
+ required ServiceWorkerCacheResponse response = 2;
+} \ No newline at end of file
diff --git a/chromium/content/browser/service_worker/service_worker_cache_listener.cc b/chromium/content/browser/service_worker/service_worker_cache_listener.cc
new file mode 100644
index 00000000000..e52c940666d
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_listener.cc
@@ -0,0 +1,459 @@
+// 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/service_worker/service_worker_cache_listener.h"
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/service_worker/service_worker_cache.h"
+#include "content/browser/service_worker/service_worker_cache_storage_manager.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_version.h"
+#include "content/common/service_worker/service_worker_messages.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
+
+namespace content {
+
+using blink::WebServiceWorkerCacheError;
+
+namespace {
+
+WebServiceWorkerCacheError ToWebServiceWorkerCacheError(
+ ServiceWorkerCacheStorage::CacheStorageError err) {
+ switch (err) {
+ case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR:
+ NOTREACHED();
+ return blink::WebServiceWorkerCacheErrorNotImplemented;
+ case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_IMPLEMENTED:
+ return blink::WebServiceWorkerCacheErrorNotImplemented;
+ case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND:
+ return blink::WebServiceWorkerCacheErrorNotFound;
+ case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_EXISTS:
+ return blink::WebServiceWorkerCacheErrorExists;
+ case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_STORAGE:
+ // TODO(jkarlin): Change this to CACHE_STORAGE_ERROR_STORAGE once that's
+ // added.
+ return blink::WebServiceWorkerCacheErrorNotFound;
+ case ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_CLOSING:
+ // TODO(jkarlin): Update this to CACHE_STORAGE_ERROR_CLOSING once that's
+ // added.
+ return blink::WebServiceWorkerCacheErrorNotFound;
+ }
+ NOTREACHED();
+ return blink::WebServiceWorkerCacheErrorNotImplemented;
+}
+
+// TODO(jkarlin): ServiceWorkerCache and ServiceWorkerCacheStorage should share
+// an error enum type.
+WebServiceWorkerCacheError CacheErrorToWebServiceWorkerCacheError(
+ ServiceWorkerCache::ErrorType err) {
+ switch (err) {
+ case ServiceWorkerCache::ErrorTypeOK:
+ NOTREACHED();
+ return blink::WebServiceWorkerCacheErrorNotImplemented;
+ case ServiceWorkerCache::ErrorTypeExists:
+ return blink::WebServiceWorkerCacheErrorExists;
+ case ServiceWorkerCache::ErrorTypeStorage:
+ // TODO(jkarlin): Change this to CACHE_STORAGE_ERROR_STORAGE once that's
+ // added.
+ return blink::WebServiceWorkerCacheErrorNotFound;
+ case ServiceWorkerCache::ErrorTypeNotFound:
+ return blink::WebServiceWorkerCacheErrorNotFound;
+ }
+ NOTREACHED();
+ return blink::WebServiceWorkerCacheErrorNotImplemented;
+}
+
+} // namespace
+
+ServiceWorkerCacheListener::ServiceWorkerCacheListener(
+ ServiceWorkerVersion* version,
+ base::WeakPtr<ServiceWorkerContextCore> context)
+ : version_(version),
+ context_(context),
+ next_cache_id_(0),
+ weak_factory_(this) {
+ version_->embedded_worker()->AddListener(this);
+}
+
+ServiceWorkerCacheListener::~ServiceWorkerCacheListener() {
+ version_->embedded_worker()->RemoveListener(this);
+}
+
+bool ServiceWorkerCacheListener::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ServiceWorkerCacheListener, message)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageHas,
+ OnCacheStorageHas)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageOpen,
+ OnCacheStorageOpen)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageDelete,
+ OnCacheStorageDelete)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheStorageKeys,
+ OnCacheStorageKeys)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheMatch,
+ OnCacheMatch)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheMatchAll,
+ OnCacheMatchAll)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheKeys,
+ OnCacheKeys)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheBatch,
+ OnCacheBatch)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CacheClosed,
+ OnCacheClosed)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_BlobDataHandled, OnBlobDataHandled)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void ServiceWorkerCacheListener::OnCacheStorageHas(
+ int request_id,
+ const base::string16& cache_name) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerCacheListener::OnCacheStorageHas");
+ context_->cache_manager()->HasCache(
+ version_->scope().GetOrigin(),
+ base::UTF16ToUTF8(cache_name),
+ base::Bind(&ServiceWorkerCacheListener::OnCacheStorageHasCallback,
+ weak_factory_.GetWeakPtr(),
+ request_id));
+}
+
+void ServiceWorkerCacheListener::OnCacheStorageOpen(
+ int request_id,
+ const base::string16& cache_name) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerCacheListener::OnCacheStorageOpen");
+ context_->cache_manager()->OpenCache(
+ version_->scope().GetOrigin(),
+ base::UTF16ToUTF8(cache_name),
+ base::Bind(&ServiceWorkerCacheListener::OnCacheStorageOpenCallback,
+ weak_factory_.GetWeakPtr(),
+ request_id));
+}
+
+void ServiceWorkerCacheListener::OnCacheStorageDelete(
+ int request_id,
+ const base::string16& cache_name) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerCacheListener::OnCacheStorageDelete");
+ context_->cache_manager()->DeleteCache(
+ version_->scope().GetOrigin(),
+ base::UTF16ToUTF8(cache_name),
+ base::Bind(&ServiceWorkerCacheListener::OnCacheStorageDeleteCallback,
+ weak_factory_.GetWeakPtr(),
+ request_id));
+}
+
+void ServiceWorkerCacheListener::OnCacheStorageKeys(int request_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerCacheListener::OnCacheStorageKeys");
+ context_->cache_manager()->EnumerateCaches(
+ version_->scope().GetOrigin(),
+ base::Bind(&ServiceWorkerCacheListener::OnCacheStorageKeysCallback,
+ weak_factory_.GetWeakPtr(),
+ request_id));
+}
+
+void ServiceWorkerCacheListener::OnCacheMatch(
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const ServiceWorkerCacheQueryParams& match_params) {
+ IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
+ if (it == id_to_cache_map_.end()) {
+ Send(ServiceWorkerMsg_CacheMatchError(
+ request_id, blink::WebServiceWorkerCacheErrorNotFound));
+ return;
+ }
+
+ scoped_refptr<ServiceWorkerCache> cache = it->second;
+ scoped_ptr<ServiceWorkerFetchRequest> scoped_request(
+ new ServiceWorkerFetchRequest(request.url,
+ request.method,
+ request.headers,
+ request.referrer,
+ request.is_reload));
+ cache->Match(scoped_request.Pass(),
+ base::Bind(&ServiceWorkerCacheListener::OnCacheMatchCallback,
+ weak_factory_.GetWeakPtr(),
+ request_id,
+ cache));
+}
+
+void ServiceWorkerCacheListener::OnCacheMatchAll(
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const ServiceWorkerCacheQueryParams& match_params) {
+ // TODO(gavinp,jkarlin): Implement this method.
+ Send(ServiceWorkerMsg_CacheMatchAllError(
+ request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
+}
+
+void ServiceWorkerCacheListener::OnCacheKeys(
+ int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const ServiceWorkerCacheQueryParams& match_params) {
+ IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
+ if (it == id_to_cache_map_.end()) {
+ Send(ServiceWorkerMsg_CacheKeysError(
+ request_id, blink::WebServiceWorkerCacheErrorNotFound));
+ return;
+ }
+
+ scoped_refptr<ServiceWorkerCache> cache = it->second;
+
+ cache->Keys(base::Bind(&ServiceWorkerCacheListener::OnCacheKeysCallback,
+ weak_factory_.GetWeakPtr(),
+ request_id,
+ cache));
+}
+
+void ServiceWorkerCacheListener::OnCacheBatch(
+ int request_id,
+ int cache_id,
+ const std::vector<ServiceWorkerBatchOperation>& operations) {
+ if (operations.size() != 1u) {
+ Send(ServiceWorkerMsg_CacheBatchError(
+ request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
+ return;
+ }
+
+ IDToCacheMap::iterator it = id_to_cache_map_.find(cache_id);
+ if (it == id_to_cache_map_.end()) {
+ Send(ServiceWorkerMsg_CacheBatchError(
+ request_id, blink::WebServiceWorkerCacheErrorNotFound));
+ return;
+ }
+
+ const ServiceWorkerBatchOperation& operation = operations[0];
+
+ scoped_refptr<ServiceWorkerCache> cache = it->second;
+ scoped_ptr<ServiceWorkerFetchRequest> scoped_request(
+ new ServiceWorkerFetchRequest(operation.request.url,
+ operation.request.method,
+ operation.request.headers,
+ operation.request.referrer,
+ operation.request.is_reload));
+
+ if (operation.operation_type == SERVICE_WORKER_CACHE_OPERATION_TYPE_DELETE) {
+ cache->Delete(scoped_request.Pass(),
+ base::Bind(&ServiceWorkerCacheListener::OnCacheDeleteCallback,
+ weak_factory_.GetWeakPtr(),
+ request_id,
+ cache));
+ return;
+ }
+
+ if (operation.operation_type == SERVICE_WORKER_CACHE_OPERATION_TYPE_PUT) {
+ scoped_ptr<ServiceWorkerResponse> scoped_response(
+ new ServiceWorkerResponse(operation.response.url,
+ operation.response.status_code,
+ operation.response.status_text,
+ operation.response.response_type,
+ operation.response.headers,
+ operation.response.blob_uuid,
+ operation.response.blob_size));
+ cache->Put(scoped_request.Pass(),
+ scoped_response.Pass(),
+ base::Bind(&ServiceWorkerCacheListener::OnCachePutCallback,
+ weak_factory_.GetWeakPtr(),
+ request_id,
+ cache));
+
+ return;
+ }
+
+ Send(ServiceWorkerMsg_CacheBatchError(
+ request_id, blink::WebServiceWorkerCacheErrorNotImplemented));
+}
+
+void ServiceWorkerCacheListener::OnCacheClosed(int cache_id) {
+ DropCacheReference(cache_id);
+}
+
+void ServiceWorkerCacheListener::OnBlobDataHandled(const std::string& uuid) {
+ DropBlobDataHandle(uuid);
+}
+
+void ServiceWorkerCacheListener::Send(const IPC::Message& message) {
+ version_->embedded_worker()->SendMessage(message);
+}
+
+void ServiceWorkerCacheListener::OnCacheStorageHasCallback(
+ int request_id,
+ bool has_cache,
+ ServiceWorkerCacheStorage::CacheStorageError error) {
+ if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
+ Send(ServiceWorkerMsg_CacheStorageHasError(
+ request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+ if (!has_cache) {
+ Send(ServiceWorkerMsg_CacheStorageHasError(
+ request_id,
+ blink::WebServiceWorkerCacheErrorNotFound));
+ return;
+ }
+ Send(ServiceWorkerMsg_CacheStorageHasSuccess(request_id));
+}
+
+void ServiceWorkerCacheListener::OnCacheStorageOpenCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCacheStorage::CacheStorageError error) {
+ if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
+ Send(ServiceWorkerMsg_CacheStorageOpenError(
+ request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+ CacheID cache_id = StoreCacheReference(cache);
+ Send(ServiceWorkerMsg_CacheStorageOpenSuccess(request_id, cache_id));
+}
+
+void ServiceWorkerCacheListener::OnCacheStorageDeleteCallback(
+ int request_id,
+ bool deleted,
+ ServiceWorkerCacheStorage::CacheStorageError error) {
+ if (!deleted ||
+ error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
+ Send(ServiceWorkerMsg_CacheStorageDeleteError(
+ request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+ Send(ServiceWorkerMsg_CacheStorageDeleteSuccess(request_id));
+}
+
+void ServiceWorkerCacheListener::OnCacheStorageKeysCallback(
+ int request_id,
+ const std::vector<std::string>& strings,
+ ServiceWorkerCacheStorage::CacheStorageError error) {
+ if (error != ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR) {
+ Send(ServiceWorkerMsg_CacheStorageKeysError(
+ request_id, ToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ std::vector<base::string16> string16s;
+ for (size_t i = 0, max = strings.size(); i < max; ++i) {
+ string16s.push_back(base::UTF8ToUTF16(strings[i]));
+ }
+ Send(ServiceWorkerMsg_CacheStorageKeysSuccess(request_id, string16s));
+}
+
+void ServiceWorkerCacheListener::OnCacheMatchCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ if (error != ServiceWorkerCache::ErrorTypeOK) {
+ Send(ServiceWorkerMsg_CacheMatchError(
+ request_id, CacheErrorToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ if (blob_data_handle)
+ StoreBlobDataHandle(blob_data_handle.Pass());
+
+ Send(ServiceWorkerMsg_CacheMatchSuccess(request_id, *response));
+}
+
+void ServiceWorkerCacheListener::OnCacheKeysCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerCache::Requests> requests) {
+ if (error != ServiceWorkerCache::ErrorTypeOK) {
+ Send(ServiceWorkerMsg_CacheKeysError(
+ request_id, CacheErrorToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ ServiceWorkerCache::Requests out;
+
+ for (ServiceWorkerCache::Requests::const_iterator it = requests->begin();
+ it != requests->end();
+ ++it) {
+ ServiceWorkerFetchRequest request(
+ it->url, it->method, it->headers, it->referrer, it->is_reload);
+ out.push_back(request);
+ }
+
+ Send(ServiceWorkerMsg_CacheKeysSuccess(request_id, out));
+}
+
+void ServiceWorkerCacheListener::OnCacheDeleteCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCache::ErrorType error) {
+ if (error != ServiceWorkerCache::ErrorTypeOK) {
+ Send(ServiceWorkerMsg_CacheBatchError(
+ request_id, CacheErrorToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ Send(ServiceWorkerMsg_CacheBatchSuccess(
+ request_id, std::vector<ServiceWorkerResponse>()));
+}
+
+void ServiceWorkerCacheListener::OnCachePutCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ if (error != ServiceWorkerCache::ErrorTypeOK) {
+ Send(ServiceWorkerMsg_CacheBatchError(
+ request_id, CacheErrorToWebServiceWorkerCacheError(error)));
+ return;
+ }
+
+ if (blob_data_handle)
+ StoreBlobDataHandle(blob_data_handle.Pass());
+
+ std::vector<ServiceWorkerResponse> responses;
+ responses.push_back(*response);
+ Send(ServiceWorkerMsg_CacheBatchSuccess(request_id, responses));
+}
+
+ServiceWorkerCacheListener::CacheID
+ServiceWorkerCacheListener::StoreCacheReference(
+ const scoped_refptr<ServiceWorkerCache>& cache) {
+ int cache_id = next_cache_id_++;
+ id_to_cache_map_[cache_id] = cache;
+ return cache_id;
+}
+
+void ServiceWorkerCacheListener::DropCacheReference(CacheID cache_id) {
+ id_to_cache_map_.erase(cache_id);
+}
+
+void ServiceWorkerCacheListener::StoreBlobDataHandle(
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ DCHECK(blob_data_handle);
+ std::pair<UUIDToBlobDataHandleList::iterator, bool> rv =
+ blob_handle_store_.insert(std::make_pair(
+ blob_data_handle->uuid(), std::list<storage::BlobDataHandle>()));
+ rv.first->second.push_front(storage::BlobDataHandle(*blob_data_handle));
+}
+
+void ServiceWorkerCacheListener::DropBlobDataHandle(std::string uuid) {
+ UUIDToBlobDataHandleList::iterator it = blob_handle_store_.find(uuid);
+ if (it == blob_handle_store_.end())
+ return;
+ DCHECK(!it->second.empty());
+ it->second.pop_front();
+ if (it->second.empty())
+ blob_handle_store_.erase(it);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_cache_listener.h b/chromium/content/browser/service_worker/service_worker_cache_listener.h
new file mode 100644
index 00000000000..d0364f36d94
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_listener.h
@@ -0,0 +1,150 @@
+// 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_SERVICE_WORKER_SERVICE_WORKER_CACHE_LISTENER_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_LISTENER_H_
+
+#include <list>
+#include <map>
+
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "content/browser/service_worker/embedded_worker_instance.h"
+#include "content/browser/service_worker/service_worker_cache.h"
+#include "content/browser/service_worker/service_worker_cache_storage.h"
+
+namespace content {
+
+struct ServiceWorkerBatchOperation;
+struct ServiceWorkerCacheQueryParams;
+struct ServiceWorkerFetchRequest;
+class ServiceWorkerVersion;
+
+// This class listens for requests on the Cache APIs, and sends response
+// messages to the renderer process. There is one instance per
+// ServiceWorkerVersion instance.
+class ServiceWorkerCacheListener : public EmbeddedWorkerInstance::Listener {
+ public:
+ ServiceWorkerCacheListener(ServiceWorkerVersion* version,
+ base::WeakPtr<ServiceWorkerContextCore> context);
+ ~ServiceWorkerCacheListener() override;
+
+ // From EmbeddedWorkerInstance::Listener:
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ private:
+ // The message receiver functions for the CacheStorage API:
+ void OnCacheStorageGet(int request_id, const base::string16& cache_name);
+ void OnCacheStorageHas(int request_id, const base::string16& cache_name);
+ void OnCacheStorageCreate(int request_id,
+ const base::string16& cache_name);
+ void OnCacheStorageOpen(int request_id, const base::string16& cache_name);
+ void OnCacheStorageDelete(int request_id,
+ const base::string16& cache_name);
+ void OnCacheStorageKeys(int request_id);
+
+ // The message receiver functions for the Cache API:
+ void OnCacheMatch(int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const ServiceWorkerCacheQueryParams& match_params);
+ void OnCacheMatchAll(int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const ServiceWorkerCacheQueryParams& match_params);
+ void OnCacheKeys(int request_id,
+ int cache_id,
+ const ServiceWorkerFetchRequest& request,
+ const ServiceWorkerCacheQueryParams& match_params);
+ void OnCacheBatch(int request_id,
+ int cache_id,
+ const std::vector<ServiceWorkerBatchOperation>& operations);
+ void OnCacheClosed(int cache_id);
+ void OnBlobDataHandled(const std::string& uuid);
+
+ private:
+ typedef int32_t CacheID; // TODO(jkarlin): Bump to 64 bit.
+ typedef std::map<CacheID, scoped_refptr<ServiceWorkerCache>> IDToCacheMap;
+ typedef std::map<std::string, std::list<storage::BlobDataHandle>>
+ UUIDToBlobDataHandleList;
+
+ void Send(const IPC::Message& message);
+
+ // CacheStorageManager callbacks
+ void OnCacheStorageGetCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCacheStorage::CacheStorageError error);
+ void OnCacheStorageHasCallback(
+ int request_id,
+ bool has_cache,
+ ServiceWorkerCacheStorage::CacheStorageError error);
+ void OnCacheStorageCreateCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCacheStorage::CacheStorageError error);
+ void OnCacheStorageOpenCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCacheStorage::CacheStorageError error);
+ void OnCacheStorageDeleteCallback(
+ int request_id,
+ bool deleted,
+ ServiceWorkerCacheStorage::CacheStorageError error);
+ void OnCacheStorageKeysCallback(
+ int request_id,
+ const std::vector<std::string>& strings,
+ ServiceWorkerCacheStorage::CacheStorageError error);
+
+ // Cache callbacks
+ void OnCacheMatchCallback(
+ int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+ void OnCacheKeysCallback(int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerCache::Requests> requests);
+ void OnCacheDeleteCallback(int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCache::ErrorType error);
+ void OnCachePutCallback(int request_id,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+
+ // 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<ServiceWorkerCache>& cache);
+ void DropCacheReference(CacheID cache_id);
+
+ // Stores blob handles while waiting for acknowledgement of receipt from the
+ // renderer.
+ void StoreBlobDataHandle(
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle);
+ void DropBlobDataHandle(std::string uuid);
+
+ // The ServiceWorkerVersion to use for messaging back to the renderer thread.
+ ServiceWorkerVersion* version_;
+
+ // The ServiceWorkerContextCore should always outlive this.
+ base::WeakPtr<ServiceWorkerContextCore> context_;
+
+ IDToCacheMap id_to_cache_map_;
+ CacheID next_cache_id_;
+
+ UUIDToBlobDataHandleList blob_handle_store_;
+
+ base::WeakPtrFactory<ServiceWorkerCacheListener> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheListener);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_LISTENER_H_
diff --git a/chromium/content/browser/service_worker/service_worker_cache_quota_client.cc b/chromium/content/browser/service_worker/service_worker_cache_quota_client.cc
new file mode 100644
index 00000000000..c7ed1c0cbd8
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_quota_client.cc
@@ -0,0 +1,97 @@
+// 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/service_worker/service_worker_cache_quota_client.h"
+
+#include "content/browser/service_worker/service_worker_cache_storage_manager.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+ServiceWorkerCacheQuotaClient::ServiceWorkerCacheQuotaClient(
+ base::WeakPtr<ServiceWorkerCacheStorageManager> cache_manager)
+ : cache_manager_(cache_manager) {
+}
+
+ServiceWorkerCacheQuotaClient::~ServiceWorkerCacheQuotaClient() {
+}
+
+storage::QuotaClient::ID ServiceWorkerCacheQuotaClient::id() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return kServiceWorkerCache;
+}
+
+void ServiceWorkerCacheQuotaClient::OnQuotaManagerDestroyed() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ delete this;
+}
+
+void ServiceWorkerCacheQuotaClient::GetOriginUsage(
+ const GURL& origin_url,
+ storage::StorageType type,
+ const GetUsageCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!cache_manager_ || !DoesSupport(type)) {
+ callback.Run(0);
+ return;
+ }
+
+ cache_manager_->GetOriginUsage(origin_url, callback);
+}
+
+void ServiceWorkerCacheQuotaClient::GetOriginsForType(
+ storage::StorageType type,
+ const GetOriginsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!cache_manager_ || !DoesSupport(type)) {
+ callback.Run(std::set<GURL>());
+ return;
+ }
+
+ cache_manager_->GetOrigins(callback);
+}
+
+void ServiceWorkerCacheQuotaClient::GetOriginsForHost(
+ storage::StorageType type,
+ const std::string& host,
+ const GetOriginsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!cache_manager_ || !DoesSupport(type)) {
+ callback.Run(std::set<GURL>());
+ return;
+ }
+
+ cache_manager_->GetOriginsForHost(host, callback);
+}
+
+void ServiceWorkerCacheQuotaClient::DeleteOriginData(
+ const GURL& origin,
+ storage::StorageType type,
+ const DeletionCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!cache_manager_) {
+ callback.Run(storage::kQuotaErrorAbort);
+ return;
+ }
+
+ if (!DoesSupport(type)) {
+ callback.Run(storage::kQuotaStatusOk);
+ return;
+ }
+
+ cache_manager_->DeleteOriginData(origin, callback);
+}
+
+bool ServiceWorkerCacheQuotaClient::DoesSupport(
+ storage::StorageType type) const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return type == storage::kStorageTypeTemporary;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_cache_quota_client.h b/chromium/content/browser/service_worker/service_worker_cache_quota_client.h
new file mode 100644
index 00000000000..82111497b84
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_quota_client.h
@@ -0,0 +1,54 @@
+// 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_SERVICE_WORKER_SERVICE_WORKER_CACHE_QUOTA_CLIENT_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_QUOTA_CLIENT_H_
+
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "storage/browser/quota/quota_client.h"
+#include "storage/common/quota/quota_types.h"
+
+namespace storage {
+class QuotaManagerProxy;
+}
+
+namespace content {
+class ServiceWorkerCacheStorageManager;
+
+// ServiceWorkerCacheQuotaClient is owned by the QuotaManager. There is one per
+// ServiceWorkerCacheStorageManager, and therefore one per
+// ServiceWorkerContextCore.
+class CONTENT_EXPORT ServiceWorkerCacheQuotaClient
+ : public storage::QuotaClient {
+ public:
+ explicit ServiceWorkerCacheQuotaClient(
+ base::WeakPtr<ServiceWorkerCacheStorageManager> cache_manager);
+ ~ServiceWorkerCacheQuotaClient() override;
+
+ // QuotaClient overrides
+ ID id() const override;
+ void OnQuotaManagerDestroyed() override;
+ void GetOriginUsage(const GURL& origin_url,
+ storage::StorageType type,
+ const GetUsageCallback& callback) override;
+ void GetOriginsForType(storage::StorageType type,
+ const GetOriginsCallback& callback) override;
+ void GetOriginsForHost(storage::StorageType type,
+ const std::string& host,
+ const GetOriginsCallback& callback) override;
+ void DeleteOriginData(const GURL& origin,
+ storage::StorageType type,
+ const DeletionCallback& callback) override;
+ bool DoesSupport(storage::StorageType type) const override;
+
+ private:
+ base::WeakPtr<ServiceWorkerCacheStorageManager> cache_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheQuotaClient);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_QUOTA_CLIENT_H_
diff --git a/chromium/content/browser/service_worker/service_worker_cache_storage.cc b/chromium/content/browser/service_worker/service_worker_cache_storage.cc
new file mode 100644
index 00000000000..62adb60dfbc
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_storage.cc
@@ -0,0 +1,683 @@
+// 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/service_worker/service_worker_cache_storage.h"
+
+#include <string>
+
+#include "base/barrier_closure.h"
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/memory/ref_counted.h"
+#include "base/sha1.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "content/browser/service_worker/service_worker_cache.h"
+#include "content/browser/service_worker/service_worker_cache.pb.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/directory_lister.h"
+#include "net/base/net_errors.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+
+namespace content {
+
+namespace {
+
+void CloseAllCachesDidCloseCache(const scoped_refptr<ServiceWorkerCache>& cache,
+ const base::Closure& barrier_closure) {
+ barrier_closure.Run();
+}
+
+} // namespace
+
+const char ServiceWorkerCacheStorage::kIndexFileName[] = "index.txt";
+
+// Handles the loading and clean up of ServiceWorkerCache objects. The
+// callback of every public method is guaranteed to be called.
+class ServiceWorkerCacheStorage::CacheLoader {
+ public:
+ typedef base::Callback<void(const scoped_refptr<ServiceWorkerCache>&)>
+ CacheCallback;
+ typedef base::Callback<void(bool)> BoolCallback;
+ typedef base::Callback<void(scoped_ptr<std::vector<std::string> >)>
+ StringVectorCallback;
+
+ CacheLoader(
+ base::SequencedTaskRunner* cache_task_runner,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context,
+ const GURL& origin)
+ : cache_task_runner_(cache_task_runner),
+ request_context_(request_context),
+ quota_manager_proxy_(quota_manager_proxy),
+ blob_context_(blob_context),
+ origin_(origin) {
+ DCHECK(!origin_.is_empty());
+ }
+
+ virtual ~CacheLoader() {}
+
+ // Creates a ServiceWorkerCache with the given name. It does not attempt to
+ // load the backend, that happens lazily when the cache is used.
+ virtual scoped_refptr<ServiceWorkerCache> CreateServiceWorkerCache(
+ const std::string& cache_name) = 0;
+
+ // Deletes any pre-existing cache of the same name and then loads it.
+ virtual void CreateCache(const std::string& cache_name,
+ const CacheCallback& callback) = 0;
+
+ // After the backend has been deleted, do any extra house keeping such as
+ // removing the cache's directory.
+ virtual void CleanUpDeletedCache(const std::string& key,
+ const BoolCallback& callback) = 0;
+
+ // Writes the cache names (and sizes) to disk if applicable.
+ virtual void WriteIndex(const StringVector& cache_names,
+ const BoolCallback& callback) = 0;
+
+ // Loads the cache names from disk if applicable.
+ virtual void LoadIndex(scoped_ptr<std::vector<std::string> > cache_names,
+ const StringVectorCallback& callback) = 0;
+
+ protected:
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
+ net::URLRequestContext* request_context_;
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+ base::WeakPtr<storage::BlobStorageContext> blob_context_;
+ GURL origin_;
+};
+
+// Creates memory-only ServiceWorkerCaches. Because these caches have no
+// persistent storage it is not safe to free them from memory if they might be
+// used again. Therefore this class holds a reference to each cache until the
+// cache is deleted.
+class ServiceWorkerCacheStorage::MemoryLoader
+ : public ServiceWorkerCacheStorage::CacheLoader {
+ public:
+ MemoryLoader(
+ base::SequencedTaskRunner* cache_task_runner,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context,
+ const GURL& origin)
+ : CacheLoader(cache_task_runner,
+ request_context,
+ quota_manager_proxy,
+ blob_context,
+ origin) {}
+
+ scoped_refptr<ServiceWorkerCache> CreateServiceWorkerCache(
+ const std::string& cache_name) override {
+ return ServiceWorkerCache::CreateMemoryCache(
+ origin_, request_context_, quota_manager_proxy_, blob_context_);
+ }
+
+ void CreateCache(const std::string& cache_name,
+ const CacheCallback& callback) override {
+ scoped_refptr<ServiceWorkerCache> cache =
+ CreateServiceWorkerCache(cache_name);
+ cache_refs_.insert(std::make_pair(cache_name, cache));
+ callback.Run(cache);
+ }
+
+ void CleanUpDeletedCache(const std::string& cache_name,
+ const BoolCallback& callback) override {
+ CacheRefMap::iterator it = cache_refs_.find(cache_name);
+ DCHECK(it != cache_refs_.end());
+ cache_refs_.erase(it);
+ callback.Run(true);
+ }
+
+ void WriteIndex(const StringVector& cache_names,
+ const BoolCallback& callback) override {
+ callback.Run(false);
+ }
+
+ void LoadIndex(scoped_ptr<std::vector<std::string>> cache_names,
+ const StringVectorCallback& callback) override {
+ callback.Run(cache_names.Pass());
+ }
+
+ private:
+ typedef std::map<std::string, scoped_refptr<ServiceWorkerCache> > CacheRefMap;
+ ~MemoryLoader() override {}
+
+ // Keep a reference to each cache to ensure that it's not freed before the
+ // client calls ServiceWorkerCacheStorage::Delete or the CacheStorage is
+ // freed.
+ CacheRefMap cache_refs_;
+};
+
+class ServiceWorkerCacheStorage::SimpleCacheLoader
+ : public ServiceWorkerCacheStorage::CacheLoader {
+ public:
+ SimpleCacheLoader(
+ const base::FilePath& origin_path,
+ base::SequencedTaskRunner* cache_task_runner,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context,
+ const GURL& origin)
+ : CacheLoader(cache_task_runner,
+ request_context,
+ quota_manager_proxy,
+ blob_context,
+ origin),
+ origin_path_(origin_path),
+ weak_ptr_factory_(this) {}
+
+ scoped_refptr<ServiceWorkerCache> CreateServiceWorkerCache(
+ const std::string& cache_name) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ return ServiceWorkerCache::CreatePersistentCache(
+ origin_,
+ CreatePersistentCachePath(origin_path_, cache_name),
+ request_context_,
+ quota_manager_proxy_,
+ blob_context_);
+ }
+
+ void CreateCache(const std::string& cache_name,
+ const CacheCallback& callback) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // 1. Delete the cache's directory if it exists.
+ // (CreateCacheDeleteFilesInPool)
+ // 2. Load the cache. (LoadCreateDirectoryInPool)
+
+ base::FilePath cache_path =
+ CreatePersistentCachePath(origin_path_, cache_name);
+
+ PostTaskAndReplyWithResult(
+ cache_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&SimpleCacheLoader::CreateCachePrepDirInPool, cache_path),
+ base::Bind(&SimpleCacheLoader::CreateCachePreppedDir,
+ cache_name,
+ callback,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ static bool CreateCachePrepDirInPool(const base::FilePath& cache_path) {
+ if (base::PathExists(cache_path))
+ base::DeleteFile(cache_path, /* recursive */ true);
+ return base::CreateDirectory(cache_path);
+ }
+
+ static void CreateCachePreppedDir(const std::string& cache_name,
+ const CacheCallback& callback,
+ base::WeakPtr<SimpleCacheLoader> loader,
+ bool success) {
+ if (!success || !loader) {
+ callback.Run(scoped_refptr<ServiceWorkerCache>());
+ return;
+ }
+
+ callback.Run(loader->CreateServiceWorkerCache(cache_name));
+ }
+
+ void CleanUpDeletedCache(const std::string& cache_name,
+ const BoolCallback& callback) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // 1. Delete the cache's directory. (CleanUpDeleteCacheDirInPool)
+
+ base::FilePath cache_path =
+ CreatePersistentCachePath(origin_path_, cache_name);
+ cache_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool,
+ cache_path,
+ callback,
+ base::MessageLoopProxy::current()));
+ }
+
+ static void CleanUpDeleteCacheDirInPool(
+ const base::FilePath& cache_path,
+ const BoolCallback& callback,
+ const scoped_refptr<base::MessageLoopProxy>& original_loop) {
+ bool rv = base::DeleteFile(cache_path, true);
+ original_loop->PostTask(FROM_HERE, base::Bind(callback, rv));
+ }
+
+ void WriteIndex(const StringVector& cache_names,
+ const BoolCallback& callback) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // 1. Create the index file as a string. (WriteIndex)
+ // 2. Write the file to disk. (WriteIndexWriteToFileInPool)
+
+ ServiceWorkerCacheStorageIndex index;
+ index.set_origin(origin_.spec());
+
+ for (size_t i = 0u, max = cache_names.size(); i < max; ++i) {
+ ServiceWorkerCacheStorageIndex::Cache* index_cache = index.add_cache();
+ index_cache->set_name(cache_names[i]);
+ }
+
+ std::string serialized;
+ bool success = index.SerializeToString(&serialized);
+ DCHECK(success);
+
+ base::FilePath tmp_path = origin_path_.AppendASCII("index.txt.tmp");
+ base::FilePath index_path =
+ origin_path_.AppendASCII(ServiceWorkerCacheStorage::kIndexFileName);
+
+ cache_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&SimpleCacheLoader::WriteIndexWriteToFileInPool,
+ tmp_path,
+ index_path,
+ serialized,
+ callback,
+ base::MessageLoopProxy::current()));
+ }
+
+ static void WriteIndexWriteToFileInPool(
+ const base::FilePath& tmp_path,
+ const base::FilePath& index_path,
+ const std::string& data,
+ const BoolCallback& callback,
+ const scoped_refptr<base::MessageLoopProxy>& original_loop) {
+ int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size());
+ if (bytes_written != implicit_cast<int>(data.size())) {
+ base::DeleteFile(tmp_path, /* recursive */ false);
+ original_loop->PostTask(FROM_HERE, base::Bind(callback, false));
+ }
+
+ // Atomically rename the temporary index file to become the real one.
+ bool rv = base::ReplaceFile(tmp_path, index_path, NULL);
+ original_loop->PostTask(FROM_HERE, base::Bind(callback, rv));
+ }
+
+ void LoadIndex(scoped_ptr<std::vector<std::string>> names,
+ const StringVectorCallback& callback) override {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ // 1. Read the file from disk. (LoadIndexReadFileInPool)
+ // 2. Parse file and return the names of the caches (LoadIndexDidReadFile)
+
+ base::FilePath index_path =
+ origin_path_.AppendASCII(ServiceWorkerCacheStorage::kIndexFileName);
+
+ cache_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&SimpleCacheLoader::LoadIndexReadFileInPool,
+ index_path,
+ base::Passed(names.Pass()),
+ callback,
+ base::MessageLoopProxy::current()));
+ }
+
+ static void LoadIndexReadFileInPool(
+ const base::FilePath& index_path,
+ scoped_ptr<std::vector<std::string> > names,
+ const StringVectorCallback& callback,
+ const scoped_refptr<base::MessageLoopProxy>& original_loop) {
+ std::string body;
+ base::ReadFileToString(index_path, &body);
+
+ original_loop->PostTask(FROM_HERE,
+ base::Bind(&SimpleCacheLoader::LoadIndexDidReadFile,
+ base::Passed(names.Pass()),
+ callback,
+ body));
+ }
+
+ static void LoadIndexDidReadFile(scoped_ptr<std::vector<std::string> > names,
+ const StringVectorCallback& callback,
+ const std::string& serialized) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ServiceWorkerCacheStorageIndex index;
+ if (index.ParseFromString(serialized)) {
+ for (int i = 0, max = index.cache_size(); i < max; ++i) {
+ const ServiceWorkerCacheStorageIndex::Cache& cache = index.cache(i);
+ names->push_back(cache.name());
+ }
+ }
+
+ // TODO(jkarlin): Delete caches that are in the directory and not returned
+ // in LoadIndex.
+ callback.Run(names.Pass());
+ }
+
+ private:
+ ~SimpleCacheLoader() override {}
+
+ static std::string HexedHash(const std::string& value) {
+ std::string value_hash = base::SHA1HashString(value);
+ std::string valued_hexed_hash = base::StringToLowerASCII(
+ base::HexEncode(value_hash.c_str(), value_hash.length()));
+ return valued_hexed_hash;
+ }
+
+ static base::FilePath CreatePersistentCachePath(
+ const base::FilePath& origin_path,
+ const std::string& cache_name) {
+ return origin_path.AppendASCII(HexedHash(cache_name));
+ }
+
+ const base::FilePath origin_path_;
+
+ base::WeakPtrFactory<SimpleCacheLoader> weak_ptr_factory_;
+};
+
+ServiceWorkerCacheStorage::ServiceWorkerCacheStorage(
+ const base::FilePath& path,
+ bool memory_only,
+ base::SequencedTaskRunner* cache_task_runner,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context,
+ const GURL& origin)
+ : initialized_(false),
+ origin_path_(path),
+ cache_task_runner_(cache_task_runner),
+ memory_only_(memory_only),
+ weak_factory_(this) {
+ if (memory_only)
+ cache_loader_.reset(new MemoryLoader(cache_task_runner_.get(),
+ request_context,
+ quota_manager_proxy,
+ blob_context,
+ origin));
+ else
+ cache_loader_.reset(new SimpleCacheLoader(origin_path_,
+ cache_task_runner_.get(),
+ request_context,
+ quota_manager_proxy,
+ blob_context,
+ origin));
+}
+
+ServiceWorkerCacheStorage::~ServiceWorkerCacheStorage() {
+}
+
+void ServiceWorkerCacheStorage::OpenCache(
+ const std::string& cache_name,
+ const CacheAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_) {
+ LazyInit(base::Bind(&ServiceWorkerCacheStorage::OpenCache,
+ weak_factory_.GetWeakPtr(),
+ cache_name,
+ callback));
+ return;
+ }
+
+ scoped_refptr<ServiceWorkerCache> cache = GetLoadedCache(cache_name);
+ if (cache.get()) {
+ callback.Run(cache, CACHE_STORAGE_ERROR_NO_ERROR);
+ return;
+ }
+
+ cache_loader_->CreateCache(
+ cache_name,
+ base::Bind(&ServiceWorkerCacheStorage::CreateCacheDidCreateCache,
+ weak_factory_.GetWeakPtr(),
+ cache_name,
+ callback));
+}
+
+void ServiceWorkerCacheStorage::HasCache(const std::string& cache_name,
+ const BoolAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_) {
+ LazyInit(base::Bind(&ServiceWorkerCacheStorage::HasCache,
+ weak_factory_.GetWeakPtr(),
+ cache_name,
+ callback));
+ return;
+ }
+
+ bool has_cache = cache_map_.find(cache_name) != cache_map_.end();
+
+ callback.Run(has_cache, CACHE_STORAGE_ERROR_NO_ERROR);
+}
+
+void ServiceWorkerCacheStorage::DeleteCache(
+ const std::string& cache_name,
+ const BoolAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_) {
+ LazyInit(base::Bind(&ServiceWorkerCacheStorage::DeleteCache,
+ weak_factory_.GetWeakPtr(),
+ cache_name,
+ callback));
+ return;
+ }
+
+ CacheMap::iterator it = cache_map_.find(cache_name);
+ if (it == cache_map_.end()) {
+ callback.Run(false, CACHE_STORAGE_ERROR_NOT_FOUND);
+ return;
+ }
+
+ base::WeakPtr<ServiceWorkerCache> cache = it->second;
+ cache_map_.erase(it);
+
+ // Delete the name from ordered_cache_names_.
+ StringVector::iterator iter = std::find(
+ ordered_cache_names_.begin(), ordered_cache_names_.end(), cache_name);
+ DCHECK(iter != ordered_cache_names_.end());
+ ordered_cache_names_.erase(iter);
+
+ base::Closure closure =
+ base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidClose,
+ weak_factory_.GetWeakPtr(), cache_name, callback,
+ ordered_cache_names_, make_scoped_refptr(cache.get()));
+
+ if (cache) {
+ cache->Close(closure);
+ return;
+ }
+
+ closure.Run();
+}
+
+void ServiceWorkerCacheStorage::EnumerateCaches(
+ const StringsAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_) {
+ LazyInit(base::Bind(&ServiceWorkerCacheStorage::EnumerateCaches,
+ weak_factory_.GetWeakPtr(),
+ callback));
+ return;
+ }
+
+ callback.Run(ordered_cache_names_, CACHE_STORAGE_ERROR_NO_ERROR);
+}
+
+void ServiceWorkerCacheStorage::CloseAllCaches(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_) {
+ callback.Run();
+ return;
+ }
+
+ int live_cache_count = 0;
+ for (const auto& key_value : cache_map_) {
+ if (key_value.second)
+ live_cache_count += 1;
+ }
+
+ if (live_cache_count == 0) {
+ callback.Run();
+ return;
+ }
+
+ // 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));
+
+ 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));
+ }
+ }
+
+ barrier_closure.Run();
+}
+
+int64 ServiceWorkerCacheStorage::MemoryBackedSize() const {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!initialized_ || !memory_only_)
+ return 0;
+
+ int64 sum = 0;
+ for (auto& key_value : cache_map_) {
+ if (key_value.second)
+ sum += key_value.second->MemoryBackedSize();
+ }
+ return sum;
+}
+
+// Init is run lazily so that it is called on the proper MessageLoop.
+void ServiceWorkerCacheStorage::LazyInit(const base::Closure& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!initialized_);
+
+ init_callbacks_.push_back(callback);
+
+ // If this isn't the first call to LazyInit then return as the initialization
+ // has already started.
+ if (init_callbacks_.size() > 1u)
+ return;
+
+ // 1. Get the list of cache names (async call)
+ // 2. For each cache name, load the cache (async call)
+ // 3. Once each load is complete, update the map variables.
+ // 4. Call the list of waiting callbacks.
+
+ scoped_ptr<std::vector<std::string> > indexed_cache_names(
+ new std::vector<std::string>());
+
+ cache_loader_->LoadIndex(
+ indexed_cache_names.Pass(),
+ base::Bind(&ServiceWorkerCacheStorage::LazyInitDidLoadIndex,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+void ServiceWorkerCacheStorage::LazyInitDidLoadIndex(
+ const base::Closure& callback,
+ scoped_ptr<std::vector<std::string> > indexed_cache_names) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ for (size_t i = 0u, max = indexed_cache_names->size(); i < max; ++i) {
+ cache_map_.insert(std::make_pair(indexed_cache_names->at(i),
+ base::WeakPtr<ServiceWorkerCache>()));
+ ordered_cache_names_.push_back(indexed_cache_names->at(i));
+ }
+
+ initialized_ = true;
+ for (std::vector<base::Closure>::iterator it = init_callbacks_.begin();
+ it != init_callbacks_.end();
+ ++it) {
+ it->Run();
+ }
+ init_callbacks_.clear();
+}
+
+void ServiceWorkerCacheStorage::CreateCacheDidCreateCache(
+ const std::string& cache_name,
+ const CacheAndErrorCallback& callback,
+ const scoped_refptr<ServiceWorkerCache>& cache) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (!cache.get()) {
+ callback.Run(scoped_refptr<ServiceWorkerCache>(),
+ CACHE_STORAGE_ERROR_CLOSING);
+ return;
+ }
+
+ cache_map_.insert(std::make_pair(cache_name, cache->AsWeakPtr()));
+ ordered_cache_names_.push_back(cache_name);
+
+ cache_loader_->WriteIndex(
+ ordered_cache_names_,
+ base::Bind(&ServiceWorkerCacheStorage::CreateCacheDidWriteIndex,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ cache));
+}
+
+void ServiceWorkerCacheStorage::CreateCacheDidWriteIndex(
+ const CacheAndErrorCallback& callback,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(cache.get());
+
+ callback.Run(cache, CACHE_STORAGE_ERROR_NO_ERROR);
+}
+
+void ServiceWorkerCacheStorage::DeleteCacheDidClose(
+ const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ const StringVector& ordered_cache_names,
+ const scoped_refptr<ServiceWorkerCache>& cache /* might be null */) {
+ cache_loader_->WriteIndex(
+ ordered_cache_names,
+ base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidWriteIndex,
+ weak_factory_.GetWeakPtr(), cache_name, callback));
+}
+
+void ServiceWorkerCacheStorage::DeleteCacheDidWriteIndex(
+ const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ cache_loader_->CleanUpDeletedCache(
+ cache_name,
+ base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidCleanUp,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+void ServiceWorkerCacheStorage::DeleteCacheDidCleanUp(
+ const BoolAndErrorCallback& callback,
+ bool success) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ callback.Run(true, CACHE_STORAGE_ERROR_NO_ERROR);
+}
+
+scoped_refptr<ServiceWorkerCache> ServiceWorkerCacheStorage::GetLoadedCache(
+ const std::string& cache_name) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(initialized_);
+
+ CacheMap::iterator map_iter = cache_map_.find(cache_name);
+ if (map_iter == cache_map_.end())
+ return scoped_refptr<ServiceWorkerCache>();
+
+ base::WeakPtr<ServiceWorkerCache> cache = map_iter->second;
+
+ if (!cache) {
+ scoped_refptr<ServiceWorkerCache> new_cache =
+ cache_loader_->CreateServiceWorkerCache(cache_name);
+ map_iter->second = new_cache->AsWeakPtr();
+ return new_cache;
+ }
+
+ return make_scoped_refptr(cache.get());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_cache_storage.h b/chromium/content/browser/service_worker/service_worker_cache_storage.h
new file mode 100644
index 00000000000..a102707356f
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_storage.h
@@ -0,0 +1,165 @@
+// 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_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_H_
+
+#include <map>
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/service_worker/service_worker_cache.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace net {
+class URLRequestContext;
+}
+
+namespace storage {
+class BlobStorageContext;
+}
+
+namespace content {
+
+// TODO(jkarlin): Constrain the total bytes used per origin.
+
+// ServiceWorkerCacheStorage holds the set of caches for a given origin. It is
+// owned by the ServiceWorkerCacheStorageManager. This class expects to be run
+// on the IO thread.
+class CONTENT_EXPORT ServiceWorkerCacheStorage {
+ public:
+ enum CacheStorageError {
+ CACHE_STORAGE_ERROR_NO_ERROR,
+ CACHE_STORAGE_ERROR_NOT_IMPLEMENTED,
+ CACHE_STORAGE_ERROR_NOT_FOUND,
+ CACHE_STORAGE_ERROR_EXISTS,
+ CACHE_STORAGE_ERROR_STORAGE,
+ CACHE_STORAGE_ERROR_CLOSING
+ };
+ typedef std::vector<std::string> StringVector;
+ typedef base::Callback<void(bool, CacheStorageError)> BoolAndErrorCallback;
+ typedef base::Callback<void(const scoped_refptr<ServiceWorkerCache>&,
+ CacheStorageError)> CacheAndErrorCallback;
+ typedef base::Callback<void(const StringVector&, CacheStorageError)>
+ StringsAndErrorCallback;
+
+ static const char kIndexFileName[];
+
+ ServiceWorkerCacheStorage(
+ const base::FilePath& origin_path,
+ bool memory_only,
+ base::SequencedTaskRunner* cache_task_runner,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context,
+ const GURL& origin);
+
+ // Any unfinished asynchronous operations may not complete or call their
+ // callbacks.
+ virtual ~ServiceWorkerCacheStorage();
+
+ // Get the cache for the given key. If the cache is not found it is
+ // created.
+ void OpenCache(const std::string& cache_name,
+ const CacheAndErrorCallback& callback);
+
+ // Calls the callback with whether or not the cache exists.
+ void HasCache(const std::string& cache_name,
+ const BoolAndErrorCallback& callback);
+
+ // Deletes the cache if it exists. If it doesn't exist,
+ // CACHE_STORAGE_ERROR_NOT_FOUND is returned.
+ void DeleteCache(const std::string& cache_name,
+ const BoolAndErrorCallback& callback);
+
+ // Calls the callback with a vector of cache names (keys) available.
+ void EnumerateCaches(const StringsAndErrorCallback& callback);
+
+ // TODO(jkarlin): Add match() function.
+
+ void CloseAllCaches(const base::Closure& callback);
+
+ // The size of all of the origin's contents in memory. Returns 0 if the cache
+ // backend is not a memory backend.
+ int64 MemoryBackedSize() const;
+
+ private:
+ class MemoryLoader;
+ class SimpleCacheLoader;
+ class CacheLoader;
+
+ typedef std::map<std::string, base::WeakPtr<ServiceWorkerCache> > CacheMap;
+
+ // Return a ServiceWorkerCache for the given name if the name is known. If the
+ // ServiceWorkerCache has been deleted, creates a new one.
+ scoped_refptr<ServiceWorkerCache> GetLoadedCache(
+ const std::string& cache_name);
+
+ // Initializer and its callback are below. While LazyInit is running any new
+ // operations will be queued and started in order after initialization.
+ void LazyInit(const base::Closure& closure);
+ void LazyInitDidLoadIndex(
+ const base::Closure& callback,
+ scoped_ptr<std::vector<std::string> > indexed_cache_names);
+
+ void AddCacheToMap(const std::string& cache_name,
+ base::WeakPtr<ServiceWorkerCache> cache);
+
+ // The CreateCache callbacks are below.
+ void CreateCacheDidCreateCache(
+ const std::string& cache_name,
+ const CacheAndErrorCallback& callback,
+ const scoped_refptr<ServiceWorkerCache>& cache);
+ void CreateCacheDidWriteIndex(const CacheAndErrorCallback& callback,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ bool success);
+
+ // The DeleteCache callbacks are below.
+ void DeleteCacheDidClose(const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ const StringVector& ordered_cache_names,
+ const scoped_refptr<ServiceWorkerCache>& cache);
+ void DeleteCacheDidWriteIndex(const std::string& cache_name,
+ const BoolAndErrorCallback& callback,
+ bool success);
+ void DeleteCacheDidCleanUp(const BoolAndErrorCallback& callback,
+ bool success);
+
+ // Whether or not we've loaded the list of cache names into memory.
+ bool initialized_;
+
+ // The list of operations waiting on initialization.
+ std::vector<base::Closure> init_callbacks_;
+
+ // The map of cache names to ServiceWorkerCache objects.
+ CacheMap cache_map_;
+
+ // The names of caches in the order that they were created.
+ StringVector ordered_cache_names_;
+
+ // The file path for this CacheStorage.
+ base::FilePath origin_path_;
+
+ // The TaskRunner to run file IO on.
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
+
+ // Whether or not to store data in disk or memory.
+ bool memory_only_;
+
+ // Performs backend specific operations (memory vs disk).
+ scoped_ptr<CacheLoader> cache_loader_;
+
+ base::WeakPtrFactory<ServiceWorkerCacheStorage> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheStorage);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_H_
diff --git a/chromium/content/browser/service_worker/service_worker_cache_storage_manager.cc b/chromium/content/browser/service_worker/service_worker_cache_storage_manager.cc
new file mode 100644
index 00000000000..3c3203dc507
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_storage_manager.cc
@@ -0,0 +1,325 @@
+// 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/service_worker/service_worker_cache_storage_manager.h"
+
+#include <map>
+#include <string>
+
+#include "base/bind.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/id_map.h"
+#include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "content/browser/service_worker/service_worker_cache.pb.h"
+#include "content/browser/service_worker/service_worker_cache_quota_client.h"
+#include "content/browser/service_worker/service_worker_cache_storage.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 "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/quota/quota_status_code.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+base::FilePath ConstructOriginPath(const base::FilePath& root_path,
+ const GURL& origin) {
+ std::string origin_hash = base::SHA1HashString(origin.spec());
+ std::string origin_hash_hex = base::StringToLowerASCII(
+ base::HexEncode(origin_hash.c_str(), origin_hash.length()));
+ return root_path.AppendASCII(origin_hash_hex);
+}
+
+bool DeleteDir(const base::FilePath& path) {
+ return base::DeleteFile(path, true /* recursive */);
+}
+
+void DeleteOriginDidDeleteDir(
+ const storage::QuotaClient::DeletionCallback& callback,
+ bool rv) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ callback.Run(rv ? storage::kQuotaStatusOk : storage::kQuotaErrorAbort);
+}
+
+std::set<GURL> ListOriginsOnDisk(base::FilePath root_path_) {
+ std::set<GURL> origins;
+ base::FileEnumerator file_enum(
+ root_path_, false /* recursive */, base::FileEnumerator::DIRECTORIES);
+
+ base::FilePath path;
+ while (!(path = file_enum.Next()).empty()) {
+ std::string protobuf;
+ base::ReadFileToString(
+ path.AppendASCII(ServiceWorkerCacheStorage::kIndexFileName), &protobuf);
+
+ ServiceWorkerCacheStorageIndex index;
+ if (index.ParseFromString(protobuf)) {
+ if (index.has_origin())
+ origins.insert(GURL(index.origin()));
+ }
+ }
+
+ return origins;
+}
+
+void GetOriginsForHostDidListOrigins(
+ const std::string& host,
+ const storage::QuotaClient::GetOriginsCallback& callback,
+ const std::set<GURL>& origins) {
+ std::set<GURL> out_origins;
+ for (const GURL& origin : origins) {
+ if (host == net::GetHostOrSpecFromURL(origin))
+ out_origins.insert(origin);
+ }
+ callback.Run(out_origins);
+}
+
+} // namespace
+
+// static
+scoped_ptr<ServiceWorkerCacheStorageManager>
+ServiceWorkerCacheStorageManager::Create(
+ const base::FilePath& path,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ const 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 ServiceWorkerCacheStorageManager(
+ root_path, cache_task_runner, quota_manager_proxy));
+}
+
+// static
+scoped_ptr<ServiceWorkerCacheStorageManager>
+ServiceWorkerCacheStorageManager::Create(
+ ServiceWorkerCacheStorageManager* old_manager) {
+ scoped_ptr<ServiceWorkerCacheStorageManager> manager(
+ new ServiceWorkerCacheStorageManager(
+ old_manager->root_path(),
+ old_manager->cache_task_runner(),
+ old_manager->quota_manager_proxy_.get()));
+ // These values may be NULL, in which case this will be called again later by
+ // the dispatcher host per usual.
+ manager->SetBlobParametersForCache(old_manager->url_request_context(),
+ old_manager->blob_storage_context());
+ return manager.Pass();
+}
+
+ServiceWorkerCacheStorageManager::~ServiceWorkerCacheStorageManager() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ for (ServiceWorkerCacheStorageMap::iterator it = cache_storage_map_.begin();
+ it != cache_storage_map_.end();
+ ++it) {
+ delete it->second;
+ }
+}
+
+void ServiceWorkerCacheStorageManager::OpenCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const ServiceWorkerCacheStorage::CacheAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ServiceWorkerCacheStorage* cache_storage =
+ FindOrCreateServiceWorkerCacheManager(origin);
+
+ cache_storage->OpenCache(cache_name, callback);
+}
+
+void ServiceWorkerCacheStorageManager::HasCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const ServiceWorkerCacheStorage::BoolAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ServiceWorkerCacheStorage* cache_storage =
+ FindOrCreateServiceWorkerCacheManager(origin);
+ cache_storage->HasCache(cache_name, callback);
+}
+
+void ServiceWorkerCacheStorageManager::DeleteCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const ServiceWorkerCacheStorage::BoolAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ServiceWorkerCacheStorage* cache_storage =
+ FindOrCreateServiceWorkerCacheManager(origin);
+ cache_storage->DeleteCache(cache_name, callback);
+}
+
+void ServiceWorkerCacheStorageManager::EnumerateCaches(
+ const GURL& origin,
+ const ServiceWorkerCacheStorage::StringsAndErrorCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ServiceWorkerCacheStorage* cache_storage =
+ FindOrCreateServiceWorkerCacheManager(origin);
+
+ cache_storage->EnumerateCaches(callback);
+}
+
+void ServiceWorkerCacheStorageManager::SetBlobParametersForCache(
+ net::URLRequestContext* request_context,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(cache_storage_map_.empty());
+ DCHECK(!request_context_ || request_context_ == request_context);
+ DCHECK(!blob_context_ || blob_context_.get() == blob_storage_context.get());
+ request_context_ = request_context;
+ blob_context_ = blob_storage_context;
+}
+
+void ServiceWorkerCacheStorageManager::GetOriginUsage(
+ const GURL& origin_url,
+ const storage::QuotaClient::GetUsageCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (IsMemoryBacked()) {
+ int64 sum = 0;
+ for (const auto& key_value : cache_storage_map_)
+ sum += key_value.second->MemoryBackedSize();
+ callback.Run(sum);
+ return;
+ }
+
+ PostTaskAndReplyWithResult(
+ cache_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(base::ComputeDirectorySize,
+ ConstructOriginPath(root_path_, origin_url)),
+ base::Bind(callback));
+}
+
+void ServiceWorkerCacheStorageManager::GetOrigins(
+ const storage::QuotaClient::GetOriginsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (IsMemoryBacked()) {
+ std::set<GURL> origins;
+ for (const auto& key_value : cache_storage_map_)
+ origins.insert(key_value.first);
+
+ callback.Run(origins);
+ return;
+ }
+
+ PostTaskAndReplyWithResult(cache_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&ListOriginsOnDisk, root_path_),
+ base::Bind(callback));
+}
+
+void ServiceWorkerCacheStorageManager::GetOriginsForHost(
+ const std::string& host,
+ const storage::QuotaClient::GetOriginsCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (IsMemoryBacked()) {
+ std::set<GURL> origins;
+ for (const auto& key_value : cache_storage_map_) {
+ if (host == net::GetHostOrSpecFromURL(key_value.first))
+ origins.insert(key_value.first);
+ }
+ callback.Run(origins);
+ return;
+ }
+
+ PostTaskAndReplyWithResult(
+ cache_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(&ListOriginsOnDisk, root_path_),
+ base::Bind(&GetOriginsForHostDidListOrigins, host, callback));
+}
+
+void ServiceWorkerCacheStorageManager::DeleteOriginData(
+ const GURL& origin,
+ const storage::QuotaClient::DeletionCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ ServiceWorkerCacheStorage* cache_storage =
+ FindOrCreateServiceWorkerCacheManager(origin);
+ cache_storage_map_.erase(origin);
+ cache_storage->CloseAllCaches(
+ base::Bind(&ServiceWorkerCacheStorageManager::DeleteOriginDidClose,
+ origin, callback, base::Passed(make_scoped_ptr(cache_storage)),
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+// static
+void ServiceWorkerCacheStorageManager::DeleteOriginDidClose(
+ const GURL& origin,
+ const storage::QuotaClient::DeletionCallback& callback,
+ scoped_ptr<ServiceWorkerCacheStorage> cache_storage,
+ base::WeakPtr<ServiceWorkerCacheStorageManager> cache_manager) {
+ // TODO(jkarlin): Deleting the storage leaves any unfinished operations
+ // hanging, resulting in unresolved promises. Fix this by guaranteeing that
+ // callbacks are called in ServiceWorkerStorage.
+ cache_storage.reset();
+
+ if (!cache_manager) {
+ callback.Run(storage::kQuotaErrorAbort);
+ return;
+ }
+
+ if (cache_manager->IsMemoryBacked()) {
+ callback.Run(storage::kQuotaStatusOk);
+ return;
+ }
+
+ PostTaskAndReplyWithResult(
+ cache_manager->cache_task_runner_.get(), FROM_HERE,
+ base::Bind(&DeleteDir,
+ ConstructOriginPath(cache_manager->root_path_, origin)),
+ base::Bind(&DeleteOriginDidDeleteDir, callback));
+}
+
+ServiceWorkerCacheStorageManager::ServiceWorkerCacheStorageManager(
+ const base::FilePath& path,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
+ : root_path_(path),
+ cache_task_runner_(cache_task_runner),
+ quota_manager_proxy_(quota_manager_proxy),
+ request_context_(NULL),
+ weak_ptr_factory_(this) {
+ if (quota_manager_proxy_.get()) {
+ quota_manager_proxy_->RegisterClient(
+ new ServiceWorkerCacheQuotaClient(weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+ServiceWorkerCacheStorage*
+ServiceWorkerCacheStorageManager::FindOrCreateServiceWorkerCacheManager(
+ const GURL& origin) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(request_context_);
+ ServiceWorkerCacheStorageMap::const_iterator it =
+ cache_storage_map_.find(origin);
+ if (it == cache_storage_map_.end()) {
+ ServiceWorkerCacheStorage* cache_storage =
+ new ServiceWorkerCacheStorage(ConstructOriginPath(root_path_, origin),
+ IsMemoryBacked(),
+ cache_task_runner_.get(),
+ request_context_,
+ quota_manager_proxy_,
+ blob_context_,
+ origin);
+ // The map owns fetch_stores.
+ cache_storage_map_.insert(std::make_pair(origin, cache_storage));
+ return cache_storage;
+ }
+ return it->second;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_cache_storage_manager.h b/chromium/content/browser/service_worker/service_worker_cache_storage_manager.h
new file mode 100644
index 00000000000..79ac6c07a26
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_storage_manager.h
@@ -0,0 +1,144 @@
+// 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_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_MANAGER_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "content/browser/service_worker/service_worker_cache_storage.h"
+#include "content/common/content_export.h"
+#include "storage/browser/quota/quota_client.h"
+#include "url/gurl.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace net {
+class URLRequestContext;
+}
+
+namespace storage {
+class BlobStorageContext;
+class QuotaManagerProxy;
+}
+
+namespace content {
+
+class ServiceWorkerCacheQuotaClient;
+class ServiceWorkerCacheStorageManagerTest;
+
+// Keeps track of a ServiceWorkerCacheStorage per origin. There is one
+// ServiceWorkerCacheStorageManager per ServiceWorkerContextCore.
+// TODO(jkarlin): Remove ServiceWorkerCacheStorage from memory once they're no
+// longer in active use.
+class CONTENT_EXPORT ServiceWorkerCacheStorageManager {
+ public:
+ static scoped_ptr<ServiceWorkerCacheStorageManager> Create(
+ const base::FilePath& path,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy);
+
+ static scoped_ptr<ServiceWorkerCacheStorageManager> Create(
+ ServiceWorkerCacheStorageManager* old_manager);
+
+ virtual ~ServiceWorkerCacheStorageManager();
+
+ // Methods to support the CacheStorage spec. These methods call the
+ // corresponding ServiceWorkerCacheStorage method on the appropriate thread.
+ void OpenCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const ServiceWorkerCacheStorage::CacheAndErrorCallback& callback);
+ void HasCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const ServiceWorkerCacheStorage::BoolAndErrorCallback& callback);
+ void DeleteCache(
+ const GURL& origin,
+ const std::string& cache_name,
+ const ServiceWorkerCacheStorage::BoolAndErrorCallback& callback);
+ void EnumerateCaches(
+ const GURL& origin,
+ const ServiceWorkerCacheStorage::StringsAndErrorCallback& callback);
+ // TODO(jkarlin): Add match() function.
+
+ // This must be called before creating any of the public *Cache functions
+ // above.
+ void SetBlobParametersForCache(
+ net::URLRequestContext* request_context,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context);
+
+ base::WeakPtr<ServiceWorkerCacheStorageManager> AsWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
+ private:
+ friend class ServiceWorkerCacheQuotaClient;
+ friend class ServiceWorkerCacheStorageManagerTest;
+
+ typedef std::map<GURL, ServiceWorkerCacheStorage*>
+ ServiceWorkerCacheStorageMap;
+
+ ServiceWorkerCacheStorageManager(
+ const base::FilePath& path,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy);
+
+ // The returned ServiceWorkerCacheStorage* is owned by
+ // service_worker_cache_storages_.
+ ServiceWorkerCacheStorage* FindOrCreateServiceWorkerCacheManager(
+ const GURL& origin);
+
+ // QuotaClient support
+ void GetOriginUsage(const GURL& origin_url,
+ const storage::QuotaClient::GetUsageCallback& callback);
+ void GetOrigins(const storage::QuotaClient::GetOriginsCallback& callback);
+ void GetOriginsForHost(
+ const std::string& host,
+ const storage::QuotaClient::GetOriginsCallback& callback);
+ void DeleteOriginData(const GURL& origin,
+ const storage::QuotaClient::DeletionCallback& callback);
+ static void DeleteOriginDidClose(
+ const GURL& origin,
+ const storage::QuotaClient::DeletionCallback& callback,
+ scoped_ptr<ServiceWorkerCacheStorage> cache_storage,
+ base::WeakPtr<ServiceWorkerCacheStorageManager> cache_manager);
+
+ net::URLRequestContext* url_request_context() const {
+ return request_context_;
+ }
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context() const {
+ return blob_context_;
+ }
+ base::FilePath root_path() const { return root_path_; }
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner() const {
+ return cache_task_runner_;
+ }
+
+ bool IsMemoryBacked() const { return root_path_.empty(); }
+
+ base::FilePath root_path_;
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
+
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+
+ // The map owns the CacheStorages and the CacheStorages are only accessed on
+ // |cache_task_runner_|.
+ ServiceWorkerCacheStorageMap cache_storage_map_;
+
+ net::URLRequestContext* request_context_;
+ base::WeakPtr<storage::BlobStorageContext> blob_context_;
+
+ base::WeakPtrFactory<ServiceWorkerCacheStorageManager> weak_ptr_factory_;
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheStorageManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CACHE_STORAGE_MANAGER_H_
diff --git a/chromium/content/browser/service_worker/service_worker_cache_storage_manager_unittest.cc b/chromium/content/browser/service_worker/service_worker_cache_storage_manager_unittest.cc
new file mode 100644
index 00000000000..8bfe7cce66d
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_storage_manager_unittest.cc
@@ -0,0 +1,631 @@
+// 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/service_worker/service_worker_cache_storage_manager.h"
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/run_loop.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/browser/quota/mock_quota_manager_proxy.h"
+#include "content/browser/service_worker/service_worker_cache_quota_client.h"
+#include "content/public/browser/browser_thread.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_getter.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class ServiceWorkerCacheStorageManagerTest : public testing::Test {
+ protected:
+ ServiceWorkerCacheStorageManagerTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ callback_bool_(false),
+ callback_error_(
+ ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR),
+ callback_cache_error_(ServiceWorkerCache::ErrorTypeOK),
+ origin1_("http://example1.com"),
+ origin2_("http://example2.com") {}
+
+ void SetUp() override {
+ ChromeBlobStorageContext* blob_storage_context(
+ ChromeBlobStorageContext::GetFor(&browser_context_));
+ // Wait for ChromeBlobStorageContext to finish initializing.
+ base::RunLoop().RunUntilIdle();
+
+ quota_manager_proxy_ = new MockQuotaManagerProxy(
+ nullptr, base::MessageLoopProxy::current().get());
+
+ net::URLRequestContext* url_request_context =
+ browser_context_.GetRequestContext()->GetURLRequestContext();
+ if (MemoryOnly()) {
+ cache_manager_ = ServiceWorkerCacheStorageManager::Create(
+ base::FilePath(),
+ base::MessageLoopProxy::current(),
+ quota_manager_proxy_);
+ } else {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ cache_manager_ = ServiceWorkerCacheStorageManager::Create(
+ temp_dir_.path(),
+ base::MessageLoopProxy::current(),
+ quota_manager_proxy_);
+ }
+
+ cache_manager_->SetBlobParametersForCache(
+ url_request_context, blob_storage_context->context()->AsWeakPtr());
+ }
+
+ void TearDown() override {
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ virtual bool MemoryOnly() { return false; }
+
+ void BoolAndErrorCallback(
+ base::RunLoop* run_loop,
+ bool value,
+ ServiceWorkerCacheStorage::CacheStorageError error) {
+ callback_bool_ = value;
+ callback_error_ = error;
+ run_loop->Quit();
+ }
+
+ void CacheAndErrorCallback(
+ base::RunLoop* run_loop,
+ const scoped_refptr<ServiceWorkerCache>& cache,
+ ServiceWorkerCacheStorage::CacheStorageError error) {
+ callback_cache_ = cache;
+ callback_error_ = error;
+ run_loop->Quit();
+ }
+
+ void StringsAndErrorCallback(
+ base::RunLoop* run_loop,
+ const std::vector<std::string>& strings,
+ ServiceWorkerCacheStorage::CacheStorageError error) {
+ callback_strings_ = strings;
+ callback_error_ = error;
+ run_loop->Quit();
+ }
+
+ void CachePutCallback(base::RunLoop* run_loop,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ callback_cache_error_ = error;
+ run_loop->Quit();
+ }
+
+ void CacheMatchCallback(
+ base::RunLoop* run_loop,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle) {
+ callback_cache_error_ = error;
+ callback_cache_response_ = response.Pass();
+ // Deliberately drop the data handle as only the url is being tested.
+ run_loop->Quit();
+ }
+
+ bool Open(const GURL& origin, const std::string& cache_name) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_manager_->OpenCache(
+ origin,
+ cache_name,
+ base::Bind(&ServiceWorkerCacheStorageManagerTest::CacheAndErrorCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ bool error = callback_error_ !=
+ ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR;
+ if (error)
+ EXPECT_TRUE(!callback_cache_.get());
+ else
+ EXPECT_TRUE(callback_cache_.get());
+ return !error;
+ }
+
+ bool Has(const GURL& origin, const std::string& cache_name) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_manager_->HasCache(
+ origin,
+ cache_name,
+ base::Bind(&ServiceWorkerCacheStorageManagerTest::BoolAndErrorCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_bool_;
+ }
+
+ bool Delete(const GURL& origin, const std::string& cache_name) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_manager_->DeleteCache(
+ origin,
+ cache_name,
+ base::Bind(&ServiceWorkerCacheStorageManagerTest::BoolAndErrorCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_bool_;
+ }
+
+ bool Keys(const GURL& origin) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_manager_->EnumerateCaches(
+ origin,
+ base::Bind(
+ &ServiceWorkerCacheStorageManagerTest::StringsAndErrorCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ bool error = callback_error_ !=
+ ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NO_ERROR;
+ return !error;
+ }
+
+ bool CachePut(const scoped_refptr<ServiceWorkerCache>& cache,
+ const GURL& url) {
+ scoped_ptr<ServiceWorkerFetchRequest> request(
+ new ServiceWorkerFetchRequest());
+ scoped_ptr<ServiceWorkerResponse> response(new ServiceWorkerResponse());
+ request->url = url;
+ response->url = url;
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache->Put(
+ request.Pass(),
+ response.Pass(),
+ base::Bind(&ServiceWorkerCacheStorageManagerTest::CachePutCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ bool error = callback_cache_error_ != ServiceWorkerCache::ErrorTypeOK;
+ return !error;
+ }
+
+ bool CacheMatch(const scoped_refptr<ServiceWorkerCache>& cache,
+ const GURL& url) {
+ scoped_ptr<ServiceWorkerFetchRequest> request(
+ new ServiceWorkerFetchRequest());
+ request->url = url;
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache->Match(
+ request.Pass(),
+ base::Bind(&ServiceWorkerCacheStorageManagerTest::CacheMatchCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ bool error = callback_cache_error_ != ServiceWorkerCache::ErrorTypeOK;
+ return !error;
+ }
+
+ ServiceWorkerCacheStorage* CacheStorageForOrigin(const GURL& origin) {
+ return cache_manager_->FindOrCreateServiceWorkerCacheManager(origin);
+ }
+
+ protected:
+ TestBrowserContext browser_context_;
+ TestBrowserThreadBundle browser_thread_bundle_;
+
+ base::ScopedTempDir temp_dir_;
+ scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
+ scoped_ptr<ServiceWorkerCacheStorageManager> cache_manager_;
+
+ scoped_refptr<ServiceWorkerCache> callback_cache_;
+ int callback_bool_;
+ ServiceWorkerCacheStorage::CacheStorageError callback_error_;
+ ServiceWorkerCache::ErrorType callback_cache_error_;
+ scoped_ptr<ServiceWorkerResponse> callback_cache_response_;
+ std::vector<std::string> callback_strings_;
+
+ const GURL origin1_;
+ const GURL origin2_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheStorageManagerTest);
+};
+
+class ServiceWorkerCacheStorageManagerMemoryOnlyTest
+ : public ServiceWorkerCacheStorageManagerTest {
+ bool MemoryOnly() override { return true; }
+};
+
+class ServiceWorkerCacheStorageManagerTestP
+ : public ServiceWorkerCacheStorageManagerTest,
+ public testing::WithParamInterface<bool> {
+ bool MemoryOnly() override { return !GetParam(); }
+};
+
+TEST_F(ServiceWorkerCacheStorageManagerTest, TestsRunOnIOThread) {
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, OpenCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, OpenTwoCaches) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin1_, "bar"));
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, CachePointersDiffer) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_NE(callback_cache_.get(), cache.get());
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, Open2CachesSameNameDiffOrigins) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
+ EXPECT_TRUE(Open(origin2_, "foo"));
+ EXPECT_NE(cache.get(), callback_cache_.get());
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, OpenExistingCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_EQ(callback_cache_.get(), cache.get());
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, HasCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Has(origin1_, "foo"));
+ EXPECT_TRUE(callback_bool_);
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, HasNonExistent) {
+ EXPECT_FALSE(Has(origin1_, "foo"));
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, DeleteCache) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_FALSE(Has(origin1_, "foo"));
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, DeleteTwice) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_FALSE(Delete(origin1_, "foo"));
+ EXPECT_EQ(ServiceWorkerCacheStorage::CACHE_STORAGE_ERROR_NOT_FOUND,
+ callback_error_);
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, EmptyKeys) {
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_TRUE(callback_strings_.empty());
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, SomeKeys) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_TRUE(Open(origin2_, "baz"));
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(2u, callback_strings_.size());
+ std::vector<std::string> expected_keys;
+ expected_keys.push_back("foo");
+ expected_keys.push_back("bar");
+ EXPECT_EQ(expected_keys, callback_strings_);
+ EXPECT_TRUE(Keys(origin2_));
+ EXPECT_EQ(1u, callback_strings_.size());
+ EXPECT_STREQ("baz", callback_strings_[0].c_str());
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, DeletedKeysGone) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_TRUE(Open(origin2_, "baz"));
+ EXPECT_TRUE(Delete(origin1_, "bar"));
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(1u, callback_strings_.size());
+ EXPECT_STREQ("foo", callback_strings_[0].c_str());
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, Chinese) {
+ EXPECT_TRUE(Open(origin1_, "你好"));
+ scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
+ EXPECT_TRUE(Open(origin1_, "你好"));
+ EXPECT_EQ(callback_cache_.get(), cache.get());
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(1u, callback_strings_.size());
+ EXPECT_STREQ("你好", callback_strings_[0].c_str());
+}
+
+TEST_F(ServiceWorkerCacheStorageManagerTest, EmptyKey) {
+ EXPECT_TRUE(Open(origin1_, ""));
+ scoped_refptr<ServiceWorkerCache> cache = callback_cache_;
+ EXPECT_TRUE(Open(origin1_, ""));
+ EXPECT_EQ(cache.get(), callback_cache_.get());
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(1u, callback_strings_.size());
+ EXPECT_STREQ("", callback_strings_[0].c_str());
+ EXPECT_TRUE(Has(origin1_, ""));
+ EXPECT_TRUE(Delete(origin1_, ""));
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(0u, callback_strings_.size());
+}
+
+TEST_F(ServiceWorkerCacheStorageManagerTest, DataPersists) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_TRUE(Open(origin1_, "baz"));
+ EXPECT_TRUE(Open(origin2_, "raz"));
+ EXPECT_TRUE(Delete(origin1_, "bar"));
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ cache_manager_ =
+ ServiceWorkerCacheStorageManager::Create(cache_manager_.get());
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(2u, callback_strings_.size());
+ std::vector<std::string> expected_keys;
+ expected_keys.push_back("foo");
+ expected_keys.push_back("baz");
+ EXPECT_EQ(expected_keys, callback_strings_);
+}
+
+TEST_F(ServiceWorkerCacheStorageManagerMemoryOnlyTest, DataLostWhenMemoryOnly) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin2_, "baz"));
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ cache_manager_ =
+ ServiceWorkerCacheStorageManager::Create(cache_manager_.get());
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(0u, callback_strings_.size());
+}
+
+TEST_F(ServiceWorkerCacheStorageManagerTest, BadCacheName) {
+ // Since the implementation writes cache names to disk, ensure that we don't
+ // escape the directory.
+ const std::string bad_name = "../../../../../../../../../../../../../../foo";
+ EXPECT_TRUE(Open(origin1_, bad_name));
+ EXPECT_TRUE(Keys(origin1_));
+ EXPECT_EQ(1u, callback_strings_.size());
+ EXPECT_STREQ(bad_name.c_str(), callback_strings_[0].c_str());
+}
+
+TEST_F(ServiceWorkerCacheStorageManagerTest, BadOriginName) {
+ // Since the implementation writes origin names to disk, ensure that we don't
+ // escape the directory.
+ GURL bad_origin("http://../../../../../../../../../../../../../../foo");
+ EXPECT_TRUE(Open(bad_origin, "foo"));
+ EXPECT_TRUE(Keys(bad_origin));
+ EXPECT_EQ(1u, callback_strings_.size());
+ EXPECT_STREQ("foo", callback_strings_[0].c_str());
+}
+
+// With a persistent cache if the client drops its reference to a
+// ServiceWorkerCache
+// it should be deleted.
+TEST_F(ServiceWorkerCacheStorageManagerTest, DropReference) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ base::WeakPtr<ServiceWorkerCache> cache = callback_cache_->AsWeakPtr();
+ callback_cache_ = NULL;
+ EXPECT_TRUE(!cache);
+}
+
+// With a memory cache the cache can't be freed from memory until the client
+// calls delete.
+TEST_F(ServiceWorkerCacheStorageManagerMemoryOnlyTest,
+ MemoryLosesReferenceOnlyAfterDelete) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ base::WeakPtr<ServiceWorkerCache> cache = callback_cache_->AsWeakPtr();
+ callback_cache_ = NULL;
+ EXPECT_TRUE(cache);
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_FALSE(cache);
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, RecreateCacheOnDemand) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ callback_cache_ = NULL;
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CacheMatch(callback_cache_, GURL("http://example.com/foo")));
+}
+
+TEST_P(ServiceWorkerCacheStorageManagerTestP, DeleteBeforeRelease) {
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Delete(origin1_, "foo"));
+ EXPECT_TRUE(callback_cache_->AsWeakPtr());
+}
+
+TEST_F(ServiceWorkerCacheStorageManagerMemoryOnlyTest, MemoryBackedSize) {
+ ServiceWorkerCacheStorage* cache_storage = CacheStorageForOrigin(origin1_);
+ EXPECT_EQ(0, cache_storage->MemoryBackedSize());
+
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ scoped_refptr<ServiceWorkerCache> foo_cache = callback_cache_;
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ scoped_refptr<ServiceWorkerCache> bar_cache = callback_cache_;
+ EXPECT_EQ(0, cache_storage->MemoryBackedSize());
+
+ EXPECT_TRUE(CachePut(foo_cache, GURL("http://example.com/foo")));
+ EXPECT_LT(0, cache_storage->MemoryBackedSize());
+ int64 foo_size = cache_storage->MemoryBackedSize();
+
+ EXPECT_TRUE(CachePut(bar_cache, GURL("http://example.com/foo")));
+ EXPECT_EQ(foo_size * 2, cache_storage->MemoryBackedSize());
+}
+
+TEST_F(ServiceWorkerCacheStorageManagerTest, MemoryBackedSizePersistent) {
+ ServiceWorkerCacheStorage* 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());
+}
+
+class ServiceWorkerCacheQuotaClientTest
+ : public ServiceWorkerCacheStorageManagerTest {
+ protected:
+ ServiceWorkerCacheQuotaClientTest() {}
+
+ void SetUp() override {
+ ServiceWorkerCacheStorageManagerTest::SetUp();
+ quota_client_.reset(
+ new ServiceWorkerCacheQuotaClient(cache_manager_->AsWeakPtr()));
+ }
+
+ void UsageCallback(base::RunLoop* run_loop, int64 usage) {
+ callback_usage_ = usage;
+ run_loop->Quit();
+ }
+
+ void OriginsCallback(base::RunLoop* run_loop, const std::set<GURL>& origins) {
+ callback_origins_ = origins;
+ run_loop->Quit();
+ }
+
+ void DeleteOriginCallback(base::RunLoop* run_loop,
+ storage::QuotaStatusCode status) {
+ callback_status_ = status;
+ run_loop->Quit();
+ }
+
+ int64 QuotaGetOriginUsage(const GURL& origin) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ quota_client_->GetOriginUsage(
+ origin,
+ storage::kStorageTypeTemporary,
+ base::Bind(&ServiceWorkerCacheQuotaClientTest::UsageCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+ return callback_usage_;
+ }
+
+ size_t QuotaGetOriginsForType() {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ quota_client_->GetOriginsForType(
+ storage::kStorageTypeTemporary,
+ base::Bind(&ServiceWorkerCacheQuotaClientTest::OriginsCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+ return callback_origins_.size();
+ }
+
+ size_t QuotaGetOriginsForHost(const std::string& host) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ quota_client_->GetOriginsForHost(
+ storage::kStorageTypeTemporary,
+ host,
+ base::Bind(&ServiceWorkerCacheQuotaClientTest::OriginsCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+ return callback_origins_.size();
+ }
+
+ bool QuotaDeleteOriginData(const GURL& origin) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ quota_client_->DeleteOriginData(
+ origin,
+ storage::kStorageTypeTemporary,
+ base::Bind(&ServiceWorkerCacheQuotaClientTest::DeleteOriginCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+ return callback_status_ == storage::kQuotaStatusOk;
+ }
+
+ bool QuotaDoesSupport(storage::StorageType type) {
+ return quota_client_->DoesSupport(type);
+ }
+
+ scoped_ptr<ServiceWorkerCacheQuotaClient> quota_client_;
+
+ storage::QuotaStatusCode callback_status_;
+ int64 callback_usage_;
+ std::set<GURL> callback_origins_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheQuotaClientTest);
+};
+
+class ServiceWorkerCacheQuotaClientTestP
+ : public ServiceWorkerCacheQuotaClientTest,
+ public testing::WithParamInterface<bool> {
+ bool MemoryOnly() override { return !GetParam(); }
+};
+
+TEST_P(ServiceWorkerCacheQuotaClientTestP, QuotaID) {
+ EXPECT_EQ(storage::QuotaClient::kServiceWorkerCache, quota_client_->id());
+}
+
+TEST_P(ServiceWorkerCacheQuotaClientTestP, QuotaGetOriginUsage) {
+ EXPECT_EQ(0, QuotaGetOriginUsage(origin1_));
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(CachePut(callback_cache_, GURL("http://example.com/foo")));
+ EXPECT_LT(0, QuotaGetOriginUsage(origin1_));
+}
+
+TEST_P(ServiceWorkerCacheQuotaClientTestP, QuotaGetOriginsForType) {
+ EXPECT_EQ(0u, QuotaGetOriginsForType());
+ EXPECT_TRUE(Open(origin1_, "foo"));
+ EXPECT_TRUE(Open(origin1_, "bar"));
+ EXPECT_TRUE(Open(origin2_, "foo"));
+ EXPECT_EQ(2u, QuotaGetOriginsForType());
+}
+
+TEST_P(ServiceWorkerCacheQuotaClientTestP, QuotaGetOriginsForHost) {
+ EXPECT_EQ(0u, QuotaGetOriginsForHost("example.com"));
+ EXPECT_TRUE(Open(GURL("http://example.com:8080"), "foo"));
+ EXPECT_TRUE(Open(GURL("http://example.com:9000"), "foo"));
+ EXPECT_TRUE(Open(GURL("ftp://example.com"), "foo"));
+ EXPECT_TRUE(Open(GURL("http://example2.com"), "foo"));
+ EXPECT_EQ(3u, QuotaGetOriginsForHost("example.com"));
+ EXPECT_EQ(1u, QuotaGetOriginsForHost("example2.com"));
+ EXPECT_TRUE(callback_origins_.find(GURL("http://example2.com")) !=
+ callback_origins_.end());
+ EXPECT_EQ(0u, QuotaGetOriginsForHost("unknown.com"));
+}
+
+TEST_P(ServiceWorkerCacheQuotaClientTestP, QuotaDeleteOriginData) {
+ 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(Open(origin1_, "bar"));
+ EXPECT_TRUE(Open(origin2_, "baz"));
+
+ EXPECT_TRUE(QuotaDeleteOriginData(origin1_));
+
+ EXPECT_FALSE(Has(origin1_, "foo"));
+ EXPECT_FALSE(Has(origin1_, "bar"));
+ EXPECT_TRUE(Has(origin2_, "baz"));
+ EXPECT_TRUE(Open(origin1_, "foo"));
+}
+
+TEST_P(ServiceWorkerCacheQuotaClientTestP, QuotaDeleteEmptyOrigin) {
+ EXPECT_TRUE(QuotaDeleteOriginData(origin1_));
+}
+
+TEST_P(ServiceWorkerCacheQuotaClientTestP, QuotaDoesSupport) {
+ EXPECT_TRUE(QuotaDoesSupport(storage::kStorageTypeTemporary));
+ EXPECT_FALSE(QuotaDoesSupport(storage::kStorageTypePersistent));
+ EXPECT_FALSE(QuotaDoesSupport(storage::kStorageTypeSyncable));
+ EXPECT_FALSE(QuotaDoesSupport(storage::kStorageTypeQuotaNotManaged));
+ EXPECT_FALSE(QuotaDoesSupport(storage::kStorageTypeUnknown));
+}
+
+INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheStorageManagerTests,
+ ServiceWorkerCacheStorageManagerTestP,
+ ::testing::Values(false, true));
+
+INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheQuotaClientTests,
+ ServiceWorkerCacheQuotaClientTestP,
+ ::testing::Values(false, true));
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_cache_unittest.cc b/chromium/content/browser/service_worker/service_worker_cache_unittest.cc
new file mode 100644
index 00000000000..0d1c8fad3a5
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_cache_unittest.cc
@@ -0,0 +1,796 @@
+// 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/service_worker/service_worker_cache.h"
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/run_loop.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
+#include "content/browser/fileapi/mock_url_request_delegate.h"
+#include "content/browser/quota/mock_quota_manager_proxy.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/browser_thread.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"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_url_request_job_factory.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/common/blob/blob_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+const char kTestData[] = "Hello World";
+
+// Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
+// the memory.
+storage::BlobProtocolHandler* CreateMockBlobProtocolHandler(
+ storage::BlobStorageContext* blob_storage_context) {
+ // The FileSystemContext and MessageLoopProxy are not actually used but a
+ // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor.
+ return new storage::BlobProtocolHandler(
+ blob_storage_context, NULL, base::MessageLoopProxy::current().get());
+}
+
+} // namespace
+
+// A ServiceWorkerCache that can optionally pause during backend creation.
+class TestServiceWorkerCache : public ServiceWorkerCache {
+ public:
+ TestServiceWorkerCache(
+ const GURL& origin,
+ const base::FilePath& path,
+ net::URLRequestContext* request_context,
+ const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
+ base::WeakPtr<storage::BlobStorageContext> blob_context)
+ : ServiceWorkerCache(origin,
+ path,
+ request_context,
+ quota_manager_proxy,
+ blob_context),
+ pause_backend_creation_(false) {}
+
+ virtual void CreateBackend(const ErrorCallback& callback) override {
+ backend_creation_callback_ = callback;
+ if (pause_backend_creation_)
+ return;
+ ContinueCreateBackend();
+ }
+
+ void ContinueCreateBackend() {
+ ServiceWorkerCache::CreateBackend(backend_creation_callback_);
+ }
+
+ void set_pause_backend_creation(bool pause) {
+ pause_backend_creation_ = pause;
+ }
+
+ private:
+ virtual ~TestServiceWorkerCache() override {}
+
+ bool pause_backend_creation_;
+ ErrorCallback backend_creation_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestServiceWorkerCache);
+};
+
+class ServiceWorkerCacheTest : public testing::Test {
+ public:
+ ServiceWorkerCacheTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ callback_error_(ServiceWorkerCache::ErrorTypeOK),
+ callback_closed_(false) {}
+
+ void SetUp() override {
+ ChromeBlobStorageContext* blob_storage_context =
+ ChromeBlobStorageContext::GetFor(&browser_context_);
+ // Wait for chrome_blob_storage_context to finish initializing.
+ base::RunLoop().RunUntilIdle();
+ blob_storage_context_ = blob_storage_context->context();
+
+ quota_manager_proxy_ = new MockQuotaManagerProxy(
+ nullptr, base::MessageLoopProxy::current().get());
+
+ url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl);
+ url_request_job_factory_->SetProtocolHandler(
+ "blob", CreateMockBlobProtocolHandler(blob_storage_context->context()));
+
+ net::URLRequestContext* url_request_context =
+ browser_context_.GetRequestContext()->GetURLRequestContext();
+
+ url_request_context->set_job_factory(url_request_job_factory_.get());
+
+ 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 TestServiceWorkerCache(
+ GURL("http://example.com"), path, url_request_context,
+ quota_manager_proxy_, blob_storage_context->context()->AsWeakPtr()));
+ }
+
+ void TearDown() override {
+ quota_manager_proxy_->SimulateQuotaManagerDestroyed();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void CreateRequests(ChromeBlobStorageContext* blob_storage_context) {
+ ServiceWorkerHeaderMap headers;
+ headers.insert(std::make_pair("a", "a"));
+ headers.insert(std::make_pair("b", "b"));
+ body_request_ = ServiceWorkerFetchRequest(
+ GURL("http://example.com/body.html"), "GET", headers, GURL(""), false);
+ no_body_request_ =
+ ServiceWorkerFetchRequest(GURL("http://example.com/no_body.html"),
+ "GET",
+ headers,
+ GURL(""),
+ false);
+
+ std::string expected_response;
+ for (int i = 0; i < 100; ++i)
+ expected_blob_data_ += kTestData;
+
+ scoped_refptr<storage::BlobData> blob_data(
+ new storage::BlobData("blob-id:myblob"));
+ blob_data->AppendData(expected_blob_data_);
+
+ blob_handle_ =
+ blob_storage_context->context()->AddFinishedBlob(blob_data.get());
+
+ body_response_ =
+ ServiceWorkerResponse(GURL("http://example.com/body.html"),
+ 200,
+ "OK",
+ blink::WebServiceWorkerResponseTypeDefault,
+ headers,
+ blob_handle_->uuid(),
+ expected_blob_data_.size());
+
+ no_body_response_ =
+ ServiceWorkerResponse(GURL("http://example.com/no_body.html"),
+ 200,
+ "OK",
+ blink::WebServiceWorkerResponseTypeDefault,
+ headers,
+ "",
+ 0);
+ }
+
+ scoped_ptr<ServiceWorkerFetchRequest> CopyFetchRequest(
+ const ServiceWorkerFetchRequest& request) {
+ return make_scoped_ptr(new ServiceWorkerFetchRequest(request.url,
+ request.method,
+ request.headers,
+ request.referrer,
+ request.is_reload));
+ }
+
+ scoped_ptr<ServiceWorkerResponse> CopyFetchResponse(
+ const ServiceWorkerResponse& response) {
+ scoped_ptr<ServiceWorkerResponse> sw_response(
+ new ServiceWorkerResponse(response.url,
+ response.status_code,
+ response.status_text,
+ response.response_type,
+ response.headers,
+ response.blob_uuid,
+ response.blob_size));
+ return sw_response.Pass();
+ }
+
+ bool Put(const ServiceWorkerFetchRequest& request,
+ const ServiceWorkerResponse& response) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->Put(CopyFetchRequest(request),
+ CopyFetchResponse(response),
+ base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
+ // once the cache uses a passed in MessageLoopProxy instead of the CACHE
+ // thread.
+ loop->Run();
+
+ return callback_error_ == ServiceWorkerCache::ErrorTypeOK;
+ }
+
+ bool Match(const ServiceWorkerFetchRequest& request) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->Match(CopyFetchRequest(request),
+ base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == ServiceWorkerCache::ErrorTypeOK;
+ }
+
+ bool Delete(const ServiceWorkerFetchRequest& request) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->Delete(CopyFetchRequest(request),
+ base::Bind(&ServiceWorkerCacheTest::ErrorTypeCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == ServiceWorkerCache::ErrorTypeOK;
+ }
+
+ bool Keys() {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->Keys(base::Bind(&ServiceWorkerCacheTest::RequestsCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+
+ return callback_error_ == ServiceWorkerCache::ErrorTypeOK;
+ }
+
+ bool Close() {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+
+ cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ loop->Run();
+ return callback_closed_;
+ }
+
+ void RequestsCallback(base::RunLoop* run_loop,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerCache::Requests> requests) {
+ callback_error_ = error;
+ callback_strings_.clear();
+ if (requests) {
+ for (size_t i = 0u; i < requests->size(); ++i)
+ callback_strings_.push_back(requests->at(i).url.spec());
+ }
+ if (run_loop)
+ run_loop->Quit();
+ }
+
+ void ErrorTypeCallback(base::RunLoop* run_loop,
+ ServiceWorkerCache::ErrorType error) {
+ callback_error_ = error;
+ if (run_loop)
+ run_loop->Quit();
+ }
+
+ void ResponseAndErrorCallback(
+ base::RunLoop* run_loop,
+ ServiceWorkerCache::ErrorType error,
+ scoped_ptr<ServiceWorkerResponse> response,
+ scoped_ptr<storage::BlobDataHandle> body_handle) {
+ callback_error_ = error;
+ callback_response_ = response.Pass();
+ callback_response_data_.reset();
+ if (error == ServiceWorkerCache::ErrorTypeOK &&
+ !callback_response_->blob_uuid.empty()) {
+ callback_response_data_ = body_handle.Pass();
+ }
+
+ if (run_loop)
+ run_loop->Quit();
+ }
+
+ void CloseCallback(base::RunLoop* run_loop) {
+ EXPECT_FALSE(callback_closed_);
+ callback_closed_ = true;
+ if (run_loop)
+ run_loop->Quit();
+ }
+
+ void CopyBody(storage::BlobDataHandle* blob_handle, std::string* output) {
+ storage::BlobData* data = blob_handle->data();
+ std::vector<storage::BlobData::Item> items = data->items();
+ for (size_t i = 0, max = items.size(); i < max; ++i)
+ output->append(items[i].bytes(), items[i].length());
+ }
+
+ bool VerifyKeys(const std::vector<std::string>& expected_keys) {
+ if (expected_keys.size() != callback_strings_.size())
+ return false;
+
+ std::set<std::string> found_set;
+ for (int i = 0, max = callback_strings_.size(); i < max; ++i)
+ found_set.insert(callback_strings_[i]);
+
+ for (int i = 0, max = expected_keys.size(); i < max; ++i) {
+ if (found_set.find(expected_keys[i]) == found_set.end())
+ return false;
+ }
+ return true;
+ }
+
+ bool TestResponseType(blink::WebServiceWorkerResponseType response_type) {
+ body_response_.response_type = response_type;
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+ EXPECT_TRUE(Delete(body_request_));
+ return response_type == callback_response_->response_type;
+ }
+
+ void VerifyAllOpsFail() {
+ EXPECT_FALSE(Put(no_body_request_, no_body_response_));
+ EXPECT_FALSE(Match(no_body_request_));
+ EXPECT_FALSE(Delete(body_request_));
+ EXPECT_FALSE(Keys());
+ }
+
+ virtual bool MemoryOnly() { return false; }
+
+ protected:
+ TestBrowserContext browser_context_;
+ TestBrowserThreadBundle browser_thread_bundle_;
+ scoped_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_;
+ scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
+ storage::BlobStorageContext* blob_storage_context_;
+
+ base::ScopedTempDir temp_dir_;
+ scoped_refptr<TestServiceWorkerCache> cache_;
+
+ ServiceWorkerFetchRequest body_request_;
+ ServiceWorkerResponse body_response_;
+ ServiceWorkerFetchRequest no_body_request_;
+ ServiceWorkerResponse no_body_response_;
+ scoped_ptr<storage::BlobDataHandle> blob_handle_;
+ std::string expected_blob_data_;
+
+ ServiceWorkerCache::ErrorType callback_error_;
+ scoped_ptr<ServiceWorkerResponse> callback_response_;
+ scoped_ptr<storage::BlobDataHandle> callback_response_data_;
+ std::vector<std::string> callback_strings_;
+ bool callback_closed_;
+};
+
+class ServiceWorkerCacheTestP : public ServiceWorkerCacheTest,
+ public testing::WithParamInterface<bool> {
+ bool MemoryOnly() override { return !GetParam(); }
+};
+
+class ServiceWorkerCacheMemoryOnlyTest
+ : public ServiceWorkerCacheTest,
+ public testing::WithParamInterface<bool> {
+ bool MemoryOnly() override { return true; }
+};
+
+TEST_P(ServiceWorkerCacheTestP, PutNoBody) {
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(callback_response_);
+ EXPECT_STREQ(no_body_response_.url.spec().c_str(),
+ callback_response_->url.spec().c_str());
+ EXPECT_FALSE(callback_response_data_);
+ EXPECT_STREQ("", callback_response_->blob_uuid.c_str());
+ EXPECT_EQ(0u, callback_response_->blob_size);
+}
+
+TEST_P(ServiceWorkerCacheTestP, PutBody) {
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(callback_response_);
+ EXPECT_STREQ(body_response_.url.spec().c_str(),
+ callback_response_->url.spec().c_str());
+ EXPECT_TRUE(callback_response_data_);
+ EXPECT_STRNE("", callback_response_->blob_uuid.c_str());
+ EXPECT_EQ(expected_blob_data_.size(), callback_response_->blob_size);
+
+ std::string response_body;
+ CopyBody(callback_response_data_.get(), &response_body);
+ EXPECT_STREQ(expected_blob_data_.c_str(), response_body.c_str());
+}
+
+TEST_P(ServiceWorkerCacheTestP, ResponseURLDiffersFromRequestURL) {
+ no_body_response_.url = GURL("http://example.com/foobar");
+ EXPECT_STRNE("http://example.com/foobar",
+ no_body_request_.url.spec().c_str());
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Match(no_body_request_));
+ EXPECT_STREQ("http://example.com/foobar",
+ callback_response_->url.spec().c_str());
+}
+
+TEST_P(ServiceWorkerCacheTestP, ResponseURLEmpty) {
+ no_body_response_.url = GURL();
+ EXPECT_STRNE("", no_body_request_.url.spec().c_str());
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Match(no_body_request_));
+ EXPECT_STREQ("", callback_response_->url.spec().c_str());
+}
+
+TEST_F(ServiceWorkerCacheTest, PutBodyDropBlobRef) {
+ scoped_ptr<base::RunLoop> loop(new base::RunLoop());
+ cache_->Put(CopyFetchRequest(body_request_),
+ CopyFetchResponse(body_response_),
+ base::Bind(&ServiceWorkerCacheTestP::ResponseAndErrorCallback,
+ base::Unretained(this),
+ base::Unretained(loop.get())));
+ // The handle should be held by the cache now so the deref here should be
+ // okay.
+ blob_handle_.reset();
+ loop->Run();
+
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_);
+}
+
+TEST_P(ServiceWorkerCacheTestP, PutReplace) {
+ EXPECT_TRUE(Put(body_request_, no_body_response_));
+ EXPECT_TRUE(Match(body_request_));
+ EXPECT_FALSE(callback_response_data_);
+
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+ EXPECT_TRUE(callback_response_data_);
+
+ EXPECT_TRUE(Put(body_request_, no_body_response_));
+ EXPECT_TRUE(Match(body_request_));
+ EXPECT_FALSE(callback_response_data_);
+}
+
+TEST_P(ServiceWorkerCacheTestP, MatchNoBody) {
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Match(no_body_request_));
+ EXPECT_EQ(200, callback_response_->status_code);
+ EXPECT_STREQ("OK", callback_response_->status_text.c_str());
+ EXPECT_STREQ("http://example.com/no_body.html",
+ callback_response_->url.spec().c_str());
+ EXPECT_STREQ("", callback_response_->blob_uuid.c_str());
+ EXPECT_EQ(0u, callback_response_->blob_size);
+}
+
+TEST_P(ServiceWorkerCacheTestP, MatchBody) {
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+ EXPECT_EQ(200, callback_response_->status_code);
+ EXPECT_STREQ("OK", callback_response_->status_text.c_str());
+ EXPECT_STREQ("http://example.com/body.html",
+ callback_response_->url.spec().c_str());
+ EXPECT_STRNE("", callback_response_->blob_uuid.c_str());
+ EXPECT_EQ(expected_blob_data_.size(), callback_response_->blob_size);
+
+ std::string response_body;
+ CopyBody(callback_response_data_.get(), &response_body);
+ EXPECT_STREQ(expected_blob_data_.c_str(), response_body.c_str());
+}
+
+TEST_P(ServiceWorkerCacheTestP, Vary) {
+ body_request_.headers["vary_foo"] = "foo";
+ body_response_.headers["vary"] = "vary_foo";
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+
+ body_request_.headers["vary_foo"] = "bar";
+ EXPECT_FALSE(Match(body_request_));
+
+ body_request_.headers.erase("vary_foo");
+ EXPECT_FALSE(Match(body_request_));
+}
+
+TEST_P(ServiceWorkerCacheTestP, EmptyVary) {
+ body_response_.headers["vary"] = "";
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+
+ body_request_.headers["zoo"] = "zoo";
+ EXPECT_TRUE(Match(body_request_));
+}
+
+TEST_P(ServiceWorkerCacheTestP, NoVaryButDiffHeaders) {
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+
+ body_request_.headers["zoo"] = "zoo";
+ EXPECT_TRUE(Match(body_request_));
+}
+
+TEST_P(ServiceWorkerCacheTestP, VaryMultiple) {
+ body_request_.headers["vary_foo"] = "foo";
+ body_request_.headers["vary_bar"] = "bar";
+ body_response_.headers["vary"] = " vary_foo , vary_bar";
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+
+ body_request_.headers["vary_bar"] = "foo";
+ EXPECT_FALSE(Match(body_request_));
+
+ body_request_.headers.erase("vary_bar");
+ EXPECT_FALSE(Match(body_request_));
+}
+
+TEST_P(ServiceWorkerCacheTestP, VaryNewHeader) {
+ body_request_.headers["vary_foo"] = "foo";
+ body_response_.headers["vary"] = " vary_foo, vary_bar";
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+
+ body_request_.headers["vary_bar"] = "bar";
+ EXPECT_FALSE(Match(body_request_));
+}
+
+TEST_P(ServiceWorkerCacheTestP, VaryStar) {
+ body_response_.headers["vary"] = "*";
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_FALSE(Match(body_request_));
+}
+
+TEST_P(ServiceWorkerCacheTestP, EmptyKeys) {
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(0u, callback_strings_.size());
+}
+
+TEST_P(ServiceWorkerCacheTestP, TwoKeys) {
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(2u, 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());
+ EXPECT_TRUE(VerifyKeys(expected_keys));
+}
+
+TEST_P(ServiceWorkerCacheTestP, TwoKeysThenOne) {
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(2u, 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());
+ EXPECT_TRUE(VerifyKeys(expected_keys));
+
+ EXPECT_TRUE(Delete(body_request_));
+ EXPECT_TRUE(Keys());
+ EXPECT_EQ(1u, callback_strings_.size());
+ std::vector<std::string> expected_key;
+ expected_key.push_back(no_body_request_.url.spec());
+ EXPECT_TRUE(VerifyKeys(expected_key));
+}
+
+TEST_P(ServiceWorkerCacheTestP, DeleteNoBody) {
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Match(no_body_request_));
+ EXPECT_TRUE(Delete(no_body_request_));
+ EXPECT_FALSE(Match(no_body_request_));
+ EXPECT_FALSE(Delete(no_body_request_));
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Match(no_body_request_));
+ EXPECT_TRUE(Delete(no_body_request_));
+}
+
+TEST_P(ServiceWorkerCacheTestP, DeleteBody) {
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+ EXPECT_TRUE(Delete(body_request_));
+ EXPECT_FALSE(Match(body_request_));
+ EXPECT_FALSE(Delete(body_request_));
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Match(body_request_));
+ EXPECT_TRUE(Delete(body_request_));
+}
+
+TEST_P(ServiceWorkerCacheTestP, QuickStressNoBody) {
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_FALSE(Match(no_body_request_));
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_TRUE(Match(no_body_request_));
+ EXPECT_TRUE(Delete(no_body_request_));
+ }
+}
+
+TEST_P(ServiceWorkerCacheTestP, QuickStressBody) {
+ for (int i = 0; i < 100; ++i) {
+ ASSERT_FALSE(Match(body_request_));
+ ASSERT_TRUE(Put(body_request_, body_response_));
+ ASSERT_TRUE(Match(body_request_));
+ ASSERT_TRUE(Delete(body_request_));
+ }
+}
+
+TEST_P(ServiceWorkerCacheTestP, PutResponseType) {
+ EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeBasic));
+ EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeCORS));
+ EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeDefault));
+ EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeError));
+ EXPECT_TRUE(TestResponseType(blink::WebServiceWorkerResponseTypeOpaque));
+}
+
+TEST_F(ServiceWorkerCacheTest, CaselessServiceWorkerResponseHeaders) {
+ // ServiceWorkerCache depends on ServiceWorkerResponse having caseless
+ // headers so that it can quickly lookup vary headers.
+ ServiceWorkerResponse response(GURL("http://www.example.com"),
+ 200,
+ "OK",
+ blink::WebServiceWorkerResponseTypeDefault,
+ ServiceWorkerHeaderMap(),
+ "",
+ 0);
+ response.headers["content-type"] = "foo";
+ response.headers["Content-Type"] = "bar";
+ EXPECT_EQ("bar", response.headers["content-type"]);
+}
+
+TEST_F(ServiceWorkerCacheTest, CaselessServiceWorkerFetchRequestHeaders) {
+ // ServiceWorkerCache depends on ServiceWorkerFetchRequest having caseless
+ // headers so that it can quickly lookup vary headers.
+ ServiceWorkerFetchRequest request(GURL("http://www.example.com"),
+ "GET",
+ ServiceWorkerHeaderMap(),
+ GURL(""),
+ false);
+ request.headers["content-type"] = "foo";
+ request.headers["Content-Type"] = "bar";
+ EXPECT_EQ("bar", request.headers["content-type"]);
+}
+
+TEST_P(ServiceWorkerCacheTestP, QuotaManagerModified) {
+ EXPECT_EQ(0, quota_manager_proxy_->notify_storage_modified_count());
+
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_EQ(1, quota_manager_proxy_->notify_storage_modified_count());
+ EXPECT_LT(0, quota_manager_proxy_->last_notified_delta());
+ int64 sum_delta = quota_manager_proxy_->last_notified_delta();
+
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ 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_));
+ EXPECT_EQ(3, quota_manager_proxy_->notify_storage_modified_count());
+ sum_delta += quota_manager_proxy_->last_notified_delta();
+
+ EXPECT_TRUE(Delete(no_body_request_));
+ 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(ServiceWorkerCacheMemoryOnlyTest, MemoryBackedSize) {
+ EXPECT_EQ(0, cache_->MemoryBackedSize());
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_LT(0, cache_->MemoryBackedSize());
+ int64 no_body_size = cache_->MemoryBackedSize();
+
+ EXPECT_TRUE(Delete(no_body_request_));
+ EXPECT_EQ(0, cache_->MemoryBackedSize());
+
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_LT(no_body_size, cache_->MemoryBackedSize());
+
+ EXPECT_TRUE(Delete(body_request_));
+ EXPECT_EQ(0, cache_->MemoryBackedSize());
+}
+
+TEST_F(ServiceWorkerCacheTest, MemoryBackedSizePersistent) {
+ EXPECT_EQ(0, cache_->MemoryBackedSize());
+ EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+ EXPECT_EQ(0, cache_->MemoryBackedSize());
+}
+
+TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackendNeverCreated) {
+ cache_->set_pause_backend_creation(
+ true); // Will hang the test if a backend is created.
+ EXPECT_TRUE(Close());
+ VerifyAllOpsFail();
+}
+
+TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackend) {
+ // Create the backend and put something in it.
+ EXPECT_TRUE(Put(body_request_, body_response_));
+ EXPECT_TRUE(Close());
+ VerifyAllOpsFail();
+}
+
+TEST_F(ServiceWorkerCacheTest, ClosedDuringPut) {
+ // Even though Close is called in the middle of a Put operation (during
+ // backend creation), the put operation should still finish.
+ cache_->set_pause_backend_creation(true);
+ scoped_ptr<base::RunLoop> close_loop(new base::RunLoop());
+ cache_->Put(CopyFetchRequest(body_request_),
+ CopyFetchResponse(body_response_),
+ base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback,
+ base::Unretained(this), nullptr));
+ cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback,
+ base::Unretained(this), close_loop.get()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(callback_response_);
+ EXPECT_FALSE(callback_closed_);
+
+ cache_->ContinueCreateBackend();
+
+ close_loop->Run();
+ EXPECT_TRUE(callback_response_);
+ EXPECT_TRUE(callback_closed_);
+
+ VerifyAllOpsFail();
+}
+
+TEST_F(ServiceWorkerCacheTest, ClosedDuringMatch) {
+ // Even though Close is called in the middle of a Match operation (during
+ // backend creation), the match operation should still finish.
+ cache_->set_pause_backend_creation(true);
+ scoped_ptr<base::RunLoop> close_loop(new base::RunLoop());
+ cache_->Match(CopyFetchRequest(body_request_),
+ base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback,
+ base::Unretained(this), nullptr));
+ cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback,
+ base::Unretained(this), close_loop.get()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_);
+ EXPECT_FALSE(callback_closed_);
+
+ cache_->ContinueCreateBackend();
+
+ close_loop->Run();
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_);
+ EXPECT_TRUE(callback_closed_);
+
+ VerifyAllOpsFail();
+}
+
+TEST_F(ServiceWorkerCacheTest, ClosedDuringDelete) {
+ // Even though Close is called in the middle of a Delete operation (during
+ // backend creation), the delete operation should still finish.
+ cache_->set_pause_backend_creation(true);
+ scoped_ptr<base::RunLoop> close_loop(new base::RunLoop());
+ cache_->Delete(CopyFetchRequest(body_request_),
+ base::Bind(&ServiceWorkerCacheTest::ErrorTypeCallback,
+ base::Unretained(this), nullptr));
+ cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback,
+ base::Unretained(this), close_loop.get()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_);
+ EXPECT_FALSE(callback_closed_);
+
+ cache_->ContinueCreateBackend();
+
+ close_loop->Run();
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_);
+ EXPECT_TRUE(callback_closed_);
+
+ VerifyAllOpsFail();
+}
+
+TEST_F(ServiceWorkerCacheTest, ClosedDuringKeys) {
+ // Even though Close is called in the middle of a Keys operation (during
+ // backend creation), the keys operation should still finish.
+ cache_->set_pause_backend_creation(true);
+ scoped_ptr<base::RunLoop> close_loop(new base::RunLoop());
+ callback_error_ = ServiceWorkerCache::ErrorTypeNotFound;
+ cache_->Keys(base::Bind(&ServiceWorkerCacheTest::RequestsCallback,
+ base::Unretained(this), nullptr));
+ cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback,
+ base::Unretained(this), close_loop.get()));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_);
+ EXPECT_FALSE(callback_closed_);
+
+ cache_->ContinueCreateBackend();
+
+ close_loop->Run();
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_);
+ EXPECT_TRUE(callback_closed_);
+
+ VerifyAllOpsFail();
+}
+
+INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheTest,
+ ServiceWorkerCacheTestP,
+ ::testing::Values(false, true));
+
+} // namespace content
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 cdc67460bcc..2272c95851b 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_core.cc
@@ -4,12 +4,17 @@
#include "content/browser/service_worker/service_worker_context_core.h"
+#include "base/barrier_closure.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/files/file_path.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
+#include "content/browser/service_worker/service_worker_cache_storage_manager.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_database_task_manager.h"
#include "content/browser/service_worker/service_worker_info.h"
#include "content/browser/service_worker/service_worker_job_coordinator.h"
#include "content/browser/service_worker/service_worker_process_manager.h"
@@ -18,9 +23,33 @@
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/public/browser/browser_thread.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
#include "url/gurl.h"
namespace content {
+namespace {
+void SuccessCollectorCallback(const base::Closure& done_closure,
+ bool* overall_success,
+ ServiceWorkerStatusCode status) {
+ if (status != ServiceWorkerStatusCode::SERVICE_WORKER_OK) {
+ *overall_success = false;
+ }
+ done_closure.Run();
+}
+
+void SuccessReportingCallback(
+ const bool* success,
+ const ServiceWorkerContextCore::UnregistrationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ bool result = *success;
+ callback.Run(result ? ServiceWorkerStatusCode::SERVICE_WORKER_OK
+ : ServiceWorkerStatusCode::SERVICE_WORKER_ERROR_FAILED);
+}
+} // namespace
+
+const base::FilePath::CharType
+ ServiceWorkerContextCore::kServiceWorkerDirectory[] =
+ FILE_PATH_LITERAL("Service Worker");
ServiceWorkerContextCore::ProviderHostIterator::~ProviderHostIterator() {}
@@ -33,7 +62,7 @@ ServiceWorkerContextCore::ProviderHostIterator::GetProviderHost() {
void ServiceWorkerContextCore::ProviderHostIterator::Advance() {
DCHECK(!IsAtEnd());
DCHECK(!provider_host_iterator_->IsAtEnd());
- DCHECK(!provider_iterator_->IsAtEnd());
+ DCHECK(!process_iterator_->IsAtEnd());
// Advance the inner iterator. If an element is reached, we're done.
provider_host_iterator_->Advance();
@@ -42,10 +71,10 @@ void ServiceWorkerContextCore::ProviderHostIterator::Advance() {
// Advance the outer iterator until an element is reached, or end is hit.
while (true) {
- provider_iterator_->Advance();
- if (provider_iterator_->IsAtEnd())
+ process_iterator_->Advance();
+ if (process_iterator_->IsAtEnd())
return;
- ProviderMap* provider_map = provider_iterator_->GetCurrentValue();
+ ProviderMap* provider_map = process_iterator_->GetCurrentValue();
provider_host_iterator_.reset(new ProviderMap::iterator(provider_map));
if (!provider_host_iterator_->IsAtEnd())
return;
@@ -53,7 +82,7 @@ void ServiceWorkerContextCore::ProviderHostIterator::Advance() {
}
bool ServiceWorkerContextCore::ProviderHostIterator::IsAtEnd() {
- return provider_iterator_->IsAtEnd() &&
+ return process_iterator_->IsAtEnd() &&
(!provider_host_iterator_ || provider_host_iterator_->IsAtEnd());
}
@@ -65,37 +94,65 @@ ServiceWorkerContextCore::ProviderHostIterator::ProviderHostIterator(
}
void ServiceWorkerContextCore::ProviderHostIterator::Initialize() {
- provider_iterator_.reset(new ProcessToProviderMap::iterator(map_));
+ process_iterator_.reset(new ProcessToProviderMap::iterator(map_));
// Advance to the first element.
- while (!provider_iterator_->IsAtEnd()) {
- ProviderMap* provider_map = provider_iterator_->GetCurrentValue();
+ while (!process_iterator_->IsAtEnd()) {
+ ProviderMap* provider_map = process_iterator_->GetCurrentValue();
provider_host_iterator_.reset(new ProviderMap::iterator(provider_map));
if (!provider_host_iterator_->IsAtEnd())
return;
- provider_iterator_->Advance();
+ process_iterator_->Advance();
}
}
ServiceWorkerContextCore::ServiceWorkerContextCore(
const base::FilePath& path,
- base::SequencedTaskRunner* database_task_runner,
- base::MessageLoopProxy* disk_cache_thread,
- quota::QuotaManagerProxy* quota_manager_proxy,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy,
ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list,
ServiceWorkerContextWrapper* wrapper)
: weak_factory_(this),
wrapper_(wrapper),
- storage_(new ServiceWorkerStorage(path,
- AsWeakPtr(),
- database_task_runner,
- disk_cache_thread,
- quota_manager_proxy)),
- embedded_worker_registry_(new EmbeddedWorkerRegistry(AsWeakPtr())),
+ providers_(new ProcessToProviderMap),
+ storage_(ServiceWorkerStorage::Create(path,
+ AsWeakPtr(),
+ database_task_manager.Pass(),
+ disk_cache_thread,
+ quota_manager_proxy,
+ special_storage_policy)),
+ cache_manager_(ServiceWorkerCacheStorageManager::Create(
+ path,
+ cache_task_runner.get(),
+ make_scoped_refptr(quota_manager_proxy))),
+ embedded_worker_registry_(EmbeddedWorkerRegistry::Create(AsWeakPtr())),
job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())),
next_handle_id_(0),
+ next_registration_handle_id_(0),
observer_list_(observer_list) {
}
+ServiceWorkerContextCore::ServiceWorkerContextCore(
+ ServiceWorkerContextCore* old_context,
+ ServiceWorkerContextWrapper* wrapper)
+ : weak_factory_(this),
+ wrapper_(wrapper),
+ providers_(old_context->providers_.release()),
+ storage_(
+ ServiceWorkerStorage::Create(AsWeakPtr(), old_context->storage())),
+ cache_manager_(ServiceWorkerCacheStorageManager::Create(
+ old_context->cache_manager())),
+ embedded_worker_registry_(EmbeddedWorkerRegistry::Create(
+ AsWeakPtr(),
+ old_context->embedded_worker_registry())),
+ job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())),
+ next_handle_id_(old_context->next_handle_id_),
+ next_registration_handle_id_(old_context->next_registration_handle_id_),
+ observer_list_(old_context->observer_list_) {
+}
+
ServiceWorkerContextCore::~ServiceWorkerContextCore() {
for (VersionMap::iterator it = live_versions_.begin();
it != live_versions_.end();
@@ -119,7 +176,7 @@ void ServiceWorkerContextCore::AddProviderHost(
ProviderMap* map = GetProviderMapForProcess(host_ptr->process_id());
if (!map) {
map = new ProviderMap;
- providers_.AddWithID(map, host_ptr->process_id());
+ providers_->AddWithID(map, host_ptr->process_id());
}
map->AddWithID(host_ptr, host_ptr->provider_id());
}
@@ -133,30 +190,31 @@ void ServiceWorkerContextCore::RemoveProviderHost(
void ServiceWorkerContextCore::RemoveAllProviderHostsForProcess(
int process_id) {
- if (providers_.Lookup(process_id))
- providers_.Remove(process_id);
+ if (providers_->Lookup(process_id))
+ providers_->Remove(process_id);
}
scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator>
ServiceWorkerContextCore::GetProviderHostIterator() {
- return make_scoped_ptr(new ProviderHostIterator(&providers_));
+ return make_scoped_ptr(new ProviderHostIterator(providers_.get()));
}
void ServiceWorkerContextCore::RegisterServiceWorker(
const GURL& pattern,
const GURL& script_url,
- int source_process_id,
ServiceWorkerProviderHost* provider_host,
const RegistrationCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- // TODO(kinuko): Wire the provider_host so that we can tell which document
- // is calling .register.
+ if (storage()->IsDisabled()) {
+ callback.Run(SERVICE_WORKER_ERROR_ABORT,
+ kInvalidServiceWorkerRegistrationId);
+ return;
+ }
job_coordinator_->Register(
pattern,
script_url,
- source_process_id,
+ provider_host,
base::Bind(&ServiceWorkerContextCore::RegistrationComplete,
AsWeakPtr(),
pattern,
@@ -167,6 +225,10 @@ 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,
@@ -176,26 +238,67 @@ void ServiceWorkerContextCore::UnregisterServiceWorker(
callback));
}
+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()->GetAllRegistrations(base::Bind(
+ &ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin,
+ AsWeakPtr(),
+ callback,
+ origin));
+}
+
+void ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin(
+ const UnregistrationCallback& result,
+ const GURL& origin,
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+ std::set<GURL> scopes;
+ for (const auto& registration_info : registrations) {
+ if (origin == registration_info.pattern.GetOrigin()) {
+ scopes.insert(registration_info.pattern);
+ }
+ }
+ bool* overall_success = new bool(true);
+ base::Closure barrier = base::BarrierClosure(
+ scopes.size(),
+ base::Bind(
+ &SuccessReportingCallback, base::Owned(overall_success), result));
+
+ for (const GURL& scope : scopes) {
+ UnregisterServiceWorker(
+ scope, base::Bind(&SuccessCollectorCallback, barrier, overall_success));
+ }
+}
+
+void ServiceWorkerContextCore::UpdateServiceWorker(
+ ServiceWorkerRegistration* registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (storage()->IsDisabled())
+ return;
+ job_coordinator_->Update(registration);
+}
+
void ServiceWorkerContextCore::RegistrationComplete(
const GURL& pattern,
const ServiceWorkerContextCore::RegistrationCallback& callback,
ServiceWorkerStatusCode status,
- ServiceWorkerRegistration* registration,
- ServiceWorkerVersion* version) {
+ ServiceWorkerRegistration* registration) {
if (status != SERVICE_WORKER_OK) {
- DCHECK(!version);
- callback.Run(status,
- kInvalidServiceWorkerRegistrationId,
- kInvalidServiceWorkerVersionId);
+ DCHECK(!registration);
+ callback.Run(status, kInvalidServiceWorkerRegistrationId);
return;
}
- DCHECK(version);
- DCHECK_EQ(version->registration_id(), registration->id());
- callback.Run(status,
- registration->id(),
- version->version_id());
- if (observer_list_) {
+ DCHECK(registration);
+ callback.Run(status, registration->id());
+ if (observer_list_.get()) {
observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationStored,
pattern);
}
@@ -206,7 +309,7 @@ void ServiceWorkerContextCore::UnregistrationComplete(
const ServiceWorkerContextCore::UnregistrationCallback& callback,
ServiceWorkerStatusCode status) {
callback.Run(status);
- if (observer_list_) {
+ if (observer_list_.get()) {
observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationDeleted,
pattern);
}
@@ -272,8 +375,34 @@ int ServiceWorkerContextCore::GetNewServiceWorkerHandleId() {
return next_handle_id_++;
}
+int ServiceWorkerContextCore::GetNewRegistrationHandleId() {
+ return next_registration_handle_id_++;
+}
+
+void ServiceWorkerContextCore::ScheduleDeleteAndStartOver() const {
+ storage_->Disable();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&ServiceWorkerContextWrapper::DeleteAndStartOver, wrapper_));
+}
+
+void ServiceWorkerContextCore::DeleteAndStartOver(
+ const StatusCallback& callback) {
+ job_coordinator_->AbortAll();
+ storage_->DeleteAndStartOver(callback);
+}
+
+void ServiceWorkerContextCore::SetBlobParametersForCache(
+ net::URLRequestContext* request_context,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ cache_manager_->SetBlobParametersForCache(request_context,
+ blob_storage_context);
+}
+
void ServiceWorkerContextCore::OnWorkerStarted(ServiceWorkerVersion* version) {
- if (!observer_list_)
+ if (!observer_list_.get())
return;
observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStarted,
version->version_id(),
@@ -282,7 +411,7 @@ void ServiceWorkerContextCore::OnWorkerStarted(ServiceWorkerVersion* version) {
}
void ServiceWorkerContextCore::OnWorkerStopped(ServiceWorkerVersion* version) {
- if (!observer_list_)
+ if (!observer_list_.get())
return;
observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStopped,
version->version_id(),
@@ -292,7 +421,7 @@ void ServiceWorkerContextCore::OnWorkerStopped(ServiceWorkerVersion* version) {
void ServiceWorkerContextCore::OnVersionStateChanged(
ServiceWorkerVersion* version) {
- if (!observer_list_)
+ if (!observer_list_.get())
return;
observer_list_->Notify(&ServiceWorkerContextObserver::OnVersionStateChanged,
version->version_id());
@@ -304,7 +433,7 @@ void ServiceWorkerContextCore::OnErrorReported(
int line_number,
int column_number,
const GURL& source_url) {
- if (!observer_list_)
+ if (!observer_list_.get())
return;
observer_list_->Notify(
&ServiceWorkerContextObserver::OnErrorReported,
@@ -322,7 +451,7 @@ void ServiceWorkerContextCore::OnReportConsoleMessage(
const base::string16& message,
int line_number,
const GURL& source_url) {
- if (!observer_list_)
+ if (!observer_list_.get())
return;
observer_list_->Notify(
&ServiceWorkerContextObserver::OnReportConsoleMessage,
@@ -334,7 +463,9 @@ void ServiceWorkerContextCore::OnReportConsoleMessage(
}
ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() {
- return wrapper_->process_manager();
+ if (wrapper_)
+ return wrapper_->process_manager();
+ return NULL;
}
} // namespace content
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 b3f97ae28f3..63522ea3b39 100644
--- a/chromium/content/browser/service_worker/service_worker_context_core.h
+++ b/chromium/content/browser/service_worker/service_worker_context_core.h
@@ -25,19 +25,26 @@ class GURL;
namespace base {
class FilePath;
-class MessageLoopProxy;
class SequencedTaskRunner;
+class SingleThreadTaskRunner;
}
-namespace quota {
+namespace net {
+class URLRequestContext;
+}
+
+namespace storage {
class QuotaManagerProxy;
+class SpecialStoragePolicy;
}
namespace content {
class EmbeddedWorkerRegistry;
+class ServiceWorkerCacheStorageManager;
class ServiceWorkerContextObserver;
class ServiceWorkerContextWrapper;
+class ServiceWorkerDatabaseTaskManager;
class ServiceWorkerHandle;
class ServiceWorkerJobCoordinator;
class ServiceWorkerProviderHost;
@@ -50,16 +57,19 @@ class ServiceWorkerStorage;
// is the root of the containment hierarchy for service worker data
// associated with a particular partition.
class CONTENT_EXPORT ServiceWorkerContextCore
- : public ServiceWorkerVersion::Listener {
+ : NON_EXPORTED_BASE(public ServiceWorkerVersion::Listener) {
public:
+ typedef base::Callback<void(ServiceWorkerStatusCode status)> StatusCallback;
typedef base::Callback<void(ServiceWorkerStatusCode status,
- int64 registration_id,
- int64 version_id)> RegistrationCallback;
+ int64 registration_id)> RegistrationCallback;
typedef base::Callback<
void(ServiceWorkerStatusCode status)> UnregistrationCallback;
typedef IDMap<ServiceWorkerProviderHost, IDMapOwnPointer> ProviderMap;
typedef IDMap<ProviderMap, IDMapOwnPointer> ProcessToProviderMap;
+ // Directory for ServiceWorkerStorage and ServiceWorkerCacheManager.
+ static const base::FilePath::CharType kServiceWorkerDirectory[];
+
// Iterates over ServiceWorkerProviderHost objects in a ProcessToProviderMap.
class ProviderHostIterator {
public:
@@ -74,7 +84,7 @@ class CONTENT_EXPORT ServiceWorkerContextCore
void Initialize();
ProcessToProviderMap* map_;
- scoped_ptr<ProcessToProviderMap::iterator> provider_iterator_;
+ scoped_ptr<ProcessToProviderMap::iterator> process_iterator_;
scoped_ptr<ProviderMap::iterator> provider_host_iterator_;
DISALLOW_COPY_AND_ASSIGN(ProviderHostIterator);
@@ -88,30 +98,38 @@ class CONTENT_EXPORT ServiceWorkerContextCore
// be called on the thread which called AddObserver() of |observer_list|.
ServiceWorkerContextCore(
const base::FilePath& user_data_directory,
- base::SequencedTaskRunner* database_task_runner,
- base::MessageLoopProxy* disk_cache_thread,
- quota::QuotaManagerProxy* quota_manager_proxy,
+ const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner,
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_runner_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy,
ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list,
ServiceWorkerContextWrapper* wrapper);
- virtual ~ServiceWorkerContextCore();
+ ServiceWorkerContextCore(
+ ServiceWorkerContextCore* old_context,
+ ServiceWorkerContextWrapper* wrapper);
+ ~ServiceWorkerContextCore() override;
// ServiceWorkerVersion::Listener overrides.
- virtual void OnWorkerStarted(ServiceWorkerVersion* version) OVERRIDE;
- virtual void OnWorkerStopped(ServiceWorkerVersion* version) OVERRIDE;
- virtual void OnVersionStateChanged(ServiceWorkerVersion* version) OVERRIDE;
- virtual void OnErrorReported(ServiceWorkerVersion* version,
- const base::string16& error_message,
- int line_number,
- int column_number,
- const GURL& source_url) OVERRIDE;
- virtual void OnReportConsoleMessage(ServiceWorkerVersion* version,
- int source_identifier,
- int message_level,
- const base::string16& message,
- int line_number,
- const GURL& source_url) OVERRIDE;
+ void OnWorkerStarted(ServiceWorkerVersion* version) override;
+ void OnWorkerStopped(ServiceWorkerVersion* version) override;
+ void OnVersionStateChanged(ServiceWorkerVersion* version) override;
+ void OnErrorReported(ServiceWorkerVersion* version,
+ const base::string16& error_message,
+ int line_number,
+ int column_number,
+ const GURL& source_url) override;
+ void OnReportConsoleMessage(ServiceWorkerVersion* version,
+ int source_identifier,
+ int message_level,
+ const base::string16& message,
+ int line_number,
+ const GURL& source_url) override;
ServiceWorkerStorage* storage() { return storage_.get(); }
+ ServiceWorkerCacheStorageManager* cache_manager() {
+ return cache_manager_.get();
+ }
ServiceWorkerProcessManager* process_manager();
EmbeddedWorkerRegistry* embedded_worker_registry() {
return embedded_worker_registry_.get();
@@ -127,20 +145,21 @@ class CONTENT_EXPORT ServiceWorkerContextCore
void RemoveAllProviderHostsForProcess(int process_id);
scoped_ptr<ProviderHostIterator> GetProviderHostIterator();
- // The callback will be called on the IO thread.
// A child process of |source_process_id| may be used to run the created
// worker for initial installation.
- // Non-null |provider_host| must be given if this is called from a document,
- // whose process_id() must match with |source_process_id|.
+ // Non-null |provider_host| must be given if this is called from a document.
void RegisterServiceWorker(const GURL& pattern,
const GURL& script_url,
- int source_process_id,
ServiceWorkerProviderHost* provider_host,
const RegistrationCallback& callback);
-
- // The callback will be called on the IO thread.
void UnregisterServiceWorker(const GURL& pattern,
const UnregistrationCallback& callback);
+ // Callback is called issued after all unregistrations occur. The Status
+ // is populated as SERVICE_WORKER_OK if all succeed, or SERVICE_WORKER_FAILED
+ // if any did not succeed.
+ void UnregisterServiceWorkers(const GURL& origin,
+ const UnregistrationCallback& callback);
+ void UpdateServiceWorker(ServiceWorkerRegistration* registration);
// This class maintains collections of live instances, this class
// does not own these object or influence their lifetime.
@@ -154,8 +173,19 @@ class CONTENT_EXPORT ServiceWorkerContextCore
std::vector<ServiceWorkerRegistrationInfo> GetAllLiveRegistrationInfo();
std::vector<ServiceWorkerVersionInfo> GetAllLiveVersionInfo();
- // Returns new context-local unique ID for ServiceWorkerHandle.
+ // Returns new context-local unique ID.
int GetNewServiceWorkerHandleId();
+ int GetNewRegistrationHandleId();
+
+ void ScheduleDeleteAndStartOver() const;
+
+ // Deletes all files on disk and restarts the system. This leaves the system
+ // in a disabled state until it's done.
+ void DeleteAndStartOver(const StatusCallback& callback);
+
+ void SetBlobParametersForCache(
+ net::URLRequestContext* request_context,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context);
base::WeakPtr<ServiceWorkerContextCore> AsWeakPtr() {
return weak_factory_.GetWeakPtr();
@@ -166,31 +196,37 @@ class CONTENT_EXPORT ServiceWorkerContextCore
typedef std::map<int64, ServiceWorkerVersion*> VersionMap;
ProviderMap* GetProviderMapForProcess(int process_id) {
- return providers_.Lookup(process_id);
+ return providers_->Lookup(process_id);
}
void RegistrationComplete(const GURL& pattern,
const RegistrationCallback& callback,
ServiceWorkerStatusCode status,
- ServiceWorkerRegistration* registration,
- ServiceWorkerVersion* version);
+ ServiceWorkerRegistration* registration);
void UnregistrationComplete(const GURL& pattern,
const UnregistrationCallback& callback,
ServiceWorkerStatusCode status);
+ void DidGetAllRegistrationsForUnregisterForOrigin(
+ const UnregistrationCallback& result,
+ const GURL& origin,
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations);
+
base::WeakPtrFactory<ServiceWorkerContextCore> weak_factory_;
// It's safe to store a raw pointer instead of a scoped_refptr to |wrapper_|
// because the Wrapper::Shutdown call that hops threads to destroy |this| uses
// Bind() to hold a reference to |wrapper_| until |this| is fully destroyed.
ServiceWorkerContextWrapper* wrapper_;
- ProcessToProviderMap providers_;
+ scoped_ptr<ProcessToProviderMap> providers_;
scoped_ptr<ServiceWorkerStorage> storage_;
+ scoped_ptr<ServiceWorkerCacheStorageManager> cache_manager_;
scoped_refptr<EmbeddedWorkerRegistry> embedded_worker_registry_;
scoped_ptr<ServiceWorkerJobCoordinator> job_coordinator_;
std::map<int64, ServiceWorkerRegistration*> live_registrations_;
std::map<int64, ServiceWorkerVersion*> live_versions_;
int next_handle_id_;
+ int next_registration_handle_id_;
scoped_refptr<ObserverListThreadSafe<ServiceWorkerContextObserver> >
observer_list_;
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 248587fceb7..3bd8418c227 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
@@ -4,12 +4,15 @@
#include "content/browser/service_worker/service_worker_context_request_handler.h"
+#include "base/time/time.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_read_from_cache_job.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/browser/service_worker/service_worker_write_to_cache_job.h"
+#include "content/public/browser/resource_context.h"
+#include "net/base/load_flags.h"
#include "net/url_request/url_request.h"
namespace content {
@@ -17,8 +20,8 @@ namespace content {
ServiceWorkerContextRequestHandler::ServiceWorkerContextRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context,
- ResourceType::Type resource_type)
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ ResourceType resource_type)
: ServiceWorkerRequestHandler(context,
provider_host,
blob_storage_context,
@@ -32,8 +35,9 @@ ServiceWorkerContextRequestHandler::~ServiceWorkerContextRequestHandler() {
net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) {
- if (!provider_host_ || !version_ || !context_)
+ net::NetworkDelegate* network_delegate,
+ ResourceContext* resource_context) {
+ if (!provider_host_ || !version_.get() || !context_)
return NULL;
// We currently have no use case for hijacking a redirected request.
@@ -45,17 +49,35 @@ net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJob(
// retrieve it from the script cache.
// TODO(michaeln): Get the desired behavior clarified in the spec,
// and make tweak the behavior here to match.
- if (resource_type_ != ResourceType::SERVICE_WORKER &&
- resource_type_ != ResourceType::SCRIPT) {
+ if (resource_type_ != RESOURCE_TYPE_SERVICE_WORKER &&
+ resource_type_ != RESOURCE_TYPE_SCRIPT) {
return NULL;
}
if (ShouldAddToScriptCache(request->url())) {
+ ServiceWorkerRegistration* registration =
+ context_->GetLiveRegistration(version_->registration_id());
+ DCHECK(registration); // We're registering or updating so must be there.
+
int64 response_id = context_->storage()->NewResourceId();
if (response_id == kInvalidServiceWorkerResponseId)
return NULL;
- return new ServiceWorkerWriteToCacheJob(
- request, network_delegate, context_, version_, response_id);
+
+ // Bypass the browser cache for initial installs and update
+ // checks after 24 hours have passed.
+ int extra_load_flags = 0;
+ base::TimeDelta time_since_last_check =
+ base::Time::Now() - registration->last_update_check();
+ if (time_since_last_check > base::TimeDelta::FromHours(24))
+ extra_load_flags = net::LOAD_BYPASS_CACHE;
+
+ return new ServiceWorkerWriteToCacheJob(request,
+ network_delegate,
+ resource_type_,
+ context_,
+ version_.get(),
+ extra_load_flags,
+ response_id);
}
int64 response_id = kInvalidServiceWorkerResponseId;
@@ -68,13 +90,30 @@ net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJob(
return NULL;
}
+void ServiceWorkerContextRequestHandler::GetExtraResponseInfo(
+ bool* was_fetched_via_service_worker,
+ bool* was_fallback_required_by_service_worker,
+ GURL* original_url_via_service_worker,
+ blink::WebServiceWorkerResponseType* response_type_via_service_worker,
+ base::TimeTicks* fetch_start_time,
+ base::TimeTicks* fetch_ready_time,
+ base::TimeTicks* fetch_end_time) const {
+ *was_fetched_via_service_worker = false;
+ *was_fallback_required_by_service_worker = false;
+ *original_url_via_service_worker = GURL();
+ *response_type_via_service_worker =
+ blink::WebServiceWorkerResponseTypeDefault;
+}
+
bool ServiceWorkerContextRequestHandler::ShouldAddToScriptCache(
const GURL& url) {
// We only write imports that occur during the initial eval.
- if (version_->status() != ServiceWorkerVersion::NEW)
+ if (version_->status() != ServiceWorkerVersion::NEW &&
+ version_->status() != ServiceWorkerVersion::INSTALLING) {
return false;
- return version_->script_cache_map()->Lookup(url) ==
- kInvalidServiceWorkerResponseId;
+ }
+ return version_->script_cache_map()->LookupResourceId(url) ==
+ kInvalidServiceWorkerResponseId;
}
bool ServiceWorkerContextRequestHandler::ShouldReadFromScriptCache(
@@ -83,7 +122,7 @@ bool ServiceWorkerContextRequestHandler::ShouldReadFromScriptCache(
if (version_->status() == ServiceWorkerVersion::NEW ||
version_->status() == ServiceWorkerVersion::INSTALLING)
return false;
- *response_id_out = version_->script_cache_map()->Lookup(url);
+ *response_id_out = version_->script_cache_map()->LookupResourceId(url);
return *response_id_out != kInvalidServiceWorkerResponseId;
}
diff --git a/chromium/content/browser/service_worker/service_worker_context_request_handler.h b/chromium/content/browser/service_worker/service_worker_context_request_handler.h
index ca894ce237e..c8af8ed5fd9 100644
--- a/chromium/content/browser/service_worker/service_worker_context_request_handler.h
+++ b/chromium/content/browser/service_worker/service_worker_context_request_handler.h
@@ -19,14 +19,24 @@ class CONTENT_EXPORT ServiceWorkerContextRequestHandler
ServiceWorkerContextRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context,
- ResourceType::Type resource_type);
- virtual ~ServiceWorkerContextRequestHandler();
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ ResourceType resource_type);
+ ~ServiceWorkerContextRequestHandler() override;
// Called via custom URLRequestJobFactory.
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) OVERRIDE;
+ net::NetworkDelegate* network_delegate,
+ ResourceContext* resource_context) override;
+
+ void GetExtraResponseInfo(
+ bool* was_fetched_via_service_worker,
+ bool* was_fallback_required_by_service_worker,
+ GURL* original_url_via_service_worker,
+ blink::WebServiceWorkerResponseType* response_type_via_service_worker,
+ base::TimeTicks* fetch_start_time,
+ base::TimeTicks* fetch_ready_time,
+ base::TimeTicks* fetch_end_time) const override;
private:
bool ShouldAddToScriptCache(const GURL& url);
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
new file mode 100644
index 00000000000..c1063d726fa
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -0,0 +1,140 @@
+// 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 "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "content/browser/browser_thread_impl.h"
+#include "content/browser/fileapi/mock_url_request_delegate.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_request_handler.h"
+#include "content/browser/service_worker/service_worker_provider_host.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/browser/service_worker/service_worker_write_to_cache_job.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_request_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+int kMockRenderProcessId = 1224;
+
+void EmptyCallback() {}
+
+}
+
+class ServiceWorkerContextRequestHandlerTest : public testing::Test {
+ public:
+ ServiceWorkerContextRequestHandlerTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
+
+ void SetUp() override {
+ helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
+
+ // A new unstored registration/version.
+ scope_ = GURL("http://host/scope/");
+ script_url_ = GURL("http://host/script.js");
+ registration_ = new ServiceWorkerRegistration(
+ scope_, 1L, context()->AsWeakPtr());
+ version_ = new ServiceWorkerVersion(
+ registration_.get(), script_url_, 1L, context()->AsWeakPtr());
+
+ // An empty host.
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kMockRenderProcessId, 1 /* provider_id */,
+ context()->AsWeakPtr(), NULL));
+ provider_host_ = host->AsWeakPtr();
+ context()->AddProviderHost(host.Pass());
+
+ context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void TearDown() override {
+ version_ = NULL;
+ registration_ = NULL;
+ helper_.reset();
+ }
+
+ ServiceWorkerContextCore* context() const { return helper_->context(); }
+
+ protected:
+ TestBrowserThreadBundle browser_thread_bundle_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_refptr<ServiceWorkerVersion> version_;
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+ net::URLRequestContext url_request_context_;
+ MockURLRequestDelegate url_request_delegate_;
+ GURL scope_;
+ GURL script_url_;
+};
+
+TEST_F(ServiceWorkerContextRequestHandlerTest, UpdateBefore24Hours) {
+ // Give the registration a very recent last update time and pretend
+ // we're installing a new version.
+ registration_->set_last_update_check(base::Time::Now());
+ 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_,
+ NULL);
+ scoped_ptr<ServiceWorkerContextRequestHandler> handler(
+ new ServiceWorkerContextRequestHandler(
+ context()->AsWeakPtr(),
+ provider_host_,
+ base::WeakPtr<storage::BlobStorageContext>(),
+ RESOURCE_TYPE_SERVICE_WORKER));
+ scoped_refptr<net::URLRequestJob> job =
+ handler->MaybeCreateJob(request.get(), NULL, NULL);
+ ASSERT_TRUE(job.get());
+ ServiceWorkerWriteToCacheJob* sw_job =
+ static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
+
+ // Verify the net request is not initialized to bypass the browser cache.
+ EXPECT_FALSE(sw_job->net_request_->load_flags() & net::LOAD_BYPASS_CACHE);
+}
+
+TEST_F(ServiceWorkerContextRequestHandlerTest, UpdateAfter24Hours) {
+ // Give the registration a old update time and pretend
+ // we're installing a new version.
+ registration_->set_last_update_check(
+ base::Time::Now() - base::TimeDelta::FromDays(7));
+ 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_,
+ NULL);
+ scoped_ptr<ServiceWorkerContextRequestHandler> handler(
+ new ServiceWorkerContextRequestHandler(
+ context()->AsWeakPtr(),
+ provider_host_,
+ base::WeakPtr<storage::BlobStorageContext>(),
+ RESOURCE_TYPE_SERVICE_WORKER));
+ scoped_refptr<net::URLRequestJob> job =
+ handler->MaybeCreateJob(request.get(), NULL, NULL);
+ ASSERT_TRUE(job.get());
+ ServiceWorkerWriteToCacheJob* sw_job =
+ static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
+
+ // Verify the net request is initialized to bypass the browser cache.
+ EXPECT_TRUE(sw_job->net_request_->load_flags() & net::LOAD_BYPASS_CACHE);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_context_unittest.cc b/chromium/content/browser/service_worker/service_worker_context_unittest.cc
index 14f54f7cb50..a5bba95facb 100644
--- a/chromium/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_unittest.cc
@@ -25,23 +25,17 @@ namespace {
void SaveResponseCallback(bool* called,
int64* store_registration_id,
- int64* store_version_id,
ServiceWorkerStatusCode status,
- int64 registration_id,
- int64 version_id) {
+ int64 registration_id) {
EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
*called = true;
*store_registration_id = registration_id;
- *store_version_id = version_id;
}
ServiceWorkerContextCore::RegistrationCallback MakeRegisteredCallback(
bool* called,
- int64* store_registration_id,
- int64* store_version_id) {
- return base::Bind(&SaveResponseCallback, called,
- store_registration_id,
- store_version_id);
+ int64* store_registration_id) {
+ return base::Bind(&SaveResponseCallback, called, store_registration_id);
}
void CallCompletedCallback(bool* called, ServiceWorkerStatusCode) {
@@ -55,29 +49,24 @@ ServiceWorkerContextCore::UnregistrationCallback MakeUnregisteredCallback(
void ExpectRegisteredWorkers(
ServiceWorkerStatusCode expect_status,
- int64 expect_version_id,
bool expect_waiting,
bool expect_active,
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
ASSERT_EQ(expect_status, status);
if (status != SERVICE_WORKER_OK) {
- EXPECT_FALSE(registration);
+ EXPECT_FALSE(registration.get());
return;
}
if (expect_waiting) {
EXPECT_TRUE(registration->waiting_version());
- EXPECT_EQ(expect_version_id,
- registration->waiting_version()->version_id());
} else {
EXPECT_FALSE(registration->waiting_version());
}
if (expect_active) {
EXPECT_TRUE(registration->active_version());
- EXPECT_EQ(expect_version_id,
- registration->active_version()->version_id());
} else {
EXPECT_FALSE(registration->active_version());
}
@@ -85,12 +74,12 @@ void ExpectRegisteredWorkers(
class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
public:
- RejectInstallTestHelper(int mock_render_process_id)
+ explicit RejectInstallTestHelper(int mock_render_process_id)
: EmbeddedWorkerTestHelper(mock_render_process_id) {}
- virtual void OnInstallEvent(int embedded_worker_id,
- int request_id,
- int active_version_id) OVERRIDE {
+ void OnInstallEvent(int embedded_worker_id,
+ int request_id,
+ int active_version_id) override {
SimulateSend(
new ServiceWorkerHostMsg_InstallEventFinished(
embedded_worker_id, request_id,
@@ -100,11 +89,10 @@ class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
class RejectActivateTestHelper : public EmbeddedWorkerTestHelper {
public:
- RejectActivateTestHelper(int mock_render_process_id)
+ explicit RejectActivateTestHelper(int mock_render_process_id)
: EmbeddedWorkerTestHelper(mock_render_process_id) {}
- virtual void OnActivateEvent(int embedded_worker_id,
- int request_id) OVERRIDE {
+ void OnActivateEvent(int embedded_worker_id, int request_id) override {
SimulateSend(
new ServiceWorkerHostMsg_ActivateEventFinished(
embedded_worker_id, request_id,
@@ -120,13 +108,11 @@ class ServiceWorkerContextTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
render_process_id_(99) {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_));
}
- virtual void TearDown() OVERRIDE {
- helper_.reset();
- }
+ void TearDown() override { helper_.reset(); }
ServiceWorkerContextCore* context() { return helper_->context(); }
@@ -139,14 +125,12 @@ class ServiceWorkerContextTest : public testing::Test {
// Make sure basic registration is working.
TEST_F(ServiceWorkerContextTest, Register) {
int64 registration_id = kInvalidServiceWorkerRegistrationId;
- int64 version_id = kInvalidServiceWorkerVersionId;
bool called = false;
context()->RegisterServiceWorker(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
NULL,
- MakeRegisteredCallback(&called, &registration_id, &version_id));
+ MakeRegisteredCallback(&called, &registration_id));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
@@ -162,14 +146,12 @@ TEST_F(ServiceWorkerContextTest, Register) {
EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
EmbeddedWorkerMsg_StopWorker::ID));
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
- EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
context()->storage()->FindRegistrationForId(
registration_id,
GURL("http://www.example.com"),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_OK,
- version_id,
false /* expect_waiting */,
true /* expect_active */));
base::RunLoop().RunUntilIdle();
@@ -182,14 +164,12 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
helper_.reset(); // Make sure the process lookups stay overridden.
helper_.reset(new RejectInstallTestHelper(render_process_id_));
int64 registration_id = kInvalidServiceWorkerRegistrationId;
- int64 version_id = kInvalidServiceWorkerVersionId;
bool called = false;
context()->RegisterServiceWorker(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
NULL,
- MakeRegisteredCallback(&called, &registration_id, &version_id));
+ MakeRegisteredCallback(&called, &registration_id));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
@@ -205,14 +185,12 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
EmbeddedWorkerMsg_StopWorker::ID));
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
- EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
context()->storage()->FindRegistrationForId(
registration_id,
GURL("http://www.example.com"),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_NOT_FOUND,
- kInvalidServiceWorkerVersionId,
false /* expect_waiting */,
false /* expect_active */));
base::RunLoop().RunUntilIdle();
@@ -225,14 +203,12 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) {
helper_.reset(); // Make sure the process lookups stay overridden.
helper_.reset(new RejectActivateTestHelper(render_process_id_));
int64 registration_id = kInvalidServiceWorkerRegistrationId;
- int64 version_id = kInvalidServiceWorkerVersionId;
bool called = false;
context()->RegisterServiceWorker(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
NULL,
- MakeRegisteredCallback(&called, &registration_id, &version_id));
+ MakeRegisteredCallback(&called, &registration_id));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
@@ -248,14 +224,12 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) {
EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
EmbeddedWorkerMsg_StopWorker::ID));
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
- EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
context()->storage()->FindRegistrationForId(
registration_id,
GURL("http://www.example.com"),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_NOT_FOUND,
- kInvalidServiceWorkerVersionId,
false /* expect_waiting */,
false /* expect_active */));
base::RunLoop().RunUntilIdle();
@@ -263,23 +237,20 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) {
// Make sure registrations are cleaned up when they are unregistered.
TEST_F(ServiceWorkerContextTest, Unregister) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
bool called = false;
int64 registration_id = kInvalidServiceWorkerRegistrationId;
- int64 version_id = kInvalidServiceWorkerVersionId;
context()->RegisterServiceWorker(
pattern,
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
NULL,
- MakeRegisteredCallback(&called, &registration_id, &version_id));
+ MakeRegisteredCallback(&called, &registration_id));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
- EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
called = false;
context()->UnregisterServiceWorker(pattern,
@@ -294,92 +265,234 @@ TEST_F(ServiceWorkerContextTest, Unregister) {
pattern.GetOrigin(),
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_NOT_FOUND,
- kInvalidServiceWorkerVersionId,
false /* expect_waiting */,
false /* expect_active */));
base::RunLoop().RunUntilIdle();
}
-// Make sure that when a new registration replaces an existing
-// registration, that the old one is cleaned up.
+// Make sure registrations are cleaned up when they are unregistered in bulk.
+TEST_F(ServiceWorkerContextTest, UnregisterMultiple) {
+ GURL origin1_p1("http://www.example.com/test");
+ GURL origin1_p2("http://www.example.com/hello");
+ GURL origin2_p1("http://www.example.com:8080/again");
+ GURL origin3_p1("http://www.other.com/");
+
+ bool called = false;
+ int64 registration_id1 = kInvalidServiceWorkerRegistrationId;
+ int64 registration_id2 = kInvalidServiceWorkerRegistrationId;
+ int64 registration_id3 = kInvalidServiceWorkerRegistrationId;
+ int64 registration_id4 = kInvalidServiceWorkerRegistrationId;
+ context()->RegisterServiceWorker(
+ origin1_p1,
+ GURL("http://www.example.com/service_worker.js"),
+ NULL,
+ MakeRegisteredCallback(&called, &registration_id1));
+ context()->RegisterServiceWorker(
+ origin1_p2,
+ GURL("http://www.example.com/service_worker2.js"),
+ NULL,
+ MakeRegisteredCallback(&called, &registration_id2));
+ context()->RegisterServiceWorker(
+ origin2_p1,
+ GURL("http://www.example.com:8080/service_worker3.js"),
+ NULL,
+ MakeRegisteredCallback(&called, &registration_id3));
+ context()->RegisterServiceWorker(
+ origin3_p1,
+ GURL("http://www.other.com/service_worker4.js"),
+ NULL,
+ MakeRegisteredCallback(&called, &registration_id4));
+
+ ASSERT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(called);
+
+ EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id1);
+ EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id2);
+ EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id3);
+ EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id4);
+
+ called = false;
+ context()->UnregisterServiceWorkers(origin1_p1.GetOrigin(),
+ MakeUnregisteredCallback(&called));
+
+ ASSERT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(called);
+
+ context()->storage()->FindRegistrationForId(
+ registration_id1,
+ origin1_p1.GetOrigin(),
+ base::Bind(&ExpectRegisteredWorkers,
+ SERVICE_WORKER_ERROR_NOT_FOUND,
+ false /* expect_waiting */,
+ false /* expect_active */));
+ context()->storage()->FindRegistrationForId(
+ registration_id2,
+ origin1_p2.GetOrigin(),
+ base::Bind(&ExpectRegisteredWorkers,
+ SERVICE_WORKER_ERROR_NOT_FOUND,
+ false /* expect_waiting */,
+ false /* expect_active */));
+ context()->storage()->FindRegistrationForId(
+ registration_id3,
+ origin2_p1.GetOrigin(),
+ base::Bind(&ExpectRegisteredWorkers,
+ SERVICE_WORKER_OK,
+ false /* expect_waiting */,
+ true /* expect_active */));
+
+ context()->storage()->FindRegistrationForId(
+ registration_id4,
+ origin3_p1.GetOrigin(),
+ base::Bind(&ExpectRegisteredWorkers,
+ SERVICE_WORKER_OK,
+ false /* expect_waiting */,
+ true /* expect_active */));
+
+ base::RunLoop().RunUntilIdle();
+}
+
+// Make sure registering a new script shares an existing registration.
TEST_F(ServiceWorkerContextTest, RegisterNewScript) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
bool called = false;
int64 old_registration_id = kInvalidServiceWorkerRegistrationId;
- int64 old_version_id = kInvalidServiceWorkerVersionId;
context()->RegisterServiceWorker(
pattern,
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
NULL,
- MakeRegisteredCallback(&called, &old_registration_id, &old_version_id));
+ MakeRegisteredCallback(&called, &old_registration_id));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
EXPECT_NE(kInvalidServiceWorkerRegistrationId, old_registration_id);
- EXPECT_NE(kInvalidServiceWorkerVersionId, old_version_id);
called = false;
int64 new_registration_id = kInvalidServiceWorkerRegistrationId;
- int64 new_version_id = kInvalidServiceWorkerVersionId;
context()->RegisterServiceWorker(
pattern,
GURL("http://www.example.com/service_worker_new.js"),
- render_process_id_,
NULL,
- MakeRegisteredCallback(&called, &new_registration_id, &new_version_id));
+ MakeRegisteredCallback(&called, &new_registration_id));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
- // Returned IDs should be valid, and should differ from the values
- // returned for the previous registration.
EXPECT_NE(kInvalidServiceWorkerRegistrationId, new_registration_id);
- EXPECT_NE(kInvalidServiceWorkerVersionId, new_version_id);
- EXPECT_NE(old_registration_id, new_registration_id);
- EXPECT_NE(old_version_id, new_version_id);
+ EXPECT_EQ(old_registration_id, new_registration_id);
}
// Make sure that when registering a duplicate pattern+script_url
// combination, that the same registration is used.
TEST_F(ServiceWorkerContextTest, RegisterDuplicateScript) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
GURL script_url("http://www.example.com/service_worker.js");
bool called = false;
int64 old_registration_id = kInvalidServiceWorkerRegistrationId;
- int64 old_version_id = kInvalidServiceWorkerVersionId;
context()->RegisterServiceWorker(
pattern,
script_url,
- render_process_id_,
NULL,
- MakeRegisteredCallback(&called, &old_registration_id, &old_version_id));
+ MakeRegisteredCallback(&called, &old_registration_id));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
EXPECT_NE(kInvalidServiceWorkerRegistrationId, old_registration_id);
- EXPECT_NE(kInvalidServiceWorkerVersionId, old_version_id);
called = false;
int64 new_registration_id = kInvalidServiceWorkerRegistrationId;
- int64 new_version_id = kInvalidServiceWorkerVersionId;
context()->RegisterServiceWorker(
pattern,
script_url,
- render_process_id_,
NULL,
- MakeRegisteredCallback(&called, &new_registration_id, &new_version_id));
+ MakeRegisteredCallback(&called, &new_registration_id));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
EXPECT_EQ(old_registration_id, new_registration_id);
- EXPECT_EQ(old_version_id, new_version_id);
+}
+
+// TODO(nhiroki): Test this for on-disk storage.
+TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) {
+ int64 registration_id = kInvalidServiceWorkerRegistrationId;
+ bool called = false;
+ context()->RegisterServiceWorker(
+ GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"),
+ NULL,
+ MakeRegisteredCallback(&called, &registration_id));
+
+ ASSERT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+
+ context()->storage()->FindRegistrationForId(
+ registration_id,
+ GURL("http://www.example.com"),
+ base::Bind(&ExpectRegisteredWorkers,
+ SERVICE_WORKER_OK,
+ false /* expect_waiting */,
+ true /* expect_active */));
+ base::RunLoop().RunUntilIdle();
+
+ // Next handle ids should be 0 (the next call should return 1).
+ EXPECT_EQ(0, context()->GetNewServiceWorkerHandleId());
+ EXPECT_EQ(0, context()->GetNewRegistrationHandleId());
+
+ context()->ScheduleDeleteAndStartOver();
+
+ // The storage is disabled while the recovery process is running, so the
+ // operation should be failed.
+ context()->storage()->FindRegistrationForId(
+ registration_id,
+ GURL("http://www.example.com"),
+ base::Bind(&ExpectRegisteredWorkers,
+ SERVICE_WORKER_ERROR_FAILED,
+ false /* expect_waiting */,
+ true /* expect_active */));
+ base::RunLoop().RunUntilIdle();
+
+ // The context started over and the storage was re-initialized, so the
+ // registration should not be found.
+ context()->storage()->FindRegistrationForId(
+ registration_id,
+ GURL("http://www.example.com"),
+ base::Bind(&ExpectRegisteredWorkers,
+ SERVICE_WORKER_ERROR_NOT_FOUND,
+ false /* expect_waiting */,
+ true /* expect_active */));
+ base::RunLoop().RunUntilIdle();
+
+ called = false;
+ context()->RegisterServiceWorker(
+ GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"),
+ NULL,
+ MakeRegisteredCallback(&called, &registration_id));
+
+ ASSERT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+
+ context()->storage()->FindRegistrationForId(
+ registration_id,
+ GURL("http://www.example.com"),
+ base::Bind(&ExpectRegisteredWorkers,
+ SERVICE_WORKER_OK,
+ false /* expect_waiting */,
+ true /* expect_active */));
+ base::RunLoop().RunUntilIdle();
+
+ // The new context should take over next handle ids.
+ EXPECT_EQ(1, context()->GetNewServiceWorkerHandleId());
+ EXPECT_EQ(1, context()->GetNewRegistrationHandleId());
}
} // namespace content
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 460f6df36e4..6a4fc0892ee 100644
--- a/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -4,21 +4,59 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/barrier_closure.h"
+#include "base/bind.h"
#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
#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_process_manager.h"
+#include "content/browser/service_worker/service_worker_quota_client.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
+#include "content/public/browser/service_worker_context.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/browser/quota/special_storage_policy.h"
namespace content {
+namespace {
+
+typedef std::set<std::string> HeaderNameSet;
+base::LazyInstance<HeaderNameSet> g_excluded_header_name_set =
+ LAZY_INSTANCE_INITIALIZER;
+}
+
+void ServiceWorkerContext::AddExcludedHeadersForFetchEvent(
+ const std::set<std::string>& header_names) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ g_excluded_header_name_set.Get().insert(header_names.begin(),
+ header_names.end());
+}
+
+bool ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(
+ const std::string& header_name) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ return g_excluded_header_name_set.Get().find(header_name) !=
+ g_excluded_header_name_set.Get().end();
+}
+
ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
BrowserContext* browser_context)
: observer_list_(
new ObserverListThreadSafe<ServiceWorkerContextObserver>()),
- process_manager_(new ServiceWorkerProcessManager(browser_context)) {
+ process_manager_(new ServiceWorkerProcessManager(browser_context)),
+ is_incognito_(false) {
}
ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
@@ -26,16 +64,24 @@ ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
void ServiceWorkerContextWrapper::Init(
const base::FilePath& user_data_directory,
- quota::QuotaManagerProxy* quota_manager_proxy) {
- scoped_refptr<base::SequencedTaskRunner> database_task_runner =
- BrowserThread::GetBlockingPool()->
- GetSequencedTaskRunnerWithShutdownBehavior(
- BrowserThread::GetBlockingPool()->GetSequenceToken(),
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
- scoped_refptr<base::MessageLoopProxy> disk_cache_thread =
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy) {
+ is_incognito_ = user_data_directory.empty();
+ base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
+ new ServiceWorkerDatabaseTaskManagerImpl(pool));
+ scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread =
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE);
- InitInternal(user_data_directory, database_task_runner,
- disk_cache_thread, quota_manager_proxy);
+ scoped_refptr<base::SequencedTaskRunner> cache_task_runner =
+ pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ BrowserThread::GetBlockingPool()->GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+ InitInternal(user_data_directory,
+ cache_task_runner,
+ database_task_manager.Pass(),
+ disk_cache_thread,
+ quota_manager_proxy,
+ special_storage_policy);
}
void ServiceWorkerContextWrapper::Shutdown() {
@@ -47,6 +93,12 @@ void ServiceWorkerContextWrapper::Shutdown() {
base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO, this));
}
+void ServiceWorkerContextWrapper::DeleteAndStartOver() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ context_core_->DeleteAndStartOver(
+ base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver, this));
+}
+
ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return context_core_.get();
@@ -55,8 +107,7 @@ ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
static void FinishRegistrationOnIO(
const ServiceWorkerContext::ResultCallback& continuation,
ServiceWorkerStatusCode status,
- int64 registration_id,
- int64 version_id) {
+ int64 registration_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask(
BrowserThread::UI,
@@ -79,11 +130,17 @@ void ServiceWorkerContextWrapper::RegisterServiceWorker(
continuation));
return;
}
-
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(continuation, false));
+ return;
+ }
context()->RegisterServiceWorker(
pattern,
script_url,
- -1,
NULL /* provider_host */,
base::Bind(&FinishRegistrationOnIO, continuation));
}
@@ -111,15 +168,89 @@ void ServiceWorkerContextWrapper::UnregisterServiceWorker(
continuation));
return;
}
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(continuation, false));
+ return;
+ }
context()->UnregisterServiceWorker(
pattern,
base::Bind(&FinishUnregistrationOnIO, continuation));
}
-void ServiceWorkerContextWrapper::Terminate() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- process_manager_->Shutdown();
+void ServiceWorkerContextWrapper::GetAllOriginsInfo(
+ const GetUsageInfoCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, std::vector<ServiceWorkerUsageInfo>()));
+ return;
+ }
+ context()->storage()->GetAllRegistrations(base::Bind(
+ &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
+ this,
+ callback));
+}
+
+void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
+ const GetUsageInfoCallback& callback,
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::vector<ServiceWorkerUsageInfo> usage_infos;
+
+ std::map<GURL, ServiceWorkerUsageInfo> origins;
+ for (const auto& registration_info : registrations) {
+ GURL origin = registration_info.pattern.GetOrigin();
+
+ ServiceWorkerUsageInfo& usage_info = origins[origin];
+ if (usage_info.origin.is_empty())
+ usage_info.origin = origin;
+ usage_info.scopes.push_back(registration_info.pattern);
+ usage_info.total_size_bytes += registration_info.stored_version_size_bytes;
+ }
+
+ for (const auto& origin_info_pair : origins) {
+ usage_infos.push_back(origin_info_pair.second);
+ }
+ callback.Run(usage_infos);
+}
+
+namespace {
+void StatusCodeToBoolCallbackAdapter(
+ const ServiceWorkerContext::ResultCallback& callback,
+ ServiceWorkerStatusCode code) {
+ callback.Run(code == ServiceWorkerStatusCode::SERVICE_WORKER_OK);
+}
+
+void EmptySuccessCallback(bool success) {
+}
+} // namespace
+
+void ServiceWorkerContextWrapper::DeleteForOrigin(
+ const GURL& origin_url,
+ const ResultCallback& result) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (!context_core_.get()) {
+ LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(result, false));
+ return;
+ }
+ context()->UnregisterServiceWorkers(
+ origin_url, base::Bind(&StatusCodeToBoolCallbackAdapter, result));
+}
+
+void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) {
+ DeleteForOrigin(origin_url, base::Bind(&EmptySuccessCallback));
}
void ServiceWorkerContextWrapper::AddObserver(
@@ -132,11 +263,25 @@ void ServiceWorkerContextWrapper::RemoveObserver(
observer_list_->RemoveObserver(observer);
}
+void ServiceWorkerContextWrapper::SetBlobParametersForCache(
+ net::URLRequestContextGetter* request_context,
+ ChromeBlobStorageContext* blob_storage_context) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ if (context_core_ && request_context && blob_storage_context) {
+ context_core_->SetBlobParametersForCache(
+ request_context->GetURLRequestContext(),
+ blob_storage_context->context()->AsWeakPtr());
+ }
+}
+
void ServiceWorkerContextWrapper::InitInternal(
const base::FilePath& user_data_directory,
- base::SequencedTaskRunner* database_task_runner,
- base::MessageLoopProxy* disk_cache_thread,
- quota::QuotaManagerProxy* quota_manager_proxy) {
+ const scoped_refptr<base::SequencedTaskRunner>& stores_task_runner,
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
BrowserThread::IO,
@@ -144,17 +289,24 @@ void ServiceWorkerContextWrapper::InitInternal(
base::Bind(&ServiceWorkerContextWrapper::InitInternal,
this,
user_data_directory,
- make_scoped_refptr(database_task_runner),
- make_scoped_refptr(disk_cache_thread),
- make_scoped_refptr(quota_manager_proxy)));
+ stores_task_runner,
+ base::Passed(&database_task_manager),
+ disk_cache_thread,
+ make_scoped_refptr(quota_manager_proxy),
+ make_scoped_refptr(special_storage_policy)));
return;
}
DCHECK(!context_core_);
+ if (quota_manager_proxy) {
+ quota_manager_proxy->RegisterClient(new ServiceWorkerQuotaClient(this));
+ }
context_core_.reset(new ServiceWorkerContextCore(user_data_directory,
- database_task_runner,
+ stores_task_runner,
+ database_task_manager.Pass(),
disk_cache_thread,
quota_manager_proxy,
- observer_list_,
+ special_storage_policy,
+ observer_list_.get(),
this));
}
@@ -163,4 +315,15 @@ void ServiceWorkerContextWrapper::ShutdownOnIO() {
context_core_.reset();
}
+void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
+ ServiceWorkerStatusCode status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ if (status != SERVICE_WORKER_OK) {
+ context_core_.reset();
+ return;
+ }
+ context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this));
+ DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
+}
+
} // namespace content
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 029af6f54ca..7df3cb093b1 100644
--- a/chromium/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.h
@@ -16,17 +16,23 @@
namespace base {
class FilePath;
-class MessageLoopProxy;
class SequencedTaskRunner;
+class SingleThreadTaskRunner;
}
-namespace quota {
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace storage {
class QuotaManagerProxy;
+class SpecialStoragePolicy;
}
namespace content {
class BrowserContext;
+class ChromeBlobStorageContext;
class ServiceWorkerContextCore;
class ServiceWorkerContextObserver;
@@ -43,9 +49,15 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
// 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,
- quota::QuotaManagerProxy* quota_manager_proxy);
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy);
void Shutdown();
+ // 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.
+ void DeleteAndStartOver();
+
// The core context is only for use on the IO thread.
ServiceWorkerContextCore* context();
@@ -55,35 +67,65 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
}
// ServiceWorkerContext implementation:
- virtual void RegisterServiceWorker(
- const GURL& pattern,
- const GURL& script_url,
- const ResultCallback& continuation) OVERRIDE;
- virtual void UnregisterServiceWorker(const GURL& pattern,
- const ResultCallback& continuation)
- OVERRIDE;
- virtual void Terminate() OVERRIDE;
+ void RegisterServiceWorker(const GURL& pattern,
+ const GURL& script_url,
+ const ResultCallback& continuation) override;
+ void UnregisterServiceWorker(const GURL& pattern,
+ const ResultCallback& continuation) override;
+ void GetAllOriginsInfo(const GetUsageInfoCallback& callback) override;
+ void DeleteForOrigin(const GURL& origin_url) override;
+
+ // DeleteForOrigin with completion callback. Does not exit early, and returns
+ // false if one or more of the deletions fail.
+ virtual void DeleteForOrigin(const GURL& origin_url,
+ const ResultCallback& done);
void AddObserver(ServiceWorkerContextObserver* observer);
void RemoveObserver(ServiceWorkerContextObserver* observer);
+ bool is_incognito() const { return is_incognito_; }
+
+ // The URLRequestContext doesn't exist until after the StoragePartition is
+ // made (which is after this object is made). This function must be called
+ // after this object is created but before any ServiceWorkerCache operations.
+ // It must be called on the IO thread. If either parameter is NULL the
+ // function immediately returns without forwarding to the
+ // ServiceWorkerCacheStorageManager.
+ void SetBlobParametersForCache(
+ net::URLRequestContextGetter* request_context,
+ ChromeBlobStorageContext* blob_storage_context);
+
private:
friend class base::RefCountedThreadSafe<ServiceWorkerContextWrapper>;
friend class EmbeddedWorkerTestHelper;
friend class ServiceWorkerProcessManager;
- virtual ~ServiceWorkerContextWrapper();
+ friend class MockServiceWorkerContextWrapper;
- void InitInternal(const base::FilePath& user_data_directory,
- base::SequencedTaskRunner* database_task_runner,
- base::MessageLoopProxy* disk_cache_thread,
- quota::QuotaManagerProxy* quota_manager_proxy);
+ ~ServiceWorkerContextWrapper() override;
+
+ void InitInternal(
+ const base::FilePath& user_data_directory,
+ const scoped_refptr<base::SequencedTaskRunner>& stores_task_runner,
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy);
void ShutdownOnIO();
+ void DidDeleteAndStartOver(ServiceWorkerStatusCode status);
+
+ void DidGetAllRegistrationsForGetAllOrigins(
+ const GetUsageInfoCallback& callback,
+ const std::vector<ServiceWorkerRegistrationInfo>& registrations);
+
const scoped_refptr<ObserverListThreadSafe<ServiceWorkerContextObserver> >
observer_list_;
const scoped_ptr<ServiceWorkerProcessManager> process_manager_;
// Cleared in Shutdown():
scoped_ptr<ServiceWorkerContextCore> context_core_;
+
+ // Initialized in Init(); true if the user data directory is empty.
+ bool is_incognito_;
};
} // namespace content
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 14a707b62e8..da4bd123f23 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
@@ -4,12 +4,18 @@
#include "content/browser/service_worker/service_worker_controllee_request_handler.h"
+#include "base/debug/trace_event.h"
#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_url_request_job.h"
#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_client.h"
+#include "net/base/load_flags.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request.h"
@@ -18,22 +24,46 @@ namespace content {
ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context,
- ResourceType::Type resource_type)
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ FetchRequestMode request_mode,
+ FetchCredentialsMode credentials_mode,
+ ResourceType resource_type,
+ RequestContextType request_context_type,
+ RequestContextFrameType frame_type,
+ scoped_refptr<ResourceRequestBody> body)
: ServiceWorkerRequestHandler(context,
provider_host,
blob_storage_context,
resource_type),
+ is_main_resource_load_(
+ ServiceWorkerUtils::IsMainResourceType(resource_type)),
+ request_mode_(request_mode),
+ credentials_mode_(credentials_mode),
+ request_context_type_(request_context_type),
+ frame_type_(frame_type),
+ body_(body),
weak_factory_(this) {
}
ServiceWorkerControlleeRequestHandler::
~ServiceWorkerControlleeRequestHandler() {
+ // Navigation triggers an update to occur shortly after the page and
+ // its initial subresources load.
+ if (provider_host_ && provider_host_->active_version()) {
+ if (is_main_resource_load_)
+ provider_host_->active_version()->ScheduleUpdate();
+ else
+ provider_host_->active_version()->DeferScheduledUpdate();
+ }
+
+ if (is_main_resource_load_ && provider_host_)
+ provider_host_->SetAllowAssociation(true);
}
net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) {
+ net::NetworkDelegate* network_delegate,
+ ResourceContext* resource_context) {
if (!context_ || !provider_host_) {
// We can't do anything other than to fall back to network.
job_ = NULL;
@@ -57,10 +87,19 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
// It's for original request (A) or redirect case (B-a or B-b).
DCHECK(!job_.get() || job_->ShouldForwardToServiceWorker());
- job_ = new ServiceWorkerURLRequestJob(
- request, network_delegate, provider_host_, blob_storage_context_);
- if (ServiceWorkerUtils::IsMainResourceType(resource_type_))
- PrepareForMainResource(request->url());
+ job_ = new ServiceWorkerURLRequestJob(request,
+ network_delegate,
+ provider_host_,
+ blob_storage_context_,
+ request_mode_,
+ credentials_mode_,
+ request_context_type_,
+ frame_type_,
+ body_);
+ resource_context_ = resource_context;
+
+ if (is_main_resource_load_)
+ PrepareForMainResource(request);
else
PrepareForSubResource();
@@ -75,17 +114,50 @@ net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
return job_.get();
}
+void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo(
+ bool* was_fetched_via_service_worker,
+ bool* was_fallback_required_by_service_worker,
+ GURL* original_url_via_service_worker,
+ blink::WebServiceWorkerResponseType* response_type_via_service_worker,
+ base::TimeTicks* fetch_start_time,
+ base::TimeTicks* fetch_ready_time,
+ base::TimeTicks* fetch_end_time) const {
+ if (!job_.get()) {
+ *was_fetched_via_service_worker = false;
+ *was_fallback_required_by_service_worker = false;
+ *original_url_via_service_worker = GURL();
+ return;
+ }
+ job_->GetExtraResponseInfo(was_fetched_via_service_worker,
+ was_fallback_required_by_service_worker,
+ original_url_via_service_worker,
+ response_type_via_service_worker,
+ fetch_start_time,
+ fetch_ready_time,
+ fetch_end_time);
+}
+
void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
- const GURL& url) {
+ const net::URLRequest* request) {
DCHECK(job_.get());
DCHECK(context_);
- // The corresponding provider_host may already have associate version in
- // redirect case, unassociate it now.
- provider_host_->SetActiveVersion(NULL);
- provider_host_->SetWaitingVersion(NULL);
+ DCHECK(provider_host_);
+ TRACE_EVENT_ASYNC_BEGIN1(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ job_.get(),
+ "URL", request->url().spec());
+ // The corresponding provider_host may already have associated a registration
+ // in redirect case, unassociate it now.
+ provider_host_->DisassociateRegistration();
+
+ // Also prevent a registrater job for establishing an association to a new
+ // registration while we're finding an existing registration.
+ provider_host_->SetAllowAssociation(false);
- GURL stripped_url = net::SimplifyUrlForRequest(url);
+ GURL stripped_url = net::SimplifyUrlForRequest(request->url());
provider_host_->SetDocumentUrl(stripped_url);
+ provider_host_->SetTopmostFrameUrl(request->first_party_for_cookies());
context_->storage()->FindRegistrationForDocument(
stripped_url,
base::Bind(&self::DidLookupRegistrationForMainResource,
@@ -97,17 +169,102 @@ ServiceWorkerControlleeRequestHandler::DidLookupRegistrationForMainResource(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
DCHECK(job_.get());
- if (status != SERVICE_WORKER_OK || !registration->active_version()) {
- // No registration, or no active version for the registration is available.
+ if (provider_host_)
+ provider_host_->SetAllowAssociation(true);
+ if (status != SERVICE_WORKER_OK || !provider_host_) {
job_->FallbackToNetwork();
+ TRACE_EVENT_ASYNC_END1(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ job_.get(),
+ "Status", status);
return;
}
- // TODO(michaeln): should SetWaitingVersion() even if no active version so
- // so the versions in the pipeline (.installing, .waiting) show up in the
- // attribute values.
- DCHECK(registration);
- provider_host_->SetActiveVersion(registration->active_version());
- provider_host_->SetWaitingVersion(registration->waiting_version());
+ DCHECK(registration.get());
+
+ if (!GetContentClient()->browser()->AllowServiceWorker(
+ registration->pattern(),
+ provider_host_->topmost_frame_url(),
+ resource_context_)) {
+ job_->FallbackToNetwork();
+ TRACE_EVENT_ASYNC_END2(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ job_.get(),
+ "Status", status,
+ "Info", "ServiceWorker is blocked");
+ return;
+ }
+
+ // Initiate activation of a waiting version.
+ // Usually a register job initiates activation but that
+ // doesn't happen if the browser exits prior to activation
+ // having occurred. This check handles that case.
+ if (registration->waiting_version())
+ registration->ActivateWaitingVersionWhenReady();
+
+ scoped_refptr<ServiceWorkerVersion> active_version =
+ registration->active_version();
+
+ // Wait until it's activated before firing fetch events.
+ 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));
+ TRACE_EVENT_ASYNC_END2(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ job_.get(),
+ "Status", status,
+ "Info", "Wait until finished SW activation");
+ return;
+ }
+
+ if (!active_version.get() ||
+ active_version->status() != ServiceWorkerVersion::ACTIVATED) {
+ job_->FallbackToNetwork();
+ TRACE_EVENT_ASYNC_END2(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ job_.get(),
+ "Status", status,
+ "Info",
+ "ServiceWorkerVersion is not available, so falling back to network");
+ return;
+ }
+
+ ServiceWorkerMetrics::CountControlledPageLoad();
+
+ provider_host_->AssociateRegistration(registration.get());
+ job_->ForwardToServiceWorker();
+ TRACE_EVENT_ASYNC_END2(
+ "ServiceWorker",
+ "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
+ job_.get(),
+ "Status", status,
+ "Info",
+ "Forwarded to the ServiceWorker");
+}
+
+void ServiceWorkerControlleeRequestHandler::OnVersionStatusChanged(
+ ServiceWorkerRegistration* registration,
+ ServiceWorkerVersion* version) {
+ if (provider_host_)
+ provider_host_->SetAllowAssociation(true);
+ if (version != registration->active_version() ||
+ version->status() != ServiceWorkerVersion::ACTIVATED ||
+ !provider_host_) {
+ job_->FallbackToNetwork();
+ return;
+ }
+
+ ServiceWorkerMetrics::CountControlledPageLoad();
+
+ provider_host_->AssociateRegistration(registration);
job_->ForwardToServiceWorker();
}
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 87227cb32dd..9c2beccba39 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
@@ -5,7 +5,13 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTROLLEE_REQUEST_HANDLER_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTROLLEE_REQUEST_HANDLER_H_
+#include "base/gtest_prod_util.h"
#include "content/browser/service_worker/service_worker_request_handler.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/common/request_context_frame_type.h"
+#include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_type.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
namespace net {
class NetworkDelegate;
@@ -14,8 +20,10 @@ class URLRequest;
namespace content {
+class ResourceRequestBody;
class ServiceWorkerRegistration;
class ServiceWorkerURLRequestJob;
+class ServiceWorkerVersion;
// A request handler derivative used to handle requests from
// controlled documents.
@@ -25,28 +33,55 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler
ServiceWorkerControlleeRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context,
- ResourceType::Type resource_type);
- virtual ~ServiceWorkerControlleeRequestHandler();
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ FetchRequestMode request_mode,
+ FetchCredentialsMode credentials_mode,
+ ResourceType resource_type,
+ RequestContextType request_context_type,
+ RequestContextFrameType frame_type,
+ scoped_refptr<ResourceRequestBody> body);
+ ~ServiceWorkerControlleeRequestHandler() override;
// Called via custom URLRequestJobFactory.
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) OVERRIDE;
+ net::NetworkDelegate* network_delegate,
+ ResourceContext* resource_context) override;
+
+ void GetExtraResponseInfo(
+ bool* was_fetched_via_service_worker,
+ bool* was_fallback_required_by_service_worker,
+ GURL* original_url_via_service_worker,
+ blink::WebServiceWorkerResponseType* response_type_via_service_worker,
+ base::TimeTicks* fetch_start_time,
+ base::TimeTicks* fetch_ready_time,
+ base::TimeTicks* fetch_end_time) const override;
private:
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerControlleeRequestHandlerTest,
+ ActivateWaitingVersion);
typedef ServiceWorkerControlleeRequestHandler self;
// For main resource case.
- void PrepareForMainResource(const GURL& url);
+ void PrepareForMainResource(const net::URLRequest* request);
void DidLookupRegistrationForMainResource(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
+ void OnVersionStatusChanged(
+ ServiceWorkerRegistration* registration,
+ ServiceWorkerVersion* version);
// For sub resource case.
void PrepareForSubResource();
+ bool is_main_resource_load_;
scoped_refptr<ServiceWorkerURLRequestJob> job_;
+ FetchRequestMode request_mode_;
+ FetchCredentialsMode credentials_mode_;
+ RequestContextType request_context_type_;
+ RequestContextFrameType frame_type_;
+ scoped_refptr<ResourceRequestBody> body_;
+ ResourceContext* resource_context_;
base::WeakPtrFactory<ServiceWorkerControlleeRequestHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerControlleeRequestHandler);
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
new file mode 100644
index 00000000000..9a6835addb7
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -0,0 +1,244 @@
+// 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 "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "content/browser/browser_thread_impl.h"
+#include "content/browser/fileapi/mock_url_request_delegate.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_controllee_request_handler.h"
+#include "content/browser/service_worker/service_worker_provider_host.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_url_request_job.h"
+#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/common/resource_request_body.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/common/request_context_frame_type.h"
+#include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_type.h"
+#include "content/public/test/mock_resource_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/test_content_browser_client.h"
+#include "net/url_request/url_request_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+int kMockRenderProcessId = 1224;
+int kMockProviderId = 1;
+
+void EmptyCallback() {}
+
+}
+
+class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
+ public:
+ ServiceWorkerControlleeRequestHandlerTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
+
+ void SetUp() override {
+ helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
+
+ // A new unstored registration/version.
+ scope_ = GURL("http://host/scope/");
+ script_url_ = GURL("http://host/script.js");
+ registration_ = new ServiceWorkerRegistration(
+ scope_, 1L, context()->AsWeakPtr());
+ version_ = new ServiceWorkerVersion(
+ registration_.get(), script_url_, 1L, context()->AsWeakPtr());
+
+ // An empty host.
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kMockRenderProcessId, kMockProviderId,
+ context()->AsWeakPtr(), NULL));
+ provider_host_ = host->AsWeakPtr();
+ context()->AddProviderHost(host.Pass());
+
+ context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void TearDown() override {
+ version_ = NULL;
+ registration_ = NULL;
+ helper_.reset();
+ }
+
+ ServiceWorkerContextCore* context() const { return helper_->context(); }
+
+ protected:
+ TestBrowserThreadBundle browser_thread_bundle_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_refptr<ServiceWorkerVersion> version_;
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+ net::URLRequestContext url_request_context_;
+ MockURLRequestDelegate url_request_delegate_;
+ MockResourceContext mock_resource_context_;
+ GURL scope_;
+ GURL script_url_;
+};
+
+class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
+ public:
+ ServiceWorkerTestContentBrowserClient() {}
+ bool AllowServiceWorker(const GURL& scope,
+ const GURL& first_party,
+ content::ResourceContext* context) override {
+ return false;
+ }
+};
+
+TEST_F(ServiceWorkerControlleeRequestHandlerTest, DisallowServiceWorker) {
+ ServiceWorkerTestContentBrowserClient test_browser_client;
+ ContentBrowserClient* old_browser_client =
+ SetBrowserClientForTesting(&test_browser_client);
+
+ // Store an activated worker.
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ registration_->SetActiveVersion(version_.get());
+ context()->storage()->StoreRegistration(
+ registration_.get(),
+ version_.get(),
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ base::RunLoop().RunUntilIdle();
+
+ // Conduct a main resource load.
+ const GURL kDocUrl("http://host/scope/doc");
+ scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
+ kDocUrl, net::DEFAULT_PRIORITY, &url_request_delegate_, NULL);
+ scoped_ptr<ServiceWorkerControlleeRequestHandler> handler(
+ new ServiceWorkerControlleeRequestHandler(
+ context()->AsWeakPtr(),
+ provider_host_,
+ base::WeakPtr<storage::BlobStorageContext>(),
+ FETCH_REQUEST_MODE_NO_CORS,
+ FETCH_CREDENTIALS_MODE_OMIT,
+ RESOURCE_TYPE_MAIN_FRAME,
+ REQUEST_CONTEXT_TYPE_HYPERLINK,
+ REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ scoped_refptr<ResourceRequestBody>()));
+ scoped_refptr<net::URLRequestJob> job =
+ handler->MaybeCreateJob(request.get(), NULL, &mock_resource_context_);
+ ServiceWorkerURLRequestJob* sw_job =
+ static_cast<ServiceWorkerURLRequestJob*>(job.get());
+
+ EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
+ EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
+ EXPECT_FALSE(version_->HasControllee());
+ base::RunLoop().RunUntilIdle();
+
+ // Verify we did not use the worker.
+ EXPECT_TRUE(sw_job->ShouldFallbackToNetwork());
+ EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
+ EXPECT_FALSE(version_->HasControllee());
+
+ SetBrowserClientForTesting(old_browser_client);
+}
+
+TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
+ // Store a registration that is installed but not activated yet.
+ version_->SetStatus(ServiceWorkerVersion::INSTALLED);
+ registration_->SetWaitingVersion(version_.get());
+ context()->storage()->StoreRegistration(
+ registration_.get(),
+ version_.get(),
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ base::RunLoop().RunUntilIdle();
+
+ // Conduct a main resource load.
+ const GURL kDocUrl("http://host/scope/doc");
+ scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
+ kDocUrl,
+ net::DEFAULT_PRIORITY,
+ &url_request_delegate_,
+ NULL);
+ scoped_ptr<ServiceWorkerControlleeRequestHandler> handler(
+ new ServiceWorkerControlleeRequestHandler(
+ context()->AsWeakPtr(),
+ provider_host_,
+ base::WeakPtr<storage::BlobStorageContext>(),
+ FETCH_REQUEST_MODE_NO_CORS,
+ FETCH_CREDENTIALS_MODE_OMIT,
+ RESOURCE_TYPE_MAIN_FRAME,
+ REQUEST_CONTEXT_TYPE_HYPERLINK,
+ REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ scoped_refptr<ResourceRequestBody>()));
+ scoped_refptr<net::URLRequestJob> job =
+ handler->MaybeCreateJob(request.get(), NULL, &mock_resource_context_);
+ ServiceWorkerURLRequestJob* sw_job =
+ static_cast<ServiceWorkerURLRequestJob*>(job.get());
+
+ EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
+ EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
+ EXPECT_FALSE(version_->HasControllee());
+
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
+ version_->status());
+ EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
+ EXPECT_TRUE(sw_job->ShouldForwardToServiceWorker());
+ EXPECT_TRUE(version_->HasControllee());
+
+ // Navigations should trigger an update too.
+ handler.reset(NULL);
+ EXPECT_TRUE(version_->update_timer_.IsRunning());
+}
+
+// Test to not regress crbug/414118.
+TEST_F(ServiceWorkerControlleeRequestHandlerTest, DeletedProviderHost) {
+ // Store a registration so the call to FindRegistrationForDocument will read
+ // from the database.
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ registration_->SetActiveVersion(version_.get());
+ context()->storage()->StoreRegistration(
+ registration_.get(),
+ version_.get(),
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ base::RunLoop().RunUntilIdle();
+ version_ = NULL;
+ registration_ = NULL;
+
+ // Conduct a main resource load.
+ const GURL kDocUrl("http://host/scope/doc");
+ scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
+ kDocUrl,
+ net::DEFAULT_PRIORITY,
+ &url_request_delegate_,
+ NULL);
+ scoped_ptr<ServiceWorkerControlleeRequestHandler> handler(
+ new ServiceWorkerControlleeRequestHandler(
+ context()->AsWeakPtr(),
+ provider_host_,
+ base::WeakPtr<storage::BlobStorageContext>(),
+ FETCH_REQUEST_MODE_NO_CORS,
+ FETCH_CREDENTIALS_MODE_OMIT,
+ RESOURCE_TYPE_MAIN_FRAME,
+ REQUEST_CONTEXT_TYPE_HYPERLINK,
+ REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ scoped_refptr<ResourceRequestBody>()));
+ scoped_refptr<net::URLRequestJob> job =
+ handler->MaybeCreateJob(request.get(), NULL, &mock_resource_context_);
+ ServiceWorkerURLRequestJob* sw_job =
+ static_cast<ServiceWorkerURLRequestJob*>(job.get());
+
+ EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
+ EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
+
+ // Shouldn't crash if the ProviderHost is deleted prior to completion of
+ // the database lookup.
+ context()->RemoveProviderHost(kMockRenderProcessId, kMockProviderId);
+ EXPECT_FALSE(provider_host_.get());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(sw_job->ShouldFallbackToNetwork());
+ EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_database.cc b/chromium/content/browser/service_worker/service_worker_database.cc
index 1058acc6165..61b8659e77c 100644
--- a/chromium/content/browser/service_worker/service_worker_database.cc
+++ b/chromium/content/browser/service_worker/service_worker_database.cc
@@ -6,7 +6,7 @@
#include <string>
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
@@ -16,6 +16,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "content/browser/service_worker/service_worker_database.pb.h"
+#include "content/browser/service_worker/service_worker_metrics.h"
#include "content/common/service_worker/service_worker_types.h"
#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
@@ -78,14 +79,6 @@ const char kPurgeableResIdKeyPrefix[] = "PRES:";
const int64 kCurrentSchemaVersion = 1;
-// For histogram.
-const char kOpenResultHistogramLabel[] =
- "ServiceWorker.Database.OpenResult";
-const char kReadResultHistogramLabel[] =
- "ServiceWorker.Database.ReadResult";
-const char kWriteResultHistogramLabel[] =
- "ServiceWorker.Database.WriteResult";
-
bool RemovePrefix(const std::string& str,
const std::string& prefix,
std::string* out) {
@@ -141,6 +134,7 @@ void PutRegistrationDataToBatch(
data.set_is_active(input.is_active);
data.set_has_fetch_handler(input.has_fetch_handler);
data.set_last_update_check_time(input.last_update_check.ToInternalValue());
+ data.set_resources_total_size_bytes(input.resources_total_size_bytes);
std::string value;
bool success = data.SerializeToString(&value);
@@ -154,11 +148,13 @@ void PutResourceRecordToBatch(
int64 version_id,
leveldb::WriteBatch* batch) {
DCHECK(batch);
+ DCHECK_GE(input.size_bytes, 0);
// Convert ResourceRecord to ServiceWorkerResourceRecord.
ServiceWorkerResourceRecord record;
record.set_resource_id(input.resource_id);
record.set_url(input.url.spec());
+ record.set_size_bytes(input.size_bytes);
std::string value;
bool success = record.SerializeToString(&value);
@@ -222,6 +218,9 @@ ServiceWorkerDatabase::Status ParseRegistrationData(
if (!scope_url.is_valid() ||
!script_url.is_valid() ||
scope_url.GetOrigin() != script_url.GetOrigin()) {
+ DLOG(ERROR) << "Scope URL '" << data.scope_url() << "' and/or script url '"
+ << data.script_url()
+ << "' are invalid or have mismatching origins.";
return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED;
}
@@ -234,6 +233,8 @@ ServiceWorkerDatabase::Status ParseRegistrationData(
out->has_fetch_handler = data.has_fetch_handler();
out->last_update_check =
base::Time::FromInternalValue(data.last_update_check_time());
+ out->resources_total_size_bytes = data.resources_total_size_bytes();
+
return ServiceWorkerDatabase::STATUS_OK;
}
@@ -252,6 +253,7 @@ ServiceWorkerDatabase::Status ParseResourceRecord(
// Convert ServiceWorkerResourceRecord to ResourceRecord.
out->resource_id = record.resource_id();
out->url = url;
+ out->size_bytes = record.size_bytes();
return ServiceWorkerDatabase::STATUS_OK;
}
@@ -269,7 +271,10 @@ ServiceWorkerDatabase::Status LevelDBStatusToStatus(
return ServiceWorkerDatabase::STATUS_ERROR_FAILED;
}
-const char* StatusToString(ServiceWorkerDatabase::Status status) {
+} // namespace
+
+const char* ServiceWorkerDatabase::StatusToString(
+ ServiceWorkerDatabase::Status status) {
switch (status) {
case ServiceWorkerDatabase::STATUS_OK:
return "Database OK";
@@ -289,13 +294,12 @@ const char* StatusToString(ServiceWorkerDatabase::Status status) {
return "Database unknown error";
}
-} // namespace
-
ServiceWorkerDatabase::RegistrationData::RegistrationData()
: registration_id(kInvalidServiceWorkerRegistrationId),
version_id(kInvalidServiceWorkerVersionId),
is_active(false),
- has_fetch_handler(false) {
+ has_fetch_handler(false),
+ resources_total_size_bytes(0) {
}
ServiceWorkerDatabase::RegistrationData::~RegistrationData() {
@@ -488,9 +492,12 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistration(
ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration(
const RegistrationData& registration,
const std::vector<ResourceRecord>& resources,
+ RegistrationData* old_registration,
std::vector<int64>* newly_purgeable_resources) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(old_registration);
Status status = LazyOpen(true);
+ old_registration->version_id = kInvalidServiceWorkerVersionId;
if (status != STATUS_OK)
return status;
@@ -499,6 +506,15 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration(
BumpNextVersionIdIfNeeded(registration.version_id, &batch);
PutUniqueOriginToBatch(registration.scope.GetOrigin(), &batch);
+#if DCHECK_IS_ON
+ int64_t total_size_bytes = 0;
+ for (const auto& resource : resources) {
+ total_size_bytes += resource.size_bytes;
+ }
+ DCHECK_EQ(total_size_bytes, registration.resources_total_size_bytes)
+ << "The total size in the registration must match the cumulative "
+ << "sizes of the resources.";
+#endif
PutRegistrationDataToBatch(registration, &batch);
// Used for avoiding multiple writes for the same resource id or url.
@@ -518,19 +534,21 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration(
// Delete a resource from the uncommitted list.
batch.Delete(CreateResourceIdKey(
kUncommittedResIdKeyPrefix, itr->resource_id));
+ // Delete from the purgeable list in case this version was once deleted.
+ batch.Delete(
+ CreateResourceIdKey(kPurgeableResIdKeyPrefix, itr->resource_id));
}
// Retrieve a previous version to sweep purgeable resources.
- RegistrationData old_registration;
status = ReadRegistrationData(registration.registration_id,
registration.scope.GetOrigin(),
- &old_registration);
+ old_registration);
if (status != STATUS_OK && status != STATUS_ERROR_NOT_FOUND)
return status;
if (status == STATUS_OK) {
- DCHECK_LT(old_registration.version_id, registration.version_id);
+ DCHECK_LT(old_registration->version_id, registration.version_id);
status = DeleteResourceRecords(
- old_registration.version_id, newly_purgeable_resources, &batch);
+ old_registration->version_id, newly_purgeable_resources, &batch);
if (status != STATUS_OK)
return status;
@@ -550,7 +568,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::UpdateVersionToActive(
int64 registration_id,
const GURL& origin) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
- ServiceWorkerDatabase::Status status = LazyOpen(false);
+ Status status = LazyOpen(false);
if (IsNewOrNonexistentDatabase(status))
return STATUS_ERROR_NOT_FOUND;
if (status != STATUS_OK)
@@ -575,7 +593,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::UpdateLastCheckTime(
const GURL& origin,
const base::Time& time) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
- ServiceWorkerDatabase::Status status = LazyOpen(false);
+ Status status = LazyOpen(false);
if (IsNewOrNonexistentDatabase(status))
return STATUS_ERROR_NOT_FOUND;
if (status != STATUS_OK)
@@ -598,8 +616,11 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::UpdateLastCheckTime(
ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration(
int64 registration_id,
const GURL& origin,
+ RegistrationData* deleted_version,
std::vector<int64>* newly_purgeable_resources) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+ DCHECK(deleted_version);
+ deleted_version->version_id = kInvalidServiceWorkerVersionId;
Status status = LazyOpen(false);
if (IsNewOrNonexistentDatabase(status))
return STATUS_OK;
@@ -627,11 +648,11 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration(
batch.Delete(CreateRegistrationKey(registration_id, origin));
// Delete resource records associated with the registration.
- for (std::vector<RegistrationData>::const_iterator itr =
- registrations.begin(); itr != registrations.end(); ++itr) {
- if (itr->registration_id == registration_id) {
+ for (const auto& registration : registrations) {
+ if (registration.registration_id == registration_id) {
+ *deleted_version = registration;
status = DeleteResourceRecords(
- itr->version_id, newly_purgeable_resources, &batch);
+ registration.version_id, newly_purgeable_resources, &batch);
if (status != STATUS_OK)
return status;
break;
@@ -685,8 +706,8 @@ ServiceWorkerDatabase::PurgeUncommittedResourceIds(
return WriteBatch(&batch);
}
-ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigin(
- const GURL& origin,
+ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigins(
+ const std::set<GURL>& origins,
std::vector<int64>* newly_purgeable_resources) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
Status status = LazyOpen(false);
@@ -694,27 +715,28 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigin(
return STATUS_OK;
if (status != STATUS_OK)
return status;
- if (!origin.is_valid())
- return STATUS_ERROR_FAILED;
-
leveldb::WriteBatch batch;
- // Delete from the unique origin list.
- batch.Delete(CreateUniqueOriginKey(origin));
+ for (const GURL& origin : origins) {
+ if (!origin.is_valid())
+ return STATUS_ERROR_FAILED;
- std::vector<RegistrationData> registrations;
- status = GetRegistrationsForOrigin(origin, &registrations);
- if (status != STATUS_OK)
- return status;
+ // Delete from the unique origin list.
+ batch.Delete(CreateUniqueOriginKey(origin));
- // Delete registrations and resource records.
- for (std::vector<RegistrationData>::const_iterator itr =
- registrations.begin(); itr != registrations.end(); ++itr) {
- batch.Delete(CreateRegistrationKey(itr->registration_id, origin));
- status = DeleteResourceRecords(
- itr->version_id, newly_purgeable_resources, &batch);
+ std::vector<RegistrationData> registrations;
+ status = GetRegistrationsForOrigin(origin, &registrations);
if (status != STATUS_OK)
return status;
+
+ // Delete registrations and resource records.
+ for (const RegistrationData& data : registrations) {
+ batch.Delete(CreateRegistrationKey(data.registration_id, origin));
+ status = DeleteResourceRecords(
+ data.version_id, newly_purgeable_resources, &batch);
+ if (status != STATUS_OK)
+ return status;
+ }
}
return WriteBatch(&batch);
@@ -723,8 +745,19 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigin(
ServiceWorkerDatabase::Status ServiceWorkerDatabase::DestroyDatabase() {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
Disable(FROM_HERE, STATUS_OK);
+
+ leveldb::Options options;
+ if (path_.empty()) {
+ if (env_) {
+ options.env = env_.get();
+ } else {
+ // In-memory database not initialized.
+ return STATUS_OK;
+ }
+ }
+
return LevelDBStatusToStatus(
- leveldb::DestroyDB(path_.AsUTF8Unsafe(), leveldb::Options()));
+ leveldb::DestroyDB(path_.AsUTF8Unsafe(), options));
}
ServiceWorkerDatabase::Status ServiceWorkerDatabase::LazyOpen(
@@ -969,11 +1002,15 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteResourceIdsInBatch(
if (status != STATUS_OK)
return status;
+ if (ids.empty())
+ return STATUS_OK;
for (std::set<int64>::const_iterator itr = ids.begin();
itr != ids.end(); ++itr) {
// Value should be empty.
batch->Put(CreateResourceIdKey(id_key_prefix, *itr), "");
}
+ // std::set is sorted, so the last element is the largest.
+ BumpNextResourceIdIfNeeded(*ids.rbegin(), batch);
return STATUS_OK;
}
@@ -1055,6 +1092,15 @@ void ServiceWorkerDatabase::BumpNextRegistrationIdIfNeeded(
}
}
+void ServiceWorkerDatabase::BumpNextResourceIdIfNeeded(
+ int64 used_id, leveldb::WriteBatch* batch) {
+ DCHECK(batch);
+ if (next_avail_resource_id_ <= used_id) {
+ next_avail_resource_id_ = used_id + 1;
+ batch->Put(kNextResIdKey, base::Int64ToString(next_avail_resource_id_));
+ }
+}
+
void ServiceWorkerDatabase::BumpNextVersionIdIfNeeded(
int64 used_id, leveldb::WriteBatch* batch) {
DCHECK(batch);
@@ -1083,31 +1129,25 @@ void ServiceWorkerDatabase::Disable(
void ServiceWorkerDatabase::HandleOpenResult(
const tracked_objects::Location& from_here,
Status status) {
- if (status != ServiceWorkerDatabase::STATUS_OK)
+ if (status != STATUS_OK)
Disable(from_here, status);
- UMA_HISTOGRAM_ENUMERATION(kOpenResultHistogramLabel,
- status,
- ServiceWorkerDatabase::STATUS_ERROR_MAX);
+ ServiceWorkerMetrics::CountOpenDatabaseResult(status);
}
void ServiceWorkerDatabase::HandleReadResult(
const tracked_objects::Location& from_here,
Status status) {
- if (status != ServiceWorkerDatabase::STATUS_OK)
+ if (status != STATUS_OK)
Disable(from_here, status);
- UMA_HISTOGRAM_ENUMERATION(kReadResultHistogramLabel,
- status,
- ServiceWorkerDatabase::STATUS_ERROR_MAX);
+ ServiceWorkerMetrics::CountReadDatabaseResult(status);
}
void ServiceWorkerDatabase::HandleWriteResult(
const tracked_objects::Location& from_here,
Status status) {
- if (status != ServiceWorkerDatabase::STATUS_OK)
+ if (status != STATUS_OK)
Disable(from_here, status);
- UMA_HISTOGRAM_ENUMERATION(kWriteResultHistogramLabel,
- status,
- ServiceWorkerDatabase::STATUS_ERROR_MAX);
+ ServiceWorkerMetrics::CountWriteDatabaseResult(status);
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_database.h b/chromium/content/browser/service_worker/service_worker_database.h
index 6475de04a99..96283c95bd6 100644
--- a/chromium/content/browser/service_worker/service_worker_database.h
+++ b/chromium/content/browser/service_worker/service_worker_database.h
@@ -48,21 +48,25 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
STATUS_ERROR_FAILED,
STATUS_ERROR_MAX,
};
+ static const char* StatusToString(Status status);
struct CONTENT_EXPORT RegistrationData {
// These values are immutable for the life of a registration.
int64 registration_id;
GURL scope;
- GURL script;
// Versions are first stored once they successfully install and become
// the waiting version. Then transition to the active version. The stored
- // version may be in the ACTIVE state or in the INSTALLED state.
+ // version may be in the ACTIVATED state or in the INSTALLED state.
+ GURL script;
int64 version_id;
bool is_active;
bool has_fetch_handler;
base::Time last_update_check;
+ // Not populated until ServiceWorkerStorage::StoreRegistration is called.
+ int64_t resources_total_size_bytes;
+
RegistrationData();
~RegistrationData();
};
@@ -70,9 +74,13 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
struct ResourceRecord {
int64 resource_id;
GURL url;
+ // Signed so we can store -1 to specify an unknown or error state. When
+ // stored to the database, this value should always be >= 0.
+ int64 size_bytes;
- ResourceRecord() {}
- ResourceRecord(int64 id, GURL url) : resource_id(id), url(url) {}
+ ResourceRecord() : resource_id(-1), size_bytes(0) {}
+ ResourceRecord(int64 id, GURL url, int64 size_bytes)
+ : resource_id(id), url(url), size_bytes(size_bytes) {}
};
// Reads next available ids from the database. Returns OK if they are
@@ -114,14 +122,17 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
// Writes |registration| and |resources| into the database and does following
// things:
- // - Deletes an old version of the registration if exists.
+ // - If an old version of the registration exists, deletes it and sets
+ // |deleted_version| to the old version registration data object
+ // |newly_purgeable_resources| to its resources. Otherwise, sets
+ // |deleted_version->version_id| to -1.
// - Bumps the next registration id and the next version id if needed.
// - Removes |resources| from the uncommitted list if exist.
// Returns OK they are successfully written. Otherwise, returns an error.
- Status WriteRegistration(
- const RegistrationData& registration,
- const std::vector<ResourceRecord>& resources,
- std::vector<int64>* newly_purgeable_resources);
+ Status WriteRegistration(const RegistrationData& registration,
+ const std::vector<ResourceRecord>& resources,
+ RegistrationData* deleted_version,
+ std::vector<int64>* newly_purgeable_resources);
// Updates a registration for |registration_id| to an active state. Returns OK
// if it's successfully updated. Otherwise, returns an error.
@@ -137,12 +148,15 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
const base::Time& time);
// Deletes a registration for |registration_id| and moves resource records
- // associated with it into the purgeable list. Returns OK if it's successfully
- // deleted or not found in the database. Otherwise, returns an error.
- Status DeleteRegistration(
- int64 registration_id,
- const GURL& origin,
- std::vector<int64>* newly_purgeable_resources);
+ // associated with it into the purgeable list. If deletion occurred, sets
+ // |version_id| to the id of the version that was deleted and
+ // |newly_purgeable_resources| to its resources; otherwise, sets |version_id|
+ // to -1. Returns OK if it's successfully deleted or not found in the
+ // database. Otherwise, returns an error.
+ Status DeleteRegistration(int64 registration_id,
+ const GURL& origin,
+ RegistrationData* deleted_version,
+ std::vector<int64>* newly_purgeable_resources);
// As new resources are put into the diskcache, they go into an uncommitted
// list. When a registration is saved that refers to those ids, they're
@@ -179,13 +193,12 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
// Returns OK on success. Otherwise deletes nothing and returns an error.
Status PurgeUncommittedResourceIds(const std::set<int64>& ids);
- // Deletes all data for |origin|, namely, unique origin, registrations and
+ // Deletes all data for |origins|, namely, unique origin, registrations and
// resource records. Resources are moved to the purgeable list. Returns OK if
// they are successfully deleted or not found in the database. Otherwise,
// returns an error.
- Status DeleteAllDataForOrigin(
- const GURL& origin,
- std::vector<int64>* newly_purgeable_resources);
+ Status DeleteAllDataForOrigins(const std::set<GURL>& origins,
+ std::vector<int64>* newly_purgeable_resources);
// Completely deletes the contents of the database.
// Be careful using this function.
@@ -274,6 +287,9 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
void BumpNextRegistrationIdIfNeeded(
int64 used_id,
leveldb::WriteBatch* batch);
+ void BumpNextResourceIdIfNeeded(
+ int64 used_id,
+ leveldb::WriteBatch* batch);
void BumpNextVersionIdIfNeeded(
int64 used_id,
leveldb::WriteBatch* batch);
diff --git a/chromium/content/browser/service_worker/service_worker_database.proto b/chromium/content/browser/service_worker/service_worker_database.proto
index c2223ecdd76..bb4acef1fbf 100644
--- a/chromium/content/browser/service_worker/service_worker_database.proto
+++ b/chromium/content/browser/service_worker/service_worker_database.proto
@@ -23,9 +23,12 @@ message ServiceWorkerRegistrationData {
// Serialized by Time::ToInternalValue().
required int64 last_update_check_time = 7;
+
+ optional uint64 resources_total_size_bytes = 8;
}
message ServiceWorkerResourceRecord {
required int64 resource_id = 1;
required string url = 2;
+ optional uint64 size_bytes = 3;
}
diff --git a/chromium/content/browser/service_worker/service_worker_database_task_manager.cc b/chromium/content/browser/service_worker/service_worker_database_task_manager.cc
new file mode 100644
index 00000000000..be7f4d0e796
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_database_task_manager.cc
@@ -0,0 +1,71 @@
+// 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 "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "content/browser/service_worker/service_worker_database_task_manager.h"
+
+namespace content {
+
+ServiceWorkerDatabaseTaskManagerImpl::ServiceWorkerDatabaseTaskManagerImpl(
+ base::SequencedWorkerPool* pool) {
+ base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken();
+ task_runner_ = pool->GetSequencedTaskRunner(token);
+ shutdown_blocking_task_runner_ =
+ pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ token, base::SequencedWorkerPool::BLOCK_SHUTDOWN);
+}
+
+ServiceWorkerDatabaseTaskManagerImpl::~ServiceWorkerDatabaseTaskManagerImpl() {
+}
+
+scoped_ptr<ServiceWorkerDatabaseTaskManager>
+ServiceWorkerDatabaseTaskManagerImpl::Clone() {
+ return make_scoped_ptr(new ServiceWorkerDatabaseTaskManagerImpl(
+ task_runner_, shutdown_blocking_task_runner_));
+}
+
+base::SequencedTaskRunner*
+ServiceWorkerDatabaseTaskManagerImpl::GetTaskRunner() {
+ return task_runner_.get();
+}
+
+base::SequencedTaskRunner*
+ServiceWorkerDatabaseTaskManagerImpl::GetShutdownBlockingTaskRunner() {
+ return shutdown_blocking_task_runner_.get();
+}
+
+ServiceWorkerDatabaseTaskManagerImpl::ServiceWorkerDatabaseTaskManagerImpl(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+ const scoped_refptr<base::SequencedTaskRunner>&
+ shutdown_blocking_task_runner)
+ : task_runner_(task_runner),
+ shutdown_blocking_task_runner_(shutdown_blocking_task_runner) {
+}
+
+MockServiceWorkerDatabaseTaskManager::MockServiceWorkerDatabaseTaskManager(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+ : task_runner_(task_runner) {
+}
+
+MockServiceWorkerDatabaseTaskManager::~MockServiceWorkerDatabaseTaskManager() {
+}
+
+scoped_ptr<ServiceWorkerDatabaseTaskManager>
+MockServiceWorkerDatabaseTaskManager::Clone() {
+ return make_scoped_ptr(
+ new MockServiceWorkerDatabaseTaskManager(task_runner_));
+}
+
+base::SequencedTaskRunner*
+MockServiceWorkerDatabaseTaskManager::GetTaskRunner() {
+ return task_runner_.get();
+}
+
+base::SequencedTaskRunner*
+MockServiceWorkerDatabaseTaskManager::GetShutdownBlockingTaskRunner() {
+ return task_runner_.get();
+}
+
+} // namespace content
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
new file mode 100644
index 00000000000..fdf13f97228
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_database_task_manager.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_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_RUNNER_MANAGER_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_RUNNER_MANAGER_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace content {
+
+// Used to sequence ServiceWorkerDatabase tasks. Vends two task runners: one
+// that blocks shutdown and one that doesn't. The task runners use the same
+// sequence token, so no matter which runner you post to, the tasks run in the
+// order they are posted. This lets you post sequenced tasks with mixed shutdown
+// behaviors.
+class ServiceWorkerDatabaseTaskManager {
+ public:
+ virtual ~ServiceWorkerDatabaseTaskManager(){};
+ virtual scoped_ptr<ServiceWorkerDatabaseTaskManager> Clone() = 0;
+ virtual base::SequencedTaskRunner* GetTaskRunner() = 0;
+ virtual base::SequencedTaskRunner* GetShutdownBlockingTaskRunner() = 0;
+};
+
+class ServiceWorkerDatabaseTaskManagerImpl
+ : public ServiceWorkerDatabaseTaskManager {
+ public:
+ explicit ServiceWorkerDatabaseTaskManagerImpl(
+ base::SequencedWorkerPool* pool);
+ ~ServiceWorkerDatabaseTaskManagerImpl() override;
+
+ protected:
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> Clone() override;
+ base::SequencedTaskRunner* GetTaskRunner() override;
+ base::SequencedTaskRunner* GetShutdownBlockingTaskRunner() override;
+
+ private:
+ ServiceWorkerDatabaseTaskManagerImpl(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+ const scoped_refptr<base::SequencedTaskRunner>&
+ shutdown_blocking_task_runner);
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> shutdown_blocking_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDatabaseTaskManagerImpl);
+};
+
+// Dummy implementation for testing. It vends whatever you give it in the ctor.
+class CONTENT_EXPORT MockServiceWorkerDatabaseTaskManager
+ : public NON_EXPORTED_BASE(ServiceWorkerDatabaseTaskManager) {
+ public:
+ explicit MockServiceWorkerDatabaseTaskManager(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+ ~MockServiceWorkerDatabaseTaskManager() override;
+
+ protected:
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> Clone() override;
+ base::SequencedTaskRunner* GetTaskRunner() override;
+ base::SequencedTaskRunner* GetShutdownBlockingTaskRunner() override;
+
+ private:
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockServiceWorkerDatabaseTaskManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DATABASE_TASK_RUNNER_MANAGER_
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 baa2542cbc1..0e052f5ff20 100644
--- a/chromium/content/browser/service_worker/service_worker_database_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_database_unittest.cc
@@ -6,10 +6,11 @@
#include <string>
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/stl_util.h"
#include "content/browser/service_worker/service_worker_database.pb.h"
+#include "content/common/service_worker/service_worker_types.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -36,12 +37,9 @@ GURL URL(const GURL& origin, const std::string& path) {
return out;
}
-Resource CreateResource(int64 resource_id, const GURL& url) {
+Resource CreateResource(int64 resource_id, const GURL& url, uint64 size_bytes) {
EXPECT_TRUE(url.is_valid());
- Resource resource;
- resource.resource_id = resource_id;
- resource.url = url;
- return resource;
+ return Resource(resource_id, url, size_bytes);
}
ServiceWorkerDatabase* CreateDatabase(const base::FilePath& path) {
@@ -61,6 +59,8 @@ void VerifyRegistrationData(const RegistrationData& expected,
EXPECT_EQ(expected.is_active, actual.is_active);
EXPECT_EQ(expected.has_fetch_handler, actual.has_fetch_handler);
EXPECT_EQ(expected.last_update_check, actual.last_update_check);
+ EXPECT_EQ(expected.resources_total_size_bytes,
+ actual.resources_total_size_bytes);
}
void VerifyResourceRecords(const std::vector<Resource>& expected,
@@ -69,6 +69,7 @@ void VerifyResourceRecords(const std::vector<Resource>& expected,
for (size_t i = 0; i < expected.size(); ++i) {
EXPECT_EQ(expected[i].resource_id, actual[i].resource_id);
EXPECT_EQ(expected[i].url, actual[i].url);
+ EXPECT_EQ(expected[i].size_bytes, actual[i].size_bytes);
}
}
@@ -119,11 +120,12 @@ TEST(ServiceWorkerDatabaseTest, DatabaseVersion) {
// First writing triggers database initialization and bumps the schema
// version.
std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
ServiceWorkerDatabase::RegistrationData data;
ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data, resources,
- &newly_purgeable_resources));
+ database->WriteRegistration(
+ data, resources, &deleted_version, &newly_purgeable_resources));
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
database->ReadDatabaseVersion(&db_version));
@@ -156,14 +158,16 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
// Writing a registration bumps the next available ids.
std::vector<Resource> resources;
RegistrationData data1;
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
data1.registration_id = 100;
data1.scope = URL(origin, "/foo");
data1.script = URL(origin, "/script1.js");
data1.version_id = 200;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data1, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data1, resources, &deleted_version, &newly_purgeable_resources));
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->GetNextAvailableIds(
&ids.reg_id, &ids.ver_id, &ids.res_id));
@@ -171,6 +175,31 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
EXPECT_EQ(201, ids.ver_id);
EXPECT_EQ(0, ids.res_id);
+ // Writing uncommitted resources bumps the next available id.
+ const int64 kUncommittedIds[] = {0, 1, 3, 5, 6, 10};
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUncommittedResourceIds(std::set<int64>(
+ kUncommittedIds, kUncommittedIds + arraysize(kUncommittedIds))));
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->GetNextAvailableIds(&ids.reg_id, &ids.ver_id, &ids.res_id));
+ EXPECT_EQ(101, ids.reg_id);
+ EXPECT_EQ(201, ids.ver_id);
+ EXPECT_EQ(11, ids.res_id);
+
+ // Writing purgeable resources bumps the next available id.
+ const int64 kPurgeableIds[] = {4, 12, 16, 17, 20};
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUncommittedResourceIds(std::set<int64>(
+ kPurgeableIds, kPurgeableIds + arraysize(kPurgeableIds))));
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->GetNextAvailableIds(&ids.reg_id, &ids.ver_id, &ids.res_id));
+ EXPECT_EQ(101, ids.reg_id);
+ EXPECT_EQ(201, ids.ver_id);
+ EXPECT_EQ(21, ids.res_id);
+
// Writing a registration whose ids are lower than the stored ones should not
// bump the next available ids.
RegistrationData data2;
@@ -178,9 +207,16 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
data2.scope = URL(origin, "/bar");
data2.script = URL(origin, "/script2.js");
data2.version_id = 20;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data2, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data2, resources, &deleted_version, &newly_purgeable_resources));
+
+ // Same with resources.
+ int64 kLowResourceId = 15;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteUncommittedResourceIds(
+ std::set<int64>(&kLowResourceId, &kLowResourceId + 1)));
// Close and reopen the database to verify the stored values.
database.reset(CreateDatabase(database_dir.path()));
@@ -189,7 +225,7 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
&ids.reg_id, &ids.ver_id, &ids.res_id));
EXPECT_EQ(101, ids.reg_id);
EXPECT_EQ(201, ids.ver_id);
- EXPECT_EQ(0, ids.res_id);
+ EXPECT_EQ(21, ids.res_id);
}
TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
@@ -201,6 +237,7 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
EXPECT_TRUE(origins.empty());
std::vector<Resource> resources;
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
GURL origin1("http://example.com");
@@ -209,9 +246,10 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
data1.scope = URL(origin1, "/foo");
data1.script = URL(origin1, "/script1.js");
data1.version_id = 456;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data1, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data1, resources, &deleted_version, &newly_purgeable_resources));
GURL origin2("https://www.example.com");
RegistrationData data2;
@@ -219,9 +257,10 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
data2.scope = URL(origin2, "/bar");
data2.script = URL(origin2, "/script2.js");
data2.version_id = 567;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data2, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data2, resources, &deleted_version, &newly_purgeable_resources));
GURL origin3("https://example.org");
RegistrationData data3;
@@ -229,9 +268,10 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
data3.scope = URL(origin3, "/hoge");
data3.script = URL(origin3, "/script3.js");
data3.version_id = 678;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data3, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data3, resources, &deleted_version, &newly_purgeable_resources));
// |origin3| has two registrations.
RegistrationData data4;
@@ -239,9 +279,10 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
data4.scope = URL(origin3, "/fuga");
data4.script = URL(origin3, "/script4.js");
data4.version_id = 789;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data4, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data4, resources, &deleted_version, &newly_purgeable_resources));
origins.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -254,8 +295,11 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
// |origin3| has another registration, so should not remove it from the
// unique origin list.
ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->DeleteRegistration(data4.registration_id, origin3,
+ database->DeleteRegistration(data4.registration_id,
+ origin3,
+ &deleted_version,
&newly_purgeable_resources));
+ EXPECT_EQ(data4.registration_id, deleted_version.registration_id);
origins.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -267,8 +311,11 @@ TEST(ServiceWorkerDatabaseTest, GetOriginsWithRegistrations) {
// |origin3| should be removed from the unique origin list.
ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->DeleteRegistration(data3.registration_id, origin3,
+ database->DeleteRegistration(data3.registration_id,
+ origin3,
+ &deleted_version,
&newly_purgeable_resources));
+ EXPECT_EQ(data3.registration_id, deleted_version.registration_id);
origins.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -291,6 +338,7 @@ TEST(ServiceWorkerDatabaseTest, GetRegistrationsForOrigin) {
EXPECT_TRUE(registrations.empty());
std::vector<Resource> resources;
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
RegistrationData data1;
@@ -298,27 +346,30 @@ TEST(ServiceWorkerDatabaseTest, GetRegistrationsForOrigin) {
data1.scope = URL(origin1, "/foo");
data1.script = URL(origin1, "/script1.js");
data1.version_id = 1000;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data1, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data1, resources, &deleted_version, &newly_purgeable_resources));
RegistrationData data2;
data2.registration_id = 200;
data2.scope = URL(origin2, "/bar");
data2.script = URL(origin2, "/script2.js");
data2.version_id = 2000;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data2, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data2, resources, &deleted_version, &newly_purgeable_resources));
RegistrationData data3;
data3.registration_id = 300;
data3.scope = URL(origin3, "/hoge");
data3.script = URL(origin3, "/script3.js");
data3.version_id = 3000;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data3, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data3, resources, &deleted_version, &newly_purgeable_resources));
// |origin3| has two registrations.
RegistrationData data4;
@@ -326,9 +377,10 @@ TEST(ServiceWorkerDatabaseTest, GetRegistrationsForOrigin) {
data4.scope = URL(origin3, "/fuga");
data4.script = URL(origin3, "/script4.js");
data4.version_id = 4000;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data4, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data4, resources, &deleted_version, &newly_purgeable_resources));
registrations.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -347,6 +399,7 @@ TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) {
EXPECT_TRUE(registrations.empty());
std::vector<Resource> resources;
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
GURL origin1("http://www1.example.com");
@@ -355,9 +408,10 @@ TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) {
data1.scope = URL(origin1, "/foo");
data1.script = URL(origin1, "/script1.js");
data1.version_id = 1000;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data1, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data1, resources, &deleted_version, &newly_purgeable_resources));
GURL origin2("http://www2.example.com");
RegistrationData data2;
@@ -365,9 +419,10 @@ TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) {
data2.scope = URL(origin2, "/bar");
data2.script = URL(origin2, "/script2.js");
data2.version_id = 2000;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data2, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data2, resources, &deleted_version, &newly_purgeable_resources));
GURL origin3("http://www3.example.com");
RegistrationData data3;
@@ -375,9 +430,10 @@ TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) {
data3.scope = URL(origin3, "/hoge");
data3.script = URL(origin3, "/script3.js");
data3.version_id = 3000;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data3, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data3, resources, &deleted_version, &newly_purgeable_resources));
// |origin3| has two registrations.
RegistrationData data4;
@@ -385,9 +441,10 @@ TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) {
data4.scope = URL(origin3, "/fuga");
data4.script = URL(origin3, "/script4.js");
data4.version_id = 4000;
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data4, resources,
- &newly_purgeable_resources));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data4, resources, &deleted_version, &newly_purgeable_resources));
registrations.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
@@ -408,10 +465,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) {
data.scope = URL(origin, "/foo");
data.script = URL(origin, "/script.js");
data.version_id = 200;
+ data.resources_total_size_bytes = 10939 + 200;
std::vector<Resource> resources;
- resources.push_back(CreateResource(1, URL(origin, "/resource1")));
- resources.push_back(CreateResource(2, URL(origin, "/resource2")));
+ resources.push_back(CreateResource(1, URL(origin, "/resource1"), 10939));
+ resources.push_back(CreateResource(2, URL(origin, "/resource2"), 200));
// Write a resource to the uncommitted list to make sure that writing
// registration removes resource ids associated with the registration from
@@ -425,10 +483,15 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) {
database->GetUncommittedResourceIds(&uncommitted_ids_out));
EXPECT_EQ(uncommitted_ids, uncommitted_ids_out);
+ ServiceWorkerDatabase::RegistrationData deleted_version;
+ deleted_version.version_id = 222; // Dummy initial value
std::vector<int64> newly_purgeable_resources;
+
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data, resources,
- &newly_purgeable_resources));
+ database->WriteRegistration(
+ data, resources, &deleted_version, &newly_purgeable_resources));
+ EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id);
+ EXPECT_TRUE(newly_purgeable_resources.empty());
// Make sure that the registration and resource records are stored.
RegistrationData data_out;
@@ -446,8 +509,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) {
EXPECT_TRUE(uncommitted_ids_out.empty());
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->DeleteRegistration(data.registration_id, origin,
+ database->DeleteRegistration(data.registration_id,
+ origin,
+ &deleted_version,
&newly_purgeable_resources));
+ EXPECT_EQ(data.version_id, deleted_version.version_id);
ASSERT_EQ(resources.size(), newly_purgeable_resources.size());
for (size_t i = 0; i < resources.size(); ++i)
EXPECT_EQ(newly_purgeable_resources[i], resources[i].resource_id);
@@ -468,6 +534,56 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) {
EXPECT_TRUE(ContainsKey(purgeable_ids_out, resources[1].resource_id));
}
+TEST(ServiceWorkerDatabaseTest, DeleteNonExistentRegistration) {
+ scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+
+ GURL origin("http://example.com");
+ RegistrationData data;
+ data.registration_id = 100;
+ data.scope = URL(origin, "/foo");
+ data.script = URL(origin, "/script.js");
+ data.version_id = 200;
+ data.resources_total_size_bytes = 19 + 29129;
+
+ std::vector<Resource> resources;
+ resources.push_back(CreateResource(1, URL(origin, "/resource1"), 19));
+ resources.push_back(CreateResource(2, URL(origin, "/resource2"), 29129));
+
+ const int64 kNonExistentRegistrationId = 999;
+ const int64 kArbitraryVersionId = 222; // Used as a dummy initial value
+
+ ServiceWorkerDatabase::RegistrationData deleted_version;
+ deleted_version.version_id = kArbitraryVersionId;
+ std::vector<int64> newly_purgeable_resources;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data, resources, &deleted_version, &newly_purgeable_resources));
+ EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id);
+ EXPECT_TRUE(newly_purgeable_resources.empty());
+
+ // Delete from an origin that has a registration.
+ deleted_version.version_id = kArbitraryVersionId;
+ newly_purgeable_resources.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteRegistration(kNonExistentRegistrationId,
+ origin,
+ &deleted_version,
+ &newly_purgeable_resources));
+ EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id);
+ EXPECT_TRUE(newly_purgeable_resources.empty());
+
+ // Delete from an origin that has no registration.
+ deleted_version.version_id = kArbitraryVersionId;
+ newly_purgeable_resources.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ database->DeleteRegistration(kNonExistentRegistrationId,
+ GURL("http://example.net"),
+ &deleted_version,
+ &newly_purgeable_resources));
+ EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id);
+ EXPECT_TRUE(newly_purgeable_resources.empty());
+}
+
TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) {
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
@@ -477,15 +593,21 @@ TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) {
data.scope = URL(origin, "/foo");
data.script = URL(origin, "/script.js");
data.version_id = 200;
+ data.resources_total_size_bytes = 10 + 11;
std::vector<Resource> resources1;
- resources1.push_back(CreateResource(1, URL(origin, "/resource1")));
- resources1.push_back(CreateResource(2, URL(origin, "/resource2")));
+ resources1.push_back(CreateResource(1, URL(origin, "/resource1"), 10));
+ resources1.push_back(CreateResource(2, URL(origin, "/resource2"), 11));
+
+ ServiceWorkerDatabase::RegistrationData deleted_version;
+ deleted_version.version_id = 222; // Dummy inital value
std::vector<int64> newly_purgeable_resources;
- EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data, resources1,
- &newly_purgeable_resources));
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data, resources1, &deleted_version, &newly_purgeable_resources));
+ EXPECT_EQ(kInvalidServiceWorkerVersionId, deleted_version.version_id);
EXPECT_TRUE(newly_purgeable_resources.empty());
// Make sure that the registration and resource records are stored.
@@ -499,15 +621,19 @@ TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) {
// Update the registration.
RegistrationData updated_data = data;
updated_data.version_id = data.version_id + 1;
+ updated_data.resources_total_size_bytes = 12 + 13;
std::vector<Resource> resources2;
- resources2.push_back(CreateResource(3, URL(origin, "/resource3")));
- resources2.push_back(CreateResource(4, URL(origin, "/resource4")));
+ resources2.push_back(CreateResource(3, URL(origin, "/resource3"), 12));
+ resources2.push_back(CreateResource(4, URL(origin, "/resource4"), 13));
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(updated_data, resources2,
+ database->WriteRegistration(updated_data,
+ resources2,
+ &deleted_version,
&newly_purgeable_resources));
+ EXPECT_EQ(data.version_id, deleted_version.version_id);
ASSERT_EQ(resources1.size(), newly_purgeable_resources.size());
- for(size_t i = 0; i < resources1.size(); ++i)
+ for (size_t i = 0; i < resources1.size(); ++i)
EXPECT_EQ(newly_purgeable_resources[i], resources1[i].resource_id);
// Make sure that |updated_data| is stored and resources referred from |data|
@@ -530,6 +656,7 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
GURL origin("http://example.com");
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
// Add registration1.
@@ -538,13 +665,15 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
data1.scope = URL(origin, "/foo");
data1.script = URL(origin, "/script1.js");
data1.version_id = 200;
+ data1.resources_total_size_bytes = 1451 + 15234;
std::vector<Resource> resources1;
- resources1.push_back(CreateResource(1, URL(origin, "/resource1")));
- resources1.push_back(CreateResource(2, URL(origin, "/resource2")));
- EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data1, resources1,
- &newly_purgeable_resources));
+ resources1.push_back(CreateResource(1, URL(origin, "/resource1"), 1451));
+ resources1.push_back(CreateResource(2, URL(origin, "/resource2"), 15234));
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data1, resources1, &deleted_version, &newly_purgeable_resources));
// Add registration2.
RegistrationData data2;
@@ -552,13 +681,15 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
data2.scope = URL(origin, "/bar");
data2.script = URL(origin, "/script2.js");
data2.version_id = 201;
+ data2.resources_total_size_bytes = 5 + 6;
std::vector<Resource> resources2;
- resources2.push_back(CreateResource(3, URL(origin, "/resource3")));
- resources2.push_back(CreateResource(4, URL(origin, "/resource4")));
- EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data2, resources2,
- &newly_purgeable_resources));
+ resources2.push_back(CreateResource(3, URL(origin, "/resource3"), 5));
+ resources2.push_back(CreateResource(4, URL(origin, "/resource4"), 6));
+ EXPECT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data2, resources2, &deleted_version, &newly_purgeable_resources));
// Make sure that registration1 is stored.
RegistrationData data_out;
@@ -582,8 +713,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
// Delete registration1.
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->DeleteRegistration(data1.registration_id, origin,
+ database->DeleteRegistration(data1.registration_id,
+ origin,
+ &deleted_version,
&newly_purgeable_resources));
+ EXPECT_EQ(data1.registration_id, deleted_version.registration_id);
// Make sure that registration1 is gone.
resources_out.clear();
@@ -611,6 +745,7 @@ TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
GURL origin("http://example.com");
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
// Should be false because a registration does not exist.
@@ -625,7 +760,9 @@ TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
data.version_id = 200;
data.is_active = false;
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data, std::vector<Resource>(),
+ database->WriteRegistration(data,
+ std::vector<Resource>(),
+ &deleted_version,
&newly_purgeable_resources));
// Make sure that the registration is stored.
@@ -653,8 +790,11 @@ TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
// Delete the registration.
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->DeleteRegistration(data.registration_id, origin,
+ database->DeleteRegistration(data.registration_id,
+ origin,
+ &deleted_version,
&newly_purgeable_resources));
+ EXPECT_EQ(data.registration_id, deleted_version.registration_id);
// Should be false because the registration is gone.
EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
@@ -664,6 +804,7 @@ TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) {
TEST(ServiceWorkerDatabaseTest, UpdateLastCheckTime) {
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
GURL origin("http://example.com");
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
// Should be false because a registration does not exist.
@@ -678,7 +819,9 @@ TEST(ServiceWorkerDatabaseTest, UpdateLastCheckTime) {
data.version_id = 200;
data.last_update_check = base::Time::Now();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data, std::vector<Resource>(),
+ database->WriteRegistration(data,
+ std::vector<Resource>(),
+ &deleted_version,
&newly_purgeable_resources));
// Make sure that the registration is stored.
@@ -708,8 +851,11 @@ TEST(ServiceWorkerDatabaseTest, UpdateLastCheckTime) {
// Delete the registration.
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->DeleteRegistration(data.registration_id, origin,
+ database->DeleteRegistration(data.registration_id,
+ origin,
+ &deleted_version,
&newly_purgeable_resources));
+ EXPECT_EQ(data.registration_id, deleted_version.registration_id);
// Should be false because the registration is gone.
EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND,
@@ -805,6 +951,7 @@ TEST(ServiceWorkerDatabaseTest, PurgeableResourceIds) {
TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
// Data associated with |origin1| will be removed.
@@ -817,26 +964,30 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
data1.scope = URL(origin1, "/foo");
data1.script = URL(origin1, "/script1.js");
data1.version_id = 100;
+ data1.resources_total_size_bytes = 2013 + 512;
std::vector<Resource> resources1;
- resources1.push_back(CreateResource(1, URL(origin1, "/resource1")));
- resources1.push_back(CreateResource(2, URL(origin1, "/resource2")));
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data1, resources1,
- &newly_purgeable_resources));
+ resources1.push_back(CreateResource(1, URL(origin1, "/resource1"), 2013));
+ resources1.push_back(CreateResource(2, URL(origin1, "/resource2"), 512));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data1, resources1, &deleted_version, &newly_purgeable_resources));
RegistrationData data2;
data2.registration_id = 11;
data2.scope = URL(origin1, "/bar");
data2.script = URL(origin1, "/script2.js");
data2.version_id = 101;
+ data2.resources_total_size_bytes = 4 + 5;
std::vector<Resource> resources2;
- resources2.push_back(CreateResource(3, URL(origin1, "/resource3")));
- resources2.push_back(CreateResource(4, URL(origin1, "/resource4")));
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data2, resources2,
- &newly_purgeable_resources));
+ resources2.push_back(CreateResource(3, URL(origin1, "/resource3"), 4));
+ resources2.push_back(CreateResource(4, URL(origin1, "/resource4"), 5));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data2, resources2, &deleted_version, &newly_purgeable_resources));
// |origin2| has one registration.
RegistrationData data3;
@@ -844,17 +995,21 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
data3.scope = URL(origin2, "/hoge");
data3.script = URL(origin2, "/script3.js");
data3.version_id = 102;
+ data3.resources_total_size_bytes = 6 + 7;
std::vector<Resource> resources3;
- resources3.push_back(CreateResource(5, URL(origin2, "/resource5")));
- resources3.push_back(CreateResource(6, URL(origin2, "/resource6")));
- ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->WriteRegistration(data3, resources3,
- &newly_purgeable_resources));
-
+ resources3.push_back(CreateResource(5, URL(origin2, "/resource5"), 6));
+ resources3.push_back(CreateResource(6, URL(origin2, "/resource6"), 7));
+ ASSERT_EQ(
+ ServiceWorkerDatabase::STATUS_OK,
+ database->WriteRegistration(
+ data3, resources3, &deleted_version, &newly_purgeable_resources));
+
+ std::set<GURL> origins_to_delete;
+ origins_to_delete.insert(origin1);
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- database->DeleteAllDataForOrigin(origin1,
- &newly_purgeable_resources));
+ database->DeleteAllDataForOrigins(origins_to_delete,
+ &newly_purgeable_resources));
// |origin1| should be removed from the unique origin list.
std::set<GURL> unique_origins;
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 a8ca52acae7..d31f00c62ae 100644
--- a/chromium/content/browser/service_worker/service_worker_disk_cache.cc
+++ b/chromium/content/browser/service_worker/service_worker_disk_cache.cc
@@ -8,15 +8,12 @@ namespace content {
ServiceWorkerResponseReader::ServiceWorkerResponseReader(
int64 response_id, ServiceWorkerDiskCache* disk_cache)
- : appcache::AppCacheResponseReader(response_id, 0, disk_cache) {
+ : AppCacheResponseReader(response_id, 0, disk_cache) {
}
ServiceWorkerResponseWriter::ServiceWorkerResponseWriter(
int64 response_id, ServiceWorkerDiskCache* disk_cache)
- : appcache::AppCacheResponseWriter(response_id, 0, disk_cache) {
-}
-
-HttpResponseInfoIOBuffer::~HttpResponseInfoIOBuffer() {
+ : AppCacheResponseWriter(response_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 83850129aad..7fa51eed634 100644
--- a/chromium/content/browser/service_worker/service_worker_disk_cache.h
+++ b/chromium/content/browser/service_worker/service_worker_disk_cache.h
@@ -5,8 +5,8 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_H_
+#include "content/browser/appcache/appcache_disk_cache.h"
#include "content/common/content_export.h"
-#include "webkit/browser/appcache/appcache_disk_cache.h"
namespace content {
@@ -17,11 +17,11 @@ namespace content {
// resused classes to a more common location.
class CONTENT_EXPORT ServiceWorkerDiskCache
- : public appcache::AppCacheDiskCache {
+ : public AppCacheDiskCache {
};
class CONTENT_EXPORT ServiceWorkerResponseReader
- : public appcache::AppCacheResponseReader {
+ : public AppCacheResponseReader {
protected:
// Should only be constructed by the storage class.
friend class ServiceWorkerStorage;
@@ -31,7 +31,7 @@ class CONTENT_EXPORT ServiceWorkerResponseReader
};
class CONTENT_EXPORT ServiceWorkerResponseWriter
- : public appcache::AppCacheResponseWriter {
+ : public AppCacheResponseWriter {
protected:
// Should only be constructed by the storage class.
friend class ServiceWorkerStorage;
@@ -40,16 +40,6 @@ class CONTENT_EXPORT ServiceWorkerResponseWriter
ServiceWorkerDiskCache* disk_cache);
};
-struct CONTENT_EXPORT HttpResponseInfoIOBuffer
- : public appcache::HttpResponseInfoIOBuffer {
- public:
- HttpResponseInfoIOBuffer() : appcache::HttpResponseInfoIOBuffer() {}
- explicit HttpResponseInfoIOBuffer(net::HttpResponseInfo* info)
- : appcache::HttpResponseInfoIOBuffer(info) {}
- protected:
- virtual ~HttpResponseInfoIOBuffer();
-};
-
} // namespace content
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_H_
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 964a393f8eb..8f00707381f 100644
--- a/chromium/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -4,6 +4,7 @@
#include "content/browser/service_worker/service_worker_dispatcher_host.h"
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/message_port_message_filter.h"
@@ -13,10 +14,14 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_handle.h"
#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_registration_handle.h"
#include "content/browser/service_worker/service_worker_utils.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_client.h"
#include "ipc/ipc_message_macros.h"
+#include "net/base/net_util.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
#include "url/gurl.h"
@@ -26,41 +31,74 @@ namespace content {
namespace {
-const char kDisabledErrorMessage[] =
- "ServiceWorker is disabled";
-const char kDomainMismatchErrorMessage[] =
- "Scope and scripts do not have the same origin";
+const char kShutdownErrorMessage[] =
+ "The Service Worker system has shutdown.";
+const char kDisabledErrorMessage[] = "The browser has disabled Service Worker.";
const uint32 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();
+}
+
+// TODO(dominicc): When crbug.com/362214 is fixed use that to be
+// consistent with Blink's
+// SecurityOrigin::canAccessFeatureRequiringSecureOrigin.
+bool OriginCanAccessServiceWorkers(const GURL& url) {
+ return url.SchemeIsSecure() || net::IsLocalhost(url.host());
+}
+
+bool CheckPatternIsUnderTheScriptDirectory(const GURL& pattern,
+ const GURL& script_url) {
+ size_t slash_pos = script_url.spec().rfind('/');
+ if (slash_pos == std::string::npos)
+ return false;
+ return pattern.spec().compare(
+ 0, slash_pos + 1, script_url.spec(), 0, slash_pos + 1) == 0;
+}
+
bool CanRegisterServiceWorker(const GURL& document_url,
const GURL& pattern,
const GURL& script_url) {
- // TODO: Respect Chrome's content settings, if we add a setting for
- // controlling whether Service Worker is allowed.
- return document_url.GetOrigin() == pattern.GetOrigin() &&
- document_url.GetOrigin() == script_url.GetOrigin();
+ DCHECK(document_url.is_valid());
+ DCHECK(pattern.is_valid());
+ DCHECK(script_url.is_valid());
+ return AllOriginsMatch(document_url, pattern, script_url) &&
+ OriginCanAccessServiceWorkers(document_url) &&
+ CheckPatternIsUnderTheScriptDirectory(pattern, script_url);
}
bool CanUnregisterServiceWorker(const GURL& document_url,
const GURL& pattern) {
- // TODO: Respect Chrome's content settings, if we add a setting for
- // controlling whether Service Worker is allowed.
- return document_url.GetOrigin() == pattern.GetOrigin();
+ DCHECK(document_url.is_valid());
+ DCHECK(pattern.is_valid());
+ return document_url.GetOrigin() == pattern.GetOrigin() &&
+ OriginCanAccessServiceWorkers(document_url);
+}
+
+bool CanGetRegistration(const GURL& document_url,
+ const GURL& given_document_url) {
+ DCHECK(document_url.is_valid());
+ DCHECK(given_document_url.is_valid());
+ return document_url.GetOrigin() == given_document_url.GetOrigin() &&
+ OriginCanAccessServiceWorkers(document_url);
}
} // namespace
ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
int render_process_id,
- MessagePortMessageFilter* message_port_message_filter)
+ MessagePortMessageFilter* message_port_message_filter,
+ ResourceContext* resource_context)
: BrowserMessageFilter(kFilteredMessageClasses,
arraysize(kFilteredMessageClasses)),
render_process_id_(render_process_id),
message_port_message_filter_(message_port_message_filter),
+ resource_context_(resource_context),
channel_ready_(false) {
}
@@ -81,13 +119,15 @@ void ServiceWorkerDispatcherHost::Init(
this, make_scoped_refptr(context_wrapper)));
return;
}
+
context_wrapper_ = context_wrapper;
GetContext()->embedded_worker_registry()->AddChildProcessSender(
render_process_id_, this);
}
void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender* sender) {
- BrowserMessageFilter::OnFilterAdded(sender);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnFilterAdded");
channel_ready_ = true;
std::vector<IPC::Message*> messages;
pending_messages_.release(&messages);
@@ -96,6 +136,18 @@ void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender* sender) {
}
}
+void ServiceWorkerDispatcherHost::OnFilterRemoved() {
+ // Don't wait until the destructor to teardown since a new dispatcher host
+ // for this process might be created before then.
+ if (GetContext()) {
+ GetContext()->RemoveAllProviderHostsForProcess(render_process_id_);
+ GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
+ render_process_id_);
+ }
+ context_wrapper_ = nullptr;
+ channel_ready_ = false;
+}
+
void ServiceWorkerDispatcherHost::OnDestruct() const {
BrowserThread::DeleteOnIOThread::Destruct(this);
}
@@ -108,6 +160,8 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived(
OnRegisterServiceWorker)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker,
OnUnregisterServiceWorker)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistration,
+ OnGetRegistration)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated,
OnProviderCreated)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
@@ -116,14 +170,20 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived(
OnSetHostedVersionId)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker,
OnPostMessageToWorker)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerReadyForInspection,
+ OnWorkerReadyForInspection)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded,
OnWorkerScriptLoaded)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed,
OnWorkerScriptLoadFailed)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptEvaluated,
+ OnWorkerScriptEvaluated)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted,
OnWorkerStarted)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped,
OnWorkerStopped)
+ IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_DidPauseAfterDownload,
+ OnPausedAfterDownload)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException,
OnReportException)
IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage,
@@ -132,6 +192,10 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived(
OnIncrementServiceWorkerRefCount)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount,
OnDecrementServiceWorkerRefCount)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementRegistrationRefCount,
+ OnIncrementRegistrationRefCount)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementRegistrationRefCount,
+ OnDecrementRegistrationRefCount)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -156,24 +220,55 @@ bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) {
return true;
}
+ServiceWorkerRegistrationHandle*
+ServiceWorkerDispatcherHost::GetOrCreateRegistrationHandle(
+ int provider_id,
+ ServiceWorkerRegistration* registration) {
+ ServiceWorkerRegistrationHandle* handle =
+ FindRegistrationHandle(provider_id, registration->id());
+ if (handle) {
+ handle->IncrementRefCount();
+ return handle;
+ }
+
+ scoped_ptr<ServiceWorkerRegistrationHandle> new_handle(
+ new ServiceWorkerRegistrationHandle(
+ GetContext()->AsWeakPtr(), this, provider_id, registration));
+ handle = new_handle.get();
+ RegisterServiceWorkerRegistrationHandle(new_handle.Pass());
+ return handle;
+}
+
void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
scoped_ptr<ServiceWorkerHandle> handle) {
int handle_id = handle->handle_id();
handles_.AddWithID(handle.release(), handle_id);
}
+void ServiceWorkerDispatcherHost::RegisterServiceWorkerRegistrationHandle(
+ scoped_ptr<ServiceWorkerRegistrationHandle> handle) {
+ int handle_id = handle->handle_id();
+ registration_handles_.AddWithID(handle.release(), handle_id);
+}
+
void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
int thread_id,
int request_id,
int provider_id,
const GURL& pattern,
const GURL& script_url) {
- if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnRegisterServiceWorker");
+ if (!GetContext()) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id,
request_id,
- WebServiceWorkerError::ErrorTypeDisabled,
- base::ASCIIToUTF16(kDisabledErrorMessage)));
+ WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
+ return;
+ }
+ if (!pattern.is_valid() || !script_url.is_valid()) {
+ BadMessageReceived();
return;
}
@@ -187,28 +282,40 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id,
request_id,
- WebServiceWorkerError::ErrorTypeDisabled,
- base::ASCIIToUTF16(kDisabledErrorMessage)));
+ WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
if (!CanRegisterServiceWorker(
provider_host->document_url(), pattern, script_url)) {
+ BadMessageReceived();
+ return;
+ }
+
+ if (!GetContentClient()->browser()->AllowServiceWorker(
+ pattern, provider_host->topmost_frame_url(), resource_context_)) {
Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
thread_id,
request_id,
- WebServiceWorkerError::ErrorTypeSecurity,
- base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
+ WebServiceWorkerError::ErrorTypeDisabled,
+ base::ASCIIToUTF16(kDisabledErrorMessage)));
return;
}
+
+ TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker",
+ "ServiceWorkerDispatcherHost::RegisterServiceWorker",
+ request_id,
+ "Pattern", pattern.spec(),
+ "Script URL", script_url.spec());
GetContext()->RegisterServiceWorker(
pattern,
script_url,
- render_process_id_,
provider_host,
base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete,
this,
thread_id,
+ provider_id,
request_id));
}
@@ -217,12 +324,18 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
int request_id,
int provider_id,
const GURL& pattern) {
- if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) {
- Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnUnregisterServiceWorker");
+ if (!GetContext()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id,
request_id,
- blink::WebServiceWorkerError::ErrorTypeDisabled,
- base::ASCIIToUTF16(kDisabledErrorMessage)));
+ blink::WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
+ return;
+ }
+ if (!pattern.is_valid()) {
+ BadMessageReceived();
return;
}
@@ -233,23 +346,34 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
return;
}
if (!provider_host->IsContextAlive()) {
- Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id,
request_id,
- blink::WebServiceWorkerError::ErrorTypeDisabled,
- base::ASCIIToUTF16(kDisabledErrorMessage)));
+ blink::WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
return;
}
if (!CanUnregisterServiceWorker(provider_host->document_url(), pattern)) {
- Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
+ BadMessageReceived();
+ return;
+ }
+
+ if (!GetContentClient()->browser()->AllowServiceWorker(
+ pattern, provider_host->topmost_frame_url(), resource_context_)) {
+ Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
thread_id,
request_id,
- WebServiceWorkerError::ErrorTypeSecurity,
- base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
+ WebServiceWorkerError::ErrorTypeDisabled,
+ base::ASCIIToUTF16(kDisabledErrorMessage)));
return;
}
+ TRACE_EVENT_ASYNC_BEGIN1(
+ "ServiceWorker",
+ "ServiceWorkerDispatcherHost::UnregisterServiceWorker",
+ request_id,
+ "Pattern", pattern.spec());
GetContext()->UnregisterServiceWorker(
pattern,
base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete,
@@ -258,11 +382,86 @@ void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
request_id));
}
+void ServiceWorkerDispatcherHost::OnGetRegistration(
+ int thread_id,
+ int request_id,
+ int provider_id,
+ const GURL& document_url) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnGetRegistration");
+ if (!GetContext()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
+ thread_id,
+ request_id,
+ blink::WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
+ return;
+ }
+ if (!document_url.is_valid()) {
+ BadMessageReceived();
+ return;
+ }
+
+ ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost(
+ render_process_id_, provider_id);
+ if (!provider_host) {
+ BadMessageReceived();
+ return;
+ }
+ if (!provider_host->IsContextAlive()) {
+ Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
+ thread_id,
+ request_id,
+ blink::WebServiceWorkerError::ErrorTypeAbort,
+ base::ASCIIToUTF16(kShutdownErrorMessage)));
+ return;
+ }
+
+ if (!CanGetRegistration(provider_host->document_url(), document_url)) {
+ BadMessageReceived();
+ return;
+ }
+
+ if (!GetContentClient()->browser()->AllowServiceWorker(
+ provider_host->document_url(),
+ provider_host->topmost_frame_url(),
+ resource_context_)) {
+ Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
+ thread_id,
+ request_id,
+ WebServiceWorkerError::ErrorTypeDisabled,
+ base::ASCIIToUTF16(kDisabledErrorMessage)));
+ return;
+ }
+
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ 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());
+
+ GetContext()->storage()->FindRegistrationForDocument(
+ document_url,
+ base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationComplete,
+ this,
+ thread_id,
+ provider_id,
+ request_id));
+}
+
void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
int handle_id,
const base::string16& message,
const std::vector<int>& sent_message_port_ids) {
- if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled())
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnPostMessageToWorker");
+ if (!GetContext())
return;
ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
@@ -282,6 +481,8 @@ void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
}
void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnProviderCreated");
if (!GetContext())
return;
if (GetContext()->GetProviderHost(render_process_id_, provider_id)) {
@@ -295,6 +496,8 @@ void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
}
void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnProviderDestroyed");
if (!GetContext())
return;
if (!GetContext()->GetProviderHost(render_process_id_, provider_id)) {
@@ -306,6 +509,8 @@ void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
int provider_id, int64 version_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnSetHostedVersionId");
if (!GetContext())
return;
ServiceWorkerProviderHost* provider_host =
@@ -320,12 +525,46 @@ void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
BadMessageReceived();
}
+ServiceWorkerRegistrationHandle*
+ServiceWorkerDispatcherHost::FindRegistrationHandle(int provider_id,
+ int64 registration_id) {
+ for (IDMap<ServiceWorkerRegistrationHandle, IDMapOwnPointer>::iterator
+ iter(&registration_handles_);
+ !iter.IsAtEnd();
+ iter.Advance()) {
+ ServiceWorkerRegistrationHandle* handle = iter.GetCurrentValue();
+ DCHECK(handle);
+ if (handle->provider_id() == provider_id && handle->registration() &&
+ handle->registration()->id() == registration_id) {
+ return handle;
+ }
+ }
+ return NULL;
+}
+
+void ServiceWorkerDispatcherHost::GetRegistrationObjectInfoAndVersionAttributes(
+ int provider_id,
+ ServiceWorkerRegistration* registration,
+ ServiceWorkerRegistrationObjectInfo* info,
+ ServiceWorkerVersionAttributes* attrs) {
+ ServiceWorkerRegistrationHandle* handle =
+ GetOrCreateRegistrationHandle(provider_id, registration);
+ *info = handle->GetObjectInfo();
+
+ attrs->installing = handle->CreateServiceWorkerHandleAndPass(
+ registration->installing_version());
+ attrs->waiting = handle->CreateServiceWorkerHandleAndPass(
+ registration->waiting_version());
+ attrs->active = handle->CreateServiceWorkerHandleAndPass(
+ registration->active_version());
+}
+
void ServiceWorkerDispatcherHost::RegistrationComplete(
int thread_id,
+ int provider_id,
int request_id,
ServiceWorkerStatusCode status,
- int64 registration_id,
- int64 version_id) {
+ int64 registration_id) {
if (!GetContext())
return;
@@ -334,47 +573,105 @@ void ServiceWorkerDispatcherHost::RegistrationComplete(
return;
}
- ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id);
- DCHECK(version);
- DCHECK_EQ(registration_id, version->registration_id());
- scoped_ptr<ServiceWorkerHandle> handle =
- ServiceWorkerHandle::Create(GetContext()->AsWeakPtr(),
- this, thread_id, version);
+ ServiceWorkerRegistration* registration =
+ GetContext()->GetLiveRegistration(registration_id);
+ DCHECK(registration);
+
+ ServiceWorkerRegistrationObjectInfo info;
+ ServiceWorkerVersionAttributes attrs;
+ GetRegistrationObjectInfoAndVersionAttributes(
+ provider_id, registration, &info, &attrs);
+
Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
- thread_id, request_id, handle->GetObjectInfo()));
- RegisterServiceWorkerHandle(handle.Pass());
+ thread_id, request_id, info, attrs));
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "ServiceWorkerDispatcherHost::RegisterServiceWorker",
+ request_id,
+ "Registration ID",
+ registration_id);
}
-// TODO(nhiroki): These message handlers that take |embedded_worker_id| as an
-// input should check if the worker refers to the live context. If the context
-// was deleted, handle the messege gracefully (http://crbug.com/371675).
-void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(int embedded_worker_id) {
+void ServiceWorkerDispatcherHost::OnWorkerReadyForInspection(
+ int embedded_worker_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnWorkerReadyForInspection");
if (!GetContext())
return;
- GetContext()->embedded_worker_registry()->OnWorkerScriptLoaded(
- render_process_id_, embedded_worker_id);
+ EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
+ if (!registry->CanHandle(embedded_worker_id))
+ return;
+ registry->OnWorkerReadyForInspection(render_process_id_, embedded_worker_id);
+}
+
+void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(
+ int embedded_worker_id,
+ int thread_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnWorkerScriptLoaded");
+ if (!GetContext())
+ return;
+ EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
+ if (!registry->CanHandle(embedded_worker_id))
+ return;
+ registry->OnWorkerScriptLoaded(
+ render_process_id_, thread_id, embedded_worker_id);
}
void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
int embedded_worker_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed");
if (!GetContext())
return;
- GetContext()->embedded_worker_registry()->OnWorkerScriptLoadFailed(
- render_process_id_, embedded_worker_id);
+ EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
+ if (!registry->CanHandle(embedded_worker_id))
+ return;
+ registry->OnWorkerScriptLoadFailed(render_process_id_, embedded_worker_id);
}
-void ServiceWorkerDispatcherHost::OnWorkerStarted(
- int thread_id, int embedded_worker_id) {
+void ServiceWorkerDispatcherHost::OnWorkerScriptEvaluated(
+ int embedded_worker_id,
+ bool success) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnWorkerScriptEvaluated");
if (!GetContext())
return;
- GetContext()->embedded_worker_registry()->OnWorkerStarted(
- render_process_id_, thread_id, embedded_worker_id);
+ EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
+ if (!registry->CanHandle(embedded_worker_id))
+ return;
+ registry->OnWorkerScriptEvaluated(
+ render_process_id_, embedded_worker_id, success);
+}
+
+void ServiceWorkerDispatcherHost::OnWorkerStarted(int embedded_worker_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnWorkerStarted");
+ if (!GetContext())
+ return;
+ EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
+ if (!registry->CanHandle(embedded_worker_id))
+ return;
+ registry->OnWorkerStarted(render_process_id_, embedded_worker_id);
}
void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnWorkerStopped");
if (!GetContext())
return;
- GetContext()->embedded_worker_registry()->OnWorkerStopped(
+ EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
+ if (!registry->CanHandle(embedded_worker_id))
+ return;
+ registry->OnWorkerStopped(render_process_id_, embedded_worker_id);
+}
+
+void ServiceWorkerDispatcherHost::OnPausedAfterDownload(
+ int embedded_worker_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnPausedAfterDownload");
+ if (!GetContext())
+ return;
+ GetContext()->embedded_worker_registry()->OnPausedAfterDownload(
render_process_id_, embedded_worker_id);
}
@@ -384,32 +681,42 @@ void ServiceWorkerDispatcherHost::OnReportException(
int line_number,
int column_number,
const GURL& source_url) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnReportException");
if (!GetContext())
return;
- GetContext()->embedded_worker_registry()->OnReportException(
- embedded_worker_id,
- error_message,
- line_number,
- column_number,
- source_url);
+ EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
+ if (!registry->CanHandle(embedded_worker_id))
+ return;
+ registry->OnReportException(embedded_worker_id,
+ error_message,
+ line_number,
+ column_number,
+ source_url);
}
void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
int embedded_worker_id,
const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnReportConsoleMessage");
if (!GetContext())
return;
- GetContext()->embedded_worker_registry()->OnReportConsoleMessage(
- embedded_worker_id,
- params.source_identifier,
- params.message_level,
- params.message,
- params.line_number,
- params.source_url);
+ EmbeddedWorkerRegistry* registry = GetContext()->embedded_worker_registry();
+ if (!registry->CanHandle(embedded_worker_id))
+ return;
+ registry->OnReportConsoleMessage(embedded_worker_id,
+ params.source_identifier,
+ params.message_level,
+ params.message,
+ params.line_number,
+ params.source_url);
}
void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
int handle_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount");
ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
if (!handle) {
BadMessageReceived();
@@ -420,6 +727,8 @@ void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
int handle_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount");
ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
if (!handle) {
BadMessageReceived();
@@ -430,16 +739,86 @@ void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
handles_.Remove(handle_id);
}
+void ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount(
+ int registration_handle_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnIncrementRegistrationRefCount");
+ ServiceWorkerRegistrationHandle* handle =
+ registration_handles_.Lookup(registration_handle_id);
+ if (!handle) {
+ BadMessageReceived();
+ return;
+ }
+ handle->IncrementRefCount();
+}
+
+void ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount(
+ int registration_handle_id) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerDispatcherHost::OnDecrementRegistrationRefCount");
+ ServiceWorkerRegistrationHandle* handle =
+ registration_handles_.Lookup(registration_handle_id);
+ if (!handle) {
+ BadMessageReceived();
+ return;
+ }
+ handle->DecrementRefCount();
+ if (handle->HasNoRefCount())
+ registration_handles_.Remove(registration_handle_id);
+}
+
void ServiceWorkerDispatcherHost::UnregistrationComplete(
int thread_id,
int request_id,
ServiceWorkerStatusCode status) {
- if (status != SERVICE_WORKER_OK) {
- SendRegistrationError(thread_id, request_id, status);
+ if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
+ SendUnregistrationError(thread_id, request_id, status);
+ 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(
+ int thread_id,
+ int provider_id,
+ 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);
+
+ if (!GetContext())
+ return;
+
+ if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
+ SendGetRegistrationError(thread_id, request_id, status);
return;
}
- Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id));
+ ServiceWorkerRegistrationObjectInfo info;
+ ServiceWorkerVersionAttributes attrs;
+ if (status == SERVICE_WORKER_OK) {
+ DCHECK(registration.get());
+ if (!registration->is_uninstalling()) {
+ GetRegistrationObjectInfoAndVersionAttributes(
+ provider_id, registration.get(), &info, &attrs);
+ }
+ }
+
+ Send(new ServiceWorkerMsg_DidGetRegistration(
+ thread_id, request_id, info, attrs));
}
void ServiceWorkerDispatcherHost::SendRegistrationError(
@@ -454,7 +833,33 @@ void ServiceWorkerDispatcherHost::SendRegistrationError(
thread_id, request_id, error_type, error_message));
}
+void ServiceWorkerDispatcherHost::SendUnregistrationError(
+ int thread_id,
+ int request_id,
+ ServiceWorkerStatusCode status) {
+ base::string16 error_message;
+ blink::WebServiceWorkerError::ErrorType error_type;
+ GetServiceWorkerRegistrationStatusResponse(
+ status, &error_type, &error_message);
+ Send(new ServiceWorkerMsg_ServiceWorkerUnregistrationError(
+ thread_id, request_id, error_type, error_message));
+}
+
+void ServiceWorkerDispatcherHost::SendGetRegistrationError(
+ int thread_id,
+ int request_id,
+ ServiceWorkerStatusCode status) {
+ base::string16 error_message;
+ blink::WebServiceWorkerError::ErrorType error_type;
+ GetServiceWorkerRegistrationStatusResponse(
+ status, &error_type, &error_message);
+ Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
+ thread_id, request_id, error_type, error_message));
+}
+
ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
+ if (!context_wrapper_.get())
+ return nullptr;
return context_wrapper_->context();
}
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 b269311497b..61126f9c3a8 100644
--- a/chromium/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/chromium/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISPATCHER_HOST_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISPATCHER_HOST_H_
+#include <vector>
+
#include "base/id_map.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
@@ -17,24 +19,30 @@ struct EmbeddedWorkerHostMsg_ReportConsoleMessage_Params;
namespace content {
class MessagePortMessageFilter;
+class ResourceContext;
class ServiceWorkerContextCore;
class ServiceWorkerContextWrapper;
class ServiceWorkerHandle;
class ServiceWorkerProviderHost;
class ServiceWorkerRegistration;
+class ServiceWorkerRegistrationHandle;
+struct ServiceWorkerRegistrationObjectInfo;
+struct ServiceWorkerVersionAttributes;
class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
public:
ServiceWorkerDispatcherHost(
int render_process_id,
- MessagePortMessageFilter* message_port_message_filter);
+ MessagePortMessageFilter* message_port_message_filter,
+ ResourceContext* resource_context);
void Init(ServiceWorkerContextWrapper* context_wrapper);
// BrowserMessageFilter implementation
- virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE;
- virtual void OnDestruct() const OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnFilterAdded(IPC::Sender* sender) override;
+ void OnFilterRemoved() override;
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
// IPC::Sender implementation
@@ -42,16 +50,24 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
// class assumes that Send() can only fail after that when the renderer
// process has terminated, at which point the whole instance will eventually
// be destroyed.
- virtual bool Send(IPC::Message* message) OVERRIDE;
+ bool Send(IPC::Message* message) override;
+
+ // Returns the existing registration handle whose reference count is
+ // incremented or newly created one if it doesn't exist.
+ ServiceWorkerRegistrationHandle* GetOrCreateRegistrationHandle(
+ int provider_id,
+ ServiceWorkerRegistration* registration);
void RegisterServiceWorkerHandle(scoped_ptr<ServiceWorkerHandle> handle);
+ void RegisterServiceWorkerRegistrationHandle(
+ scoped_ptr<ServiceWorkerRegistrationHandle> handle);
MessagePortMessageFilter* message_port_message_filter() {
return message_port_message_filter_;
}
protected:
- virtual ~ServiceWorkerDispatcherHost();
+ ~ServiceWorkerDispatcherHost() override;
private:
friend class BrowserThread;
@@ -68,14 +84,20 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
int request_id,
int provider_id,
const GURL& pattern);
+ void OnGetRegistration(int thread_id,
+ int request_id,
+ int provider_id,
+ const GURL& document_url);
void OnProviderCreated(int provider_id);
void OnProviderDestroyed(int provider_id);
void OnSetHostedVersionId(int provider_id, int64 version_id);
- void OnWorkerScriptLoaded(int embedded_worker_id);
+ void OnWorkerReadyForInspection(int embedded_worker_id);
+ void OnWorkerScriptLoaded(int embedded_worker_id, int thread_id);
void OnWorkerScriptLoadFailed(int embedded_worker_id);
- void OnWorkerStarted(int thread_id,
- int embedded_worker_id);
+ void OnWorkerScriptEvaluated(int embedded_worker_id, bool success);
+ void OnWorkerStarted(int embedded_worker_id);
void OnWorkerStopped(int embedded_worker_id);
+ void OnPausedAfterDownload(int embedded_worker_id);
void OnReportException(int embedded_worker_id,
const base::string16& error_message,
int line_number,
@@ -89,33 +111,62 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
const std::vector<int>& sent_message_port_ids);
void OnIncrementServiceWorkerRefCount(int handle_id);
void OnDecrementServiceWorkerRefCount(int handle_id);
+ void OnIncrementRegistrationRefCount(int registration_handle_id);
+ void OnDecrementRegistrationRefCount(int registration_handle_id);
void OnPostMessageToWorker(int handle_id,
const base::string16& message,
const std::vector<int>& sent_message_port_ids);
void OnServiceWorkerObjectDestroyed(int handle_id);
+ ServiceWorkerRegistrationHandle* FindRegistrationHandle(
+ int provider_id,
+ int64 registration_id);
+
+ void GetRegistrationObjectInfoAndVersionAttributes(
+ int provider_id,
+ ServiceWorkerRegistration* registration,
+ ServiceWorkerRegistrationObjectInfo* info,
+ ServiceWorkerVersionAttributes* attrs);
+
// Callbacks from ServiceWorkerContextCore
void RegistrationComplete(int thread_id,
+ int provider_id,
int request_id,
ServiceWorkerStatusCode status,
- int64 registration_id,
- int64 version_id);
+ int64 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 SendRegistrationError(int thread_id,
int request_id,
ServiceWorkerStatusCode status);
+ void SendUnregistrationError(int thread_id,
+ int request_id,
+ ServiceWorkerStatusCode status);
+
+ void SendGetRegistrationError(int thread_id,
+ int request_id,
+ ServiceWorkerStatusCode status);
+
ServiceWorkerContextCore* GetContext();
int render_process_id_;
MessagePortMessageFilter* const message_port_message_filter_;
+ ResourceContext* resource_context_;
scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
IDMap<ServiceWorkerHandle, IDMapOwnPointer> handles_;
+ IDMap<ServiceWorkerRegistrationHandle, IDMapOwnPointer> registration_handles_;
bool channel_ready_; // True after BrowserMessageFilter::sender_ != NULL.
ScopedVector<IPC::Message> pending_messages_;
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 079c8de65fb..3f21c458832 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
@@ -16,11 +16,24 @@
#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"
+#include "content/public/test/mock_resource_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/test_content_browser_client.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
+namespace {
+
+static void SaveStatusCallback(bool* called,
+ ServiceWorkerStatusCode* out,
+ ServiceWorkerStatusCode status) {
+ *called = true;
+ *out = status;
+}
+
+}
+
static const int kRenderProcessId = 1;
class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost {
@@ -28,28 +41,25 @@ class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost {
TestingServiceWorkerDispatcherHost(
int process_id,
ServiceWorkerContextWrapper* context_wrapper,
+ ResourceContext* resource_context,
EmbeddedWorkerTestHelper* helper)
- : ServiceWorkerDispatcherHost(process_id, NULL),
+ : ServiceWorkerDispatcherHost(process_id, NULL, resource_context),
bad_messages_received_count_(0),
helper_(helper) {
Init(context_wrapper);
}
- virtual bool Send(IPC::Message* message) OVERRIDE {
- return helper_->Send(message);
- }
+ bool Send(IPC::Message* message) override { return helper_->Send(message); }
IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); }
- virtual void BadMessageReceived() OVERRIDE {
- ++bad_messages_received_count_;
- }
+ void BadMessageReceived() override { ++bad_messages_received_count_; }
int bad_messages_received_count_;
protected:
EmbeddedWorkerTestHelper* helper_;
- virtual ~TestingServiceWorkerDispatcherHost() {}
+ ~TestingServiceWorkerDispatcherHost() override {}
};
class ServiceWorkerDispatcherHostTest : public testing::Test {
@@ -57,149 +67,310 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
ServiceWorkerDispatcherHostTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
- virtual void SetUp() {
+ void SetUp() override {
helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
dispatcher_host_ = new TestingServiceWorkerDispatcherHost(
- kRenderProcessId, context_wrapper(), helper_.get());
+ kRenderProcessId, context_wrapper(), &resource_context_, helper_.get());
}
- virtual void TearDown() {
- helper_.reset();
- }
+ void TearDown() override { helper_.reset(); }
ServiceWorkerContextCore* context() { return helper_->context(); }
ServiceWorkerContextWrapper* context_wrapper() {
return helper_->context_wrapper();
}
- void Register(int64 provider_id,
- GURL pattern,
- GURL worker_url,
- uint32 expected_message) {
+ void SendRegister(int64 provider_id, GURL pattern, GURL worker_url) {
dispatcher_host_->OnMessageReceived(
ServiceWorkerHostMsg_RegisterServiceWorker(
-1, -1, provider_id, pattern, worker_url));
base::RunLoop().RunUntilIdle();
+ }
+
+ void Register(int64 provider_id,
+ GURL pattern,
+ GURL worker_url,
+ uint32 expected_message) {
+ SendRegister(provider_id, pattern, worker_url);
EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
expected_message));
dispatcher_host_->ipc_sink()->ClearMessages();
}
- void Unregister(int64 provider_id, GURL pattern, uint32 expected_message) {
+ void SendUnregister(int64 provider_id, GURL pattern) {
dispatcher_host_->OnMessageReceived(
ServiceWorkerHostMsg_UnregisterServiceWorker(
-1, -1, provider_id, pattern));
base::RunLoop().RunUntilIdle();
+ }
+
+ void Unregister(int64 provider_id, GURL pattern, uint32 expected_message) {
+ SendUnregister(provider_id, pattern);
+ EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
+ expected_message));
+ dispatcher_host_->ipc_sink()->ClearMessages();
+ }
+
+ void SendGetRegistration(int64 provider_id, GURL document_url) {
+ dispatcher_host_->OnMessageReceived(
+ ServiceWorkerHostMsg_GetRegistration(
+ -1, -1, provider_id, document_url));
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void GetRegistration(int64 provider_id,
+ GURL document_url,
+ uint32 expected_message) {
+ SendGetRegistration(provider_id, document_url);
EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
expected_message));
dispatcher_host_->ipc_sink()->ClearMessages();
}
TestBrowserThreadBundle browser_thread_bundle_;
+ content::MockResourceContext resource_context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_;
};
-TEST_F(ServiceWorkerDispatcherHostTest, DisabledCausesError) {
- DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableServiceWorker));
-
- dispatcher_host_->OnMessageReceived(
- ServiceWorkerHostMsg_RegisterServiceWorker(-1, -1, -1, GURL(), GURL()));
+class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
+ public:
+ ServiceWorkerTestContentBrowserClient() {}
+ bool AllowServiceWorker(const GURL& scope,
+ const GURL& first_party,
+ content::ResourceContext* context) override {
+ return false;
+ }
+};
- // TODO(alecflett): Pump the message loop when this becomes async.
- ASSERT_EQ(1UL, dispatcher_host_->ipc_sink()->message_count());
- EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
- ServiceWorkerMsg_ServiceWorkerRegistrationError::ID));
-}
+TEST_F(ServiceWorkerDispatcherHostTest,
+ Register_ContentSettingsDisallowsServiceWorker) {
+ ServiceWorkerTestContentBrowserClient test_browser_client;
+ ContentBrowserClient* old_browser_client =
+ SetBrowserClientForTesting(&test_browser_client);
-// TODO(falken): Enable this test when we remove the
-// --enable-service-worker-flag (see crbug.com/352581)
-TEST_F(ServiceWorkerDispatcherHostTest, DISABLED_RegisterSameOrigin) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
- host->SetDocumentUrl(GURL("http://www.example.com/foo"));
- base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
Register(kProviderId,
- GURL("http://www.example.com/*"),
- GURL("http://foo.example.com/bar"),
- ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
- Register(kProviderId,
- GURL("http://foo.example.com/*"),
- GURL("http://www.example.com/bar"),
+ GURL("https://www.example.com/"),
+ GURL("https://www.example.com/bar"),
ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
+ Unregister(kProviderId,
+ GURL("https://www.example.com/"),
+ ServiceWorkerMsg_ServiceWorkerUnregistrationError::ID);
+ GetRegistration(kProviderId,
+ GURL("https://www.example.com/"),
+ ServiceWorkerMsg_ServiceWorkerGetRegistrationError::ID);
+
+ SetBrowserClientForTesting(old_browser_client);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, Register_HTTPS) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
Register(kProviderId,
- GURL("http://foo.example.com/*"),
- GURL("http://foo.example.com/bar"),
- ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
+ GURL("https://www.example.com/"),
+ GURL("https://www.example.com/bar"),
+ ServiceWorkerMsg_ServiceWorkerRegistered::ID);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, Register_NonSecureTransportLocalhost) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("http://127.0.0.3:81/foo"));
+ context()->AddProviderHost(host.Pass());
+
Register(kProviderId,
- GURL("http://www.example.com/*"),
- GURL("http://www.example.com/bar"),
+ GURL("http://127.0.0.3:81/bar"),
+ GURL("http://127.0.0.3:81/baz"),
ServiceWorkerMsg_ServiceWorkerRegistered::ID);
}
-// TODO(falken): Enable this test when we remove the
-// --enable-service-worker-flag (see crbug.com/352581)
-TEST_F(ServiceWorkerDispatcherHostTest, DISABLED_UnregisterSameOrigin) {
+TEST_F(ServiceWorkerDispatcherHostTest,
+ Register_DifferentDirectoryThanScriptShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ SendRegister(kProviderId,
+ GURL("https://www.example.com/hoge/piyo"),
+ GURL("https://www.example.com/bar/hoge.js"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest,
+ Register_SameDirectoryAsScriptButNoSlashShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ SendRegister(kProviderId,
+ GURL("https://www.example.com/bar"),
+ GURL("https://www.example.com/bar/hoge.js"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, Register_InvalidScopeShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ SendRegister(
+ kProviderId, GURL(""), GURL("https://www.example.com/bar/hoge.js"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, Register_InvalidScriptShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ SendRegister(kProviderId, GURL("https://www.example.com/bar/"), GURL(""));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, Register_NonSecureOriginShouldFail) {
const int64 kProviderId = 99; // Dummy value
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
host->SetDocumentUrl(GURL("http://www.example.com/foo"));
- base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
+ context()->AddProviderHost(host.Pass());
+
+ SendRegister(kProviderId,
+ GURL("http://www.example.com/"),
+ GURL("http://www.example.com/bar"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOriginShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ // Script has a different host
+ SendRegister(kProviderId,
+ GURL("https://www.example.com/"),
+ GURL("https://foo.example.com/bar"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+
+ // Scope has a different host
+ SendRegister(kProviderId,
+ GURL("https://foo.example.com/"),
+ GURL("https://www.example.com/bar"));
+ EXPECT_EQ(2, dispatcher_host_->bad_messages_received_count_);
+
+ // Script has a different port
+ SendRegister(kProviderId,
+ GURL("https://www.example.com/"),
+ GURL("https://www.example.com:8080/bar"));
+ EXPECT_EQ(3, dispatcher_host_->bad_messages_received_count_);
+
+ // Scope has a different transport
+ SendRegister(kProviderId,
+ GURL("wss://www.example.com/"),
+ GURL("https://www.example.com/bar"));
+ EXPECT_EQ(4, dispatcher_host_->bad_messages_received_count_);
+
+ // Script and scope have a different host but match each other
+ SendRegister(kProviderId,
+ GURL("https://foo.example.com/"),
+ GURL("https://foo.example.com/bar"));
+ EXPECT_EQ(5, dispatcher_host_->bad_messages_received_count_);
+
+ // Script and scope URLs are invalid
+ SendRegister(kProviderId,
+ GURL(),
+ GURL("h@ttps://@"));
+ EXPECT_EQ(6, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, Unregister_HTTPS) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
context()->AddProviderHost(host.Pass());
Unregister(kProviderId,
- GURL("http://foo.example.com/*"),
- ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
+ GURL("https://www.example.com/"),
+ ServiceWorkerMsg_ServiceWorkerUnregistered::ID);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest,
+ Unregister_NonSecureTransportLocalhost) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("http://localhost/foo"));
+ context()->AddProviderHost(host.Pass());
+
Unregister(kProviderId,
- GURL("http://www.example.com/*"),
+ GURL("http://localhost/"),
ServiceWorkerMsg_ServiceWorkerUnregistered::ID);
}
-// Disable this since now we cache command-line switch in
-// ServiceWorkerUtils::IsFeatureEnabled() and this could be flaky depending
-// on testing order. (crbug.com/352581)
-// TODO(kinuko): Just remove DisabledCausesError test above and enable
-// this test when we remove the --enable-service-worker flag.
-TEST_F(ServiceWorkerDispatcherHostTest, DISABLED_Enabled) {
- DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableServiceWorker));
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableServiceWorker);
+TEST_F(ServiceWorkerDispatcherHostTest, Unregister_CrossOriginShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
- dispatcher_host_->OnMessageReceived(
- ServiceWorkerHostMsg_RegisterServiceWorker(-1, -1, -1, GURL(), GURL()));
- base::RunLoop().RunUntilIdle();
+ SendUnregister(kProviderId, GURL("https://foo.example.com/"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, Unregister_InvalidScopeShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
- // TODO(alecflett): Pump the message loop when this becomes async.
- ASSERT_EQ(2UL, dispatcher_host_->ipc_sink()->message_count());
- EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
- EmbeddedWorkerMsg_StartWorker::ID));
- EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
- ServiceWorkerMsg_ServiceWorkerRegistered::ID));
+ SendUnregister(kProviderId, GURL(""));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
}
-TEST_F(ServiceWorkerDispatcherHostTest, EarlyContextDeletion) {
- DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableServiceWorker));
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableServiceWorker);
+TEST_F(ServiceWorkerDispatcherHostTest, Unregister_NonSecureOriginShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("http://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ SendUnregister(kProviderId, GURL("http://www.example.com/"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+TEST_F(ServiceWorkerDispatcherHostTest, EarlyContextDeletion) {
helper_->ShutdownContext();
// Let the shutdown reach the simulated IO thread.
base::RunLoop().RunUntilIdle();
- dispatcher_host_->OnMessageReceived(
- ServiceWorkerHostMsg_RegisterServiceWorker(-1, -1, -1, GURL(), GURL()));
-
- // TODO(alecflett): Pump the message loop when this becomes async.
- ASSERT_EQ(1UL, dispatcher_host_->ipc_sink()->message_count());
- EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
- ServiceWorkerMsg_ServiceWorkerRegistrationError::ID));
+ Register(-1,
+ GURL(),
+ GURL(),
+ ServiceWorkerMsg_ServiceWorkerRegistrationError::ID);
}
TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) {
@@ -233,4 +404,116 @@ TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) {
EXPECT_FALSE(context()->GetProviderHost(kRenderProcessId, kProviderId));
}
+TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_SameOrigin) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ GetRegistration(kProviderId,
+ GURL("https://www.example.com/"),
+ ServiceWorkerMsg_DidGetRegistration::ID);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_CrossOriginShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ SendGetRegistration(kProviderId, GURL("https://foo.example.com/"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest,
+ GetRegistration_InvalidScopeShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ SendGetRegistration(kProviderId, GURL(""));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest,
+ GetRegistration_NotSecureOriginShouldFail) {
+ const int64 kProviderId = 99; // Dummy value
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL));
+ host->SetDocumentUrl(GURL("http://www.example.com/foo"));
+ context()->AddProviderHost(host.Pass());
+
+ SendGetRegistration(kProviderId, GURL("http://www.example.com/"));
+ EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_EarlyContextDeletion) {
+ helper_->ShutdownContext();
+
+ // Let the shutdown reach the simulated IO thread.
+ base::RunLoop().RunUntilIdle();
+
+ GetRegistration(-1,
+ GURL(),
+ ServiceWorkerMsg_ServiceWorkerGetRegistrationError::ID);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) {
+ // Add a provider and worker.
+ const int64 kProviderId = 99; // Dummy value
+ dispatcher_host_->OnMessageReceived(
+ ServiceWorkerHostMsg_ProviderCreated(kProviderId));
+
+ 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()));
+ helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId);
+
+ // Start up the worker.
+ bool called;
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT;
+ version->StartWorker(base::Bind(&SaveStatusCallback, &called, &status));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(called);
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+
+ EXPECT_TRUE(context()->GetProviderHost(kRenderProcessId, kProviderId));
+ 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(kRenderProcessId, kProviderId));
+ 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
+ // render process.
+ scoped_refptr<TestingServiceWorkerDispatcherHost> new_dispatcher_host(
+ new TestingServiceWorkerDispatcherHost(kRenderProcessId,
+ context_wrapper(),
+ &resource_context_,
+ helper_.get()));
+
+ // To show the new dispatcher can operate, simulate provider creation. Since
+ // the old dispatcher cleaned up the old provider host, the new one won't
+ // complain.
+ new_dispatcher_host->OnMessageReceived(
+ ServiceWorkerHostMsg_ProviderCreated(kProviderId));
+ EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_);
+}
+
} // 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 81be9aff2a7..7ed3051e3f1 100644
--- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -5,30 +5,28 @@
#include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
#include "base/bind.h"
+#include "base/debug/trace_event.h"
#include "content/browser/service_worker/service_worker_version.h"
-#include "net/url_request/url_request.h"
namespace content {
ServiceWorkerFetchDispatcher::ServiceWorkerFetchDispatcher(
- net::URLRequest* request,
+ scoped_ptr<ServiceWorkerFetchRequest> request,
ServiceWorkerVersion* version,
- const FetchCallback& callback)
+ const base::Closure& prepare_callback,
+ const FetchCallback& fetch_callback)
: version_(version),
- callback_(callback),
+ prepare_callback_(prepare_callback),
+ fetch_callback_(fetch_callback),
+ request_(request.Pass()),
weak_factory_(this) {
- request_.url = request->url();
- request_.method = request->method();
- const net::HttpRequestHeaders& headers = request->extra_request_headers();
- for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();)
- request_.headers[it.name()] = it.value();
}
ServiceWorkerFetchDispatcher::~ServiceWorkerFetchDispatcher() {}
void ServiceWorkerFetchDispatcher::Run() {
DCHECK(version_->status() == ServiceWorkerVersion::ACTIVATING ||
- version_->status() == ServiceWorkerVersion::ACTIVE)
+ version_->status() == ServiceWorkerVersion::ACTIVATED)
<< version_->status();
if (version_->status() == ServiceWorkerVersion::ACTIVATING) {
@@ -41,7 +39,7 @@ void ServiceWorkerFetchDispatcher::Run() {
}
void ServiceWorkerFetchDispatcher::DidWaitActivation() {
- if (version_->status() != ServiceWorkerVersion::ACTIVE) {
+ if (version_->status() != ServiceWorkerVersion::ACTIVATED) {
DCHECK_EQ(ServiceWorkerVersion::INSTALLED, version_->status());
DidFailActivation();
return;
@@ -60,19 +58,35 @@ void ServiceWorkerFetchDispatcher::DidFailActivation() {
}
void ServiceWorkerFetchDispatcher::DispatchFetchEvent() {
+ TRACE_EVENT_ASYNC_BEGIN0(
+ "ServiceWorker",
+ "ServiceWorkerFetchDispatcher::DispatchFetchEvent",
+ request_.get());
version_->DispatchFetchEvent(
- request_,
+ *request_.get(),
+ base::Bind(&ServiceWorkerFetchDispatcher::DidPrepare,
+ weak_factory_.GetWeakPtr()),
base::Bind(&ServiceWorkerFetchDispatcher::DidFinish,
weak_factory_.GetWeakPtr()));
}
+void ServiceWorkerFetchDispatcher::DidPrepare() {
+ DCHECK(!prepare_callback_.is_null());
+ base::Closure prepare_callback = prepare_callback_;
+ prepare_callback.Run();
+}
+
void ServiceWorkerFetchDispatcher::DidFinish(
ServiceWorkerStatusCode status,
ServiceWorkerFetchEventResult fetch_result,
const ServiceWorkerResponse& response) {
- DCHECK(!callback_.is_null());
- FetchCallback callback = callback_;
- callback.Run(status, fetch_result, response);
+ TRACE_EVENT_ASYNC_END0(
+ "ServiceWorker",
+ "ServiceWorkerFetchDispatcher::DispatchFetchEvent",
+ request_.get());
+ DCHECK(!fetch_callback_.is_null());
+ FetchCallback fetch_callback = fetch_callback_;
+ fetch_callback.Run(status, fetch_result, response);
}
} // 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 9e595ab0870..f20fb949548 100644
--- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -11,10 +11,6 @@
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/common/service_worker/service_worker_types.h"
-namespace net {
-class URLRequest;
-}
-
namespace content {
class ServiceWorkerVersion;
@@ -26,10 +22,10 @@ class ServiceWorkerFetchDispatcher {
ServiceWorkerFetchEventResult,
const ServiceWorkerResponse&)> FetchCallback;
- ServiceWorkerFetchDispatcher(
- net::URLRequest* request,
- ServiceWorkerVersion* version,
- const FetchCallback& callback);
+ ServiceWorkerFetchDispatcher(scoped_ptr<ServiceWorkerFetchRequest> request,
+ ServiceWorkerVersion* version,
+ const base::Closure& prepare_callback,
+ const FetchCallback& fetch_callback);
~ServiceWorkerFetchDispatcher();
// Dispatches a fetch event to the |version| given in ctor, and fires
@@ -40,13 +36,15 @@ class ServiceWorkerFetchDispatcher {
void DidWaitActivation();
void DidFailActivation();
void DispatchFetchEvent();
+ void DidPrepare();
void DidFinish(ServiceWorkerStatusCode status,
ServiceWorkerFetchEventResult fetch_result,
const ServiceWorkerResponse& response);
scoped_refptr<ServiceWorkerVersion> version_;
- FetchCallback callback_;
- ServiceWorkerFetchRequest request_;
+ base::Closure prepare_callback_;
+ FetchCallback fetch_callback_;
+ scoped_ptr<ServiceWorkerFetchRequest> request_;
base::WeakPtrFactory<ServiceWorkerFetchDispatcher> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerFetchDispatcher);
diff --git a/chromium/content/browser/service_worker/service_worker_handle.cc b/chromium/content/browser/service_worker/service_worker_handle.cc
index a07ab9e9d91..f39904e4035 100644
--- a/chromium/content/browser/service_worker/service_worker_handle.cc
+++ b/chromium/content/browser/service_worker/service_worker_handle.cc
@@ -18,20 +18,17 @@ GetWebServiceWorkerState(ServiceWorkerVersion* version) {
DCHECK(version);
switch (version->status()) {
case ServiceWorkerVersion::NEW:
- if (version->running_status() == ServiceWorkerVersion::RUNNING)
- return blink::WebServiceWorkerStateParsed;
- else
- return blink::WebServiceWorkerStateUnknown;
+ return blink::WebServiceWorkerStateUnknown;
case ServiceWorkerVersion::INSTALLING:
return blink::WebServiceWorkerStateInstalling;
case ServiceWorkerVersion::INSTALLED:
return blink::WebServiceWorkerStateInstalled;
case ServiceWorkerVersion::ACTIVATING:
return blink::WebServiceWorkerStateActivating;
- case ServiceWorkerVersion::ACTIVE:
- return blink::WebServiceWorkerStateActive;
- case ServiceWorkerVersion::DEACTIVATED:
- return blink::WebServiceWorkerStateDeactivated;
+ case ServiceWorkerVersion::ACTIVATED:
+ return blink::WebServiceWorkerStateActivated;
+ case ServiceWorkerVersion::REDUNDANT:
+ return blink::WebServiceWorkerStateRedundant;
}
NOTREACHED() << version->status();
return blink::WebServiceWorkerStateUnknown;
@@ -43,25 +40,27 @@ scoped_ptr<ServiceWorkerHandle> ServiceWorkerHandle::Create(
base::WeakPtr<ServiceWorkerContextCore> context,
IPC::Sender* sender,
int thread_id,
+ int provider_id,
ServiceWorkerVersion* version) {
if (!context || !version)
return scoped_ptr<ServiceWorkerHandle>();
ServiceWorkerRegistration* registration =
context->GetLiveRegistration(version->registration_id());
- return make_scoped_ptr(
- new ServiceWorkerHandle(context, sender, thread_id,
- registration, version));
+ return make_scoped_ptr(new ServiceWorkerHandle(
+ context, sender, thread_id, provider_id, registration, version));
}
ServiceWorkerHandle::ServiceWorkerHandle(
base::WeakPtr<ServiceWorkerContextCore> context,
IPC::Sender* sender,
int thread_id,
+ int provider_id,
ServiceWorkerRegistration* registration,
ServiceWorkerVersion* version)
: context_(context),
sender_(sender),
thread_id_(thread_id),
+ provider_id_(provider_id),
handle_id_(context.get() ? context->GetNewServiceWorkerHandleId() : -1),
ref_count_(1),
registration_(registration),
@@ -108,8 +107,9 @@ ServiceWorkerObjectInfo ServiceWorkerHandle::GetObjectInfo() {
ServiceWorkerObjectInfo info;
info.handle_id = handle_id_;
info.scope = registration_->pattern();
- info.url = registration_->script_url();
- info.state = GetWebServiceWorkerState(version_);
+ info.url = version_->script_url();
+ info.state = GetWebServiceWorkerState(version_.get());
+ info.version_id = version_->version_id();
return info;
}
diff --git a/chromium/content/browser/service_worker/service_worker_handle.h b/chromium/content/browser/service_worker/service_worker_handle.h
index 81d5b3574a2..b7696407089 100644
--- a/chromium/content/browser/service_worker/service_worker_handle.h
+++ b/chromium/content/browser/service_worker/service_worker_handle.h
@@ -28,7 +28,7 @@ class ServiceWorkerRegistration;
// ServiceWorkerRegistration (therefore they're guaranteed to be alive while
// this handle is around).
class CONTENT_EXPORT ServiceWorkerHandle
- : public ServiceWorkerVersion::Listener {
+ : NON_EXPORTED_BASE(public ServiceWorkerVersion::Listener) {
public:
// Creates a handle for a live version. The version's corresponding
// registration must be also alive.
@@ -40,36 +40,40 @@ class CONTENT_EXPORT ServiceWorkerHandle
base::WeakPtr<ServiceWorkerContextCore> context,
IPC::Sender* sender,
int thread_id,
+ int provider_id,
ServiceWorkerVersion* version);
ServiceWorkerHandle(base::WeakPtr<ServiceWorkerContextCore> context,
IPC::Sender* sender,
int thread_id,
+ int provider_id,
ServiceWorkerRegistration* registration,
ServiceWorkerVersion* version);
- virtual ~ServiceWorkerHandle();
+ ~ServiceWorkerHandle() override;
// ServiceWorkerVersion::Listener overrides.
- virtual void OnWorkerStarted(ServiceWorkerVersion* version) OVERRIDE;
- virtual void OnWorkerStopped(ServiceWorkerVersion* version) OVERRIDE;
- virtual void OnErrorReported(ServiceWorkerVersion* version,
- const base::string16& error_message,
- int line_number,
- int column_number,
- const GURL& source_url) OVERRIDE;
- virtual void OnReportConsoleMessage(ServiceWorkerVersion* version,
- int source_identifier,
- int message_level,
- const base::string16& message,
- int line_number,
- const GURL& source_url) OVERRIDE;
- virtual void OnVersionStateChanged(ServiceWorkerVersion* version) OVERRIDE;
+ void OnWorkerStarted(ServiceWorkerVersion* version) override;
+ void OnWorkerStopped(ServiceWorkerVersion* version) override;
+ void OnErrorReported(ServiceWorkerVersion* version,
+ const base::string16& error_message,
+ int line_number,
+ int column_number,
+ const GURL& source_url) override;
+ void OnReportConsoleMessage(ServiceWorkerVersion* version,
+ int source_identifier,
+ int message_level,
+ const base::string16& message,
+ int line_number,
+ const GURL& source_url) override;
+ void OnVersionStateChanged(ServiceWorkerVersion* version) override;
ServiceWorkerObjectInfo GetObjectInfo();
+ int thread_id() const { return thread_id_; }
+ int provider_id() const { return provider_id_; }
+ int handle_id() const { return handle_id_; }
ServiceWorkerRegistration* registration() { return registration_.get(); }
ServiceWorkerVersion* version() { return version_.get(); }
- int handle_id() const { return handle_id_; }
bool HasNoRefCount() const { return ref_count_ <= 0; }
void IncrementRefCount();
@@ -79,6 +83,7 @@ class CONTENT_EXPORT ServiceWorkerHandle
base::WeakPtr<ServiceWorkerContextCore> context_;
IPC::Sender* sender_; // Not owned, it should always outlive this.
const int thread_id_;
+ const int provider_id_;
const int handle_id_;
int ref_count_; // Created with 1.
scoped_refptr<ServiceWorkerRegistration> registration_;
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 70c445613c9..8adf4f50bfe 100644
--- a/chromium/content/browser/service_worker/service_worker_handle_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_handle_unittest.cc
@@ -43,23 +43,24 @@ class ServiceWorkerHandleTest : public testing::Test {
ServiceWorkerHandleTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
+ const GURL pattern("http://www.example.com/");
registration_ = new ServiceWorkerRegistration(
- GURL("http://www.example.com/*"),
- GURL("http://www.example.com/service_worker.js"),
+ pattern,
1L,
helper_->context()->AsWeakPtr());
version_ = new ServiceWorkerVersion(
- registration_, 1L, helper_->context()->AsWeakPtr());
+ registration_.get(),
+ GURL("http://www.example.com/service_worker.js"),
+ 1L,
+ helper_->context()->AsWeakPtr());
- // Simulate adding one process to the worker.
- int embedded_worker_id = version_->embedded_worker()->embedded_worker_id();
- helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId);
+ helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId);
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
registration_ = NULL;
version_ = NULL;
helper_.reset();
@@ -71,6 +72,8 @@ class ServiceWorkerHandleTest : public testing::Test {
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
+
+ private:
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHandleTest);
};
@@ -79,7 +82,8 @@ TEST_F(ServiceWorkerHandleTest, OnVersionStateChanged) {
ServiceWorkerHandle::Create(helper_->context()->AsWeakPtr(),
helper_.get(),
1 /* thread_id */,
- version_);
+ 33 /* provider_id */,
+ version_.get());
// Start the worker, and then...
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
@@ -89,10 +93,13 @@ TEST_F(ServiceWorkerHandleTest, OnVersionStateChanged) {
// ...dispatch install event.
status = SERVICE_WORKER_ERROR_FAILED;
+ version_->SetStatus(ServiceWorkerVersion::INSTALLING);
version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
+ version_->SetStatus(ServiceWorkerVersion::INSTALLED);
+
ASSERT_EQ(4UL, ipc_sink()->message_count());
// We should be sending 1. StartWorker,
diff --git a/chromium/content/browser/service_worker/service_worker_histograms.cc b/chromium/content/browser/service_worker/service_worker_histograms.cc
deleted file mode 100644
index 8d1df4bef4b..00000000000
--- a/chromium/content/browser/service_worker/service_worker_histograms.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/service_worker/service_worker_histograms.h"
-
-#include "base/metrics/histogram.h"
-
-namespace content {
-
-// static
-void ServiceWorkerHistograms::CountInitDiskCacheResult(bool result) {
- UMA_HISTOGRAM_BOOLEAN("ServiceWorker.DiskCache.InitResult", result);
-}
-
-// static
-void ServiceWorkerHistograms::CountReadResponseResult(
- ServiceWorkerHistograms::ReadResponseResult result) {
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.DiskCache.ReadResponseResult",
- result, NUM_READ_RESPONSE_RESULT_TYPES);
-}
-
-// static
-void ServiceWorkerHistograms::CountWriteResponseResult(
- ServiceWorkerHistograms::WriteResponseResult result) {
- UMA_HISTOGRAM_ENUMERATION("ServiceWorker.DiskCache.WriteResponseResult",
- result, NUM_WRITE_RESPONSE_RESULT_TYPES);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_histograms.h b/chromium/content/browser/service_worker/service_worker_histograms.h
deleted file mode 100644
index a9ad8c6ef06..00000000000
--- a/chromium/content/browser/service_worker/service_worker_histograms.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_HISTOGRAMS_H_
-#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_HISTOGRAMS_H_
-
-#include "base/macros.h"
-
-namespace content {
-
-class ServiceWorkerHistograms {
- public:
- enum ReadResponseResult {
- READ_OK,
- READ_HEADERS_ERROR,
- READ_DATA_ERROR,
- NUM_READ_RESPONSE_RESULT_TYPES,
- };
-
- enum WriteResponseResult {
- WRITE_OK,
- WRITE_HEADERS_ERROR,
- WRITE_DATA_ERROR,
- NUM_WRITE_RESPONSE_RESULT_TYPES,
- };
-
- static void CountInitDiskCacheResult(bool result);
- static void CountReadResponseResult(ReadResponseResult result);
- static void CountWriteResponseResult(WriteResponseResult result);
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerHistograms);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_HISTOGRAMS_H_
diff --git a/chromium/content/browser/service_worker/service_worker_info.cc b/chromium/content/browser/service_worker/service_worker_info.cc
index 8933340c2ff..1efe110c62f 100644
--- a/chromium/content/browser/service_worker/service_worker_info.cc
+++ b/chromium/content/browser/service_worker/service_worker_info.cc
@@ -10,8 +10,7 @@
namespace content {
ServiceWorkerVersionInfo::ServiceWorkerVersionInfo()
- : is_null(true),
- running_status(ServiceWorkerVersion::STOPPED),
+ : running_status(ServiceWorkerVersion::STOPPED),
status(ServiceWorkerVersion::NEW),
version_id(kInvalidServiceWorkerVersionId),
process_id(-1),
@@ -22,13 +21,14 @@ ServiceWorkerVersionInfo::ServiceWorkerVersionInfo()
ServiceWorkerVersionInfo::ServiceWorkerVersionInfo(
ServiceWorkerVersion::RunningStatus running_status,
ServiceWorkerVersion::Status status,
+ const GURL& script_url,
int64 version_id,
int process_id,
int thread_id,
int devtools_agent_route_id)
- : is_null(false),
- running_status(running_status),
+ : running_status(running_status),
status(status),
+ script_url(script_url),
version_id(version_id),
process_id(process_id),
thread_id(thread_id),
@@ -37,19 +37,24 @@ ServiceWorkerVersionInfo::ServiceWorkerVersionInfo(
ServiceWorkerVersionInfo::~ServiceWorkerVersionInfo() {}
-ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo() {}
+ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo()
+ : registration_id(kInvalidServiceWorkerRegistrationId),
+ stored_version_size_bytes(0) {
+}
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
- const GURL& script_url,
const GURL& pattern,
int64 registration_id,
const ServiceWorkerVersionInfo& active_version,
- const ServiceWorkerVersionInfo& waiting_version)
- : script_url(script_url),
- pattern(pattern),
+ const ServiceWorkerVersionInfo& waiting_version,
+ const ServiceWorkerVersionInfo& installing_version,
+ int64_t stored_version_size_bytes)
+ : pattern(pattern),
registration_id(registration_id),
active_version(active_version),
- waiting_version(waiting_version) {
+ waiting_version(waiting_version),
+ installing_version(installing_version),
+ stored_version_size_bytes(stored_version_size_bytes) {
}
ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo() {}
diff --git a/chromium/content/browser/service_worker/service_worker_info.h b/chromium/content/browser/service_worker/service_worker_info.h
index 99e374696b0..0e93bd0748b 100644
--- a/chromium/content/browser/service_worker/service_worker_info.h
+++ b/chromium/content/browser/service_worker/service_worker_info.h
@@ -18,15 +18,16 @@ class CONTENT_EXPORT ServiceWorkerVersionInfo {
ServiceWorkerVersionInfo();
ServiceWorkerVersionInfo(ServiceWorkerVersion::RunningStatus running_status,
ServiceWorkerVersion::Status status,
+ const GURL& script_url,
int64 version_id,
int process_id,
int thread_id,
int devtools_agent_route_id);
~ServiceWorkerVersionInfo();
- bool is_null;
ServiceWorkerVersion::RunningStatus running_status;
ServiceWorkerVersion::Status status;
+ GURL script_url;
int64 version_id;
int process_id;
int thread_id;
@@ -37,18 +38,22 @@ class CONTENT_EXPORT ServiceWorkerRegistrationInfo {
public:
ServiceWorkerRegistrationInfo();
ServiceWorkerRegistrationInfo(
- const GURL& script_url,
const GURL& pattern,
int64 registration_id,
const ServiceWorkerVersionInfo& active_version,
- const ServiceWorkerVersionInfo& waiting_version);
+ const ServiceWorkerVersionInfo& waiting_version,
+ const ServiceWorkerVersionInfo& installing_version,
+ int64_t active_version_total_size_bytes);
~ServiceWorkerRegistrationInfo();
- GURL script_url;
GURL pattern;
int64 registration_id;
+ ServiceWorkerVersionInfo controlling_version;
ServiceWorkerVersionInfo active_version;
ServiceWorkerVersionInfo waiting_version;
+ ServiceWorkerVersionInfo installing_version;
+
+ int64_t stored_version_size_bytes;
};
} // namespace content
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 e976ad82884..a7c8d716813 100644
--- a/chromium/content/browser/service_worker/service_worker_internals_ui.cc
+++ b/chromium/content/browser/service_worker/service_worker_internals_ui.cc
@@ -11,12 +11,13 @@
#include "base/memory/scoped_vector.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
-#include "content/browser/devtools/devtools_manager_impl.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/browser/devtools/embedded_worker_devtools_manager.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_registration.h"
#include "content/browser/service_worker/service_worker_version.h"
+#include "content/grit/content_resources.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
@@ -24,7 +25,6 @@
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/common/url_constants.h"
-#include "grit/content_resources.h"
using base::DictionaryValue;
using base::FundamentalValue;
@@ -75,11 +75,11 @@ void CallServiceWorkerVersionMethodWithVersionID(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
scoped_refptr<ServiceWorkerVersion> version =
context->context()->GetLiveVersion(version_id);
- if (!version) {
+ if (!version.get()) {
callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
return;
}
- (*version.*method)(callback);
+ (*version.get().*method)(callback);
}
void DispatchPushEventWithVersionID(
@@ -99,7 +99,7 @@ void DispatchPushEventWithVersionID(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
scoped_refptr<ServiceWorkerVersion> version =
context->context()->GetLiveVersion(version_id);
- if (!version) {
+ if (!version.get()) {
callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
return;
}
@@ -189,13 +189,14 @@ void UpdateVersionInfo(const ServiceWorkerVersionInfo& version,
case ServiceWorkerVersion::ACTIVATING:
info->SetString("status", "ACTIVATING");
break;
- case ServiceWorkerVersion::ACTIVE:
- info->SetString("status", "ACTIVE");
+ case ServiceWorkerVersion::ACTIVATED:
+ info->SetString("status", "ACTIVATED");
break;
- case ServiceWorkerVersion::DEACTIVATED:
- info->SetString("status", "DEACTIVATED");
+ case ServiceWorkerVersion::REDUNDANT:
+ info->SetString("status", "REDUNDANT");
break;
}
+ 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("thread_id", version.thread_id);
@@ -212,17 +213,18 @@ ListValue* GetRegistrationListValue(
const ServiceWorkerRegistrationInfo& registration = *it;
DictionaryValue* registration_info = new DictionaryValue();
registration_info->SetString("scope", registration.pattern.spec());
- registration_info->SetString("script_url", registration.script_url.spec());
registration_info->SetString(
"registration_id", base::Int64ToString(registration.registration_id));
- if (!registration.active_version.is_null) {
+ if (registration.active_version.version_id !=
+ kInvalidServiceWorkerVersionId) {
DictionaryValue* active_info = new DictionaryValue();
UpdateVersionInfo(registration.active_version, active_info);
registration_info->Set("active", active_info);
}
- if (!registration.waiting_version.is_null) {
+ if (registration.waiting_version.version_id !=
+ kInvalidServiceWorkerVersionId) {
DictionaryValue* waiting_info = new DictionaryValue();
UpdateVersionInfo(registration.waiting_version, waiting_info);
registration_info->Set("waiting", waiting_info);
@@ -300,11 +302,11 @@ class ServiceWorkerInternalsUI::PartitionObserver
public:
PartitionObserver(int partition_id, WebUI* web_ui)
: partition_id_(partition_id), web_ui_(web_ui) {}
- virtual ~PartitionObserver() {}
+ ~PartitionObserver() override {}
// ServiceWorkerContextObserver overrides:
- virtual void OnWorkerStarted(int64 version_id,
- int process_id,
- int thread_id) OVERRIDE {
+ void OnWorkerStarted(int64 version_id,
+ int process_id,
+ int thread_id) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
web_ui_->CallJavascriptFunction(
"serviceworker.onWorkerStarted",
@@ -313,9 +315,9 @@ class ServiceWorkerInternalsUI::PartitionObserver
FundamentalValue(process_id),
FundamentalValue(thread_id));
}
- virtual void OnWorkerStopped(int64 version_id,
- int process_id,
- int thread_id) OVERRIDE {
+ void OnWorkerStopped(int64 version_id,
+ int process_id,
+ int thread_id) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
web_ui_->CallJavascriptFunction(
"serviceworker.onWorkerStopped",
@@ -324,17 +326,17 @@ class ServiceWorkerInternalsUI::PartitionObserver
FundamentalValue(process_id),
FundamentalValue(thread_id));
}
- virtual void OnVersionStateChanged(int64 version_id) OVERRIDE {
+ void OnVersionStateChanged(int64 version_id) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
web_ui_->CallJavascriptFunction(
"serviceworker.onVersionStateChanged",
FundamentalValue(partition_id_),
StringValue(base::Int64ToString(version_id)));
}
- virtual void OnErrorReported(int64 version_id,
- int process_id,
- int thread_id,
- const ErrorInfo& info) OVERRIDE {
+ void OnErrorReported(int64 version_id,
+ int process_id,
+ int thread_id,
+ const ErrorInfo& info) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ScopedVector<const Value> args;
args.push_back(new FundamentalValue(partition_id_));
@@ -350,10 +352,10 @@ class ServiceWorkerInternalsUI::PartitionObserver
web_ui_->CallJavascriptFunction("serviceworker.onErrorReported",
args.get());
}
- virtual void OnReportConsoleMessage(int64 version_id,
- int process_id,
- int thread_id,
- const ConsoleMessage& message) OVERRIDE {
+ void OnReportConsoleMessage(int64 version_id,
+ int process_id,
+ int thread_id,
+ const ConsoleMessage& message) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ScopedVector<const Value> args;
args.push_back(new FundamentalValue(partition_id_));
@@ -370,12 +372,12 @@ class ServiceWorkerInternalsUI::PartitionObserver
web_ui_->CallJavascriptFunction("serviceworker.onConsoleMessageReported",
args.get());
}
- virtual void OnRegistrationStored(const GURL& pattern) OVERRIDE {
+ void OnRegistrationStored(const GURL& pattern) override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
web_ui_->CallJavascriptFunction("serviceworker.onRegistrationStored",
StringValue(pattern.spec()));
}
- virtual void OnRegistrationDeleted(const GURL& pattern) OVERRIDE {
+ void OnRegistrationDeleted(const GURL& pattern) override {
web_ui_->CallJavascriptFunction("serviceworker.onRegistrationDeleted",
StringValue(pattern.spec()));
}
@@ -390,7 +392,6 @@ ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui)
: WebUIController(web_ui), next_partition_id_(0) {
WebUIDataSource* source =
WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost);
- source->SetUseJsonJSFormatV2();
source->SetJsonPath("strings.js");
source->AddResourcePath("serviceworker_internals.js",
IDR_SERVICE_WORKER_INTERNALS_JS);
@@ -500,6 +501,7 @@ void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
context->AddObserver(new_observer.get());
observers_.set(reinterpret_cast<uintptr_t>(partition), new_observer.Pass());
}
+
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
@@ -510,7 +512,9 @@ void ServiceWorkerInternalsUI::AddContextFromStoragePartition(
base::Bind(OnAllRegistrations,
AsWeakPtr(),
partition_id,
- partition->GetPath()))));
+ context->is_incognito()
+ ? base::FilePath()
+ : partition->GetPath()))));
}
void ServiceWorkerInternalsUI::RemoveObserverFromStoragePartition(
@@ -560,11 +564,11 @@ void ServiceWorkerInternalsUI::CallServiceWorkerVersionMethod(
const ListValue* args) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
int callback_id;
- int partition_id;
- int64 version_id;
- std::string version_id_string;
const DictionaryValue* cmd_args = NULL;
+ int partition_id;
scoped_refptr<ServiceWorkerContextWrapper> context;
+ std::string version_id_string;
+ int64 version_id = 0;
if (!args->GetInteger(0, &callback_id) ||
!args->GetDictionary(1, &cmd_args) ||
!cmd_args->GetInteger("partition_id", &partition_id) ||
@@ -585,7 +589,7 @@ void ServiceWorkerInternalsUI::DispatchPushEvent(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
int callback_id;
int partition_id;
- int64 version_id;
+ int64 version_id = 0;
std::string version_id_string;
const DictionaryValue* cmd_args = NULL;
scoped_refptr<ServiceWorkerContextWrapper> context;
@@ -606,10 +610,9 @@ void ServiceWorkerInternalsUI::DispatchPushEvent(
void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
int callback_id;
- int process_id;
- int devtools_agent_route_id;
const DictionaryValue* cmd_args = NULL;
- scoped_refptr<ServiceWorkerContextWrapper> context;
+ int process_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) ||
@@ -619,15 +622,14 @@ void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) {
}
base::Callback<void(ServiceWorkerStatusCode)> callback =
base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id);
- scoped_refptr<DevToolsAgentHost> agent_host(
+ scoped_refptr<DevToolsAgentHostImpl> agent_host(
EmbeddedWorkerDevToolsManager::GetInstance()
->GetDevToolsAgentHostForWorker(process_id, devtools_agent_route_id));
- if (!agent_host) {
+ if (!agent_host.get()) {
callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND);
return;
}
- DevToolsManagerImpl::GetInstance()->Inspect(
- web_ui()->GetWebContents()->GetBrowserContext(), agent_host.get());
+ agent_host->Inspect(web_ui()->GetWebContents()->GetBrowserContext());
callback.Run(SERVICE_WORKER_OK);
}
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 84c1e19204e..f0c09d68616 100644
--- a/chromium/content/browser/service_worker/service_worker_internals_ui.h
+++ b/chromium/content/browser/service_worker/service_worker_internals_ui.h
@@ -42,7 +42,7 @@ class ServiceWorkerInternalsUI
class OperationProxy;
class PartitionObserver;
- virtual ~ServiceWorkerInternalsUI();
+ ~ServiceWorkerInternalsUI() override;
void AddContextFromStoragePartition(StoragePartition* partition);
void RemoveObserverFromStoragePartition(StoragePartition* partition);
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 8152b490272..c3bfb396b4f 100644
--- a/chromium/content/browser/service_worker/service_worker_job_coordinator.cc
+++ b/chromium/content/browser/service_worker/service_worker_job_coordinator.cc
@@ -71,14 +71,14 @@ ServiceWorkerJobCoordinator::~ServiceWorkerJobCoordinator() {
void ServiceWorkerJobCoordinator::Register(
const GURL& pattern,
const GURL& script_url,
- int source_process_id,
+ ServiceWorkerProviderHost* provider_host,
const ServiceWorkerRegisterJob::RegistrationCallback& callback) {
scoped_ptr<ServiceWorkerRegisterJobBase> job(
new ServiceWorkerRegisterJob(context_, pattern, script_url));
ServiceWorkerRegisterJob* queued_job =
static_cast<ServiceWorkerRegisterJob*>(
job_queues_[pattern].Push(job.Pass()));
- queued_job->AddCallback(callback, source_process_id);
+ queued_job->AddCallback(callback, provider_host);
}
void ServiceWorkerJobCoordinator::Unregister(
@@ -92,6 +92,15 @@ void ServiceWorkerJobCoordinator::Unregister(
queued_job->AddCallback(callback);
}
+void ServiceWorkerJobCoordinator::Update(
+ ServiceWorkerRegistration* registration) {
+ DCHECK(registration);
+ DCHECK(registration->GetNewestVersion());
+ job_queues_[registration->pattern()].Push(
+ make_scoped_ptr<ServiceWorkerRegisterJobBase>(
+ new ServiceWorkerRegisterJob(context_, registration)));
+}
+
void ServiceWorkerJobCoordinator::AbortAll() {
for (RegistrationJobMap::iterator it = job_queues_.begin();
it != job_queues_.end(); ++it) {
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 06a1057d76e..b85a84bc52c 100644
--- a/chromium/content/browser/service_worker/service_worker_job_coordinator.h
+++ b/chromium/content/browser/service_worker/service_worker_job_coordinator.h
@@ -16,6 +16,7 @@
namespace content {
class EmbeddedWorkerRegistry;
+class ServiceWorkerProviderHost;
class ServiceWorkerRegistration;
class ServiceWorkerStorage;
@@ -28,13 +29,15 @@ class CONTENT_EXPORT ServiceWorkerJobCoordinator {
void Register(const GURL& pattern,
const GURL& script_url,
- int source_process_id,
+ ServiceWorkerProviderHost* provider_host,
const ServiceWorkerRegisterJob::RegistrationCallback& callback);
void Unregister(
const GURL& pattern,
const ServiceWorkerUnregisterJob::UnregistrationCallback& callback);
+ void Update(ServiceWorkerRegistration* registration);
+
// Calls ServiceWorkerRegisterJobBase::Abort() on all jobs and removes them.
void AbortAll();
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 efa8bd1aa1e..515e0f82fdc 100644
--- a/chromium/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_job_unittest.cc
@@ -9,27 +9,36 @@
#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_disk_cache.h"
#include "content/browser/service_worker/service_worker_job_coordinator.h"
#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/public/test/test_browser_thread_bundle.h"
#include "ipc/ipc_test_sink.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
+using net::IOBuffer;
+using net::TestCompletionCallback;
+using net::WrappedIOBuffer;
+
// Unit tests for testing all job registration tasks.
namespace content {
namespace {
+int kMockRenderProcessId = 88;
+
void SaveRegistrationCallback(
ServiceWorkerStatusCode expected_status,
bool* called,
scoped_refptr<ServiceWorkerRegistration>* registration_out,
ServiceWorkerStatusCode status,
- ServiceWorkerRegistration* registration,
- ServiceWorkerVersion* version) {
- ASSERT_TRUE(!version || version->registration_id() == registration->id())
- << version << " " << registration;
+ ServiceWorkerRegistration* registration) {
EXPECT_EQ(expected_status, status);
*called = true;
*registration_out = registration;
@@ -91,15 +100,13 @@ class ServiceWorkerJobTest : public testing::Test {
public:
ServiceWorkerJobTest()
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
- render_process_id_(88) {}
+ render_process_id_(kMockRenderProcessId) {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_));
}
- virtual void TearDown() OVERRIDE {
- helper_.reset();
- }
+ void TearDown() override { helper_.reset(); }
ServiceWorkerContextCore* context() const { return helper_->context(); }
@@ -111,7 +118,6 @@ class ServiceWorkerJobTest : public testing::Test {
protected:
TestBrowserThreadBundle browser_thread_bundle_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
-
int render_process_id_;
};
@@ -119,9 +125,9 @@ TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) {
scoped_refptr<ServiceWorkerRegistration> original_registration;
bool called;
job_coordinator()->Register(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration));
EXPECT_FALSE(called);
base::RunLoop().RunUntilIdle();
@@ -137,7 +143,7 @@ TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) {
SaveFoundRegistration(SERVICE_WORKER_OK, &called, &registration2));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(called);
- ASSERT_TRUE(registration1);
+ ASSERT_TRUE(registration1.get());
ASSERT_EQ(registration1, original_registration);
ASSERT_EQ(registration1, registration2);
}
@@ -146,9 +152,9 @@ TEST_F(ServiceWorkerJobTest, SameMatchSameRegistration) {
bool called;
scoped_refptr<ServiceWorkerRegistration> original_registration;
job_coordinator()->Register(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration));
EXPECT_FALSE(called);
base::RunLoop().RunUntilIdle();
@@ -177,17 +183,17 @@ TEST_F(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) {
bool called1;
scoped_refptr<ServiceWorkerRegistration> original_registration1;
job_coordinator()->Register(
- GURL("http://www.example.com/one/*"),
+ GURL("http://www.example.com/one/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called1, &original_registration1));
bool called2;
scoped_refptr<ServiceWorkerRegistration> original_registration2;
job_coordinator()->Register(
- GURL("http://www.example.com/two/*"),
+ GURL("http://www.example.com/two/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called2, &original_registration2));
EXPECT_FALSE(called1);
@@ -216,9 +222,9 @@ TEST_F(ServiceWorkerJobTest, Register) {
bool called = false;
scoped_refptr<ServiceWorkerRegistration> registration;
job_coordinator()->Register(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
ASSERT_FALSE(called);
@@ -230,14 +236,14 @@ TEST_F(ServiceWorkerJobTest, Register) {
// Make sure registrations are cleaned up when they are unregistered.
TEST_F(ServiceWorkerJobTest, Unregister) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
bool called;
scoped_refptr<ServiceWorkerRegistration> registration;
job_coordinator()->Register(
pattern,
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
ASSERT_FALSE(called);
@@ -266,28 +272,29 @@ TEST_F(ServiceWorkerJobTest, Unregister) {
}
TEST_F(ServiceWorkerJobTest, Unregister_NothingRegistered) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
bool called;
- job_coordinator()->Unregister(pattern,
- SaveUnregistration(SERVICE_WORKER_OK, &called));
+ job_coordinator()->Unregister(
+ pattern,
+ SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND, &called));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
}
-// Make sure that when a new registration replaces an existing
-// registration, that the old one is cleaned up.
+// Make sure registering a new script creates a new version and shares an
+// existing registration.
TEST_F(ServiceWorkerJobTest, RegisterNewScript) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
bool called;
scoped_refptr<ServiceWorkerRegistration> old_registration;
job_coordinator()->Register(
pattern,
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration));
ASSERT_FALSE(called);
@@ -311,16 +318,14 @@ TEST_F(ServiceWorkerJobTest, RegisterNewScript) {
job_coordinator()->Register(
pattern,
GURL("http://www.example.com/service_worker_new.js"),
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
- ASSERT_TRUE(old_registration->HasOneRef());
-
- ASSERT_NE(old_registration, new_registration);
+ ASSERT_EQ(old_registration, new_registration);
scoped_refptr<ServiceWorkerRegistration> new_registration_by_pattern;
storage()->FindRegistrationForPattern(
@@ -338,7 +343,7 @@ TEST_F(ServiceWorkerJobTest, RegisterNewScript) {
// Make sure that when registering a duplicate pattern+script_url
// combination, that the same registration is used.
TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
GURL script_url("http://www.example.com/service_worker.js");
bool called;
@@ -346,7 +351,7 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
job_coordinator()->Register(
pattern,
script_url,
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration));
ASSERT_FALSE(called);
@@ -362,13 +367,13 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
- ASSERT_TRUE(old_registration_by_pattern);
+ ASSERT_TRUE(old_registration_by_pattern.get());
scoped_refptr<ServiceWorkerRegistration> new_registration;
job_coordinator()->Register(
pattern,
script_url,
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration));
ASSERT_FALSE(called);
@@ -394,14 +399,14 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
public:
- FailToStartWorkerTestHelper(int mock_render_process_id)
+ explicit FailToStartWorkerTestHelper(int mock_render_process_id)
: EmbeddedWorkerTestHelper(mock_render_process_id) {}
- virtual void OnStartWorker(int embedded_worker_id,
- int64 service_worker_version_id,
- const GURL& scope,
- const GURL& script_url) OVERRIDE {
- // Simulate failure by sending worker stopped instead of started.
+ void OnStartWorker(int embedded_worker_id,
+ int64 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);
}
@@ -413,9 +418,9 @@ TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) {
bool called = false;
scoped_refptr<ServiceWorkerRegistration> registration;
job_coordinator()->Register(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("http://www.example.com/service_worker.js"),
- render_process_id_,
+ NULL,
SaveRegistration(
SERVICE_WORKER_ERROR_START_WORKER_FAILED, &called, &registration));
@@ -429,7 +434,7 @@ TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) {
// Register and then unregister the pattern, in parallel. Job coordinator should
// process jobs until the last job.
TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
GURL script_url("http://www.example.com/service_worker.js");
bool registration_called = false;
@@ -437,7 +442,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) {
job_coordinator()->Register(
pattern,
script_url,
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_OK, &registration_called, &registration));
bool unregistration_called = false;
@@ -466,7 +471,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) {
// registration should win, and the old registration should have been
// shutdown.
TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
GURL script_url1("http://www.example.com/service_worker1.js");
bool registration1_called = false;
@@ -474,7 +479,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) {
job_coordinator()->Register(
pattern,
script_url1,
- render_process_id_,
+ NULL,
SaveRegistration(
SERVICE_WORKER_OK, &registration1_called, &registration1));
@@ -484,7 +489,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) {
job_coordinator()->Register(
pattern,
script_url2,
- render_process_id_,
+ NULL,
SaveRegistration(
SERVICE_WORKER_OK, &registration2_called, &registration2));
@@ -510,7 +515,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) {
// coalesced such that both callers get the exact same registration
// object.
TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
GURL script_url("http://www.example.com/service_worker1.js");
bool registration1_called = false;
@@ -518,7 +523,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) {
job_coordinator()->Register(
pattern,
script_url,
- render_process_id_,
+ NULL,
SaveRegistration(
SERVICE_WORKER_OK, &registration1_called, &registration1));
@@ -527,7 +532,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) {
job_coordinator()->Register(
pattern,
script_url,
- render_process_id_,
+ NULL,
SaveRegistration(
SERVICE_WORKER_OK, &registration2_called, &registration2));
@@ -552,17 +557,20 @@ TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) {
// Call simulataneous unregister calls.
TEST_F(ServiceWorkerJobTest, ParallelUnreg) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
GURL script_url("http://www.example.com/service_worker.js");
bool unregistration1_called = false;
job_coordinator()->Unregister(
pattern,
- SaveUnregistration(SERVICE_WORKER_OK, &unregistration1_called));
+ SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND,
+ &unregistration1_called));
bool unregistration2_called = false;
job_coordinator()->Unregister(
- pattern, SaveUnregistration(SERVICE_WORKER_OK, &unregistration2_called));
+ pattern,
+ SaveUnregistration(SERVICE_WORKER_ERROR_NOT_FOUND,
+ &unregistration2_called));
ASSERT_FALSE(unregistration1_called);
ASSERT_FALSE(unregistration2_called);
@@ -585,8 +593,8 @@ TEST_F(ServiceWorkerJobTest, ParallelUnreg) {
}
TEST_F(ServiceWorkerJobTest, AbortAll_Register) {
- GURL pattern1("http://www1.example.com/*");
- GURL pattern2("http://www2.example.com/*");
+ GURL pattern1("http://www1.example.com/");
+ GURL pattern2("http://www2.example.com/");
GURL script_url1("http://www1.example.com/service_worker.js");
GURL script_url2("http://www2.example.com/service_worker.js");
@@ -595,7 +603,7 @@ TEST_F(ServiceWorkerJobTest, AbortAll_Register) {
job_coordinator()->Register(
pattern1,
script_url1,
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_ERROR_ABORT,
&registration_called1, &registration1));
@@ -604,7 +612,7 @@ TEST_F(ServiceWorkerJobTest, AbortAll_Register) {
job_coordinator()->Register(
pattern2,
script_url2,
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_ERROR_ABORT,
&registration_called2, &registration2));
@@ -636,8 +644,8 @@ TEST_F(ServiceWorkerJobTest, AbortAll_Register) {
}
TEST_F(ServiceWorkerJobTest, AbortAll_Unregister) {
- GURL pattern1("http://www1.example.com/*");
- GURL pattern2("http://www2.example.com/*");
+ GURL pattern1("http://www1.example.com/");
+ GURL pattern2("http://www2.example.com/");
bool unregistration_called1 = false;
scoped_refptr<ServiceWorkerRegistration> registration1;
@@ -662,7 +670,7 @@ TEST_F(ServiceWorkerJobTest, AbortAll_Unregister) {
}
TEST_F(ServiceWorkerJobTest, AbortAll_RegUnreg) {
- GURL pattern("http://www.example.com/*");
+ GURL pattern("http://www.example.com/");
GURL script_url("http://www.example.com/service_worker.js");
bool registration_called = false;
@@ -670,7 +678,7 @@ TEST_F(ServiceWorkerJobTest, AbortAll_RegUnreg) {
job_coordinator()->Register(
pattern,
script_url,
- render_process_id_,
+ NULL,
SaveRegistration(SERVICE_WORKER_ERROR_ABORT,
&registration_called, &registration));
@@ -699,4 +707,499 @@ TEST_F(ServiceWorkerJobTest, AbortAll_RegUnreg) {
EXPECT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
}
+// Tests that the waiting worker enters the 'redundant' state upon
+// unregistration.
+TEST_F(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) {
+ scoped_refptr<ServiceWorkerRegistration> registration;
+ bool called = false;
+ GURL script_url("http://www.example.com/service_worker.js");
+ job_coordinator()->Register(
+ GURL("http://www.example.com/"),
+ script_url,
+ NULL,
+ SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(called);
+ ASSERT_TRUE(registration.get());
+
+ // Manually create the waiting worker since there is no way to become a
+ // waiting worker until Update is implemented.
+ scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
+ registration.get(), script_url, 1L, helper_->context()->AsWeakPtr());
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ version->StartWorker(CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(SERVICE_WORKER_OK, status);
+
+ version->SetStatus(ServiceWorkerVersion::INSTALLED);
+ registration->SetWaitingVersion(version.get());
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING,
+ version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::INSTALLED, version->status());
+
+ called = false;
+ job_coordinator()->Unregister(GURL("http://www.example.com/"),
+ SaveUnregistration(SERVICE_WORKER_OK, &called));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(called);
+
+ // The version should be stopped since there is no controllee after
+ // unregistration.
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
+}
+
+// Tests that the active worker enters the 'redundant' state upon
+// unregistration.
+TEST_F(ServiceWorkerJobTest, UnregisterActiveSetsRedundant) {
+ scoped_refptr<ServiceWorkerRegistration> registration;
+ bool called = false;
+ job_coordinator()->Register(
+ GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"),
+ NULL,
+ SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(called);
+ ASSERT_TRUE(registration.get());
+
+ scoped_refptr<ServiceWorkerVersion> version = registration->active_version();
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status());
+
+ called = false;
+ job_coordinator()->Unregister(GURL("http://www.example.com/"),
+ SaveUnregistration(SERVICE_WORKER_OK, &called));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(called);
+
+ // The version should be stopped since there is no controllee after
+ // unregistration.
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
+}
+
+// Tests that the active worker enters the 'redundant' state upon
+// unregistration.
+TEST_F(ServiceWorkerJobTest,
+ UnregisterActiveSetsRedundant_WaitForNoControllee) {
+ scoped_refptr<ServiceWorkerRegistration> registration;
+ bool called = false;
+ job_coordinator()->Register(
+ GURL("http://www.example.com/"),
+ GURL("http://www.example.com/service_worker.js"),
+ NULL,
+ SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(called);
+ ASSERT_TRUE(registration.get());
+
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ new ServiceWorkerProviderHost(33 /* dummy render process id */,
+ 1 /* dummy provider_id */,
+ context()->AsWeakPtr(),
+ NULL));
+ registration->active_version()->AddControllee(host.get());
+
+ scoped_refptr<ServiceWorkerVersion> version = registration->active_version();
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status());
+
+ called = false;
+ job_coordinator()->Unregister(GURL("http://www.example.com/"),
+ SaveUnregistration(SERVICE_WORKER_OK, &called));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(called);
+
+ // The version should be running since there is still a controllee.
+ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status());
+
+ registration->active_version()->RemoveControllee(host.get());
+ base::RunLoop().RunUntilIdle();
+
+ // The version should be stopped since there is no controllee.
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status());
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
+}
+
+namespace { // Helpers for the update job tests.
+
+const GURL kNoChangeOrigin("http://nochange/");
+const GURL kNewVersionOrigin("http://newversion/");
+const std::string kScope("scope/");
+const std::string kScript("script.js");
+
+void RunNestedUntilIdle() {
+ base::MessageLoop::ScopedNestableTaskAllower allow(
+ base::MessageLoop::current());
+ base::MessageLoop::current()->RunUntilIdle();
+}
+
+void OnIOComplete(int* rv_out, int rv) {
+ *rv_out = rv;
+}
+
+void WriteResponse(
+ ServiceWorkerStorage* storage, int64 id,
+ const std::string& headers,
+ IOBuffer* body, int length) {
+ scoped_ptr<ServiceWorkerResponseWriter> writer =
+ storage->CreateResponseWriter(id);
+
+ scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
+ info->request_time = base::Time::Now();
+ info->response_time = base::Time::Now();
+ info->was_cached = false;
+ info->headers = new net::HttpResponseHeaders(headers);
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
+ new HttpResponseInfoIOBuffer(info.release());
+
+ int rv = -1234;
+ writer->WriteInfo(info_buffer.get(), base::Bind(&OnIOComplete, &rv));
+ RunNestedUntilIdle();
+ EXPECT_LT(0, rv);
+
+ rv = -1234;
+ writer->WriteData(body, length,
+ base::Bind(&OnIOComplete, &rv));
+ RunNestedUntilIdle();
+ EXPECT_EQ(length, rv);
+}
+
+void WriteStringResponse(
+ ServiceWorkerStorage* storage, int64 id,
+ const std::string& body) {
+ scoped_refptr<IOBuffer> body_buffer(new WrappedIOBuffer(body.data()));
+ const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0\0";
+ std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
+ WriteResponse(storage, id, headers, body_buffer.get(), body.length());
+}
+
+class UpdateJobTestHelper
+ : public EmbeddedWorkerTestHelper,
+ public ServiceWorkerRegistration::Listener,
+ public ServiceWorkerVersion::Listener {
+ public:
+ struct AttributeChangeLogEntry {
+ int64 registration_id;
+ ChangedVersionAttributesMask mask;
+ ServiceWorkerRegistrationInfo info;
+ };
+
+ struct StateChangeLogEntry {
+ int64 version_id;
+ ServiceWorkerVersion::Status status;
+ };
+
+ UpdateJobTestHelper(int mock_render_process_id)
+ : EmbeddedWorkerTestHelper(mock_render_process_id),
+ update_found_(false) {}
+ ~UpdateJobTestHelper() override {
+ if (registration_.get())
+ registration_->RemoveListener(this);
+ }
+
+ ServiceWorkerStorage* storage() { return context()->storage(); }
+ ServiceWorkerJobCoordinator* job_coordinator() {
+ return context()->job_coordinator();
+ }
+
+ scoped_refptr<ServiceWorkerRegistration> SetupInitialRegistration(
+ const GURL& test_origin) {
+ scoped_refptr<ServiceWorkerRegistration> registration;
+ bool called = false;
+ job_coordinator()->Register(
+ test_origin.Resolve(kScope),
+ test_origin.Resolve(kScript),
+ NULL,
+ SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ EXPECT_TRUE(registration.get());
+ EXPECT_TRUE(registration->active_version());
+ EXPECT_FALSE(registration->installing_version());
+ EXPECT_FALSE(registration->waiting_version());
+ registration_ = registration;
+ return registration;
+ }
+
+ // EmbeddedWorkerTestHelper overrides
+ void OnStartWorker(int embedded_worker_id,
+ int64 version_id,
+ const GURL& scope,
+ const GURL& script,
+ bool pause_after_download) override {
+ const std::string kMockScriptBody = "mock_script";
+ const uint64 kMockScriptSize = 19284;
+ ServiceWorkerVersion* version = context()->GetLiveVersion(version_id);
+ ASSERT_TRUE(version);
+ version->AddListener(this);
+
+ if (!pause_after_download) {
+ // Spoof caching the script for the initial version.
+ int64 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());
+ } else {
+ // Spoof caching the script for the new version.
+ int64 resource_id = storage()->NewResourceId();
+ version->script_cache_map()->NotifyStartedCaching(script, resource_id);
+ if (script.GetOrigin() == kNoChangeOrigin)
+ WriteStringResponse(storage(), resource_id, kMockScriptBody);
+ else
+ WriteStringResponse(storage(), resource_id, "mock_different_script");
+ version->script_cache_map()->NotifyFinishedCaching(
+ script, kMockScriptSize, net::URLRequestStatus());
+ }
+ EmbeddedWorkerTestHelper::OnStartWorker(
+ embedded_worker_id, version_id, scope, script, pause_after_download);
+ }
+
+ // ServiceWorkerRegistration::Listener overrides
+ void OnVersionAttributesChanged(
+ ServiceWorkerRegistration* registration,
+ ChangedVersionAttributesMask changed_mask,
+ const ServiceWorkerRegistrationInfo& info) override {
+ AttributeChangeLogEntry entry;
+ entry.registration_id = registration->id();
+ entry.mask = changed_mask;
+ entry.info = info;
+ attribute_change_log_.push_back(entry);
+ }
+
+ void OnRegistrationFailed(ServiceWorkerRegistration* registration) override {
+ NOTREACHED();
+ }
+
+ void OnRegistrationFinishedUninstalling(
+ ServiceWorkerRegistration* registration) override {
+ NOTREACHED();
+ }
+
+ void OnUpdateFound(ServiceWorkerRegistration* registration) override {
+ ASSERT_FALSE(update_found_);
+ update_found_ = true;
+ }
+
+ // ServiceWorkerVersion::Listener overrides
+ void OnVersionStateChanged(ServiceWorkerVersion* version) override {
+ StateChangeLogEntry entry;
+ entry.version_id = version->version_id();
+ entry.status = version->status();
+ state_change_log_.push_back(entry);
+ }
+
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+
+ std::vector<AttributeChangeLogEntry> attribute_change_log_;
+ std::vector<StateChangeLogEntry> state_change_log_;
+ bool update_found_;
+};
+
+} // namespace
+
+TEST_F(ServiceWorkerJobTest, Update_NoChange) {
+ UpdateJobTestHelper* update_helper =
+ new UpdateJobTestHelper(render_process_id_);
+ helper_.reset(update_helper);
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ update_helper->SetupInitialRegistration(kNoChangeOrigin);
+ ASSERT_TRUE(registration.get());
+ ASSERT_EQ(4u, update_helper->state_change_log_.size());
+ EXPECT_EQ(ServiceWorkerVersion::INSTALLING,
+ update_helper->state_change_log_[0].status);
+ EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
+ update_helper->state_change_log_[1].status);
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATING,
+ update_helper->state_change_log_[2].status);
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
+ update_helper->state_change_log_[3].status);
+ update_helper->state_change_log_.clear();
+
+ // Run the update job.
+ registration->AddListener(update_helper);
+ scoped_refptr<ServiceWorkerVersion> first_version =
+ registration->active_version();
+ first_version->StartUpdate();
+ base::RunLoop().RunUntilIdle();
+
+ // Verify results.
+ ASSERT_TRUE(registration->active_version());
+ EXPECT_EQ(first_version.get(), registration->active_version());
+ EXPECT_FALSE(registration->installing_version());
+ EXPECT_FALSE(registration->waiting_version());
+ EXPECT_TRUE(update_helper->attribute_change_log_.empty());
+ ASSERT_EQ(1u, update_helper->state_change_log_.size());
+ EXPECT_NE(registration->active_version()->version_id(),
+ update_helper->state_change_log_[0].version_id);
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT,
+ update_helper->state_change_log_[0].status);
+ EXPECT_FALSE(update_helper->update_found_);
+}
+
+TEST_F(ServiceWorkerJobTest, Update_NewVersion) {
+ UpdateJobTestHelper* update_helper =
+ new UpdateJobTestHelper(render_process_id_);
+ helper_.reset(update_helper);
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ update_helper->SetupInitialRegistration(kNewVersionOrigin);
+ ASSERT_TRUE(registration.get());
+ update_helper->state_change_log_.clear();
+
+ // Run the update job.
+ registration->AddListener(update_helper);
+ scoped_refptr<ServiceWorkerVersion> first_version =
+ registration->active_version();
+ first_version->StartUpdate();
+ base::RunLoop().RunUntilIdle();
+
+ // Verify results.
+ ASSERT_TRUE(registration->active_version());
+ EXPECT_NE(first_version.get(), registration->active_version());
+ EXPECT_FALSE(registration->installing_version());
+ EXPECT_FALSE(registration->waiting_version());
+ ASSERT_EQ(3u, update_helper->attribute_change_log_.size());
+
+ UpdateJobTestHelper::AttributeChangeLogEntry entry;
+ entry = update_helper->attribute_change_log_[0];
+ EXPECT_TRUE(entry.mask.installing_changed());
+ EXPECT_FALSE(entry.mask.waiting_changed());
+ EXPECT_FALSE(entry.mask.active_changed());
+ EXPECT_NE(entry.info.installing_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_EQ(entry.info.waiting_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_NE(entry.info.active_version.version_id,
+ kInvalidServiceWorkerVersionId);
+
+ entry = update_helper->attribute_change_log_[1];
+ EXPECT_TRUE(entry.mask.installing_changed());
+ EXPECT_TRUE(entry.mask.waiting_changed());
+ EXPECT_FALSE(entry.mask.active_changed());
+ EXPECT_EQ(entry.info.installing_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_NE(entry.info.waiting_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_NE(entry.info.active_version.version_id,
+ kInvalidServiceWorkerVersionId);
+
+ entry = update_helper->attribute_change_log_[2];
+ EXPECT_FALSE(entry.mask.installing_changed());
+ EXPECT_TRUE(entry.mask.waiting_changed());
+ EXPECT_TRUE(entry.mask.active_changed());
+ EXPECT_EQ(entry.info.installing_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_EQ(entry.info.waiting_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_NE(entry.info.active_version.version_id,
+ kInvalidServiceWorkerVersionId);
+
+ // expected version state transitions:
+ // new.installing, new.installed,
+ // old.redundant,
+ // new.activating, new.activated
+ ASSERT_EQ(5u, update_helper->state_change_log_.size());
+
+ EXPECT_EQ(registration->active_version()->version_id(),
+ update_helper->state_change_log_[0].version_id);
+ EXPECT_EQ(ServiceWorkerVersion::INSTALLING,
+ update_helper->state_change_log_[0].status);
+
+ EXPECT_EQ(registration->active_version()->version_id(),
+ update_helper->state_change_log_[1].version_id);
+ EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
+ update_helper->state_change_log_[1].status);
+
+ EXPECT_EQ(first_version->version_id(),
+ update_helper->state_change_log_[2].version_id);
+ EXPECT_EQ(ServiceWorkerVersion::REDUNDANT,
+ update_helper->state_change_log_[2].status);
+
+ EXPECT_EQ(registration->active_version()->version_id(),
+ update_helper->state_change_log_[3].version_id);
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATING,
+ update_helper->state_change_log_[3].status);
+
+ EXPECT_EQ(registration->active_version()->version_id(),
+ update_helper->state_change_log_[4].version_id);
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
+ update_helper->state_change_log_[4].status);
+
+ EXPECT_TRUE(update_helper->update_found_);
+}
+
+TEST_F(ServiceWorkerJobTest, Update_NewestVersionChanged) {
+ bool called;
+ scoped_refptr<ServiceWorkerRegistration> registration;
+ job_coordinator()->Register(
+ GURL("http://www.example.com/one/"),
+ GURL("http://www.example.com/service_worker.js"),
+ NULL,
+ SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
+
+ EXPECT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+ ServiceWorkerVersion* active_version = registration->active_version();
+
+ // Queue an Update, it should abort when it starts and sees the new version.
+ job_coordinator()->Update(registration.get());
+
+ // Add a waiting version with new script.
+ scoped_refptr<ServiceWorkerVersion> version =
+ new ServiceWorkerVersion(registration.get(),
+ GURL("http://www.example.com/new_worker.js"),
+ 2L /* dummy version id */,
+ helper_->context()->AsWeakPtr());
+ registration->SetWaitingVersion(version.get());
+
+ base::RunLoop().RunUntilIdle();
+
+ // Verify the registration was not modified by the Update.
+ EXPECT_EQ(active_version, registration->active_version());
+ EXPECT_EQ(version.get(), registration->waiting_version());
+ EXPECT_EQ(NULL, registration->installing_version());
+}
+
+TEST_F(ServiceWorkerJobTest, Update_UninstallingRegistration) {
+ bool called;
+ scoped_refptr<ServiceWorkerRegistration> registration;
+ job_coordinator()->Register(
+ GURL("http://www.example.com/one/"),
+ GURL("http://www.example.com/service_worker.js"),
+ NULL,
+ SaveRegistration(SERVICE_WORKER_OK, &called, &registration));
+
+ EXPECT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+
+ // Add a controllee and queue an unregister to force the uninstalling state.
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ new ServiceWorkerProviderHost(33 /* dummy render_process id */,
+ 1 /* dummy provider_id */,
+ helper_->context()->AsWeakPtr(),
+ NULL));
+ ServiceWorkerVersion* active_version = registration->active_version();
+ active_version->AddControllee(host.get());
+ job_coordinator()->Unregister(GURL("http://www.example.com/one/"),
+ SaveUnregistration(SERVICE_WORKER_OK, &called));
+
+ // Update should abort after it starts and sees uninstalling.
+ job_coordinator()->Update(registration.get());
+
+ EXPECT_FALSE(called);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(called);
+
+ // Verify the registration was not modified by the Update.
+ EXPECT_TRUE(registration->is_uninstalling());
+ EXPECT_EQ(active_version, registration->active_version());
+ EXPECT_EQ(NULL, registration->waiting_version());
+ EXPECT_EQ(NULL, registration->installing_version());
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_metrics.cc b/chromium/content/browser/service_worker/service_worker_metrics.cc
new file mode 100644
index 00000000000..6e3ddf1d7aa
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_metrics.cc
@@ -0,0 +1,58 @@
+// 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/service_worker/service_worker_metrics.h"
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/user_metrics_action.h"
+#include "content/public/browser/user_metrics.h"
+
+namespace content {
+
+// static
+void ServiceWorkerMetrics::CountInitDiskCacheResult(bool result) {
+ UMA_HISTOGRAM_BOOLEAN("ServiceWorker.DiskCache.InitResult", result);
+}
+
+// static
+void ServiceWorkerMetrics::CountReadResponseResult(
+ ServiceWorkerMetrics::ReadResponseResult result) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.DiskCache.ReadResponseResult",
+ result, NUM_READ_RESPONSE_RESULT_TYPES);
+}
+
+// static
+void ServiceWorkerMetrics::CountWriteResponseResult(
+ ServiceWorkerMetrics::WriteResponseResult result) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.DiskCache.WriteResponseResult",
+ result, NUM_WRITE_RESPONSE_RESULT_TYPES);
+}
+
+// static
+void ServiceWorkerMetrics::CountOpenDatabaseResult(
+ ServiceWorkerDatabase::Status status) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.Database.OpenResult",
+ status, ServiceWorkerDatabase::STATUS_ERROR_MAX);
+}
+
+// static
+void ServiceWorkerMetrics::CountReadDatabaseResult(
+ ServiceWorkerDatabase::Status status) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.Database.ReadResult",
+ status, ServiceWorkerDatabase::STATUS_ERROR_MAX);
+}
+
+// static
+void ServiceWorkerMetrics::CountWriteDatabaseResult(
+ ServiceWorkerDatabase::Status status) {
+ UMA_HISTOGRAM_ENUMERATION("ServiceWorker.Database.WriteResult",
+ status, ServiceWorkerDatabase::STATUS_ERROR_MAX);
+}
+
+// static
+void ServiceWorkerMetrics::CountControlledPageLoad() {
+ RecordAction(base::UserMetricsAction("ServiceWorker.ControlledPageLoad"));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_metrics.h b/chromium/content/browser/service_worker/service_worker_metrics.h
new file mode 100644
index 00000000000..deea3b3f1c4
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_metrics.h
@@ -0,0 +1,48 @@
+// 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_SERVICE_WORKER_SERVICE_WORKER_METRICS_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_METRICS_H_
+
+#include "base/macros.h"
+#include "content/browser/service_worker/service_worker_database.h"
+
+namespace content {
+
+class ServiceWorkerMetrics {
+ public:
+ enum ReadResponseResult {
+ READ_OK,
+ READ_HEADERS_ERROR,
+ READ_DATA_ERROR,
+ NUM_READ_RESPONSE_RESULT_TYPES,
+ };
+
+ enum WriteResponseResult {
+ WRITE_OK,
+ WRITE_HEADERS_ERROR,
+ WRITE_DATA_ERROR,
+ NUM_WRITE_RESPONSE_RESULT_TYPES,
+ };
+
+ // Used for ServiceWorkerDiskCache.
+ static void CountInitDiskCacheResult(bool result);
+ static void CountReadResponseResult(ReadResponseResult result);
+ static void CountWriteResponseResult(WriteResponseResult result);
+
+ // Used for ServiceWorkerDatabase.
+ static void CountOpenDatabaseResult(ServiceWorkerDatabase::Status status);
+ static void CountReadDatabaseResult(ServiceWorkerDatabase::Status status);
+ static void CountWriteDatabaseResult(ServiceWorkerDatabase::Status status);
+
+ // Counts the number of page loads controlled by a Service Worker.
+ static void CountControlledPageLoad();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_METRICS_H_
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 7395e7b7b77..fe7e5e34f7d 100644
--- a/chromium/content/browser/service_worker/service_worker_process_manager.cc
+++ b/chromium/content/browser/service_worker/service_worker_process_manager.cc
@@ -12,6 +12,18 @@
namespace content {
+namespace {
+
+// Functor to sort by the .second element of a struct.
+struct SecondGreater {
+ template <typename Value>
+ bool operator()(const Value& lhs, const Value& rhs) {
+ return lhs.second > rhs.second;
+ }
+};
+
+} // namespace
+
static bool IncrementWorkerRefCountByPid(int process_id) {
RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
if (!rph || rph->FastShutdownStarted())
@@ -50,6 +62,7 @@ ServiceWorkerProcessManager::~ServiceWorkerProcessManager() {
}
void ServiceWorkerProcessManager::Shutdown() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
browser_context_ = NULL;
for (std::map<int, ProcessInfo>::const_iterator it = instance_info_.begin();
it != instance_info_.end();
@@ -61,9 +74,66 @@ void ServiceWorkerProcessManager::Shutdown() {
instance_info_.clear();
}
+void ServiceWorkerProcessManager::AddProcessReferenceToPattern(
+ const GURL& pattern, int process_id) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ServiceWorkerProcessManager::AddProcessReferenceToPattern,
+ weak_this_,
+ pattern,
+ process_id));
+ return;
+ }
+
+ ProcessRefMap& process_refs = pattern_processes_[pattern];
+ ++process_refs[process_id];
+}
+
+void ServiceWorkerProcessManager::RemoveProcessReferenceFromPattern(
+ const GURL& pattern, int process_id) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &ServiceWorkerProcessManager::RemoveProcessReferenceFromPattern,
+ weak_this_,
+ pattern,
+ process_id));
+ return;
+ }
+
+ PatternProcessRefMap::iterator it = pattern_processes_.find(pattern);
+ if (it == pattern_processes_.end()) {
+ NOTREACHED() << "process refrences not found for pattern: " << pattern;
+ return;
+ }
+ ProcessRefMap& process_refs = it->second;
+ ProcessRefMap::iterator found = process_refs.find(process_id);
+ if (found == process_refs.end()) {
+ NOTREACHED() << "Releasing unknown process ref " << process_id;
+ return;
+ }
+ if (--found->second == 0) {
+ process_refs.erase(found);
+ if (process_refs.empty())
+ pattern_processes_.erase(it);
+ }
+}
+
+bool ServiceWorkerProcessManager::PatternHasProcessToRun(
+ const GURL& pattern) const {
+ PatternProcessRefMap::const_iterator it = pattern_processes_.find(pattern);
+ if (it == pattern_processes_.end())
+ return false;
+ return !it->second.empty();
+}
+
void ServiceWorkerProcessManager::AllocateWorkerProcess(
int embedded_worker_id,
- const std::vector<int>& process_ids,
+ const GURL& pattern,
const GURL& script_url,
const base::Callback<void(ServiceWorkerStatusCode, int process_id)>&
callback) {
@@ -74,7 +144,7 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
base::Bind(&ServiceWorkerProcessManager::AllocateWorkerProcess,
weak_this_,
embedded_worker_id,
- process_ids,
+ pattern,
script_url,
callback));
return;
@@ -93,17 +163,18 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess(
DCHECK(!ContainsKey(instance_info_, embedded_worker_id))
<< embedded_worker_id << " already has a process allocated";
- for (std::vector<int>::const_iterator it = process_ids.begin();
- it != process_ids.end();
+ std::vector<int> sorted_candidates = SortProcessesForPattern(pattern);
+ for (std::vector<int>::const_iterator it = sorted_candidates.begin();
+ it != sorted_candidates.end();
++it) {
- if (IncrementWorkerRefCountByPid(*it)) {
- instance_info_.insert(
- std::make_pair(embedded_worker_id, ProcessInfo(*it)));
- BrowserThread::PostTask(BrowserThread::IO,
- FROM_HERE,
- base::Bind(callback, SERVICE_WORKER_OK, *it));
- return;
- }
+ if (!IncrementWorkerRefCountByPid(*it))
+ continue;
+ instance_info_.insert(
+ std::make_pair(embedded_worker_id, ProcessInfo(*it)));
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_OK, *it));
+ return;
}
if (!browser_context_) {
@@ -164,7 +235,7 @@ void ServiceWorkerProcessManager::ReleaseWorkerProcess(int embedded_worker_id) {
instance_info_.find(embedded_worker_id);
DCHECK(info != instance_info_.end());
RenderProcessHost* rph = NULL;
- if (info->second.site_instance) {
+ if (info->second.site_instance.get()) {
rph = info->second.site_instance->GetProcess();
DCHECK_EQ(info->second.process_id, rph->GetID())
<< "A SiteInstance's process shouldn't get destroyed while we're "
@@ -179,6 +250,22 @@ void ServiceWorkerProcessManager::ReleaseWorkerProcess(int embedded_worker_id) {
instance_info_.erase(info);
}
+std::vector<int> ServiceWorkerProcessManager::SortProcessesForPattern(
+ const GURL& pattern) const {
+ PatternProcessRefMap::const_iterator it = pattern_processes_.find(pattern);
+ if (it == pattern_processes_.end())
+ return std::vector<int>();
+
+ std::vector<std::pair<int, int> > counted(
+ it->second.begin(), it->second.end());
+ std::sort(counted.begin(), counted.end(), SecondGreater());
+
+ std::vector<int> result(counted.size());
+ for (size_t i = 0; i < counted.size(); ++i)
+ result[i] = counted[i].first;
+ return result;
+}
+
} // namespace content
namespace base {
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 85fbcc1c050..2a3bae1db3b 100644
--- a/chromium/content/browser/service_worker/service_worker_process_manager.h
+++ b/chromium/content/browser/service_worker/service_worker_process_manager.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/common/service_worker/service_worker_status_code.h"
@@ -21,9 +22,9 @@ class BrowserContext;
class SiteInstance;
// Interacts with the UI thread to keep RenderProcessHosts alive while the
-// ServiceWorker system is using them. Each instance of
-// ServiceWorkerProcessManager is destroyed on the UI thread shortly after its
-// ServiceWorkerContextWrapper is destroyed.
+// ServiceWorker system is using them. It also tracks candidate processes
+// for each pattern. Each instance of ServiceWorkerProcessManager is destroyed
+// on the UI thread shortly after its ServiceWorkerContextWrapper is destroyed.
class CONTENT_EXPORT ServiceWorkerProcessManager {
public:
// |*this| must be owned by a ServiceWorkerContextWrapper in a
@@ -33,21 +34,19 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
// Shutdown must be called before the ProcessManager is destroyed.
~ServiceWorkerProcessManager();
- // Synchronously prevents new processes from being allocated.
- // TODO(jyasskin): Drop references to RenderProcessHosts too.
+ // Synchronously prevents new processes from being allocated
+ // and drops references to RenderProcessHosts.
void Shutdown();
// Returns a reference to a running process suitable for starting the Service
- // Worker at |script_url|. Processes in |process_ids| will be checked in order
- // for existence, and if none exist, then a new process will be created. Posts
- // |callback| to the IO thread to indicate whether creation succeeded and the
- // process ID that has a new reference.
+ // Worker at |script_url|. Posts |callback| to the IO thread to indicate
+ // whether creation succeeded and the process ID that has a new reference.
//
// Allocation can fail with SERVICE_WORKER_ERROR_START_WORKER_FAILED if
// RenderProcessHost::Init fails.
void AllocateWorkerProcess(
int embedded_worker_id,
- const std::vector<int>& process_ids,
+ const GURL& pattern,
const GURL& script_url,
const base::Callback<void(ServiceWorkerStatusCode, int process_id)>&
callback);
@@ -65,7 +64,17 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
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);
+ void RemoveProcessReferenceFromPattern(const GURL& pattern, int process_id);
+
+ // Returns true if the |pattern| has at least one process to run.
+ bool PatternHasProcessToRun(const GURL& pattern) const;
+
private:
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProcessManagerTest, SortProcess);
+
// Information about the process for an EmbeddedWorkerInstance.
struct ProcessInfo {
explicit ProcessInfo(const scoped_refptr<SiteInstance>& site_instance);
@@ -84,6 +93,15 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
int process_id;
};
+ // Maps the process ID to its reference count.
+ typedef std::map<int, int> ProcessRefMap;
+
+ // Maps registration scope pattern to ProcessRefMap.
+ typedef std::map<const GURL, ProcessRefMap> PatternProcessRefMap;
+
+ // Returns a process vector sorted by the reference count for the |pattern|.
+ std::vector<int> SortProcessesForPattern(const GURL& pattern) const;
+
// These fields are only accessed on the UI thread.
BrowserContext* browser_context_;
@@ -100,6 +118,10 @@ class CONTENT_EXPORT ServiceWorkerProcessManager {
// EmbeddedWorkerInstances.
int process_id_for_test_;
+ // Candidate processes info for each pattern, should be accessed on the
+ // UI thread.
+ PatternProcessRefMap pattern_processes_;
+
// Used to double-check that we don't access *this after it's destroyed.
base::WeakPtrFactory<ServiceWorkerProcessManager> weak_this_factory_;
const base::WeakPtr<ServiceWorkerProcessManager> weak_this_;
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
new file mode 100644
index 00000000000..3b53740aad4
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc
@@ -0,0 +1,54 @@
+// 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 "base/basictypes.h"
+#include "content/browser/service_worker/service_worker_process_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"
+#include "url/gurl.h"
+
+namespace content {
+
+class ServiceWorkerProcessManagerTest : public testing::Test {
+ public:
+ ServiceWorkerProcessManagerTest() {}
+
+ void SetUp() override {
+ process_manager_.reset(new ServiceWorkerProcessManager(NULL));
+ pattern_ = GURL("http://www.example.com/");
+ }
+
+ void TearDown() override { process_manager_.reset(); }
+
+ protected:
+ scoped_ptr<ServiceWorkerProcessManager> process_manager_;
+ GURL pattern_;
+
+ private:
+ content::TestBrowserThreadBundle thread_bundle_;
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProcessManagerTest);
+};
+
+TEST_F(ServiceWorkerProcessManagerTest, SortProcess) {
+ // Process 1 has 2 ref, 2 has 3 refs and 3 has 1 refs.
+ process_manager_->AddProcessReferenceToPattern(pattern_, 1);
+ process_manager_->AddProcessReferenceToPattern(pattern_, 1);
+ process_manager_->AddProcessReferenceToPattern(pattern_, 2);
+ process_manager_->AddProcessReferenceToPattern(pattern_, 2);
+ process_manager_->AddProcessReferenceToPattern(pattern_, 2);
+ process_manager_->AddProcessReferenceToPattern(pattern_, 3);
+
+ // Process 2 has the biggest # of references and it should be chosen.
+ EXPECT_THAT(process_manager_->SortProcessesForPattern(pattern_),
+ testing::ElementsAre(2, 1, 3));
+
+ process_manager_->RemoveProcessReferenceFromPattern(pattern_, 1);
+ process_manager_->RemoveProcessReferenceFromPattern(pattern_, 1);
+ // Scores for each process: 2 : 3, 3 : 1, process 1 is removed.
+ EXPECT_THAT(process_manager_->SortProcessesForPattern(pattern_),
+ testing::ElementsAre(2, 3));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_proto.gyp b/chromium/content/browser/service_worker/service_worker_proto.gyp
index b2588fff6a5..aab5e63bb7f 100644
--- a/chromium/content/browser/service_worker/service_worker_proto.gyp
+++ b/chromium/content/browser/service_worker/service_worker_proto.gyp
@@ -1,10 +1,11 @@
{
'targets': [
{
- # GN version: //content/browser/service_worker:database_proto
- 'target_name': 'database_proto',
+ # GN version: //content/browser/service_worker:proto
+ 'target_name': 'proto',
'type': 'static_library',
'sources': [
+ 'service_worker_cache.proto',
'service_worker_database.proto',
],
'variables': {
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 eeba3736d03..e16454558e0 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host.cc
+++ b/chromium/content/browser/service_worker/service_worker_provider_host.cc
@@ -11,9 +11,12 @@
#include "content/browser/service_worker/service_worker_controllee_request_handler.h"
#include "content/browser/service_worker/service_worker_dispatcher_host.h"
#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_utils.h"
#include "content/browser/service_worker/service_worker_version.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"
namespace content {
@@ -26,14 +29,30 @@ ServiceWorkerProviderHost::ServiceWorkerProviderHost(
: process_id_(process_id),
provider_id_(provider_id),
context_(context),
- dispatcher_host_(dispatcher_host) {
+ dispatcher_host_(dispatcher_host),
+ allow_association_(true) {
}
ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
- if (active_version_)
- active_version_->RemoveControllee(this);
- if (waiting_version_)
- waiting_version_->RemoveWaitingControllee(this);
+ // Clear docurl so the deferred activation of a waiting worker
+ // won't associate the new version with a provider being destroyed.
+ document_url_ = GURL();
+ if (controlling_version_.get())
+ controlling_version_->RemoveControllee(this);
+ if (associated_registration_.get()) {
+ DecreaseProcessReference(associated_registration_->pattern());
+ associated_registration_->RemoveListener(this);
+ }
+ for (std::vector<GURL>::iterator it = associated_patterns_.begin();
+ it != associated_patterns_.end(); ++it) {
+ DecreaseProcessReference(*it);
+ }
+}
+
+void ServiceWorkerProviderHost::OnRegistrationFailed(
+ ServiceWorkerRegistration* registration) {
+ DCHECK_EQ(associated_registration_.get(), registration);
+ DisassociateRegistration();
}
void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
@@ -41,47 +60,33 @@ void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
document_url_ = url;
}
-void ServiceWorkerProviderHost::SetActiveVersion(
- ServiceWorkerVersion* version) {
- if (version == active_version_)
- return;
- scoped_refptr<ServiceWorkerVersion> previous_version = active_version_;
- active_version_ = version;
- if (version)
- version->AddControllee(this);
- if (previous_version)
- previous_version->RemoveControllee(this);
-
- if (!dispatcher_host_)
- return; // Could be NULL in some tests.
-
- dispatcher_host_->Send(new ServiceWorkerMsg_SetCurrentServiceWorker(
- kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
+void ServiceWorkerProviderHost::SetTopmostFrameUrl(const GURL& url) {
+ topmost_frame_url_ = url;
}
-void ServiceWorkerProviderHost::SetWaitingVersion(
+void ServiceWorkerProviderHost::SetControllerVersionAttribute(
ServiceWorkerVersion* version) {
- DCHECK(ValidateVersionForAssociation(version));
- if (version == waiting_version_)
+ if (version == controlling_version_.get())
return;
- scoped_refptr<ServiceWorkerVersion> previous_version = waiting_version_;
- waiting_version_ = version;
+
+ scoped_refptr<ServiceWorkerVersion> previous_version = controlling_version_;
+ controlling_version_ = version;
if (version)
- version->AddWaitingControllee(this);
- if (previous_version)
- previous_version->RemoveWaitingControllee(this);
+ version->AddControllee(this);
+ if (previous_version.get())
+ previous_version->RemoveControllee(this);
if (!dispatcher_host_)
return; // Could be NULL in some tests.
- dispatcher_host_->Send(new ServiceWorkerMsg_SetWaitingServiceWorker(
+ dispatcher_host_->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
}
bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
if (!context_)
return true; // System is shutting down.
- if (active_version_)
+ if (active_version())
return false; // Unexpected bad message.
ServiceWorkerVersion* live_version = context_->GetLiveVersion(version_id);
@@ -100,43 +105,87 @@ bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
return true;
}
+void ServiceWorkerProviderHost::AssociateRegistration(
+ ServiceWorkerRegistration* registration) {
+ DCHECK(CanAssociateRegistration(registration));
+ if (associated_registration_.get())
+ DecreaseProcessReference(associated_registration_->pattern());
+ IncreaseProcessReference(registration->pattern());
+
+ if (dispatcher_host_) {
+ ServiceWorkerRegistrationHandle* handle =
+ dispatcher_host_->GetOrCreateRegistrationHandle(
+ provider_id(), registration);
+
+ ServiceWorkerVersionAttributes attrs;
+ attrs.installing = handle->CreateServiceWorkerHandleAndPass(
+ registration->installing_version());
+ attrs.waiting = handle->CreateServiceWorkerHandleAndPass(
+ registration->waiting_version());
+ attrs.active = handle->CreateServiceWorkerHandleAndPass(
+ registration->active_version());
+
+ dispatcher_host_->Send(new ServiceWorkerMsg_AssociateRegistration(
+ kDocumentMainThreadId, provider_id(), handle->GetObjectInfo(), attrs));
+ }
+
+ associated_registration_ = registration;
+ associated_registration_->AddListener(this);
+ SetControllerVersionAttribute(registration->active_version());
+}
+
+void ServiceWorkerProviderHost::DisassociateRegistration() {
+ if (!associated_registration_.get())
+ return;
+ DecreaseProcessReference(associated_registration_->pattern());
+ associated_registration_->RemoveListener(this);
+ associated_registration_ = NULL;
+ SetControllerVersionAttribute(NULL);
+
+ if (dispatcher_host_) {
+ dispatcher_host_->Send(new ServiceWorkerMsg_DisassociateRegistration(
+ kDocumentMainThreadId, provider_id()));
+ }
+}
+
scoped_ptr<ServiceWorkerRequestHandler>
ServiceWorkerProviderHost::CreateRequestHandler(
- ResourceType::Type resource_type,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context) {
+ FetchRequestMode request_mode,
+ FetchCredentialsMode credentials_mode,
+ ResourceType resource_type,
+ RequestContextType request_context_type,
+ RequestContextFrameType frame_type,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ scoped_refptr<ResourceRequestBody> body) {
if (IsHostToRunningServiceWorker()) {
return scoped_ptr<ServiceWorkerRequestHandler>(
new ServiceWorkerContextRequestHandler(
context_, AsWeakPtr(), blob_storage_context, resource_type));
}
if (ServiceWorkerUtils::IsMainResourceType(resource_type) ||
- active_version()) {
+ controlling_version()) {
return scoped_ptr<ServiceWorkerRequestHandler>(
- new ServiceWorkerControlleeRequestHandler(
- context_, AsWeakPtr(), blob_storage_context, resource_type));
+ new ServiceWorkerControlleeRequestHandler(context_,
+ AsWeakPtr(),
+ blob_storage_context,
+ request_mode,
+ credentials_mode,
+ resource_type,
+ request_context_type,
+ frame_type,
+ body));
}
return scoped_ptr<ServiceWorkerRequestHandler>();
}
-bool ServiceWorkerProviderHost::ValidateVersionForAssociation(
- ServiceWorkerVersion* version) {
- if (running_hosted_version_)
+bool ServiceWorkerProviderHost::CanAssociateRegistration(
+ ServiceWorkerRegistration* registration) {
+ if (!context_)
+ return false;
+ if (running_hosted_version_.get())
+ return false;
+ if (!registration || associated_registration_.get() || !allow_association_)
return false;
- if (!version)
- return true;
-
- // A version to be associated with this provider should have the same
- // registration (scope) as current active/waiting versions.
- if (active_version_) {
- if (active_version_->registration_id() != version->registration_id())
- return false;
- DCHECK_EQ(active_version_->scope(), version->scope());
- }
- if (waiting_version_) {
- if (waiting_version_->registration_id() != version->registration_id())
- return false;
- DCHECK_EQ(waiting_version_->scope(), version->scope());
- }
return true;
}
@@ -159,20 +208,44 @@ void ServiceWorkerProviderHost::PostMessage(
new_routing_ids));
}
+void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
+ const GURL& pattern) {
+ associated_patterns_.push_back(pattern);
+ IncreaseProcessReference(pattern);
+}
+
ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass(
ServiceWorkerVersion* version) {
- DCHECK(ValidateVersionForAssociation(version));
ServiceWorkerObjectInfo info;
if (context_ && version) {
scoped_ptr<ServiceWorkerHandle> handle =
- ServiceWorkerHandle::Create(context_, dispatcher_host_,
- kDocumentMainThreadId, version);
+ ServiceWorkerHandle::Create(context_,
+ dispatcher_host_,
+ kDocumentMainThreadId,
+ provider_id_,
+ version);
info = handle->GetObjectInfo();
dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
}
return info;
}
+void ServiceWorkerProviderHost::IncreaseProcessReference(
+ const GURL& pattern) {
+ if (context_ && context_->process_manager()) {
+ context_->process_manager()->AddProcessReferenceToPattern(
+ pattern, process_id_);
+ }
+}
+
+void ServiceWorkerProviderHost::DecreaseProcessReference(
+ const GURL& pattern) {
+ if (context_ && context_->process_manager()) {
+ context_->process_manager()->RemoveProcessReferenceFromPattern(
+ pattern, process_id_);
+ }
+}
+
bool ServiceWorkerProviderHost::IsContextAlive() {
return context_ != NULL;
}
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 31f4a372b1b..04fb21d0a2b 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host.h
+++ b/chromium/content/browser/service_worker/service_worker_provider_host.h
@@ -10,20 +10,24 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "content/browser/service_worker/service_worker_registration.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_types.h"
-#include "webkit/common/resource_type.h"
+#include "content/public/common/request_context_frame_type.h"
+#include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_type.h"
namespace IPC {
class Sender;
}
-namespace webkit_blob {
+namespace storage {
class BlobStorageContext;
}
namespace content {
+class ResourceRequestBody;
class ServiceWorkerContextCore;
class ServiceWorkerDispatcherHost;
class ServiceWorkerRequestHandler;
@@ -38,31 +42,40 @@ class ServiceWorkerVersion;
// Note this class can also host a running service worker, in which
// case it will observe resource loads made directly by the service worker.
class CONTENT_EXPORT ServiceWorkerProviderHost
- : public base::SupportsWeakPtr<ServiceWorkerProviderHost> {
+ : public NON_EXPORTED_BASE(ServiceWorkerRegistration::Listener),
+ public base::SupportsWeakPtr<ServiceWorkerProviderHost> {
public:
ServiceWorkerProviderHost(int process_id,
int provider_id,
base::WeakPtr<ServiceWorkerContextCore> context,
ServiceWorkerDispatcherHost* dispatcher_host);
- ~ServiceWorkerProviderHost();
+ virtual ~ServiceWorkerProviderHost();
int process_id() const { return process_id_; }
int provider_id() const { return provider_id_; }
bool IsHostToRunningServiceWorker() {
- return running_hosted_version_ != NULL;
+ return running_hosted_version_.get() != NULL;
}
- // The service worker version that corresponds with
- // navigator.serviceWorker.active for our document.
+ ServiceWorkerVersion* controlling_version() const {
+ return controlling_version_.get();
+ }
ServiceWorkerVersion* active_version() const {
- return active_version_.get();
+ return associated_registration_.get() ?
+ associated_registration_->active_version() : NULL;
}
-
- // The service worker version that corresponds with
- // navigate.serviceWorker.waiting for our document.
ServiceWorkerVersion* waiting_version() const {
- return waiting_version_.get();
+ return associated_registration_.get() ?
+ associated_registration_->waiting_version() : NULL;
+ }
+ ServiceWorkerVersion* installing_version() const {
+ return associated_registration_.get() ?
+ associated_registration_->installing_version() : NULL;
+ }
+
+ ServiceWorkerRegistration* associated_registration() const {
+ return associated_registration_.get();
}
// The running version, if any, that this provider is providing resource
@@ -74,11 +87,14 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
void SetDocumentUrl(const GURL& url);
const GURL& document_url() const { return document_url_; }
- // Associates |version| to this provider as its '.active' or '.waiting'
- // version.
- // Giving NULL to this method will unset the corresponding field.
- void SetActiveVersion(ServiceWorkerVersion* version);
- void SetWaitingVersion(ServiceWorkerVersion* version);
+ void SetTopmostFrameUrl(const GURL& url);
+ const GURL& topmost_frame_url() const { return topmost_frame_url_; }
+
+ // Associates to |registration| to listen for its version change events.
+ void AssociateRegistration(ServiceWorkerRegistration* registration);
+
+ // 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.
@@ -87,12 +103,21 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
// Returns a handler for a request, the handler may return NULL if
// the request doesn't require special handling.
scoped_ptr<ServiceWorkerRequestHandler> CreateRequestHandler(
- ResourceType::Type resource_type,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context);
-
- // Returns true if |version| has the same registration as active and waiting
- // versions.
- bool ValidateVersionForAssociation(ServiceWorkerVersion* version);
+ FetchRequestMode request_mode,
+ FetchCredentialsMode credentials_mode,
+ ResourceType resource_type,
+ RequestContextType request_context_type,
+ RequestContextFrameType frame_type,
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ scoped_refptr<ResourceRequestBody> body);
+
+ // Returns true if |registration| can be associated with this provider.
+ bool CanAssociateRegistration(ServiceWorkerRegistration* registration);
+
+ // For use by the ServiceWorkerControlleeRequestHandler to disallow
+ // new registration association while a navigation is occurring and
+ // an existing registration is being looked for.
+ void SetAllowAssociation(bool allow) { allow_association_ = allow; }
// Returns true if the context referred to by this host (i.e. |context_|) is
// still alive.
@@ -102,20 +127,47 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
void PostMessage(const base::string16& message,
const std::vector<int>& sent_message_port_ids);
+ // Adds reference of this host's process to the |pattern|, the reference will
+ // be removed in destructor.
+ void AddScopedProcessReferenceToPattern(const GURL& pattern);
+
private:
+ friend class ServiceWorkerProviderHostTest;
+ friend class ServiceWorkerWriteToCacheJobTest;
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
+ UpdateBefore24Hours);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
+ UpdateAfter24Hours);
+
+ // ServiceWorkerRegistration::Listener overrides.
+ void OnRegistrationFailed(ServiceWorkerRegistration* registration) override;
+
+ // Sets the controller version field to |version| or if |version| is NULL,
+ // clears the field.
+ void SetControllerVersionAttribute(ServiceWorkerVersion* version);
+
// Creates a ServiceWorkerHandle to retain |version| and returns a
// ServiceWorkerInfo with the handle ID to pass to the provider. The
// provider is responsible for releasing the handle.
ServiceWorkerObjectInfo CreateHandleAndPass(ServiceWorkerVersion* version);
+ // Increase/decrease this host's process reference for |pattern|.
+ void IncreaseProcessReference(const GURL& pattern);
+ void DecreaseProcessReference(const GURL& pattern);
+
const int process_id_;
const int provider_id_;
GURL document_url_;
- scoped_refptr<ServiceWorkerVersion> active_version_;
- scoped_refptr<ServiceWorkerVersion> waiting_version_;
+ GURL topmost_frame_url_;
+
+ std::vector<GURL> associated_patterns_;
+ scoped_refptr<ServiceWorkerRegistration> associated_registration_;
+
+ scoped_refptr<ServiceWorkerVersion> controlling_version_;
scoped_refptr<ServiceWorkerVersion> running_hosted_version_;
base::WeakPtr<ServiceWorkerContextCore> context_;
ServiceWorkerDispatcherHost* dispatcher_host_;
+ bool allow_association_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHost);
};
diff --git a/chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc b/chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc
index 1f52514a603..fac7cb734ab 100644
--- a/chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -4,6 +4,8 @@
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
+#include "base/thread_task_runner_handle.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_provider_host.h"
#include "content/browser/service_worker/service_worker_register_job.h"
@@ -20,24 +22,17 @@ class ServiceWorkerProviderHostTest : public testing::Test {
protected:
ServiceWorkerProviderHostTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
- virtual ~ServiceWorkerProviderHostTest() {}
+ ~ServiceWorkerProviderHostTest() override {}
- virtual void SetUp() OVERRIDE {
- context_.reset(
- new ServiceWorkerContextCore(base::FilePath(),
- base::MessageLoopProxy::current(),
- base::MessageLoopProxy::current(),
- NULL,
- NULL,
- NULL));
-
- scope_ = GURL("http://www.example.com/*");
+ void SetUp() override {
+ helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
+ context_ = helper_->context();
+ pattern_ = GURL("http://www.example.com/");
script_url_ = GURL("http://www.example.com/service_worker.js");
registration_ = new ServiceWorkerRegistration(
- scope_, script_url_, 1L, context_->AsWeakPtr());
+ pattern_, 1L, context_->AsWeakPtr());
version_ = new ServiceWorkerVersion(
- registration_,
- 1L, context_->AsWeakPtr());
+ registration_.get(), script_url_, 1L, context_->AsWeakPtr());
// Prepare provider hosts (for the same process).
scoped_ptr<ServiceWorkerProviderHost> host1(new ServiceWorkerProviderHost(
@@ -46,31 +41,30 @@ class ServiceWorkerProviderHostTest : public testing::Test {
scoped_ptr<ServiceWorkerProviderHost> host2(new ServiceWorkerProviderHost(
kRenderProcessId, 2 /* provider_id */,
context_->AsWeakPtr(), NULL));
- scoped_ptr<ServiceWorkerProviderHost> host3(new ServiceWorkerProviderHost(
- kRenderProcessId, 3 /* provider_id */,
- context_->AsWeakPtr(), NULL));
provider_host1_ = host1->AsWeakPtr();
provider_host2_ = host2->AsWeakPtr();
- provider_host3_ = host3->AsWeakPtr();
context_->AddProviderHost(make_scoped_ptr(host1.release()));
context_->AddProviderHost(make_scoped_ptr(host2.release()));
- context_->AddProviderHost(make_scoped_ptr(host3.release()));
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
version_ = 0;
registration_ = 0;
- context_.reset();
+ helper_.reset();
+ }
+
+ bool HasProcessToRun() const {
+ return context_->process_manager()->PatternHasProcessToRun(pattern_);
}
content::TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<ServiceWorkerContextCore> context_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ ServiceWorkerContextCore* context_;
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
base::WeakPtr<ServiceWorkerProviderHost> provider_host1_;
base::WeakPtr<ServiceWorkerProviderHost> provider_host2_;
- base::WeakPtr<ServiceWorkerProviderHost> provider_host3_;
- GURL scope_;
+ GURL pattern_;
GURL script_url_;
private:
@@ -78,206 +72,81 @@ class ServiceWorkerProviderHostTest : public testing::Test {
};
TEST_F(ServiceWorkerProviderHostTest, SetActiveVersion_ProcessStatus) {
- ASSERT_FALSE(version_->HasProcessToRun());
+ provider_host1_->AssociateRegistration(registration_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Associating version_ to a provider_host's active version will internally
// add the provider_host's process ref to the version.
- provider_host1_->SetActiveVersion(version_);
- ASSERT_TRUE(version_->HasProcessToRun());
+ registration_->SetActiveVersion(version_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Re-associating the same version and provider_host should just work too.
- provider_host1_->SetActiveVersion(version_);
- ASSERT_TRUE(version_->HasProcessToRun());
+ registration_->SetActiveVersion(version_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Resetting the provider_host's active version should remove process refs
// from the version.
- provider_host1_->SetActiveVersion(NULL);
- ASSERT_FALSE(version_->HasProcessToRun());
+ provider_host1_->DisassociateRegistration();
+ ASSERT_FALSE(HasProcessToRun());
}
TEST_F(ServiceWorkerProviderHostTest,
SetActiveVersion_MultipleHostsForSameProcess) {
- ASSERT_FALSE(version_->HasProcessToRun());
+ provider_host1_->AssociateRegistration(registration_.get());
+ provider_host2_->AssociateRegistration(registration_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Associating version_ to two providers as active version.
- provider_host1_->SetActiveVersion(version_);
- provider_host2_->SetActiveVersion(version_);
- ASSERT_TRUE(version_->HasProcessToRun());
+ registration_->SetActiveVersion(version_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Disassociating one provider_host shouldn't remove all process refs
// from the version yet.
- provider_host1_->SetActiveVersion(NULL);
- ASSERT_TRUE(version_->HasProcessToRun());
+ provider_host1_->DisassociateRegistration();
+ ASSERT_TRUE(HasProcessToRun());
// Disassociating the other provider_host will remove all process refs.
- provider_host2_->SetActiveVersion(NULL);
- ASSERT_FALSE(version_->HasProcessToRun());
+ provider_host2_->DisassociateRegistration();
+ ASSERT_FALSE(HasProcessToRun());
}
TEST_F(ServiceWorkerProviderHostTest, SetWaitingVersion_ProcessStatus) {
- ASSERT_FALSE(version_->HasProcessToRun());
+ provider_host1_->AssociateRegistration(registration_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Associating version_ to a provider_host's waiting version will internally
// add the provider_host's process ref to the version.
- provider_host1_->SetWaitingVersion(version_);
- ASSERT_TRUE(version_->HasProcessToRun());
+ registration_->SetWaitingVersion(version_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Re-associating the same version and provider_host should just work too.
- provider_host1_->SetWaitingVersion(version_);
- ASSERT_TRUE(version_->HasProcessToRun());
+ registration_->SetWaitingVersion(version_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Resetting the provider_host's waiting version should remove process refs
// from the version.
- provider_host1_->SetWaitingVersion(NULL);
- ASSERT_FALSE(version_->HasProcessToRun());
+ provider_host1_->DisassociateRegistration();
+ ASSERT_FALSE(HasProcessToRun());
}
TEST_F(ServiceWorkerProviderHostTest,
SetWaitingVersion_MultipleHostsForSameProcess) {
- ASSERT_FALSE(version_->HasProcessToRun());
+ provider_host1_->AssociateRegistration(registration_.get());
+ provider_host2_->AssociateRegistration(registration_.get());
+ ASSERT_TRUE(HasProcessToRun());
- // Associating version_ to two providers as active version.
- provider_host1_->SetWaitingVersion(version_);
- provider_host2_->SetWaitingVersion(version_);
- ASSERT_TRUE(version_->HasProcessToRun());
+ // Associating version_ to two providers as waiting version.
+ registration_->SetWaitingVersion(version_.get());
+ ASSERT_TRUE(HasProcessToRun());
// Disassociating one provider_host shouldn't remove all process refs
// from the version yet.
- provider_host1_->SetWaitingVersion(NULL);
- ASSERT_TRUE(version_->HasProcessToRun());
+ provider_host1_->DisassociateRegistration();
+ ASSERT_TRUE(HasProcessToRun());
// Disassociating the other provider_host will remove all process refs.
- provider_host2_->SetWaitingVersion(NULL);
- ASSERT_FALSE(version_->HasProcessToRun());
-}
-
-class ServiceWorkerProviderHostWaitingVersionTest : public testing::Test {
- protected:
- ServiceWorkerProviderHostWaitingVersionTest()
- : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
- next_provider_id_(1L) {}
- virtual ~ServiceWorkerProviderHostWaitingVersionTest() {}
-
- virtual void SetUp() OVERRIDE {
- context_.reset(
- new ServiceWorkerContextCore(base::FilePath(),
- base::MessageLoopProxy::current(),
- base::MessageLoopProxy::current(),
- NULL,
- NULL,
- NULL));
-
- // Prepare provider hosts (for the same process).
- provider_host1_ = CreateProviderHost(GURL("http://www.example.com/foo"));
- provider_host2_ = CreateProviderHost(GURL("http://www.example.com/bar"));
- provider_host3_ = CreateProviderHost(GURL("http://www.example.ca/foo"));
- }
-
- base::WeakPtr<ServiceWorkerProviderHost> CreateProviderHost(
- const GURL& document_url) {
- scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kRenderProcessId, next_provider_id_++, context_->AsWeakPtr(), NULL));
- host->SetDocumentUrl(document_url);
- base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
- context_->AddProviderHost(host.Pass());
- return provider_host;
- }
-
- virtual void TearDown() OVERRIDE {
- context_.reset();
- }
-
- content::TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<ServiceWorkerContextCore> context_;
- base::WeakPtr<ServiceWorkerProviderHost> provider_host1_;
- base::WeakPtr<ServiceWorkerProviderHost> provider_host2_;
- base::WeakPtr<ServiceWorkerProviderHost> provider_host3_;
-
- private:
- int64 next_provider_id_;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostWaitingVersionTest);
-};
-
-TEST_F(ServiceWorkerProviderHostWaitingVersionTest,
- AssociateWaitingVersionToDocuments) {
- const GURL scope1("http://www.example.com/*");
- const GURL script_url1("http://www.example.com/service_worker1.js");
- scoped_refptr<ServiceWorkerRegistration> registration1(
- new ServiceWorkerRegistration(
- scope1, script_url1, 1L, context_->AsWeakPtr()));
- scoped_refptr<ServiceWorkerVersion> version1(
- new ServiceWorkerVersion(registration1, 1L, context_->AsWeakPtr()));
-
- ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments(
- context_->AsWeakPtr(), version1.get());
- EXPECT_EQ(version1.get(), provider_host1_->waiting_version());
- EXPECT_EQ(version1.get(), provider_host2_->waiting_version());
- EXPECT_EQ(NULL, provider_host3_->waiting_version());
-
- // Version2 is associated with the same registration as version1, so the
- // waiting version of host1 and host2 should be replaced.
- scoped_refptr<ServiceWorkerVersion> version2(
- new ServiceWorkerVersion(registration1, 2L, context_->AsWeakPtr()));
- ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments(
- context_->AsWeakPtr(), version2.get());
- EXPECT_EQ(version2.get(), provider_host1_->waiting_version());
- EXPECT_EQ(version2.get(), provider_host2_->waiting_version());
- EXPECT_EQ(NULL, provider_host3_->waiting_version());
-
- const GURL scope3(provider_host1_->document_url());
- const GURL script_url3("http://www.example.com/service_worker3.js");
- scoped_refptr<ServiceWorkerRegistration> registration3(
- new ServiceWorkerRegistration(
- scope3, script_url3, 3L, context_->AsWeakPtr()));
- scoped_refptr<ServiceWorkerVersion> version3(
- new ServiceWorkerVersion(registration3, 3L, context_->AsWeakPtr()));
-
- // Although version3 can match longer than version2 for host1, it should be
- // ignored because version3 is associated with a different registration from
- // version2.
- ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments(
- context_->AsWeakPtr(), version3.get());
- EXPECT_EQ(version2.get(), provider_host1_->waiting_version());
- EXPECT_EQ(version2.get(), provider_host2_->waiting_version());
- EXPECT_EQ(NULL, provider_host3_->waiting_version());
-}
-
-TEST_F(ServiceWorkerProviderHostWaitingVersionTest,
- DisassociateWaitingVersionFromDocuments) {
- const GURL scope1("http://www.example.com/*");
- const GURL script_url1("http://www.example.com/service_worker.js");
- scoped_refptr<ServiceWorkerRegistration> registration1(
- new ServiceWorkerRegistration(
- scope1, script_url1, 1L, context_->AsWeakPtr()));
- scoped_refptr<ServiceWorkerVersion> version1(
- new ServiceWorkerVersion(registration1, 1L, context_->AsWeakPtr()));
-
- const GURL scope2("http://www.example.ca/*");
- const GURL script_url2("http://www.example.ca/service_worker.js");
- scoped_refptr<ServiceWorkerRegistration> registration2(
- new ServiceWorkerRegistration(
- scope2, script_url2, 2L, context_->AsWeakPtr()));
- scoped_refptr<ServiceWorkerVersion> version2(
- new ServiceWorkerVersion(registration2, 2L, context_->AsWeakPtr()));
-
- ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments(
- context_->AsWeakPtr(), version1.get());
- ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments(
- context_->AsWeakPtr(), version2.get());
-
- // Host1 and host2 are associated with version1 as a waiting version, whereas
- // host3 is associated with version2.
- EXPECT_EQ(version1.get(), provider_host1_->waiting_version());
- EXPECT_EQ(version1.get(), provider_host2_->waiting_version());
- EXPECT_EQ(version2.get(), provider_host3_->waiting_version());
-
- // Disassociate version1 from host1 and host2.
- ServiceWorkerRegisterJob::DisassociateWaitingVersionFromDocuments(
- context_->AsWeakPtr(), version1->version_id());
- EXPECT_EQ(NULL, provider_host1_->waiting_version());
- EXPECT_EQ(NULL, provider_host2_->waiting_version());
- EXPECT_EQ(version2.get(), provider_host3_->waiting_version());
+ provider_host2_->DisassociateRegistration();
+ ASSERT_FALSE(HasProcessToRun());
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_quota_client.cc b/chromium/content/browser/service_worker/service_worker_quota_client.cc
new file mode 100644
index 00000000000..2a7842ff4d4
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_quota_client.cc
@@ -0,0 +1,111 @@
+// 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/service_worker/service_worker_quota_client.h"
+
+#include "base/bind.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/browser_thread.h"
+
+using storage::QuotaClient;
+
+namespace content {
+namespace {
+void ReportOrigins(const QuotaClient::GetOriginsCallback& callback,
+ bool restrict_on_host,
+ const std::string host,
+ const std::vector<ServiceWorkerUsageInfo>& usage_info) {
+ std::set<GURL> origins;
+ for (const ServiceWorkerUsageInfo& info : usage_info) {
+ if (restrict_on_host && info.origin.host() != host) {
+ continue;
+ }
+ origins.insert(info.origin);
+ }
+ callback.Run(origins);
+}
+
+void ReportToQuotaStatus(const QuotaClient::DeletionCallback& callback,
+ bool status) {
+ callback.Run(status ? storage::QuotaStatusCode::kQuotaStatusOk
+ : storage::QuotaStatusCode::kQuotaStatusUnknown);
+}
+
+void FindUsageForOrigin(const QuotaClient::GetUsageCallback& callback,
+ const GURL& origin,
+ const std::vector<ServiceWorkerUsageInfo>& usage_info) {
+ for (const auto& info : usage_info) {
+ if (info.origin == origin) {
+ callback.Run(info.total_size_bytes);
+ return;
+ }
+ }
+ callback.Run(0);
+}
+} // namespace
+
+ServiceWorkerQuotaClient::ServiceWorkerQuotaClient(
+ ServiceWorkerContextWrapper* context)
+ : context_(context) {
+}
+
+ServiceWorkerQuotaClient::~ServiceWorkerQuotaClient() {
+}
+
+QuotaClient::ID ServiceWorkerQuotaClient::id() const {
+ return QuotaClient::kServiceWorker;
+}
+
+void ServiceWorkerQuotaClient::OnQuotaManagerDestroyed() {
+ delete this;
+}
+
+void ServiceWorkerQuotaClient::GetOriginUsage(
+ const GURL& origin,
+ storage::StorageType type,
+ const GetUsageCallback& callback) {
+ if (type != storage::StorageType::kStorageTypeTemporary) {
+ callback.Run(0);
+ return;
+ }
+ context_->GetAllOriginsInfo(
+ base::Bind(&FindUsageForOrigin, callback, origin));
+}
+
+void ServiceWorkerQuotaClient::GetOriginsForType(
+ storage::StorageType type,
+ const GetOriginsCallback& callback) {
+ if (type != storage::StorageType::kStorageTypeTemporary) {
+ callback.Run(std::set<GURL>());
+ return;
+ }
+ context_->GetAllOriginsInfo(base::Bind(&ReportOrigins, callback, false, ""));
+}
+
+void ServiceWorkerQuotaClient::GetOriginsForHost(
+ storage::StorageType type,
+ const std::string& host,
+ const GetOriginsCallback& callback) {
+ if (type != storage::StorageType::kStorageTypeTemporary) {
+ callback.Run(std::set<GURL>());
+ return;
+ }
+ context_->GetAllOriginsInfo(base::Bind(&ReportOrigins, callback, true, host));
+}
+
+void ServiceWorkerQuotaClient::DeleteOriginData(
+ const GURL& origin,
+ storage::StorageType type,
+ const DeletionCallback& callback) {
+ if (type != storage::StorageType::kStorageTypeTemporary) {
+ callback.Run(storage::QuotaStatusCode::kQuotaStatusOk);
+ return;
+ }
+ context_->DeleteForOrigin(origin, base::Bind(&ReportToQuotaStatus, callback));
+}
+
+bool ServiceWorkerQuotaClient::DoesSupport(storage::StorageType type) const {
+ return type == storage::StorageType::kStorageTypeTemporary;
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_quota_client.h b/chromium/content/browser/service_worker/service_worker_quota_client.h
new file mode 100644
index 00000000000..a1cf91ddb80
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_quota_client.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_QUOTA_CLIENT_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_QUOTA_CLIENT_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "storage/browser/quota/quota_client.h"
+#include "storage/common/quota/quota_types.h"
+
+namespace content {
+class ServiceWorkerContextWrapper;
+
+class ServiceWorkerQuotaClient : public storage::QuotaClient {
+ public:
+ ~ServiceWorkerQuotaClient() override;
+
+ // QuotaClient method overrides
+ ID id() const override;
+ void OnQuotaManagerDestroyed() override;
+ void GetOriginUsage(const GURL& origin,
+ storage::StorageType type,
+ const GetUsageCallback& callback) override;
+ void GetOriginsForType(storage::StorageType type,
+ const GetOriginsCallback& callback) override;
+ void GetOriginsForHost(storage::StorageType type,
+ const std::string& host,
+ const GetOriginsCallback& callback) override;
+ void DeleteOriginData(const GURL& origin,
+ storage::StorageType type,
+ const DeletionCallback& callback) override;
+ bool DoesSupport(storage::StorageType type) const override;
+
+ private:
+ friend class ServiceWorkerContextWrapper;
+ friend class ServiceWorkerQuotaClientTest;
+
+ CONTENT_EXPORT explicit ServiceWorkerQuotaClient(
+ ServiceWorkerContextWrapper* context);
+
+ scoped_refptr<ServiceWorkerContextWrapper> context_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerQuotaClient);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_QUOTA_CLIENT_H_
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 5189a86c2bd..07f47e11016 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
@@ -4,9 +4,13 @@
#include "content/browser/service_worker/service_worker_read_from_cache_job.h"
+#include <string>
+#include <vector>
+
+#include "base/debug/trace_event.h"
#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_histograms.h"
+#include "content/browser/service_worker/service_worker_metrics.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
@@ -33,6 +37,10 @@ ServiceWorkerReadFromCacheJob::~ServiceWorkerReadFromCacheJob() {
}
void ServiceWorkerReadFromCacheJob::Start() {
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+ "ServiceWorkerReadFromCacheJob::ReadInfo",
+ this,
+ "URL", request_->url().spec());
if (!context_) {
NotifyStartError(net::URLRequestStatus(
net::URLRequestStatus::FAILED, net::ERR_FAILED));
@@ -44,7 +52,7 @@ void ServiceWorkerReadFromCacheJob::Start() {
reader_ = context_->storage()->CreateResponseReader(response_id_);
http_info_io_buffer_ = new HttpResponseInfoIOBuffer;
reader_->ReadInfo(
- http_info_io_buffer_,
+ http_info_io_buffer_.get(),
base::Bind(&ServiceWorkerReadFromCacheJob::OnReadInfoComplete,
weak_factory_.GetWeakPtr()));
SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
@@ -116,6 +124,10 @@ bool ServiceWorkerReadFromCacheJob::ReadRawData(
DCHECK_NE(buf_size, 0);
DCHECK(bytes_read);
DCHECK(!reader_->IsReadPending());
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+ "ServiceWorkerReadFromCacheJob::ReadRawData",
+ this,
+ "URL", request_->url().spec());
reader_->ReadData(
buf, buf_size, base::Bind(&ServiceWorkerReadFromCacheJob::OnReadComplete,
weak_factory_.GetWeakPtr()));
@@ -134,18 +146,22 @@ const net::HttpResponseInfo* ServiceWorkerReadFromCacheJob::http_info() const {
void ServiceWorkerReadFromCacheJob::OnReadInfoComplete(int result) {
scoped_refptr<ServiceWorkerReadFromCacheJob> protect(this);
if (!http_info_io_buffer_->http_info) {
- DCHECK(result < 0);
- ServiceWorkerHistograms::CountReadResponseResult(
- ServiceWorkerHistograms::READ_HEADERS_ERROR);
+ DCHECK_LT(result, 0);
+ ServiceWorkerMetrics::CountReadResponseResult(
+ ServiceWorkerMetrics::READ_HEADERS_ERROR);
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
return;
}
- DCHECK(result >= 0);
+ 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);
http_info_io_buffer_ = NULL;
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "ServiceWorkerReadFromCacheJob::ReadInfo",
+ this,
+ "Result", result);
NotifyHeadersComplete();
}
@@ -173,19 +189,23 @@ void ServiceWorkerReadFromCacheJob::SetupRangeResponse(int resource_size) {
}
void ServiceWorkerReadFromCacheJob::OnReadComplete(int result) {
- ServiceWorkerHistograms::ReadResponseResult check_result;
+ ServiceWorkerMetrics::ReadResponseResult check_result;
if (result == 0) {
- check_result = ServiceWorkerHistograms::READ_OK;
+ check_result = ServiceWorkerMetrics::READ_OK;
NotifyDone(net::URLRequestStatus());
} else if (result < 0) {
- check_result = ServiceWorkerHistograms::READ_DATA_ERROR;
+ check_result = ServiceWorkerMetrics::READ_DATA_ERROR;
NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
} else {
- check_result = ServiceWorkerHistograms::READ_OK;
+ check_result = ServiceWorkerMetrics::READ_OK;
SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
}
- ServiceWorkerHistograms::CountReadResponseResult(check_result);
+ ServiceWorkerMetrics::CountReadResponseResult(check_result);
NotifyReadComplete(result);
+ TRACE_EVENT_ASYNC_END1("ServiceWorker",
+ "ServiceWorkerReadFromCacheJob::ReadRawData",
+ this,
+ "Result", result);
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_read_from_cache_job.h b/chromium/content/browser/service_worker/service_worker_read_from_cache_job.h
index 5fb74015127..2a290d3c84d 100644
--- a/chromium/content/browser/service_worker/service_worker_read_from_cache_job.h
+++ b/chromium/content/browser/service_worker/service_worker_read_from_cache_job.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_READ_FROM_CACHE_JOB_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_READ_FROM_CACHE_JOB_H_
+#include <string>
+
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_disk_cache.h"
@@ -30,21 +32,18 @@ class CONTENT_EXPORT ServiceWorkerReadFromCacheJob
int64 response_id);
private:
- virtual ~ServiceWorkerReadFromCacheJob();
+ ~ServiceWorkerReadFromCacheJob() override;
// net::URLRequestJob overrides
- virtual void Start() OVERRIDE;
- virtual void Kill() OVERRIDE;
- virtual net::LoadState GetLoadState() const OVERRIDE;
- virtual bool GetCharset(std::string* charset) OVERRIDE;
- virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
- virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE;
- virtual int GetResponseCode() const OVERRIDE;
- virtual void SetExtraRequestHeaders(
- const net::HttpRequestHeaders& headers) OVERRIDE;
- virtual bool ReadRawData(net::IOBuffer* buf,
- int buf_size,
- int *bytes_read) OVERRIDE;
+ void Start() override;
+ void Kill() override;
+ net::LoadState GetLoadState() const override;
+ bool GetCharset(std::string* charset) override;
+ 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;
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
// Reader completion callbacks.
void OnReadInfoComplete(int result);
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 098b6b31df8..b68cd30f819 100644
--- a/chromium/content/browser/service_worker/service_worker_register_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_register_job.cc
@@ -12,6 +12,7 @@
#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_utils.h"
+#include "net/base/net_errors.h"
namespace content {
@@ -21,7 +22,7 @@ void RunSoon(const base::Closure& closure) {
base::MessageLoop::current()->PostTask(FROM_HERE, closure);
}
-}
+} // namespace
typedef ServiceWorkerRegisterJobBase::RegistrationJobType RegistrationJobType;
@@ -30,6 +31,7 @@ ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
const GURL& pattern,
const GURL& script_url)
: context_(context),
+ job_type_(REGISTRATION_JOB),
pattern_(pattern),
script_url_(script_url),
phase_(INITIAL),
@@ -37,32 +39,58 @@ ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
promise_resolved_status_(SERVICE_WORKER_OK),
weak_factory_(this) {}
+ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ ServiceWorkerRegistration* registration)
+ : context_(context),
+ job_type_(UPDATE_JOB),
+ pattern_(registration->pattern()),
+ script_url_(registration->GetNewestVersion()->script_url()),
+ phase_(INITIAL),
+ is_promise_resolved_(false),
+ promise_resolved_status_(SERVICE_WORKER_OK),
+ weak_factory_(this) {
+ internal_.registration = registration;
+}
+
ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {
DCHECK(!context_ ||
phase_ == INITIAL || phase_ == COMPLETE || phase_ == ABORT)
<< "Jobs should only be interrupted during shutdown.";
}
-void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback,
- int process_id) {
+void ServiceWorkerRegisterJob::AddCallback(
+ const RegistrationCallback& callback,
+ ServiceWorkerProviderHost* provider_host) {
if (!is_promise_resolved_) {
callbacks_.push_back(callback);
- if (process_id != -1 && (phase_ < UPDATE || !pending_version()))
- pending_process_ids_.push_back(process_id);
+ if (provider_host)
+ provider_host->AddScopedProcessReferenceToPattern(pattern_);
return;
}
RunSoon(base::Bind(
- callback, promise_resolved_status_,
- promise_resolved_registration_, promise_resolved_version_));
+ callback, promise_resolved_status_, promise_resolved_registration_));
}
void ServiceWorkerRegisterJob::Start() {
SetPhase(START);
- context_->storage()->FindRegistrationForPattern(
- pattern_,
- base::Bind(
- &ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue,
- weak_factory_.GetWeakPtr()));
+ ServiceWorkerStorage::FindRegistrationCallback next_step;
+ if (job_type_ == REGISTRATION_JOB) {
+ next_step = base::Bind(
+ &ServiceWorkerRegisterJob::ContinueWithRegistration,
+ weak_factory_.GetWeakPtr());
+ } else {
+ next_step = base::Bind(
+ &ServiceWorkerRegisterJob::ContinueWithUpdate,
+ weak_factory_.GetWeakPtr());
+ }
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ context_->storage()->GetUninstallingRegistration(pattern_);
+ if (registration.get())
+ RunSoon(base::Bind(next_step, SERVICE_WORKER_OK, registration));
+ else
+ context_->storage()->FindRegistrationForPattern(pattern_, next_step);
}
void ServiceWorkerRegisterJob::Abort() {
@@ -82,7 +110,7 @@ bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJobBase* job) {
}
RegistrationJobType ServiceWorkerRegisterJob::GetType() {
- return REGISTRATION;
+ return job_type_;
}
ServiceWorkerRegisterJob::Internal::Internal() {}
@@ -90,27 +118,39 @@ ServiceWorkerRegisterJob::Internal::Internal() {}
ServiceWorkerRegisterJob::Internal::~Internal() {}
void ServiceWorkerRegisterJob::set_registration(
- ServiceWorkerRegistration* registration) {
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
DCHECK(phase_ == START || phase_ == REGISTER) << phase_;
- DCHECK(!internal_.registration);
+ DCHECK(!internal_.registration.get());
internal_.registration = registration;
}
ServiceWorkerRegistration* ServiceWorkerRegisterJob::registration() {
- DCHECK(phase_ >= REGISTER) << phase_;
- return internal_.registration;
+ DCHECK(phase_ >= REGISTER || job_type_ == UPDATE_JOB) << phase_;
+ return internal_.registration.get();
}
-void ServiceWorkerRegisterJob::set_pending_version(
+void ServiceWorkerRegisterJob::set_new_version(
ServiceWorkerVersion* version) {
DCHECK(phase_ == UPDATE) << phase_;
- DCHECK(!internal_.pending_version);
- internal_.pending_version = version;
+ DCHECK(!internal_.new_version.get());
+ internal_.new_version = version;
}
-ServiceWorkerVersion* ServiceWorkerRegisterJob::pending_version() {
+ServiceWorkerVersion* ServiceWorkerRegisterJob::new_version() {
DCHECK(phase_ >= UPDATE) << phase_;
- return internal_.pending_version;
+ return internal_.new_version.get();
+}
+
+void ServiceWorkerRegisterJob::set_uninstalling_registration(
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ DCHECK_EQ(phase_, WAIT_FOR_UNINSTALL);
+ internal_.uninstalling_registration = registration;
+}
+
+ServiceWorkerRegistration*
+ServiceWorkerRegisterJob::uninstalling_registration() {
+ DCHECK_EQ(phase_, WAIT_FOR_UNINSTALL);
+ return internal_.uninstalling_registration.get();
}
void ServiceWorkerRegisterJob::SetPhase(Phase phase) {
@@ -121,9 +161,12 @@ void ServiceWorkerRegisterJob::SetPhase(Phase phase) {
case START:
DCHECK(phase_ == INITIAL) << phase_;
break;
- case REGISTER:
+ case WAIT_FOR_UNINSTALL:
DCHECK(phase_ == START) << phase_;
break;
+ case REGISTER:
+ DCHECK(phase_ == START || phase_ == WAIT_FOR_UNINSTALL) << phase_;
+ break;
case UPDATE:
DCHECK(phase_ == START || phase_ == REGISTER) << phase_;
break;
@@ -133,9 +176,6 @@ void ServiceWorkerRegisterJob::SetPhase(Phase phase) {
case STORE:
DCHECK(phase_ == INSTALL) << phase_;
break;
- case ACTIVATE:
- DCHECK(phase_ == STORE) << phase_;
- break;
case COMPLETE:
DCHECK(phase_ != INITIAL && phase_ != COMPLETE) << phase_;
break;
@@ -145,57 +185,78 @@ void ServiceWorkerRegisterJob::SetPhase(Phase phase) {
phase_ = phase;
}
-// This function corresponds to the steps in Register following
-// "Let serviceWorkerRegistration be _GetRegistration(scope)"
-// |existing_registration| corresponds to serviceWorkerRegistration.
+// This function corresponds to the steps in [[Register]] following
+// "Let registration be the result of running the [[GetRegistration]] algorithm.
// Throughout this file, comments in quotes are excerpts from the spec.
-void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue(
+void ServiceWorkerRegisterJob::ContinueWithRegistration(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& existing_registration) {
- // On unexpected error, abort this registration job.
+ DCHECK_EQ(REGISTRATION_JOB, job_type_);
if (status != SERVICE_WORKER_ERROR_NOT_FOUND && status != SERVICE_WORKER_OK) {
Complete(status);
return;
}
- // "If serviceWorkerRegistration is not null and script is equal to
- // serviceWorkerRegistration.scriptUrl..." resolve with the existing
- // registration and abort.
- if (existing_registration.get() &&
- existing_registration->script_url() == script_url_) {
- set_registration(existing_registration);
- // If there's no active version, go ahead to Update (this isn't in the spec
- // but seems reasonable, and without SoftUpdate implemented we can never
- // Update otherwise).
- if (!existing_registration->active_version()) {
- UpdateAndContinue(status);
- return;
- }
- ResolvePromise(
- status, existing_registration, existing_registration->active_version());
- Complete(SERVICE_WORKER_OK);
+ if (!existing_registration.get() || existing_registration->is_uninstalled()) {
+ RegisterAndContinue(SERVICE_WORKER_OK);
return;
}
- // "If serviceWorkerRegistration is null..." create a new registration.
- if (!existing_registration.get()) {
- RegisterAndContinue(SERVICE_WORKER_OK);
+ DCHECK(existing_registration->GetNewestVersion());
+ // "If scriptURL is equal to registration.[[ScriptURL]], then:"
+ if (existing_registration->GetNewestVersion()->script_url() == script_url_) {
+ // "Set registration.[[Uninstalling]] to false."
+ existing_registration->AbortPendingClear(base::Bind(
+ &ServiceWorkerRegisterJob::ContinueWithRegistrationForSameScriptUrl,
+ weak_factory_.GetWeakPtr(),
+ existing_registration));
return;
}
- // On script URL mismatch, "set serviceWorkerRegistration.scriptUrl to
- // script." We accomplish this by deleting the existing registration and
- // registering a new one.
- // TODO(falken): Match the spec. We now throw away the active_version_ and
- // waiting_version_ of the existing registration, which isn't in the spec.
- // TODO(michaeln): Deactivate the live existing_registration object and
- // eventually call storage->DeleteVersionResources()
- // when it no longer has any controllees.
- context_->storage()->DeleteRegistration(
- existing_registration->id(),
- existing_registration->script_url().GetOrigin(),
- base::Bind(&ServiceWorkerRegisterJob::RegisterAndContinue,
- weak_factory_.GetWeakPtr()));
+ if (existing_registration->is_uninstalling()) {
+ // "Wait until the Record {[[key]], [[value]]} entry of its
+ // [[ScopeToRegistrationMap]] where registation.scope matches entry.[[key]]
+ // is deleted."
+ WaitForUninstall(existing_registration);
+ return;
+ }
+
+ // "Set registration.[[Uninstalling]] to false."
+ DCHECK(!existing_registration->is_uninstalling());
+
+ // "Return the result of running the [[Update]] algorithm, or its equivalent,
+ // passing registration as the argument."
+ set_registration(existing_registration);
+ UpdateAndContinue();
+}
+
+void ServiceWorkerRegisterJob::ContinueWithUpdate(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& existing_registration) {
+ DCHECK_EQ(UPDATE_JOB, job_type_);
+ if (status != SERVICE_WORKER_OK) {
+ Complete(status);
+ return;
+ }
+
+ if (existing_registration.get() != registration()) {
+ Complete(SERVICE_WORKER_ERROR_NOT_FOUND);
+ return;
+ }
+
+ // A previous job may have unregistered or installed a new version to this
+ // registration.
+ if (registration()->is_uninstalling() ||
+ registration()->GetNewestVersion()->script_url() != script_url_) {
+ Complete(SERVICE_WORKER_ERROR_NOT_FOUND);
+ return;
+ }
+
+ // TODO(michaeln): If the last update check was less than 24 hours
+ // ago, depending on the freshness of the cached worker script we
+ // may be able to complete the update job right here.
+
+ UpdateAndContinue();
}
// Creates a new ServiceWorkerRegistration.
@@ -209,76 +270,115 @@ void ServiceWorkerRegisterJob::RegisterAndContinue(
}
set_registration(new ServiceWorkerRegistration(
- pattern_, script_url_, context_->storage()->NewRegistrationId(),
- context_));
- context_->storage()->NotifyInstallingRegistration(registration());
- UpdateAndContinue(SERVICE_WORKER_OK);
+ pattern_, context_->storage()->NewRegistrationId(), context_));
+ AssociateProviderHostsToRegistration(registration());
+ UpdateAndContinue();
}
-// This function corresponds to the spec's _Update algorithm.
-void ServiceWorkerRegisterJob::UpdateAndContinue(
+void ServiceWorkerRegisterJob::WaitForUninstall(
+ const scoped_refptr<ServiceWorkerRegistration>& existing_registration) {
+ SetPhase(WAIT_FOR_UNINSTALL);
+ set_uninstalling_registration(existing_registration);
+ uninstalling_registration()->AddListener(this);
+}
+
+void ServiceWorkerRegisterJob::ContinueWithRegistrationForSameScriptUrl(
+ const scoped_refptr<ServiceWorkerRegistration>& existing_registration,
ServiceWorkerStatusCode status) {
- SetPhase(UPDATE);
if (status != SERVICE_WORKER_OK) {
- // Abort this registration job.
Complete(status);
return;
}
+ set_registration(existing_registration);
+
+ // "If newestWorker is not null, and scriptURL is equal to
+ // newestWorker.scriptURL, then:
+ // Return a promise resolved with registration."
+ // We resolve only if there's an active version. If there's not,
+ // then there is either no version or only a waiting version from
+ // the last browser session; it makes sense to proceed with registration in
+ // either case.
+ DCHECK(!existing_registration->installing_version());
+ if (existing_registration->active_version()) {
+ ResolvePromise(status, existing_registration.get());
+ Complete(SERVICE_WORKER_OK);
+ return;
+ }
- // TODO(falken): "If serviceWorkerRegistration.installingWorker is not null.."
- // then terminate the installing worker. It doesn't make sense to implement
- // yet since we always activate the worker if install completed, so there can
- // be no installing worker at this point.
- // TODO(nhiroki): Check 'installing_version()' instead when it's supported.
- DCHECK(!registration()->waiting_version());
+ // "Return the result of running the [[Update]] algorithm, or its equivalent,
+ // passing registration as the argument."
+ UpdateAndContinue();
+}
- // "Let serviceWorker be a newly-created ServiceWorker object..." and start
- // the worker.
- set_pending_version(new ServiceWorkerVersion(
- registration(), context_->storage()->NewVersionId(), context_));
+// This function corresponds to the spec's [[Update]] algorithm.
+void ServiceWorkerRegisterJob::UpdateAndContinue() {
+ SetPhase(UPDATE);
+ context_->storage()->NotifyInstallingRegistration(registration());
- // TODO(michaeln): Start the worker into a paused state where the
- // script resource is downloaded but not yet evaluated.
- pending_version()->StartWorkerWithCandidateProcesses(
- pending_process_ids_,
+ // "Let worker be a new ServiceWorker object..." and start
+ // the worker.
+ set_new_version(new ServiceWorkerVersion(registration(),
+ script_url_,
+ context_->storage()->NewVersionId(),
+ context_));
+
+ bool pause_after_download = job_type_ == UPDATE_JOB;
+ if (pause_after_download)
+ new_version()->embedded_worker()->AddListener(this);
+ new_version()->StartWorker(
+ pause_after_download,
base::Bind(&ServiceWorkerRegisterJob::OnStartWorkerFinished,
weak_factory_.GetWeakPtr()));
}
void ServiceWorkerRegisterJob::OnStartWorkerFinished(
ServiceWorkerStatusCode status) {
- // "If serviceWorker fails to start up..." then reject the promise with an
- // error and abort.
- if (status != SERVICE_WORKER_OK) {
- Complete(status);
+ if (status == SERVICE_WORKER_OK) {
+ InstallAndContinue();
return;
}
- // TODO(michaeln): Compare the old and new script.
- // If different unpause the worker and continue with
- // the job. If the same ResolvePromise with the current
- // version and complete the job, throwing away the new version
- // since there's nothing new.
-
- // "Resolve promise with serviceWorker."
- // Although the spec doesn't set waitingWorker until after resolving the
- // promise, our system's resolving works by passing ServiceWorkerRegistration
- // to the callbacks, so waitingWorker must be set first.
- DCHECK(!registration()->waiting_version());
- registration()->set_waiting_version(pending_version());
- ResolvePromise(status, registration(), pending_version());
-
- AssociateWaitingVersionToDocuments(context_, pending_version());
-
- InstallAndContinue();
+ // "If serviceWorker fails to start up..." then reject the promise with an
+ // error and abort. When there is a main script network error, the status will
+ // be updated to a more specific one.
+ const net::URLRequestStatus& main_script_status =
+ new_version()->script_cache_map()->main_script_status();
+ if (main_script_status.status() != net::URLRequestStatus::SUCCESS) {
+ switch (main_script_status.error()) {
+ case net::ERR_INSECURE_RESPONSE:
+ case net::ERR_UNSAFE_REDIRECT:
+ status = SERVICE_WORKER_ERROR_SECURITY;
+ break;
+ case net::ERR_ABORTED:
+ status = SERVICE_WORKER_ERROR_ABORT;
+ break;
+ default:
+ status = SERVICE_WORKER_ERROR_NETWORK;
+ }
+ }
+ Complete(status);
}
-// This function corresponds to the spec's _Install algorithm.
+// This function corresponds to the spec's [[Install]] algorithm.
void ServiceWorkerRegisterJob::InstallAndContinue() {
SetPhase(INSTALL);
- // "Set serviceWorkerRegistration.installingWorker._state to installing."
- // "Fire install event on the associated ServiceWorkerGlobalScope object."
- pending_version()->DispatchInstallEvent(
+
+ // "Set registration.installingWorker to worker."
+ DCHECK(!registration()->installing_version());
+ registration()->SetInstallingVersion(new_version());
+
+ // "Run the Update State algorithm passing registration's installing worker
+ // and installing as the arguments."
+ new_version()->SetStatus(ServiceWorkerVersion::INSTALLING);
+
+ // "Resolve registrationPromise with registration."
+ ResolvePromise(SERVICE_WORKER_OK, registration());
+
+ // "Fire a simple event named updatefound..."
+ registration()->NotifyUpdateFound();
+
+ // "Fire an event named install..."
+ new_version()->DispatchInstallEvent(
-1,
base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished,
weak_factory_.GetWeakPtr()));
@@ -286,19 +386,19 @@ void ServiceWorkerRegisterJob::InstallAndContinue() {
void ServiceWorkerRegisterJob::OnInstallFinished(
ServiceWorkerStatusCode status) {
- // "If any handler called waitUntil()..." and the resulting promise
- // is rejected, abort.
// TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
// unexpectedly terminated) we may want to retry sending the event again.
if (status != SERVICE_WORKER_OK) {
+ // "8. If installFailed is true, then:..."
Complete(status);
return;
}
SetPhase(STORE);
+ registration()->set_last_update_check(base::Time::Now());
context_->storage()->StoreRegistration(
registration(),
- pending_version(),
+ new_version(),
base::Bind(&ServiceWorkerRegisterJob::OnStoreRegistrationComplete,
weak_factory_.GetWeakPtr()));
}
@@ -310,61 +410,28 @@ void ServiceWorkerRegisterJob::OnStoreRegistrationComplete(
return;
}
- ActivateAndContinue();
-}
-
-// This function corresponds to the spec's _Activate algorithm.
-void ServiceWorkerRegisterJob::ActivateAndContinue() {
- SetPhase(ACTIVATE);
-
- // "If existingWorker is not null, then: wait for exitingWorker to finish
- // handling any in-progress requests."
- // See if we already have an active_version for the scope and it has
- // controllee documents (if so activating the new version should wait
- // until we have no documents controlled by the version).
- if (registration()->active_version() &&
- registration()->active_version()->HasControllee()) {
- // TODO(kinuko,falken): Currently we immediately return if the existing
- // registration already has an active version, so we shouldn't come
- // this way.
- NOTREACHED();
- // TODO(falken): Register an continuation task to wait for NoControllees
- // notification so that we can resume activation later (see comments
- // in ServiceWorkerVersion::RemoveControllee).
- Complete(SERVICE_WORKER_OK);
- return;
+ // "9. If registration.waitingWorker is not null, then:..."
+ if (registration()->waiting_version()) {
+ // "1. Run the [[UpdateState]] algorithm passing registration.waitingWorker
+ // and "redundant" as the arguments."
+ registration()->waiting_version()->SetStatus(
+ ServiceWorkerVersion::REDUNDANT);
}
- // "Set serviceWorkerRegistration.waitingWorker to null."
- // "Set serviceWorkerRegistration.activeWorker to activatingWorker."
- DisassociateWaitingVersionFromDocuments(
- context_, pending_version()->version_id());
- registration()->set_waiting_version(NULL);
- DCHECK(!registration()->active_version());
- registration()->set_active_version(pending_version());
-
- // "Set serviceWorkerRegistration.activeWorker._state to activating."
- // "Fire activate event on the associated ServiceWorkerGlobalScope object."
- // "Set serviceWorkerRegistration.activeWorker._state to active."
- pending_version()->DispatchActivateEvent(
- base::Bind(&ServiceWorkerRegisterJob::OnActivateFinished,
- weak_factory_.GetWeakPtr()));
-}
+ // "10. Set registration.waitingWorker to registration.installingWorker."
+ // "11. Set registration.installingWorker to null."
+ registration()->SetWaitingVersion(new_version());
+
+ // "12. Run the [[UpdateState]] algorithm passing registration.waitingWorker
+ // and "installed" as the arguments."
+ new_version()->SetStatus(ServiceWorkerVersion::INSTALLED);
+
+ // TODO(michaeln): "13. If activateImmediate is true, then..."
+
+ // "14. Wait until no document is using registration as their
+ // Service Worker registration."
+ registration()->ActivateWaitingVersionWhenReady();
-void ServiceWorkerRegisterJob::OnActivateFinished(
- ServiceWorkerStatusCode status) {
- // "If any handler called waitUntil()..." and the resulting promise
- // is rejected, abort.
- // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
- // unexpectedly terminated) we may want to retry sending the event again.
- if (status != SERVICE_WORKER_OK) {
- registration()->set_active_version(NULL);
- Complete(status);
- return;
- }
- context_->storage()->UpdateToActiveState(
- registration(),
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
Complete(SERVICE_WORKER_OK);
}
@@ -377,91 +444,115 @@ void ServiceWorkerRegisterJob::CompleteInternal(
ServiceWorkerStatusCode status) {
SetPhase(COMPLETE);
if (status != SERVICE_WORKER_OK) {
- if (registration() && registration()->waiting_version()) {
- DisassociateWaitingVersionFromDocuments(
- context_, registration()->waiting_version()->version_id());
- registration()->set_waiting_version(NULL);
- }
- if (registration() && !registration()->active_version()) {
- context_->storage()->DeleteRegistration(
- registration()->id(),
- registration()->script_url().GetOrigin(),
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ if (registration()) {
+ if (new_version()) {
+ registration()->UnsetVersion(new_version());
+ new_version()->Doom();
+ }
+ if (!registration()->waiting_version() &&
+ !registration()->active_version()) {
+ registration()->NotifyRegistrationFailed();
+ context_->storage()->DeleteRegistration(
+ registration()->id(),
+ registration()->pattern().GetOrigin(),
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ }
}
if (!is_promise_resolved_)
- ResolvePromise(status, NULL, NULL);
+ ResolvePromise(status, NULL);
}
DCHECK(callbacks_.empty());
if (registration()) {
context_->storage()->NotifyDoneInstallingRegistration(
- registration(), pending_version(), status);
+ registration(), new_version(), status);
}
+ if (new_version())
+ new_version()->embedded_worker()->RemoveListener(this);
}
void ServiceWorkerRegisterJob::ResolvePromise(
ServiceWorkerStatusCode status,
- ServiceWorkerRegistration* registration,
- ServiceWorkerVersion* version) {
+ ServiceWorkerRegistration* registration) {
DCHECK(!is_promise_resolved_);
is_promise_resolved_ = true;
promise_resolved_status_ = status;
promise_resolved_registration_ = registration;
- promise_resolved_version_ = version;
for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin();
it != callbacks_.end();
++it) {
- it->Run(status, registration, version);
+ it->Run(status, registration);
}
callbacks_.clear();
}
-// static
-void ServiceWorkerRegisterJob::AssociateWaitingVersionToDocuments(
- base::WeakPtr<ServiceWorkerContextCore> context,
- ServiceWorkerVersion* version) {
- DCHECK(context);
- DCHECK(version);
+void ServiceWorkerRegisterJob::OnPausedAfterDownload() {
+ // This happens prior to OnStartWorkerFinished time.
+ scoped_refptr<ServiceWorkerVersion> most_recent_version =
+ registration()->waiting_version() ?
+ registration()->waiting_version() :
+ registration()->active_version();
+ DCHECK(most_recent_version.get());
+ int64 most_recent_script_id =
+ most_recent_version->script_cache_map()->LookupResourceId(script_url_);
+ int64 new_script_id =
+ new_version()->script_cache_map()->LookupResourceId(script_url_);
+
+ // TODO(michaeln): It would be better to compare as the new resource
+ // is being downloaded and to avoid writing it to disk until we know
+ // its needed.
+ context_->storage()->CompareScriptResources(
+ most_recent_script_id,
+ new_script_id,
+ base::Bind(&ServiceWorkerRegisterJob::OnCompareScriptResourcesComplete,
+ weak_factory_.GetWeakPtr()));
+}
- for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
- context->GetProviderHostIterator();
- !it->IsAtEnd();
- it->Advance()) {
- ServiceWorkerProviderHost* host = it->GetProviderHost();
- if (!host->IsContextAlive())
- continue;
- if (ServiceWorkerUtils::ScopeMatches(version->scope(),
- host->document_url())) {
- // The spec's _Update algorithm says, "upgrades active version to a new
- // version for the same URL scope.", so skip if the scope (registration)
- // of |version| is different from that of the current active/waiting
- // version.
- if (!host->ValidateVersionForAssociation(version))
- continue;
-
- // TODO(nhiroki): Keep |host->waiting_version()| to be replaced and set
- // status of them to 'redandunt' after breaking the loop.
-
- host->SetWaitingVersion(version);
- // TODO(nhiroki): Set |host|'s installing version to null.
+bool ServiceWorkerRegisterJob::OnMessageReceived(const IPC::Message& message) {
+ return false;
+}
+
+void ServiceWorkerRegisterJob::OnRegistrationFinishedUninstalling(
+ ServiceWorkerRegistration* existing_registration) {
+ DCHECK_EQ(phase_, WAIT_FOR_UNINSTALL);
+ DCHECK_EQ(existing_registration, uninstalling_registration());
+ existing_registration->RemoveListener(this);
+ set_uninstalling_registration(NULL);
+ RegisterAndContinue(SERVICE_WORKER_OK);
+}
+
+void ServiceWorkerRegisterJob::OnCompareScriptResourcesComplete(
+ ServiceWorkerStatusCode status,
+ bool are_equal) {
+ if (are_equal) {
+ // 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(24)) {
+ registration()->set_last_update_check(base::Time::Now());
+ context_->storage()->UpdateLastUpdateCheckTime(registration());
}
+
+ ResolvePromise(SERVICE_WORKER_OK, registration());
+ Complete(SERVICE_WORKER_ERROR_EXISTS);
+ return;
}
+
+ // Proceed with really starting the worker.
+ new_version()->embedded_worker()->ResumeAfterDownload();
+ new_version()->embedded_worker()->RemoveListener(this);
}
-// static
-void ServiceWorkerRegisterJob::DisassociateWaitingVersionFromDocuments(
- base::WeakPtr<ServiceWorkerContextCore> context,
- int64 version_id) {
- DCHECK(context);
+void ServiceWorkerRegisterJob::AssociateProviderHostsToRegistration(
+ ServiceWorkerRegistration* registration) {
+ DCHECK(registration);
for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
- context->GetProviderHostIterator();
- !it->IsAtEnd();
- it->Advance()) {
+ context_->GetProviderHostIterator();
+ !it->IsAtEnd(); it->Advance()) {
ServiceWorkerProviderHost* host = it->GetProviderHost();
- if (!host->IsContextAlive())
- continue;
- if (host->waiting_version() &&
- host->waiting_version()->version_id() == version_id) {
- host->SetWaitingVersion(NULL);
+ if (ServiceWorkerUtils::ScopeMatches(registration->pattern(),
+ host->document_url())) {
+ if (host->CanAssociateRegistration(registration))
+ host->AssociateRegistration(registration);
}
}
}
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 db10fa61118..167501b82cf 100644
--- a/chromium/content/browser/service_worker/service_worker_register_job.h
+++ b/chromium/content/browser/service_worker/service_worker_register_job.h
@@ -8,6 +8,7 @@
#include <vector>
#include "base/memory/weak_ptr.h"
+#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/service_worker_register_job_base.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/common/service_worker/service_worker_status_code.h"
@@ -18,61 +19,69 @@ namespace content {
class ServiceWorkerJobCoordinator;
class ServiceWorkerStorage;
-// Handles the registration of a Service Worker.
+// Handles the initial registration of a Service Worker and the
+// subsequent update of existing registrations.
//
-// The registration flow includes most or all of the following,
+// The control flow includes most or all of the following,
// depending on what is already registered:
// - creating a ServiceWorkerRegistration instance if there isn't
// already something registered
-// - creating a ServiceWorkerVersion for the new registration instance.
+// - creating a ServiceWorkerVersion for the new version.
// - starting a worker for the ServiceWorkerVersion
-// - telling the Version to evaluate the script
// - firing the 'install' event at the ServiceWorkerVersion
// - firing the 'activate' event at the ServiceWorkerVersion
// - waiting for older ServiceWorkerVersions to deactivate
// - designating the new version to be the 'active' version
-class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase {
+// - updating storage
+class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase,
+ public EmbeddedWorkerInstance::Listener,
+ public ServiceWorkerRegistration::Listener {
public:
typedef base::Callback<void(ServiceWorkerStatusCode status,
- ServiceWorkerRegistration* registration,
- ServiceWorkerVersion* version)>
+ ServiceWorkerRegistration* registration)>
RegistrationCallback;
+ // For registration jobs.
CONTENT_EXPORT ServiceWorkerRegisterJob(
base::WeakPtr<ServiceWorkerContextCore> context,
const GURL& pattern,
const GURL& script_url);
- virtual ~ServiceWorkerRegisterJob();
+
+ // For update jobs.
+ CONTENT_EXPORT ServiceWorkerRegisterJob(
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ ServiceWorkerRegistration* registration);
+ ~ServiceWorkerRegisterJob() override;
// Registers a callback to be called when the promise would resolve (whether
- // successfully or not). Multiple callbacks may be registered. If |process_id|
- // is not -1, it's added to the existing clients when deciding in which
- // process to create the Service Worker instance. If there are no existing
- // clients, a new RenderProcessHost will be created.
- void AddCallback(const RegistrationCallback& callback, int process_id);
+ // successfully or not). Multiple callbacks may be registered.
+ // If |provider_host| is not NULL, its process will be regarded as a candidate
+ // process to run the worker.
+ void AddCallback(const RegistrationCallback& callback,
+ ServiceWorkerProviderHost* provider_host);
// ServiceWorkerRegisterJobBase implementation:
- virtual void Start() OVERRIDE;
- virtual void Abort() OVERRIDE;
- virtual bool Equals(ServiceWorkerRegisterJobBase* job) OVERRIDE;
- virtual RegistrationJobType GetType() OVERRIDE;
+ void Start() override;
+ void Abort() override;
+ bool Equals(ServiceWorkerRegisterJobBase* job) override;
+ RegistrationJobType GetType() override;
private:
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProviderHostWaitingVersionTest,
- AssociateWaitingVersionToDocuments);
+ AssociateInstallingVersionToDocuments);
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProviderHostWaitingVersionTest,
- DisassociateWaitingVersionFromDocuments);
+ DisassociateVersionFromDocuments);
enum Phase {
- INITIAL,
- START,
- REGISTER,
- UPDATE,
- INSTALL,
- STORE,
- ACTIVATE,
- COMPLETE,
- ABORT,
+ INITIAL,
+ START,
+ WAIT_FOR_UNINSTALL,
+ REGISTER,
+ UPDATE,
+ INSTALL,
+ STORE,
+ COMPLETE,
+ ABORT,
};
// Holds internal state of ServiceWorkerRegistrationJob, to compel use of the
@@ -82,22 +91,37 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase {
~Internal();
scoped_refptr<ServiceWorkerRegistration> registration;
- // Holds 'installing' or 'waiting' version depending on the phase.
- scoped_refptr<ServiceWorkerVersion> pending_version;
+ // Holds the version created by this job. It can be the 'installing',
+ // 'waiting', or 'active' version depending on the phase.
+ scoped_refptr<ServiceWorkerVersion> new_version;
+
+ scoped_refptr<ServiceWorkerRegistration> uninstalling_registration;
};
- void set_registration(ServiceWorkerRegistration* registration);
+ void set_registration(
+ const scoped_refptr<ServiceWorkerRegistration>& registration);
ServiceWorkerRegistration* registration();
- void set_pending_version(ServiceWorkerVersion* version);
- ServiceWorkerVersion* pending_version();
+ void set_new_version(ServiceWorkerVersion* version);
+ ServiceWorkerVersion* new_version();
+ void set_uninstalling_registration(
+ const scoped_refptr<ServiceWorkerRegistration>& registration);
+ ServiceWorkerRegistration* uninstalling_registration();
void SetPhase(Phase phase);
- void HandleExistingRegistrationAndContinue(
+ void ContinueWithRegistration(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration);
+ void ContinueWithUpdate(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
void RegisterAndContinue(ServiceWorkerStatusCode status);
- void UpdateAndContinue(ServiceWorkerStatusCode status);
+ void WaitForUninstall(
+ const scoped_refptr<ServiceWorkerRegistration>& registration);
+ void ContinueWithRegistrationForSameScriptUrl(
+ const scoped_refptr<ServiceWorkerRegistration>& existing_registration,
+ ServiceWorkerStatusCode status);
+ void UpdateAndContinue();
void OnStartWorkerFinished(ServiceWorkerStatusCode status);
void OnStoreRegistrationComplete(ServiceWorkerStatusCode status);
void InstallAndContinue();
@@ -106,35 +130,36 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase {
void OnActivateFinished(ServiceWorkerStatusCode status);
void Complete(ServiceWorkerStatusCode status);
void CompleteInternal(ServiceWorkerStatusCode status);
-
void ResolvePromise(ServiceWorkerStatusCode status,
- ServiceWorkerRegistration* registration,
- ServiceWorkerVersion* version);
+ ServiceWorkerRegistration* registration);
- // Associates a waiting version to documents matched with a scope of the
- // version.
- CONTENT_EXPORT static void AssociateWaitingVersionToDocuments(
- base::WeakPtr<ServiceWorkerContextCore> context,
- ServiceWorkerVersion* version);
+ // EmbeddedWorkerInstance::Listener override of OnPausedAfterDownload.
+ void OnPausedAfterDownload() override;
+ bool OnMessageReceived(const IPC::Message& message) override;
- // Disassociates a waiting version specified by |version_id| from documents.
- CONTENT_EXPORT static void DisassociateWaitingVersionFromDocuments(
- base::WeakPtr<ServiceWorkerContextCore> context,
- int64 version_id);
+ // ServiceWorkerRegistration::Listener overrides
+ void OnRegistrationFinishedUninstalling(
+ ServiceWorkerRegistration* registration) override;
+
+ void OnCompareScriptResourcesComplete(
+ ServiceWorkerStatusCode status,
+ bool are_equal);
+
+ void AssociateProviderHostsToRegistration(
+ ServiceWorkerRegistration* registration);
// The ServiceWorkerContextCore object should always outlive this.
base::WeakPtr<ServiceWorkerContextCore> context_;
+ RegistrationJobType job_type_;
const GURL pattern_;
const GURL script_url_;
std::vector<RegistrationCallback> callbacks_;
- std::vector<int> pending_process_ids_;
Phase phase_;
Internal internal_;
bool is_promise_resolved_;
ServiceWorkerStatusCode promise_resolved_status_;
scoped_refptr<ServiceWorkerRegistration> promise_resolved_registration_;
- scoped_refptr<ServiceWorkerVersion> promise_resolved_version_;
base::WeakPtrFactory<ServiceWorkerRegisterJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegisterJob);
diff --git a/chromium/content/browser/service_worker/service_worker_register_job_base.h b/chromium/content/browser/service_worker/service_worker_register_job_base.h
index 7995adda7c6..9233e7c69af 100644
--- a/chromium/content/browser/service_worker/service_worker_register_job_base.h
+++ b/chromium/content/browser/service_worker/service_worker_register_job_base.h
@@ -7,11 +7,13 @@
namespace content {
-// A base class for ServiceWorkerRegisterJob and ServiceWorkerUnregisterJob. A
-// job lives only for the lifetime of a single registration or unregistration.
class ServiceWorkerRegisterJobBase {
public:
- enum RegistrationJobType { REGISTRATION, UNREGISTRATION, };
+ enum RegistrationJobType {
+ REGISTRATION_JOB,
+ UNREGISTRATION_JOB,
+ UPDATE_JOB
+ };
virtual ~ServiceWorkerRegisterJobBase() {}
diff --git a/chromium/content/browser/service_worker/service_worker_registration.cc b/chromium/content/browser/service_worker/service_worker_registration.cc
index 9e166b6f7b1..0445f08f7e6 100644
--- a/chromium/content/browser/service_worker/service_worker_registration.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration.cc
@@ -6,19 +6,33 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_info.h"
+#include "content/browser/service_worker/service_worker_register_job.h"
+#include "content/browser/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_thread.h"
namespace content {
+namespace {
+
+ServiceWorkerVersionInfo GetVersionInfo(ServiceWorkerVersion* version) {
+ if (!version)
+ return ServiceWorkerVersionInfo();
+ return version->GetInfo();
+}
+
+} // namespace
+
ServiceWorkerRegistration::ServiceWorkerRegistration(
const GURL& pattern,
- const GURL& script_url,
int64 registration_id,
base::WeakPtr<ServiceWorkerContextCore> context)
: pattern_(pattern),
- script_url_(script_url),
registration_id_(registration_id),
- is_shutdown_(false),
+ is_deleted_(false),
+ is_uninstalling_(false),
+ is_uninstalled_(false),
+ should_activate_when_ready_(false),
+ resources_total_size_bytes_(0),
context_(context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(context_);
@@ -27,33 +41,297 @@ ServiceWorkerRegistration::ServiceWorkerRegistration(
ServiceWorkerRegistration::~ServiceWorkerRegistration() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(!listeners_.might_have_observers());
if (context_)
context_->RemoveLiveRegistration(registration_id_);
+ if (active_version())
+ active_version()->RemoveListener(this);
+}
+
+ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const {
+ if (installing_version())
+ return installing_version();
+ if (waiting_version())
+ return waiting_version();
+ return active_version();
+}
+
+void ServiceWorkerRegistration::AddListener(Listener* listener) {
+ listeners_.AddObserver(listener);
+}
+
+void ServiceWorkerRegistration::RemoveListener(Listener* listener) {
+ listeners_.RemoveObserver(listener);
+}
+
+void ServiceWorkerRegistration::NotifyRegistrationFailed() {
+ FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
+}
+
+void ServiceWorkerRegistration::NotifyUpdateFound() {
+ FOR_EACH_OBSERVER(Listener, listeners_, OnUpdateFound(this));
}
ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
return ServiceWorkerRegistrationInfo(
- script_url(),
pattern(),
registration_id_,
- active_version_ ? active_version_->GetInfo() : ServiceWorkerVersionInfo(),
- waiting_version_ ? waiting_version_->GetInfo()
- : ServiceWorkerVersionInfo());
+ GetVersionInfo(active_version_.get()),
+ GetVersionInfo(waiting_version_.get()),
+ GetVersionInfo(installing_version_.get()),
+ resources_total_size_bytes_);
}
-ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() {
- if (active_version())
- return active_version();
- return waiting_version();
+void ServiceWorkerRegistration::SetActiveVersion(
+ ServiceWorkerVersion* version) {
+ should_activate_when_ready_ = false;
+ SetVersionInternal(version, &active_version_,
+ ChangedVersionAttributesMask::ACTIVE_VERSION);
+}
+
+void ServiceWorkerRegistration::SetWaitingVersion(
+ ServiceWorkerVersion* version) {
+ should_activate_when_ready_ = false;
+ SetVersionInternal(version, &waiting_version_,
+ ChangedVersionAttributesMask::WAITING_VERSION);
+}
+
+void ServiceWorkerRegistration::SetInstallingVersion(
+ ServiceWorkerVersion* version) {
+ SetVersionInternal(version, &installing_version_,
+ ChangedVersionAttributesMask::INSTALLING_VERSION);
+}
+
+void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
+ if (!version)
+ return;
+ ChangedVersionAttributesMask mask;
+ UnsetVersionInternal(version, &mask);
+ if (mask.changed()) {
+ ServiceWorkerRegistrationInfo info = GetInfo();
+ FOR_EACH_OBSERVER(Listener, listeners_,
+ OnVersionAttributesChanged(this, mask, info));
+ }
+}
+
+void ServiceWorkerRegistration::SetVersionInternal(
+ ServiceWorkerVersion* version,
+ scoped_refptr<ServiceWorkerVersion>* data_member,
+ int change_flag) {
+ if (version == data_member->get())
+ return;
+ scoped_refptr<ServiceWorkerVersion> protect(version);
+ ChangedVersionAttributesMask mask;
+ if (version)
+ UnsetVersionInternal(version, &mask);
+ *data_member = version;
+ if (active_version_.get() && active_version_.get() == version)
+ active_version_->AddListener(this);
+ mask.add(change_flag);
+ ServiceWorkerRegistrationInfo info = GetInfo();
+ FOR_EACH_OBSERVER(Listener, listeners_,
+ OnVersionAttributesChanged(this, mask, info));
+}
+
+void ServiceWorkerRegistration::UnsetVersionInternal(
+ ServiceWorkerVersion* version,
+ ChangedVersionAttributesMask* mask) {
+ DCHECK(version);
+ if (installing_version_.get() == version) {
+ installing_version_ = NULL;
+ mask->add(ChangedVersionAttributesMask::INSTALLING_VERSION);
+ } else if (waiting_version_.get() == version) {
+ waiting_version_ = NULL;
+ mask->add(ChangedVersionAttributesMask::WAITING_VERSION);
+ } else if (active_version_.get() == version) {
+ active_version_->RemoveListener(this);
+ active_version_ = NULL;
+ mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
+ }
+}
+
+void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
+ DCHECK(waiting_version());
+ should_activate_when_ready_ = true;
+ if (!active_version() || !active_version()->HasControllee())
+ ActivateWaitingVersion();
+}
+
+void ServiceWorkerRegistration::ClearWhenReady() {
+ DCHECK(context_);
+ if (is_uninstalling_)
+ return;
+ is_uninstalling_ = true;
+
+ context_->storage()->NotifyUninstallingRegistration(this);
+ context_->storage()->DeleteRegistration(
+ id(),
+ pattern().GetOrigin(),
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+
+ if (!active_version() || !active_version()->HasControllee())
+ Clear();
+}
+
+void ServiceWorkerRegistration::AbortPendingClear(
+ const StatusCallback& callback) {
+ DCHECK(context_);
+ if (!is_uninstalling()) {
+ callback.Run(SERVICE_WORKER_OK);
+ return;
+ }
+ is_uninstalling_ = false;
+ context_->storage()->NotifyDoneUninstallingRegistration(this);
+
+ scoped_refptr<ServiceWorkerVersion> most_recent_version =
+ waiting_version() ? waiting_version() : active_version();
+ DCHECK(most_recent_version.get());
+ context_->storage()->NotifyInstallingRegistration(this);
+ context_->storage()->StoreRegistration(
+ this,
+ most_recent_version.get(),
+ base::Bind(&ServiceWorkerRegistration::OnRestoreFinished,
+ this,
+ callback,
+ most_recent_version));
+}
+
+void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
+ DCHECK_EQ(active_version(), version);
+ if (is_uninstalling_)
+ Clear();
+ else if (should_activate_when_ready_)
+ ActivateWaitingVersion();
+ is_uninstalling_ = false;
+ should_activate_when_ready_ = false;
}
void ServiceWorkerRegistration::ActivateWaitingVersion() {
- active_version_->SetStatus(ServiceWorkerVersion::DEACTIVATED);
- active_version_ = waiting_version_;
- // TODO(kinuko): This should be set to ACTIVATING until activation finishes.
- active_version_->SetStatus(ServiceWorkerVersion::ACTIVE);
- waiting_version_ = NULL;
+ DCHECK(context_);
+ DCHECK(waiting_version());
+ DCHECK(should_activate_when_ready_);
+ should_activate_when_ready_ = false;
+ scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
+ scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
+
+ if (activating_version->is_doomed() ||
+ activating_version->status() == ServiceWorkerVersion::REDUNDANT) {
+ return; // Activation is no longer relevant.
+ }
+
+ // "4. If exitingWorker is not null,
+ if (exiting_version.get()) {
+ DCHECK(!exiting_version->HasControllee());
+ // TODO(michaeln): should wait for events to be complete
+ // "1. Wait for exitingWorker to finish handling any in-progress requests."
+ // "2. Terminate exitingWorker."
+ exiting_version->StopWorker(
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
+ // "redundant" as the arguments."
+ exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
+ }
+
+ // "5. Set serviceWorkerRegistration.activeWorker to activatingWorker."
+ // "6. Set serviceWorkerRegistration.waitingWorker to null."
+ SetActiveVersion(activating_version.get());
+
+ // "7. Run the [[UpdateState]] algorithm passing registration.activeWorker and
+ // "activating" as arguments."
+ activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
+
+ // TODO(nhiroki): "8. Fire a simple event named controllerchange..."
+
+ // "9. Queue a task to fire an event named activate..."
+ activating_version->DispatchActivateEvent(
+ base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
+ this, activating_version));
+}
+
+void ServiceWorkerRegistration::OnActivateEventFinished(
+ ServiceWorkerVersion* activating_version,
+ ServiceWorkerStatusCode status) {
+ if (!context_ || activating_version != active_version())
+ return;
+ // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
+ // unexpectedly terminated) we may want to retry sending the event again.
+ if (status != SERVICE_WORKER_OK) {
+ // "11. If activateFailed is true, then:..."
+ UnsetVersion(activating_version);
+ activating_version->Doom();
+ if (!waiting_version()) {
+ // Delete the records from the db.
+ context_->storage()->DeleteRegistration(
+ id(), pattern().GetOrigin(),
+ base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
+ // But not from memory if there is a version in the pipeline.
+ if (installing_version())
+ is_deleted_ = false;
+ }
+ return;
+ }
+
+ // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
+ // and "activated" as the arguments."
+ activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ if (context_) {
+ context_->storage()->UpdateToActiveState(
+ this,
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ }
+}
+
+void ServiceWorkerRegistration::OnDeleteFinished(
+ ServiceWorkerStatusCode status) {
+ // Intentionally empty completion callback, used to prevent
+ // |this| from being deleted until the storage method completes.
+}
+
+void ServiceWorkerRegistration::Clear() {
+ is_uninstalling_ = false;
+ is_uninstalled_ = true;
+ if (context_)
+ context_->storage()->NotifyDoneUninstallingRegistration(this);
+
+ ChangedVersionAttributesMask mask;
+ if (installing_version_.get()) {
+ installing_version_->Doom();
+ installing_version_ = NULL;
+ mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
+ }
+ if (waiting_version_.get()) {
+ waiting_version_->Doom();
+ waiting_version_ = NULL;
+ mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
+ }
+ if (active_version_.get()) {
+ active_version_->Doom();
+ active_version_->RemoveListener(this);
+ active_version_ = NULL;
+ mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
+ }
+ if (mask.changed()) {
+ ServiceWorkerRegistrationInfo info = GetInfo();
+ FOR_EACH_OBSERVER(Listener, listeners_,
+ OnVersionAttributesChanged(this, mask, info));
+ }
+
+ FOR_EACH_OBSERVER(
+ Listener, listeners_, OnRegistrationFinishedUninstalling(this));
+}
+
+void ServiceWorkerRegistration::OnRestoreFinished(
+ const StatusCallback& callback,
+ scoped_refptr<ServiceWorkerVersion> version,
+ ServiceWorkerStatusCode status) {
+ if (!context_) {
+ callback.Run(SERVICE_WORKER_ERROR_ABORT);
+ return;
+ }
+ context_->storage()->NotifyDoneInstallingRegistration(
+ this, version.get(), status);
+ callback.Run(status);
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_registration.h b/chromium/content/browser/service_worker/service_worker_registration.h
index df23dc3d61a..b386eecfad3 100644
--- a/chromium/content/browser/service_worker/service_worker_registration.h
+++ b/chromium/content/browser/service_worker/service_worker_registration.h
@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/content_export.h"
+#include "content/common/service_worker/service_worker_types.h"
#include "url/gurl.h"
namespace content {
@@ -19,76 +20,148 @@ namespace content {
class ServiceWorkerRegistrationInfo;
class ServiceWorkerVersion;
-// This class manages all persistence of service workers:
-// - Registrations
-// - Mapping of caches to registrations / versions
-//
-// This is the place where we manage simultaneous
-// requests for the same registrations and caches, making sure that
-// two pages that are registering the same pattern at the same time
-// have their registrations coalesced rather than overwriting each
-// other.
-//
-// This class also manages the state of the upgrade process, which
-// includes managing which ServiceWorkerVersion is "active" vs "in
-// waiting".
+// This class represents a Service Worker registration. The scope is constant
+// for the life of the persistent registration. It's refcounted to facilitate
+// multiple controllees being associated with the same registration.
class CONTENT_EXPORT ServiceWorkerRegistration
- : NON_EXPORTED_BASE(public base::RefCounted<ServiceWorkerRegistration>) {
+ : NON_EXPORTED_BASE(public base::RefCounted<ServiceWorkerRegistration>),
+ public ServiceWorkerVersion::Listener {
public:
+ typedef base::Callback<void(ServiceWorkerStatusCode status)> StatusCallback;
+
+ class Listener {
+ public:
+ virtual void OnVersionAttributesChanged(
+ ServiceWorkerRegistration* registration,
+ ChangedVersionAttributesMask changed_mask,
+ const ServiceWorkerRegistrationInfo& info) {}
+ virtual void OnRegistrationFailed(
+ ServiceWorkerRegistration* registration) {}
+ virtual void OnRegistrationFinishedUninstalling(
+ ServiceWorkerRegistration* registration) {}
+ virtual void OnUpdateFound(
+ ServiceWorkerRegistration* registration) {}
+ };
+
ServiceWorkerRegistration(const GURL& pattern,
- const GURL& script_url,
int64 registration_id,
base::WeakPtr<ServiceWorkerContextCore> context);
int64 id() const { return registration_id_; }
- const GURL& script_url() const { return script_url_; }
const GURL& pattern() const { return pattern_; }
+ bool is_deleted() const { return is_deleted_; }
+ void set_is_deleted(bool deleted) { is_deleted_ = deleted; }
+
+ bool is_uninstalling() const { return is_uninstalling_; }
+ bool is_uninstalled() const { return is_uninstalled_; }
+
+ int64_t resources_total_size_bytes() const {
+ return resources_total_size_bytes_;
+ }
+
+ void set_resources_total_size_bytes(int64_t resources_total_size_bytes) {
+ resources_total_size_bytes_ = resources_total_size_bytes;
+ }
+
ServiceWorkerVersion* active_version() const {
- DCHECK(!is_shutdown_);
return active_version_.get();
}
ServiceWorkerVersion* waiting_version() const {
- DCHECK(!is_shutdown_);
return waiting_version_.get();
}
- void set_active_version(ServiceWorkerVersion* version) {
- DCHECK(!is_shutdown_);
- active_version_ = version;
+ ServiceWorkerVersion* installing_version() const {
+ return installing_version_.get();
}
- void set_waiting_version(ServiceWorkerVersion* version) {
- DCHECK(!is_shutdown_);
- waiting_version_ = version;
- }
+ ServiceWorkerVersion* GetNewestVersion() const;
+
+ void AddListener(Listener* listener);
+ void RemoveListener(Listener* listener);
+ void NotifyRegistrationFailed();
+ void NotifyUpdateFound();
ServiceWorkerRegistrationInfo GetInfo();
- // Returns the active version, if it is not null; otherwise, returns the
- // waiting version.
- ServiceWorkerVersion* GetNewestVersion();
+ // Sets the corresposding version attribute and resets the position
+ // (if any) left vacant (ie. by a waiting version being promoted).
+ // Also notifies listeners via OnVersionAttributesChanged.
+ void SetActiveVersion(ServiceWorkerVersion* version);
+ void SetWaitingVersion(ServiceWorkerVersion* version);
+ void SetInstallingVersion(ServiceWorkerVersion* version);
- // The final synchronous switchover after all events have been
- // fired, and the old "active version" is being shut down.
- void ActivateWaitingVersion();
+ // If version is the installing, waiting, active version of this
+ // registation, the method will reset that field to NULL, and notify
+ // listeners via OnVersionAttributesChanged.
+ void UnsetVersion(ServiceWorkerVersion* version);
+
+ // Triggers the [[Activate]] algorithm when the currently active version
+ // has no controllees. If there are no controllees at the time the method
+ // is called, activation is initiated immediately.
+ void ActivateWaitingVersionWhenReady();
+
+ // Triggers the [[ClearRegistration]] algorithm when the currently
+ // active version has no controllees. Deletes this registration
+ // from storage immediately.
+ void ClearWhenReady();
+
+ // Restores this registration in storage and cancels the pending
+ // [[ClearRegistration]] algorithm.
+ void AbortPendingClear(const StatusCallback& callback);
+
+ // The time of the most recent update check.
+ base::Time last_update_check() const { return last_update_check_; }
+ void set_last_update_check(base::Time last) { last_update_check_ = last; }
private:
- ~ServiceWorkerRegistration();
friend class base::RefCounted<ServiceWorkerRegistration>;
+ ~ServiceWorkerRegistration() override;
+
+ void SetVersionInternal(
+ ServiceWorkerVersion* version,
+ scoped_refptr<ServiceWorkerVersion>* data_member,
+ int change_flag);
+ void UnsetVersionInternal(
+ ServiceWorkerVersion* version,
+ ChangedVersionAttributesMask* mask);
+
+ // ServiceWorkerVersion::Listener override.
+ void OnNoControllees(ServiceWorkerVersion* version) override;
+
+ // This method corresponds to the [[Activate]] algorithm.
+ void ActivateWaitingVersion();
+ void OnActivateEventFinished(
+ ServiceWorkerVersion* activating_version,
+ ServiceWorkerStatusCode status);
+ void OnDeleteFinished(ServiceWorkerStatusCode status);
+
+ // This method corresponds to the [[ClearRegistration]] algorithm.
+ void Clear();
+
+ void OnRestoreFinished(const StatusCallback& callback,
+ scoped_refptr<ServiceWorkerVersion> version,
+ ServiceWorkerStatusCode status);
+
const GURL pattern_;
- const GURL script_url_;
const int64 registration_id_;
-
+ bool is_deleted_;
+ bool is_uninstalling_;
+ bool is_uninstalled_;
+ bool should_activate_when_ready_;
+ base::Time last_update_check_;
+ int64_t resources_total_size_bytes_;
scoped_refptr<ServiceWorkerVersion> active_version_;
scoped_refptr<ServiceWorkerVersion> waiting_version_;
-
- bool is_shutdown_;
+ scoped_refptr<ServiceWorkerVersion> installing_version_;
+ ObserverList<Listener> listeners_;
base::WeakPtr<ServiceWorkerContextCore> context_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistration);
};
+
} // namespace content
+
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTRATION_H_
diff --git a/chromium/content/browser/service_worker/service_worker_registration_handle.cc b/chromium/content/browser/service_worker/service_worker_registration_handle.cc
new file mode 100644
index 00000000000..195a33a8235
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_registration_handle.cc
@@ -0,0 +1,147 @@
+// 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/service_worker/service_worker_registration_handle.h"
+
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_dispatcher_host.h"
+#include "content/browser/service_worker/service_worker_handle.h"
+#include "content/common/service_worker/service_worker_messages.h"
+
+namespace content {
+
+static const int kDocumentMainThreadId = 0;
+
+ServiceWorkerRegistrationHandle::ServiceWorkerRegistrationHandle(
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ ServiceWorkerDispatcherHost* dispatcher_host,
+ int provider_id,
+ ServiceWorkerRegistration* registration)
+ : context_(context),
+ dispatcher_host_(dispatcher_host),
+ provider_id_(provider_id),
+ handle_id_(context ? context->GetNewRegistrationHandleId()
+ : kInvalidServiceWorkerRegistrationHandleId),
+ ref_count_(1),
+ registration_(registration) {
+ DCHECK(registration_.get());
+ SetVersionAttributes(registration->installing_version(),
+ registration->waiting_version(),
+ registration->active_version());
+ registration_->AddListener(this);
+}
+
+ServiceWorkerRegistrationHandle::~ServiceWorkerRegistrationHandle() {
+ DCHECK(registration_.get());
+ registration_->RemoveListener(this);
+}
+
+ServiceWorkerRegistrationObjectInfo
+ServiceWorkerRegistrationHandle::GetObjectInfo() {
+ ServiceWorkerRegistrationObjectInfo info;
+ info.handle_id = handle_id_;
+ info.scope = registration_->pattern();
+ info.registration_id = registration_->id();
+ return info;
+}
+
+ServiceWorkerObjectInfo
+ServiceWorkerRegistrationHandle::CreateServiceWorkerHandleAndPass(
+ ServiceWorkerVersion* version) {
+ ServiceWorkerObjectInfo info;
+ if (context_ && version) {
+ scoped_ptr<ServiceWorkerHandle> handle =
+ ServiceWorkerHandle::Create(context_,
+ dispatcher_host_,
+ kDocumentMainThreadId,
+ provider_id_,
+ version);
+ info = handle->GetObjectInfo();
+ dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
+ }
+ return info;
+}
+
+void ServiceWorkerRegistrationHandle::IncrementRefCount() {
+ DCHECK_GT(ref_count_, 0);
+ ++ref_count_;
+}
+
+void ServiceWorkerRegistrationHandle::DecrementRefCount() {
+ DCHECK_GT(ref_count_, 0);
+ --ref_count_;
+}
+
+void ServiceWorkerRegistrationHandle::OnVersionAttributesChanged(
+ ServiceWorkerRegistration* registration,
+ ChangedVersionAttributesMask changed_mask,
+ const ServiceWorkerRegistrationInfo& info) {
+ DCHECK_EQ(registration->id(), registration_->id());
+ SetVersionAttributes(registration->installing_version(),
+ registration->waiting_version(),
+ registration->active_version());
+}
+
+void ServiceWorkerRegistrationHandle::OnRegistrationFailed(
+ ServiceWorkerRegistration* registration) {
+ DCHECK_EQ(registration->id(), registration_->id());
+ ClearVersionAttributes();
+}
+
+void ServiceWorkerRegistrationHandle::OnUpdateFound(
+ ServiceWorkerRegistration* registration) {
+ if (!dispatcher_host_)
+ return; // Could be NULL in some tests.
+ dispatcher_host_->Send(new ServiceWorkerMsg_UpdateFound(
+ kDocumentMainThreadId, GetObjectInfo()));
+}
+
+void ServiceWorkerRegistrationHandle::SetVersionAttributes(
+ ServiceWorkerVersion* installing_version,
+ ServiceWorkerVersion* waiting_version,
+ ServiceWorkerVersion* active_version) {
+ ChangedVersionAttributesMask mask;
+
+ if (installing_version != installing_version_.get()) {
+ installing_version_ = installing_version;
+ mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
+ }
+ if (waiting_version != waiting_version_.get()) {
+ waiting_version_ = waiting_version;
+ mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
+ }
+ if (active_version != active_version_.get()) {
+ active_version_ = active_version;
+ mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
+ }
+
+ if (!dispatcher_host_)
+ return; // Could be NULL in some tests.
+ if (!mask.changed())
+ return;
+
+ ServiceWorkerVersionAttributes attributes;
+ if (mask.installing_changed()) {
+ attributes.installing =
+ CreateServiceWorkerHandleAndPass(installing_version);
+ }
+ if (mask.waiting_changed()) {
+ attributes.waiting =
+ CreateServiceWorkerHandleAndPass(waiting_version);
+ }
+ if (mask.active_changed()) {
+ attributes.active =
+ CreateServiceWorkerHandleAndPass(active_version);
+ }
+
+ dispatcher_host_->Send(new ServiceWorkerMsg_SetVersionAttributes(
+ kDocumentMainThreadId, provider_id_, handle_id_,
+ mask.changed(), attributes));
+}
+
+void ServiceWorkerRegistrationHandle::ClearVersionAttributes() {
+ SetVersionAttributes(NULL, NULL, NULL);
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_registration_handle.h b/chromium/content/browser/service_worker/service_worker_registration_handle.h
new file mode 100644
index 00000000000..9439027041b
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_registration_handle.h
@@ -0,0 +1,84 @@
+// 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_SERVICE_WORKER_SERVICE_WORKER_REGISTRATION_HANDLE_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTRATION_HANDLE_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_version.h"
+#include "content/common/service_worker/service_worker_types.h"
+
+namespace content {
+
+class ServiceWorkerContextCore;
+class ServiceWorkerDispatcherHost;
+class ServiceWorkerVersion;
+
+// Roughly Corresponds to one ServiceWorkerRegistration object in the renderer
+// process (WebServiceWorkerRegistrationImpl).
+// Has references to the corresponding ServiceWorkerRegistration and
+// ServiceWorkerVersions (therefore they're guaranteed to be alive while this
+// handle is around).
+class ServiceWorkerRegistrationHandle
+ : public ServiceWorkerRegistration::Listener {
+ public:
+ CONTENT_EXPORT ServiceWorkerRegistrationHandle(
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ ServiceWorkerDispatcherHost* dispatcher_host,
+ int provider_id,
+ ServiceWorkerRegistration* registration);
+ virtual ~ServiceWorkerRegistrationHandle();
+
+ ServiceWorkerRegistrationObjectInfo GetObjectInfo();
+ ServiceWorkerObjectInfo CreateServiceWorkerHandleAndPass(
+ ServiceWorkerVersion* version);
+
+ bool HasNoRefCount() const { return ref_count_ <= 0; }
+ void IncrementRefCount();
+ void DecrementRefCount();
+
+ int provider_id() const { return provider_id_; }
+ int handle_id() const { return handle_id_; }
+
+ ServiceWorkerRegistration* registration() { return registration_.get(); }
+
+ private:
+ // ServiceWorkerRegistration::Listener overrides.
+ void OnVersionAttributesChanged(
+ ServiceWorkerRegistration* registration,
+ ChangedVersionAttributesMask changed_mask,
+ const ServiceWorkerRegistrationInfo& info) override;
+ void OnRegistrationFailed(ServiceWorkerRegistration* registration) override;
+ void OnUpdateFound(ServiceWorkerRegistration* registration) override;
+
+ // Sets the corresponding version field to the given version or if the given
+ // version is NULL, clears the field.
+ void SetVersionAttributes(
+ ServiceWorkerVersion* installing_version,
+ ServiceWorkerVersion* waiting_version,
+ ServiceWorkerVersion* active_version);
+
+ // Clears all version fields.
+ void ClearVersionAttributes();
+
+ base::WeakPtr<ServiceWorkerContextCore> context_;
+ ServiceWorkerDispatcherHost* dispatcher_host_;
+ const int provider_id_;
+ const int handle_id_;
+ int ref_count_; // Created with 1.
+
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_refptr<ServiceWorkerVersion> installing_version_;
+ scoped_refptr<ServiceWorkerVersion> waiting_version_;
+ scoped_refptr<ServiceWorkerVersion> active_version_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRegistrationHandle);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTRATION_HANDLE_H_
diff --git a/chromium/content/browser/service_worker/service_worker_registration_status.cc b/chromium/content/browser/service_worker/service_worker_registration_status.cc
index ee5ea906676..e67b833826d 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_status.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration_status.cc
@@ -35,6 +35,14 @@ void GetServiceWorkerRegistrationStatusResponse(
*error_type = WebServiceWorkerError::ErrorTypeNotFound;
return;
+ case SERVICE_WORKER_ERROR_NETWORK:
+ *error_type = WebServiceWorkerError::ErrorTypeNetwork;
+ return;
+
+ case SERVICE_WORKER_ERROR_SECURITY:
+ *error_type = WebServiceWorkerError::ErrorTypeSecurity;
+ return;
+
case SERVICE_WORKER_ERROR_ABORT:
case SERVICE_WORKER_ERROR_IPC_FAILED:
case SERVICE_WORKER_ERROR_FAILED:
diff --git a/chromium/content/browser/service_worker/service_worker_registration_unittest.cc b/chromium/content/browser/service_worker/service_worker_registration_unittest.cc
index ccce6417526..cea4b47734b 100644
--- a/chromium/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -4,13 +4,14 @@
#include "content/browser/service_worker/service_worker_registration.h"
-
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_registration_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -21,22 +22,69 @@ class ServiceWorkerRegistrationTest : public testing::Test {
ServiceWorkerRegistrationTest()
: io_thread_(BrowserThread::IO, &message_loop_) {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
+ new MockServiceWorkerDatabaseTaskManager(
+ base::ThreadTaskRunnerHandle::Get()));
context_.reset(
new ServiceWorkerContextCore(base::FilePath(),
- base::MessageLoopProxy::current(),
- base::MessageLoopProxy::current(),
+ base::ThreadTaskRunnerHandle::Get(),
+ database_task_manager.Pass(),
+ base::ThreadTaskRunnerHandle::Get(),
+ NULL,
NULL,
NULL,
NULL));
context_ptr_ = context_->AsWeakPtr();
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
context_.reset();
base::RunLoop().RunUntilIdle();
}
+ class RegistrationListener : public ServiceWorkerRegistration::Listener {
+ public:
+ RegistrationListener() {}
+ ~RegistrationListener() {
+ if (observed_registration_.get())
+ observed_registration_->RemoveListener(this);
+ }
+
+ void OnVersionAttributesChanged(
+ ServiceWorkerRegistration* registration,
+ ChangedVersionAttributesMask changed_mask,
+ const ServiceWorkerRegistrationInfo& info) override {
+ observed_registration_ = registration;
+ observed_changed_mask_ = changed_mask;
+ observed_info_ = info;
+ }
+
+ void OnRegistrationFailed(
+ ServiceWorkerRegistration* registration) override {
+ NOTREACHED();
+ }
+
+ void OnRegistrationFinishedUninstalling(
+ ServiceWorkerRegistration* registration) override {
+ NOTREACHED();
+ }
+
+ void OnUpdateFound(ServiceWorkerRegistration* registration) override {
+ NOTREACHED();
+ }
+
+ void Reset() {
+ observed_registration_ = NULL;
+ observed_changed_mask_ = ChangedVersionAttributesMask();
+ observed_info_ = ServiceWorkerRegistrationInfo();
+ }
+
+ scoped_refptr<ServiceWorkerRegistration> observed_registration_;
+ ChangedVersionAttributesMask observed_changed_mask_;
+ ServiceWorkerRegistrationInfo observed_info_;
+ };
+
protected:
scoped_ptr<ServiceWorkerContextCore> context_;
base::WeakPtr<ServiceWorkerContextCore> context_ptr_;
@@ -44,33 +92,100 @@ class ServiceWorkerRegistrationTest : public testing::Test {
BrowserThreadImpl io_thread_;
};
-// Make sure that activation does not leak
-TEST_F(ServiceWorkerRegistrationTest, ActivatePending) {
- int64 registration_id = -1L;
+TEST_F(ServiceWorkerRegistrationTest, SetAndUnsetVersions) {
+ const GURL kScope("http://www.example.not/");
+ const GURL kScript("http://www.example.not/service_worker.js");
+ int64 kRegistrationId = 1L;
scoped_refptr<ServiceWorkerRegistration> registration =
new ServiceWorkerRegistration(
- GURL("http://www.example.com/*"),
- GURL("http://www.example.com/service_worker.js"),
- registration_id,
+ kScope,
+ kRegistrationId,
context_ptr_);
const int64 version_1_id = 1L;
const int64 version_2_id = 2L;
- scoped_refptr<ServiceWorkerVersion> version_1 =
- new ServiceWorkerVersion(registration, version_1_id, context_ptr_);
- version_1->SetStatus(ServiceWorkerVersion::ACTIVE);
- registration->set_active_version(version_1);
+ scoped_refptr<ServiceWorkerVersion> version_1 = new ServiceWorkerVersion(
+ registration.get(), kScript, version_1_id, context_ptr_);
+ scoped_refptr<ServiceWorkerVersion> version_2 = new ServiceWorkerVersion(
+ registration.get(), kScript, version_2_id, context_ptr_);
+
+ RegistrationListener listener;
+ registration->AddListener(&listener);
+ registration->SetActiveVersion(version_1.get());
- scoped_refptr<ServiceWorkerVersion> version_2 =
- new ServiceWorkerVersion(registration, version_2_id, context_ptr_);
- registration->set_waiting_version(version_2);
+ EXPECT_EQ(version_1.get(), registration->active_version());
+ EXPECT_EQ(registration, listener.observed_registration_);
+ EXPECT_EQ(ChangedVersionAttributesMask::ACTIVE_VERSION,
+ listener.observed_changed_mask_.changed());
+ EXPECT_EQ(kScope, listener.observed_info_.pattern);
+ EXPECT_EQ(version_1_id, listener.observed_info_.active_version.version_id);
+ EXPECT_EQ(kScript, listener.observed_info_.active_version.script_url);
+ EXPECT_EQ(listener.observed_info_.installing_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_EQ(listener.observed_info_.waiting_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_EQ(listener.observed_info_.controlling_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ listener.Reset();
- registration->ActivateWaitingVersion();
- DCHECK_EQ(version_2, registration->active_version());
- DCHECK(version_1->HasOneRef());
- version_1 = NULL;
+ registration->SetInstallingVersion(version_2.get());
- DCHECK(!version_2->HasOneRef());
+ EXPECT_EQ(version_2.get(), registration->installing_version());
+ EXPECT_EQ(ChangedVersionAttributesMask::INSTALLING_VERSION,
+ listener.observed_changed_mask_.changed());
+ EXPECT_EQ(version_1_id, listener.observed_info_.active_version.version_id);
+ EXPECT_EQ(version_2_id,
+ listener.observed_info_.installing_version.version_id);
+ EXPECT_EQ(listener.observed_info_.waiting_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_EQ(listener.observed_info_.controlling_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ listener.Reset();
+
+ registration->SetWaitingVersion(version_2.get());
+
+ EXPECT_EQ(version_2.get(), registration->waiting_version());
+ EXPECT_FALSE(registration->installing_version());
+ EXPECT_TRUE(listener.observed_changed_mask_.waiting_changed());
+ EXPECT_TRUE(listener.observed_changed_mask_.installing_changed());
+ EXPECT_EQ(version_1_id, listener.observed_info_.active_version.version_id);
+ EXPECT_EQ(version_2_id, listener.observed_info_.waiting_version.version_id);
+ EXPECT_EQ(listener.observed_info_.installing_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_EQ(listener.observed_info_.controlling_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ listener.Reset();
+
+ registration->UnsetVersion(version_2.get());
+
+ EXPECT_FALSE(registration->waiting_version());
+ EXPECT_EQ(ChangedVersionAttributesMask::WAITING_VERSION,
+ listener.observed_changed_mask_.changed());
+ EXPECT_EQ(version_1_id, listener.observed_info_.active_version.version_id);
+ EXPECT_EQ(listener.observed_info_.waiting_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_EQ(listener.observed_info_.installing_version.version_id,
+ kInvalidServiceWorkerVersionId);
+ EXPECT_EQ(listener.observed_info_.controlling_version.version_id,
+ kInvalidServiceWorkerVersionId);
+}
+
+TEST_F(ServiceWorkerRegistrationTest, FailedRegistrationNoCrash) {
+ const GURL kScope("http://www.example.not/");
+ int64 kRegistrationId = 1L;
+ int kProviderId = 1;
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ new ServiceWorkerRegistration(
+ kScope,
+ kRegistrationId,
+ context_ptr_);
+ scoped_ptr<ServiceWorkerRegistrationHandle> handle(
+ new ServiceWorkerRegistrationHandle(context_ptr_,
+ NULL,
+ kProviderId,
+ registration.get()));
+ registration->NotifyRegistrationFailed();
+ // Don't crash when handle gets destructed.
}
} // namespace content
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 a04e0116452..6c871e6cd55 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler.cc
+++ b/chromium/content/browser/service_worker/service_worker_request_handler.cc
@@ -4,16 +4,21 @@
#include "content/browser/service_worker/service_worker_request_handler.h"
+#include <string>
+
#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_registration.h"
#include "content/browser/service_worker/service_worker_url_request_job.h"
#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/resource_context.h"
+#include "net/base/net_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_interceptor.h"
-#include "webkit/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_storage_context.h"
namespace content {
@@ -24,29 +29,30 @@ int kUserDataKey; // Key value is not important.
class ServiceWorkerRequestInterceptor
: public net::URLRequestInterceptor {
public:
- ServiceWorkerRequestInterceptor() {}
- virtual ~ServiceWorkerRequestInterceptor() {}
- virtual net::URLRequestJob* MaybeInterceptRequest(
+ explicit ServiceWorkerRequestInterceptor(ResourceContext* resource_context)
+ : resource_context_(resource_context) {}
+ ~ServiceWorkerRequestInterceptor() override {}
+ net::URLRequestJob* MaybeInterceptRequest(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
ServiceWorkerRequestHandler* handler =
ServiceWorkerRequestHandler::GetHandler(request);
if (!handler)
return NULL;
- return handler->MaybeCreateJob(request, network_delegate);
+ return handler->MaybeCreateJob(
+ request, network_delegate, resource_context_);
}
private:
+ ResourceContext* resource_context_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRequestInterceptor);
};
-bool IsMethodSupported(const std::string& method) {
- return (method == "GET") || (method == "HEAD");
-}
-
-bool IsSchemeAndMethodSupported(const net::URLRequest* request) {
- return request->url().SchemeIsHTTPOrHTTPS() &&
- IsMethodSupported(request->method());
+// This is work around to avoid hijacking CORS preflight.
+// TODO(horo): Remove this check when we implement "HTTP fetch" correctly.
+// http://fetch.spec.whatwg.org/#concept-http-fetch
+bool IsMethodSupportedForServiceWorker(const std::string& method) {
+ return method != "OPTIONS";
}
} // namespace
@@ -54,12 +60,18 @@ bool IsSchemeAndMethodSupported(const net::URLRequest* request) {
void ServiceWorkerRequestHandler::InitializeHandler(
net::URLRequest* request,
ServiceWorkerContextWrapper* context_wrapper,
- webkit_blob::BlobStorageContext* blob_storage_context,
+ storage::BlobStorageContext* blob_storage_context,
int process_id,
int provider_id,
- ResourceType::Type resource_type) {
- if (!ServiceWorkerUtils::IsFeatureEnabled() ||
- !IsSchemeAndMethodSupported(request)) {
+ bool skip_service_worker,
+ FetchRequestMode request_mode,
+ FetchCredentialsMode credentials_mode,
+ ResourceType resource_type,
+ RequestContextType request_context_type,
+ RequestContextFrameType frame_type,
+ scoped_refptr<ResourceRequestBody> body) {
+ if (!request->url().SchemeIsHTTPOrHTTPS() ||
+ !IsMethodSupportedForServiceWorker(request->method())) {
return;
}
@@ -73,9 +85,22 @@ void ServiceWorkerRequestHandler::InitializeHandler(
if (!provider_host || !provider_host->IsContextAlive())
return;
+ if (skip_service_worker) {
+ if (ServiceWorkerUtils::IsMainResourceType(resource_type)) {
+ provider_host->SetDocumentUrl(net::SimplifyUrlForRequest(request->url()));
+ provider_host->SetTopmostFrameUrl(request->first_party_for_cookies());
+ }
+ return;
+ }
+
scoped_ptr<ServiceWorkerRequestHandler> handler(
- provider_host->CreateRequestHandler(resource_type,
- blob_storage_context->AsWeakPtr()));
+ provider_host->CreateRequestHandler(request_mode,
+ credentials_mode,
+ resource_type,
+ request_context_type,
+ frame_type,
+ blob_storage_context->AsWeakPtr(),
+ body));
if (!handler)
return;
@@ -84,14 +109,24 @@ void ServiceWorkerRequestHandler::InitializeHandler(
ServiceWorkerRequestHandler* ServiceWorkerRequestHandler::GetHandler(
net::URLRequest* request) {
- return reinterpret_cast<ServiceWorkerRequestHandler*>(
+ return static_cast<ServiceWorkerRequestHandler*>(
request->GetUserData(&kUserDataKey));
}
scoped_ptr<net::URLRequestInterceptor>
-ServiceWorkerRequestHandler::CreateInterceptor() {
+ServiceWorkerRequestHandler::CreateInterceptor(
+ ResourceContext* resource_context) {
return scoped_ptr<net::URLRequestInterceptor>(
- new ServiceWorkerRequestInterceptor);
+ new ServiceWorkerRequestInterceptor(resource_context));
+}
+
+bool ServiceWorkerRequestHandler::IsControlledByServiceWorker(
+ net::URLRequest* request) {
+ ServiceWorkerRequestHandler* handler = GetHandler(request);
+ if (!handler || !handler->provider_host_)
+ return false;
+ return handler->provider_host_->associated_registration() ||
+ handler->provider_host_->running_hosted_version();
}
ServiceWorkerRequestHandler::~ServiceWorkerRequestHandler() {
@@ -100,8 +135,8 @@ ServiceWorkerRequestHandler::~ServiceWorkerRequestHandler() {
ServiceWorkerRequestHandler::ServiceWorkerRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context,
- ResourceType::Type resource_type)
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ ResourceType resource_type)
: context_(context),
provider_host_(provider_host),
blob_storage_context_(blob_storage_context),
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 0c666b548df..91afd2688e8 100644
--- a/chromium/content/browser/service_worker/service_worker_request_handler.h
+++ b/chromium/content/browser/service_worker/service_worker_request_handler.h
@@ -8,10 +8,15 @@
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
+#include "base/time/time.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/request_context_frame_type.h"
+#include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_type.h"
#include "net/url_request/url_request_job_factory.h"
-#include "webkit/common/resource_type.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
namespace net {
class NetworkDelegate;
@@ -19,12 +24,14 @@ class URLRequest;
class URLRequestInterceptor;
}
-namespace webkit_blob {
+namespace storage {
class BlobStorageContext;
}
namespace content {
+class ResourceContext;
+class ResourceRequestBody;
class ServiceWorkerContextCore;
class ServiceWorkerContextWrapper;
class ServiceWorkerProviderHost;
@@ -43,10 +50,16 @@ class CONTENT_EXPORT ServiceWorkerRequestHandler
static void InitializeHandler(
net::URLRequest* request,
ServiceWorkerContextWrapper* context_wrapper,
- webkit_blob::BlobStorageContext* blob_storage_context,
+ storage::BlobStorageContext* blob_storage_context,
int process_id,
int provider_id,
- ResourceType::Type resource_type);
+ bool skip_service_worker,
+ FetchRequestMode request_mode,
+ FetchCredentialsMode credentials_mode,
+ ResourceType resource_type,
+ RequestContextType request_context_type,
+ RequestContextFrameType frame_type,
+ scoped_refptr<ResourceRequestBody> body);
// Returns the handler attached to |request|. This may return NULL
// if no handler is attached.
@@ -54,27 +67,45 @@ class CONTENT_EXPORT ServiceWorkerRequestHandler
net::URLRequest* request);
// Creates a protocol interceptor for ServiceWorker.
- static scoped_ptr<net::URLRequestInterceptor> CreateInterceptor();
+ static scoped_ptr<net::URLRequestInterceptor> CreateInterceptor(
+ ResourceContext* resource_context);
- virtual ~ServiceWorkerRequestHandler();
+ // Returns true if the request falls into the scope of a ServiceWorker.
+ // It's only reliable after the ServiceWorkerRequestHandler MaybeCreateJob
+ // method runs to completion for this request. The AppCache handler uses
+ // this to avoid colliding with ServiceWorkers.
+ static bool IsControlledByServiceWorker(net::URLRequest* request);
+
+ ~ServiceWorkerRequestHandler() override;
// Called via custom URLRequestJobFactory.
virtual net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) = 0;
+ net::NetworkDelegate* network_delegate,
+ ResourceContext* context) = 0;
+
+ virtual void GetExtraResponseInfo(
+ bool* was_fetched_via_service_worker,
+ bool* was_fallback_required_by_service_worker,
+ GURL* original_url_via_service_worker,
+ blink::WebServiceWorkerResponseType* response_type_via_service_worker,
+ base::TimeTicks* fetch_start_time,
+ base::TimeTicks* fetch_ready_time,
+ base::TimeTicks* fetch_end_time) const = 0;
protected:
ServiceWorkerRequestHandler(
base::WeakPtr<ServiceWorkerContextCore> context,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context,
- ResourceType::Type resource_type);
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ ResourceType resource_type);
base::WeakPtr<ServiceWorkerContextCore> context_;
base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context_;
- ResourceType::Type resource_type_;
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
+ ResourceType resource_type_;
+ private:
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRequestHandler);
};
diff --git a/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc b/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc
new file mode 100644
index 00000000000..fe5483de70e
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_request_handler_unittest.cc
@@ -0,0 +1,158 @@
+// 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/service_worker/service_worker_request_handler.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"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_provider_host.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/common/resource_request_body.h"
+#include "content/public/common/request_context_frame_type.h"
+#include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_type.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/url_request/url_request_context.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+int kMockRenderProcessId = 1224;
+int kMockProviderId = 1;
+
+void EmptyCallback() {
+}
+
+}
+
+class ServiceWorkerRequestHandlerTest : public testing::Test {
+ public:
+ ServiceWorkerRequestHandlerTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
+
+ void SetUp() override {
+ helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
+
+ // A new unstored registration/version.
+ registration_ = new ServiceWorkerRegistration(
+ GURL("http://host/scope/"), 1L, context()->AsWeakPtr());
+ version_ = new ServiceWorkerVersion(registration_.get(),
+ GURL("http://host/script.js"),
+ 1L,
+ context()->AsWeakPtr());
+
+ // An empty host.
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kMockRenderProcessId, kMockProviderId, context()->AsWeakPtr(), NULL));
+ provider_host_ = host->AsWeakPtr();
+ context()->AddProviderHost(host.Pass());
+
+ context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
+ base::RunLoop().RunUntilIdle();
+
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ registration_->SetActiveVersion(version_.get());
+ context()->storage()->StoreRegistration(
+ registration_.get(),
+ version_.get(),
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ provider_host_->AssociateRegistration(registration_.get());
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void TearDown() override {
+ version_ = NULL;
+ registration_ = NULL;
+ helper_.reset();
+ }
+
+ ServiceWorkerContextCore* context() const { return helper_->context(); }
+ ServiceWorkerContextWrapper* context_wrapper() const {
+ return helper_->context_wrapper();
+ }
+
+ bool InitializeHandlerCheck(const std::string& url,
+ const std::string& method,
+ bool skip_service_worker,
+ ResourceType resource_type) {
+ const GURL kDocUrl(url);
+ scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
+ kDocUrl, net::DEFAULT_PRIORITY, &url_request_delegate_, NULL);
+ request->set_method(method);
+ ServiceWorkerRequestHandler::InitializeHandler(
+ request.get(),
+ context_wrapper(),
+ &blob_storage_context_,
+ kMockRenderProcessId,
+ kMockProviderId,
+ skip_service_worker,
+ FETCH_REQUEST_MODE_NO_CORS,
+ FETCH_CREDENTIALS_MODE_OMIT,
+ resource_type,
+ REQUEST_CONTEXT_TYPE_HYPERLINK,
+ REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ NULL);
+ return ServiceWorkerRequestHandler::GetHandler(request.get()) != NULL;
+ }
+
+ protected:
+ TestBrowserThreadBundle browser_thread_bundle_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_refptr<ServiceWorkerVersion> version_;
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+ net::URLRequestContext url_request_context_;
+ MockURLRequestDelegate url_request_delegate_;
+ storage::BlobStorageContext blob_storage_context_;
+};
+
+TEST_F(ServiceWorkerRequestHandlerTest, InitializeHandler) {
+ EXPECT_TRUE(InitializeHandlerCheck(
+ "http://host/scope/doc", "GET", false, RESOURCE_TYPE_MAIN_FRAME));
+ EXPECT_TRUE(InitializeHandlerCheck(
+ "https://host/scope/doc", "GET", false, RESOURCE_TYPE_MAIN_FRAME));
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "ftp://host/scope/doc", "GET", false, RESOURCE_TYPE_MAIN_FRAME));
+
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "http://host/scope/doc", "OPTIONS", false, RESOURCE_TYPE_MAIN_FRAME));
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "https://host/scope/doc", "OPTIONS", false, RESOURCE_TYPE_MAIN_FRAME));
+
+ provider_host_->SetDocumentUrl(GURL(""));
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "http://host/scope/doc", "GET", true, RESOURCE_TYPE_MAIN_FRAME));
+ EXPECT_STREQ("http://host/scope/doc",
+ provider_host_->document_url().spec().c_str());
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "https://host/scope/doc", "GET", true, RESOURCE_TYPE_MAIN_FRAME));
+ EXPECT_STREQ("https://host/scope/doc",
+ provider_host_->document_url().spec().c_str());
+
+ provider_host_->SetDocumentUrl(GURL(""));
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "http://host/scope/doc", "GET", true, RESOURCE_TYPE_SUB_FRAME));
+ EXPECT_STREQ("http://host/scope/doc",
+ provider_host_->document_url().spec().c_str());
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "https://host/scope/doc", "GET", true, RESOURCE_TYPE_SUB_FRAME));
+ EXPECT_STREQ("https://host/scope/doc",
+ provider_host_->document_url().spec().c_str());
+
+ provider_host_->SetDocumentUrl(GURL(""));
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "http://host/scope/doc", "GET", true, RESOURCE_TYPE_IMAGE));
+ EXPECT_STREQ("", provider_host_->document_url().spec().c_str());
+ EXPECT_FALSE(InitializeHandlerCheck(
+ "https://host/scope/doc", "GET", true, RESOURCE_TYPE_IMAGE));
+ EXPECT_STREQ("", provider_host_->document_url().spec().c_str());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_script_cache_map.cc b/chromium/content/browser/service_worker/service_worker_script_cache_map.cc
index 60876b8d716..062ae159a2a 100644
--- a/chromium/content/browser/service_worker/service_worker_script_cache_map.cc
+++ b/chromium/content/browser/service_worker/service_worker_script_cache_map.cc
@@ -16,56 +16,70 @@ ServiceWorkerScriptCacheMap::ServiceWorkerScriptCacheMap(
ServiceWorkerVersion* owner,
base::WeakPtr<ServiceWorkerContextCore> context)
: owner_(owner),
- context_(context),
- has_error_(false) {
+ context_(context) {
}
ServiceWorkerScriptCacheMap::~ServiceWorkerScriptCacheMap() {
}
-int64 ServiceWorkerScriptCacheMap::Lookup(const GURL& url) {
- ResourceIDMap::const_iterator found = resource_ids_.find(url);
- if (found == resource_ids_.end())
+int64 ServiceWorkerScriptCacheMap::LookupResourceId(const GURL& url) {
+ ResourceMap::const_iterator found = resource_map_.find(url);
+ if (found == resource_map_.end())
return kInvalidServiceWorkerResponseId;
- return found->second;
+ return found->second.resource_id;
+}
+
+int64 ServiceWorkerScriptCacheMap::LookupResourceSize(const GURL& url) {
+ ResourceMap::const_iterator found = resource_map_.find(url);
+ if (found == resource_map_.end())
+ return kInvalidServiceWorkerResponseId;
+ return found->second.size_bytes;
}
void ServiceWorkerScriptCacheMap::NotifyStartedCaching(
const GURL& url, int64 resource_id) {
- DCHECK_EQ(kInvalidServiceWorkerResponseId, Lookup(url));
- DCHECK(owner_->status() == ServiceWorkerVersion::NEW);
- resource_ids_[url] = resource_id;
- context_->storage()->StoreUncommittedReponseId(resource_id);
+ DCHECK_EQ(kInvalidServiceWorkerResponseId, LookupResourceId(url));
+ DCHECK(owner_->status() == ServiceWorkerVersion::NEW ||
+ owner_->status() == ServiceWorkerVersion::INSTALLING);
+ resource_map_[url] =
+ ServiceWorkerDatabase::ResourceRecord(resource_id, url, -1);
+ context_->storage()->StoreUncommittedResponseId(resource_id);
}
void ServiceWorkerScriptCacheMap::NotifyFinishedCaching(
- const GURL& url, bool success) {
- DCHECK_NE(kInvalidServiceWorkerResponseId, Lookup(url));
- DCHECK(owner_->status() == ServiceWorkerVersion::NEW);
- if (!success) {
- context_->storage()->DoomUncommittedResponse(Lookup(url));
- has_error_ = true;
- resource_ids_.erase(url);
+ const GURL& url,
+ int64 size_bytes,
+ const net::URLRequestStatus& status) {
+ DCHECK_NE(kInvalidServiceWorkerResponseId, LookupResourceId(url));
+ DCHECK(owner_->status() == ServiceWorkerVersion::NEW ||
+ owner_->status() == ServiceWorkerVersion::INSTALLING);
+ if (!status.is_success()) {
+ context_->storage()->DoomUncommittedResponse(LookupResourceId(url));
+ resource_map_.erase(url);
+ if (owner_->script_url() == url)
+ main_script_status_ = status;
+ } else {
+ resource_map_[url].size_bytes = size_bytes;
}
}
void ServiceWorkerScriptCacheMap::GetResources(
std::vector<ServiceWorkerDatabase::ResourceRecord>* resources) {
DCHECK(resources->empty());
- for (ResourceIDMap::const_iterator it = resource_ids_.begin();
- it != resource_ids_.end(); ++it) {
- resources->push_back(
- ServiceWorkerDatabase::ResourceRecord(it->second, it->first));
+ for (ResourceMap::const_iterator it = resource_map_.begin();
+ it != resource_map_.end();
+ ++it) {
+ resources->push_back(it->second);
}
}
void ServiceWorkerScriptCacheMap::SetResources(
const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources) {
- DCHECK(resource_ids_.empty());
+ DCHECK(resource_map_.empty());
typedef std::vector<ServiceWorkerDatabase::ResourceRecord> RecordVector;
for (RecordVector::const_iterator it = resources.begin();
it != resources.end(); ++it) {
- resource_ids_[it->url] = it->resource_id;
+ resource_map_[it->url] = *it;
}
}
diff --git a/chromium/content/browser/service_worker/service_worker_script_cache_map.h b/chromium/content/browser/service_worker/service_worker_script_cache_map.h
index 4513f3d9ea7..de814c210b1 100644
--- a/chromium/content/browser/service_worker/service_worker_script_cache_map.h
+++ b/chromium/content/browser/service_worker/service_worker_script_cache_map.h
@@ -11,6 +11,8 @@
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_database.h"
+#include "content/common/content_export.h"
+#include "net/url_request/url_request_status.h"
class GURL;
@@ -20,18 +22,22 @@ class ServiceWorkerContextCore;
class ServiceWorkerVersion;
// Class that maintains the mapping between urls and a resource id
-// for a particular versions implicit script resources.
-class ServiceWorkerScriptCacheMap {
+// for a particular version's implicit script resources.
+class CONTENT_EXPORT ServiceWorkerScriptCacheMap {
public:
- int64 Lookup(const GURL& url);
+ int64 LookupResourceId(const GURL& url);
+ // A size of -1 means that we don't know the size yet
+ // (it has not finished caching).
+ int64 LookupResourceSize(const GURL& url);
// Used during the initial run of a new version to build the map
// of resources ids.
void NotifyStartedCaching(const GURL& url, int64 resource_id);
- void NotifyFinishedCaching(const GURL& url, bool success);
+ void NotifyFinishedCaching(const GURL& url,
+ int64 size_bytes,
+ const net::URLRequestStatus& status);
// Used to retrieve the results of the initial run of a new version.
- bool HasError() const { return has_error_; }
void GetResources(
std::vector<ServiceWorkerDatabase::ResourceRecord>* resources);
@@ -39,8 +45,14 @@ class ServiceWorkerScriptCacheMap {
void SetResources(
const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources);
+ size_t size() const { return resource_map_.size(); }
+
+ const net::URLRequestStatus& main_script_status() const {
+ return main_script_status_;
+ }
+
private:
- typedef std::map<GURL, int64> ResourceIDMap;
+ typedef std::map<GURL, ServiceWorkerDatabase::ResourceRecord> ResourceMap;
// The version objects owns its script cache and provides a rawptr to it.
friend class ServiceWorkerVersion;
@@ -51,8 +63,8 @@ class ServiceWorkerScriptCacheMap {
ServiceWorkerVersion* owner_;
base::WeakPtr<ServiceWorkerContextCore> context_;
- ResourceIDMap resource_ids_;
- bool has_error_;
+ ResourceMap resource_map_;
+ net::URLRequestStatus main_script_status_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerScriptCacheMap);
};
diff --git a/chromium/content/browser/service_worker/service_worker_storage.cc b/chromium/content/browser/service_worker/service_worker_storage.cc
index 8a924e0c723..0a06823ca41 100644
--- a/chromium/content/browser/service_worker/service_worker_storage.cc
+++ b/chromium/content/browser/service_worker/service_worker_storage.cc
@@ -7,20 +7,26 @@
#include <string>
#include "base/bind_helpers.h"
+#include "base/debug/trace_event.h"
+#include "base/files/file_util.h"
#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "base/task_runner_util.h"
#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_histograms.h"
#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_registration.h"
#include "content/browser/service_worker/service_worker_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/public/browser/browser_thread.h"
+#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
-#include "webkit/browser/quota/quota_manager_proxy.h"
+#include "storage/browser/quota/quota_manager_proxy.h"
+#include "storage/browser/quota/special_storage_policy.h"
namespace content {
@@ -46,8 +52,6 @@ void CompleteFindSoon(
RunSoon(from_here, base::Bind(callback, status, registration));
}
-const base::FilePath::CharType kServiceWorkerDirectory[] =
- FILE_PATH_LITERAL("Service Worker");
const base::FilePath::CharType kDatabaseName[] =
FILE_PATH_LITERAL("Database");
const base::FilePath::CharType kDiskCacheName[] =
@@ -56,8 +60,6 @@ const base::FilePath::CharType kDiskCacheName[] =
const int kMaxMemDiskCacheSize = 10 * 1024 * 1024;
const int kMaxDiskCacheSize = 250 * 1024 * 1024;
-void EmptyCompletionCallback(int) {}
-
ServiceWorkerStatusCode DatabaseStatusToStatusCode(
ServiceWorkerDatabase::Status status) {
switch (status) {
@@ -72,6 +74,129 @@ ServiceWorkerStatusCode DatabaseStatusToStatusCode(
}
}
+class ResponseComparer : public base::RefCounted<ResponseComparer> {
+ public:
+ ResponseComparer(
+ base::WeakPtr<ServiceWorkerStorage> owner,
+ scoped_ptr<ServiceWorkerResponseReader> lhs,
+ scoped_ptr<ServiceWorkerResponseReader> rhs,
+ const ServiceWorkerStorage::CompareCallback& callback)
+ : owner_(owner),
+ completion_callback_(callback),
+ lhs_reader_(lhs.release()),
+ rhs_reader_(rhs.release()),
+ completion_count_(0),
+ previous_result_(0) {
+ }
+
+ void Start();
+
+ private:
+ friend class base::RefCounted<ResponseComparer>;
+
+ static const int kBufferSize = 16 * 1024;
+
+ ~ResponseComparer() {}
+ void ReadInfos();
+ void OnReadInfoComplete(int result);
+ void ReadSomeData();
+ void OnReadDataComplete(int result);
+
+ base::WeakPtr<ServiceWorkerStorage> owner_;
+ ServiceWorkerStorage::CompareCallback completion_callback_;
+ scoped_ptr<ServiceWorkerResponseReader> lhs_reader_;
+ scoped_refptr<HttpResponseInfoIOBuffer> lhs_info_;
+ scoped_refptr<net::IOBuffer> lhs_buffer_;
+ scoped_ptr<ServiceWorkerResponseReader> rhs_reader_;
+ scoped_refptr<HttpResponseInfoIOBuffer> rhs_info_;
+ scoped_refptr<net::IOBuffer> rhs_buffer_;
+ int completion_count_;
+ int previous_result_;
+ DISALLOW_COPY_AND_ASSIGN(ResponseComparer);
+};
+
+void ResponseComparer::Start() {
+ lhs_buffer_ = new net::IOBuffer(kBufferSize);
+ lhs_info_ = new HttpResponseInfoIOBuffer();
+ rhs_buffer_ = new net::IOBuffer(kBufferSize);
+ rhs_info_ = new HttpResponseInfoIOBuffer();
+
+ ReadInfos();
+}
+
+void ResponseComparer::ReadInfos() {
+ lhs_reader_->ReadInfo(
+ lhs_info_.get(), base::Bind(&ResponseComparer::OnReadInfoComplete, this));
+ rhs_reader_->ReadInfo(
+ rhs_info_.get(), base::Bind(&ResponseComparer::OnReadInfoComplete, this));
+}
+
+void ResponseComparer::OnReadInfoComplete(int result) {
+ if (completion_callback_.is_null() || !owner_)
+ return;
+ if (result < 0) {
+ completion_callback_.Run(SERVICE_WORKER_ERROR_FAILED, false);
+ completion_callback_.Reset();
+ return;
+ }
+ if (++completion_count_ != 2)
+ return;
+
+ if (lhs_info_->response_data_size != rhs_info_->response_data_size) {
+ completion_callback_.Run(SERVICE_WORKER_OK, false);
+ return;
+ }
+ ReadSomeData();
+}
+
+void ResponseComparer::ReadSomeData() {
+ completion_count_ = 0;
+ lhs_reader_->ReadData(
+ lhs_buffer_.get(),
+ kBufferSize,
+ base::Bind(&ResponseComparer::OnReadDataComplete, this));
+ rhs_reader_->ReadData(
+ rhs_buffer_.get(),
+ kBufferSize,
+ base::Bind(&ResponseComparer::OnReadDataComplete, this));
+}
+
+void ResponseComparer::OnReadDataComplete(int result) {
+ if (completion_callback_.is_null() || !owner_)
+ return;
+ if (result < 0) {
+ completion_callback_.Run(SERVICE_WORKER_ERROR_FAILED, false);
+ completion_callback_.Reset();
+ return;
+ }
+ if (++completion_count_ != 2) {
+ previous_result_ = result;
+ return;
+ }
+
+ // TODO(michaeln): Probably shouldn't assume that the amounts read from
+ // each reader will always be the same. This would wrongly signal false
+ // in that case.
+ if (result != previous_result_) {
+ completion_callback_.Run(SERVICE_WORKER_OK, false);
+ return;
+ }
+
+ if (result == 0) {
+ completion_callback_.Run(SERVICE_WORKER_OK, true);
+ return;
+ }
+
+ int compare_result =
+ memcmp(lhs_buffer_->data(), rhs_buffer_->data(), result);
+ if (compare_result != 0) {
+ completion_callback_.Run(SERVICE_WORKER_OK, false);
+ return;
+ }
+
+ ReadSomeData();
+}
+
} // namespace
ServiceWorkerStorage::InitialData::InitialData()
@@ -83,30 +208,49 @@ ServiceWorkerStorage::InitialData::InitialData()
ServiceWorkerStorage::InitialData::~InitialData() {
}
-ServiceWorkerStorage::ServiceWorkerStorage(
- const base::FilePath& path,
- base::WeakPtr<ServiceWorkerContextCore> context,
- base::SequencedTaskRunner* database_task_runner,
- base::MessageLoopProxy* disk_cache_thread,
- quota::QuotaManagerProxy* quota_manager_proxy)
- : next_registration_id_(kInvalidServiceWorkerRegistrationId),
- next_version_id_(kInvalidServiceWorkerVersionId),
- next_resource_id_(kInvalidServiceWorkerResourceId),
- state_(UNINITIALIZED),
- context_(context),
- database_task_runner_(database_task_runner),
- disk_cache_thread_(disk_cache_thread),
- quota_manager_proxy_(quota_manager_proxy),
- is_purge_pending_(false),
- weak_factory_(this) {
- if (!path.empty())
- path_ = path.Append(kServiceWorkerDirectory);
- database_.reset(new ServiceWorkerDatabase(GetDatabasePath()));
+ServiceWorkerStorage::
+DidDeleteRegistrationParams::DidDeleteRegistrationParams()
+ : registration_id(kInvalidServiceWorkerRegistrationId) {
+}
+
+ServiceWorkerStorage::
+DidDeleteRegistrationParams::~DidDeleteRegistrationParams() {
}
ServiceWorkerStorage::~ServiceWorkerStorage() {
+ ClearSessionOnlyOrigins();
weak_factory_.InvalidateWeakPtrs();
- database_task_runner_->DeleteSoon(FROM_HERE, database_.release());
+ database_task_manager_->GetTaskRunner()->DeleteSoon(FROM_HERE,
+ database_.release());
+}
+
+// static
+scoped_ptr<ServiceWorkerStorage> ServiceWorkerStorage::Create(
+ const base::FilePath& path,
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy) {
+ return make_scoped_ptr(new ServiceWorkerStorage(path,
+ context,
+ database_task_manager.Pass(),
+ disk_cache_thread,
+ quota_manager_proxy,
+ special_storage_policy));
+}
+
+// static
+scoped_ptr<ServiceWorkerStorage> ServiceWorkerStorage::Create(
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ ServiceWorkerStorage* old_storage) {
+ return make_scoped_ptr(
+ new ServiceWorkerStorage(old_storage->path_,
+ context,
+ old_storage->database_task_manager_->Clone(),
+ old_storage->disk_cache_thread_,
+ old_storage->quota_manager_proxy_.get(),
+ old_storage->special_storage_policy_.get()));
}
void ServiceWorkerStorage::FindRegistrationForDocument(
@@ -120,6 +264,11 @@ void ServiceWorkerStorage::FindRegistrationForDocument(
CompleteFindNow(scoped_refptr<ServiceWorkerRegistration>(),
SERVICE_WORKER_ERROR_FAILED, callback);
}
+ TRACE_EVENT_INSTANT1(
+ "ServiceWorker",
+ "ServiceWorkerStorage::FindRegistrationForDocument:LazyInitialize",
+ TRACE_EVENT_SCOPE_THREAD,
+ "URL", document_url.spec());
return;
}
DCHECK_EQ(INITIALIZED, state_);
@@ -129,15 +278,29 @@ void ServiceWorkerStorage::FindRegistrationForDocument(
// Look for something currently being installed.
scoped_refptr<ServiceWorkerRegistration> installing_registration =
FindInstallingRegistrationForDocument(document_url);
- CompleteFindNow(
- installing_registration,
- installing_registration ?
- SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND,
- callback);
+ ServiceWorkerStatusCode status = installing_registration.get() ?
+ SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND;
+ TRACE_EVENT_INSTANT2(
+ "ServiceWorker",
+ "ServiceWorkerStorage::FindRegistrationForDocument:CheckInstalling",
+ TRACE_EVENT_SCOPE_THREAD,
+ "URL", document_url.spec(),
+ "Status", ServiceWorkerStatusToString(status));
+ CompleteFindNow(installing_registration,
+ status,
+ callback);
return;
}
- database_task_runner_->PostTask(
+ // To connect this TRACE_EVENT with the callback, TimeTicks is used for
+ // callback id.
+ int64 callback_id = base::TimeTicks::Now().ToInternalValue();
+ TRACE_EVENT_ASYNC_BEGIN1(
+ "ServiceWorker",
+ "ServiceWorkerStorage::FindRegistrationForDocument",
+ callback_id,
+ "URL", document_url.spec());
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(
&FindForDocumentInDB,
@@ -145,7 +308,10 @@ void ServiceWorkerStorage::FindRegistrationForDocument(
base::MessageLoopProxy::current(),
document_url,
base::Bind(&ServiceWorkerStorage::DidFindRegistrationForDocument,
- weak_factory_.GetWeakPtr(), document_url, callback)));
+ weak_factory_.GetWeakPtr(),
+ document_url,
+ callback,
+ callback_id)));
}
void ServiceWorkerStorage::FindRegistrationForPattern(
@@ -167,15 +333,16 @@ void ServiceWorkerStorage::FindRegistrationForPattern(
// Look for something currently being installed.
scoped_refptr<ServiceWorkerRegistration> installing_registration =
FindInstallingRegistrationForPattern(scope);
- CompleteFindSoon(
- FROM_HERE, installing_registration,
- installing_registration ?
- SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND,
- callback);
+ CompleteFindSoon(FROM_HERE,
+ installing_registration,
+ installing_registration.get()
+ ? SERVICE_WORKER_OK
+ : SERVICE_WORKER_ERROR_NOT_FOUND,
+ callback);
return;
}
- database_task_runner_->PostTask(
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(
&FindForPatternInDB,
@@ -186,6 +353,22 @@ void ServiceWorkerStorage::FindRegistrationForPattern(
weak_factory_.GetWeakPtr(), scope, callback)));
}
+ServiceWorkerRegistration* ServiceWorkerStorage::GetUninstallingRegistration(
+ const GURL& scope) {
+ if (state_ != INITIALIZED || !context_)
+ return NULL;
+ for (RegistrationRefsById::const_iterator it =
+ uninstalling_registrations_.begin();
+ it != uninstalling_registrations_.end();
+ ++it) {
+ if (it->second->pattern() == scope) {
+ DCHECK(it->second->is_uninstalling());
+ return it->second.get();
+ }
+ }
+ return NULL;
+}
+
void ServiceWorkerStorage::FindRegistrationForId(
int64 registration_id,
const GURL& origin,
@@ -206,22 +389,22 @@ void ServiceWorkerStorage::FindRegistrationForId(
// Look for something currently being installed.
scoped_refptr<ServiceWorkerRegistration> installing_registration =
FindInstallingRegistrationForId(registration_id);
- CompleteFindNow(
- installing_registration,
- installing_registration ?
- SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND,
- callback);
+ CompleteFindNow(installing_registration,
+ installing_registration.get()
+ ? SERVICE_WORKER_OK
+ : SERVICE_WORKER_ERROR_NOT_FOUND,
+ callback);
return;
}
scoped_refptr<ServiceWorkerRegistration> registration =
context_->GetLiveRegistration(registration_id);
- if (registration) {
+ if (registration.get()) {
CompleteFindNow(registration, SERVICE_WORKER_OK, callback);
return;
}
- database_task_runner_->PostTask(
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&FindForIdInDB,
database_.get(),
@@ -246,7 +429,7 @@ void ServiceWorkerStorage::GetAllRegistrations(
RegistrationList* registrations = new RegistrationList;
PostTaskAndReplyWithResult(
- database_task_runner_,
+ database_task_manager_->GetTaskRunner(),
FROM_HERE,
base::Bind(&ServiceWorkerDatabase::GetAllRegistrations,
base::Unretained(database_.get()),
@@ -264,8 +447,8 @@ void ServiceWorkerStorage::StoreRegistration(
DCHECK(registration);
DCHECK(version);
- DCHECK(state_ == INITIALIZED || state_ == DISABLED);
- if (state_ != INITIALIZED || !context_) {
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_;
+ if (IsDisabled() || !context_) {
RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
return;
}
@@ -273,24 +456,37 @@ void ServiceWorkerStorage::StoreRegistration(
ServiceWorkerDatabase::RegistrationData data;
data.registration_id = registration->id();
data.scope = registration->pattern();
- data.script = registration->script_url();
+ data.script = version->script_url();
data.has_fetch_handler = true;
data.version_id = version->version_id();
- data.last_update_check = base::Time::Now();
- data.is_active = false; // initially stored in the waiting state
+ data.last_update_check = registration->last_update_check();
+ data.is_active = (version == registration->active_version());
ResourceList resources;
version->script_cache_map()->GetResources(&resources);
- database_task_runner_->PostTask(
+ uint64 resources_total_size_bytes = 0;
+ for (const auto& resource : resources) {
+ resources_total_size_bytes += resource.size_bytes;
+ }
+ data.resources_total_size_bytes = resources_total_size_bytes;
+
+ if (!has_checked_for_stale_resources_)
+ DeleteStaleResources();
+
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&WriteRegistrationInDB,
database_.get(),
base::MessageLoopProxy::current(),
- data, resources,
+ data,
+ resources,
base::Bind(&ServiceWorkerStorage::DidStoreRegistration,
weak_factory_.GetWeakPtr(),
- callback)));
+ callback,
+ data)));
+
+ registration->set_is_deleted(false);
}
void ServiceWorkerStorage::UpdateToActiveState(
@@ -298,47 +494,75 @@ void ServiceWorkerStorage::UpdateToActiveState(
const StatusCallback& callback) {
DCHECK(registration);
- DCHECK(state_ == INITIALIZED || state_ == DISABLED);
- if (state_ != INITIALIZED || !context_) {
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_;
+ if (IsDisabled() || !context_) {
RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
return;
}
PostTaskAndReplyWithResult(
- database_task_runner_,
+ database_task_manager_->GetTaskRunner(),
FROM_HERE,
base::Bind(&ServiceWorkerDatabase::UpdateVersionToActive,
base::Unretained(database_.get()),
registration->id(),
- registration->script_url().GetOrigin()),
+ registration->pattern().GetOrigin()),
base::Bind(&ServiceWorkerStorage::DidUpdateToActiveState,
weak_factory_.GetWeakPtr(),
callback));
}
+void ServiceWorkerStorage::UpdateLastUpdateCheckTime(
+ ServiceWorkerRegistration* registration) {
+ DCHECK(registration);
+
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_;
+ if (IsDisabled() || !context_)
+ return;
+
+ database_task_manager_->GetTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ base::IgnoreResult(&ServiceWorkerDatabase::UpdateLastCheckTime),
+ base::Unretained(database_.get()),
+ registration->id(),
+ registration->pattern().GetOrigin(),
+ registration->last_update_check()));
+}
+
void ServiceWorkerStorage::DeleteRegistration(
int64 registration_id,
const GURL& origin,
const StatusCallback& callback) {
- DCHECK(state_ == INITIALIZED || state_ == DISABLED);
- if (state_ != INITIALIZED || !context_) {
+ DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_;
+ if (IsDisabled() || !context_) {
RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
return;
}
- database_task_runner_->PostTask(
+ if (!has_checked_for_stale_resources_)
+ DeleteStaleResources();
+
+ DidDeleteRegistrationParams params;
+ params.registration_id = registration_id;
+ params.origin = origin;
+ params.callback = callback;
+
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&DeleteRegistrationFromDB,
database_.get(),
base::MessageLoopProxy::current(),
registration_id, origin,
base::Bind(&ServiceWorkerStorage::DidDeleteRegistration,
- weak_factory_.GetWeakPtr(), origin, callback)));
+ weak_factory_.GetWeakPtr(), params)));
- // TODO(michaeln): Either its instance should also be
- // removed from liveregistrations map or the live object
- // should marked as deleted in some way and not 'findable'
- // thereafter.
+ // The registration should no longer be findable.
+ pending_deletions_.insert(registration_id);
+ ServiceWorkerRegistration* registration =
+ context_->GetLiveRegistration(registration_id);
+ if (registration)
+ registration->set_is_deleted(true);
}
scoped_ptr<ServiceWorkerResponseReader>
@@ -353,9 +577,14 @@ ServiceWorkerStorage::CreateResponseWriter(int64 response_id) {
new ServiceWorkerResponseWriter(response_id, disk_cache()));
}
-void ServiceWorkerStorage::StoreUncommittedReponseId(int64 id) {
+void ServiceWorkerStorage::StoreUncommittedResponseId(int64 id) {
DCHECK_NE(kInvalidServiceWorkerResponseId, id);
- database_task_runner_->PostTask(
+ DCHECK_EQ(INITIALIZED, state_);
+
+ if (!has_checked_for_stale_resources_)
+ DeleteStaleResources();
+
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(base::IgnoreResult(
&ServiceWorkerDatabase::WriteUncommittedResourceIds),
@@ -365,7 +594,7 @@ void ServiceWorkerStorage::StoreUncommittedReponseId(int64 id) {
void ServiceWorkerStorage::DoomUncommittedResponse(int64 id) {
DCHECK_NE(kInvalidServiceWorkerResponseId, id);
- database_task_runner_->PostTask(
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(base::IgnoreResult(
&ServiceWorkerDatabase::PurgeUncommittedResourceIds),
@@ -374,6 +603,32 @@ void ServiceWorkerStorage::DoomUncommittedResponse(int64 id) {
StartPurgingResources(std::vector<int64>(1, id));
}
+void ServiceWorkerStorage::CompareScriptResources(
+ int64 lhs_id, int64 rhs_id,
+ const CompareCallback& callback) {
+ DCHECK(!callback.is_null());
+ scoped_refptr<ResponseComparer> comparer =
+ new ResponseComparer(weak_factory_.GetWeakPtr(),
+ CreateResponseReader(lhs_id),
+ CreateResponseReader(rhs_id),
+ callback);
+ comparer->Start(); // It deletes itself when done.
+}
+
+void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback& callback) {
+ Disable();
+
+ // Delete the database on the database thread.
+ PostTaskAndReplyWithResult(
+ database_task_manager_->GetTaskRunner(),
+ FROM_HERE,
+ base::Bind(&ServiceWorkerDatabase::DestroyDatabase,
+ base::Unretained(database_.get())),
+ base::Bind(&ServiceWorkerStorage::DidDeleteDatabase,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
int64 ServiceWorkerStorage::NewRegistrationId() {
if (state_ == DISABLED)
return kInvalidServiceWorkerRegistrationId;
@@ -397,6 +652,8 @@ int64 ServiceWorkerStorage::NewResourceId() {
void ServiceWorkerStorage::NotifyInstallingRegistration(
ServiceWorkerRegistration* registration) {
+ DCHECK(installing_registrations_.find(registration->id()) ==
+ installing_registrations_.end());
installing_registrations_[registration->id()] = registration;
}
@@ -413,27 +670,78 @@ void ServiceWorkerStorage::NotifyDoneInstallingRegistration(
for (size_t i = 0; i < resources.size(); ++i)
ids.insert(resources[i].resource_id);
- database_task_runner_->PostTask(
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(base::IgnoreResult(
&ServiceWorkerDatabase::PurgeUncommittedResourceIds),
base::Unretained(database_.get()),
ids));
-
- StartPurgingResources(resources);
}
}
+void ServiceWorkerStorage::NotifyUninstallingRegistration(
+ ServiceWorkerRegistration* registration) {
+ DCHECK(uninstalling_registrations_.find(registration->id()) ==
+ uninstalling_registrations_.end());
+ uninstalling_registrations_[registration->id()] = registration;
+}
+
+void ServiceWorkerStorage::NotifyDoneUninstallingRegistration(
+ ServiceWorkerRegistration* registration) {
+ uninstalling_registrations_.erase(registration->id());
+}
+
+void ServiceWorkerStorage::Disable() {
+ state_ = DISABLED;
+ if (disk_cache_)
+ disk_cache_->Disable();
+}
+
+bool ServiceWorkerStorage::IsDisabled() const {
+ return state_ == DISABLED;
+}
+
+void ServiceWorkerStorage::PurgeResources(const ResourceList& resources) {
+ if (!has_checked_for_stale_resources_)
+ DeleteStaleResources();
+ StartPurgingResources(resources);
+}
+
+ServiceWorkerStorage::ServiceWorkerStorage(
+ const base::FilePath& path,
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy)
+ : next_registration_id_(kInvalidServiceWorkerRegistrationId),
+ next_version_id_(kInvalidServiceWorkerVersionId),
+ next_resource_id_(kInvalidServiceWorkerResourceId),
+ state_(UNINITIALIZED),
+ path_(path),
+ context_(context),
+ database_task_manager_(database_task_manager.Pass()),
+ disk_cache_thread_(disk_cache_thread),
+ quota_manager_proxy_(quota_manager_proxy),
+ special_storage_policy_(special_storage_policy),
+ is_purge_pending_(false),
+ has_checked_for_stale_resources_(false),
+ weak_factory_(this) {
+ database_.reset(new ServiceWorkerDatabase(GetDatabasePath()));
+}
+
base::FilePath ServiceWorkerStorage::GetDatabasePath() {
if (path_.empty())
return base::FilePath();
- return path_.Append(kDatabaseName);
+ return path_.Append(ServiceWorkerContextCore::kServiceWorkerDirectory)
+ .Append(kDatabaseName);
}
base::FilePath ServiceWorkerStorage::GetDiskCachePath() {
if (path_.empty())
return base::FilePath();
- return path_.Append(kDiskCacheName);
+ return path_.Append(ServiceWorkerContextCore::kServiceWorkerDirectory)
+ .Append(kDiskCacheName);
}
bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) {
@@ -454,7 +762,7 @@ bool ServiceWorkerStorage::LazyInitialize(const base::Closure& callback) {
}
state_ = INITIALIZING;
- database_task_runner_->PostTask(
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ReadInitialDataFromDB,
database_.get(),
@@ -477,10 +785,9 @@ void ServiceWorkerStorage::DidReadInitialData(
registered_origins_.swap(data->origins);
state_ = INITIALIZED;
} else {
- // TODO(nhiroki): If status==STATUS_ERROR_CORRUPTED, do corruption recovery
- // (http://crbug.com/371675).
- DLOG(WARNING) << "Failed to initialize: " << status;
- state_ = DISABLED;
+ DVLOG(2) << "Failed to initialize: "
+ << ServiceWorkerDatabase::StatusToString(status);
+ ScheduleDeleteAndStartOver();
}
for (std::vector<base::Closure>::const_iterator it = pending_tasks_.begin();
@@ -493,11 +800,17 @@ void ServiceWorkerStorage::DidReadInitialData(
void ServiceWorkerStorage::DidFindRegistrationForDocument(
const GURL& document_url,
const FindRegistrationCallback& callback,
+ int64 callback_id,
const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources,
ServiceWorkerDatabase::Status status) {
if (status == ServiceWorkerDatabase::STATUS_OK) {
- callback.Run(SERVICE_WORKER_OK, GetOrCreateRegistration(data, resources));
+ ReturnFoundRegistration(callback, data, resources);
+ TRACE_EVENT_ASYNC_END1(
+ "ServiceWorker",
+ "ServiceWorkerStorage::FindRegistrationForDocument",
+ callback_id,
+ "Status", ServiceWorkerDatabase::StatusToString(status));
return;
}
@@ -505,15 +818,29 @@ void ServiceWorkerStorage::DidFindRegistrationForDocument(
// Look for something currently being installed.
scoped_refptr<ServiceWorkerRegistration> installing_registration =
FindInstallingRegistrationForDocument(document_url);
- callback.Run(installing_registration ?
- SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND,
- installing_registration);
+ ServiceWorkerStatusCode installing_status = installing_registration.get() ?
+ SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND;
+ callback.Run(installing_status, installing_registration);
+ TRACE_EVENT_ASYNC_END2(
+ "ServiceWorker",
+ "ServiceWorkerStorage::FindRegistrationForDocument",
+ callback_id,
+ "Status", ServiceWorkerDatabase::StatusToString(status),
+ "Info",
+ (installing_status == SERVICE_WORKER_OK) ?
+ "Installing registration is found" :
+ "Any registrations are not found");
return;
}
- // TODO(nhiroki): Handle database error (http://crbug.com/371675).
+ ScheduleDeleteAndStartOver();
callback.Run(DatabaseStatusToStatusCode(status),
scoped_refptr<ServiceWorkerRegistration>());
+ TRACE_EVENT_ASYNC_END1(
+ "ServiceWorker",
+ "ServiceWorkerStorage::FindRegistrationForDocument",
+ callback_id,
+ "Status", ServiceWorkerDatabase::StatusToString(status));
}
void ServiceWorkerStorage::DidFindRegistrationForPattern(
@@ -523,20 +850,20 @@ void ServiceWorkerStorage::DidFindRegistrationForPattern(
const ResourceList& resources,
ServiceWorkerDatabase::Status status) {
if (status == ServiceWorkerDatabase::STATUS_OK) {
- callback.Run(SERVICE_WORKER_OK, GetOrCreateRegistration(data, resources));
+ ReturnFoundRegistration(callback, data, resources);
return;
}
if (status == ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
scoped_refptr<ServiceWorkerRegistration> installing_registration =
FindInstallingRegistrationForPattern(scope);
- callback.Run(installing_registration ?
- SERVICE_WORKER_OK : SERVICE_WORKER_ERROR_NOT_FOUND,
- installing_registration);
+ callback.Run(installing_registration.get() ? SERVICE_WORKER_OK
+ : SERVICE_WORKER_ERROR_NOT_FOUND,
+ installing_registration);
return;
}
- // TODO(nhiroki): Handle database error (http://crbug.com/371675).
+ ScheduleDeleteAndStartOver();
callback.Run(DatabaseStatusToStatusCode(status),
scoped_refptr<ServiceWorkerRegistration>());
}
@@ -547,22 +874,44 @@ void ServiceWorkerStorage::DidFindRegistrationForId(
const ResourceList& resources,
ServiceWorkerDatabase::Status status) {
if (status == ServiceWorkerDatabase::STATUS_OK) {
- callback.Run(SERVICE_WORKER_OK,
- GetOrCreateRegistration(data, resources));
+ ReturnFoundRegistration(callback, data, resources);
return;
}
- // TODO(nhiroki): Handle database error (http://crbug.com/371675).
+
+ if (status == ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
+ // TODO(nhiroki): Find a registration in |installing_registrations_|.
+ callback.Run(DatabaseStatusToStatusCode(status),
+ scoped_refptr<ServiceWorkerRegistration>());
+ return;
+ }
+
+ ScheduleDeleteAndStartOver();
callback.Run(DatabaseStatusToStatusCode(status),
scoped_refptr<ServiceWorkerRegistration>());
}
+void ServiceWorkerStorage::ReturnFoundRegistration(
+ const FindRegistrationCallback& callback,
+ const ServiceWorkerDatabase::RegistrationData& data,
+ const ResourceList& resources) {
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ GetOrCreateRegistration(data, resources);
+ if (registration->is_deleted()) {
+ // It's past the point of no return and no longer findable.
+ callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND, NULL);
+ return;
+ }
+ callback.Run(SERVICE_WORKER_OK, registration);
+}
+
void ServiceWorkerStorage::DidGetAllRegistrations(
const GetAllRegistrationInfosCallback& callback,
RegistrationList* registrations,
ServiceWorkerDatabase::Status status) {
DCHECK(registrations);
- if (status != ServiceWorkerDatabase::STATUS_OK) {
- // TODO(nhiroki): Handle database error (http://crbug.com/371675).
+ if (status != ServiceWorkerDatabase::STATUS_OK &&
+ status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
+ ScheduleDeleteAndStartOver();
callback.Run(std::vector<ServiceWorkerRegistrationInfo>());
return;
}
@@ -570,26 +919,26 @@ void ServiceWorkerStorage::DidGetAllRegistrations(
// Add all stored registrations.
std::set<int64> pushed_registrations;
std::vector<ServiceWorkerRegistrationInfo> infos;
- for (RegistrationList::const_iterator it = registrations->begin();
- it != registrations->end(); ++it) {
+ for (const auto& registration_data : *registrations) {
const bool inserted =
- pushed_registrations.insert(it->registration_id).second;
+ pushed_registrations.insert(registration_data.registration_id).second;
DCHECK(inserted);
ServiceWorkerRegistration* registration =
- context_->GetLiveRegistration(it->registration_id);
+ context_->GetLiveRegistration(registration_data.registration_id);
if (registration) {
infos.push_back(registration->GetInfo());
continue;
}
ServiceWorkerRegistrationInfo info;
- info.pattern = it->scope;
- info.script_url = it->script;
- info.registration_id = it->registration_id;
+ info.pattern = registration_data.scope;
+ info.registration_id = registration_data.registration_id;
+ info.stored_version_size_bytes =
+ registration_data.resources_total_size_bytes;
if (ServiceWorkerVersion* version =
- context_->GetLiveVersion(it->version_id)) {
- if (it->is_active)
+ context_->GetLiveVersion(registration_data.version_id)) {
+ if (registration_data.is_active)
info.active_version = version->GetInfo();
else
info.waiting_version = version->GetInfo();
@@ -597,14 +946,12 @@ void ServiceWorkerStorage::DidGetAllRegistrations(
continue;
}
- if (it->is_active) {
- info.active_version.is_null = false;
- info.active_version.status = ServiceWorkerVersion::ACTIVE;
- info.active_version.version_id = it->version_id;
+ if (registration_data.is_active) {
+ info.active_version.status = ServiceWorkerVersion::ACTIVATED;
+ info.active_version.version_id = registration_data.version_id;
} else {
- info.waiting_version.is_null = false;
info.waiting_version.status = ServiceWorkerVersion::INSTALLED;
- info.waiting_version.version_id = it->version_id;
+ info.waiting_version.version_id = registration_data.version_id;
}
infos.push_back(info);
}
@@ -622,41 +969,74 @@ void ServiceWorkerStorage::DidGetAllRegistrations(
void ServiceWorkerStorage::DidStoreRegistration(
const StatusCallback& callback,
+ const ServiceWorkerDatabase::RegistrationData& new_version,
const GURL& origin,
+ const ServiceWorkerDatabase::RegistrationData& deleted_version,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status) {
if (status != ServiceWorkerDatabase::STATUS_OK) {
- // TODO(nhiroki): Handle database error (http://crbug.com/371675).
+ ScheduleDeleteAndStartOver();
callback.Run(DatabaseStatusToStatusCode(status));
return;
}
registered_origins_.insert(origin);
+
+ scoped_refptr<ServiceWorkerRegistration> registration =
+ context_->GetLiveRegistration(new_version.registration_id);
+ registration->set_resources_total_size_bytes(
+ new_version.resources_total_size_bytes);
+ if (quota_manager_proxy_.get()) {
+ // Can be nullptr in tests.
+ quota_manager_proxy_->NotifyStorageModified(
+ storage::QuotaClient::kServiceWorker,
+ origin,
+ storage::StorageType::kStorageTypeTemporary,
+ new_version.resources_total_size_bytes -
+ deleted_version.resources_total_size_bytes);
+ }
+
callback.Run(SERVICE_WORKER_OK);
- StartPurgingResources(newly_purgeable_resources);
+
+ if (!context_ || !context_->GetLiveVersion(deleted_version.version_id))
+ StartPurgingResources(newly_purgeable_resources);
}
void ServiceWorkerStorage::DidUpdateToActiveState(
const StatusCallback& callback,
ServiceWorkerDatabase::Status status) {
- // TODO(nhiroki): Handle database error (http://crbug.com/371675).
+ if (status != ServiceWorkerDatabase::STATUS_OK &&
+ status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
+ ScheduleDeleteAndStartOver();
+ }
callback.Run(DatabaseStatusToStatusCode(status));
}
void ServiceWorkerStorage::DidDeleteRegistration(
- const GURL& origin,
- const StatusCallback& callback,
+ const DidDeleteRegistrationParams& params,
bool origin_is_deletable,
+ const ServiceWorkerDatabase::RegistrationData& deleted_version,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status) {
+ pending_deletions_.erase(params.registration_id);
if (status != ServiceWorkerDatabase::STATUS_OK) {
- // TODO(nhiroki): Handle database error (http://crbug.com/371675).
- callback.Run(DatabaseStatusToStatusCode(status));
+ ScheduleDeleteAndStartOver();
+ params.callback.Run(DatabaseStatusToStatusCode(status));
return;
}
+ if (quota_manager_proxy_.get()) {
+ // Can be nullptr in tests.
+ quota_manager_proxy_->NotifyStorageModified(
+ storage::QuotaClient::kServiceWorker,
+ params.origin,
+ storage::StorageType::kStorageTypeTemporary,
+ -deleted_version.resources_total_size_bytes);
+ }
if (origin_is_deletable)
- registered_origins_.erase(origin);
- callback.Run(SERVICE_WORKER_OK);
- StartPurgingResources(newly_purgeable_resources);
+ registered_origins_.erase(params.origin);
+ params.callback.Run(SERVICE_WORKER_OK);
+
+ if (!context_ || !context_->GetLiveVersion(deleted_version.version_id))
+ StartPurgingResources(newly_purgeable_resources);
}
scoped_refptr<ServiceWorkerRegistration>
@@ -665,28 +1045,34 @@ ServiceWorkerStorage::GetOrCreateRegistration(
const ResourceList& resources) {
scoped_refptr<ServiceWorkerRegistration> registration =
context_->GetLiveRegistration(data.registration_id);
- if (registration)
+ if (registration.get())
return registration;
registration = new ServiceWorkerRegistration(
- data.scope, data.script, data.registration_id, context_);
+ data.scope, data.registration_id, context_);
+ registration->set_resources_total_size_bytes(data.resources_total_size_bytes);
+ registration->set_last_update_check(data.last_update_check);
+ if (pending_deletions_.find(data.registration_id) !=
+ pending_deletions_.end()) {
+ registration->set_is_deleted(true);
+ }
scoped_refptr<ServiceWorkerVersion> version =
context_->GetLiveVersion(data.version_id);
- if (!version) {
- version = new ServiceWorkerVersion(registration, data.version_id, context_);
+ if (!version.get()) {
+ version = new ServiceWorkerVersion(
+ registration.get(), data.script, data.version_id, context_);
version->SetStatus(data.is_active ?
- ServiceWorkerVersion::ACTIVE : ServiceWorkerVersion::INSTALLED);
+ ServiceWorkerVersion::ACTIVATED : ServiceWorkerVersion::INSTALLED);
version->script_cache_map()->SetResources(resources);
}
- if (version->status() == ServiceWorkerVersion::ACTIVE)
- registration->set_active_version(version);
+ if (version->status() == ServiceWorkerVersion::ACTIVATED)
+ registration->SetActiveVersion(version.get());
else if (version->status() == ServiceWorkerVersion::INSTALLED)
- registration->set_waiting_version(version);
+ registration->SetWaitingVersion(version.get());
else
NOTREACHED();
- // TODO(michaeln): Hmmm, what if DeleteReg was invoked after
- // the Find result we're returning here? NOTREACHED condition?
+
return registration;
}
@@ -704,7 +1090,7 @@ ServiceWorkerStorage::FindInstallingRegistrationForDocument(
installing_registrations_.begin();
it != installing_registrations_.end(); ++it) {
if (matcher.MatchLongest(it->second->pattern()))
- match = it->second;
+ match = it->second.get();
}
return match;
}
@@ -716,7 +1102,7 @@ ServiceWorkerStorage::FindInstallingRegistrationForPattern(
installing_registrations_.begin();
it != installing_registrations_.end(); ++it) {
if (it->second->pattern() == scope)
- return it->second;
+ return it->second.get();
}
return NULL;
}
@@ -728,7 +1114,7 @@ ServiceWorkerStorage::FindInstallingRegistrationForId(
installing_registrations_.find(registration_id);
if (found == installing_registrations_.end())
return NULL;
- return found->second;
+ return found->second.get();
}
ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() {
@@ -739,16 +1125,17 @@ ServiceWorkerDiskCache* ServiceWorkerStorage::disk_cache() {
base::FilePath path = GetDiskCachePath();
if (path.empty()) {
- int rv = disk_cache_->InitWithMemBackend(
- kMaxMemDiskCacheSize,
- base::Bind(&EmptyCompletionCallback));
+ int rv = disk_cache_->InitWithMemBackend(kMaxMemDiskCacheSize,
+ net::CompletionCallback());
DCHECK_EQ(net::OK, rv);
return disk_cache_.get();
}
int rv = disk_cache_->InitWithDiskBackend(
- path, kMaxDiskCacheSize, false,
- disk_cache_thread_.get(),
+ path,
+ kMaxDiskCacheSize,
+ false,
+ disk_cache_thread_,
base::Bind(&ServiceWorkerStorage::OnDiskCacheInitialized,
weak_factory_.GetWeakPtr()));
if (rv != net::ERR_IO_PENDING)
@@ -761,36 +1148,36 @@ void ServiceWorkerStorage::OnDiskCacheInitialized(int rv) {
if (rv != net::OK) {
LOG(ERROR) << "Failed to open the serviceworker diskcache: "
<< net::ErrorToString(rv);
- // TODO(michaeln): DeleteAndStartOver()
- disk_cache_->Disable();
- state_ = DISABLED;
+ ScheduleDeleteAndStartOver();
}
- ServiceWorkerHistograms::CountInitDiskCacheResult(rv == net::OK);
+ ServiceWorkerMetrics::CountInitDiskCacheResult(rv == net::OK);
}
void ServiceWorkerStorage::StartPurgingResources(
const std::vector<int64>& ids) {
+ DCHECK(has_checked_for_stale_resources_);
for (size_t i = 0; i < ids.size(); ++i)
- purgeable_reource_ids_.push_back(ids[i]);
+ purgeable_resource_ids_.push_back(ids[i]);
ContinuePurgingResources();
}
void ServiceWorkerStorage::StartPurgingResources(
const ResourceList& resources) {
+ DCHECK(has_checked_for_stale_resources_);
for (size_t i = 0; i < resources.size(); ++i)
- purgeable_reource_ids_.push_back(resources[i].resource_id);
+ purgeable_resource_ids_.push_back(resources[i].resource_id);
ContinuePurgingResources();
}
void ServiceWorkerStorage::ContinuePurgingResources() {
- if (purgeable_reource_ids_.empty() || is_purge_pending_)
+ if (purgeable_resource_ids_.empty() || is_purge_pending_)
return;
// Do one at a time until we're done, use RunSoon to avoid recursion when
// DoomEntry returns immediately.
is_purge_pending_ = true;
- int64 id = purgeable_reource_ids_.front();
- purgeable_reource_ids_.pop_front();
+ int64 id = purgeable_resource_ids_.front();
+ purgeable_resource_ids_.pop_front();
RunSoon(FROM_HERE,
base::Bind(&ServiceWorkerStorage::PurgeResource,
weak_factory_.GetWeakPtr(), id));
@@ -809,7 +1196,7 @@ void ServiceWorkerStorage::OnResourcePurged(int64 id, int rv) {
DCHECK(is_purge_pending_);
is_purge_pending_ = false;
- database_task_runner_->PostTask(
+ database_task_manager_->GetTaskRunner()->PostTask(
FROM_HERE,
base::Bind(base::IgnoreResult(
&ServiceWorkerDatabase::ClearPurgeableResourceIds),
@@ -819,6 +1206,79 @@ void ServiceWorkerStorage::OnResourcePurged(int64 id, int rv) {
ContinuePurgingResources();
}
+void ServiceWorkerStorage::DeleteStaleResources() {
+ DCHECK(!has_checked_for_stale_resources_);
+ has_checked_for_stale_resources_ = true;
+ database_task_manager_->GetTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ServiceWorkerStorage::CollectStaleResourcesFromDB,
+ database_.get(),
+ base::MessageLoopProxy::current(),
+ base::Bind(&ServiceWorkerStorage::DidCollectStaleResources,
+ weak_factory_.GetWeakPtr())));
+}
+
+void ServiceWorkerStorage::DidCollectStaleResources(
+ const std::vector<int64>& stale_resource_ids,
+ ServiceWorkerDatabase::Status status) {
+ DCHECK_EQ(ServiceWorkerDatabase::STATUS_OK, status);
+ if (status != ServiceWorkerDatabase::STATUS_OK)
+ return;
+ StartPurgingResources(stale_resource_ids);
+}
+
+void ServiceWorkerStorage::ClearSessionOnlyOrigins() {
+ // Can be null in tests.
+ if (!special_storage_policy_.get())
+ return;
+
+ if (!special_storage_policy_->HasSessionOnlyOrigins())
+ return;
+
+ std::set<GURL> session_only_origins;
+ for (const GURL& origin : registered_origins_) {
+ if (special_storage_policy_->IsStorageSessionOnly(origin))
+ session_only_origins.insert(origin);
+ }
+
+ database_task_manager_->GetShutdownBlockingTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&DeleteAllDataForOriginsFromDB,
+ database_.get(),
+ session_only_origins));
+}
+
+void ServiceWorkerStorage::CollectStaleResourcesFromDB(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ const GetResourcesCallback& callback) {
+ std::set<int64> ids;
+ ServiceWorkerDatabase::Status status =
+ database->GetUncommittedResourceIds(&ids);
+ if (status != ServiceWorkerDatabase::STATUS_OK) {
+ original_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(
+ callback, std::vector<int64>(ids.begin(), ids.end()), status));
+ return;
+ }
+
+ status = database->PurgeUncommittedResourceIds(ids);
+ if (status != ServiceWorkerDatabase::STATUS_OK) {
+ original_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(
+ callback, std::vector<int64>(ids.begin(), ids.end()), status));
+ return;
+ }
+
+ ids.clear();
+ status = database->GetPurgeableResourceIds(&ids);
+ original_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(callback, std::vector<int64>(ids.begin(), ids.end()), status));
+}
+
void ServiceWorkerStorage::ReadInitialDataFromDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
@@ -850,13 +1310,15 @@ void ServiceWorkerStorage::DeleteRegistrationFromDB(
const DeleteRegistrationCallback& callback) {
DCHECK(database);
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
- ServiceWorkerDatabase::Status status =
- database->DeleteRegistration(registration_id, origin,
- &newly_purgeable_resources);
+ ServiceWorkerDatabase::Status status = database->DeleteRegistration(
+ registration_id, origin, &deleted_version, &newly_purgeable_resources);
if (status != ServiceWorkerDatabase::STATUS_OK) {
original_task_runner->PostTask(
- FROM_HERE, base::Bind(callback, false, std::vector<int64>(), status));
+ FROM_HERE,
+ base::Bind(
+ callback, false, deleted_version, std::vector<int64>(), status));
return;
}
@@ -866,14 +1328,19 @@ void ServiceWorkerStorage::DeleteRegistrationFromDB(
status = database->GetRegistrationsForOrigin(origin, &registrations);
if (status != ServiceWorkerDatabase::STATUS_OK) {
original_task_runner->PostTask(
- FROM_HERE, base::Bind(callback, false, std::vector<int64>(), status));
+ FROM_HERE,
+ base::Bind(
+ callback, false, deleted_version, std::vector<int64>(), status));
return;
}
bool deletable = registrations.empty();
- original_task_runner->PostTask(
- FROM_HERE, base::Bind(callback, deletable,
- newly_purgeable_resources, status));
+ original_task_runner->PostTask(FROM_HERE,
+ base::Bind(callback,
+ deletable,
+ deleted_version,
+ newly_purgeable_resources,
+ status));
}
void ServiceWorkerStorage::WriteRegistrationInDB(
@@ -883,13 +1350,16 @@ void ServiceWorkerStorage::WriteRegistrationInDB(
const ResourceList& resources,
const WriteRegistrationCallback& callback) {
DCHECK(database);
+ ServiceWorkerDatabase::RegistrationData deleted_version;
std::vector<int64> newly_purgeable_resources;
- ServiceWorkerDatabase::Status status =
- database->WriteRegistration(data, resources, &newly_purgeable_resources);
- original_task_runner->PostTask(
- FROM_HERE,
- base::Bind(callback, data.script.GetOrigin(),
- newly_purgeable_resources, status));
+ ServiceWorkerDatabase::Status status = database->WriteRegistration(
+ data, resources, &deleted_version, &newly_purgeable_resources);
+ original_task_runner->PostTask(FROM_HERE,
+ base::Bind(callback,
+ data.script.GetOrigin(),
+ deleted_version,
+ newly_purgeable_resources,
+ status));
}
void ServiceWorkerStorage::FindForDocumentInDB(
@@ -982,4 +1452,69 @@ void ServiceWorkerStorage::FindForIdInDB(
FROM_HERE, base::Bind(callback, data, resources, status));
}
+void ServiceWorkerStorage::DeleteAllDataForOriginsFromDB(
+ ServiceWorkerDatabase* database,
+ const std::set<GURL>& origins) {
+ DCHECK(database);
+
+ std::vector<int64> newly_purgeable_resources;
+ database->DeleteAllDataForOrigins(origins, &newly_purgeable_resources);
+}
+
+// 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
+// controls it instead.
+void ServiceWorkerStorage::ScheduleDeleteAndStartOver() {
+ // TODO(dmurph): Notify the quota manager somehow that all of our data is now
+ // removed.
+ if (state_ == DISABLED) {
+ // Recovery process has already been scheduled.
+ return;
+ }
+ Disable();
+
+ DVLOG(1) << "Schedule to delete the context and start over.";
+ context_->ScheduleDeleteAndStartOver();
+}
+
+void ServiceWorkerStorage::DidDeleteDatabase(
+ const StatusCallback& callback,
+ ServiceWorkerDatabase::Status status) {
+ DCHECK_EQ(DISABLED, state_);
+ if (status != ServiceWorkerDatabase::STATUS_OK) {
+ // Give up the corruption recovery until the browser restarts.
+ LOG(ERROR) << "Failed to delete the database: "
+ << ServiceWorkerDatabase::StatusToString(status);
+ callback.Run(DatabaseStatusToStatusCode(status));
+ return;
+ }
+ DVLOG(1) << "Deleted ServiceWorkerDatabase successfully.";
+
+ // Delete the disk cache on the cache thread.
+ // TODO(nhiroki): What if there is a bunch of files in the cache directory?
+ // Deleting the directory could take a long time and restart could be delayed.
+ // We should probably rename the directory and delete it later.
+ PostTaskAndReplyWithResult(
+ database_task_manager_->GetTaskRunner(),
+ FROM_HERE,
+ base::Bind(&base::DeleteFile, GetDiskCachePath(), true),
+ base::Bind(&ServiceWorkerStorage::DidDeleteDiskCache,
+ weak_factory_.GetWeakPtr(),
+ callback));
+}
+
+void ServiceWorkerStorage::DidDeleteDiskCache(
+ const StatusCallback& callback, bool result) {
+ DCHECK_EQ(DISABLED, state_);
+ if (!result) {
+ // Give up the corruption recovery until the browser restarts.
+ LOG(ERROR) << "Failed to delete the diskcache.";
+ callback.Run(SERVICE_WORKER_ERROR_FAILED);
+ return;
+ }
+ DVLOG(1) << "Deleted ServiceWorkerDiskCache successfully.";
+ callback.Run(SERVICE_WORKER_OK);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_storage.h b/chromium/content/browser/service_worker/service_worker_storage.h
index 5d89864dc21..0eda8bf540e 100644
--- a/chromium/content/browser/service_worker/service_worker_storage.h
+++ b/chromium/content/browser/service_worker/service_worker_storage.h
@@ -16,17 +16,20 @@
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_database.h"
+#include "content/browser/service_worker/service_worker_database_task_manager.h"
+#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "url/gurl.h"
namespace base {
-class MessageLoopProxy;
class SequencedTaskRunner;
+class SingleThreadTaskRunner;
}
-namespace quota {
+namespace storage {
class QuotaManagerProxy;
+class SpecialStoragePolicy;
}
namespace content {
@@ -37,11 +40,11 @@ class ServiceWorkerRegistration;
class ServiceWorkerRegistrationInfo;
class ServiceWorkerResponseReader;
class ServiceWorkerResponseWriter;
-class ServiceWorkerVersion;
// This class provides an interface to store and retrieve ServiceWorker
// registration data.
-class CONTENT_EXPORT ServiceWorkerStorage {
+class CONTENT_EXPORT ServiceWorkerStorage
+ : NON_EXPORTED_BASE(public ServiceWorkerVersion::Listener) {
public:
typedef std::vector<ServiceWorkerDatabase::ResourceRecord> ResourceList;
typedef base::Callback<void(ServiceWorkerStatusCode status)> StatusCallback;
@@ -52,15 +55,23 @@ class CONTENT_EXPORT ServiceWorkerStorage {
void(const std::vector<ServiceWorkerRegistrationInfo>& registrations)>
GetAllRegistrationInfosCallback;
typedef base::Callback<
- void(ServiceWorkerStatusCode status, int result)>
+ void(ServiceWorkerStatusCode status, bool are_equal)>
CompareCallback;
- ServiceWorkerStorage(const base::FilePath& path,
- base::WeakPtr<ServiceWorkerContextCore> context,
- base::SequencedTaskRunner* database_task_runner,
- base::MessageLoopProxy* disk_cache_thread,
- quota::QuotaManagerProxy* quota_manager_proxy);
- ~ServiceWorkerStorage();
+ ~ServiceWorkerStorage() override;
+
+ static scoped_ptr<ServiceWorkerStorage> Create(
+ const base::FilePath& path,
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy);
+
+ // Used for DeleteAndStartOver. Creates new storage based on |old_storage|.
+ static scoped_ptr<ServiceWorkerStorage> Create(
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ ServiceWorkerStorage* old_storage);
// Finds registration for |document_url| or |pattern| or |registration_id|.
// The Find methods will find stored and initially installing registrations.
@@ -79,27 +90,31 @@ class CONTENT_EXPORT ServiceWorkerStorage {
const GURL& origin,
const FindRegistrationCallback& callback);
+ ServiceWorkerRegistration* GetUninstallingRegistration(const GURL& scope);
+
// Returns info about all stored and initially installing registrations.
void GetAllRegistrations(const GetAllRegistrationInfosCallback& callback);
// Commits |registration| with the installed but not activated |version|
// to storage, overwritting any pre-existing registration data for the scope.
- // A pre-existing version's script resources will remain available until
- // either a browser restart or DeleteVersionResources is called.
- void StoreRegistration(
- ServiceWorkerRegistration* registration,
- ServiceWorkerVersion* version,
- const StatusCallback& callback);
+ // A pre-existing version's script resources remain available if that version
+ // is live. PurgeResources should be called when it's OK to delete them.
+ void StoreRegistration(ServiceWorkerRegistration* registration,
+ ServiceWorkerVersion* version,
+ const StatusCallback& callback);
// Updates the state of the registration's stored version to active.
void UpdateToActiveState(
ServiceWorkerRegistration* registration,
const StatusCallback& callback);
- // Deletes the registration data for |registration_id|, the
- // script resources for the registration's stored version
- // will remain available until either a browser restart or
- // DeleteVersionResources is called.
+ // Updates the stored time to match the value of
+ // registration->last_update_check().
+ void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration);
+
+ // Deletes the registration data for |registration_id|. If the registration's
+ // version is live, its script resources will remain available.
+ // PurgeResources should be called when it's OK to delete them.
void DeleteRegistration(int64 registration_id,
const GURL& origin,
const StatusCallback& callback);
@@ -111,29 +126,60 @@ class CONTENT_EXPORT ServiceWorkerStorage {
// Adds |id| to the set of resources ids that are in the disk
// cache but not yet stored with a registration.
- void StoreUncommittedReponseId(int64 id);
+ void StoreUncommittedResponseId(int64 id);
// Removes |id| from uncommitted list, adds it to the
// purgeable list and purges it.
void DoomUncommittedResponse(int64 id);
+ // Compares only the response bodies.
+ void CompareScriptResources(int64 lhs_id, int64 rhs_id,
+ const CompareCallback& callback);
+
+ // Deletes the storage and starts over.
+ void DeleteAndStartOver(const StatusCallback& callback);
+
// Returns new IDs which are guaranteed to be unique in the storage.
int64 NewRegistrationId();
int64 NewVersionId();
int64 NewResourceId();
- // Intended for use only by ServiceWorkerRegisterJob.
+ // Intended for use only by ServiceWorkerRegisterJob and
+ // ServiceWorkerRegistration.
void NotifyInstallingRegistration(
ServiceWorkerRegistration* registration);
void NotifyDoneInstallingRegistration(
ServiceWorkerRegistration* registration,
ServiceWorkerVersion* version,
ServiceWorkerStatusCode status);
+ void NotifyUninstallingRegistration(ServiceWorkerRegistration* registration);
+ void NotifyDoneUninstallingRegistration(
+ ServiceWorkerRegistration* registration);
+
+ void Disable();
+ bool IsDisabled() const;
+
+ // |resources| must already be on the purgeable list.
+ void PurgeResources(const ResourceList& resources);
private:
- friend class ServiceWorkerStorageTest;
- FRIEND_TEST_ALL_PREFIXES(ServiceWorkerStorageTest,
- ResourceIdsAreStoredAndPurged);
+ friend class ServiceWorkerResourceStorageTest;
+ friend class ServiceWorkerControlleeRequestHandlerTest;
+ friend class ServiceWorkerContextRequestHandlerTest;
+ friend class ServiceWorkerRequestHandlerTest;
+ friend class ServiceWorkerWriteToCacheJobTest;
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
+ DeleteRegistration_NoLiveVersion);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
+ DeleteRegistration_WaitingVersion);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
+ DeleteRegistration_ActiveVersion);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageTest,
+ UpdateRegistration);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageDiskTest,
+ CleanupOnRestart);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerResourceStorageDiskTest,
+ ClearOnExit);
struct InitialData {
int64 next_registration_id;
@@ -145,6 +191,16 @@ class CONTENT_EXPORT ServiceWorkerStorage {
~InitialData();
};
+ // Because there are too many params for base::Bind to wrap a closure around.
+ struct DidDeleteRegistrationParams {
+ int64 registration_id;
+ GURL origin;
+ StatusCallback callback;
+
+ DidDeleteRegistrationParams();
+ ~DidDeleteRegistrationParams();
+ };
+
typedef std::vector<ServiceWorkerDatabase::RegistrationData> RegistrationList;
typedef std::map<int64, scoped_refptr<ServiceWorkerRegistration> >
RegistrationRefsById;
@@ -153,16 +209,29 @@ class CONTENT_EXPORT ServiceWorkerStorage {
ServiceWorkerDatabase::Status status)> InitializeCallback;
typedef base::Callback<void(
const GURL& origin,
+ const ServiceWorkerDatabase::RegistrationData& deleted_version_data,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status)> WriteRegistrationCallback;
typedef base::Callback<void(
bool origin_is_deletable,
+ const ServiceWorkerDatabase::RegistrationData& deleted_version_data,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status)> DeleteRegistrationCallback;
typedef base::Callback<void(
const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources,
ServiceWorkerDatabase::Status status)> FindInDBCallback;
+ typedef base::Callback<void(const std::vector<int64>& resource_ids,
+ ServiceWorkerDatabase::Status status)>
+ GetResourcesCallback;
+
+ ServiceWorkerStorage(
+ const base::FilePath& path,
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
+ storage::QuotaManagerProxy* quota_manager_proxy,
+ storage::SpecialStoragePolicy* special_storage_policy);
base::FilePath GetDatabasePath();
base::FilePath GetDiskCachePath();
@@ -175,6 +244,7 @@ class CONTENT_EXPORT ServiceWorkerStorage {
void DidFindRegistrationForDocument(
const GURL& document_url,
const FindRegistrationCallback& callback,
+ int64 callback_id,
const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources,
ServiceWorkerDatabase::Status status);
@@ -195,18 +265,24 @@ class CONTENT_EXPORT ServiceWorkerStorage {
ServiceWorkerDatabase::Status status);
void DidStoreRegistration(
const StatusCallback& callback,
+ const ServiceWorkerDatabase::RegistrationData& new_version,
const GURL& origin,
+ const ServiceWorkerDatabase::RegistrationData& deleted_version,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status);
void DidUpdateToActiveState(
const StatusCallback& callback,
ServiceWorkerDatabase::Status status);
void DidDeleteRegistration(
- const GURL& origin,
- const StatusCallback& callback,
+ const DidDeleteRegistrationParams& params,
bool origin_is_deletable,
+ const ServiceWorkerDatabase::RegistrationData& deleted_version,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status);
+ void ReturnFoundRegistration(
+ const FindRegistrationCallback& callback,
+ const ServiceWorkerDatabase::RegistrationData& data,
+ const ResourceList& resources);
scoped_refptr<ServiceWorkerRegistration> GetOrCreateRegistration(
const ServiceWorkerDatabase::RegistrationData& data,
@@ -228,7 +304,20 @@ class CONTENT_EXPORT ServiceWorkerStorage {
void PurgeResource(int64 id);
void OnResourcePurged(int64 id, int rv);
+ // Deletes purgeable and uncommitted resources left over from the previous
+ // browser session. This must be called once per session before any database
+ // operation that may mutate the purgeable or uncommitted resource lists.
+ void DeleteStaleResources();
+ void DidCollectStaleResources(const std::vector<int64>& stale_resource_ids,
+ ServiceWorkerDatabase::Status status);
+
+ void ClearSessionOnlyOrigins();
+
// Static cross-thread helpers.
+ static void CollectStaleResourcesFromDB(
+ ServiceWorkerDatabase* database,
+ scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+ const GetResourcesCallback& callback);
static void ReadInitialDataFromDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
@@ -261,9 +350,21 @@ class CONTENT_EXPORT ServiceWorkerStorage {
int64 registration_id,
const GURL& origin,
const FindInDBCallback& callback);
+ static void DeleteAllDataForOriginsFromDB(
+ ServiceWorkerDatabase* database,
+ const std::set<GURL>& origins);
+
+ void ScheduleDeleteAndStartOver();
+ void DidDeleteDatabase(
+ const StatusCallback& callback,
+ ServiceWorkerDatabase::Status status);
+ void DidDeleteDiskCache(
+ const StatusCallback& callback,
+ bool result);
- // For finding registrations being installed.
+ // For finding registrations being installed or uninstalled.
RegistrationRefsById installing_registrations_;
+ RegistrationRefsById uninstalling_registrations_;
// Origins having registations.
std::set<GURL> registered_origins_;
@@ -286,15 +387,18 @@ class CONTENT_EXPORT ServiceWorkerStorage {
base::FilePath path_;
base::WeakPtr<ServiceWorkerContextCore> context_;
- // Only accessed on |database_task_runner_|.
+ // Only accessed using |database_task_manager_|.
scoped_ptr<ServiceWorkerDatabase> database_;
- scoped_refptr<base::SequencedTaskRunner> database_task_runner_;
- scoped_refptr<base::MessageLoopProxy> disk_cache_thread_;
- scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager_;
+ scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread_;
+ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
scoped_ptr<ServiceWorkerDiskCache> disk_cache_;
- std::deque<int64> purgeable_reource_ids_;
+ std::deque<int64> purgeable_resource_ids_;
bool is_purge_pending_;
+ bool has_checked_for_stale_resources_;
+ std::set<int64> pending_deletions_;
base::WeakPtrFactory<ServiceWorkerStorage> weak_factory_;
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 417a0b7f237..e98b83dbc6c 100644
--- a/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -4,23 +4,27 @@
#include <string>
+#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
#include "content/browser/browser_thread_impl.h"
#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_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
+#include "content/browser/service_worker/service_worker_utils.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
using net::IOBuffer;
+using net::TestCompletionCallback;
using net::WrappedIOBuffer;
namespace content {
@@ -75,74 +79,108 @@ ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback(
return base::Bind(&GetAllCallback, was_called, all);
}
-void OnIOComplete(int* rv_out, int rv) {
- *rv_out = rv;
+void OnCompareComplete(
+ ServiceWorkerStatusCode* status_out, bool* are_equal_out,
+ ServiceWorkerStatusCode status, bool are_equal) {
+ *status_out = status;
+ *are_equal_out = are_equal;
}
-void WriteBasicResponse(ServiceWorkerStorage* storage, int64 id) {
+void WriteResponse(
+ ServiceWorkerStorage* storage, int64 id,
+ const std::string& headers,
+ IOBuffer* body, int length) {
scoped_ptr<ServiceWorkerResponseWriter> writer =
storage->CreateResponseWriter(id);
- const char kHttpHeaders[] =
- "HTTP/1.0 200 HONKYDORY\0Content-Length: 6\0\0";
- const char kHttpBody[] = "Hello\0";
- scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBody));
- std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
info->request_time = base::Time::Now();
info->response_time = base::Time::Now();
info->was_cached = false;
- info->headers = new net::HttpResponseHeaders(raw_headers);
+ info->headers = new net::HttpResponseHeaders(headers);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
new HttpResponseInfoIOBuffer(info.release());
+ {
+ TestCompletionCallback cb;
+ writer->WriteInfo(info_buffer.get(), cb.callback());
+ int rv = cb.WaitForResult();
+ EXPECT_LT(0, rv);
+ }
+ {
+ TestCompletionCallback cb;
+ writer->WriteData(body, length, cb.callback());
+ int rv = cb.WaitForResult();
+ EXPECT_EQ(length, rv);
+ }
+}
- int rv = -1234;
- writer->WriteInfo(info_buffer, base::Bind(&OnIOComplete, &rv));
- base::RunLoop().RunUntilIdle();
- EXPECT_LT(0, rv);
+void WriteStringResponse(
+ ServiceWorkerStorage* storage, int64 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());
+}
- rv = -1234;
- writer->WriteData(body, arraysize(kHttpBody),
- base::Bind(&OnIOComplete, &rv));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(static_cast<int>(arraysize(kHttpBody)), rv);
+void WriteBasicResponse(ServiceWorkerStorage* storage, int64 id) {
+ scoped_ptr<ServiceWorkerResponseWriter> writer =
+ storage->CreateResponseWriter(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));
}
bool VerifyBasicResponse(ServiceWorkerStorage* storage, int64 id,
bool expected_positive_result) {
- const char kExpectedHttpBody[] = "Hello\0";
+ const std::string kExpectedHttpBody("Hello");
scoped_ptr<ServiceWorkerResponseReader> reader =
storage->CreateResponseReader(id);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
new HttpResponseInfoIOBuffer();
- int rv = -1234;
- reader->ReadInfo(info_buffer, base::Bind(&OnIOComplete, &rv));
- base::RunLoop().RunUntilIdle();
- if (expected_positive_result)
- EXPECT_LT(0, rv);
- if (rv <= 0)
- return false;
+ {
+ 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;
+ }
- const int kBigEnough = 512;
- scoped_refptr<net::IOBuffer> buffer = new IOBuffer(kBigEnough);
- rv = -1234;
- reader->ReadData(buffer, kBigEnough, base::Bind(&OnIOComplete, &rv));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(static_cast<int>(arraysize(kExpectedHttpBody)), 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);
+ }
bool status_match =
std::string("HONKYDORY") ==
info_buffer->http_info->headers->GetStatusText();
- bool data_match =
- std::string(kExpectedHttpBody) == std::string(buffer->data());
+ bool data_match = kExpectedHttpBody == received_body;
EXPECT_TRUE(status_match);
EXPECT_TRUE(data_match);
return status_match && data_match;
}
+void WriteResponseOfSize(ServiceWorkerStorage* storage, int64 id,
+ char val, int size) {
+ const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\00";
+ std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(size);
+ memset(buffer->data(), val, size);
+ WriteResponse(storage, id, headers, buffer.get(), size);
+}
+
} // namespace
class ServiceWorkerStorageTest : public testing::Test {
@@ -151,20 +189,25 @@ class ServiceWorkerStorageTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {
}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
+ new MockServiceWorkerDatabaseTaskManager(
+ base::ThreadTaskRunnerHandle::Get()));
context_.reset(
- new ServiceWorkerContextCore(base::FilePath(),
- base::MessageLoopProxy::current(),
- base::MessageLoopProxy::current(),
+ new ServiceWorkerContextCore(GetUserDataDirectory(),
+ base::ThreadTaskRunnerHandle::Get(),
+ database_task_manager.Pass(),
+ base::ThreadTaskRunnerHandle::Get(),
+ NULL,
NULL,
NULL,
NULL));
context_ptr_ = context_->AsWeakPtr();
}
- virtual void TearDown() OVERRIDE {
- context_.reset();
- }
+ void TearDown() override { context_.reset(); }
+
+ virtual base::FilePath GetUserDataDirectory() { return base::FilePath(); }
ServiceWorkerStorage* storage() { return context_->storage(); }
@@ -187,8 +230,9 @@ class ServiceWorkerStorageTest : public testing::Test {
scoped_refptr<ServiceWorkerVersion> version) {
bool was_called = false;
ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
- storage()->StoreRegistration(
- registration, version, MakeStatusCallback(&was_called, &result));
+ storage()->StoreRegistration(registration.get(),
+ version.get(),
+ MakeStatusCallback(&was_called, &result));
EXPECT_FALSE(was_called); // always async
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(was_called);
@@ -222,14 +266,19 @@ class ServiceWorkerStorageTest : public testing::Test {
scoped_refptr<ServiceWorkerRegistration> registration) {
bool was_called = false;
ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
- storage()->UpdateToActiveState(
- registration, MakeStatusCallback(&was_called, &result));
+ storage()->UpdateToActiveState(registration.get(),
+ MakeStatusCallback(&was_called, &result));
EXPECT_FALSE(was_called); // always async
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(was_called);
return result;
}
+ void UpdateLastUpdateCheckTime(ServiceWorkerRegistration* registration) {
+ storage()->UpdateLastUpdateCheckTime(registration);
+ base::RunLoop().RunUntilIdle();
+ }
+
ServiceWorkerStatusCode FindRegistrationForDocument(
const GURL& document_url,
scoped_refptr<ServiceWorkerRegistration>* registration) {
@@ -275,37 +324,51 @@ class ServiceWorkerStorageTest : public testing::Test {
};
TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
- const GURL kScope("http://www.test.not/scope/*");
+ const GURL kScope("http://www.test.not/scope/");
const GURL kScript("http://www.test.not/script.js");
const GURL kDocumentUrl("http://www.test.not/scope/document.html");
+ const GURL kResource1("http://www.test.not/scope/resource1.js");
+ const int64 kResource1Size = 1591234;
+ const GURL kResource2("http://www.test.not/scope/resource2.js");
+ const int64 kResource2Size = 51;
const int64 kRegistrationId = 0;
const int64 kVersionId = 0;
+ const base::Time kToday = base::Time::Now();
+ const base::Time kYesterday = kToday - base::TimeDelta::FromDays(1);
scoped_refptr<ServiceWorkerRegistration> found_registration;
// We shouldn't find anything without having stored anything.
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForPattern(kScope, &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForId(
kRegistrationId, kScope.GetOrigin(), &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
+
+ std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
+ resources.push_back(
+ ServiceWorkerDatabase::ResourceRecord(1, kResource1, kResource1Size));
+ resources.push_back(
+ ServiceWorkerDatabase::ResourceRecord(2, kResource2, kResource2Size));
// Store something.
scoped_refptr<ServiceWorkerRegistration> live_registration =
new ServiceWorkerRegistration(
- kScope, kScript, kRegistrationId, context_ptr_);
+ kScope, kRegistrationId, context_ptr_);
scoped_refptr<ServiceWorkerVersion> live_version =
new ServiceWorkerVersion(
- live_registration, kVersionId, context_ptr_);
+ live_registration.get(), kScript, kVersionId, context_ptr_);
live_version->SetStatus(ServiceWorkerVersion::INSTALLED);
- live_registration->set_waiting_version(live_version);
+ live_version->script_cache_map()->SetResources(resources);
+ live_registration->SetWaitingVersion(live_version.get());
+ live_registration->set_last_update_check(kYesterday);
EXPECT_EQ(SERVICE_WORKER_OK,
StoreRegistration(live_registration, live_version));
@@ -313,6 +376,10 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
EXPECT_EQ(SERVICE_WORKER_OK,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
EXPECT_EQ(live_registration, found_registration);
+ EXPECT_EQ(kResource1Size + kResource2Size,
+ live_registration->resources_total_size_bytes());
+ EXPECT_EQ(kResource1Size + kResource2Size,
+ found_registration->resources_total_size_bytes());
found_registration = NULL;
// But FindRegistrationForPattern is always async.
@@ -325,7 +392,7 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
EXPECT_EQ(SERVICE_WORKER_OK,
FindRegistrationForId(
kRegistrationId, kScope.GetOrigin(), &found_registration));
- ASSERT_TRUE(found_registration);
+ ASSERT_TRUE(found_registration.get());
EXPECT_EQ(kRegistrationId, found_registration->id());
EXPECT_EQ(live_registration, found_registration);
found_registration = NULL;
@@ -336,10 +403,21 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
// Now FindRegistrationForDocument should be async.
EXPECT_EQ(SERVICE_WORKER_OK,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
- ASSERT_TRUE(found_registration);
+ ASSERT_TRUE(found_registration.get());
EXPECT_EQ(kRegistrationId, found_registration->id());
EXPECT_TRUE(found_registration->HasOneRef());
- EXPECT_EQ(live_version, found_registration->waiting_version());
+
+ // Check that sizes are populated correctly
+ EXPECT_EQ(live_version.get(), found_registration->waiting_version());
+ EXPECT_EQ(kResource1Size + kResource2Size,
+ found_registration->resources_total_size_bytes());
+ std::vector<ServiceWorkerRegistrationInfo> all_registrations;
+ GetAllRegistrations(&all_registrations);
+ EXPECT_EQ(1u, all_registrations.size());
+ ServiceWorkerRegistrationInfo info = all_registrations[0];
+ EXPECT_EQ(kResource1Size + kResource2Size, info.stored_version_size_bytes);
+ all_registrations.clear();
+
found_registration = NULL;
// Drop the live version too.
@@ -348,42 +426,47 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
// And FindRegistrationForPattern is always async.
EXPECT_EQ(SERVICE_WORKER_OK,
FindRegistrationForPattern(kScope, &found_registration));
- ASSERT_TRUE(found_registration);
+ ASSERT_TRUE(found_registration.get());
EXPECT_EQ(kRegistrationId, found_registration->id());
EXPECT_TRUE(found_registration->HasOneRef());
EXPECT_FALSE(found_registration->active_version());
ASSERT_TRUE(found_registration->waiting_version());
+ EXPECT_EQ(kYesterday, found_registration->last_update_check());
EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
found_registration->waiting_version()->status());
- // Update to active.
+ // Update to active and update the last check time.
scoped_refptr<ServiceWorkerVersion> temp_version =
found_registration->waiting_version();
- found_registration->set_waiting_version(NULL);
- temp_version->SetStatus(ServiceWorkerVersion::ACTIVE);
- found_registration->set_active_version(temp_version);
+ temp_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ found_registration->SetActiveVersion(temp_version.get());
temp_version = NULL;
EXPECT_EQ(SERVICE_WORKER_OK, UpdateToActiveState(found_registration));
+ found_registration->set_last_update_check(kToday);
+ UpdateLastUpdateCheckTime(found_registration.get());
+
found_registration = NULL;
// Trying to update a unstored registration to active should fail.
scoped_refptr<ServiceWorkerRegistration> unstored_registration =
new ServiceWorkerRegistration(
- kScope, kScript, kRegistrationId + 1, context_ptr_);
+ kScope, kRegistrationId + 1, context_ptr_);
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
UpdateToActiveState(unstored_registration));
unstored_registration = NULL;
- // The Find methods should return a registration with an active version.
+ // The Find methods should return a registration with an active version
+ // and the expected update time.
EXPECT_EQ(SERVICE_WORKER_OK,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
- ASSERT_TRUE(found_registration);
+ ASSERT_TRUE(found_registration.get());
EXPECT_EQ(kRegistrationId, found_registration->id());
EXPECT_TRUE(found_registration->HasOneRef());
EXPECT_FALSE(found_registration->waiting_version());
ASSERT_TRUE(found_registration->active_version());
- EXPECT_EQ(ServiceWorkerVersion::ACTIVE,
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
found_registration->active_version()->status());
+ EXPECT_EQ(kToday, found_registration->last_update_check());
// Delete from storage but with a instance still live.
EXPECT_TRUE(context_->GetLiveVersion(kRegistrationId));
@@ -395,7 +478,7 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForId(
kRegistrationId, kScope.GetOrigin(), &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
// Deleting an unstored registration should succeed.
EXPECT_EQ(SERVICE_WORKER_OK,
@@ -403,7 +486,7 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
}
TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
- const GURL kScope("http://www.test.not/scope/*");
+ const GURL kScope("http://www.test.not/scope/");
const GURL kScript("http://www.test.not/script.js");
const GURL kDocumentUrl("http://www.test.not/scope/document.html");
const int64 kRegistrationId = 0;
@@ -414,33 +497,33 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
// Create an unstored registration.
scoped_refptr<ServiceWorkerRegistration> live_registration =
new ServiceWorkerRegistration(
- kScope, kScript, kRegistrationId, context_ptr_);
+ kScope, kRegistrationId, context_ptr_);
scoped_refptr<ServiceWorkerVersion> live_version =
new ServiceWorkerVersion(
- live_registration, kVersionId, context_ptr_);
+ live_registration.get(), kScript, kVersionId, context_ptr_);
live_version->SetStatus(ServiceWorkerVersion::INSTALLING);
- live_registration->set_waiting_version(live_version);
+ live_registration->SetWaitingVersion(live_version.get());
// Should not be findable, including by GetAllRegistrations.
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForId(
kRegistrationId, kScope.GetOrigin(), &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForPattern(kScope, &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
std::vector<ServiceWorkerRegistrationInfo> all_registrations;
GetAllRegistrations(&all_registrations);
EXPECT_TRUE(all_registrations.empty());
// Notify storage of it being installed.
- storage()->NotifyInstallingRegistration(live_registration);
+ storage()->NotifyInstallingRegistration(live_registration.get());
// Now should be findable.
EXPECT_EQ(SERVICE_WORKER_OK,
@@ -465,85 +548,371 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
// Notify storage of installation no longer happening.
storage()->NotifyDoneInstallingRegistration(
- live_registration, NULL, SERVICE_WORKER_OK);
+ live_registration.get(), NULL, SERVICE_WORKER_OK);
// Once again, should not be findable.
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForId(
kRegistrationId, kScope.GetOrigin(), &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForDocument(kDocumentUrl, &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
FindRegistrationForPattern(kScope, &found_registration));
- EXPECT_FALSE(found_registration);
+ EXPECT_FALSE(found_registration.get());
GetAllRegistrations(&all_registrations);
EXPECT_TRUE(all_registrations.empty());
}
-TEST_F(ServiceWorkerStorageTest, ResourceIdsAreStoredAndPurged) {
- storage()->LazyInitialize(base::Bind(&base::DoNothing));
+class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest {
+ public:
+ void SetUp() override {
+ ServiceWorkerStorageTest::SetUp();
+
+ storage()->LazyInitialize(base::Bind(&base::DoNothing));
+ base::RunLoop().RunUntilIdle();
+ scope_ = GURL("http://www.test.not/scope/");
+ script_ = GURL("http://www.test.not/script.js");
+ import_ = GURL("http://www.test.not/import.js");
+ document_url_ = GURL("http://www.test.not/scope/document.html");
+ registration_id_ = storage()->NewRegistrationId();
+ version_id_ = storage()->NewVersionId();
+ resource_id1_ = storage()->NewResourceId();
+ resource_id2_ = storage()->NewResourceId();
+ resource_id1_size_ = 239193;
+ resource_id2_size_ = 59923;
+
+ // Cons up a new registration+version with two script resources.
+ RegistrationData data;
+ data.registration_id = registration_id_;
+ data.scope = scope_;
+ data.script = script_;
+ data.version_id = version_id_;
+ data.is_active = false;
+ std::vector<ResourceRecord> resources;
+ resources.push_back(
+ ResourceRecord(resource_id1_, script_, resource_id1_size_));
+ resources.push_back(
+ ResourceRecord(resource_id2_, import_, resource_id2_size_));
+ registration_ = storage()->GetOrCreateRegistration(data, resources);
+ registration_->waiting_version()->SetStatus(ServiceWorkerVersion::NEW);
+
+ // Add the resources ids to the uncommitted list.
+ storage()->StoreUncommittedResponseId(resource_id1_);
+ storage()->StoreUncommittedResponseId(resource_id2_);
+ base::RunLoop().RunUntilIdle();
+ std::set<int64> verify_ids;
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetUncommittedResourceIds(&verify_ids));
+ EXPECT_EQ(2u, verify_ids.size());
+
+ // And dump something in the disk cache for them.
+ WriteBasicResponse(storage(), resource_id1_);
+ WriteBasicResponse(storage(), resource_id2_);
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
+
+ // Storing the registration/version should take the resources ids out
+ // of the uncommitted list.
+ EXPECT_EQ(
+ SERVICE_WORKER_OK,
+ StoreRegistration(registration_, registration_->waiting_version()));
+ verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetUncommittedResourceIds(&verify_ids));
+ EXPECT_TRUE(verify_ids.empty());
+ }
+
+ protected:
+ GURL scope_;
+ GURL script_;
+ GURL import_;
+ GURL document_url_;
+ int64 registration_id_;
+ int64 version_id_;
+ int64 resource_id1_;
+ uint64 resource_id1_size_;
+ int64 resource_id2_;
+ uint64 resource_id2_size_;
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+};
+
+class ServiceWorkerResourceStorageDiskTest
+ : public ServiceWorkerResourceStorageTest {
+ public:
+ void SetUp() override {
+ ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir());
+ ServiceWorkerResourceStorageTest::SetUp();
+ }
+
+ base::FilePath GetUserDataDirectory() override {
+ return user_data_directory_.path();
+ }
+
+ protected:
+ base::ScopedTempDir user_data_directory_;
+};
+
+TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_NoLiveVersion) {
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ std::set<int64> verify_ids;
+
+ registration_->SetWaitingVersion(NULL);
+ registration_ = NULL;
+
+ // Deleting the registration should result in the resources being added to the
+ // purgeable list and then doomed in the disk cache and removed from that
+ // list.
+ storage()->DeleteRegistration(
+ registration_id_,
+ scope_.GetOrigin(),
+ base::Bind(&VerifyPurgeableListStatusCallback,
+ base::Unretained(storage()->database_.get()),
+ &verify_ids,
+ &was_called,
+ &result));
base::RunLoop().RunUntilIdle();
- const GURL kScope("http://www.test.not/scope/*");
- const GURL kScript("http://www.test.not/script.js");
- const GURL kImport("http://www.test.not/import.js");
- const GURL kDocumentUrl("http://www.test.not/scope/document.html");
- const int64 kRegistrationId = storage()->NewRegistrationId();
- const int64 kVersionId = storage()->NewVersionId();
- const int64 kResourceId1 = storage()->NewResourceId();
- const int64 kResourceId2 = storage()->NewResourceId();
-
- // Cons up a new registration+version with two script resources.
- RegistrationData data;
- data.registration_id = kRegistrationId;
- data.scope = kScope;
- data.script = kScript;
- data.version_id = kVersionId;
- data.is_active = false;
- std::vector<ResourceRecord> resources;
- resources.push_back(ResourceRecord(kResourceId1, kScript));
- resources.push_back(ResourceRecord(kResourceId2, kImport));
- scoped_refptr<ServiceWorkerRegistration> registration =
- storage()->GetOrCreateRegistration(data, resources);
- registration->waiting_version()->SetStatus(ServiceWorkerVersion::NEW);
-
- // Add the resources ids to the uncommitted list.
- std::set<int64> resource_ids;
- resource_ids.insert(kResourceId1);
- resource_ids.insert(kResourceId2);
+ ASSERT_TRUE(was_called);
+ EXPECT_EQ(SERVICE_WORKER_OK, result);
+ EXPECT_EQ(2u, verify_ids.size());
+ verify_ids.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- storage()->database_->WriteUncommittedResourceIds(resource_ids));
+ storage()->database_->GetPurgeableResourceIds(&verify_ids));
+ EXPECT_TRUE(verify_ids.empty());
- // And dump something in the disk cache for them.
- WriteBasicResponse(storage(), kResourceId1);
- WriteBasicResponse(storage(), kResourceId2);
- EXPECT_TRUE(VerifyBasicResponse(storage(), kResourceId1, true));
- EXPECT_TRUE(VerifyBasicResponse(storage(), kResourceId2, true));
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
+}
- // Storing the registration/version should take the resources ids out
- // of the uncommitted list.
- EXPECT_EQ(SERVICE_WORKER_OK,
- StoreRegistration(registration, registration->waiting_version()));
+TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_WaitingVersion) {
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
std::set<int64> verify_ids;
+
+ // Deleting the registration should result in the resources being added to the
+ // purgeable list and then doomed in the disk cache and removed from that
+ // list.
+ storage()->DeleteRegistration(
+ registration_->id(),
+ scope_.GetOrigin(),
+ base::Bind(&VerifyPurgeableListStatusCallback,
+ base::Unretained(storage()->database_.get()),
+ &verify_ids,
+ &was_called,
+ &result));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(was_called);
+ EXPECT_EQ(SERVICE_WORKER_OK, result);
+ EXPECT_EQ(2u, verify_ids.size());
+ verify_ids.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
- storage()->database_->GetUncommittedResourceIds(&verify_ids));
+ storage()->database_->GetPurgeableResourceIds(&verify_ids));
+ EXPECT_EQ(2u, verify_ids.size());
+
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
+
+ // Doom the version, now it happens.
+ registration_->waiting_version()->Doom();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, result);
+ EXPECT_EQ(2u, verify_ids.size());
+ verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetPurgeableResourceIds(&verify_ids));
EXPECT_TRUE(verify_ids.empty());
- // Deleting it should result in the resources being added to the
- // purgeable list and then doomed in the disk cache and removed from
- // that list.
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
+}
+
+TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_ActiveVersion) {
+ // Promote the worker to active and add a controllee.
+ registration_->SetActiveVersion(registration_->waiting_version());
+ storage()->UpdateToActiveState(
+ registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ new ServiceWorkerProviderHost(33 /* dummy render process id */,
+ 1 /* dummy provider_id */,
+ context_->AsWeakPtr(),
+ NULL));
+ registration_->active_version()->AddControllee(host.get());
+
bool was_called = false;
ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ std::set<int64> verify_ids;
+
+ // Deleting the registration should move the resources to the purgeable list
+ // but keep them available.
+ storage()->DeleteRegistration(
+ registration_->id(),
+ scope_.GetOrigin(),
+ base::Bind(&VerifyPurgeableListStatusCallback,
+ base::Unretained(storage()->database_.get()),
+ &verify_ids,
+ &was_called,
+ &result));
+ registration_->active_version()->Doom();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(was_called);
+ EXPECT_EQ(SERVICE_WORKER_OK, result);
+ EXPECT_EQ(2u, verify_ids.size());
+ verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetPurgeableResourceIds(&verify_ids));
+ EXPECT_EQ(2u, verify_ids.size());
+
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
+
+ // Removing the controllee should cause the resources to be deleted.
+ registration_->active_version()->RemoveControllee(host.get());
+ base::RunLoop().RunUntilIdle();
verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetPurgeableResourceIds(&verify_ids));
+ EXPECT_TRUE(verify_ids.empty());
+
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
+}
+
+TEST_F(ServiceWorkerResourceStorageDiskTest, CleanupOnRestart) {
+ // Promote the worker to active and add a controllee.
+ registration_->SetActiveVersion(registration_->waiting_version());
+ registration_->SetWaitingVersion(NULL);
+ storage()->UpdateToActiveState(
+ registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ new ServiceWorkerProviderHost(33 /* dummy render process id */,
+ 1 /* dummy provider_id */,
+ context_->AsWeakPtr(),
+ NULL));
+ registration_->active_version()->AddControllee(host.get());
+
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ std::set<int64> verify_ids;
+
+ // Deleting the registration should move the resources to the purgeable list
+ // but keep them available.
storage()->DeleteRegistration(
- registration->id(), kScope.GetOrigin(),
+ registration_->id(),
+ scope_.GetOrigin(),
+ base::Bind(&VerifyPurgeableListStatusCallback,
+ base::Unretained(storage()->database_.get()),
+ &verify_ids,
+ &was_called,
+ &result));
+ base::RunLoop().RunUntilIdle();
+ ASSERT_TRUE(was_called);
+ EXPECT_EQ(SERVICE_WORKER_OK, result);
+ EXPECT_EQ(2u, verify_ids.size());
+ verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetPurgeableResourceIds(&verify_ids));
+ EXPECT_EQ(2u, verify_ids.size());
+
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, true));
+
+ // Also add an uncommitted resource.
+ int64 kStaleUncommittedResourceId = storage()->NewResourceId();
+ storage()->StoreUncommittedResponseId(kStaleUncommittedResourceId);
+ base::RunLoop().RunUntilIdle();
+ verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetUncommittedResourceIds(&verify_ids));
+ EXPECT_EQ(1u, verify_ids.size());
+ WriteBasicResponse(storage(), kStaleUncommittedResourceId);
+ EXPECT_TRUE(
+ VerifyBasicResponse(storage(), kStaleUncommittedResourceId, true));
+
+ // Simulate browser shutdown. The purgeable and uncommitted resources are now
+ // stale.
+ context_.reset();
+ scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
+ new MockServiceWorkerDatabaseTaskManager(
+ base::ThreadTaskRunnerHandle::Get()));
+ context_.reset(
+ new ServiceWorkerContextCore(GetUserDataDirectory(),
+ base::ThreadTaskRunnerHandle::Get(),
+ database_task_manager.Pass(),
+ base::ThreadTaskRunnerHandle::Get(),
+ NULL,
+ NULL,
+ NULL,
+ NULL));
+ storage()->LazyInitialize(base::Bind(&base::DoNothing));
+ base::RunLoop().RunUntilIdle();
+
+ // Store a new uncommitted resource. This triggers stale resource cleanup.
+ int64 kNewResourceId = storage()->NewResourceId();
+ WriteBasicResponse(storage(), kNewResourceId);
+ storage()->StoreUncommittedResponseId(kNewResourceId);
+ base::RunLoop().RunUntilIdle();
+
+ // The stale resources should be purged, but the new resource should persist.
+ verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetUncommittedResourceIds(&verify_ids));
+ ASSERT_EQ(1u, verify_ids.size());
+ EXPECT_EQ(kNewResourceId, *verify_ids.begin());
+
+ // Purging resources needs interactions with SimpleCache's worker thread,
+ // so single RunUntilIdle() call may not be sufficient.
+ while (storage()->is_purge_pending_)
+ base::RunLoop().RunUntilIdle();
+
+ verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetPurgeableResourceIds(&verify_ids));
+ EXPECT_TRUE(verify_ids.empty());
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
+ EXPECT_FALSE(
+ VerifyBasicResponse(storage(), kStaleUncommittedResourceId, false));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), kNewResourceId, true));
+}
+
+TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) {
+ // Promote the worker to active worker and add a controllee.
+ registration_->SetActiveVersion(registration_->waiting_version());
+ storage()->UpdateToActiveState(
+ registration_.get(), base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ new ServiceWorkerProviderHost(33 /* dummy render process id */,
+ 1 /* dummy provider_id */,
+ context_->AsWeakPtr(),
+ NULL));
+ registration_->active_version()->AddControllee(host.get());
+
+ bool was_called = false;
+ ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
+ std::set<int64> verify_ids;
+
+ // Make an updated registration.
+ scoped_refptr<ServiceWorkerVersion> live_version = new ServiceWorkerVersion(
+ registration_.get(), script_, storage()->NewVersionId(), context_ptr_);
+ live_version->SetStatus(ServiceWorkerVersion::NEW);
+ registration_->SetWaitingVersion(live_version.get());
+
+ // Writing the registration should move the old version's resources to the
+ // purgeable list but keep them available.
+ storage()->StoreRegistration(
+ registration_.get(),
+ registration_->waiting_version(),
base::Bind(&VerifyPurgeableListStatusCallback,
base::Unretained(storage()->database_.get()),
- &verify_ids, &was_called, &result));
+ &verify_ids,
+ &was_called,
+ &result));
+ registration_->active_version()->Doom();
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(was_called);
EXPECT_EQ(SERVICE_WORKER_OK, result);
@@ -551,62 +920,74 @@ TEST_F(ServiceWorkerStorageTest, ResourceIdsAreStoredAndPurged) {
verify_ids.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
storage()->database_->GetPurgeableResourceIds(&verify_ids));
+ EXPECT_EQ(2u, verify_ids.size());
+
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, false));
+ EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id2_, false));
+
+ // Removing the controllee should cause the old version's resources to be
+ // deleted.
+ registration_->active_version()->RemoveControllee(host.get());
+ base::RunLoop().RunUntilIdle();
+ verify_ids.clear();
+ EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+ storage()->database_->GetPurgeableResourceIds(&verify_ids));
EXPECT_TRUE(verify_ids.empty());
- EXPECT_FALSE(VerifyBasicResponse(storage(), kResourceId1, false));
- EXPECT_FALSE(VerifyBasicResponse(storage(), kResourceId2, false));
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id1_, false));
+ EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false));
}
TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
const GURL kDocumentUrl("http://www.example.com/scope/foo");
scoped_refptr<ServiceWorkerRegistration> found_registration;
- // Registration for "/scope/*".
- const GURL kScope1("http://www.example.com/scope/*");
+ // Registration for "/scope/".
+ const GURL kScope1("http://www.example.com/scope/");
const GURL kScript1("http://www.example.com/script1.js");
const int64 kRegistrationId1 = 1;
const int64 kVersionId1 = 1;
scoped_refptr<ServiceWorkerRegistration> live_registration1 =
new ServiceWorkerRegistration(
- kScope1, kScript1, kRegistrationId1, context_ptr_);
+ kScope1, kRegistrationId1, context_ptr_);
scoped_refptr<ServiceWorkerVersion> live_version1 =
new ServiceWorkerVersion(
- live_registration1, kVersionId1, context_ptr_);
+ live_registration1.get(), kScript1, kVersionId1, context_ptr_);
live_version1->SetStatus(ServiceWorkerVersion::INSTALLED);
- live_registration1->set_waiting_version(live_version1);
+ live_registration1->SetWaitingVersion(live_version1.get());
- // Registration for "/scope/foo*".
- const GURL kScope2("http://www.example.com/scope/foo*");
+ // Registration for "/scope/foo".
+ const GURL kScope2("http://www.example.com/scope/foo");
const GURL kScript2("http://www.example.com/script2.js");
const int64 kRegistrationId2 = 2;
const int64 kVersionId2 = 2;
scoped_refptr<ServiceWorkerRegistration> live_registration2 =
new ServiceWorkerRegistration(
- kScope2, kScript2, kRegistrationId2, context_ptr_);
+ kScope2, kRegistrationId2, context_ptr_);
scoped_refptr<ServiceWorkerVersion> live_version2 =
new ServiceWorkerVersion(
- live_registration2, kVersionId2, context_ptr_);
+ live_registration2.get(), kScript2, kVersionId2, context_ptr_);
live_version2->SetStatus(ServiceWorkerVersion::INSTALLED);
- live_registration2->set_waiting_version(live_version2);
+ live_registration2->SetWaitingVersion(live_version2.get());
- // Registration for "/scope/foo".
- const GURL kScope3("http://www.example.com/scope/foo");
+ // Registration for "/scope/foobar".
+ const GURL kScope3("http://www.example.com/scope/foobar");
const GURL kScript3("http://www.example.com/script3.js");
const int64 kRegistrationId3 = 3;
const int64 kVersionId3 = 3;
scoped_refptr<ServiceWorkerRegistration> live_registration3 =
new ServiceWorkerRegistration(
- kScope3, kScript3, kRegistrationId3, context_ptr_);
+ kScope3, kRegistrationId3, context_ptr_);
scoped_refptr<ServiceWorkerVersion> live_version3 =
new ServiceWorkerVersion(
- live_registration3, kVersionId3, context_ptr_);
+ live_registration3.get(), kScript3, kVersionId3, context_ptr_);
live_version3->SetStatus(ServiceWorkerVersion::INSTALLED);
- live_registration3->set_waiting_version(live_version3);
+ live_registration3->SetWaitingVersion(live_version3.get());
// Notify storage of they being installed.
- storage()->NotifyInstallingRegistration(live_registration1);
- storage()->NotifyInstallingRegistration(live_registration2);
- storage()->NotifyInstallingRegistration(live_registration3);
+ storage()->NotifyInstallingRegistration(live_registration1.get());
+ storage()->NotifyInstallingRegistration(live_registration2.get());
+ storage()->NotifyInstallingRegistration(live_registration3.get());
// Find a registration among installing ones.
EXPECT_EQ(SERVICE_WORKER_OK,
@@ -624,11 +1005,11 @@ TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
// Notify storage of installations no longer happening.
storage()->NotifyDoneInstallingRegistration(
- live_registration1, NULL, SERVICE_WORKER_OK);
+ live_registration1.get(), NULL, SERVICE_WORKER_OK);
storage()->NotifyDoneInstallingRegistration(
- live_registration2, NULL, SERVICE_WORKER_OK);
+ live_registration2.get(), NULL, SERVICE_WORKER_OK);
storage()->NotifyDoneInstallingRegistration(
- live_registration3, NULL, SERVICE_WORKER_OK);
+ live_registration3.get(), NULL, SERVICE_WORKER_OK);
// Find a registration among installed ones.
EXPECT_EQ(SERVICE_WORKER_OK,
@@ -636,4 +1017,66 @@ TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) {
EXPECT_EQ(live_registration2, found_registration);
}
+TEST_F(ServiceWorkerStorageTest, CompareResources) {
+ // Compare two small responses containing the same data.
+ WriteBasicResponse(storage(), 1);
+ WriteBasicResponse(storage(), 2);
+ ServiceWorkerStatusCode status = static_cast<ServiceWorkerStatusCode>(-1);
+ bool are_equal = false;
+ storage()->CompareScriptResources(
+ 1, 2,
+ base::Bind(&OnCompareComplete, &status, &are_equal));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_TRUE(are_equal);
+
+ // Compare two small responses with different data.
+ const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0\0";
+ const char kHttpBody[] = "Goodbye";
+ std::string headers(kHttpHeaders, arraysize(kHttpHeaders));
+ WriteStringResponse(storage(), 3, headers, std::string(kHttpBody));
+ status = static_cast<ServiceWorkerStatusCode>(-1);
+ are_equal = true;
+ storage()->CompareScriptResources(
+ 1, 3,
+ base::Bind(&OnCompareComplete, &status, &are_equal));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_FALSE(are_equal);
+
+ // Compare two large responses with the same data.
+ const int k32K = 32 * 1024;
+ WriteResponseOfSize(storage(), 4, 'a', k32K);
+ WriteResponseOfSize(storage(), 5, 'a', k32K);
+ status = static_cast<ServiceWorkerStatusCode>(-1);
+ are_equal = false;
+ storage()->CompareScriptResources(
+ 4, 5,
+ base::Bind(&OnCompareComplete, &status, &are_equal));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_TRUE(are_equal);
+
+ // Compare a large and small response.
+ status = static_cast<ServiceWorkerStatusCode>(-1);
+ are_equal = true;
+ storage()->CompareScriptResources(
+ 1, 5,
+ base::Bind(&OnCompareComplete, &status, &are_equal));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_FALSE(are_equal);
+
+ // Compare two large responses with different data.
+ WriteResponseOfSize(storage(), 6, 'b', k32K);
+ status = static_cast<ServiceWorkerStatusCode>(-1);
+ are_equal = true;
+ storage()->CompareScriptResources(
+ 5, 6,
+ base::Bind(&OnCompareComplete, &status, &are_equal));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_FALSE(are_equal);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_unregister_job.cc b/chromium/content/browser/service_worker/service_worker_unregister_job.cc
index dabcd22f108..8889039407a 100644
--- a/chromium/content/browser/service_worker/service_worker_unregister_job.cc
+++ b/chromium/content/browser/service_worker/service_worker_unregister_job.cc
@@ -4,10 +4,13 @@
#include "content/browser/service_worker/service_worker_unregister_job.h"
+#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_job_coordinator.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_utils.h"
+#include "content/browser/service_worker/service_worker_version.h"
namespace content {
@@ -18,7 +21,9 @@ ServiceWorkerUnregisterJob::ServiceWorkerUnregisterJob(
const GURL& pattern)
: context_(context),
pattern_(pattern),
- weak_factory_(this) {}
+ is_promise_resolved_(false),
+ weak_factory_(this) {
+}
ServiceWorkerUnregisterJob::~ServiceWorkerUnregisterJob() {}
@@ -30,7 +35,7 @@ void ServiceWorkerUnregisterJob::AddCallback(
void ServiceWorkerUnregisterJob::Start() {
context_->storage()->FindRegistrationForPattern(
pattern_,
- base::Bind(&ServiceWorkerUnregisterJob::DeleteExistingRegistration,
+ base::Bind(&ServiceWorkerUnregisterJob::OnRegistrationFound,
weak_factory_.GetWeakPtr()));
}
@@ -45,32 +50,31 @@ bool ServiceWorkerUnregisterJob::Equals(ServiceWorkerRegisterJobBase* job) {
}
RegistrationJobType ServiceWorkerUnregisterJob::GetType() {
- return ServiceWorkerRegisterJobBase::UNREGISTRATION;
+ return UNREGISTRATION_JOB;
}
-void ServiceWorkerUnregisterJob::DeleteExistingRegistration(
+void ServiceWorkerUnregisterJob::OnRegistrationFound(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration) {
- if (status == SERVICE_WORKER_OK) {
- DCHECK(registration);
- // TODO(michaeln): Deactivate the live registration object and
- // eventually call storage->DeleteVersionResources()
- // when the version no longer has any controllees.
- context_->storage()->DeleteRegistration(
- registration->id(),
- registration->script_url().GetOrigin(),
- base::Bind(&ServiceWorkerUnregisterJob::Complete,
- weak_factory_.GetWeakPtr()));
+ if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
+ DCHECK(!registration.get());
+ Complete(SERVICE_WORKER_ERROR_NOT_FOUND);
return;
}
- if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
- DCHECK(!registration);
- Complete(SERVICE_WORKER_OK);
+ if (status != SERVICE_WORKER_OK || registration->is_uninstalling()) {
+ Complete(status);
return;
}
- Complete(status);
+ // TODO: "7. If registration.updatePromise is not null..."
+
+ // "8. Resolve promise."
+ ResolvePromise(SERVICE_WORKER_OK);
+
+ registration->ClearWhenReady();
+
+ Complete(SERVICE_WORKER_OK);
}
void ServiceWorkerUnregisterJob::Complete(ServiceWorkerStatusCode status) {
@@ -80,6 +84,14 @@ void ServiceWorkerUnregisterJob::Complete(ServiceWorkerStatusCode status) {
void ServiceWorkerUnregisterJob::CompleteInternal(
ServiceWorkerStatusCode status) {
+ if (!is_promise_resolved_)
+ ResolvePromise(status);
+}
+
+void ServiceWorkerUnregisterJob::ResolvePromise(
+ ServiceWorkerStatusCode status) {
+ DCHECK(!is_promise_resolved_);
+ is_promise_resolved_ = true;
for (std::vector<UnregistrationCallback>::iterator it = callbacks_.begin();
it != callbacks_.end();
++it) {
diff --git a/chromium/content/browser/service_worker/service_worker_unregister_job.h b/chromium/content/browser/service_worker/service_worker_unregister_job.h
index 484318136f3..fef9c272de6 100644
--- a/chromium/content/browser/service_worker/service_worker_unregister_job.h
+++ b/chromium/content/browser/service_worker/service_worker_unregister_job.h
@@ -32,29 +32,30 @@ class ServiceWorkerUnregisterJob : public ServiceWorkerRegisterJobBase {
ServiceWorkerUnregisterJob(base::WeakPtr<ServiceWorkerContextCore> context,
const GURL& pattern);
- virtual ~ServiceWorkerUnregisterJob();
+ ~ServiceWorkerUnregisterJob() override;
// Registers a callback to be called when the job completes (whether
// successfully or not). Multiple callbacks may be registered.
void AddCallback(const UnregistrationCallback& callback);
// ServiceWorkerRegisterJobBase implementation:
- virtual void Start() OVERRIDE;
- virtual void Abort() OVERRIDE;
- virtual bool Equals(ServiceWorkerRegisterJobBase* job) OVERRIDE;
- virtual RegistrationJobType GetType() OVERRIDE;
+ void Start() override;
+ void Abort() override;
+ bool Equals(ServiceWorkerRegisterJobBase* job) override;
+ RegistrationJobType GetType() override;
private:
- void DeleteExistingRegistration(
+ void OnRegistrationFound(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& registration);
void Complete(ServiceWorkerStatusCode status);
void CompleteInternal(ServiceWorkerStatusCode status);
+ void ResolvePromise(ServiceWorkerStatusCode status);
- // The ServiceWorkerStorage object should always outlive this.
base::WeakPtr<ServiceWorkerContextCore> context_;
const GURL pattern_;
std::vector<UnregistrationCallback> callbacks_;
+ bool is_promise_resolved_;
base::WeakPtrFactory<ServiceWorkerUnregisterJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerUnregisterJob);
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 9d75b93ec25..0e6ef2b98fc 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
@@ -4,17 +4,30 @@
#include "content/browser/service_worker/service_worker_url_request_job.h"
+#include <map>
+#include <string>
+#include <vector>
+
#include "base/bind.h"
+#include "base/guid.h"
#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
#include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
+#include "content/common/resource_request_body.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "content/public/browser/blob_handle.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/service_worker_context.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_response_info.h"
#include "net/http/http_util.h"
-#include "webkit/browser/blob/blob_data_handle.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/blob/blob_url_request_job_factory.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_url_request_job_factory.h"
+#include "ui/base/page_transition_types.h"
namespace content {
@@ -22,12 +35,24 @@ ServiceWorkerURLRequestJob::ServiceWorkerURLRequestJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context)
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ FetchRequestMode request_mode,
+ FetchCredentialsMode credentials_mode,
+ RequestContextType request_context_type,
+ RequestContextFrameType frame_type,
+ scoped_refptr<ResourceRequestBody> body)
: net::URLRequestJob(request, network_delegate),
provider_host_(provider_host),
response_type_(NOT_DETERMINED),
is_started_(false),
+ service_worker_response_type_(blink::WebServiceWorkerResponseTypeDefault),
blob_storage_context_(blob_storage_context),
+ request_mode_(request_mode),
+ credentials_mode_(credentials_mode),
+ request_context_type_(request_context_type),
+ frame_type_(frame_type),
+ fall_back_required_(false),
+ body_(body),
weak_factory_(this) {
}
@@ -76,6 +101,12 @@ void ServiceWorkerURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
if (!http_info())
return;
*info = *http_info();
+ info->response_time = response_time_;
+}
+
+void ServiceWorkerURLRequestJob::GetLoadTimingInfo(
+ net::LoadTimingInfo* load_timing_info) const {
+ *load_timing_info = load_timing_info_;
}
int ServiceWorkerURLRequestJob::GetResponseCode() const {
@@ -113,9 +144,10 @@ bool ServiceWorkerURLRequestJob::ReadRawData(
return status.is_success();
}
-void ServiceWorkerURLRequestJob::OnReceivedRedirect(net::URLRequest* request,
- const GURL& new_url,
- bool* defer_redirect) {
+void ServiceWorkerURLRequestJob::OnReceivedRedirect(
+ net::URLRequest* request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) {
NOTREACHED();
}
@@ -146,6 +178,7 @@ 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();
CommitResponseHeader();
}
@@ -169,6 +202,32 @@ const net::HttpResponseInfo* ServiceWorkerURLRequestJob::http_info() const {
return http_response_info_.get();
}
+void ServiceWorkerURLRequestJob::GetExtraResponseInfo(
+ bool* was_fetched_via_service_worker,
+ bool* was_fallback_required_by_service_worker,
+ GURL* original_url_via_service_worker,
+ blink::WebServiceWorkerResponseType* response_type_via_service_worker,
+ base::TimeTicks* fetch_start_time,
+ base::TimeTicks* fetch_ready_time,
+ base::TimeTicks* fetch_end_time) const {
+ if (response_type_ != FORWARD_TO_SERVICE_WORKER) {
+ *was_fetched_via_service_worker = false;
+ *was_fallback_required_by_service_worker = false;
+ *original_url_via_service_worker = GURL();
+ *response_type_via_service_worker =
+ blink::WebServiceWorkerResponseTypeDefault;
+ return;
+ }
+ *was_fetched_via_service_worker = true;
+ *was_fallback_required_by_service_worker = fall_back_required_;
+ *original_url_via_service_worker = response_url_;
+ *response_type_via_service_worker = service_worker_response_type_;
+ *fetch_start_time = fetch_start_time_;
+ *fetch_ready_time = fetch_ready_time_;
+ *fetch_end_time = fetch_end_time_;
+}
+
+
ServiceWorkerURLRequestJob::~ServiceWorkerURLRequestJob() {
}
@@ -198,13 +257,17 @@ void ServiceWorkerURLRequestJob::StartRequest() {
case FORWARD_TO_SERVICE_WORKER:
DCHECK(provider_host_ && provider_host_->active_version());
DCHECK(!fetch_dispatcher_);
-
// Send a fetch event to the ServiceWorker associated to the
// provider_host.
fetch_dispatcher_.reset(new ServiceWorkerFetchDispatcher(
- request(), provider_host_->active_version(),
+ CreateFetchRequest(),
+ provider_host_->active_version(),
+ base::Bind(&ServiceWorkerURLRequestJob::DidPrepareFetchEvent,
+ weak_factory_.GetWeakPtr()),
base::Bind(&ServiceWorkerURLRequestJob::DidDispatchFetchEvent,
weak_factory_.GetWeakPtr())));
+ fetch_start_time_ = base::TimeTicks::Now();
+ load_timing_info_.send_start = fetch_start_time_;
fetch_dispatcher_->Run();
return;
}
@@ -212,6 +275,104 @@ void ServiceWorkerURLRequestJob::StartRequest() {
NOTREACHED();
}
+scoped_ptr<ServiceWorkerFetchRequest>
+ServiceWorkerURLRequestJob::CreateFetchRequest() {
+ std::string blob_uuid;
+ uint64 blob_size = 0;
+ CreateRequestBodyBlob(&blob_uuid, &blob_size);
+ scoped_ptr<ServiceWorkerFetchRequest> request(
+ new ServiceWorkerFetchRequest());
+ request->mode = request_mode_;
+ request->request_context_type = request_context_type_;
+ request->frame_type = frame_type_;
+ request->url = request_->url();
+ request->method = request_->method();
+ const net::HttpRequestHeaders& headers = request_->extra_request_headers();
+ for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext();) {
+ if (ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(it.name()))
+ continue;
+ request->headers[it.name()] = it.value();
+ }
+ request->blob_uuid = blob_uuid;
+ request->blob_size = blob_size;
+ request->referrer = GURL(request_->referrer());
+ request->credentials_mode = credentials_mode_;
+ const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
+ if (info) {
+ request->is_reload = ui::PageTransitionCoreTypeIs(
+ info->GetPageTransition(), ui::PAGE_TRANSITION_RELOAD);
+ }
+ return request.Pass();
+}
+
+bool ServiceWorkerURLRequestJob::CreateRequestBodyBlob(std::string* blob_uuid,
+ uint64* blob_size) {
+ if (!body_.get() || !blob_storage_context_)
+ return false;
+
+ std::vector<const ResourceRequestBody::Element*> resolved_elements;
+ for (size_t i = 0; i < body_->elements()->size(); ++i) {
+ const ResourceRequestBody::Element& element = (*body_->elements())[i];
+ if (element.type() != ResourceRequestBody::Element::TYPE_BLOB) {
+ resolved_elements.push_back(&element);
+ continue;
+ }
+ scoped_ptr<storage::BlobDataHandle> handle =
+ blob_storage_context_->GetBlobDataFromUUID(element.blob_uuid());
+ if (handle->data()->items().empty())
+ continue;
+ for (size_t i = 0; i < handle->data()->items().size(); ++i) {
+ const storage::BlobData::Item& item = handle->data()->items().at(i);
+ DCHECK_NE(storage::BlobData::Item::TYPE_BLOB, item.type());
+ resolved_elements.push_back(&item);
+ }
+ }
+
+ const std::string uuid(base::GenerateGUID());
+ uint64 total_size = 0;
+ scoped_refptr<storage::BlobData> blob_data = new storage::BlobData(uuid);
+ for (size_t i = 0; i < resolved_elements.size(); ++i) {
+ const ResourceRequestBody::Element& element = *resolved_elements[i];
+ if (total_size != kuint64max && element.length() != kuint64max)
+ total_size += element.length();
+ else
+ total_size = kuint64max;
+ switch (element.type()) {
+ case ResourceRequestBody::Element::TYPE_BYTES:
+ blob_data->AppendData(element.bytes(), element.length());
+ break;
+ case ResourceRequestBody::Element::TYPE_FILE:
+ blob_data->AppendFile(element.path(),
+ element.offset(),
+ element.length(),
+ element.expected_modification_time());
+ break;
+ case ResourceRequestBody::Element::TYPE_BLOB:
+ // Blob elements should be resolved beforehand.
+ NOTREACHED();
+ break;
+ case ResourceRequestBody::Element::TYPE_FILE_FILESYSTEM:
+ blob_data->AppendFileSystemFile(element.filesystem_url(),
+ element.offset(),
+ element.length(),
+ element.expected_modification_time());
+ break;
+ default:
+ NOTIMPLEMENTED();
+ }
+ }
+
+ request_body_blob_data_handle_ =
+ blob_storage_context_->AddFinishedBlob(blob_data.get());
+ *blob_uuid = uuid;
+ *blob_size = total_size;
+ return true;
+}
+
+void ServiceWorkerURLRequestJob::DidPrepareFetchEvent() {
+ fetch_ready_time_ = base::TimeTicks::Now();
+}
+
void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
ServiceWorkerStatusCode status,
ServiceWorkerFetchEventResult fetch_result,
@@ -234,6 +395,18 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
}
if (fetch_result == SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK) {
+ // When the request_mode is |CORS| or |CORS-with-forced-preflight| we can't
+ // simply fallback to the network in the browser process. It is because the
+ // CORS preflight logic is implemented in the renderer. So 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) {
+ fall_back_required_ = true;
+ CreateResponseHeader(
+ 400, "Service Worker Fallback Required", ServiceWorkerHeaderMap());
+ CommitResponseHeader();
+ return;
+ }
// Change the response type and restart the request to fallback to
// the network.
response_type_ = FALLBACK_TO_NETWORK;
@@ -244,22 +417,35 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
// We should have a response now.
DCHECK_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, fetch_result);
+ // Treat a response whose status is 0 as a Network Error.
+ if (response.status_code == 0) {
+ NotifyDone(
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED));
+ return;
+ }
+
+ fetch_end_time_ = base::TimeTicks::Now();
+ load_timing_info_.send_end = fetch_end_time_;
+
// Set up a request for reading the blob.
if (!response.blob_uuid.empty() && blob_storage_context_) {
- scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle =
+ scoped_ptr<storage::BlobDataHandle> blob_data_handle =
blob_storage_context_->GetBlobDataFromUUID(response.blob_uuid);
if (!blob_data_handle) {
// The renderer gave us a bad blob UUID.
DeliverErrorResponse();
return;
}
- blob_request_ = webkit_blob::BlobProtocolHandler::CreateBlobRequest(
+ blob_request_ = storage::BlobProtocolHandler::CreateBlobRequest(
blob_data_handle.Pass(), request()->context(), this);
blob_request_->Start();
}
+ response_url_ = response.url;
+ service_worker_response_type_ = response.response_type;
CreateResponseHeader(
response.status_code, response.status_text, response.headers);
+ load_timing_info_.receive_headers_end = base::TimeTicks::Now();
if (!blob_request_)
CommitResponseHeader();
}
@@ -267,14 +453,14 @@ void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
void ServiceWorkerURLRequestJob::CreateResponseHeader(
int status_code,
const std::string& status_text,
- const std::map<std::string, std::string>& headers) {
+ const ServiceWorkerHeaderMap& headers) {
// TODO(kinuko): If the response has an identifier to on-disk cache entry,
// pull response header from the disk.
std::string status_line(
base::StringPrintf("HTTP/1.1 %d %s", status_code, status_text.c_str()));
status_line.push_back('\0');
http_response_headers_ = new net::HttpResponseHeaders(status_line);
- for (std::map<std::string, std::string>::const_iterator it = headers.begin();
+ for (ServiceWorkerHeaderMap::const_iterator it = headers.begin();
it != headers.end();
++it) {
std::string header;
@@ -295,9 +481,8 @@ void ServiceWorkerURLRequestJob::CommitResponseHeader() {
void ServiceWorkerURLRequestJob::DeliverErrorResponse() {
// TODO(falken): Print an error to the console of the ServiceWorker and of
// the requesting page.
- CreateResponseHeader(500,
- "Service Worker Response Error",
- std::map<std::string, std::string>());
+ CreateResponseHeader(
+ 500, "Service Worker Response Error", ServiceWorkerHeaderMap());
CommitResponseHeader();
}
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 498058cffb4..e8f0f0b2f7d 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
@@ -5,20 +5,30 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_URL_REQUEST_JOB_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_URL_REQUEST_JOB_H_
+#include <map>
+#include <string>
+
#include "base/memory/weak_ptr.h"
+#include "base/time/time.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/request_context_frame_type.h"
+#include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_type.h"
#include "net/http/http_byte_range.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
-namespace webkit_blob {
+namespace storage {
+class BlobDataHandle;
class BlobStorageContext;
}
namespace content {
+class ResourceRequestBody;
class ServiceWorkerContextCore;
class ServiceWorkerFetchDispatcher;
class ServiceWorkerProviderHost;
@@ -31,7 +41,12 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context);
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
+ FetchRequestMode request_mode,
+ FetchCredentialsMode credentials_mode,
+ RequestContextType request_context_type,
+ RequestContextFrameType frame_type,
+ scoped_refptr<ResourceRequestBody> body);
// Sets the response type.
void FallbackToNetwork();
@@ -45,42 +60,47 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
}
// net::URLRequestJob overrides:
- virtual void Start() OVERRIDE;
- virtual void Kill() OVERRIDE;
- virtual net::LoadState GetLoadState() const OVERRIDE;
- virtual bool GetCharset(std::string* charset) OVERRIDE;
- virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
- virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE;
- virtual int GetResponseCode() const OVERRIDE;
- virtual void SetExtraRequestHeaders(
- const net::HttpRequestHeaders& headers) OVERRIDE;
- virtual bool ReadRawData(net::IOBuffer* buf,
- int buf_size,
- int *bytes_read) OVERRIDE;
+ void Start() override;
+ void Kill() override;
+ net::LoadState GetLoadState() const override;
+ bool GetCharset(std::string* charset) override;
+ bool GetMimeType(std::string* mime_type) const override;
+ void GetResponseInfo(net::HttpResponseInfo* info) override;
+ void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
+ int GetResponseCode() const override;
+ void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
// net::URLRequest::Delegate overrides that read the blob from the
// ServiceWorkerFetchResponse.
- virtual void OnReceivedRedirect(net::URLRequest* request,
- const GURL& new_url,
- bool* defer_redirect) OVERRIDE;
- virtual void OnAuthRequired(net::URLRequest* request,
- net::AuthChallengeInfo* auth_info) OVERRIDE;
- virtual void OnCertificateRequested(
+ void OnReceivedRedirect(net::URLRequest* request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) override;
+ void OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info) override;
+ void OnCertificateRequested(
net::URLRequest* request,
- net::SSLCertRequestInfo* cert_request_info) OVERRIDE;
- virtual void OnSSLCertificateError(net::URLRequest* request,
- const net::SSLInfo& ssl_info,
- bool fatal) OVERRIDE;
- virtual void OnBeforeNetworkStart(net::URLRequest* request,
- bool* defer) OVERRIDE;
- virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
- virtual void OnReadCompleted(net::URLRequest* request,
- int bytes_read) OVERRIDE;
+ net::SSLCertRequestInfo* cert_request_info) override;
+ void OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) override;
+ void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override;
+ void OnResponseStarted(net::URLRequest* request) override;
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
const net::HttpResponseInfo* http_info() const;
+ void GetExtraResponseInfo(
+ bool* was_fetched_via_service_worker,
+ bool* was_fallback_required_by_service_worker,
+ GURL* original_url_via_service_worker,
+ blink::WebServiceWorkerResponseType* response_type_via_service_worker,
+ base::TimeTicks* fetch_start_time,
+ base::TimeTicks* fetch_ready_time,
+ base::TimeTicks* fetch_end_time) const;
+
protected:
- virtual ~ServiceWorkerURLRequestJob();
+ ~ServiceWorkerURLRequestJob() override;
private:
enum ResponseType {
@@ -94,7 +114,16 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
void MaybeStartRequest();
void StartRequest();
+ // Creates ServiceWorkerFetchRequest from |request_| and |body_|.
+ scoped_ptr<ServiceWorkerFetchRequest> CreateFetchRequest();
+
+ // Creates BlobDataHandle of the request body from |body_|. This handle
+ // |request_body_blob_data_handle_| will be deleted when
+ // ServiceWorkerURLRequestJob is deleted.
+ bool CreateRequestBodyBlob(std::string* blob_uuid, uint64* blob_size);
+
// For FORWARD_TO_SERVICE_WORKER case.
+ void DidPrepareFetchEvent();
void DidDispatchFetchEvent(ServiceWorkerStatusCode status,
ServiceWorkerFetchEventResult fetch_result,
const ServiceWorkerResponse& response);
@@ -102,7 +131,7 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
// Populates |http_response_headers_|.
void CreateResponseHeader(int status_code,
const std::string& status_text,
- const std::map<std::string, std::string>& headers);
+ const ServiceWorkerHeaderMap& headers);
// Creates |http_response_info_| using |http_response_headers_| and calls
// NotifyHeadersComplete.
@@ -113,6 +142,13 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+ // Timing info to show on the popup in Devtools' Network tab.
+ net::LoadTimingInfo load_timing_info_;
+ base::TimeTicks fetch_start_time_;
+ base::TimeTicks fetch_ready_time_;
+ base::TimeTicks fetch_end_time_;
+ base::Time response_time_;
+
ResponseType response_type_;
bool is_started_;
@@ -121,11 +157,22 @@ class CONTENT_EXPORT ServiceWorkerURLRequestJob
scoped_ptr<net::HttpResponseInfo> http_response_info_;
// Headers that have not yet been committed to |http_response_info_|.
scoped_refptr<net::HttpResponseHeaders> http_response_headers_;
+ GURL response_url_;
+ blink::WebServiceWorkerResponseType service_worker_response_type_;
// Used when response type is FORWARD_TO_SERVICE_WORKER.
scoped_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_;
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context_;
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
scoped_ptr<net::URLRequest> blob_request_;
+ FetchRequestMode request_mode_;
+ FetchCredentialsMode credentials_mode_;
+ RequestContextType request_context_type_;
+ RequestContextFrameType frame_type_;
+ bool fall_back_required_;
+ // ResourceRequestBody has a collection of BlobDataHandles attached to it
+ // using the userdata mechanism. So we have to keep it not to free the blobs.
+ scoped_refptr<ResourceRequestBody> body_;
+ scoped_ptr<storage::BlobDataHandle> request_body_blob_data_handle_;
base::WeakPtrFactory<ServiceWorkerURLRequestJob> weak_factory_;
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 54a2cc966fc..76f718e27dc 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
@@ -17,8 +17,12 @@
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/browser/service_worker/service_worker_url_request_job.h"
#include "content/browser/service_worker/service_worker_version.h"
+#include "content/common/resource_request_body.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/public/browser/blob_handle.h"
+#include "content/public/common/request_context_frame_type.h"
+#include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_type.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/io_buffer.h"
@@ -27,11 +31,11 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job_factory_impl.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_url_request_job.h"
+#include "storage/browser/blob/blob_url_request_job_factory.h"
+#include "storage/common/blob/blob_data.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/blob/blob_url_request_job.h"
-#include "webkit/browser/blob/blob_url_request_job_factory.h"
-#include "webkit/common/blob/blob_data.h"
namespace content {
@@ -48,32 +52,40 @@ class MockHttpProtocolHandler
public:
MockHttpProtocolHandler(
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context)
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context)
: provider_host_(provider_host),
blob_storage_context_(blob_storage_context) {}
- virtual ~MockHttpProtocolHandler() {}
+ ~MockHttpProtocolHandler() override {}
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
- ServiceWorkerURLRequestJob* job = new ServiceWorkerURLRequestJob(
- request, network_delegate, provider_host_, blob_storage_context_);
+ net::NetworkDelegate* network_delegate) const override {
+ ServiceWorkerURLRequestJob* job =
+ new ServiceWorkerURLRequestJob(request,
+ network_delegate,
+ provider_host_,
+ blob_storage_context_,
+ FETCH_REQUEST_MODE_NO_CORS,
+ FETCH_CREDENTIALS_MODE_OMIT,
+ REQUEST_CONTEXT_TYPE_HYPERLINK,
+ REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL,
+ scoped_refptr<ResourceRequestBody>());
job->ForwardToServiceWorker();
return job;
}
private:
base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
- base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context_;
+ base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
};
// Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns
// the memory.
-webkit_blob::BlobProtocolHandler* CreateMockBlobProtocolHandler(
- webkit_blob::BlobStorageContext* blob_storage_context) {
+storage::BlobProtocolHandler* CreateMockBlobProtocolHandler(
+ storage::BlobStorageContext* blob_storage_context) {
// The FileSystemContext and MessageLoopProxy are not actually used but a
// MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor.
- return new webkit_blob::BlobProtocolHandler(
+ return new storage::BlobProtocolHandler(
blob_storage_context, NULL, base::MessageLoopProxy::current().get());
}
@@ -83,10 +95,10 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
protected:
ServiceWorkerURLRequestJobTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
- blob_data_(new webkit_blob::BlobData("blob-id:myblob")) {}
- virtual ~ServiceWorkerURLRequestJobTest() {}
+ blob_data_(new storage::BlobData("blob-id:myblob")) {}
+ ~ServiceWorkerURLRequestJobTest() override {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
browser_context_.reset(new TestBrowserContext);
SetUpWithHelper(new EmbeddedWorkerTestHelper(kProcessID));
}
@@ -95,23 +107,26 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
helper_.reset(helper);
registration_ = new ServiceWorkerRegistration(
- GURL("http://example.com/*"),
- GURL("http://example.com/service_worker.js"),
+ GURL("http://example.com/"),
1L,
helper_->context()->AsWeakPtr());
version_ = new ServiceWorkerVersion(
- registration_, 1L, helper_->context()->AsWeakPtr());
+ registration_.get(),
+ GURL("http://example.com/service_worker.js"),
+ 1L,
+ helper_->context()->AsWeakPtr());
scoped_ptr<ServiceWorkerProviderHost> provider_host(
new ServiceWorkerProviderHost(
kProcessID, kProviderID, helper_->context()->AsWeakPtr(), NULL));
- provider_host->SetActiveVersion(version_.get());
+ provider_host->AssociateRegistration(registration_.get());
+ registration_->SetActiveVersion(version_.get());
ChromeBlobStorageContext* chrome_blob_storage_context =
ChromeBlobStorageContext::GetFor(browser_context_.get());
// Wait for chrome_blob_storage_context to finish initializing.
base::RunLoop().RunUntilIdle();
- webkit_blob::BlobStorageContext* blob_storage_context =
+ storage::BlobStorageContext* blob_storage_context =
chrome_blob_storage_context->context();
url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl);
@@ -126,7 +141,7 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
helper_->context()->AddProviderHost(provider_host.Pass());
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
version_ = NULL;
registration_ = NULL;
helper_.reset();
@@ -164,49 +179,49 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
MockURLRequestDelegate url_request_delegate_;
scoped_ptr<net::URLRequest> request_;
- scoped_refptr<webkit_blob::BlobData> blob_data_;
+ scoped_refptr<storage::BlobData> blob_data_;
+ private:
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerURLRequestJobTest);
};
TEST_F(ServiceWorkerURLRequestJobTest, Simple) {
- version_->SetStatus(ServiceWorkerVersion::ACTIVE);
- TestRequest(200, "OK", std::string());
-}
-
-TEST_F(ServiceWorkerURLRequestJobTest, WaitForActivation) {
- ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->SetStatus(ServiceWorkerVersion::INSTALLED);
- version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
-
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
TestRequest(200, "OK", std::string());
-
- EXPECT_EQ(SERVICE_WORKER_OK, status);
}
// Responds to fetch events with a blob.
class BlobResponder : public EmbeddedWorkerTestHelper {
public:
- BlobResponder(int mock_render_process_id, const std::string& blob_uuid)
+ BlobResponder(int mock_render_process_id,
+ const std::string& blob_uuid,
+ uint64 blob_size)
: EmbeddedWorkerTestHelper(mock_render_process_id),
- blob_uuid_(blob_uuid) {}
- virtual ~BlobResponder() {}
+ blob_uuid_(blob_uuid),
+ blob_size_(blob_size) {}
+ ~BlobResponder() override {}
protected:
- virtual void OnFetchEvent(int embedded_worker_id,
- int request_id,
- const ServiceWorkerFetchRequest& request) OVERRIDE {
+ void OnFetchEvent(int embedded_worker_id,
+ int request_id,
+ const ServiceWorkerFetchRequest& request) override {
SimulateSend(new ServiceWorkerHostMsg_FetchEventFinished(
embedded_worker_id,
request_id,
SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
- ServiceWorkerResponse(200,
+ ServiceWorkerResponse(GURL(""),
+ 200,
"OK",
- std::map<std::string, std::string>(),
- blob_uuid_)));
+ blink::WebServiceWorkerResponseTypeDefault,
+ ServiceWorkerHeaderMap(),
+ blob_uuid_,
+ blob_size_)));
}
std::string blob_uuid_;
+ uint64 blob_size_;
+
+ private:
DISALLOW_COPY_AND_ASSIGN(BlobResponder);
};
@@ -218,17 +233,18 @@ TEST_F(ServiceWorkerURLRequestJobTest, BlobResponse) {
blob_data_->AppendData(kTestData);
expected_response += kTestData;
}
- scoped_ptr<webkit_blob::BlobDataHandle> blob_handle =
- blob_storage_context->context()->AddFinishedBlob(blob_data_);
- SetUpWithHelper(new BlobResponder(kProcessID, blob_handle->uuid()));
+ scoped_ptr<storage::BlobDataHandle> blob_handle =
+ blob_storage_context->context()->AddFinishedBlob(blob_data_.get());
+ SetUpWithHelper(new BlobResponder(
+ kProcessID, blob_handle->uuid(), expected_response.size()));
- version_->SetStatus(ServiceWorkerVersion::ACTIVE);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
TestRequest(200, "OK", expected_response);
}
TEST_F(ServiceWorkerURLRequestJobTest, NonExistentBlobUUIDResponse) {
- SetUpWithHelper(new BlobResponder(kProcessID, "blob-id:nothing-is-here"));
- version_->SetStatus(ServiceWorkerVersion::ACTIVE);
+ SetUpWithHelper(new BlobResponder(kProcessID, "blob-id:nothing-is-here", 0));
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
TestRequest(500, "Service Worker Response Error", std::string());
}
diff --git a/chromium/content/browser/service_worker/service_worker_utils.cc b/chromium/content/browser/service_worker/service_worker_utils.cc
index 2c3d05b773f..edbe9f97b22 100644
--- a/chromium/content/browser/service_worker/service_worker_utils.cc
+++ b/chromium/content/browser/service_worker/service_worker_utils.cc
@@ -6,59 +6,25 @@
#include <string>
-#include "base/command_line.h"
#include "base/logging.h"
-#include "content/public/common/content_switches.h"
-#include "url/gurl.h"
+#include "base/strings/string_util.h"
namespace content {
// static
-bool ServiceWorkerUtils::IsFeatureEnabled() {
- static bool enabled = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableServiceWorker);
- return enabled;
-}
-
-// static
bool ServiceWorkerUtils::ScopeMatches(const GURL& scope, const GURL& url) {
DCHECK(!scope.has_ref());
DCHECK(!url.has_ref());
- const std::string& scope_spec = scope.spec();
- const std::string& url_spec = url.spec();
-
- size_t len = scope_spec.size();
- if (len > 0 && scope_spec[len - 1] == '*')
- return scope_spec.compare(0, len - 1, url_spec, 0, len - 1) == 0;
- return scope_spec == url_spec;
+ return StartsWithASCII(url.spec(), scope.spec(), true);
}
bool LongestScopeMatcher::MatchLongest(const GURL& scope) {
if (!ServiceWorkerUtils::ScopeMatches(scope, url_))
return false;
- if (match_.is_empty()) {
+ if (match_.is_empty() || match_.spec().size() < scope.spec().size()) {
match_ = scope;
return true;
}
-
- const std::string match_spec = match_.spec();
- const std::string scope_spec = scope.spec();
- if (match_spec.size() < scope_spec.size()) {
- match_ = scope;
- return true;
- }
-
- // If |scope| has the same length with |match_|, they are compared as strings.
- // For example:
- // 1) for a document "/foo", "/foo" is prioritized over "/fo*".
- // 2) for a document "/f(1)", "/f(1*" is prioritized over "/f(1)".
- // TODO(nhiroki): This isn't in the spec.
- // (https://github.com/slightlyoff/ServiceWorker/issues/287)
- if (match_spec.size() == scope_spec.size() && match_spec < scope_spec) {
- match_ = scope;
- return true;
- }
-
return false;
}
diff --git a/chromium/content/browser/service_worker/service_worker_utils.h b/chromium/content/browser/service_worker/service_worker_utils.h
index 25700dee2bd..81d6c44f17c 100644
--- a/chromium/content/browser/service_worker/service_worker_utils.h
+++ b/chromium/content/browser/service_worker/service_worker_utils.h
@@ -5,29 +5,20 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_UTILS_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_UTILS_H_
+#include "base/macros.h"
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
-#include "webkit/common/resource_type.h"
-
-class GURL;
+#include "content/public/common/resource_type.h"
+#include "url/gurl.h"
namespace content {
class ServiceWorkerUtils {
public:
- static bool IsMainResourceType(ResourceType::Type type) {
- return ResourceType::IsFrame(type) ||
- ResourceType::IsSharedWorker(type);
- }
-
- static bool IsServiceWorkerResourceType(ResourceType::Type type) {
- return ResourceType::IsServiceWorker(type);
+ static bool IsMainResourceType(ResourceType type) {
+ return IsResourceTypeFrame(type) || type == RESOURCE_TYPE_SHARED_WORKER;
}
- // Returns true if the feature is enabled (or not disabled) by command-line
- // flag.
- static bool IsFeatureEnabled();
-
// A helper for creating a do-nothing status callback.
static void NoOpStatusCallback(ServiceWorkerStatusCode status) {}
diff --git a/chromium/content/browser/service_worker/service_worker_utils_unittest.cc b/chromium/content/browser/service_worker/service_worker_utils_unittest.cc
index 67a74801d6c..30e26b49d43 100644
--- a/chromium/content/browser/service_worker/service_worker_utils_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_utils_unittest.cc
@@ -9,26 +9,42 @@ namespace content {
TEST(ServiceWorkerUtilsTest, ScopeMatches) {
ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*"), GURL("http://www.example.com/")));
+ GURL("http://www.example.com/"), GURL("http://www.example.com/")));
ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("http://www.example.com/page.html")));
ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*"), GURL("https://www.example.com/")));
+ GURL("http://www.example.com/"), GURL("https://www.example.com/")));
ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*"),
+ GURL("http://www.example.com/"),
GURL("https://www.example.com/page.html")));
ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*"), GURL("http://www.foo.com/")));
+ GURL("http://www.example.com/"), GURL("http://www.foo.com/")));
ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*"), GURL("https://www.foo.com/page.html")));
+ GURL("http://www.example.com/"), GURL("https://www.foo.com/page.html")));
+ // '*' is not a wildcard.
+ ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
+ GURL("http://www.example.com/*"), GURL("http://www.example.com/x")));
+ ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
+ GURL("http://www.example.com/*"), GURL("http://www.example.com/")));
+ ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
+ GURL("http://www.example.com/*"), GURL("http://www.example.com/xx")));
ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/"), GURL("http://www.example.com/")));
+ GURL("http://www.example.com/*"), GURL("http://www.example.com/*")));
+
+ ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
+ GURL("http://www.example.com/*/x"), GURL("http://www.example.com/*/x")));
ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/"), GURL("http://www.example.com/x")));
+ GURL("http://www.example.com/*/x"), GURL("http://www.example.com/a/x")));
+ ASSERT_FALSE(
+ ServiceWorkerUtils::ScopeMatches(GURL("http://www.example.com/*/x/*"),
+ GURL("http://www.example.com/a/x/b")));
+ ASSERT_FALSE(
+ ServiceWorkerUtils::ScopeMatches(GURL("http://www.example.com/*/x/*"),
+ GURL("http://www.example.com/*/x/b")));
// '?' is not a wildcard.
ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
@@ -45,59 +61,28 @@ TEST(ServiceWorkerUtilsTest, ScopeMatches) {
ServiceWorkerUtils::ScopeMatches(GURL("http://www.example.com/?a=b"),
GURL("http://www.example.com/?a=b")));
ASSERT_TRUE(
- ServiceWorkerUtils::ScopeMatches(GURL("http://www.example.com/?a=*"),
+ ServiceWorkerUtils::ScopeMatches(GURL("http://www.example.com/?a="),
GURL("http://www.example.com/?a=b")));
ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*"), GURL("http://www.example.com/?a=b")));
- ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
GURL("http://www.example.com/"), GURL("http://www.example.com/?a=b")));
- // '*' only has special meaning in terminal position.
+ // URLs canonicalize \ to / so this is equivalent to "...//x"
ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*/x"), GURL("http://www.example.com/*/x")));
- ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/*/x"), GURL("http://www.example.com/a/x")));
- ASSERT_FALSE(
- ServiceWorkerUtils::ScopeMatches(GURL("http://www.example.com/*/x/*"),
- GURL("http://www.example.com/a/x/b")));
- ASSERT_TRUE(
- ServiceWorkerUtils::ScopeMatches(GURL("http://www.example.com/*/x/*"),
- GURL("http://www.example.com/*/x/b")));
-
- // URLs canonicalize \ to / so this is equivalent to "...//*" and "...//x"
- ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
- GURL("http://www.example.com/\\*"), GURL("http://www.example.com/\\x")));
+ GURL("http://www.example.com/\\x"), GURL("http://www.example.com//x")));
}
-TEST(ServiceWorkerUtilsTest, FindLongestScopeMatch_Basic) {
+TEST(ServiceWorkerUtilsTest, FindLongestScopeMatch) {
LongestScopeMatcher matcher(GURL("http://www.example.com/xxx"));
- // "/xx*" should be matched longest.
- ASSERT_TRUE(matcher.MatchLongest(GURL("http://www.example.com/x*")));
- ASSERT_FALSE(matcher.MatchLongest(GURL("http://www.example.com/*")));
- ASSERT_TRUE(matcher.MatchLongest(GURL("http://www.example.com/xx*")));
-
- // "xxx*" should be matched longer than "/xx*".
- ASSERT_TRUE(matcher.MatchLongest(GURL("http://www.example.com/xxx*")));
-
- ASSERT_FALSE(matcher.MatchLongest(GURL("http://www.example.com/xxxx*")));
-}
-
-TEST(ServiceWorkerUtilsTest, FindLongestScopeMatch_SameLength) {
- LongestScopeMatcher matcher1(GURL("http://www.example.com/xxx"));
-
- // "/xxx" has the same length with "/xx*", so they are compared as strings
- // and "/xxx" should win.
- // TODO(nhiroki): This isn't in the spec (see: service_worker_utils.cc)
- ASSERT_TRUE(matcher1.MatchLongest(GURL("http://www.example.com/xxx")));
- ASSERT_FALSE(matcher1.MatchLongest(GURL("http://www.example.com/xx*")));
+ // "/xx" should be matched longest.
+ ASSERT_TRUE(matcher.MatchLongest(GURL("http://www.example.com/x")));
+ ASSERT_FALSE(matcher.MatchLongest(GURL("http://www.example.com/")));
+ ASSERT_TRUE(matcher.MatchLongest(GURL("http://www.example.com/xx")));
- LongestScopeMatcher matcher2(GURL("http://www.example.com/x(1)"));
+ // "/xxx" should be matched longer than "/xx".
+ ASSERT_TRUE(matcher.MatchLongest(GURL("http://www.example.com/xxx")));
- // "/xx*" should be prioritized over "/x(1)".
- // TODO(nhiroki): This isn't in the spec (see: service_worker_utils.cc)
- ASSERT_TRUE(matcher2.MatchLongest(GURL("http://www.example.com/x(1)")));
- ASSERT_TRUE(matcher2.MatchLongest(GURL("http://www.example.com/x(1*")));
+ ASSERT_FALSE(matcher.MatchLongest(GURL("http://www.example.com/xxxx")));
}
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_version.cc b/chromium/content/browser/service_worker/service_worker_version.cc
index 50f24df48b6..30d9fd5a0a1 100644
--- a/chromium/content/browser/service_worker/service_worker_version.cc
+++ b/chromium/content/browser/service_worker/service_worker_version.cc
@@ -23,12 +23,14 @@ typedef ServiceWorkerVersion::MessageCallback MessageCallback;
namespace {
-// Default delay to stop the worker context after all documents that
-// are associated to the worker are closed.
+// Default delay for scheduled stop.
// (Note that if all references to the version is dropped the worker
// is also stopped without delay)
const int64 kStopWorkerDelay = 30; // 30 secs.
+// Default delay for scheduled update.
+const int kUpdateDelaySeconds = 1;
+
void RunSoon(const base::Closure& callback) {
if (!callback.is_null())
base::MessageLoop::current()->PostTask(FROM_HERE, callback);
@@ -89,19 +91,21 @@ void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
ServiceWorkerVersion::ServiceWorkerVersion(
ServiceWorkerRegistration* registration,
+ const GURL& script_url,
int64 version_id,
base::WeakPtr<ServiceWorkerContextCore> context)
: version_id_(version_id),
registration_id_(kInvalidServiceWorkerVersionId),
+ script_url_(script_url),
status_(NEW),
context_(context),
script_cache_map_(this, context),
+ is_doomed_(false),
weak_factory_(this) {
DCHECK(context_);
DCHECK(registration);
if (registration) {
registration_id_ = registration->id();
- script_url_ = registration->script_url();
scope_ = registration->pattern();
}
context_->AddLiveVersion(this);
@@ -120,6 +124,10 @@ void ServiceWorkerVersion::SetStatus(Status status) {
if (status_ == status)
return;
+ // Schedule to stop worker after registration successfully completed.
+ if (status_ == ACTIVATING && status == ACTIVATED && !HasControllee())
+ ScheduleStopWorker();
+
status_ = status;
std::vector<base::Closure> callbacks;
@@ -142,6 +150,7 @@ ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
return ServiceWorkerVersionInfo(
running_status(),
status(),
+ script_url(),
version_id(),
embedded_worker()->process_id(),
embedded_worker()->thread_id(),
@@ -149,11 +158,11 @@ ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
}
void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
- StartWorkerWithCandidateProcesses(std::vector<int>(), callback);
+ StartWorker(false, callback);
}
-void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
- const std::vector<int>& possible_process_ids,
+void ServiceWorkerVersion::StartWorker(
+ bool pause_after_download,
const StatusCallback& callback) {
switch (running_status()) {
case RUNNING:
@@ -166,12 +175,14 @@ void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
case STARTING:
start_callbacks_.push_back(callback);
if (running_status() == STOPPED) {
+ DCHECK(!cache_listener_.get());
+ cache_listener_.reset(new ServiceWorkerCacheListener(this, context_));
embedded_worker_->Start(
version_id_,
scope_,
script_url_,
- possible_process_ids,
- base::Bind(&ServiceWorkerVersion::RunStartWorkerCallbacksOnError,
+ pause_after_download,
+ base::Bind(&ServiceWorkerVersion::OnStartMessageSent,
weak_factory_.GetWeakPtr()));
}
return;
@@ -193,6 +204,33 @@ void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
stop_callbacks_.push_back(callback);
}
+void ServiceWorkerVersion::ScheduleUpdate() {
+ if (update_timer_.IsRunning()) {
+ update_timer_.Reset();
+ return;
+ }
+ update_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(kUpdateDelaySeconds),
+ base::Bind(&ServiceWorkerVersion::StartUpdate,
+ weak_factory_.GetWeakPtr()));
+}
+
+void ServiceWorkerVersion::DeferScheduledUpdate() {
+ if (update_timer_.IsRunning())
+ update_timer_.Reset();
+}
+
+void ServiceWorkerVersion::StartUpdate() {
+ update_timer_.Stop();
+ if (!context_)
+ return;
+ ServiceWorkerRegistration* registration =
+ context_->GetLiveRegistration(registration_id_);
+ if (!registration || !registration->GetNewestVersion())
+ return;
+ context_->UpdateServiceWorker(registration);
+}
+
void ServiceWorkerVersion::SendMessage(
const IPC::Message& message, const StatusCallback& callback) {
if (running_status() != RUNNING) {
@@ -212,8 +250,7 @@ void ServiceWorkerVersion::SendMessage(
void ServiceWorkerVersion::DispatchInstallEvent(
int active_version_id,
const StatusCallback& callback) {
- DCHECK_EQ(NEW, status()) << status();
- SetStatus(INSTALLING);
+ DCHECK_EQ(INSTALLING, status()) << status();
if (running_status() != RUNNING) {
// Schedule calling this method after starting the worker.
@@ -232,8 +269,7 @@ void ServiceWorkerVersion::DispatchInstallEvent(
void ServiceWorkerVersion::DispatchActivateEvent(
const StatusCallback& callback) {
- DCHECK_EQ(INSTALLED, status()) << status();
- SetStatus(ACTIVATING);
+ DCHECK_EQ(ACTIVATING, status()) << status();
if (running_status() != RUNNING) {
// Schedule calling this method after starting the worker.
@@ -251,33 +287,38 @@ void ServiceWorkerVersion::DispatchActivateEvent(
void ServiceWorkerVersion::DispatchFetchEvent(
const ServiceWorkerFetchRequest& request,
- const FetchCallback& callback) {
- DCHECK_EQ(ACTIVE, status()) << status();
+ const base::Closure& prepare_callback,
+ const FetchCallback& fetch_callback) {
+ 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, callback),
+ base::Bind(&RunErrorFetchCallback, fetch_callback),
base::Bind(&self::DispatchFetchEvent,
weak_factory_.GetWeakPtr(),
- request, callback)));
+ request,
+ prepare_callback,
+ fetch_callback)));
return;
}
- int request_id = fetch_callbacks_.Add(new FetchCallback(callback));
+ prepare_callback.Run();
+
+ int request_id = fetch_callbacks_.Add(new FetchCallback(fetch_callback));
ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
ServiceWorkerMsg_FetchEvent(request_id, request));
if (status != SERVICE_WORKER_OK) {
fetch_callbacks_.Remove(request_id);
RunSoon(base::Bind(&RunErrorFetchCallback,
- callback,
+ fetch_callback,
SERVICE_WORKER_ERROR_FAILED));
}
}
void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
- DCHECK_EQ(ACTIVE, status()) << status();
+ DCHECK_EQ(ACTIVATED, status()) << status();
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableServiceWorkerSync)) {
@@ -306,7 +347,7 @@ void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
const std::string& data) {
- DCHECK_EQ(ACTIVE, status()) << status();
+ DCHECK_EQ(ACTIVATED, status()) << status();
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalWebPlatformFeatures)) {
@@ -333,16 +374,41 @@ void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
}
}
-void ServiceWorkerVersion::AddProcessToWorker(int process_id) {
- embedded_worker_->AddProcessReference(process_id);
-}
+void ServiceWorkerVersion::DispatchGeofencingEvent(
+ const StatusCallback& callback,
+ blink::WebGeofencingEventType event_type,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region) {
+ DCHECK_EQ(ACTIVATED, status()) << status();
-void ServiceWorkerVersion::RemoveProcessFromWorker(int process_id) {
- embedded_worker_->ReleaseProcessReference(process_id);
-}
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures)) {
+ callback.Run(SERVICE_WORKER_ERROR_ABORT);
+ return;
+ }
+
+ if (running_status() != RUNNING) {
+ // Schedule calling this method after starting the worker.
+ StartWorker(base::Bind(&RunTaskAfterStartWorker,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ base::Bind(&self::DispatchGeofencingEvent,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ event_type,
+ region_id,
+ region)));
+ return;
+ }
-bool ServiceWorkerVersion::HasProcessToRun() const {
- return embedded_worker_->HasProcessToRun();
+ int request_id = geofencing_callbacks_.Add(new StatusCallback(callback));
+ ServiceWorkerStatusCode status =
+ embedded_worker_->SendMessage(ServiceWorkerMsg_GeofencingEvent(
+ request_id, event_type, region_id, region));
+ if (status != SERVICE_WORKER_OK) {
+ geofencing_callbacks_.Remove(request_id);
+ RunSoon(base::Bind(callback, status));
+ }
}
void ServiceWorkerVersion::AddControllee(
@@ -350,7 +416,6 @@ void ServiceWorkerVersion::AddControllee(
DCHECK(!ContainsKey(controllee_map_, provider_host));
int controllee_id = controllee_by_id_.Add(provider_host);
controllee_map_[provider_host] = controllee_id;
- AddProcessToWorker(provider_host->process_id());
if (stop_worker_timer_.IsRunning())
stop_worker_timer_.Stop();
}
@@ -361,25 +426,14 @@ void ServiceWorkerVersion::RemoveControllee(
DCHECK(found != controllee_map_.end());
controllee_by_id_.Remove(found->second);
controllee_map_.erase(found);
- RemoveProcessFromWorker(provider_host->process_id());
- if (!HasControllee())
- ScheduleStopWorker();
- // TODO(kinuko): Fire NoControllees notification when the # of controllees
- // reaches 0, so that a new pending version can be activated (which will
- // deactivate this version).
- // TODO(michaeln): On no controllees call storage DeleteVersionResources
- // if this version has been deactivated. Probably storage can listen for
- // NoControllees for versions that have been deleted.
-}
-
-void ServiceWorkerVersion::AddWaitingControllee(
- ServiceWorkerProviderHost* provider_host) {
- AddProcessToWorker(provider_host->process_id());
-}
-
-void ServiceWorkerVersion::RemoveWaitingControllee(
- ServiceWorkerProviderHost* provider_host) {
- RemoveProcessFromWorker(provider_host->process_id());
+ if (HasControllee())
+ return;
+ FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
+ if (is_doomed_) {
+ DoomInternal();
+ return;
+ }
+ ScheduleStopWorker();
}
void ServiceWorkerVersion::AddListener(Listener* listener) {
@@ -390,8 +444,19 @@ void ServiceWorkerVersion::RemoveListener(Listener* listener) {
listeners_.RemoveObserver(listener);
}
+void ServiceWorkerVersion::Doom() {
+ if (is_doomed_)
+ return;
+ is_doomed_ = true;
+ if (!HasControllee())
+ DoomInternal();
+}
+
void ServiceWorkerVersion::OnStarted() {
DCHECK_EQ(RUNNING, running_status());
+ DCHECK(cache_listener_.get());
+ if (status() == ACTIVATED && !HasControllee())
+ ScheduleStopWorker();
// Fire all start callbacks.
RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
@@ -428,8 +493,16 @@ void ServiceWorkerVersion::OnStopped() {
RunIDMapCallbacks(&push_callbacks_,
&StatusCallback::Run,
MakeTuple(SERVICE_WORKER_ERROR_FAILED));
+ RunIDMapCallbacks(&geofencing_callbacks_,
+ &StatusCallback::Run,
+ MakeTuple(SERVICE_WORKER_ERROR_FAILED));
FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
+
+ // There should be no more communication from/to a stopped worker. Deleting
+ // the listener prevents any pending completion callbacks from causing
+ // messages to be sent to the stopped worker.
+ cache_listener_.reset();
}
void ServiceWorkerVersion::OnReportException(
@@ -474,6 +547,8 @@ bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
OnSyncEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
OnPushEventFinished)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished,
+ OnGeofencingEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
OnPostMessageToDocument)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -481,7 +556,7 @@ bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
return handled;
}
-void ServiceWorkerVersion::RunStartWorkerCallbacksOnError(
+void ServiceWorkerVersion::OnStartMessageSent(
ServiceWorkerStatusCode status) {
if (status != SERVICE_WORKER_OK)
RunCallbacks(this, &start_callbacks_, status);
@@ -492,6 +567,7 @@ void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
const StatusCallback& callback) {
DCHECK_EQ(RUNNING, running_status())
<< "Worker stopped too soon after it was started.";
+
int request_id = install_callbacks_.Add(new StatusCallback(callback));
ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
@@ -505,6 +581,7 @@ void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
const StatusCallback& callback) {
DCHECK_EQ(RUNNING, running_status())
<< "Worker stopped too soon after it was started.";
+
int request_id = activate_callbacks_.Add(new StatusCallback(callback));
ServiceWorkerStatusCode status =
embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
@@ -517,6 +594,8 @@ void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
std::vector<int> client_ids;
ControlleeByIDMap::iterator it(&controllee_by_id_);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerVersion::OnGetClientDocuments");
while (!it.IsAtEnd()) {
client_ids.push_back(it.GetCurrentKey());
it.Advance();
@@ -531,25 +610,34 @@ void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
void ServiceWorkerVersion::OnActivateEventFinished(
int request_id,
blink::WebServiceWorkerEventResult result) {
+ DCHECK(ACTIVATING == status() ||
+ REDUNDANT == status()) << status();
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerVersion::OnActivateEventFinished");
+
StatusCallback* callback = activate_callbacks_.Lookup(request_id);
if (!callback) {
NOTREACHED() << "Got unexpected message: " << request_id;
return;
}
- ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
- if (result == blink::WebServiceWorkerEventResultRejected)
- status = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
- else
- SetStatus(ACTIVE);
+ ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
+ if (result == blink::WebServiceWorkerEventResultRejected ||
+ status() != ACTIVATING) {
+ rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
+ }
scoped_refptr<ServiceWorkerVersion> protect(this);
- callback->Run(status);
+ callback->Run(rv);
activate_callbacks_.Remove(request_id);
}
void ServiceWorkerVersion::OnInstallEventFinished(
int request_id,
blink::WebServiceWorkerEventResult result) {
+ DCHECK_EQ(INSTALLING, status()) << status();
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerVersion::OnInstallEventFinished");
+
StatusCallback* callback = install_callbacks_.Lookup(request_id);
if (!callback) {
NOTREACHED() << "Got unexpected message: " << request_id;
@@ -558,8 +646,6 @@ void ServiceWorkerVersion::OnInstallEventFinished(
ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
if (result == blink::WebServiceWorkerEventResultRejected)
status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
- else
- SetStatus(INSTALLED);
scoped_refptr<ServiceWorkerVersion> protect(this);
callback->Run(status);
@@ -570,6 +656,9 @@ void ServiceWorkerVersion::OnFetchEventFinished(
int request_id,
ServiceWorkerFetchEventResult result,
const ServiceWorkerResponse& response) {
+ TRACE_EVENT1("ServiceWorker",
+ "ServiceWorkerVersion::OnFetchEventFinished",
+ "Request id", request_id);
FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
if (!callback) {
NOTREACHED() << "Got unexpected message: " << request_id;
@@ -583,6 +672,9 @@ void ServiceWorkerVersion::OnFetchEventFinished(
void ServiceWorkerVersion::OnSyncEventFinished(
int request_id) {
+ TRACE_EVENT1("ServiceWorker",
+ "ServiceWorkerVersion::OnSyncEventFinished",
+ "Request id", request_id);
StatusCallback* callback = sync_callbacks_.Lookup(request_id);
if (!callback) {
NOTREACHED() << "Got unexpected message: " << request_id;
@@ -596,6 +688,9 @@ void ServiceWorkerVersion::OnSyncEventFinished(
void ServiceWorkerVersion::OnPushEventFinished(
int request_id) {
+ TRACE_EVENT1("ServiceWorker",
+ "ServiceWorkerVersion::OnPushEventFinished",
+ "Request id", request_id);
StatusCallback* callback = push_callbacks_.Lookup(request_id);
if (!callback) {
NOTREACHED() << "Got unexpected message: " << request_id;
@@ -607,10 +702,29 @@ void ServiceWorkerVersion::OnPushEventFinished(
push_callbacks_.Remove(request_id);
}
+void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
+ TRACE_EVENT1("ServiceWorker",
+ "ServiceWorkerVersion::OnGeofencingEventFinished",
+ "Request id",
+ request_id);
+ StatusCallback* callback = geofencing_callbacks_.Lookup(request_id);
+ if (!callback) {
+ NOTREACHED() << "Got unexpected message: " << request_id;
+ return;
+ }
+
+ scoped_refptr<ServiceWorkerVersion> protect(this);
+ callback->Run(SERVICE_WORKER_OK);
+ geofencing_callbacks_.Remove(request_id);
+}
+
void ServiceWorkerVersion::OnPostMessageToDocument(
int client_id,
const base::string16& message,
const std::vector<int>& sent_message_port_ids) {
+ TRACE_EVENT1("ServiceWorker",
+ "ServiceWorkerVersion::OnPostMessageToDocument",
+ "Client id", client_id);
ServiceWorkerProviderHost* provider_host =
controllee_by_id_.Lookup(client_id);
if (!provider_host) {
@@ -634,4 +748,15 @@ void ServiceWorkerVersion::ScheduleStopWorker() {
base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)));
}
+void ServiceWorkerVersion::DoomInternal() {
+ DCHECK(!HasControllee());
+ SetStatus(REDUNDANT);
+ StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ if (!context_)
+ return;
+ std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
+ script_cache_map_.GetResources(&resources);
+ context_->storage()->PurgeResources(resources);
+}
+
} // namespace content
diff --git a/chromium/content/browser/service_worker/service_worker_version.h b/chromium/content/browser/service_worker/service_worker_version.h
index 0c7bda50775..0dcf9a4c912 100644
--- a/chromium/content/browser/service_worker/service_worker_version.h
+++ b/chromium/content/browser/service_worker/service_worker_version.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_VERSION_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_VERSION_H_
+#include <map>
#include <string>
#include <vector>
@@ -17,14 +18,20 @@
#include "base/observer_list.h"
#include "base/timer/timer.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
+#include "content/browser/service_worker/service_worker_cache_listener.h"
#include "content/browser/service_worker/service_worker_script_cache_map.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 "third_party/WebKit/public/platform/WebGeofencingEventType.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
class GURL;
+namespace blink {
+struct WebCircularGeofencingRegion;
+}
+
namespace content {
class EmbeddedWorkerRegistry;
@@ -36,12 +43,8 @@ class ServiceWorkerVersionInfo;
// This class corresponds to a specific version of a ServiceWorker
// script for a given pattern. When a script is upgraded, there may be
// more than one ServiceWorkerVersion "running" at a time, but only
-// one of them is active. This class connects the actual script with a
+// one of them is activated. This class connects the actual script with a
// running worker.
-//
-// is_shutdown_ detects the live-ness of the object itself. If the object is
-// shut down, then it is in the process of being deleted from memory.
-// This happens when a version is replaced as well as at browser shutdown.
class CONTENT_EXPORT ServiceWorkerVersion
: NON_EXPORTED_BASE(public base::RefCounted<ServiceWorkerVersion>),
public EmbeddedWorkerInstance::Listener {
@@ -60,39 +63,44 @@ class CONTENT_EXPORT ServiceWorkerVersion
STOPPING = EmbeddedWorkerInstance::STOPPING,
};
- // Current version status; some of the status (e.g. INSTALLED and ACTIVE)
+ // Current version status; some of the status (e.g. INSTALLED and ACTIVATED)
// should be persisted unlike running status.
enum Status {
NEW, // The version is just created.
INSTALLING, // Install event is dispatched and being handled.
INSTALLED, // Install event is finished and is ready to be activated.
ACTIVATING, // Activate event is dispatched and being handled.
- ACTIVE, // Activation is finished and can run as active.
- DEACTIVATED, // The version is no longer running as active, due to
- // unregistration or replace. (TODO(kinuko): we may need
- // different states for different termination sequences)
+ ACTIVATED, // Activation is finished and can run as activated.
+ REDUNDANT, // The version is no longer running as activated, due to
+ // unregistration or replace.
};
class Listener {
public:
- virtual void OnWorkerStarted(ServiceWorkerVersion* version) = 0;
- virtual void OnWorkerStopped(ServiceWorkerVersion* version) = 0;
- virtual void OnVersionStateChanged(ServiceWorkerVersion* version) = 0;
+ virtual void OnWorkerStarted(ServiceWorkerVersion* version) {}
+ virtual void OnWorkerStopped(ServiceWorkerVersion* version) {}
+ virtual void OnVersionStateChanged(ServiceWorkerVersion* version) {}
virtual void OnErrorReported(ServiceWorkerVersion* version,
const base::string16& error_message,
int line_number,
int column_number,
- const GURL& source_url) = 0;
+ const GURL& source_url) {}
virtual void OnReportConsoleMessage(ServiceWorkerVersion* version,
int source_identifier,
int message_level,
const base::string16& message,
int line_number,
- const GURL& source_url) = 0;
+ const GURL& source_url) {}
+ // Fires when a version transitions from having a controllee to not.
+ virtual void OnNoControllees(ServiceWorkerVersion* version) {}
+
+ protected:
+ virtual ~Listener() {}
};
ServiceWorkerVersion(
ServiceWorkerRegistration* registration,
+ const GURL& script_url,
int64 version_id,
base::WeakPtr<ServiceWorkerContextCore> context);
@@ -120,17 +128,26 @@ class CONTENT_EXPORT ServiceWorkerVersion
void StartWorker(const StatusCallback& callback);
// Starts an embedded worker for this version.
- // |potential_process_ids| is a list of processes in which to start the
- // worker.
+ // |pause_after_download| notifies worker to pause after download finished
+ // which could be resumed by EmbeddedWorkerInstance::ResumeAfterDownload.
// This returns OK (success) if the worker is already running.
- void StartWorkerWithCandidateProcesses(
- const std::vector<int>& potential_process_ids,
- const StatusCallback& callback);
+ void StartWorker(bool pause_after_download,
+ const StatusCallback& callback);
- // Starts an embedded worker for this version.
+ // Stops an embedded worker for this version.
// This returns OK (success) if the worker is already stopped.
void StopWorker(const StatusCallback& callback);
+ // Schedules an update to be run 'soon'.
+ void ScheduleUpdate();
+
+ // If an update is scheduled but not yet started, this resets the timer
+ // delaying the start time by a 'small' amount.
+ void DeferScheduledUpdate();
+
+ // Starts an update now.
+ void StartUpdate();
+
// Sends an IPC message to the worker.
// If the worker is not running this first tries to start it by
// calling StartWorker internally.
@@ -139,10 +156,10 @@ class CONTENT_EXPORT ServiceWorkerVersion
void SendMessage(const IPC::Message& message, const StatusCallback& callback);
// Sends install event to the associated embedded worker and asynchronously
- // calls |callback| when it errors out or it gets response from the worker
+ // calls |callback| when it errors out or it gets a response from the worker
// to notify install completion.
// |active_version_id| must be a valid positive ID
- // if there's an active (previous) version running.
+ // if there's an activated (previous) version running.
//
// This must be called when the status() is NEW. Calling this changes
// the version's status to INSTALLING.
@@ -152,52 +169,55 @@ class CONTENT_EXPORT ServiceWorkerVersion
const StatusCallback& callback);
// Sends activate event to the associated embedded worker and asynchronously
- // calls |callback| when it errors out or it gets response from the worker
+ // 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 ACTIVE
+ // 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 ACTIVE. Calling this in other
+ // 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 FetchCallback& callback);
+ const base::Closure& prepare_callback,
+ const FetchCallback& fetch_callback);
// Sends sync event to the associated embedded worker and asynchronously calls
- // |callback| when it errors out or it gets response from the worker to notify
- // completion.
+ // |callback| when it errors out or it gets a response from the worker to
+ // notify completion.
//
- // This must be called when the status() is ACTIVE.
+ // This must be called when the status() is ACTIVATED.
void DispatchSyncEvent(const StatusCallback& callback);
// Sends push event to the associated embedded worker and asynchronously calls
- // |callback| when it errors out or it gets response from the worker to notify
- // completion.
+ // |callback| when it errors out or it gets a response from the worker to
+ // notify completion.
//
- // This must be called when the status() is ACTIVE.
+ // This must be called when the status() is ACTIVATED.
void DispatchPushEvent(const StatusCallback& callback,
const std::string& data);
- // These are expected to be called when a renderer process host for the
- // same-origin as for this ServiceWorkerVersion is created. The added
- // processes are used to run an in-renderer embedded worker.
- void AddProcessToWorker(int process_id);
- void RemoveProcessFromWorker(int process_id);
-
- // Returns true if this has at least one process to run.
- bool HasProcessToRun() const;
+ // Sends geofencing 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 DispatchGeofencingEvent(
+ const StatusCallback& callback,
+ blink::WebGeofencingEventType event_type,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region);
// 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.
void AddControllee(ServiceWorkerProviderHost* provider_host);
void RemoveControllee(ServiceWorkerProviderHost* provider_host);
- void AddWaitingControllee(ServiceWorkerProviderHost* provider_host);
- void RemoveWaitingControllee(ServiceWorkerProviderHost* provider_host);
// Returns if it has controllee.
bool HasControllee() const { return !controllee_map_.empty(); }
@@ -209,29 +229,39 @@ class CONTENT_EXPORT ServiceWorkerVersion
ServiceWorkerScriptCacheMap* script_cache_map() { return &script_cache_map_; }
EmbeddedWorkerInstance* embedded_worker() { return embedded_worker_.get(); }
+ // Dooms this version to have REDUNDANT status and its resources deleted. If
+ // the version is controlling a page, these changes will happen when the
+ // version no longer controls any pages.
+ void Doom();
+ bool is_doomed() const { return is_doomed_; }
+
private:
+ friend class base::RefCounted<ServiceWorkerVersion>;
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerControlleeRequestHandlerTest,
+ ActivateWaitingVersion);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, ScheduleStopWorker);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionTest, ListenerAvailability);
typedef ServiceWorkerVersion self;
typedef std::map<ServiceWorkerProviderHost*, int> ControlleeMap;
typedef IDMap<ServiceWorkerProviderHost> ControlleeByIDMap;
- friend class base::RefCounted<ServiceWorkerVersion>;
- virtual ~ServiceWorkerVersion();
+ ~ServiceWorkerVersion() override;
// EmbeddedWorkerInstance::Listener overrides:
- virtual void OnStarted() OVERRIDE;
- virtual void OnStopped() OVERRIDE;
- virtual void OnReportException(const base::string16& error_message,
- int line_number,
- int column_number,
- const GURL& source_url) OVERRIDE;
- virtual void OnReportConsoleMessage(int source_identifier,
- int message_level,
- const base::string16& message,
- int line_number,
- const GURL& source_url) OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- void RunStartWorkerCallbacksOnError(ServiceWorkerStatusCode status);
+ void OnStarted() override;
+ void OnStopped() override;
+ void OnReportException(const base::string16& error_message,
+ int line_number,
+ int column_number,
+ const GURL& source_url) override;
+ void OnReportConsoleMessage(int source_identifier,
+ int message_level,
+ const base::string16& message,
+ int line_number,
+ const GURL& source_url) override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+
+ void OnStartMessageSent(ServiceWorkerStatusCode status);
void DispatchInstallEventAfterStartWorker(int active_version_id,
const StatusCallback& callback);
@@ -248,11 +278,13 @@ class CONTENT_EXPORT ServiceWorkerVersion
const ServiceWorkerResponse& response);
void OnSyncEventFinished(int request_id);
void OnPushEventFinished(int request_id);
+ void OnGeofencingEventFinished(int request_id);
void OnPostMessageToDocument(int client_id,
const base::string16& message,
const std::vector<int>& sent_message_port_ids);
void ScheduleStopWorker();
+ void DoomInternal();
const int64 version_id_;
int64 registration_id_;
@@ -260,6 +292,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
GURL scope_;
Status status_;
scoped_ptr<EmbeddedWorkerInstance> embedded_worker_;
+ scoped_ptr<ServiceWorkerCacheListener> cache_listener_;
std::vector<StatusCallback> start_callbacks_;
std::vector<StatusCallback> stop_callbacks_;
std::vector<base::Closure> status_change_callbacks_;
@@ -270,6 +303,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
IDMap<FetchCallback, IDMapOwnPointer> fetch_callbacks_;
IDMap<StatusCallback, IDMapOwnPointer> sync_callbacks_;
IDMap<StatusCallback, IDMapOwnPointer> push_callbacks_;
+ IDMap<StatusCallback, IDMapOwnPointer> geofencing_callbacks_;
ControlleeMap controllee_map_;
ControlleeByIDMap controllee_by_id_;
@@ -277,6 +311,8 @@ class CONTENT_EXPORT ServiceWorkerVersion
ObserverList<Listener> listeners_;
ServiceWorkerScriptCacheMap script_cache_map_;
base::OneShotTimer<ServiceWorkerVersion> stop_worker_timer_;
+ base::OneShotTimer<ServiceWorkerVersion> update_timer_;
+ bool is_doomed_;
base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_;
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 6622e5aba83..31225e96357 100644
--- a/chromium/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/chromium/content/browser/service_worker/service_worker_version_unittest.cc
@@ -36,11 +36,11 @@ class MessageReceiver : public EmbeddedWorkerTestHelper {
MessageReceiver()
: EmbeddedWorkerTestHelper(kRenderProcessId),
current_embedded_worker_id_(0) {}
- virtual ~MessageReceiver() {}
+ ~MessageReceiver() override {}
- virtual bool OnMessageToWorker(int thread_id,
- int embedded_worker_id,
- const IPC::Message& message) OVERRIDE {
+ bool OnMessageToWorker(int thread_id,
+ int embedded_worker_id,
+ const IPC::Message& message) override {
if (EmbeddedWorkerTestHelper::OnMessageToWorker(
thread_id, embedded_worker_id, message)) {
return true;
@@ -85,13 +85,11 @@ class MessageReceiverFromWorker : public EmbeddedWorkerInstance::Listener {
: instance_(instance) {
instance_->AddListener(this);
}
- virtual ~MessageReceiverFromWorker() {
- instance_->RemoveListener(this);
- }
+ ~MessageReceiverFromWorker() override { instance_->RemoveListener(this); }
- virtual void OnStarted() OVERRIDE { NOTREACHED(); }
- virtual void OnStopped() OVERRIDE { NOTREACHED(); }
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ void OnStarted() override { NOTREACHED(); }
+ void OnStopped() override { NOTREACHED(); }
+ bool OnMessageReceived(const IPC::Message& message) override {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(MessageReceiverFromWorker, message)
IPC_MESSAGE_HANDLER(TestMsg_MessageFromWorker, OnMessageFromWorker)
@@ -116,24 +114,31 @@ class ServiceWorkerVersionTest : public testing::Test {
ServiceWorkerVersionTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
- virtual void SetUp() OVERRIDE {
- helper_.reset(new MessageReceiver());
+ void SetUp() override {
+ helper_ = GetMessageReceiver();
+ pattern_ = GURL("http://www.example.com/");
registration_ = new ServiceWorkerRegistration(
- GURL("http://www.example.com/*"),
- GURL("http://www.example.com/service_worker.js"),
+ pattern_,
1L,
helper_->context()->AsWeakPtr());
version_ = new ServiceWorkerVersion(
- registration_, 1L, helper_->context()->AsWeakPtr());
+ registration_.get(),
+ GURL("http://www.example.com/service_worker.js"),
+ 1L,
+ helper_->context()->AsWeakPtr());
+
+ // Simulate adding one process to the pattern.
+ helper_->SimulateAddProcessToPattern(pattern_, kRenderProcessId);
+ ASSERT_TRUE(helper_->context()->process_manager()
+ ->PatternHasProcessToRun(pattern_));
+ }
- // Simulate adding one process to the worker.
- int embedded_worker_id = version_->embedded_worker()->embedded_worker_id();
- helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId);
- ASSERT_TRUE(version_->HasProcessToRun());
+ virtual scoped_ptr<MessageReceiver> GetMessageReceiver() {
+ return make_scoped_ptr(new MessageReceiver());
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
version_ = 0;
registration_ = 0;
helper_.reset();
@@ -143,9 +148,43 @@ class ServiceWorkerVersionTest : public testing::Test {
scoped_ptr<MessageReceiver> helper_;
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
+ GURL pattern_;
+
+ private:
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersionTest);
};
+class MessageReceiverDisallowStart : public MessageReceiver {
+ public:
+ MessageReceiverDisallowStart()
+ : MessageReceiver() {}
+ ~MessageReceiverDisallowStart() override {}
+
+ void OnStartWorker(int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& scope,
+ const GURL& script_url,
+ bool pause_after_download) override {
+ // Do nothing.
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MessageReceiverDisallowStart);
+};
+
+class ServiceWorkerFailToStartTest : public ServiceWorkerVersionTest {
+ protected:
+ ServiceWorkerFailToStartTest()
+ : ServiceWorkerVersionTest() {}
+
+ virtual scoped_ptr<MessageReceiver> GetMessageReceiver() override {
+ return make_scoped_ptr(new MessageReceiverDisallowStart());
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ServiceWorkerFailToStartTest);
+};
+
TEST_F(ServiceWorkerVersionTest, ConcurrentStartAndStop) {
// Call StartWorker() multiple times.
ServiceWorkerStatusCode status1 = SERVICE_WORKER_ERROR_FAILED;
@@ -261,7 +300,7 @@ TEST_F(ServiceWorkerVersionTest, ReceiveMessageFromWorker) {
}
TEST_F(ServiceWorkerVersionTest, InstallAndWaitCompletion) {
- EXPECT_EQ(ServiceWorkerVersion::NEW, version_->status());
+ version_->SetStatus(ServiceWorkerVersion::INSTALLING);
// Dispatch an install event.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
@@ -274,16 +313,14 @@ TEST_F(ServiceWorkerVersionTest, InstallAndWaitCompletion) {
base::RunLoop().RunUntilIdle();
- // After successful completion, version's status must be changed to
- // INSTALLED, and status change callback must have been fired.
+ // Version's status must not have changed during installation.
EXPECT_EQ(SERVICE_WORKER_OK, status);
- EXPECT_TRUE(status_change_called);
- EXPECT_EQ(ServiceWorkerVersion::INSTALLED, version_->status());
+ EXPECT_FALSE(status_change_called);
+ EXPECT_EQ(ServiceWorkerVersion::INSTALLING, version_->status());
}
TEST_F(ServiceWorkerVersionTest, ActivateAndWaitCompletion) {
- version_->SetStatus(ServiceWorkerVersion::INSTALLED);
- EXPECT_EQ(ServiceWorkerVersion::INSTALLED, version_->status());
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
// Dispatch an activate event.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
@@ -296,11 +333,10 @@ TEST_F(ServiceWorkerVersionTest, ActivateAndWaitCompletion) {
base::RunLoop().RunUntilIdle();
- // After successful completion, version's status must be changed to
- // ACTIVE, and status change callback must have been fired.
+ // Version's status must not have changed during activation.
EXPECT_EQ(SERVICE_WORKER_OK, status);
- EXPECT_TRUE(status_change_called);
- EXPECT_EQ(ServiceWorkerVersion::ACTIVE, version_->status());
+ EXPECT_FALSE(status_change_called);
+ EXPECT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
}
TEST_F(ServiceWorkerVersionTest, RepeatedlyObserveStatusChanges) {
@@ -311,45 +347,109 @@ TEST_F(ServiceWorkerVersionTest, RepeatedlyObserveStatusChanges) {
version_->RegisterStatusChangeCallback(
base::Bind(&ObserveStatusChanges, version_, &statuses));
- // Dispatch some events.
+ version_->SetStatus(ServiceWorkerVersion::INSTALLING);
+ version_->SetStatus(ServiceWorkerVersion::INSTALLED);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ version_->SetStatus(ServiceWorkerVersion::REDUNDANT);
+
+ // Verify that we could successfully observe repeated status changes.
+ ASSERT_EQ(5U, statuses.size());
+ ASSERT_EQ(ServiceWorkerVersion::INSTALLING, statuses[0]);
+ ASSERT_EQ(ServiceWorkerVersion::INSTALLED, statuses[1]);
+ ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, statuses[2]);
+ ASSERT_EQ(ServiceWorkerVersion::ACTIVATED, statuses[3]);
+ ASSERT_EQ(ServiceWorkerVersion::REDUNDANT, statuses[4]);
+}
+
+TEST_F(ServiceWorkerVersionTest, ScheduleStopWorker) {
+ // Verify the timer is not running when version initializes its status.
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ EXPECT_FALSE(version_->stop_worker_timer_.IsRunning());
+
+ // Verify the timer is running when version status changes frome ACTIVATING
+ // to ACTIVATED.
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
- version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
+ version_->StartWorker(CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ EXPECT_TRUE(version_->stop_worker_timer_.IsRunning());
+ // The timer should be running if the worker is restarted without controllee.
status = SERVICE_WORKER_ERROR_FAILED;
- version_->DispatchActivateEvent(CreateReceiverOnCurrentThread(&status));
+ version_->StopWorker(CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
+ status = SERVICE_WORKER_ERROR_FAILED;
+ version_->StartWorker(CreateReceiverOnCurrentThread(&status));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(SERVICE_WORKER_OK, status);
+ EXPECT_TRUE(version_->stop_worker_timer_.IsRunning());
+
+ // The timer should not be running if a controllee is added.
+ scoped_ptr<ServiceWorkerProviderHost> host(
+ new ServiceWorkerProviderHost(33 /* dummy render process id */,
+ 1 /* dummy provider_id */,
+ helper_->context()->AsWeakPtr(),
+ NULL));
+ version_->AddControllee(host.get());
+ EXPECT_FALSE(version_->stop_worker_timer_.IsRunning());
+
+ // The timer should be running if the controllee is removed.
+ version_->RemoveControllee(host.get());
+ EXPECT_TRUE(version_->stop_worker_timer_.IsRunning());
+}
- // Verify that we could successfully observe repeated status changes.
- ASSERT_EQ(4U, statuses.size());
- ASSERT_EQ(ServiceWorkerVersion::INSTALLING, statuses[0]);
- ASSERT_EQ(ServiceWorkerVersion::INSTALLED, statuses[1]);
- ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, statuses[2]);
- ASSERT_EQ(ServiceWorkerVersion::ACTIVE, statuses[3]);
+TEST_F(ServiceWorkerVersionTest, ListenerAvailability) {
+ // Initially the worker is not running. There should be no cache_listener_.
+ EXPECT_FALSE(version_->cache_listener_.get());
+
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ version_->StartWorker(
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+
+ // A new cache listener should be available once the worker starts.
+ EXPECT_TRUE(version_->cache_listener_.get());
+
+ version_->StopWorker(
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+
+ // Should be destroyed when the worker stops.
+ EXPECT_FALSE(version_->cache_listener_.get());
+
+ version_->StartWorker(
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+
+ // Recreated when the worker starts again.
+ EXPECT_TRUE(version_->cache_listener_.get());
}
-TEST_F(ServiceWorkerVersionTest, AddAndRemoveProcesses) {
- // Preparation (to reset the process count to 0).
- ASSERT_TRUE(version_->HasProcessToRun());
- version_->RemoveProcessFromWorker(kRenderProcessId);
- ASSERT_FALSE(version_->HasProcessToRun());
-
- // Add another process to the worker twice, and then remove process once.
- const int another_process_id = kRenderProcessId + 1;
- version_->AddProcessToWorker(another_process_id);
- version_->AddProcessToWorker(another_process_id);
- version_->RemoveProcessFromWorker(another_process_id);
-
- // We're ref-counting the process internally, so adding the same process
- // multiple times should be handled correctly.
- ASSERT_TRUE(version_->HasProcessToRun());
-
- // Removing the process again (so that # of AddProcess == # of RemoveProcess
- // for the process) should remove all process references.
- version_->RemoveProcessFromWorker(another_process_id);
- ASSERT_FALSE(version_->HasProcessToRun());
+TEST_F(ServiceWorkerFailToStartTest, RendererCrash) {
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_NETWORK; // dummy value
+ version_->StartWorker(
+ CreateReceiverOnCurrentThread(&status));
+ base::RunLoop().RunUntilIdle();
+
+ // Callback has not completed yet.
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NETWORK, status);
+ EXPECT_EQ(ServiceWorkerVersion::STARTING, version_->running_status());
+
+ // Simulate renderer crash: do what
+ // ServiceWorkerDispatcherHost::OnFilterRemoved does.
+ int process_id = helper_->mock_render_process_id();
+ helper_->context()->RemoveAllProviderHostsForProcess(process_id);
+ helper_->context()->embedded_worker_registry()->RemoveChildProcessSender(
+ process_id);
+ base::RunLoop().RunUntilIdle();
+
+ // Callback completed.
+ EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
+ EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_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 bd16a132004..0baf702a259 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
@@ -4,11 +4,13 @@
#include "content/browser/service_worker/service_worker_write_to_cache_job.h"
+#include "base/debug/trace_event.h"
#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_histograms.h"
+#include "content/browser/service_worker/service_worker_metrics.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/http/http_network_session.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
@@ -21,10 +23,13 @@ namespace content {
ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
+ ResourceType resource_type,
base::WeakPtr<ServiceWorkerContextCore> context,
ServiceWorkerVersion* version,
+ int extra_load_flags,
int64 response_id)
: net::URLRequestJob(request, network_delegate),
+ resource_type_(resource_type),
context_(context),
url_(request->url()),
response_id_(response_id),
@@ -33,7 +38,7 @@ ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob(
did_notify_started_(false),
did_notify_finished_(false),
weak_factory_(this) {
- InitNetRequest();
+ InitNetRequest(extra_load_flags);
}
ServiceWorkerWriteToCacheJob::~ServiceWorkerWriteToCacheJob() {
@@ -41,6 +46,10 @@ ServiceWorkerWriteToCacheJob::~ServiceWorkerWriteToCacheJob() {
}
void ServiceWorkerWriteToCacheJob::Start() {
+ TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::ExecutingJob",
+ this,
+ "URL", request_->url().spec());
if (!context_) {
NotifyStartError(net::URLRequestStatus(
net::URLRequestStatus::FAILED, net::ERR_FAILED));
@@ -60,7 +69,9 @@ void ServiceWorkerWriteToCacheJob::Kill() {
net_request_.reset();
if (did_notify_started_ && !did_notify_finished_) {
version_->script_cache_map()->NotifyFinishedCaching(
- url_, false);
+ url_,
+ -1,
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_ABORTED));
did_notify_finished_ = true;
}
writer_.reset();
@@ -120,7 +131,7 @@ bool ServiceWorkerWriteToCacheJob::ReadRawData(
// No more data to process, the job is complete.
io_buffer_ = NULL;
version_->script_cache_map()->NotifyFinishedCaching(
- url_, status.is_success());
+ url_, writer_->amount_written(), status);
did_notify_finished_ = true;
return status.is_success();
}
@@ -129,7 +140,8 @@ const net::HttpResponseInfo* ServiceWorkerWriteToCacheJob::http_info() const {
return http_info_.get();
}
-void ServiceWorkerWriteToCacheJob::InitNetRequest() {
+void ServiceWorkerWriteToCacheJob::InitNetRequest(
+ int extra_load_flags) {
DCHECK(request());
net_request_ = request()->context()->CreateRequest(
request()->url(),
@@ -139,10 +151,21 @@ void ServiceWorkerWriteToCacheJob::InitNetRequest() {
net_request_->set_first_party_for_cookies(
request()->first_party_for_cookies());
net_request_->SetReferrer(request()->referrer());
- net_request_->SetExtraRequestHeaders(request()->extra_request_headers());
+ if (extra_load_flags)
+ net_request_->SetLoadFlags(net_request_->load_flags() | extra_load_flags);
+
+ if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER) {
+ // This will get copied into net_request_ when URLRequest::StartJob calls
+ // ServiceWorkerWriteToCacheJob::SetExtraRequestHeaders.
+ request()->SetExtraRequestHeaderByName("Service-Worker", "script", true);
+ }
}
void ServiceWorkerWriteToCacheJob::StartNetRequest() {
+ TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::ExecutingJob",
+ this,
+ "NetRequest");
net_request_->Start(); // We'll continue in OnResponseStarted.
}
@@ -179,11 +202,15 @@ void ServiceWorkerWriteToCacheJob::WriteHeadersToCache() {
net::URLRequestStatus::FAILED, net::ERR_FAILED));
return;
}
+ TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::ExecutingJob",
+ this,
+ "WriteHeadersToCache");
writer_ = context_->storage()->CreateResponseWriter(response_id_);
info_buffer_ = new HttpResponseInfoIOBuffer(
new net::HttpResponseInfo(net_request_->response_info()));
writer_->WriteInfo(
- info_buffer_,
+ info_buffer_.get(),
base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete,
weak_factory_.GetWeakPtr()));
SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
@@ -192,22 +219,32 @@ void ServiceWorkerWriteToCacheJob::WriteHeadersToCache() {
void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(int result) {
SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
if (result < 0) {
- ServiceWorkerHistograms::CountWriteResponseResult(
- ServiceWorkerHistograms::WRITE_HEADERS_ERROR);
+ ServiceWorkerMetrics::CountWriteResponseResult(
+ ServiceWorkerMetrics::WRITE_HEADERS_ERROR);
AsyncNotifyDoneHelper(net::URLRequestStatus(
net::URLRequestStatus::FAILED, result));
return;
}
http_info_.reset(info_buffer_->http_info.release());
info_buffer_ = NULL;
+ TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::ExecutingJob",
+ this,
+ "WriteHeadersToCacheCompleted");
NotifyHeadersComplete();
}
void ServiceWorkerWriteToCacheJob::WriteDataToCache(int amount_to_write) {
DCHECK_NE(0, amount_to_write);
+ TRACE_EVENT_ASYNC_STEP_INTO1("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::ExecutingJob",
+ this,
+ "WriteDataToCache",
+ "Amount to write", amount_to_write);
SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
writer_->WriteData(
- io_buffer_, amount_to_write,
+ io_buffer_.get(),
+ amount_to_write,
base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete,
weak_factory_.GetWeakPtr()));
}
@@ -221,32 +258,39 @@ void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(int result) {
return;
}
if (result < 0) {
- ServiceWorkerHistograms::CountWriteResponseResult(
- ServiceWorkerHistograms::WRITE_DATA_ERROR);
+ ServiceWorkerMetrics::CountWriteResponseResult(
+ ServiceWorkerMetrics::WRITE_DATA_ERROR);
AsyncNotifyDoneHelper(net::URLRequestStatus(
net::URLRequestStatus::FAILED, result));
return;
}
- ServiceWorkerHistograms::CountWriteResponseResult(
- ServiceWorkerHistograms::WRITE_OK);
+ ServiceWorkerMetrics::CountWriteResponseResult(
+ ServiceWorkerMetrics::WRITE_OK);
SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
NotifyReadComplete(result);
+ TRACE_EVENT_ASYNC_END0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::ExecutingJob",
+ this);
}
void ServiceWorkerWriteToCacheJob::OnReceivedRedirect(
net::URLRequest* request,
- const GURL& new_url,
+ const net::RedirectInfo& redirect_info,
bool* defer_redirect) {
DCHECK_EQ(net_request_, request);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::OnReceivedRedirect");
// Script resources can't redirect.
AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_FAILED));
+ net::URLRequestStatus::FAILED, net::ERR_UNSAFE_REDIRECT));
}
void ServiceWorkerWriteToCacheJob::OnAuthRequired(
net::URLRequest* request,
net::AuthChallengeInfo* auth_info) {
DCHECK_EQ(net_request_, request);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::OnAuthRequired");
// TODO(michaeln): Pass this thru to our jobs client.
AsyncNotifyDoneHelper(net::URLRequestStatus(
net::URLRequestStatus::FAILED, net::ERR_FAILED));
@@ -256,27 +300,33 @@ void ServiceWorkerWriteToCacheJob::OnCertificateRequested(
net::URLRequest* request,
net::SSLCertRequestInfo* cert_request_info) {
DCHECK_EQ(net_request_, request);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::OnCertificateRequested");
// TODO(michaeln): Pass this thru to our jobs client.
// see NotifyCertificateRequested.
AsyncNotifyDoneHelper(net::URLRequestStatus(
net::URLRequestStatus::FAILED, net::ERR_FAILED));
}
-void ServiceWorkerWriteToCacheJob:: OnSSLCertificateError(
+void ServiceWorkerWriteToCacheJob::OnSSLCertificateError(
net::URLRequest* request,
const net::SSLInfo& ssl_info,
bool fatal) {
DCHECK_EQ(net_request_, request);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::OnSSLCertificateError");
// TODO(michaeln): Pass this thru to our jobs client,
// see NotifySSLCertificateError.
AsyncNotifyDoneHelper(net::URLRequestStatus(
- net::URLRequestStatus::FAILED, net::ERR_FAILED));
+ net::URLRequestStatus::FAILED, net::ERR_INSECURE_RESPONSE));
}
void ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart(
net::URLRequest* request,
bool* defer) {
DCHECK_EQ(net_request_, request);
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerWriteToCacheJob::OnBeforeNetworkStart");
NotifyBeforeNetworkStart(defer);
}
@@ -294,6 +344,29 @@ void ServiceWorkerWriteToCacheJob::OnResponseStarted(
// response to our consumer, just don't cache it?
return;
}
+ // OnSSLCertificateError is not called when the HTTPS connection is reused.
+ // So we check cert_status here.
+ if (net::IsCertStatusError(request->ssl_info().cert_status)) {
+ const net::HttpNetworkSession::Params* session_params =
+ request->context()->GetNetworkSessionParams();
+ if (!session_params || !session_params->ignore_certificate_errors) {
+ AsyncNotifyDoneHelper(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+ net::ERR_INSECURE_RESPONSE));
+ return;
+ }
+ }
+ // To prevent most user-uploaded content from being used as a serviceworker.
+ if (version_->script_url() == url_) {
+ std::string mime_type;
+ request->GetMimeType(&mime_type);
+ if (mime_type != "application/x-javascript" &&
+ mime_type != "text/javascript" &&
+ mime_type != "application/javascript") {
+ AsyncNotifyDoneHelper(net::URLRequestStatus(
+ net::URLRequestStatus::FAILED, net::ERR_INSECURE_RESPONSE));
+ return;
+ }
+ }
WriteHeadersToCache();
}
@@ -301,7 +374,8 @@ void ServiceWorkerWriteToCacheJob::OnReadCompleted(
net::URLRequest* request,
int bytes_read) {
DCHECK_EQ(net_request_, request);
- if (!request->status().is_success()) {
+ if (bytes_read < 0) {
+ DCHECK(!request->status().is_success());
AsyncNotifyDoneHelper(request->status());
return;
}
@@ -309,16 +383,25 @@ void ServiceWorkerWriteToCacheJob::OnReadCompleted(
WriteDataToCache(bytes_read);
return;
}
- // We're done with all.
- AsyncNotifyDoneHelper(request->status());
- return;
+ // No more data to process, the job is complete.
+ DCHECK(request->status().is_success());
+ io_buffer_ = NULL;
+ version_->script_cache_map()->NotifyFinishedCaching(
+ url_, writer_->amount_written(), net::URLRequestStatus());
+ did_notify_finished_ = true;
+ SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
+ NotifyReadComplete(0);
}
void ServiceWorkerWriteToCacheJob::AsyncNotifyDoneHelper(
const net::URLRequestStatus& status) {
DCHECK(!status.is_io_pending());
- version_->script_cache_map()->NotifyFinishedCaching(
- url_, status.is_success());
+ DCHECK(!did_notify_finished_);
+ int size = -1;
+ if (writer_.get()) {
+ size = writer_->amount_written();
+ }
+ version_->script_cache_map()->NotifyFinishedCaching(url_, size, status);
did_notify_finished_ = true;
SetStatus(status);
NotifyDone(status);
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 040df41b4c6..ec3bfa7464b 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
@@ -5,12 +5,15 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_WRITE_TO_CACHE_JOB_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_WRITE_TO_CACHE_JOB_H_
+#include <string>
+
#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_disk_cache.h"
#include "content/browser/service_worker/service_worker_version.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"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_job.h"
@@ -34,32 +37,36 @@ class CONTENT_EXPORT ServiceWorkerWriteToCacheJob
ServiceWorkerWriteToCacheJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
+ ResourceType resource_type,
base::WeakPtr<ServiceWorkerContextCore> context,
ServiceWorkerVersion* version,
+ int extra_load_flags,
int64 response_id);
private:
- virtual ~ServiceWorkerWriteToCacheJob();
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
+ UpdateBefore24Hours);
+ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
+ UpdateAfter24Hours);
+
+ ~ServiceWorkerWriteToCacheJob() override;
// net::URLRequestJob overrides
- virtual void Start() OVERRIDE;
- virtual void Kill() OVERRIDE;
- virtual net::LoadState GetLoadState() const OVERRIDE;
- virtual bool GetCharset(std::string* charset) OVERRIDE;
- virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
- virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE;
- virtual int GetResponseCode() const OVERRIDE;
- virtual void SetExtraRequestHeaders(
- const net::HttpRequestHeaders& headers) OVERRIDE;
- virtual bool ReadRawData(net::IOBuffer* buf,
- int buf_size,
- int *bytes_read) OVERRIDE;
+ void Start() override;
+ void Kill() override;
+ net::LoadState GetLoadState() const override;
+ bool GetCharset(std::string* charset) override;
+ 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;
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
const net::HttpResponseInfo* http_info() const;
// Methods to drive the net request forward and
// write data to the disk cache.
- void InitNetRequest();
+ void InitNetRequest(int extra_load_flags);
void StartNetRequest();
net::URLRequestStatus ReadNetData(
net::IOBuffer* buf,
@@ -71,30 +78,24 @@ class CONTENT_EXPORT ServiceWorkerWriteToCacheJob
void OnWriteDataComplete(int result);
// net::URLRequest::Delegate overrides that observe the net request.
- virtual void OnReceivedRedirect(
- net::URLRequest* request,
- const GURL& new_url,
- bool* defer_redirect) OVERRIDE;
- virtual void OnAuthRequired(
- net::URLRequest* request,
- net::AuthChallengeInfo* auth_info) OVERRIDE;
- virtual void OnCertificateRequested(
- net::URLRequest* request,
- net::SSLCertRequestInfo* cert_request_info) OVERRIDE;
- virtual void OnSSLCertificateError(
- net::URLRequest* request,
- const net::SSLInfo& ssl_info,
- bool fatal) OVERRIDE;
- virtual void OnBeforeNetworkStart(
- net::URLRequest* request,
- bool* defer) OVERRIDE;
- virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
- virtual void OnReadCompleted(
+ void OnReceivedRedirect(net::URLRequest* request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) override;
+ void OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info) override;
+ void OnCertificateRequested(
net::URLRequest* request,
- int bytes_read) OVERRIDE;
+ net::SSLCertRequestInfo* cert_request_info) override;
+ void OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) override;
+ void OnBeforeNetworkStart(net::URLRequest* request, bool* defer) override;
+ void OnResponseStarted(net::URLRequest* request) override;
+ void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
void AsyncNotifyDoneHelper(const net::URLRequestStatus& status);
+ ResourceType resource_type_; // Differentiate main script and imports
scoped_refptr<net::IOBuffer> io_buffer_;
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
base::WeakPtr<ServiceWorkerContextCore> context_;
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
new file mode 100644
index 00000000000..7c6ad3282a7
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -0,0 +1,300 @@
+// 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 "base/run_loop.h"
+#include "content/browser/fileapi/mock_url_request_delegate.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_request_handler.h"
+#include "content/browser/service_worker/service_worker_provider_host.h"
+#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_utils.h"
+#include "content/common/resource_request_body.h"
+#include "content/public/test/mock_resource_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+int kMockRenderProcessId = 1224;
+int kMockProviderId = 1;
+const char kHeaders[] =
+ "HTTP/1.1 200 OK\0"
+ "Content-Type: text/javascript\0"
+ "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
+ "\0";
+const char kScriptCode[] = "// no script code\n";
+
+void EmptyCallback() {
+}
+
+net::URLRequestJob* CreateNormalURLRequestJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) {
+ return new net::URLRequestTestJob(request,
+ network_delegate,
+ std::string(kHeaders, arraysize(kHeaders)),
+ kScriptCode,
+ true);
+}
+
+net::URLRequestJob* CreateInvalidMimeTypeJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) {
+ const char kPlainTextHeaders[] =
+ "HTTP/1.1 200 OK\0"
+ "Content-Type: text/plain\0"
+ "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
+ "\0";
+ return new net::URLRequestTestJob(
+ request,
+ network_delegate,
+ std::string(kPlainTextHeaders, arraysize(kPlainTextHeaders)),
+ kScriptCode,
+ true);
+}
+
+class SSLCertificateErrorJob : public net::URLRequestTestJob {
+ public:
+ SSLCertificateErrorJob(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),
+ weak_factory_(this) {}
+ void Start() override {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&SSLCertificateErrorJob::NotifyError,
+ weak_factory_.GetWeakPtr()));
+ }
+ void NotifyError() {
+ net::SSLInfo info;
+ info.cert_status = net::CERT_STATUS_DATE_INVALID;
+ NotifySSLCertificateError(info, true);
+ }
+
+ protected:
+ ~SSLCertificateErrorJob() override {}
+ base::WeakPtrFactory<SSLCertificateErrorJob> weak_factory_;
+};
+
+net::URLRequestJob* CreateSSLCertificateErrorJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) {
+ return new SSLCertificateErrorJob(request,
+ network_delegate,
+ std::string(kHeaders, arraysize(kHeaders)),
+ kScriptCode,
+ true);
+}
+
+class CertStatusErrorJob : public net::URLRequestTestJob {
+ public:
+ CertStatusErrorJob(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 {
+ URLRequestTestJob::GetResponseInfo(info);
+ info->ssl_info.cert_status = net::CERT_STATUS_DATE_INVALID;
+ }
+
+ protected:
+ ~CertStatusErrorJob() override {}
+};
+
+net::URLRequestJob* CreateCertStatusErrorJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) {
+ return new CertStatusErrorJob(request,
+ network_delegate,
+ std::string(kHeaders, arraysize(kHeaders)),
+ kScriptCode,
+ true);
+}
+
+class MockHttpProtocolHandler
+ : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+ typedef base::Callback<
+ net::URLRequestJob*(net::URLRequest*, net::NetworkDelegate*)> JobCallback;
+
+ MockHttpProtocolHandler(ResourceContext* resource_context)
+ : resource_context_(resource_context) {}
+ ~MockHttpProtocolHandler() override {}
+
+ net::URLRequestJob* MaybeCreateJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ ServiceWorkerRequestHandler* handler =
+ ServiceWorkerRequestHandler::GetHandler(request);
+ if (handler) {
+ return handler->MaybeCreateJob(
+ request, network_delegate, resource_context_);
+ }
+ return create_job_callback_.Run(request, network_delegate);
+ }
+ void SetCreateJobCallback(const JobCallback& callback) {
+ create_job_callback_ = callback;
+ }
+
+ private:
+ ResourceContext* resource_context_;
+ JobCallback create_job_callback_;
+};
+}
+
+class ServiceWorkerWriteToCacheJobTest : public testing::Test {
+ public:
+ ServiceWorkerWriteToCacheJobTest()
+ : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ mock_protocol_handler_(NULL) {}
+ ~ServiceWorkerWriteToCacheJobTest() override {}
+
+ void SetUp() override {
+ helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
+
+ // A new unstored registration/version.
+ scope_ = GURL("https://host/scope/");
+ script_url_ = GURL("https://host/script.js");
+ registration_ =
+ new ServiceWorkerRegistration(scope_, 1L, context()->AsWeakPtr());
+ version_ = new ServiceWorkerVersion(
+ registration_.get(), script_url_, 1L, context()->AsWeakPtr());
+
+ // An empty host.
+ scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
+ kMockRenderProcessId, kMockProviderId, context()->AsWeakPtr(), NULL));
+ provider_host_ = host->AsWeakPtr();
+ context()->AddProviderHost(host.Pass());
+ provider_host_->running_hosted_version_ = version_;
+
+ context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
+ base::RunLoop().RunUntilIdle();
+
+ url_request_context_.reset(new net::URLRequestContext);
+ mock_protocol_handler_ = new MockHttpProtocolHandler(&resource_context_);
+ url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl);
+ url_request_job_factory_->SetProtocolHandler("https",
+ mock_protocol_handler_);
+ url_request_context_->set_job_factory(url_request_job_factory_.get());
+
+ request_ = url_request_context_->CreateRequest(
+ script_url_, net::DEFAULT_PRIORITY, &url_request_delegate_, NULL);
+ ServiceWorkerRequestHandler::InitializeHandler(
+ request_.get(),
+ context_wrapper(),
+ &blob_storage_context_,
+ kMockRenderProcessId,
+ kMockProviderId,
+ false,
+ FETCH_REQUEST_MODE_NO_CORS,
+ FETCH_CREDENTIALS_MODE_OMIT,
+ RESOURCE_TYPE_SERVICE_WORKER,
+ REQUEST_CONTEXT_TYPE_SERVICE_WORKER,
+ REQUEST_CONTEXT_FRAME_TYPE_NONE,
+ scoped_refptr<ResourceRequestBody>());
+ }
+
+ void TearDown() override {
+ request_.reset();
+ url_request_context_.reset();
+ url_request_job_factory_.reset();
+ mock_protocol_handler_ = NULL;
+ version_ = NULL;
+ registration_ = NULL;
+ helper_.reset();
+ // URLRequestJobs may post clean-up tasks on destruction.
+ base::RunLoop().RunUntilIdle();
+ }
+
+ ServiceWorkerContextCore* context() const { return helper_->context(); }
+ ServiceWorkerContextWrapper* context_wrapper() const {
+ return helper_->context_wrapper();
+ }
+
+ protected:
+ TestBrowserThreadBundle browser_thread_bundle_;
+ scoped_ptr<EmbeddedWorkerTestHelper> helper_;
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_refptr<ServiceWorkerVersion> version_;
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
+ scoped_ptr<net::URLRequestContext> url_request_context_;
+ scoped_ptr<net::URLRequestJobFactoryImpl> url_request_job_factory_;
+ scoped_ptr<net::URLRequest> request_;
+ MockHttpProtocolHandler* mock_protocol_handler_;
+
+ storage::BlobStorageContext blob_storage_context_;
+ content::MockResourceContext resource_context_;
+
+ MockURLRequestDelegate url_request_delegate_;
+ GURL scope_;
+ GURL script_url_;
+};
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Normal) {
+ mock_protocol_handler_->SetCreateJobCallback(
+ base::Bind(&CreateNormalURLRequestJob));
+ request_->Start();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(net::URLRequestStatus::SUCCESS, request_->status().status());
+ EXPECT_NE(kInvalidServiceWorkerResponseId,
+ version_->script_cache_map()->LookupResourceId(script_url_));
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, InvalidMimeType) {
+ mock_protocol_handler_->SetCreateJobCallback(
+ base::Bind(&CreateInvalidMimeTypeJob));
+ request_->Start();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(net::URLRequestStatus::FAILED, request_->status().status());
+ EXPECT_EQ(net::ERR_INSECURE_RESPONSE, request_->status().error());
+ EXPECT_EQ(kInvalidServiceWorkerResponseId,
+ version_->script_cache_map()->LookupResourceId(script_url_));
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, SSLCertificateError) {
+ mock_protocol_handler_->SetCreateJobCallback(
+ base::Bind(&CreateSSLCertificateErrorJob));
+ request_->Start();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(net::URLRequestStatus::FAILED, request_->status().status());
+ EXPECT_EQ(net::ERR_INSECURE_RESPONSE, request_->status().error());
+ EXPECT_EQ(kInvalidServiceWorkerResponseId,
+ version_->script_cache_map()->LookupResourceId(script_url_));
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, CertStatusError) {
+ mock_protocol_handler_->SetCreateJobCallback(
+ base::Bind(&CreateCertStatusErrorJob));
+ request_->Start();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(net::URLRequestStatus::FAILED, request_->status().status());
+ EXPECT_EQ(net::ERR_INSECURE_RESPONSE, request_->status().error());
+ EXPECT_EQ(kInvalidServiceWorkerResponseId,
+ version_->script_cache_map()->LookupResourceId(script_url_));
+}
+
+} // namespace content
diff --git a/chromium/content/browser/session_history_browsertest.cc b/chromium/content/browser/session_history_browsertest.cc
index 4465510ec38..2d81581ee99 100644
--- a/chromium/content/browser/session_history_browsertest.cc
+++ b/chromium/content/browser/session_history_browsertest.cc
@@ -38,7 +38,7 @@ scoped_ptr<net::test_server::HttpResponse> HandleEchoTitleRequest(
base::StringPrintf(
"<html><head><title>%s</title></head></html>",
request.content.c_str()));
- return http_response.PassAs<net::test_server::HttpResponse>();
+ return http_response.Pass();
}
} // namespace
@@ -47,7 +47,7 @@ class SessionHistoryTest : public ContentBrowserTest {
protected:
SessionHistoryTest() {}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
embedded_test_server()->RegisterRequestHandler(
base::Bind(&HandleEchoTitleRequest, "/echotitle"));
diff --git a/chromium/content/browser/shared_worker/shared_worker_host.cc b/chromium/content/browser/shared_worker/shared_worker_host.cc
index 9fc9d67ec3a..40499930675 100644
--- a/chromium/content/browser/shared_worker/shared_worker_host.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_host.cc
@@ -12,7 +12,7 @@
#include "content/browser/shared_worker/shared_worker_instance.h"
#include "content/browser/shared_worker/shared_worker_message_filter.h"
#include "content/browser/shared_worker/shared_worker_service_impl.h"
-#include "content/browser/worker_host/worker_document_set.h"
+#include "content/browser/shared_worker/worker_document_set.h"
#include "content/common/view_messages.h"
#include "content/common/worker_messages.h"
#include "content/public/browser/browser_thread.h"
@@ -31,16 +31,17 @@ void WorkerCrashCallback(int render_process_unique_id, int render_frame_id) {
host->delegate()->WorkerCrashed(host);
}
-void NotifyWorkerContextStarted(int worker_process_id, int worker_route_id) {
+void NotifyWorkerReadyForInspection(int worker_process_id,
+ int worker_route_id) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::PostTask(
- BrowserThread::UI,
- FROM_HERE,
- base::Bind(
- NotifyWorkerContextStarted, worker_process_id, worker_route_id));
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(NotifyWorkerReadyForInspection,
+ worker_process_id,
+ worker_route_id));
return;
}
- EmbeddedWorkerDevToolsManager::GetInstance()->WorkerContextStarted(
+ EmbeddedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
worker_process_id, worker_route_id);
}
@@ -68,7 +69,8 @@ SharedWorkerHost::SharedWorkerHost(SharedWorkerInstance* instance,
worker_route_id_(worker_route_id),
load_failed_(false),
closed_(false),
- creation_time_(base::TimeTicks::Now()) {
+ creation_time_(base::TimeTicks::Now()),
+ weak_factory_(this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}
@@ -174,10 +176,13 @@ void SharedWorkerHost::WorkerContextDestroyed() {
worker_document_set_ = NULL;
}
+void SharedWorkerHost::WorkerReadyForInspection() {
+ NotifyWorkerReadyForInspection(worker_process_id_, worker_route_id_);
+}
+
void SharedWorkerHost::WorkerScriptLoaded() {
UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoaded",
base::TimeTicks::Now() - creation_time_);
- NotifyWorkerContextStarted(worker_process_id_, worker_route_id_);
}
void SharedWorkerHost::WorkerScriptLoadFailed() {
@@ -221,11 +226,25 @@ void SharedWorkerHost::AllowDatabase(const GURL& url,
}
void SharedWorkerHost::AllowFileSystem(const GURL& url,
- bool* result) {
+ scoped_ptr<IPC::Message> reply_msg) {
if (!instance_)
return;
- *result = GetContentClient()->browser()->AllowWorkerFileSystem(
- url, instance_->resource_context(), GetRenderFrameIDsForWorker());
+ GetContentClient()->browser()->AllowWorkerFileSystem(
+ url,
+ instance_->resource_context(),
+ GetRenderFrameIDsForWorker(),
+ base::Bind(&SharedWorkerHost::AllowFileSystemResponse,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(&reply_msg)));
+}
+
+void SharedWorkerHost::AllowFileSystemResponse(
+ scoped_ptr<IPC::Message> reply_msg,
+ bool allowed) {
+ WorkerProcessHostMsg_RequestFileSystemAccessSync::WriteReplyParams(
+ reply_msg.get(),
+ allowed);
+ Send(reply_msg.release());
}
void SharedWorkerHost::AllowIndexedDB(const GURL& url,
diff --git a/chromium/content/browser/shared_worker/shared_worker_host.h b/chromium/content/browser/shared_worker/shared_worker_host.h
index 53cc218669c..e729589c2ee 100644
--- a/chromium/content/browser/shared_worker/shared_worker_host.h
+++ b/chromium/content/browser/shared_worker/shared_worker_host.h
@@ -9,10 +9,11 @@
#include <vector>
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "content/browser/shared_worker/shared_worker_message_filter.h"
-#include "content/browser/worker_host/worker_document_set.h"
+#include "content/browser/shared_worker/worker_document_set.h"
class GURL;
@@ -55,6 +56,7 @@ class SharedWorkerHost {
unsigned long long document_id);
void WorkerContextClosed();
+ void WorkerReadyForInspection();
void WorkerScriptLoaded();
void WorkerScriptLoadFailed();
void WorkerConnected(int message_port_id);
@@ -64,7 +66,7 @@ class SharedWorkerHost {
const base::string16& display_name,
unsigned long estimated_size,
bool* result);
- void AllowFileSystem(const GURL& url, bool* result);
+ void AllowFileSystem(const GURL& url, scoped_ptr<IPC::Message> reply_msg);
void AllowIndexedDB(const GURL& url,
const base::string16& name,
bool* result);
@@ -118,7 +120,8 @@ class SharedWorkerHost {
void SetMessagePortID(SharedWorkerMessageFilter* filter,
int route_id,
int message_port_id);
-
+ void AllowFileSystemResponse(scoped_ptr<IPC::Message> reply_msg,
+ bool allowed);
scoped_ptr<SharedWorkerInstance> instance_;
scoped_refptr<WorkerDocumentSet> worker_document_set_;
FilterList filters_;
@@ -128,6 +131,9 @@ class SharedWorkerHost {
bool load_failed_;
bool closed_;
const base::TimeTicks creation_time_;
+
+ base::WeakPtrFactory<SharedWorkerHost> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(SharedWorkerHost);
};
} // namespace content
diff --git a/chromium/content/browser/shared_worker/shared_worker_instance.h b/chromium/content/browser/shared_worker/shared_worker_instance.h
index 2785c409d57..b7c5fdb2d70 100644
--- a/chromium/content/browser/shared_worker/shared_worker_instance.h
+++ b/chromium/content/browser/shared_worker/shared_worker_instance.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/basictypes.h"
-#include "content/browser/worker_host/worker_storage_partition.h"
+#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/common/content_export.h"
#include "third_party/WebKit/public/web/WebContentSecurityPolicy.h"
#include "url/gurl.h"
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 83e51c171b3..7811e77af30 100644
--- a/chromium/content/browser/shared_worker/shared_worker_instance_unittest.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_instance_unittest.cc
@@ -7,8 +7,9 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
-#include "content/browser/worker_host/worker_storage_partition.h"
+#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
@@ -37,6 +38,7 @@ class SharedWorkerInstanceTest : public testing::Test {
browser_context_->GetResourceContext());
}
+ TestBrowserThreadBundle thread_bundle_;
scoped_ptr<TestBrowserContext> browser_context_;
scoped_ptr<WorkerStoragePartition> partition_;
const WorkerStoragePartitionId partition_id_;
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 fa5f15b603f..20e2526899b 100644
--- a/chromium/content/browser/shared_worker/shared_worker_message_filter.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_message_filter.cc
@@ -4,7 +4,6 @@
#include "content/browser/shared_worker/shared_worker_message_filter.h"
-#include "content/browser/devtools/worker_devtools_manager.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/shared_worker/shared_worker_service_impl.h"
#include "content/common/devtools_messages.h"
@@ -54,6 +53,8 @@ bool SharedWorkerMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnWorkerContextClosed)
IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextDestroyed,
OnWorkerContextDestroyed)
+ IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerReadyForInspection,
+ OnWorkerReadyForInspection)
IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerScriptLoaded,
OnWorkerScriptLoaded)
IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerScriptLoadFailed,
@@ -61,8 +62,9 @@ bool SharedWorkerMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerConnected,
OnWorkerConnected)
IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowDatabase, OnAllowDatabase)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_RequestFileSystemAccessSync,
- OnRequestFileSystemAccessSync)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(
+ WorkerProcessHostMsg_RequestFileSystemAccessSync,
+ OnRequestFileSystemAccess)
IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowIndexedDB, OnAllowIndexedDB)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -109,6 +111,12 @@ void SharedWorkerMessageFilter::OnWorkerContextDestroyed(int worker_route_id) {
this);
}
+void SharedWorkerMessageFilter::OnWorkerReadyForInspection(
+ int worker_route_id) {
+ SharedWorkerServiceImpl::GetInstance()->WorkerReadyForInspection(
+ worker_route_id, this);
+}
+
void SharedWorkerMessageFilter::OnWorkerScriptLoaded(int worker_route_id) {
SharedWorkerServiceImpl::GetInstance()->WorkerScriptLoaded(worker_route_id,
this);
@@ -144,14 +152,12 @@ void SharedWorkerMessageFilter::OnAllowDatabase(
this);
}
-void SharedWorkerMessageFilter::OnRequestFileSystemAccessSync(
+void SharedWorkerMessageFilter::OnRequestFileSystemAccess(
int worker_route_id,
const GURL& url,
- bool* result) {
- SharedWorkerServiceImpl::GetInstance()->AllowFileSystem(worker_route_id,
- url,
- result,
- this);
+ IPC::Message* reply_msg) {
+ SharedWorkerServiceImpl::GetInstance()->AllowFileSystem(
+ worker_route_id, url, reply_msg, this);
}
void SharedWorkerMessageFilter::OnAllowIndexedDB(int worker_route_id,
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 8fb927b805e..e283a22f2d9 100644
--- a/chromium/content/browser/shared_worker/shared_worker_message_filter.h
+++ b/chromium/content/browser/shared_worker/shared_worker_message_filter.h
@@ -5,7 +5,7 @@
#ifndef CONTENT_BROWSER_SHARED_WORKER_SHARED_WORKER_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_SHARED_WORKER_SHARED_WORKER_MESSAGE_FILTER_H_
-#include "content/browser/worker_host/worker_storage_partition.h"
+#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
@@ -26,8 +26,8 @@ class CONTENT_EXPORT SharedWorkerMessageFilter : public BrowserMessageFilter {
MessagePortMessageFilter* message_port_filter);
// BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelClosing() override;
+ bool OnMessageReceived(const IPC::Message& message) override;
int GetNextRoutingID();
int render_process_id() const { return render_process_id_; }
@@ -38,7 +38,7 @@ class CONTENT_EXPORT SharedWorkerMessageFilter : public BrowserMessageFilter {
protected:
// This is protected, so we can define sub classes for testing.
- virtual ~SharedWorkerMessageFilter();
+ ~SharedWorkerMessageFilter() override;
private:
// Message handlers.
@@ -48,6 +48,8 @@ class CONTENT_EXPORT SharedWorkerMessageFilter : public BrowserMessageFilter {
void OnDocumentDetached(unsigned long long document_id);
void OnWorkerContextClosed(int worker_route_id);
void OnWorkerContextDestroyed(int worker_route_id);
+
+ void OnWorkerReadyForInspection(int worker_route_id);
void OnWorkerScriptLoaded(int worker_route_id);
void OnWorkerScriptLoadFailed(int worker_route_id);
void OnWorkerConnected(int message_port_id, int worker_route_id);
@@ -57,9 +59,9 @@ class CONTENT_EXPORT SharedWorkerMessageFilter : public BrowserMessageFilter {
const base::string16& display_name,
unsigned long estimated_size,
bool* result);
- void OnRequestFileSystemAccessSync(int worker_route_id,
- const GURL& url,
- bool* result);
+ void OnRequestFileSystemAccess(int worker_route_id,
+ const GURL& url,
+ IPC::Message* reply_msg);
void OnAllowIndexedDB(int worker_route_id,
const GURL& url,
const base::string16& name,
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 4a689fa812f..b773127db63 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -16,13 +16,18 @@
#include "content/browser/shared_worker/shared_worker_host.h"
#include "content/browser/shared_worker/shared_worker_instance.h"
#include "content/browser/shared_worker/shared_worker_message_filter.h"
-#include "content/browser/worker_host/worker_document_set.h"
+#include "content/browser/shared_worker/worker_document_set.h"
#include "content/common/view_messages.h"
#include "content/common/worker_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/worker_service_observer.h"
namespace content {
+
+WorkerService* WorkerService::GetInstance() {
+ return SharedWorkerServiceImpl::GetInstance();
+}
+
namespace {
class ScopedWorkerDependencyChecker {
@@ -352,6 +357,13 @@ void SharedWorkerServiceImpl::WorkerContextDestroyed(
host->WorkerContextDestroyed();
}
+void SharedWorkerServiceImpl::WorkerReadyForInspection(
+ int worker_route_id,
+ SharedWorkerMessageFilter* filter) {
+ if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
+ host->WorkerReadyForInspection();
+}
+
void SharedWorkerServiceImpl::WorkerScriptLoaded(
int worker_route_id,
SharedWorkerMessageFilter* filter) {
@@ -394,10 +406,14 @@ void SharedWorkerServiceImpl::AllowDatabase(
void SharedWorkerServiceImpl::AllowFileSystem(
int worker_route_id,
const GURL& url,
- bool* result,
+ IPC::Message* reply_msg,
SharedWorkerMessageFilter* filter) {
- if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
- host->AllowFileSystem(url, result);
+ if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id)) {
+ host->AllowFileSystem(url, make_scoped_ptr(reply_msg));
+ } else {
+ filter->Send(reply_msg);
+ return;
+ }
}
void SharedWorkerServiceImpl::AllowIndexedDB(
@@ -626,18 +642,10 @@ SharedWorkerServiceImpl::GetRenderersWithWorkerDependency() {
void SharedWorkerServiceImpl::CheckWorkerDependency() {
const std::set<int> current_worker_depended_renderers =
GetRenderersWithWorkerDependency();
- std::vector<int> added_items;
- std::vector<int> removed_items;
- std::set_difference(current_worker_depended_renderers.begin(),
- current_worker_depended_renderers.end(),
- last_worker_depended_renderers_.begin(),
- last_worker_depended_renderers_.end(),
- std::back_inserter(added_items));
- std::set_difference(last_worker_depended_renderers_.begin(),
- last_worker_depended_renderers_.end(),
- current_worker_depended_renderers.begin(),
- current_worker_depended_renderers.end(),
- std::back_inserter(removed_items));
+ std::vector<int> added_items = base::STLSetDifference<std::vector<int> >(
+ current_worker_depended_renderers, last_worker_depended_renderers_);
+ std::vector<int> removed_items = base::STLSetDifference<std::vector<int> >(
+ last_worker_depended_renderers_, current_worker_depended_renderers);
if (!added_items.empty() || !removed_items.empty()) {
last_worker_depended_renderers_ = current_worker_depended_renderers;
update_worker_dependency_(added_items, removed_items);
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 e97c259493e..b09d58345a9 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl.h
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl.h
@@ -41,10 +41,10 @@ class CONTENT_EXPORT SharedWorkerServiceImpl
static SharedWorkerServiceImpl* GetInstance();
// WorkerService implementation:
- virtual bool TerminateWorker(int process_id, int route_id) OVERRIDE;
- virtual std::vector<WorkerInfo> GetWorkers() OVERRIDE;
- virtual void AddObserver(WorkerServiceObserver* observer) OVERRIDE;
- virtual void RemoveObserver(WorkerServiceObserver* observer) OVERRIDE;
+ bool TerminateWorker(int process_id, int route_id) override;
+ std::vector<WorkerInfo> GetWorkers() override;
+ void AddObserver(WorkerServiceObserver* observer) override;
+ void RemoveObserver(WorkerServiceObserver* observer) override;
// These methods correspond to worker related IPCs.
void CreateWorker(const ViewHostMsg_CreateWorker_Params& params,
@@ -61,6 +61,8 @@ class CONTENT_EXPORT SharedWorkerServiceImpl
SharedWorkerMessageFilter* filter);
void WorkerContextDestroyed(int worker_route_id,
SharedWorkerMessageFilter* filter);
+ void WorkerReadyForInspection(int worker_route_id,
+ SharedWorkerMessageFilter* filter);
void WorkerScriptLoaded(int worker_route_id,
SharedWorkerMessageFilter* filter);
void WorkerScriptLoadFailed(int worker_route_id,
@@ -77,7 +79,7 @@ class CONTENT_EXPORT SharedWorkerServiceImpl
SharedWorkerMessageFilter* filter);
void AllowFileSystem(int worker_route_id,
const GURL& url,
- bool* result,
+ IPC::Message* reply_msg,
SharedWorkerMessageFilter* filter);
void AllowIndexedDB(int worker_route_id,
const GURL& url,
@@ -113,7 +115,7 @@ class CONTENT_EXPORT SharedWorkerServiceImpl
PendingInstaneMap;
SharedWorkerServiceImpl();
- virtual ~SharedWorkerServiceImpl();
+ ~SharedWorkerServiceImpl() override;
void ResetForTesting();
diff --git a/chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc b/chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
index e08da83efb2..8e1dd80104d 100644
--- a/chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
+++ b/chromium/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
@@ -16,7 +16,7 @@
#include "content/browser/message_port_message_filter.h"
#include "content/browser/shared_worker/shared_worker_message_filter.h"
#include "content/browser/shared_worker/shared_worker_service_impl.h"
-#include "content/browser/worker_host/worker_storage_partition.h"
+#include "content/browser/shared_worker/worker_storage_partition.h"
#include "content/common/message_port_messages.h"
#include "content/common/view_messages.h"
#include "content/common/worker_messages.h"
@@ -60,8 +60,8 @@ class SharedWorkerServiceImplTest : public testing::Test {
&SharedWorkerServiceImplTest::MockTryIncrementWorkerRefCount);
}
- virtual void SetUp() OVERRIDE {}
- virtual void TearDown() OVERRIDE {
+ void SetUp() override {}
+ void TearDown() override {
s_update_worker_dependency_call_count_ = 0;
s_worker_dependency_added_ids_.clear();
s_worker_dependency_removed_ids_.clear();
@@ -110,7 +110,7 @@ class MockMessagePortMessageFilter : public MessagePortMessageFilter {
ScopedVector<IPC::Message>* message_queue)
: MessagePortMessageFilter(callback), message_queue_(message_queue) {}
- virtual bool Send(IPC::Message* message) OVERRIDE {
+ bool Send(IPC::Message* message) override {
if (!message_queue_) {
delete message;
return false;
@@ -125,7 +125,7 @@ class MockMessagePortMessageFilter : public MessagePortMessageFilter {
}
private:
- virtual ~MockMessagePortMessageFilter() {}
+ ~MockMessagePortMessageFilter() override {}
ScopedVector<IPC::Message>* message_queue_;
};
@@ -142,7 +142,7 @@ class MockSharedWorkerMessageFilter : public SharedWorkerMessageFilter {
message_port_filter),
message_queue_(message_queue) {}
- virtual bool Send(IPC::Message* message) OVERRIDE {
+ bool Send(IPC::Message* message) override {
if (!message_queue_) {
delete message;
return false;
@@ -157,7 +157,7 @@ class MockSharedWorkerMessageFilter : public SharedWorkerMessageFilter {
}
private:
- virtual ~MockSharedWorkerMessageFilter() {}
+ ~MockSharedWorkerMessageFilter() override {}
ScopedVector<IPC::Message>* message_queue_;
};
@@ -436,6 +436,12 @@ TEST_F(SharedWorkerServiceImplTest, BasicTest) {
connector->SendSendQueuedMessages(empty_messages);
EXPECT_EQ(0U, renderer_host->QueuedMessageCount());
+ // SharedWorker sends WorkerHostMsg_WorkerReadyForInspection in
+ // EmbeddedSharedWorkerStub::WorkerReadyForInspection().
+ EXPECT_TRUE(renderer_host->OnMessageReceived(
+ new WorkerHostMsg_WorkerReadyForInspection(worker_route_id)));
+ EXPECT_EQ(0U, renderer_host->QueuedMessageCount());
+
// SharedWorker sends WorkerHostMsg_WorkerScriptLoaded in
// EmbeddedSharedWorkerStub::workerScriptLoaded().
EXPECT_TRUE(renderer_host->OnMessageReceived(
@@ -527,6 +533,12 @@ TEST_F(SharedWorkerServiceImplTest, TwoRendererTest) {
connector0->SendSendQueuedMessages(empty_messages);
EXPECT_EQ(0U, renderer_host0->QueuedMessageCount());
+ // SharedWorker sends WorkerHostMsg_WorkerReadyForInspection in
+ // EmbeddedSharedWorkerStub::WorkerReadyForInspection().
+ EXPECT_TRUE(renderer_host0->OnMessageReceived(
+ new WorkerHostMsg_WorkerReadyForInspection(worker_route_id)));
+ EXPECT_EQ(0U, renderer_host0->QueuedMessageCount());
+
// SharedWorker sends WorkerHostMsg_WorkerScriptLoaded in
// EmbeddedSharedWorkerStub::workerScriptLoaded().
EXPECT_TRUE(renderer_host0->OnMessageReceived(
diff --git a/chromium/content/browser/shared_worker/worker_browsertest.cc b/chromium/content/browser/shared_worker/worker_browsertest.cc
new file mode 100644
index 00000000000..ce39df5788c
--- /dev/null
+++ b/chromium/content/browser/shared_worker/worker_browsertest.cc
@@ -0,0 +1,145 @@
+// 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 "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
+#include "base/test/test_timeouts.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_paths.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/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
+#include "net/base/test_data_directory.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class WorkerTest : public ContentBrowserTest {
+ public:
+ WorkerTest() {}
+
+ GURL GetTestURL(const std::string& test_case, const std::string& query) {
+ base::FilePath test_file_path = GetTestFilePath(
+ "workers", test_case.c_str());
+ return GetFileUrlWithQuery(test_file_path, query);
+ }
+
+ void RunTest(Shell* window,
+ const std::string& test_case,
+ const std::string& query) {
+ GURL url = GetTestURL(test_case, query);
+ const base::string16 expected_title = base::ASCIIToUTF16("OK");
+ TitleWatcher title_watcher(window->web_contents(), expected_title);
+ NavigateToURL(window, url);
+ base::string16 final_title = title_watcher.WaitAndGetTitle();
+ EXPECT_EQ(expected_title, final_title);
+ }
+
+ void RunTest(const std::string& test_case, const std::string& query) {
+ RunTest(shell(), test_case, query);
+ }
+
+ static void QuitUIMessageLoop(base::Callback<void()> callback) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
+ }
+
+ void NavigateAndWaitForAuth(const GURL& url) {
+ ShellContentBrowserClient* browser_client =
+ ShellContentBrowserClient::Get();
+ scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner();
+ browser_client->resource_dispatcher_host_delegate()->
+ set_login_request_callback(
+ base::Bind(&QuitUIMessageLoop, runner->QuitClosure()));
+ shell()->LoadURL(url);
+ runner->Run();
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(WorkerTest, SingleWorker) {
+ RunTest("single_worker.html", std::string());
+}
+
+IN_PROC_BROWSER_TEST_F(WorkerTest, MultipleWorkers) {
+ RunTest("multi_worker.html", std::string());
+}
+
+IN_PROC_BROWSER_TEST_F(WorkerTest, SingleSharedWorker) {
+ RunTest("single_worker.html", "shared=true");
+}
+
+// http://crbug.com/96435
+IN_PROC_BROWSER_TEST_F(WorkerTest, MultipleSharedWorkers) {
+ RunTest("multi_worker.html", "shared=true");
+}
+
+// Incognito windows should not share workers with non-incognito windows
+// http://crbug.com/30021
+IN_PROC_BROWSER_TEST_F(WorkerTest, IncognitoSharedWorkers) {
+ // Load a non-incognito tab and have it create a shared worker
+ RunTest("incognito_worker.html", std::string());
+
+ // Incognito worker should not share with non-incognito
+ RunTest(CreateOffTheRecordBrowser(), "incognito_worker.html", std::string());
+}
+
+// Make sure that auth dialog is displayed from worker context.
+// http://crbug.com/33344
+IN_PROC_BROWSER_TEST_F(WorkerTest, WorkerHttpAuth) {
+ ASSERT_TRUE(test_server()->Start());
+ GURL url = test_server()->GetURL("files/workers/worker_auth.html");
+
+ NavigateAndWaitForAuth(url);
+}
+
+// Make sure that auth dialog is displayed from shared worker context.
+// http://crbug.com/33344
+IN_PROC_BROWSER_TEST_F(WorkerTest, SharedWorkerHttpAuth) {
+ ASSERT_TRUE(test_server()->Start());
+ GURL url = test_server()->GetURL("files/workers/shared_worker_auth.html");
+ NavigateAndWaitForAuth(url);
+}
+
+IN_PROC_BROWSER_TEST_F(WorkerTest, WebSocketSharedWorker) {
+ // Launch WebSocket server.
+ net::SpawnedTestServer ws_server(net::SpawnedTestServer::TYPE_WS,
+ net::SpawnedTestServer::kLocalhost,
+ net::GetWebSocketTestDataDirectory());
+ ASSERT_TRUE(ws_server.Start());
+
+ // Generate test URL.
+ std::string scheme("http");
+ GURL::Replacements replacements;
+ replacements.SetSchemeStr(scheme);
+ GURL url = ws_server.GetURL(
+ "websocket_shared_worker.html").ReplaceComponents(replacements);
+
+ // Run test.
+ Shell* window = shell();
+ const base::string16 expected_title = base::ASCIIToUTF16("OK");
+ TitleWatcher title_watcher(window->web_contents(), expected_title);
+ NavigateToURL(window, url);
+ base::string16 final_title = title_watcher.WaitAndGetTitle();
+ EXPECT_EQ(expected_title, final_title);
+}
+
+IN_PROC_BROWSER_TEST_F(WorkerTest, PassMessagePortToSharedWorker) {
+ RunTest("pass_messageport_to_sharedworker.html", "");
+}
+
+IN_PROC_BROWSER_TEST_F(WorkerTest,
+ PassMessagePortToSharedWorkerDontWaitForConnect) {
+ RunTest("pass_messageport_to_sharedworker_dont_wait_for_connect.html", "");
+}
+
+} // namespace content
diff --git a/chromium/content/browser/worker_host/worker_document_set.cc b/chromium/content/browser/shared_worker/worker_document_set.cc
index 3031493783e..f3ef7d2636d 100644
--- a/chromium/content/browser/worker_host/worker_document_set.cc
+++ b/chromium/content/browser/shared_worker/worker_document_set.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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/worker_host/worker_document_set.h"
+#include "content/browser/shared_worker/worker_document_set.h"
#include "base/logging.h"
diff --git a/chromium/content/browser/worker_host/worker_document_set.h b/chromium/content/browser/shared_worker/worker_document_set.h
index e497aa80e53..54ae9e93daa 100644
--- a/chromium/content/browser/worker_host/worker_document_set.h
+++ b/chromium/content/browser/shared_worker/worker_document_set.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_WORKER_HOST_WORKER_DOCUMENT_SET_H_
-#define CONTENT_BROWSER_WORKER_HOST_WORKER_DOCUMENT_SET_H_
+#ifndef CONTENT_BROWSER_SHARED_WORKER_WORKER_DOCUMENT_SET_H_
+#define CONTENT_BROWSER_SHARED_WORKER_WORKER_DOCUMENT_SET_H_
#include <set>
@@ -93,4 +93,4 @@ class WorkerDocumentSet : public base::RefCounted<WorkerDocumentSet> {
} // namespace content
-#endif // CONTENT_BROWSER_WORKER_HOST_WORKER_DOCUMENT_SET_H_
+#endif // CONTENT_BROWSER_SHARED_WORKER_WORKER_DOCUMENT_SET_H_
diff --git a/chromium/content/browser/worker_host/worker_storage_partition.cc b/chromium/content/browser/shared_worker/worker_storage_partition.cc
index e7a5f40660c..c9bb5bedd9d 100644
--- a/chromium/content/browser/worker_host/worker_storage_partition.cc
+++ b/chromium/content/browser/shared_worker/worker_storage_partition.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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/worker_host/worker_storage_partition.h"
+#include "content/browser/shared_worker/worker_storage_partition.h"
#include <string>
@@ -10,9 +10,9 @@
#include "content/browser/indexed_db/indexed_db_context_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "net/url_request/url_request_context_getter.h"
-#include "webkit/browser/database/database_tracker.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/quota/quota_manager.h"
+#include "storage/browser/database/database_tracker.h"
+#include "storage/browser/fileapi/file_system_context.h"
+#include "storage/browser/quota/quota_manager.h"
namespace content {
@@ -20,9 +20,9 @@ WorkerStoragePartition::WorkerStoragePartition(
net::URLRequestContextGetter* url_request_context,
net::URLRequestContextGetter* media_url_request_context,
ChromeAppCacheService* appcache_service,
- quota::QuotaManager* quota_manager,
- fileapi::FileSystemContext* filesystem_context,
- webkit_database::DatabaseTracker* database_tracker,
+ storage::QuotaManager* quota_manager,
+ storage::FileSystemContext* filesystem_context,
+ storage::DatabaseTracker* database_tracker,
IndexedDBContextImpl* indexed_db_context,
ServiceWorkerContextWrapper* service_worker_context)
: url_request_context_(url_request_context),
diff --git a/chromium/content/browser/worker_host/worker_storage_partition.h b/chromium/content/browser/shared_worker/worker_storage_partition.h
index aebd683c3f5..2f595b0e72f 100644
--- a/chromium/content/browser/worker_host/worker_storage_partition.h
+++ b/chromium/content/browser/shared_worker/worker_storage_partition.h
@@ -1,28 +1,28 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_WORKER_HOST_WORKER_STORAGE_PARTITION_H_
-#define CONTENT_BROWSER_WORKER_HOST_WORKER_STORAGE_PARTITION_H_
+#ifndef CONTENT_BROWSER_SHARED_WORKERT_WORKER_STORAGE_PARTITION_H_
+#define CONTENT_BROWSER_SHARED_WORKERT_WORKER_STORAGE_PARTITION_H_
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
-namespace quota {
+namespace storage {
class QuotaManager;
}
-namespace fileapi {
+namespace storage {
class FileSystemContext;
-} // namespace fileapi
+} // namespace storage
namespace net {
class URLRequestContextGetter;
}
-namespace webkit_database {
+namespace storage {
class DatabaseTracker;
-} // namespace webkit_database
+} // namespace storage
namespace content {
class ChromeAppCacheService;
@@ -47,9 +47,9 @@ class CONTENT_EXPORT WorkerStoragePartition {
net::URLRequestContextGetter* url_request_context,
net::URLRequestContextGetter* media_url_request_context,
ChromeAppCacheService* appcache_service,
- quota::QuotaManager* quota_manager,
- fileapi::FileSystemContext* filesystem_context,
- webkit_database::DatabaseTracker* database_tracker,
+ storage::QuotaManager* quota_manager,
+ storage::FileSystemContext* filesystem_context,
+ storage::DatabaseTracker* database_tracker,
IndexedDBContextImpl* indexed_db_context,
ServiceWorkerContextWrapper* service_worker_context);
~WorkerStoragePartition();
@@ -74,15 +74,13 @@ class CONTENT_EXPORT WorkerStoragePartition {
return appcache_service_.get();
}
- quota::QuotaManager* quota_manager() const {
- return quota_manager_.get();
- }
+ storage::QuotaManager* quota_manager() const { return quota_manager_.get(); }
- fileapi::FileSystemContext* filesystem_context() const {
+ storage::FileSystemContext* filesystem_context() const {
return filesystem_context_.get();
}
- webkit_database::DatabaseTracker* database_tracker() const {
+ storage::DatabaseTracker* database_tracker() const {
return database_tracker_.get();
}
@@ -100,9 +98,9 @@ class CONTENT_EXPORT WorkerStoragePartition {
scoped_refptr<net::URLRequestContextGetter> url_request_context_;
scoped_refptr<net::URLRequestContextGetter> media_url_request_context_;
scoped_refptr<ChromeAppCacheService> appcache_service_;
- scoped_refptr<quota::QuotaManager> quota_manager_;
- scoped_refptr<fileapi::FileSystemContext> filesystem_context_;
- scoped_refptr<webkit_database::DatabaseTracker> database_tracker_;
+ scoped_refptr<storage::QuotaManager> quota_manager_;
+ scoped_refptr<storage::FileSystemContext> filesystem_context_;
+ scoped_refptr<storage::DatabaseTracker> database_tracker_;
scoped_refptr<IndexedDBContextImpl> indexed_db_context_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
};
@@ -122,13 +120,13 @@ class CONTENT_EXPORT WorkerStoragePartitionId {
net::URLRequestContextGetter* url_request_context_;
net::URLRequestContextGetter* media_url_request_context_;
ChromeAppCacheService* appcache_service_;
- quota::QuotaManager* quota_manager_;
- fileapi::FileSystemContext* filesystem_context_;
- webkit_database::DatabaseTracker* database_tracker_;
+ storage::QuotaManager* quota_manager_;
+ storage::FileSystemContext* filesystem_context_;
+ storage::DatabaseTracker* database_tracker_;
IndexedDBContextImpl* indexed_db_context_;
ServiceWorkerContextWrapper* service_worker_context_;
};
} // namespace content
-#endif // CONTENT_BROWSER_WORKER_HOST_WORKER_STORAGE_PARTITION_H_
+#endif // CONTENT_BROWSER_SHARED_WORKERT_WORKER_STORAGE_PARTITION_H_
diff --git a/chromium/content/browser/signed_certificate_timestamp_store_impl.h b/chromium/content/browser/signed_certificate_timestamp_store_impl.h
index 4cd98ccb041..b2f728a57dd 100644
--- a/chromium/content/browser/signed_certificate_timestamp_store_impl.h
+++ b/chromium/content/browser/signed_certificate_timestamp_store_impl.h
@@ -20,18 +20,17 @@ class SignedCertificateTimestampStoreImpl
static SignedCertificateTimestampStoreImpl* GetInstance();
// SignedCertificateTimestampStore implementation:
- virtual int Store(
- net::ct::SignedCertificateTimestamp* sct,
- int render_process_host_id) OVERRIDE;
- virtual bool Retrieve(
+ int Store(net::ct::SignedCertificateTimestamp* sct,
+ int render_process_host_id) override;
+ bool Retrieve(
int sct_id,
- scoped_refptr<net::ct::SignedCertificateTimestamp>* sct) OVERRIDE;
+ scoped_refptr<net::ct::SignedCertificateTimestamp>* sct) override;
private:
friend struct DefaultSingletonTraits<SignedCertificateTimestampStoreImpl>;
SignedCertificateTimestampStoreImpl();
- virtual ~SignedCertificateTimestampStoreImpl();
+ ~SignedCertificateTimestampStoreImpl() override;
RendererDataMemoizingStore<net::ct::SignedCertificateTimestamp> store_;
diff --git a/chromium/content/browser/site_instance_impl.cc b/chromium/content/browser/site_instance_impl.cc
index b6e6918c0a4..f1555dc1af8 100644
--- a/chromium/content/browser/site_instance_impl.cc
+++ b/chromium/content/browser/site_instance_impl.cc
@@ -25,7 +25,7 @@ int32 SiteInstanceImpl::next_site_instance_id_ = 1;
SiteInstanceImpl::SiteInstanceImpl(BrowsingInstance* browsing_instance)
: id_(next_site_instance_id_++),
- active_view_count_(0),
+ active_frame_count_(0),
browsing_instance_(browsing_instance),
process_(NULL),
has_site_(false) {
@@ -120,6 +120,8 @@ RenderProcessHost* SiteInstanceImpl::GetProcess() {
process_, site_);
}
+ TRACE_EVENT2("navigation", "SiteInstanceImpl::GetProcess",
+ "site id", id_, "process id", process_->GetID());
GetContentClient()->browser()->SiteInstanceGotProcess(this);
if (has_site_)
@@ -131,6 +133,8 @@ RenderProcessHost* SiteInstanceImpl::GetProcess() {
}
void SiteInstanceImpl::SetSite(const GURL& url) {
+ TRACE_EVENT2("navigation", "SiteInstanceImpl::SetSite",
+ "site id", id_, "url", url.possibly_invalid_spec());
// A SiteInstance's site should not change.
// TODO(creis): When following links or script navigations, we can currently
// render pages from other sites in this SiteInstance. This will eventually
@@ -241,10 +245,12 @@ SiteInstance* SiteInstance::CreateForURL(BrowserContext* browser_context,
/*static*/
bool SiteInstance::IsSameWebSite(BrowserContext* browser_context,
- const GURL& real_url1,
- const GURL& real_url2) {
- GURL url1 = SiteInstanceImpl::GetEffectiveURL(browser_context, real_url1);
- GURL url2 = SiteInstanceImpl::GetEffectiveURL(browser_context, real_url2);
+ const GURL& real_src_url,
+ const GURL& real_dest_url) {
+ GURL src_url = SiteInstanceImpl::GetEffectiveURL(browser_context,
+ real_src_url);
+ GURL dest_url = SiteInstanceImpl::GetEffectiveURL(browser_context,
+ real_dest_url);
// We infer web site boundaries based on the registered domain name of the
// top-level page and the scheme. We do not pay attention to the port if
@@ -254,20 +260,26 @@ bool SiteInstance::IsSameWebSite(BrowserContext* browser_context,
// Some special URLs will match the site instance of any other URL. This is
// done before checking both of them for validity, since we want these URLs
// to have the same site instance as even an invalid one.
- if (IsRendererDebugURL(url1) || IsRendererDebugURL(url2))
+ if (IsRendererDebugURL(src_url) || IsRendererDebugURL(dest_url))
return true;
// If either URL is invalid, they aren't part of the same site.
- if (!url1.is_valid() || !url2.is_valid())
+ if (!src_url.is_valid() || !dest_url.is_valid())
return false;
+ // If the destination url is just a blank page, we treat them as part of the
+ // same site.
+ GURL blank_page(url::kAboutBlankURL);
+ if (dest_url == blank_page)
+ return true;
+
// If the schemes differ, they aren't part of the same site.
- if (url1.scheme() != url2.scheme())
+ if (src_url.scheme() != dest_url.scheme())
return false;
return net::registry_controlled_domains::SameDomainOrHost(
- url1,
- url2,
+ src_url,
+ dest_url,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
}
@@ -329,7 +341,8 @@ void SiteInstanceImpl::RenderProcessHostDestroyed(RenderProcessHost* host) {
void SiteInstanceImpl::LockToOrigin() {
// We currently only restrict this process to a particular site if the
// --enable-strict-site-isolation or --site-per-process flags are present.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kEnableStrictSiteIsolation) ||
command_line.HasSwitch(switches::kSitePerProcess)) {
ChildProcessSecurityPolicyImpl* policy =
diff --git a/chromium/content/browser/site_instance_impl.h b/chromium/content/browser/site_instance_impl.h
index 69197eeeab4..2c55688bc32 100644
--- a/chromium/content/browser/site_instance_impl.h
+++ b/chromium/content/browser/site_instance_impl.h
@@ -19,14 +19,14 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
public RenderProcessHostObserver {
public:
// SiteInstance interface overrides.
- virtual int32 GetId() OVERRIDE;
- virtual bool HasProcess() const OVERRIDE;
- virtual RenderProcessHost* GetProcess() OVERRIDE;
- virtual BrowserContext* GetBrowserContext() const OVERRIDE;
- virtual const GURL& GetSiteURL() const OVERRIDE;
- virtual SiteInstance* GetRelatedSiteInstance(const GURL& url) OVERRIDE;
- virtual bool IsRelatedSiteInstance(const SiteInstance* instance) OVERRIDE;
- virtual size_t GetRelatedActiveContentsCount() OVERRIDE;
+ int32 GetId() override;
+ bool HasProcess() const override;
+ RenderProcessHost* GetProcess() override;
+ BrowserContext* GetBrowserContext() const override;
+ const GURL& GetSiteURL() const override;
+ SiteInstance* GetRelatedSiteInstance(const GURL& url) override;
+ bool IsRelatedSiteInstance(const SiteInstance* instance) override;
+ size_t GetRelatedActiveContentsCount() override;
// Set the web site that this SiteInstance is rendering pages for.
// This includes the scheme and registered domain, but not the port. If the
@@ -45,28 +45,27 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
// navigating to the URL.
bool HasWrongProcessForURL(const GURL& url);
- // Increase the number of active views in this SiteInstance. This is
- // increased when a view is created, or a currently swapped out view
+ // Increase the number of active frames in this SiteInstance. This is
+ // increased when a frame is created, or a currently swapped out frame
// is swapped in.
- void increment_active_view_count() { active_view_count_++; }
+ void increment_active_frame_count() { active_frame_count_++; }
- // Decrease the number of active views in this SiteInstance. This is
- // decreased when a view is destroyed, or a currently active view is
+ // Decrease the number of active frames in this SiteInstance. This is
+ // decreased when a frame is destroyed, or a currently active frame is
// swapped out.
- void decrement_active_view_count() { active_view_count_--; }
+ void decrement_active_frame_count() { active_frame_count_--; }
- // Get the number of active views which belong to this
- // SiteInstance. If there is no active view left in this
- // SiteInstance, all view in this SiteInstance can be safely
- // discarded to save memory.
- size_t active_view_count() { return active_view_count_; }
+ // Get the number of active frames which belong to this SiteInstance. If
+ // there are no active frames left, all frames in this SiteInstance can be
+ // safely discarded.
+ size_t active_frame_count() { return active_frame_count_; }
// Increase the number of active WebContentses using this SiteInstance. Note
- // that, unlike active_view_count, this does not count pending RVHs.
+ // that, unlike active_frame_count, this does not count pending RFHs.
void IncrementRelatedActiveContentsCount();
// Decrease the number of active WebContentses using this SiteInstance. Note
- // that, unlike active_view_count, this does not count pending RVHs.
+ // that, unlike active_frame_count, this does not count pending RFHs.
void DecrementRelatedActiveContentsCount();
// Sets the global factory used to create new RenderProcessHosts. It may be
@@ -90,7 +89,7 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
friend class SiteInstance;
// Virtual to allow tests to extend it.
- virtual ~SiteInstanceImpl();
+ ~SiteInstanceImpl() override;
// Create a new SiteInstance. Protected to give access to BrowsingInstance
// and tests; most callers should use Create or GetRelatedSiteInstance
@@ -99,7 +98,7 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
private:
// RenderProcessHostObserver implementation.
- virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE;
+ void RenderProcessHostDestroyed(RenderProcessHost* host) override;
// Used to restrict a process' origin access rights.
void LockToOrigin();
@@ -113,8 +112,8 @@ class CONTENT_EXPORT SiteInstanceImpl : public SiteInstance,
// A unique ID for this SiteInstance.
int32 id_;
- // The number of active views under this SiteInstance.
- size_t active_view_count_;
+ // The number of active frames in this SiteInstance.
+ size_t active_frame_count_;
// BrowsingInstance to which this SiteInstance belongs.
scoped_refptr<BrowsingInstance> browsing_instance_;
diff --git a/chromium/content/browser/site_instance_impl_unittest.cc b/chromium/content/browser/site_instance_impl_unittest.cc
index 646f4d07957..993ef35179a 100644
--- a/chromium/content/browser/site_instance_impl_unittest.cc
+++ b/chromium/content/browser/site_instance_impl_unittest.cc
@@ -36,20 +36,20 @@ const char kPrivilegedScheme[] = "privileged";
class SiteInstanceTestWebUIControllerFactory : public WebUIControllerFactory {
public:
- virtual WebUIController* CreateWebUIControllerForURL(
- WebUI* web_ui, const GURL& url) const OVERRIDE {
+ WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
+ const GURL& url) const override {
return NULL;
}
- virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
+ const GURL& url) const override {
return WebUI::kNoWebUI;
}
- virtual bool UseWebUIForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ bool UseWebUIForURL(BrowserContext* browser_context,
+ const GURL& url) const override {
return HasWebUIScheme(url);
}
- virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ bool UseWebUIBindingsForURL(BrowserContext* browser_context,
+ const GURL& url) const override {
return HasWebUIScheme(url);
}
};
@@ -61,12 +61,12 @@ class SiteInstanceTestBrowserClient : public TestContentBrowserClient {
WebUIControllerFactory::RegisterFactory(&factory_);
}
- virtual ~SiteInstanceTestBrowserClient() {
+ ~SiteInstanceTestBrowserClient() override {
WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
}
- virtual bool IsSuitableHost(RenderProcessHost* process_host,
- const GURL& site_url) OVERRIDE {
+ bool IsSuitableHost(RenderProcessHost* process_host,
+ const GURL& site_url) override {
return (privileged_process_id_ == process_host->GetID()) ==
site_url.SchemeIs(kPrivilegedScheme);
}
@@ -90,7 +90,7 @@ class SiteInstanceTest : public testing::Test {
old_browser_client_(NULL) {
}
- virtual void SetUp() {
+ void SetUp() override {
old_browser_client_ = SetBrowserClientForTesting(&browser_client_);
url::AddStandardScheme(kPrivilegedScheme);
url::AddStandardScheme(kChromeUIScheme);
@@ -98,7 +98,7 @@ class SiteInstanceTest : public testing::Test {
SiteInstanceImpl::set_render_process_host_factory(&rph_factory_);
}
- virtual void TearDown() {
+ void TearDown() override {
// Ensure that no RenderProcessHosts are left over after the tests.
EXPECT_TRUE(RenderProcessHost::AllHostsIterator().IsAtEnd());
@@ -157,9 +157,7 @@ class TestBrowsingInstance : public BrowsingInstance {
using BrowsingInstance::UnregisterSiteInstance;
private:
- virtual ~TestBrowsingInstance() {
- (*delete_counter_)++;
- }
+ ~TestBrowsingInstance() override { (*delete_counter_)++; }
int* delete_counter_;
};
@@ -179,9 +177,7 @@ class TestSiteInstance : public SiteInstanceImpl {
private:
TestSiteInstance(BrowsingInstance* browsing_instance, int* delete_counter)
: SiteInstanceImpl(browsing_instance), delete_counter_(delete_counter) {}
- virtual ~TestSiteInstance() {
- (*delete_counter_)++;
- }
+ ~TestSiteInstance() override { (*delete_counter_)++; }
int* delete_counter_;
};
@@ -204,7 +200,7 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
EXPECT_EQ(0, site_delete_counter);
NavigationEntryImpl* e1 = new NavigationEntryImpl(
- instance, 0, url, Referrer(), base::string16(), PAGE_TRANSITION_LINK,
+ instance, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
false);
// Redundantly setting e1's SiteInstance shouldn't affect the ref count.
@@ -213,7 +209,7 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
// Add a second reference
NavigationEntryImpl* e2 = new NavigationEntryImpl(
- instance, 0, url, Referrer(), base::string16(), PAGE_TRANSITION_LINK,
+ instance, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
false);
// Now delete both entries and be sure the SiteInstance goes away.
@@ -266,7 +262,7 @@ TEST_F(SiteInstanceTest, CloneNavigationEntry) {
&browsing_delete_counter);
NavigationEntryImpl* e1 = new NavigationEntryImpl(
- instance1, 0, url, Referrer(), base::string16(), PAGE_TRANSITION_LINK,
+ instance1, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
false);
// Clone the entry
NavigationEntryImpl* e2 = new NavigationEntryImpl(*e1);
@@ -372,6 +368,7 @@ TEST_F(SiteInstanceTest, IsSameWebSite) {
GURL url_foo_https = GURL("https://foo/a.html");
GURL url_foo_port = GURL("http://foo:8080/a.html");
GURL url_javascript = GURL("javascript:alert(1);");
+ GURL url_blank = GURL(url::kAboutBlankURL);
// Same scheme and port -> same site.
EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo2));
@@ -388,13 +385,23 @@ TEST_F(SiteInstanceTest, IsSameWebSite) {
EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_https));
EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, 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));
+
+ // 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));
+
DrainMessageLoops();
}
// Test to ensure that there is only one SiteInstance per site in a given
// BrowsingInstance, when process-per-site is not in use.
TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
- ASSERT_FALSE(CommandLine::ForCurrentProcess()->HasSwitch(
+ ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kProcessPerSite));
int delete_counter = 0;
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
@@ -468,7 +475,7 @@ TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
// Test to ensure that there is only one RenderProcessHost per site for an
// entire BrowserContext, if process-per-site is in use.
TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInBrowserContext) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kProcessPerSite);
int delete_counter = 0;
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
@@ -557,11 +564,20 @@ static SiteInstanceImpl* CreateSiteInstance(BrowserContext* browser_context,
// Test to ensure that pages that require certain privileges are grouped
// in processes with similar pages.
TEST_F(SiteInstanceTest, ProcessSharingByType) {
- // This test shouldn't run with --site-per-process mode, since it doesn't
- // allow render process reuse, which this test explicitly exercises.
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
+ // This test shouldn't run with --site-per-process or
+ // --enable-strict-site-isolation modes, since they don't allow render
+ // process reuse, which this test explicitly exercises.
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kSitePerProcess) ||
+ command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
return;
+ // On Android by default the number of renderer hosts is unlimited and process
+ // sharing doesn't happen. We set the override so that the test can run
+ // everywhere.
+ RenderProcessHost::SetMaxRendererProcessCount(kMaxRendererProcessCount);
+
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
@@ -607,6 +623,9 @@ TEST_F(SiteInstanceTest, ProcessSharingByType) {
}
DrainMessageLoops();
+
+ // Disable the process limit override.
+ RenderProcessHost::SetMaxRendererProcessCount(0u);
}
// Test to ensure that HasWrongProcessForURL behaves properly for different
@@ -671,7 +690,7 @@ TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
// Test to ensure that HasWrongProcessForURL behaves properly even when
// --site-per-process is used (http://crbug.com/160671).
TEST_F(SiteInstanceTest, HasWrongProcessForURLInSitePerProcess) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kSitePerProcess);
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
@@ -745,7 +764,7 @@ TEST_F(SiteInstanceTest, ProcessPerSiteWithWrongBindings) {
// Test that we do not register processes with empty sites for process-per-site
// mode.
TEST_F(SiteInstanceTest, NoProcessPerSiteForEmptySite) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kProcessPerSite);
scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
scoped_ptr<RenderProcessHost> host;
diff --git a/chromium/content/browser/site_per_process_browsertest.cc b/chromium/content/browser/site_per_process_browsertest.cc
index 3adb455acc2..145a24989e3 100644
--- a/chromium/content/browser/site_per_process_browsertest.cc
+++ b/chromium/content/browser/site_per_process_browsertest.cc
@@ -2,10 +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/site_per_process_browsertest.h"
+
#include "base/command_line.h"
#include "base/strings/stringprintf.h"
#include "content/browser/frame_host/cross_process_frame_connector.h"
#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/frame_host/navigator.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/renderer_host/render_view_host_impl.h"
@@ -16,13 +19,13 @@
#include "content/public/browser/web_contents_observer.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 "content/test/content_browser_test_utils_internal.h"
+#include "content/test/test_frame_navigation_observer.h"
#include "net/dns/mock_host_resolver.h"
-#include "url/gurl.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
namespace content {
@@ -31,38 +34,28 @@ class SitePerProcessWebContentsObserver: public WebContentsObserver {
explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
: WebContentsObserver(web_contents),
navigation_succeeded_(false) {}
- virtual ~SitePerProcessWebContentsObserver() {}
+ ~SitePerProcessWebContentsObserver() override {}
- virtual void DidStartProvisionalLoadForFrame(
- int64 frame_id,
- int64 parent_frame_id,
- bool is_main_frame,
- const GURL& validated_url,
- bool is_error_page,
- bool is_iframe_srcdoc,
- RenderViewHost* render_view_host) OVERRIDE {
+ void DidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ bool is_error_page,
+ bool is_iframe_srcdoc) override {
navigation_succeeded_ = false;
}
- virtual void DidFailProvisionalLoad(
- int64 frame_id,
- const base::string16& frame_unique_name,
- bool is_main_frame,
+ void DidFailProvisionalLoad(
+ RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code,
- const base::string16& error_description,
- RenderViewHost* render_view_host) OVERRIDE {
+ const base::string16& error_description) override {
navigation_url_ = validated_url;
navigation_succeeded_ = false;
}
- virtual void DidCommitProvisionalLoadForFrame(
- int64 frame_id,
- const base::string16& frame_unique_name,
- bool is_main_frame,
+ void DidCommitProvisionalLoadForFrame(
+ RenderFrameHost* render_frame_host,
const GURL& url,
- PageTransition transition_type,
- RenderViewHost* render_view_host) OVERRIDE{
+ ui::PageTransition transition_type) override {
navigation_url_ = url;
navigation_succeeded_ = true;
}
@@ -87,7 +80,7 @@ class RedirectNotificationObserver : public NotificationObserver {
// NotificationService::AllSources().
RedirectNotificationObserver(int notification_type,
const NotificationSource& source);
- virtual ~RedirectNotificationObserver();
+ ~RedirectNotificationObserver() override;
// Wait until the specified notification occurs. If the notification was
// emitted between the construction of this object and this call then it
@@ -105,9 +98,9 @@ class RedirectNotificationObserver : public NotificationObserver {
}
// NotificationObserver:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
private:
bool seen_;
@@ -158,53 +151,56 @@ void RedirectNotificationObserver::Observe(
running_ = false;
}
-class SitePerProcessBrowserTest : public ContentBrowserTest {
- public:
- SitePerProcessBrowserTest() {}
-
- protected:
- // Start at a data URL so each extra navigation creates a navigation entry.
- // (The first navigation will silently be classified as AUTO_SUBFRAME.)
- // TODO(creis): This won't be necessary when we can wait for LOAD_STOP.
- void StartFrameAtDataURL() {
- std::string data_url_script =
+//
+// SitePerProcessBrowserTest
+//
+
+SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
+};
+
+void SitePerProcessBrowserTest::StartFrameAtDataURL() {
+ std::string data_url_script =
"var iframes = document.getElementById('test');iframes.src="
"'data:text/html,dataurl';";
- ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
- }
+ ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
+}
- bool NavigateIframeToURL(Shell* window,
- const GURL& url,
- std::string iframe_id) {
- // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
- // navigations generate extra DidStartLoading and DidStopLoading messages.
- // Until we replace swappedout:// with frame proxies, we need to listen for
- // something else. For now, we trigger NEW_SUBFRAME navigations and listen
- // for commit.
- std::string script = base::StringPrintf(
- "setTimeout(\""
- "var iframes = document.getElementById('%s');iframes.src='%s';"
- "\",0)",
- iframe_id.c_str(), url.spec().c_str());
- WindowedNotificationObserver load_observer(
- NOTIFICATION_NAV_ENTRY_COMMITTED,
- Source<NavigationController>(
- &window->web_contents()->GetController()));
- bool result = ExecuteScript(window->web_contents(), script);
- load_observer.Wait();
- return result;
- }
+bool SitePerProcessBrowserTest::NavigateIframeToURL(Shell* window,
+ const GURL& url,
+ std::string iframe_id) {
+ // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
+ // navigations generate extra DidStartLoading and DidStopLoading messages.
+ // Until we replace swappedout:// with frame proxies, we need to listen for
+ // something else. For now, we trigger NEW_SUBFRAME navigations and listen
+ // for commit.
+ std::string script = base::StringPrintf(
+ "setTimeout(\""
+ "var iframes = document.getElementById('%s');iframes.src='%s';"
+ "\",0)",
+ iframe_id.c_str(), url.spec().c_str());
+ WindowedNotificationObserver load_observer(
+ NOTIFICATION_NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(
+ &window->web_contents()->GetController()));
+ bool result = ExecuteScript(window->web_contents(), script);
+ load_observer.Wait();
+ return result;
+}
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
- command_line->AppendSwitch(switches::kSitePerProcess);
- }
+void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine* command_line) {
+ command_line->AppendSwitch(switches::kSitePerProcess);
};
-// Ensure that we can complete a cross-process subframe navigation.
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
+void SitePerProcessBrowserTest::SetUpOnMainThread() {
host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(test_server()->Start());
- GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ SetupCrossSiteRedirector(embedded_test_server());
+}
+
+// Ensure that navigating subframes in --site-per-process mode works and the
+// correct documents are committed.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
+ 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.
@@ -216,7 +212,7 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
// Load same-site page into iframe.
FrameTreeNode* child = root->child_at(0);
- GURL http_url(test_server()->GetURL("files/title1.html"));
+ GURL http_url(embedded_test_server()->GetURL("/title1.html"));
NavigateFrameToURL(child, http_url);
EXPECT_EQ(http_url, observer.navigation_url());
EXPECT_TRUE(observer.navigation_succeeded());
@@ -233,20 +229,15 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
shell()->web_contents()->GetSiteInstance());
EXPECT_FALSE(proxy_to_parent);
- // These must stay in scope with replace_host.
- GURL::Replacements replace_host;
- std::string foo_com("foo.com");
-
// Load cross-site page into iframe.
- GURL cross_site_url(test_server()->GetURL("files/title2.html"));
- replace_host.SetHostStr(foo_com);
- cross_site_url = cross_site_url.ReplaceComponents(replace_host);
- NavigateFrameToURL(root->child_at(0), cross_site_url);
- EXPECT_EQ(cross_site_url, observer.navigation_url());
+ GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(0), url);
+ // Verify that the navigation succeeded and the expected URL was loaded.
EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(url, observer.navigation_url());
// Ensure that we have created a new process for the subframe.
- ASSERT_EQ(1U, root->child_count());
+ ASSERT_EQ(2U, root->child_count());
SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
RenderViewHost* rvh = child->current_frame_host()->render_view_host();
RenderProcessHost* rph = child->current_frame_host()->GetProcess();
@@ -269,17 +260,14 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
// Load another cross-site page into the same iframe.
- cross_site_url = test_server()->GetURL("files/title3.html");
- std::string bar_com("bar.com");
- replace_host.SetHostStr(bar_com);
- cross_site_url = cross_site_url.ReplaceComponents(replace_host);
- NavigateFrameToURL(root->child_at(0), cross_site_url);
- EXPECT_EQ(cross_site_url, observer.navigation_url());
+ url = embedded_test_server()->GetURL("bar.com", "/title3.html");
+ NavigateFrameToURL(root->child_at(0), url);
EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(url, observer.navigation_url());
// Check again that a new process is created and is different from the
// top level one and the previous one.
- ASSERT_EQ(1U, root->child_count());
+ ASSERT_EQ(2U, root->child_count());
child = root->child_at(0);
EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
child->current_frame_host()->render_view_host());
@@ -304,18 +292,66 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
}
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) {
+ 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();
+
+ SitePerProcessWebContentsObserver observer(shell()->web_contents());
+
+ // Load same-site page into iframe.
+ FrameTreeNode* child = root->child_at(0);
+ GURL http_url(embedded_test_server()->GetURL("/title1.html"));
+ NavigateFrameToURL(child, http_url);
+ EXPECT_EQ(http_url, observer.navigation_url());
+ EXPECT_TRUE(observer.navigation_succeeded());
+
+ // Load cross-site page into iframe.
+ GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
+ NavigateFrameToURL(root->child_at(0), url);
+ EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(url, observer.navigation_url());
+
+ // Ensure that we have created a new process for the subframe.
+ ASSERT_EQ(2U, root->child_count());
+ SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
+
+ // Emulate the main frame changing the src of the iframe such that it
+ // navigates cross-site.
+ url = embedded_test_server()->GetURL("bar.com", "/title3.html");
+ NavigateIframeToURL(shell(), url, "test");
+ EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(url, observer.navigation_url());
+
+ // Check again that a new process is created and is different from the
+ // top level one and the previous one.
+ ASSERT_EQ(2U, root->child_count());
+ child = root->child_at(0);
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+ child->current_frame_host()->GetSiteInstance());
+ EXPECT_NE(site_instance,
+ child->current_frame_host()->GetSiteInstance());
+
+ // Navigate back to the parent's origin and ensure we return to the
+ // parent's process.
+ NavigateFrameToURL(child, http_url);
+ EXPECT_EQ(http_url, observer.navigation_url());
+ EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+ child->current_frame_host()->GetSiteInstance());
+}
+
// Crash a subframe and ensures its children are cleared from the FrameTree.
// See http://crbug.com/338508.
+// TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
// TODO(creis): Enable this on Android when we can kill the process there.
-#if defined(OS_ANDROID)
-#define MAYBE_CrashSubframe DISABLED_CrashSubframe
-#else
-#define MAYBE_CrashSubframe CrashSubframe
-#endif
-IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CrashSubframe) {
- host_resolver()->AddRule("*", "127.0.0.1");
- ASSERT_TRUE(test_server()->Start());
- GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
+ GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
NavigateToURL(shell(), main_url);
StartFrameAtDataURL();
@@ -325,10 +361,10 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CrashSubframe) {
std::string foo_com("foo.com");
// Load cross-site page into iframe.
- GURL cross_site_url(test_server()->GetURL("files/title2.html"));
- replace_host.SetHostStr(foo_com);
- cross_site_url = cross_site_url.ReplaceComponents(replace_host);
- EXPECT_TRUE(NavigateIframeToURL(shell(), cross_site_url, "test"));
+ EXPECT_TRUE(NavigateIframeToURL(
+ shell(),
+ embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"),
+ "test"));
// Check the subframe process.
FrameTreeNode* root =
@@ -337,7 +373,12 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CrashSubframe) {
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child = root->child_at(0);
EXPECT_EQ(main_url, root->current_url());
- EXPECT_EQ(cross_site_url, child->current_url());
+ EXPECT_EQ("foo.com", child->current_url().host());
+ EXPECT_EQ("/title2.html", child->current_url().path());
+
+ EXPECT_TRUE(
+ child->current_frame_host()->render_view_host()->IsRenderViewLive());
+ EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
// Crash the subframe process.
RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
@@ -355,6 +396,11 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CrashSubframe) {
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(GURL(), child->current_url());
+ EXPECT_FALSE(
+ child->current_frame_host()->render_view_host()->IsRenderViewLive());
+ EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
+ EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
+
// Now crash the top-level page to clear the child frame.
{
RenderProcessHostWatcher crash_observer(
@@ -577,4 +623,116 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
}
}
+// Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
+// created in the FrameTree skipping the subtree of the navigating frame.
+//
+// Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
+#if defined(OS_MACOSX)
+#define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
+#else
+#define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ MAYBE_ProxyCreationSkipsSubtree) {
+ 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();
+
+ EXPECT_TRUE(root->child_at(1) != NULL);
+ EXPECT_EQ(2U, root->child_at(1)->child_count());
+
+ {
+ // Load same-site page into iframe.
+ SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ GURL http_url(embedded_test_server()->GetURL("/title1.html"));
+ NavigateFrameToURL(root->child_at(0), http_url);
+ EXPECT_EQ(http_url, observer.navigation_url());
+ EXPECT_TRUE(observer.navigation_succeeded());
+ RenderFrameProxyHost* proxy_to_parent =
+ root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
+ shell()->web_contents()->GetSiteInstance());
+ EXPECT_FALSE(proxy_to_parent);
+ }
+
+ // Create the cross-site URL to navigate to.
+ GURL cross_site_url =
+ embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
+
+ // Load cross-site page into the second iframe without waiting for the
+ // navigation to complete. Once LoadURLWithParams returns, we would expect
+ // proxies to have been created in the frame tree, but children of the
+ // navigating frame to still be present. The reason is that we don't run the
+ // message loop, so no IPCs that alter the frame tree can be processed.
+ FrameTreeNode* child = root->child_at(1);
+ SiteInstance* site = NULL;
+ {
+ SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ TestFrameNavigationObserver navigation_observer(child);
+ NavigationController::LoadURLParams params(cross_site_url);
+ params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
+ params.frame_tree_node_id = child->frame_tree_node_id();
+ child->navigator()->GetController()->LoadURLWithParams(params);
+ EXPECT_TRUE(child->render_manager()->pending_frame_host());
+
+ site = child->render_manager()->pending_frame_host()->GetSiteInstance();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
+
+ EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site));
+ EXPECT_TRUE(
+ root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site));
+ EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site));
+ for (size_t i = 0; i < child->child_count(); ++i) {
+ EXPECT_FALSE(
+ child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site));
+ }
+ // Now that the verification is done, run the message loop and wait for the
+ // navigation to complete.
+ navigation_observer.Wait();
+ EXPECT_FALSE(child->render_manager()->pending_frame_host());
+ EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(cross_site_url, observer.navigation_url());
+ }
+
+ // Load another cross-site page into the same iframe.
+ cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
+ {
+ // Perform the same checks as the first cross-site navigation, since
+ // there have been issues in subsequent cross-site navigations. Also ensure
+ // that the SiteInstance has properly changed.
+ // TODO(nasko): Once we have proper cleanup of resources, add code to
+ // verify that the intermediate SiteInstance/RenderFrameHost have been
+ // properly cleaned up.
+ SitePerProcessWebContentsObserver observer(shell()->web_contents());
+ TestFrameNavigationObserver navigation_observer(child);
+ NavigationController::LoadURLParams params(cross_site_url);
+ params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
+ params.frame_tree_node_id = child->frame_tree_node_id();
+ child->navigator()->GetController()->LoadURLWithParams(params);
+ EXPECT_TRUE(child->render_manager()->pending_frame_host() != NULL);
+
+ SiteInstance* site2 =
+ child->render_manager()->pending_frame_host()->GetSiteInstance();
+ EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
+ EXPECT_NE(site, site2);
+
+ EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site2));
+ EXPECT_TRUE(
+ root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2));
+ EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site2));
+ for (size_t i = 0; i < child->child_count(); ++i) {
+ EXPECT_FALSE(
+ child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site2));
+ }
+
+ navigation_observer.Wait();
+ EXPECT_TRUE(observer.navigation_succeeded());
+ EXPECT_EQ(cross_site_url, observer.navigation_url());
+ EXPECT_EQ(0U, child->child_count());
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/site_per_process_browsertest.h b/chromium/content/browser/site_per_process_browsertest.h
new file mode 100644
index 00000000000..19dfc01c598
--- /dev/null
+++ b/chromium/content/browser/site_per_process_browsertest.h
@@ -0,0 +1,30 @@
+// 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/public/test/content_browser_test.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class Shell;
+
+class SitePerProcessBrowserTest : public ContentBrowserTest {
+ public:
+ SitePerProcessBrowserTest();
+
+ protected:
+ // Start at a data URL so each extra navigation creates a navigation entry.
+ // (The first navigation will silently be classified as AUTO_SUBFRAME.)
+ // TODO(creis): This won't be necessary when we can wait for LOAD_STOP.
+ void StartFrameAtDataURL();
+
+ bool NavigateIframeToURL(Shell* window,
+ const GURL& url,
+ std::string iframe_id);
+
+ void SetUpCommandLine(base::CommandLine* command_line) override;
+ void SetUpOnMainThread() override;
+};
+
+} // namespace content
diff --git a/chromium/content/browser/speech/audio_encoder.cc b/chromium/content/browser/speech/audio_encoder.cc
index db8e2015c1d..09b5dca287d 100644
--- a/chromium/content/browser/speech/audio_encoder.cc
+++ b/chromium/content/browser/speech/audio_encoder.cc
@@ -24,9 +24,9 @@ const int kFLACCompressionLevel = 0; // 0 for speed
class FLACEncoder : public AudioEncoder {
public:
FLACEncoder(int sampling_rate, int bits_per_sample);
- virtual ~FLACEncoder();
- virtual void Encode(const AudioChunk& raw_audio) OVERRIDE;
- virtual void Flush() OVERRIDE;
+ ~FLACEncoder() override;
+ void Encode(const AudioChunk& raw_audio) override;
+ void Flush() override;
private:
static FLAC__StreamEncoderWriteStatus WriteCallback(
@@ -113,9 +113,9 @@ COMPILE_ASSERT(kMaxSpeexFrameLength <= 0xFF, invalidLength);
class SpeexEncoder : public AudioEncoder {
public:
explicit SpeexEncoder(int sampling_rate, int bits_per_sample);
- virtual ~SpeexEncoder();
- virtual void Encode(const AudioChunk& raw_audio) OVERRIDE;
- virtual void Flush() OVERRIDE {}
+ ~SpeexEncoder() override;
+ void Encode(const AudioChunk& raw_audio) override;
+ void Flush() override {}
private:
void* encoder_state_;
diff --git a/chromium/content/browser/speech/endpointer/endpointer_unittest.cc b/chromium/content/browser/speech/endpointer/endpointer_unittest.cc
index 306a5eeca28..807b6f68287 100644
--- a/chromium/content/browser/speech/endpointer/endpointer_unittest.cc
+++ b/chromium/content/browser/speech/endpointer/endpointer_unittest.cc
@@ -73,9 +73,7 @@ class EnergyEndpointerFrameProcessor : public FrameProcessor {
explicit EnergyEndpointerFrameProcessor(EnergyEndpointer* endpointer)
: endpointer_(endpointer) {}
- virtual EpStatus ProcessFrame(int64 time,
- int16* samples,
- int frame_size) OVERRIDE {
+ EpStatus ProcessFrame(int64 time, int16* samples, int frame_size) override {
endpointer_->ProcessAudioFrame(time, samples, kFrameSize, NULL);
int64 ep_time;
return endpointer_->Status(&ep_time);
@@ -118,9 +116,7 @@ class EndpointerFrameProcessor : public FrameProcessor {
explicit EndpointerFrameProcessor(Endpointer* endpointer)
: endpointer_(endpointer) {}
- virtual EpStatus ProcessFrame(int64 time,
- int16* samples,
- int frame_size) OVERRIDE {
+ EpStatus ProcessFrame(int64 time, int16* samples, int frame_size) override {
scoped_refptr<AudioChunk> frame(
new AudioChunk(reinterpret_cast<uint8*>(samples), kFrameSize * 2, 2));
endpointer_->ProcessAudio(*frame.get(), NULL);
diff --git a/chromium/content/browser/speech/google_one_shot_remote_engine.h b/chromium/content/browser/speech/google_one_shot_remote_engine.h
index b02766597b7..0e5b09f904e 100644
--- a/chromium/content/browser/speech/google_one_shot_remote_engine.h
+++ b/chromium/content/browser/speech/google_one_shot_remote_engine.h
@@ -33,19 +33,19 @@ class CONTENT_EXPORT GoogleOneShotRemoteEngine
static int url_fetcher_id_for_tests;
explicit GoogleOneShotRemoteEngine(net::URLRequestContextGetter* context);
- virtual ~GoogleOneShotRemoteEngine();
+ ~GoogleOneShotRemoteEngine() override;
// SpeechRecognitionEngine methods.
- virtual void SetConfig(const SpeechRecognitionEngineConfig& config) OVERRIDE;
- virtual void StartRecognition() OVERRIDE;
- virtual void EndRecognition() OVERRIDE;
- virtual void TakeAudioChunk(const AudioChunk& data) OVERRIDE;
- virtual void AudioChunksEnded() OVERRIDE;
- virtual bool IsRecognitionPending() const OVERRIDE;
- virtual int GetDesiredAudioChunkDurationMs() const OVERRIDE;
+ void SetConfig(const SpeechRecognitionEngineConfig& config) override;
+ void StartRecognition() override;
+ void EndRecognition() override;
+ void TakeAudioChunk(const AudioChunk& data) override;
+ void AudioChunksEnded() override;
+ bool IsRecognitionPending() const override;
+ int GetDesiredAudioChunkDurationMs() const override;
// net::URLFetcherDelegate methods.
- virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
private:
SpeechRecognitionEngineConfig config_;
diff --git a/chromium/content/browser/speech/google_one_shot_remote_engine_unittest.cc b/chromium/content/browser/speech/google_one_shot_remote_engine_unittest.cc
index a16329cadff..16950102a28 100644
--- a/chromium/content/browser/speech/google_one_shot_remote_engine_unittest.cc
+++ b/chromium/content/browser/speech/google_one_shot_remote_engine_unittest.cc
@@ -26,13 +26,13 @@ class GoogleOneShotRemoteEngineTest : public SpeechRecognitionEngineDelegate,
void CreateAndTestRequest(bool success, const std::string& http_response);
// SpeechRecognitionRequestDelegate methods.
- virtual void OnSpeechRecognitionEngineResults(
- const SpeechRecognitionResults& results) OVERRIDE {
+ void OnSpeechRecognitionEngineResults(
+ const SpeechRecognitionResults& results) override {
results_ = results;
}
- virtual void OnSpeechRecognitionEngineError(
- const SpeechRecognitionError& error) OVERRIDE {
+ void OnSpeechRecognitionEngineError(
+ const SpeechRecognitionError& error) override {
error_ = error.code;
}
diff --git a/chromium/content/browser/speech/google_streaming_remote_engine.cc b/chromium/content/browser/speech/google_streaming_remote_engine.cc
index f9e2e6ea04d..7fea0fa90a6 100644
--- a/chromium/content/browser/speech/google_streaming_remote_engine.cc
+++ b/chromium/content/browser/speech/google_streaming_remote_engine.cc
@@ -53,7 +53,7 @@ void DumpResponse(const std::string& response) {
DVLOG(1) << "RESULT #" << i << ":";
const proto::SpeechRecognitionResult& res = event.result(i);
if (res.has_final())
- DVLOG(1) << " FINAL:\t" << res.final();
+ DVLOG(1) << " final:\t" << res.final();
if (res.has_stability())
DVLOG(1) << " STABILITY:\t" << res.stability();
for (int j = 0; j < res.alternative_size(); ++j) {
diff --git a/chromium/content/browser/speech/google_streaming_remote_engine.h b/chromium/content/browser/speech/google_streaming_remote_engine.h
index 11afae00e6c..961ef0877db 100644
--- a/chromium/content/browser/speech/google_streaming_remote_engine.h
+++ b/chromium/content/browser/speech/google_streaming_remote_engine.h
@@ -57,21 +57,22 @@ class CONTENT_EXPORT GoogleStreamingRemoteEngine
static const int kDownstreamUrlFetcherIdForTesting;
explicit GoogleStreamingRemoteEngine(net::URLRequestContextGetter* context);
- virtual ~GoogleStreamingRemoteEngine();
+ ~GoogleStreamingRemoteEngine() override;
// SpeechRecognitionEngine methods.
- virtual void SetConfig(const SpeechRecognitionEngineConfig& config) OVERRIDE;
- virtual void StartRecognition() OVERRIDE;
- virtual void EndRecognition() OVERRIDE;
- virtual void TakeAudioChunk(const AudioChunk& data) OVERRIDE;
- virtual void AudioChunksEnded() OVERRIDE;
- virtual bool IsRecognitionPending() const OVERRIDE;
- virtual int GetDesiredAudioChunkDurationMs() const OVERRIDE;
+ void SetConfig(const SpeechRecognitionEngineConfig& config) override;
+ void StartRecognition() override;
+ void EndRecognition() override;
+ void TakeAudioChunk(const AudioChunk& data) override;
+ void AudioChunksEnded() override;
+ bool IsRecognitionPending() const override;
+ int GetDesiredAudioChunkDurationMs() const override;
// net::URLFetcherDelegate methods.
- virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
- virtual void OnURLFetchDownloadProgress(const net::URLFetcher* source,
- int64 current, int64 total) OVERRIDE;
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
+ void OnURLFetchDownloadProgress(const net::URLFetcher* source,
+ int64 current,
+ int64 total) override;
private:
// Response status codes from the speech recognition webservice.
diff --git a/chromium/content/browser/speech/google_streaming_remote_engine_unittest.cc b/chromium/content/browser/speech/google_streaming_remote_engine_unittest.cc
index ab703d7ac04..57947e61e5d 100644
--- a/chromium/content/browser/speech/google_streaming_remote_engine_unittest.cc
+++ b/chromium/content/browser/speech/google_streaming_remote_engine_unittest.cc
@@ -42,18 +42,18 @@ class GoogleStreamingRemoteEngineTest : public SpeechRecognitionEngineDelegate,
void CreateAndTestRequest(bool success, const std::string& http_response);
// SpeechRecognitionRequestDelegate methods.
- virtual void OnSpeechRecognitionEngineResults(
- const SpeechRecognitionResults& results) OVERRIDE {
+ void OnSpeechRecognitionEngineResults(
+ const SpeechRecognitionResults& results) override {
results_.push(results);
}
- virtual void OnSpeechRecognitionEngineError(
- const SpeechRecognitionError& error) OVERRIDE {
+ void OnSpeechRecognitionEngineError(
+ const SpeechRecognitionError& error) override {
error_ = error.code;
}
// testing::Test methods.
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
+ void SetUp() override;
+ void TearDown() override;
protected:
enum DownstreamError {
diff --git a/chromium/content/browser/speech/speech_recognition_browsertest.cc b/chromium/content/browser/speech/speech_recognition_browsertest.cc
index 5871aa193f8..02671a4786f 100644
--- a/chromium/content/browser/speech/speech_recognition_browsertest.cc
+++ b/chromium/content/browser/speech/speech_recognition_browsertest.cc
@@ -44,29 +44,29 @@ class SpeechRecognitionBrowserTest :
};
// MockGoogleStreamingServerDelegate methods.
- virtual void OnClientConnected() OVERRIDE {
+ void OnClientConnected() override {
ASSERT_EQ(kTestAudioControllerOpened, streaming_server_state_);
streaming_server_state_ = kClientConnected;
}
- virtual void OnClientAudioUpload() OVERRIDE {
+ void OnClientAudioUpload() override {
if (streaming_server_state_ == kClientConnected)
streaming_server_state_ = kClientAudioUpload;
}
- virtual void OnClientAudioUploadComplete() OVERRIDE {
+ void OnClientAudioUploadComplete() override {
ASSERT_EQ(kTestAudioControllerClosed, streaming_server_state_);
streaming_server_state_ = kClientAudioUploadComplete;
}
- virtual void OnClientDisconnected() OVERRIDE {
+ void OnClientDisconnected() override {
ASSERT_EQ(kClientAudioUploadComplete, streaming_server_state_);
streaming_server_state_ = kClientDisconnected;
}
// media::TestAudioInputControllerDelegate methods.
- virtual void TestAudioControllerOpened(
- media::TestAudioInputController* controller) OVERRIDE {
+ void TestAudioControllerOpened(
+ media::TestAudioInputController* controller) override {
ASSERT_EQ(kIdle, streaming_server_state_);
streaming_server_state_ = kTestAudioControllerOpened;
const int capture_packet_interval_ms =
@@ -79,8 +79,8 @@ class SpeechRecognitionBrowserTest :
FeedAudioController(1000 /* ms */, /*noise=*/ false);
}
- virtual void TestAudioControllerClosed(
- media::TestAudioInputController* controller) OVERRIDE {
+ void TestAudioControllerClosed(
+ media::TestAudioInputController* controller) override {
ASSERT_EQ(kClientAudioUpload, streaming_server_state_);
streaming_server_state_ = kTestAudioControllerClosed;
mock_streaming_server_->MockGoogleStreamingServer::SimulateResult(
@@ -103,7 +103,7 @@ class SpeechRecognitionBrowserTest :
protected:
// ContentBrowserTest methods.
- virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
+ void SetUpInProcessBrowserTestFixture() override {
test_audio_input_controller_factory_.set_delegate(this);
media::AudioInputController::set_factory_for_testing(
&test_audio_input_controller_factory_);
@@ -111,18 +111,18 @@ class SpeechRecognitionBrowserTest :
streaming_server_state_ = kIdle;
}
- virtual void SetUpOnMainThread() OVERRIDE {
+ void SetUpOnMainThread() override {
ASSERT_TRUE(SpeechRecognitionManagerImpl::GetInstance());
SpeechRecognizerImpl::SetAudioManagerForTesting(
new media::MockAudioManager(BrowserThread::GetMessageLoopProxyForThread(
BrowserThread::IO)));
}
- virtual void TearDownOnMainThread() OVERRIDE {
+ void TearDownOnMainThread() override {
SpeechRecognizerImpl::SetAudioManagerForTesting(NULL);
}
- virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
+ void TearDownInProcessBrowserTestFixture() override {
test_audio_input_controller_factory_.set_delegate(NULL);
mock_streaming_server_.reset();
}
@@ -148,7 +148,7 @@ class SpeechRecognitionBrowserTest :
audio_bus->FromInterleaved(&audio_buffer.get()[0],
audio_bus->frames(),
audio_params.bits_per_sample() / 8);
- controller->event_handler()->OnData(controller, audio_bus.get());
+ controller->event_handler()->OnData(controller.get(), audio_bus.get());
}
void FeedAudioController(int duration_ms, bool feed_with_noise) {
@@ -188,7 +188,13 @@ class SpeechRecognitionBrowserTest :
// Simply loads the test page and checks if it was able to create a Speech
// Recognition object in JavaScript, to make sure the Web Speech API is enabled.
-IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, Precheck) {
+// http://crbug.com/396414
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#define MAYBE_Precheck DISABLED_Precheck
+#else
+#define MAYBE_Precheck Precheck
+#endif
+IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, MAYBE_Precheck) {
NavigateToURLBlockUntilNavigationsComplete(
shell(), GetTestUrlFromFragment("precheck"), 2);
diff --git a/chromium/content/browser/speech/speech_recognition_dispatcher_host.cc b/chromium/content/browser/speech/speech_recognition_dispatcher_host.cc
index 05a24527efe..f920c51e779 100644
--- a/chromium/content/browser/speech/speech_recognition_dispatcher_host.cc
+++ b/chromium/content/browser/speech/speech_recognition_dispatcher_host.cc
@@ -42,6 +42,10 @@ SpeechRecognitionDispatcherHost::AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
+void SpeechRecognitionDispatcherHost::OnDestruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
bool SpeechRecognitionDispatcherHost::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
@@ -88,6 +92,12 @@ void SpeechRecognitionDispatcherHost::OnStartRequest(
int embedder_render_view_id = MSG_ROUTING_NONE;
RenderViewHostImpl* render_view_host =
RenderViewHostImpl::FromID(render_process_id_, params.render_view_id);
+ if (!render_view_host) {
+ // RVH can be null if the tab was closed while continuous mode speech
+ // recognition was running. This seems to happen on mac.
+ LOG(WARNING) << "SRDH::OnStartRequest, RenderViewHost does not exist";
+ return;
+ }
WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
WebContents::FromRenderViewHost(render_view_host));
BrowserPluginGuest* guest = web_contents->GetBrowserPluginGuest();
@@ -110,6 +120,12 @@ void SpeechRecognitionDispatcherHost::OnStartRequest(
SpeechRecognitionManagerImpl::GetInstance()->delegate()->
FilterProfanities(render_process_id_);
+ // TODO(miu): This is a hack to allow SpeechRecognition to operate with the
+ // MediaStreamManager, which partitions requests per RenderFrame, not per
+ // RenderView. http://crbug.com/390749
+ const int params_render_frame_id = render_view_host ?
+ render_view_host->GetMainFrame()->GetRoutingID() : MSG_ROUTING_NONE;
+
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
@@ -118,6 +134,7 @@ void SpeechRecognitionDispatcherHost::OnStartRequest(
embedder_render_process_id,
embedder_render_view_id,
input_params,
+ params_render_frame_id,
filter_profanities));
}
@@ -125,11 +142,13 @@ void SpeechRecognitionDispatcherHost::OnStartRequestOnIO(
int embedder_render_process_id,
int embedder_render_view_id,
const SpeechRecognitionHostMsg_StartRequest_Params& params,
+ int params_render_frame_id,
bool filter_profanities) {
SpeechRecognitionSessionContext context;
context.context_name = params.origin_url;
context.render_process_id = render_process_id_;
context.render_view_id = params.render_view_id;
+ context.render_frame_id = params_render_frame_id;
context.embedder_render_process_id = embedder_render_process_id;
context.embedder_render_view_id = embedder_render_view_id;
if (embedder_render_process_id)
diff --git a/chromium/content/browser/speech/speech_recognition_dispatcher_host.h b/chromium/content/browser/speech/speech_recognition_dispatcher_host.h
index 72e7ee147d1..34b333207e8 100644
--- a/chromium/content/browser/speech/speech_recognition_dispatcher_host.h
+++ b/chromium/content/browser/speech/speech_recognition_dispatcher_host.h
@@ -34,33 +34,34 @@ class CONTENT_EXPORT SpeechRecognitionDispatcherHost
base::WeakPtr<SpeechRecognitionDispatcherHost> AsWeakPtr();
// SpeechRecognitionEventListener methods.
- virtual void OnRecognitionStart(int session_id) OVERRIDE;
- virtual void OnAudioStart(int session_id) OVERRIDE;
- virtual void OnEnvironmentEstimationComplete(int session_id) OVERRIDE;
- virtual void OnSoundStart(int session_id) OVERRIDE;
- virtual void OnSoundEnd(int session_id) OVERRIDE;
- virtual void OnAudioEnd(int session_id) OVERRIDE;
- virtual void OnRecognitionEnd(int session_id) OVERRIDE;
- virtual void OnRecognitionResults(
- int session_id,
- const SpeechRecognitionResults& results) OVERRIDE;
- virtual void OnRecognitionError(
- int session_id,
- const SpeechRecognitionError& error) OVERRIDE;
- virtual void OnAudioLevelsChange(int session_id,
- float volume,
- float noise_volume) OVERRIDE;
+ void OnRecognitionStart(int session_id) override;
+ void OnAudioStart(int session_id) override;
+ void OnEnvironmentEstimationComplete(int session_id) override;
+ void OnSoundStart(int session_id) override;
+ void OnSoundEnd(int session_id) override;
+ void OnAudioEnd(int session_id) override;
+ void OnRecognitionEnd(int session_id) override;
+ void OnRecognitionResults(int session_id,
+ const SpeechRecognitionResults& results) override;
+ void OnRecognitionError(int session_id,
+ const SpeechRecognitionError& error) override;
+ void OnAudioLevelsChange(int session_id,
+ float volume,
+ float noise_volume) override;
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OverrideThreadForMessage(
- const IPC::Message& message,
- BrowserThread::ID* thread) OVERRIDE;
+ void OnDestruct() const override;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) override;
- virtual void OnChannelClosing() OVERRIDE;
+ void OnChannelClosing() override;
private:
- virtual ~SpeechRecognitionDispatcherHost();
+ friend class base::DeleteHelper<SpeechRecognitionDispatcherHost>;
+ friend class BrowserThread;
+
+ ~SpeechRecognitionDispatcherHost() override;
void OnStartRequest(
const SpeechRecognitionHostMsg_StartRequest_Params& params);
@@ -68,6 +69,7 @@ class CONTENT_EXPORT SpeechRecognitionDispatcherHost
int embedder_render_process_id,
int embedder_render_view_id,
const SpeechRecognitionHostMsg_StartRequest_Params& params,
+ int params_render_frame_id,
bool filter_profanities);
void OnAbortRequest(int render_view_id, int request_id);
void OnStopCaptureRequest(int render_view_id, int request_id);
diff --git a/chromium/content/browser/speech/speech_recognition_manager_impl.cc b/chromium/content/browser/speech/speech_recognition_manager_impl.cc
index 4b0827a6b62..1a054204c44 100644
--- a/chromium/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/chromium/content/browser/speech/speech_recognition_manager_impl.cc
@@ -196,7 +196,7 @@ void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id,
SpeechRecognitionSessionContext& context = session->context;
context.label = media_stream_manager_->MakeMediaAccessRequest(
context.render_process_id,
- context.render_view_id,
+ context.render_frame_id,
context.request_id,
StreamOptions(true, false),
GURL(context.context_name),
diff --git a/chromium/content/browser/speech/speech_recognition_manager_impl.h b/chromium/content/browser/speech/speech_recognition_manager_impl.h
index 9a60e077437..9b8da39fc47 100644
--- a/chromium/content/browser/speech/speech_recognition_manager_impl.h
+++ b/chromium/content/browser/speech/speech_recognition_manager_impl.h
@@ -58,39 +58,39 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl :
static SpeechRecognitionManagerImpl* GetInstance();
// SpeechRecognitionManager implementation.
- virtual int CreateSession(
- const SpeechRecognitionSessionConfig& config) OVERRIDE;
- virtual void StartSession(int session_id) OVERRIDE;
- virtual void AbortSession(int session_id) OVERRIDE;
- virtual void AbortAllSessionsForRenderProcess(int render_process_id) OVERRIDE;
- virtual void AbortAllSessionsForRenderView(int render_process_id,
- int render_view_id) OVERRIDE;
- virtual void StopAudioCaptureForSession(int session_id) OVERRIDE;
- virtual const SpeechRecognitionSessionConfig& GetSessionConfig(
- int session_id) const OVERRIDE;
- virtual SpeechRecognitionSessionContext GetSessionContext(
- int session_id) const OVERRIDE;
- virtual int GetSession(int render_process_id,
- int render_view_id,
- int request_id) const OVERRIDE;
- virtual bool HasAudioInputDevices() OVERRIDE;
- virtual base::string16 GetAudioInputDeviceModel() OVERRIDE;
- virtual void ShowAudioInputSettings() OVERRIDE;
+ int CreateSession(const SpeechRecognitionSessionConfig& config) override;
+ void StartSession(int session_id) override;
+ void AbortSession(int session_id) override;
+ void AbortAllSessionsForRenderProcess(int render_process_id) override;
+ void AbortAllSessionsForRenderView(int render_process_id,
+ int render_view_id) override;
+ void StopAudioCaptureForSession(int session_id) override;
+ const SpeechRecognitionSessionConfig& GetSessionConfig(
+ int session_id) const override;
+ SpeechRecognitionSessionContext GetSessionContext(
+ int session_id) const override;
+ int GetSession(int render_process_id,
+ int render_view_id,
+ int request_id) const override;
+ bool HasAudioInputDevices() override;
+ base::string16 GetAudioInputDeviceModel() override;
+ void ShowAudioInputSettings() override;
// SpeechRecognitionEventListener methods.
- virtual void OnRecognitionStart(int session_id) OVERRIDE;
- virtual void OnAudioStart(int session_id) OVERRIDE;
- virtual void OnEnvironmentEstimationComplete(int session_id) OVERRIDE;
- virtual void OnSoundStart(int session_id) OVERRIDE;
- virtual void OnSoundEnd(int session_id) OVERRIDE;
- virtual void OnAudioEnd(int session_id) OVERRIDE;
- virtual void OnRecognitionEnd(int session_id) OVERRIDE;
- virtual void OnRecognitionResults(
- int session_id, const SpeechRecognitionResults& result) OVERRIDE;
- virtual void OnRecognitionError(
- int session_id, const SpeechRecognitionError& error) OVERRIDE;
- virtual void OnAudioLevelsChange(int session_id, float volume,
- float noise_volume) OVERRIDE;
+ void OnRecognitionStart(int session_id) override;
+ void OnAudioStart(int session_id) override;
+ void OnEnvironmentEstimationComplete(int session_id) override;
+ void OnSoundStart(int session_id) override;
+ void OnSoundEnd(int session_id) override;
+ void OnAudioEnd(int session_id) override;
+ void OnRecognitionEnd(int session_id) override;
+ void OnRecognitionResults(int session_id,
+ const SpeechRecognitionResults& result) override;
+ void OnRecognitionError(int session_id,
+ const SpeechRecognitionError& error) override;
+ void OnAudioLevelsChange(int session_id,
+ float volume,
+ float noise_volume) override;
SpeechRecognitionManagerDelegate* delegate() const { return delegate_.get(); }
@@ -101,7 +101,7 @@ class CONTENT_EXPORT SpeechRecognitionManagerImpl :
friend struct base::DefaultDeleter<SpeechRecognitionManagerImpl>;
SpeechRecognitionManagerImpl(media::AudioManager* audio_manager,
MediaStreamManager* media_stream_manager);
- virtual ~SpeechRecognitionManagerImpl();
+ ~SpeechRecognitionManagerImpl() override;
private:
// Data types for the internal Finite State Machine (FSM).
diff --git a/chromium/content/browser/speech/speech_recognizer_impl.cc b/chromium/content/browser/speech/speech_recognizer_impl.cc
index e49d30139aa..f6fb3900a5e 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl.cc
+++ b/chromium/content/browser/speech/speech_recognizer_impl.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/time/time.h"
#include "content/browser/browser_main_loop.h"
+#include "content/browser/media/media_internals.h"
#include "content/browser/speech/audio_buffer.h"
#include "content/browser/speech/google_one_shot_remote_engine.h"
#include "content/public/browser/speech_recognition_event_listener.h"
@@ -35,7 +36,7 @@ class SpeechRecognizerImpl::OnDataConverter
public:
OnDataConverter(const AudioParameters& input_params,
const AudioParameters& output_params);
- virtual ~OnDataConverter();
+ ~OnDataConverter() override;
// Converts input audio |data| bus into an AudioChunk where the input format
// is given by |input_parameters_| and the output format by
@@ -44,8 +45,7 @@ class SpeechRecognizerImpl::OnDataConverter
private:
// media::AudioConverter::InputCallback implementation.
- virtual double ProvideInput(AudioBus* dest,
- base::TimeDelta buffer_delay) OVERRIDE;
+ double ProvideInput(AudioBus* dest, base::TimeDelta buffer_delay) override;
// Handles resampling, buffering, and channel mixing between input and output
// parameters.
@@ -178,6 +178,8 @@ SpeechRecognizerImpl::SpeechRecognizerImpl(
: SpeechRecognizer(listener, session_id),
recognition_engine_(engine),
endpointer_(kAudioSampleRate),
+ audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
+ media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)),
is_dispatching_event_(false),
provisional_results_(provisional_results),
state_(STATE_IDLE) {
@@ -258,6 +260,7 @@ SpeechRecognizerImpl::~SpeechRecognizerImpl() {
if (audio_controller_.get()) {
audio_controller_->Close(
base::Bind(&KeepAudioControllerRefcountedForDtor, audio_controller_));
+ audio_log_->OnClosed(0);
}
}
@@ -552,7 +555,6 @@ SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) {
input_parameters.Reset(in_params.format(),
in_params.channel_layout(),
in_params.channels(),
- in_params.input_channels(),
in_params.sample_rate(),
in_params.bits_per_sample(),
frames_per_buffer);
@@ -570,12 +572,15 @@ SpeechRecognizerImpl::StartRecording(const FSMEventArgs&) {
return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO));
}
+ audio_log_->OnCreated(0, input_parameters, device_id_);
+
// The endpointer needs to estimate the environment/background noise before
// starting to treat the audio as user input. We wait in the state
// ESTIMATING_ENVIRONMENT until such interval has elapsed before switching
// to user input mode.
endpointer_.SetEnvironmentEstimationMode();
audio_controller_->Record();
+ audio_log_->OnStarted(0);
return STATE_STARTING;
}
@@ -772,6 +777,7 @@ void SpeechRecognizerImpl::CloseAudioControllerAsynchronously() {
audio_controller_->Close(base::Bind(&SpeechRecognizerImpl::OnAudioClosed,
this, audio_controller_));
audio_controller_ = NULL; // The controller is still refcounted by Bind.
+ audio_log_->OnClosed(0);
}
int SpeechRecognizerImpl::GetElapsedTimeMs() const {
diff --git a/chromium/content/browser/speech/speech_recognizer_impl.h b/chromium/content/browser/speech/speech_recognizer_impl.h
index 55e07f04ef6..3a26d335cac 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl.h
+++ b/chromium/content/browser/speech/speech_recognizer_impl.h
@@ -13,6 +13,7 @@
#include "content/public/common/speech_recognition_error.h"
#include "content/public/common/speech_recognition_result.h"
#include "media/audio/audio_input_controller.h"
+#include "media/audio/audio_logging.h"
#include "net/url_request/url_request_context_getter.h"
namespace media {
@@ -46,11 +47,11 @@ class CONTENT_EXPORT SpeechRecognizerImpl
bool provisional_results,
SpeechRecognitionEngine* engine);
- virtual void StartRecognition(const std::string& device_id) OVERRIDE;
- virtual void AbortRecognition() OVERRIDE;
- virtual void StopAudioCapture() OVERRIDE;
- virtual bool IsActive() const OVERRIDE;
- virtual bool IsCapturingAudio() const OVERRIDE;
+ void StartRecognition(const std::string& device_id) override;
+ void AbortRecognition() override;
+ void StopAudioCapture() override;
+ bool IsActive() const override;
+ bool IsCapturingAudio() const override;
const SpeechRecognitionEngine& recognition_engine() const;
private:
@@ -88,7 +89,7 @@ class CONTENT_EXPORT SpeechRecognizerImpl
SpeechRecognitionError engine_error;
};
- virtual ~SpeechRecognizerImpl();
+ ~SpeechRecognizerImpl() override;
// Entry point for pushing any new external event into the recognizer FSM.
void DispatchEvent(const FSMEventArgs& event_args);
@@ -128,26 +129,27 @@ class CONTENT_EXPORT SpeechRecognizerImpl
void OnAudioClosed(media::AudioInputController*);
// AudioInputController::EventHandler methods.
- virtual void OnCreated(media::AudioInputController* controller) OVERRIDE {}
- virtual void OnRecording(media::AudioInputController* controller) OVERRIDE {}
- virtual void OnError(media::AudioInputController* controller,
- media::AudioInputController::ErrorCode error_code) OVERRIDE;
- virtual void OnData(media::AudioInputController* controller,
- const media::AudioBus* data) OVERRIDE;
- virtual void OnLog(media::AudioInputController* controller,
- const std::string& message) OVERRIDE {}
+ void OnCreated(media::AudioInputController* controller) override {}
+ void OnRecording(media::AudioInputController* controller) override {}
+ void OnError(media::AudioInputController* controller,
+ media::AudioInputController::ErrorCode error_code) override;
+ void OnData(media::AudioInputController* controller,
+ const media::AudioBus* data) override;
+ void OnLog(media::AudioInputController* controller,
+ const std::string& message) override {}
// SpeechRecognitionEngineDelegate methods.
- virtual void OnSpeechRecognitionEngineResults(
- const SpeechRecognitionResults& results) OVERRIDE;
- virtual void OnSpeechRecognitionEngineError(
- const SpeechRecognitionError& error) OVERRIDE;
+ void OnSpeechRecognitionEngineResults(
+ const SpeechRecognitionResults& results) override;
+ void OnSpeechRecognitionEngineError(
+ const SpeechRecognitionError& error) override;
static media::AudioManager* audio_manager_for_tests_;
scoped_ptr<SpeechRecognitionEngine> recognition_engine_;
Endpointer endpointer_;
scoped_refptr<media::AudioInputController> audio_controller_;
+ scoped_ptr<media::AudioLog> audio_log_;
int num_samples_recorded_;
float audio_level_;
bool is_dispatching_event_;
diff --git a/chromium/content/browser/speech/speech_recognizer_impl_android.h b/chromium/content/browser/speech/speech_recognizer_impl_android.h
index e6e7f09ec69..cdf0b4db6d8 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl_android.h
+++ b/chromium/content/browser/speech/speech_recognizer_impl_android.h
@@ -24,11 +24,11 @@ class CONTENT_EXPORT SpeechRecognizerImplAndroid : public SpeechRecognizer {
int session_id);
// SpeechRecognizer methods.
- virtual void StartRecognition(const std::string& device_id) OVERRIDE;
- virtual void AbortRecognition() OVERRIDE;
- virtual void StopAudioCapture() OVERRIDE;
- virtual bool IsActive() const OVERRIDE;
- virtual bool IsCapturingAudio() const OVERRIDE;
+ virtual void StartRecognition(const std::string& device_id) override;
+ virtual void AbortRecognition() override;
+ virtual void StopAudioCapture() override;
+ virtual bool IsActive() const override;
+ virtual bool IsCapturingAudio() const override;
// Called from Java methods via JNI.
void OnAudioStart(JNIEnv* env, jobject obj);
diff --git a/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc b/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
index 13d5eba7dfc..7168fb64973 100644
--- a/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
+++ b/chromium/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -95,63 +95,64 @@ class SpeechRecognizerImplTest : public SpeechRecognitionEventListener,
}
// Overridden from SpeechRecognitionEventListener:
- virtual void OnAudioStart(int session_id) OVERRIDE {
+ void OnAudioStart(int session_id) override {
audio_started_ = true;
CheckEventsConsistency();
}
- virtual void OnAudioEnd(int session_id) OVERRIDE {
+ void OnAudioEnd(int session_id) override {
audio_ended_ = true;
CheckEventsConsistency();
}
- virtual void OnRecognitionResults(
- int session_id, const SpeechRecognitionResults& results) OVERRIDE {
+ void OnRecognitionResults(int session_id,
+ const SpeechRecognitionResults& results) override {
result_received_ = true;
}
- virtual void OnRecognitionError(
- int session_id, const SpeechRecognitionError& error) OVERRIDE {
+ void OnRecognitionError(int session_id,
+ const SpeechRecognitionError& error) override {
EXPECT_TRUE(recognition_started_);
EXPECT_FALSE(recognition_ended_);
error_ = error.code;
}
- virtual void OnAudioLevelsChange(int session_id, float volume,
- float noise_volume) OVERRIDE {
+ void OnAudioLevelsChange(int session_id,
+ float volume,
+ float noise_volume) override {
volume_ = volume;
noise_volume_ = noise_volume;
}
- virtual void OnRecognitionEnd(int session_id) OVERRIDE {
+ void OnRecognitionEnd(int session_id) override {
recognition_ended_ = true;
CheckEventsConsistency();
}
- virtual void OnRecognitionStart(int session_id) OVERRIDE {
+ void OnRecognitionStart(int session_id) override {
recognition_started_ = true;
CheckEventsConsistency();
}
- virtual void OnEnvironmentEstimationComplete(int session_id) OVERRIDE {}
+ void OnEnvironmentEstimationComplete(int session_id) override {}
- virtual void OnSoundStart(int session_id) OVERRIDE {
+ void OnSoundStart(int session_id) override {
sound_started_ = true;
CheckEventsConsistency();
}
- virtual void OnSoundEnd(int session_id) OVERRIDE {
+ void OnSoundEnd(int session_id) override {
sound_ended_ = true;
CheckEventsConsistency();
}
// testing::Test methods.
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
AudioInputController::set_factory_for_testing(
&audio_input_controller_factory_);
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
AudioInputController::set_factory_for_testing(NULL);
}
diff --git a/chromium/content/browser/ssl/ssl_cert_error_handler.cc b/chromium/content/browser/ssl/ssl_cert_error_handler.cc
index a69e993380a..9ec7885d58d 100644
--- a/chromium/content/browser/ssl/ssl_cert_error_handler.cc
+++ b/chromium/content/browser/ssl/ssl_cert_error_handler.cc
@@ -13,14 +13,16 @@ namespace content {
SSLCertErrorHandler::SSLCertErrorHandler(
const base::WeakPtr<Delegate>& delegate,
- const GlobalRequestID& id,
- ResourceType::Type resource_type,
+ ResourceType resource_type,
const GURL& url,
int render_process_id,
int render_frame_id,
const net::SSLInfo& ssl_info,
bool fatal)
- : SSLErrorHandler(delegate, id, resource_type, url, render_process_id,
+ : SSLErrorHandler(delegate,
+ resource_type,
+ url,
+ render_process_id,
render_frame_id),
ssl_info_(ssl_info),
cert_error_(net::MapCertStatusToNetError(ssl_info.cert_status)),
diff --git a/chromium/content/browser/ssl/ssl_cert_error_handler.h b/chromium/content/browser/ssl/ssl_cert_error_handler.h
index 6946f42921f..e3c4378f167 100644
--- a/chromium/content/browser/ssl/ssl_cert_error_handler.h
+++ b/chromium/content/browser/ssl/ssl_cert_error_handler.h
@@ -20,15 +20,14 @@ class SSLCertErrorHandler : public SSLErrorHandler {
public:
// Construct on the IO thread.
SSLCertErrorHandler(const base::WeakPtr<Delegate>& delegate,
- const GlobalRequestID& id,
- ResourceType::Type resource_type,
+ ResourceType resource_type,
const GURL& url,
int render_process_id,
int render_frame_id,
const net::SSLInfo& ssl_info,
bool fatal);
- virtual SSLCertErrorHandler* AsSSLCertErrorHandler() OVERRIDE;
+ SSLCertErrorHandler* AsSSLCertErrorHandler() override;
// These accessors are available on either thread
const net::SSLInfo& ssl_info() const { return ssl_info_; }
@@ -37,11 +36,11 @@ class SSLCertErrorHandler : public SSLErrorHandler {
protected:
// SSLErrorHandler methods
- virtual void OnDispatchFailed() OVERRIDE;
- virtual void OnDispatched() OVERRIDE;
+ void OnDispatchFailed() override;
+ void OnDispatched() override;
private:
- virtual ~SSLCertErrorHandler();
+ ~SSLCertErrorHandler() override;
// These read-only members may be accessed on any thread.
const net::SSLInfo ssl_info_;
diff --git a/chromium/content/browser/ssl/ssl_client_auth_handler.cc b/chromium/content/browser/ssl/ssl_client_auth_handler.cc
index b7fe9f0a7fa..8cab2c75229 100644
--- a/chromium/content/browser/ssl/ssl_client_auth_handler.cc
+++ b/chromium/content/browser/ssl/ssl_client_auth_handler.cc
@@ -5,77 +5,84 @@
#include "content/browser/ssl/ssl_client_auth_handler.h"
#include "base/bind.h"
-#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "base/logging.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "net/cert/x509_certificate.h"
-#include "net/http/http_transaction_factory.h"
#include "net/ssl/client_cert_store.h"
#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
namespace content {
+namespace {
+
+typedef base::Callback<void(net::X509Certificate*)> CertificateCallback;
+
+void CertificateSelectedOnUIThread(
+ const CertificateCallback& io_thread_callback,
+ net::X509Certificate* cert) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(io_thread_callback, make_scoped_refptr(cert)));
+}
+
+void SelectCertificateOnUIThread(
+ int render_process_host_id,
+ int render_frame_host_id,
+ net::SSLCertRequestInfo* cert_request_info,
+ const CertificateCallback& io_thread_callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ GetContentClient()->browser()->SelectClientCertificate(
+ render_process_host_id, render_frame_host_id, cert_request_info,
+ base::Bind(&CertificateSelectedOnUIThread, io_thread_callback));
+}
+
+} // namespace
+
SSLClientAuthHandler::SSLClientAuthHandler(
scoped_ptr<net::ClientCertStore> client_cert_store,
net::URLRequest* request,
- net::SSLCertRequestInfo* cert_request_info)
+ net::SSLCertRequestInfo* cert_request_info,
+ const SSLClientAuthHandler::CertificateCallback& callback)
: request_(request),
- http_network_session_(
- request_->context()->http_transaction_factory()->GetSession()),
cert_request_info_(cert_request_info),
- client_cert_store_(client_cert_store.Pass()) {
+ client_cert_store_(client_cert_store.Pass()),
+ callback_(callback),
+ weak_factory_(this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}
SSLClientAuthHandler::~SSLClientAuthHandler() {
- // If we were simply dropped, then act as if we selected no certificate.
- DoCertificateSelected(NULL);
-}
-
-void SSLClientAuthHandler::OnRequestCancelled() {
- request_ = NULL;
}
void SSLClientAuthHandler::SelectCertificate() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(request_);
if (client_cert_store_) {
client_cert_store_->GetClientCerts(
*cert_request_info_,
&cert_request_info_->client_certs,
- base::Bind(&SSLClientAuthHandler::DidGetClientCerts, this));
+ base::Bind(&SSLClientAuthHandler::DidGetClientCerts,
+ weak_factory_.GetWeakPtr()));
} else {
DidGetClientCerts();
}
}
-void SSLClientAuthHandler::CertificateSelected(net::X509Certificate* cert) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- VLOG(1) << this << " CertificateSelected " << cert;
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(
- &SSLClientAuthHandler::DoCertificateSelected, this,
- make_scoped_refptr(cert)));
-}
-
void SSLClientAuthHandler::DidGetClientCerts() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // Request may have cancelled while we were getting client certs.
- if (!request_)
- return;
// Note that if |client_cert_store_| is NULL, we intentionally fall through to
// DoCertificateSelected. This is for platforms where the client cert matching
- // is not performed by Chrome, the platform can handle the cert matching
- // before showing the dialog.
+ // is not performed by Chrome. Those platforms handle the cert matching before
+ // showing the dialog.
if (client_cert_store_ && cert_request_info_->client_certs.empty()) {
// No need to query the user if there are no certs to choose from.
- DoCertificateSelected(NULL);
+ CertificateSelected(NULL);
return;
}
@@ -83,43 +90,27 @@ void SSLClientAuthHandler::DidGetClientCerts() {
int render_frame_host_id;
if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame(
&render_process_host_id,
- &render_frame_host_id))
+ &render_frame_host_id)) {
NOTREACHED();
+ CertificateSelected(NULL);
+ return;
+ }
- // If the RVH does not exist by the time this task gets run, then the task
- // will be dropped and the scoped_refptr to SSLClientAuthHandler will go
- // away, so we do not leak anything. The destructor takes care of ensuring
- // the net::URLRequest always gets a response.
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(
- &SSLClientAuthHandler::DoSelectCertificate, this,
- render_process_host_id, render_frame_host_id));
+ base::Bind(&SelectCertificateOnUIThread,
+ render_process_host_id, render_frame_host_id,
+ cert_request_info_,
+ base::Bind(&SSLClientAuthHandler::CertificateSelected,
+ weak_factory_.GetWeakPtr())));
}
-void SSLClientAuthHandler::DoCertificateSelected(net::X509Certificate* cert) {
+void SSLClientAuthHandler::CertificateSelected(net::X509Certificate* cert) {
VLOG(1) << this << " DoCertificateSelected " << cert;
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // request_ could have been NULLed if the request was cancelled while the
- // user was choosing a cert, or because we have already responded to the
- // certificate.
- if (request_) {
- request_->ContinueWithCertificate(cert);
-
- ResourceDispatcherHostImpl::Get()->
- ClearSSLClientAuthHandlerForRequest(request_);
- request_ = NULL;
- }
-}
-void SSLClientAuthHandler::DoSelectCertificate(
- int render_process_host_id, int render_frame_host_id) {
- GetContentClient()->browser()->SelectClientCertificate(
- render_process_host_id,
- render_frame_host_id,
- http_network_session_,
- cert_request_info_.get(),
- base::Bind(&SSLClientAuthHandler::CertificateSelected, this));
+ callback_.Run(cert);
+ // |this| may be deleted at this point.
}
} // namespace content
diff --git a/chromium/content/browser/ssl/ssl_client_auth_handler.h b/chromium/content/browser/ssl/ssl_client_auth_handler.h
index b848d54d7ff..f95e65d71bb 100644
--- a/chromium/content/browser/ssl/ssl_client_auth_handler.h
+++ b/chromium/content/browser/ssl/ssl_client_auth_handler.h
@@ -6,79 +6,57 @@
#define CONTENT_BROWSER_SSL_SSL_CLIENT_AUTH_HANDLER_H_
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner_helpers.h"
-#include "content/common/content_export.h"
+#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h"
#include "net/ssl/ssl_cert_request_info.h"
namespace net {
class ClientCertStore;
-class HttpNetworkSession;
class URLRequest;
class X509Certificate;
} // namespace net
namespace content {
-class ResourceContext;
-
// This class handles the approval and selection of a certificate for SSL client
-// authentication by the user.
-// It is self-owned and deletes itself when the UI reports the user selection or
-// when the net::URLRequest is cancelled.
-class CONTENT_EXPORT SSLClientAuthHandler
- : public base::RefCountedThreadSafe<
- SSLClientAuthHandler, BrowserThread::DeleteOnIOThread> {
+// authentication by the user. Should only be used on the IO thread. If the
+// SSLClientAuthHandler is destroyed before the certificate is selected, the
+// selection is canceled and the callback never called.
+class SSLClientAuthHandler {
public:
+ typedef base::Callback<void(net::X509Certificate*)> CertificateCallback;
+
SSLClientAuthHandler(scoped_ptr<net::ClientCertStore> client_cert_store,
net::URLRequest* request,
- net::SSLCertRequestInfo* cert_request_info);
+ net::SSLCertRequestInfo* cert_request_info,
+ const CertificateCallback& callback);
+ ~SSLClientAuthHandler();
// Selects a certificate and resumes the URL request with that certificate.
- // Should only be called on the IO thread.
void SelectCertificate();
- // Invoked when the request associated with this handler is cancelled.
- // Should only be called on the IO thread.
- void OnRequestCancelled();
-
- // Calls DoCertificateSelected on the I/O thread.
- // Called on the UI thread after the user has made a selection (which may
- // be long after DoSelectCertificate returns, if the UI is modeless/async.)
- void CertificateSelected(net::X509Certificate* cert);
-
- protected:
- virtual ~SSLClientAuthHandler();
-
private:
- friend class base::RefCountedThreadSafe<
- SSLClientAuthHandler, BrowserThread::DeleteOnIOThread>;
- friend class BrowserThread;
- friend class base::DeleteHelper<SSLClientAuthHandler>;
-
// Called when ClientCertStore is done retrieving the cert list.
void DidGetClientCerts();
- // Notifies that the user has selected a cert.
- // Called on the IO thread.
- void DoCertificateSelected(net::X509Certificate* cert);
-
- // Selects a client certificate on the UI thread.
- void DoSelectCertificate(int render_process_host_id,
- int render_frame_host_id);
+ // Called when the user has selected a cert.
+ void CertificateSelected(net::X509Certificate* cert);
// The net::URLRequest that triggered this client auth.
net::URLRequest* request_;
- // The HttpNetworkSession |request_| is associated with.
- const net::HttpNetworkSession* http_network_session_;
-
// The certs to choose from.
scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
scoped_ptr<net::ClientCertStore> client_cert_store_;
+ // The callback to call when the certificate is selected.
+ CertificateCallback callback_;
+
+ base::WeakPtrFactory<SSLClientAuthHandler> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(SSLClientAuthHandler);
};
diff --git a/chromium/content/browser/ssl/ssl_error_handler.cc b/chromium/content/browser/ssl/ssl_error_handler.cc
index 6d120a9e2fb..f8deb75e534 100644
--- a/chromium/content/browser/ssl/ssl_error_handler.cc
+++ b/chromium/content/browser/ssl/ssl_error_handler.cc
@@ -19,13 +19,11 @@ using net::SSLInfo;
namespace content {
SSLErrorHandler::SSLErrorHandler(const base::WeakPtr<Delegate>& delegate,
- const GlobalRequestID& id,
- ResourceType::Type resource_type,
+ ResourceType resource_type,
const GURL& url,
int render_process_id,
int render_frame_id)
: manager_(NULL),
- request_id_(id),
delegate_(delegate),
render_process_id_(render_process_id),
render_frame_id_(render_frame_id),
@@ -133,7 +131,7 @@ void SSLErrorHandler::CompleteCancelRequest(int error) {
if (cert_error)
ssl_info = &cert_error->ssl_info();
if (delegate_.get())
- delegate_->CancelSSLRequest(request_id_, error, ssl_info);
+ delegate_->CancelSSLRequest(error, ssl_info);
request_has_been_notified_ = true;
// We're done with this object on the IO thread.
@@ -151,7 +149,7 @@ void SSLErrorHandler::CompleteContinueRequest() {
return;
if (delegate_.get())
- delegate_->ContinueSSLRequest(request_id_);
+ delegate_->ContinueSSLRequest();
request_has_been_notified_ = true;
// We're done with this object on the IO thread.
diff --git a/chromium/content/browser/ssl/ssl_error_handler.h b/chromium/content/browser/ssl/ssl_error_handler.h
index 87bc1da445e..26fc147c3f4 100644
--- a/chromium/content/browser/ssl/ssl_error_handler.h
+++ b/chromium/content/browser/ssl/ssl_error_handler.h
@@ -12,8 +12,8 @@
#include "base/memory/weak_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_request_id.h"
+#include "content/public/common/resource_type.h"
#include "url/gurl.h"
-#include "webkit/common/resource_type.h"
namespace net {
class SSLInfo;
@@ -42,22 +42,18 @@ class SSLManager;
//
class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
public:
- // Delegate functions must be called from IO thread. All functions accept
- // |id| as the first argument. |id| is a copy of the second argument of
- // SSLManager::OnSSLCertificateError() and represents the request.
- // Finally, CancelSSLRequest() or ContinueSSLRequest() will be called after
+ // Delegate functions must be called from IO thread. Finally,
+ // CancelSSLRequest() or ContinueSSLRequest() will be called after
// SSLErrorHandler makes a decision on the SSL error.
class CONTENT_EXPORT Delegate {
public:
// Called when SSLErrorHandler decides to cancel the request because of
// the SSL error.
- virtual void CancelSSLRequest(const GlobalRequestID& id,
- int error,
- const net::SSLInfo* ssl_info) = 0;
+ virtual void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) = 0;
// Called when SSLErrorHandler decides to continue the request despite the
// SSL error.
- virtual void ContinueSSLRequest(const GlobalRequestID& id) = 0;
+ virtual void ContinueSSLRequest() = 0;
protected:
virtual ~Delegate() {}
@@ -75,7 +71,7 @@ class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
const GURL& request_url() const { return request_url_; }
// Available on either thread.
- ResourceType::Type resource_type() const { return resource_type_; }
+ ResourceType resource_type() const { return resource_type_; }
// Cancels the associated net::URLRequest.
// This method can be called from OnDispatchFailed and OnDispatched.
@@ -108,8 +104,7 @@ class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
// Construct on the IO thread.
SSLErrorHandler(const base::WeakPtr<Delegate>& delegate,
- const GlobalRequestID& id,
- ResourceType::Type resource_type,
+ ResourceType resource_type,
const GURL& url,
int render_process_id,
int render_frame_id);
@@ -125,10 +120,6 @@ class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
// Should only be accessed on the UI thread.
SSLManager* manager_; // Our manager.
- // The id of the request associated with this object.
- // Should only be accessed from the IO thread.
- GlobalRequestID request_id_;
-
// The delegate we are associated with.
base::WeakPtr<Delegate> delegate_;
@@ -158,7 +149,7 @@ class SSLErrorHandler : public base::RefCountedThreadSafe<SSLErrorHandler> {
// What kind of resource is associated with the requested that generated
// that error.
// This read-only member can be accessed on any thread.
- const ResourceType::Type resource_type_;
+ const ResourceType resource_type_;
// A flag to make sure we notify the net::URLRequest exactly once.
// Should only be accessed on the IO thread
diff --git a/chromium/content/browser/ssl/ssl_host_state.cc b/chromium/content/browser/ssl/ssl_host_state.cc
deleted file mode 100644
index 06c600205fa..00000000000
--- a/chromium/content/browser/ssl/ssl_host_state.cc
+++ /dev/null
@@ -1,71 +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/ssl/ssl_host_state.h"
-
-#include "base/logging.h"
-#include "base/lazy_instance.h"
-#include "content/public/browser/browser_context.h"
-
-const char kKeyName[] = "content_ssl_host_state";
-
-namespace content {
-
-SSLHostState* SSLHostState::GetFor(BrowserContext* context) {
- SSLHostState* rv = static_cast<SSLHostState*>(context->GetUserData(kKeyName));
- if (!rv) {
- rv = new SSLHostState();
- context->SetUserData(kKeyName, rv);
- }
- return rv;
-}
-
-SSLHostState::SSLHostState() {
-}
-
-SSLHostState::~SSLHostState() {
-}
-
-void SSLHostState::HostRanInsecureContent(const std::string& host, int pid) {
- DCHECK(CalledOnValidThread());
- ran_insecure_content_hosts_.insert(BrokenHostEntry(host, pid));
-}
-
-bool SSLHostState::DidHostRunInsecureContent(const std::string& host,
- int pid) const {
- DCHECK(CalledOnValidThread());
- return !!ran_insecure_content_hosts_.count(BrokenHostEntry(host, pid));
-}
-
-void SSLHostState::DenyCertForHost(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error) {
- DCHECK(CalledOnValidThread());
-
- cert_policy_for_host_[host].Deny(cert, error);
-}
-
-void SSLHostState::AllowCertForHost(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error) {
- DCHECK(CalledOnValidThread());
-
- cert_policy_for_host_[host].Allow(cert, error);
-}
-
-void SSLHostState::Clear() {
- DCHECK(CalledOnValidThread());
-
- cert_policy_for_host_.clear();
-}
-
-net::CertPolicy::Judgment SSLHostState::QueryPolicy(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error) {
- DCHECK(CalledOnValidThread());
-
- return cert_policy_for_host_[host].Check(cert, error);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/ssl/ssl_host_state.h b/chromium/content/browser/ssl/ssl_host_state.h
deleted file mode 100644
index 820821786d3..00000000000
--- a/chromium/content/browser/ssl/ssl_host_state.h
+++ /dev/null
@@ -1,84 +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_SSL_SSL_HOST_STATE_H_
-#define CONTENT_BROWSER_SSL_SSL_HOST_STATE_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/supports_user_data.h"
-#include "base/threading/non_thread_safe.h"
-#include "content/common/content_export.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cert/x509_certificate.h"
-
-namespace content {
-class BrowserContext;
-
-// SSLHostState
-//
-// The SSLHostState encapulates the host-specific state for SSL errors. For
-// example, SSLHostState remembers whether the user has whitelisted a
-// particular broken cert for use with particular host. We separate this state
-// from the SSLManager because this state is shared across many navigation
-// controllers.
-
-class CONTENT_EXPORT SSLHostState
- : NON_EXPORTED_BASE(base::SupportsUserData::Data),
- NON_EXPORTED_BASE(public base::NonThreadSafe) {
- public:
- static SSLHostState* GetFor(BrowserContext* browser_context);
-
- SSLHostState();
- virtual ~SSLHostState();
-
- // Records that a host has run insecure content.
- void HostRanInsecureContent(const std::string& host, int pid);
-
- // Returns whether the specified host ran insecure content.
- bool DidHostRunInsecureContent(const std::string& host, int pid) const;
-
- // Records that |cert| is not permitted to be used for |host| in the future,
- // for a specified |error| type..
- void DenyCertForHost(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error);
-
- // Records that |cert| is permitted to be used for |host| in the future, for
- // a specified |error| type.
- void AllowCertForHost(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error);
-
- // Clear all allow/deny preferences.
- void Clear();
-
- // Queries whether |cert| is allowed or denied for |host| and |error|.
- net::CertPolicy::Judgment QueryPolicy(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error);
-
- private:
- // A BrokenHostEntry is a pair of (host, process_id) that indicates the host
- // contains insecure content in that renderer process.
- typedef std::pair<std::string, int> BrokenHostEntry;
-
- // Hosts which have been contaminated with insecure content in the
- // specified process. Note that insecure content can travel between
- // same-origin frames in one processs but cannot jump between processes.
- std::set<BrokenHostEntry> ran_insecure_content_hosts_;
-
- // Certificate policies for each host.
- std::map<std::string, net::CertPolicy> cert_policy_for_host_;
-
- DISALLOW_COPY_AND_ASSIGN(SSLHostState);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_SSL_SSL_HOST_STATE_H_
diff --git a/chromium/content/browser/ssl/ssl_host_state_unittest.cc b/chromium/content/browser/ssl/ssl_host_state_unittest.cc
deleted file mode 100644
index 5e4366d375d..00000000000
--- a/chromium/content/browser/ssl/ssl_host_state_unittest.cc
+++ /dev/null
@@ -1,203 +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/ssl/ssl_host_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// Certificates for test data. They're obtained with:
-//
-// $ openssl s_client -connect [host]:443 -showcerts
-// $ openssl x509 -inform PEM -outform DER > /tmp/host.der
-// $ xxd -i /tmp/host.der
-
-// Google's cert.
-
-unsigned char google_der[] = {
- 0x30, 0x82, 0x03, 0x21, 0x30, 0x82, 0x02, 0x8a, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x10, 0x3c, 0x8d, 0x3a, 0x64, 0xee, 0x18, 0xdd, 0x1b, 0x73,
- 0x0b, 0xa1, 0x92, 0xee, 0xf8, 0x98, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4c,
- 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x5a,
- 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c,
- 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75,
- 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79, 0x29, 0x20,
- 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
- 0x03, 0x13, 0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x47,
- 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x35,
- 0x30, 0x32, 0x31, 0x37, 0x30, 0x32, 0x35, 0x35, 0x5a, 0x17, 0x0d, 0x30,
- 0x39, 0x30, 0x35, 0x30, 0x32, 0x31, 0x37, 0x30, 0x32, 0x35, 0x35, 0x5a,
- 0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
- 0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61,
- 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0d, 0x4d,
- 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77,
- 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x17, 0x30,
- 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x77, 0x77, 0x77, 0x2e,
- 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x81,
- 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
- 0x81, 0x81, 0x00, 0x9b, 0x19, 0xed, 0x5d, 0xa5, 0x56, 0xaf, 0x49, 0x66,
- 0xdb, 0x79, 0xfd, 0xc2, 0x1c, 0x78, 0x4e, 0x4f, 0x11, 0xa5, 0x8a, 0xac,
- 0xe2, 0x94, 0xee, 0xe3, 0xe2, 0x4b, 0xc0, 0x03, 0x25, 0xa7, 0x99, 0xcc,
- 0x65, 0xe1, 0xec, 0x94, 0xae, 0xae, 0xf0, 0xa7, 0x99, 0xbc, 0x10, 0xd7,
- 0xed, 0x87, 0x30, 0x47, 0xcd, 0x50, 0xf9, 0xaf, 0xd3, 0xd3, 0xf4, 0x0b,
- 0x8d, 0x47, 0x8a, 0x2e, 0xe2, 0xce, 0x53, 0x9b, 0x91, 0x99, 0x7f, 0x1e,
- 0x5c, 0xf9, 0x1b, 0xd6, 0xe9, 0x93, 0x67, 0xe3, 0x4a, 0xf8, 0xcf, 0xc4,
- 0x8c, 0x0c, 0x68, 0xd1, 0x97, 0x54, 0x47, 0x0e, 0x0a, 0x24, 0x30, 0xa7,
- 0x82, 0x94, 0xae, 0xde, 0xae, 0x3f, 0xbf, 0xba, 0x14, 0xc6, 0xf8, 0xb2,
- 0x90, 0x8e, 0x36, 0xad, 0xe1, 0xd0, 0xbe, 0x16, 0x9a, 0xb3, 0x5e, 0x72,
- 0x38, 0x49, 0xda, 0x74, 0xa1, 0x3f, 0xff, 0xd2, 0x87, 0x81, 0xed, 0x02,
- 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xe7, 0x30, 0x81, 0xe4, 0x30, 0x28,
- 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b,
- 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01,
- 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86,
- 0xf8, 0x42, 0x04, 0x01, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04,
- 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0, 0x27, 0x86, 0x25, 0x68,
- 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x74, 0x68,
- 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61,
- 0x77, 0x74, 0x65, 0x53, 0x47, 0x43, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c,
- 0x30, 0x72, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01,
- 0x04, 0x66, 0x30, 0x64, 0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
- 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65,
- 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
- 0x05, 0x07, 0x30, 0x02, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
- 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65, 0x2e,
- 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f,
- 0x72, 0x79, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x5f, 0x53, 0x47,
- 0x43, 0x5f, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0c, 0x06, 0x03,
- 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
- 0x00, 0x03, 0x81, 0x81, 0x00, 0x31, 0x0a, 0x6c, 0xa2, 0x9e, 0xe9, 0x54,
- 0x19, 0x16, 0x68, 0x99, 0x91, 0xd6, 0x43, 0xcb, 0x6b, 0xb4, 0xcc, 0x6c,
- 0xcc, 0xb0, 0xfb, 0xf1, 0xee, 0x81, 0xbf, 0x00, 0x2b, 0x6f, 0x50, 0x12,
- 0xc6, 0xaf, 0x02, 0x2a, 0x36, 0xc1, 0x28, 0xde, 0xc5, 0x4c, 0x56, 0x20,
- 0x6d, 0xf5, 0x3d, 0x42, 0xb9, 0x18, 0x81, 0x20, 0xb2, 0xdd, 0x57, 0x5d,
- 0xeb, 0xbe, 0x32, 0x84, 0x50, 0x45, 0x51, 0x6e, 0xcd, 0xe4, 0x2e, 0x2a,
- 0x38, 0x88, 0x9f, 0x52, 0xed, 0x28, 0xff, 0xfc, 0x8d, 0x57, 0xb5, 0xad,
- 0x64, 0xae, 0x4d, 0x0e, 0x0e, 0xd9, 0x3d, 0xac, 0xb8, 0xfe, 0x66, 0x4c,
- 0x15, 0x8f, 0x44, 0x52, 0xfa, 0x7c, 0x3c, 0x04, 0xed, 0x7f, 0x37, 0x61,
- 0x04, 0xfe, 0xd5, 0xe9, 0xb9, 0xb0, 0x9e, 0xfe, 0xa5, 0x11, 0x69, 0xc9,
- 0x63, 0xd6, 0x46, 0x81, 0x6f, 0x00, 0xd8, 0x72, 0x2f, 0x82, 0x37, 0x44,
- 0xc1
-};
-
-} // namespace
-
-namespace content {
-
-class SSLHostStateTest : public testing::Test {
-};
-
-TEST_F(SSLHostStateTest, DidHostRunInsecureContent) {
- SSLHostState state;
-
- EXPECT_FALSE(state.DidHostRunInsecureContent("www.google.com", 42));
- EXPECT_FALSE(state.DidHostRunInsecureContent("www.google.com", 191));
- EXPECT_FALSE(state.DidHostRunInsecureContent("example.com", 42));
-
- state.HostRanInsecureContent("www.google.com", 42);
-
- EXPECT_TRUE(state.DidHostRunInsecureContent("www.google.com", 42));
- EXPECT_FALSE(state.DidHostRunInsecureContent("www.google.com", 191));
- EXPECT_FALSE(state.DidHostRunInsecureContent("example.com", 42));
-
- state.HostRanInsecureContent("example.com", 42);
-
- EXPECT_TRUE(state.DidHostRunInsecureContent("www.google.com", 42));
- EXPECT_FALSE(state.DidHostRunInsecureContent("www.google.com", 191));
- EXPECT_TRUE(state.DidHostRunInsecureContent("example.com", 42));
-}
-
-TEST_F(SSLHostStateTest, QueryPolicy) {
- scoped_refptr<net::X509Certificate> google_cert(
- net::X509Certificate::CreateFromBytes(
- reinterpret_cast<const char*>(google_der), sizeof(google_der)));
-
- SSLHostState state;
-
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "www.google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "example.com",
- net::CERT_STATUS_DATE_INVALID));
-
- state.AllowCertForHost(google_cert.get(),
- "www.google.com",
- net::CERT_STATUS_DATE_INVALID);
-
- EXPECT_EQ(net::CertPolicy::ALLOWED,
- state.QueryPolicy(google_cert.get(),
- "www.google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "example.com",
- net::CERT_STATUS_DATE_INVALID));
-
- state.AllowCertForHost(google_cert.get(),
- "example.com",
- net::CERT_STATUS_DATE_INVALID);
-
- EXPECT_EQ(net::CertPolicy::ALLOWED,
- state.QueryPolicy(google_cert.get(),
- "www.google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::ALLOWED,
- state.QueryPolicy(google_cert.get(),
- "example.com",
- net::CERT_STATUS_DATE_INVALID));
-
- state.DenyCertForHost(google_cert.get(),
- "example.com",
- net::CERT_STATUS_DATE_INVALID);
-
- EXPECT_EQ(net::CertPolicy::ALLOWED,
- state.QueryPolicy(google_cert.get(),
- "www.google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::DENIED,
- state.QueryPolicy(google_cert.get(),
- "example.com",
- net::CERT_STATUS_DATE_INVALID));
-
- state.Clear();
-
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "www.google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "google.com",
- net::CERT_STATUS_DATE_INVALID));
- EXPECT_EQ(net::CertPolicy::UNKNOWN,
- state.QueryPolicy(google_cert.get(),
- "example.com",
- net::CERT_STATUS_DATE_INVALID));
-}
-
-} // namespace content
diff --git a/chromium/content/browser/ssl/ssl_manager.cc b/chromium/content/browser/ssl/ssl_manager.cc
index 68906ced1ec..ccaf9cf2062 100644
--- a/chromium/content/browser/ssl/ssl_manager.cc
+++ b/chromium/content/browser/ssl/ssl_manager.cc
@@ -49,8 +49,7 @@ class SSLManagerSet : public base::SupportsUserData::Data {
// static
void SSLManager::OnSSLCertificateError(
const base::WeakPtr<SSLErrorHandler::Delegate>& delegate,
- const GlobalRequestID& id,
- const ResourceType::Type resource_type,
+ const ResourceType resource_type,
const GURL& url,
int render_process_id,
int render_frame_id,
@@ -58,10 +57,11 @@ void SSLManager::OnSSLCertificateError(
bool fatal) {
DCHECK(delegate.get());
DVLOG(1) << "OnSSLCertificateError() cert_error: "
- << net::MapCertStatusToNetError(ssl_info.cert_status) << " id: "
- << id.child_id << "," << id.request_id << " resource_type: "
- << resource_type << " url: " << url.spec() << " render_process_id: "
- << render_process_id << " render_frame_id: " << render_frame_id
+ << net::MapCertStatusToNetError(ssl_info.cert_status)
+ << " resource_type: " << resource_type
+ << " url: " << url.spec()
+ << " render_process_id: " << render_process_id
+ << " render_frame_id: " << render_frame_id
<< " cert_status: " << std::hex << ssl_info.cert_status;
// A certificate error occurred. Construct a SSLCertErrorHandler object and
@@ -70,7 +70,6 @@ void SSLManager::OnSSLCertificateError(
BrowserThread::UI, FROM_HERE,
base::Bind(&SSLCertErrorHandler::Dispatch,
new SSLCertErrorHandler(delegate,
- id,
resource_type,
url,
render_process_id,
@@ -171,7 +170,7 @@ void SSLManager::DidLoadFromMemoryCache(
// resouces aren't cachable.
scoped_refptr<SSLRequestInfo> info(new SSLRequestInfo(
details.url,
- ResourceType::SUB_RESOURCE,
+ RESOURCE_TYPE_SUB_RESOURCE,
details.pid,
details.cert_id,
details.cert_status));
diff --git a/chromium/content/browser/ssl/ssl_manager.h b/chromium/content/browser/ssl/ssl_manager.h
index c195e981bcb..d4fca43e6b9 100644
--- a/chromium/content/browser/ssl/ssl_manager.h
+++ b/chromium/content/browser/ssl/ssl_manager.h
@@ -45,13 +45,12 @@ class SSLManager {
// Entry point for SSLCertificateErrors. This function begins the process
// of resolving a certificate error during an SSL connection. SSLManager
// will adjust the security UI and either call |CancelSSLRequest| or
- // |ContinueSSLRequest| of |delegate| with |id| as the first argument.
+ // |ContinueSSLRequest| of |delegate|.
//
// Called on the IO thread.
static void OnSSLCertificateError(
const base::WeakPtr<SSLErrorHandler::Delegate>& delegate,
- const GlobalRequestID& id,
- ResourceType::Type resource_type,
+ ResourceType resource_type,
const GURL& url,
int render_process_id,
int render_frame_id,
diff --git a/chromium/content/browser/ssl/ssl_policy.cc b/chromium/content/browser/ssl/ssl_policy.cc
index 731645505b4..51ae7b2a1c8 100644
--- a/chromium/content/browser/ssl/ssl_policy.cc
+++ b/chromium/content/browser/ssl/ssl_policy.cc
@@ -18,10 +18,10 @@
#include "content/browser/ssl/ssl_request_info.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/common/resource_type.h"
#include "content/public/common/ssl_status.h"
#include "content/public/common/url_constants.h"
#include "net/ssl/ssl_info.h"
-#include "webkit/common/resource_type.h"
namespace content {
@@ -32,21 +32,23 @@ SSLPolicy::SSLPolicy(SSLPolicyBackend* backend)
}
void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) {
+ bool expired_previous_decision;
// First we check if we know the policy for this error.
- net::CertPolicy::Judgment judgment = backend_->QueryPolicy(
- handler->ssl_info().cert.get(),
- handler->request_url().host(),
- handler->cert_error());
-
- if (judgment == net::CertPolicy::ALLOWED) {
+ DCHECK(handler->ssl_info().is_valid());
+ SSLHostStateDelegate::CertJudgment judgment =
+ backend_->QueryPolicy(*handler->ssl_info().cert.get(),
+ handler->request_url().host(),
+ handler->cert_error(),
+ &expired_previous_decision);
+
+ if (judgment == SSLHostStateDelegate::ALLOWED) {
handler->ContinueRequest();
return;
}
- // The judgment is either DENIED or UNKNOWN.
- // For now we handle the DENIED as the UNKNOWN, which means a blocking
- // page is shown to the user every time he comes back to the page.
-
+ // For all other hosts, which must be DENIED, a blocking page is shown to the
+ // user every time they come back to the page.
+ int options_mask = 0;
switch (handler->cert_error()) {
case net::ERR_CERT_COMMON_NAME_INVALID:
case net::ERR_CERT_DATE_INVALID:
@@ -54,7 +56,13 @@ void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) {
case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
case net::ERR_CERT_WEAK_KEY:
case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
- OnCertErrorInternal(handler, !handler->fatal(), handler->fatal());
+ if (!handler->fatal())
+ options_mask |= OVERRIDABLE;
+ else
+ options_mask |= STRICT_ENFORCEMENT;
+ if (expired_previous_decision)
+ options_mask |= EXPIRED_PREVIOUS_DECISION;
+ OnCertErrorInternal(handler, options_mask);
break;
case net::ERR_CERT_NO_REVOCATION_MECHANISM:
// Ignore this error.
@@ -70,7 +78,11 @@ void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) {
case net::ERR_CERT_INVALID:
case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
- OnCertErrorInternal(handler, false, handler->fatal());
+ if (handler->fatal())
+ options_mask |= STRICT_ENFORCEMENT;
+ if (expired_previous_decision)
+ options_mask |= EXPIRED_PREVIOUS_DECISION;
+ OnCertErrorInternal(handler, options_mask);
break;
default:
NOTREACHED();
@@ -150,6 +162,7 @@ void SSLPolicy::UpdateEntry(NavigationEntryImpl* entry,
void SSLPolicy::OnAllowCertificate(scoped_refptr<SSLCertErrorHandler> handler,
bool allow) {
+ DCHECK(handler->ssl_info().is_valid());
if (allow) {
// Default behavior for accepting a certificate.
// Note that we should not call SetMaxSecurityStyle here, because the active
@@ -161,19 +174,12 @@ void SSLPolicy::OnAllowCertificate(scoped_refptr<SSLCertErrorHandler> handler,
// While AllowCertForHost() executes synchronously on this thread,
// ContinueRequest() gets posted to a different thread. Calling
// AllowCertForHost() first ensures deterministic ordering.
- backend_->AllowCertForHost(handler->ssl_info().cert.get(),
+ backend_->AllowCertForHost(*handler->ssl_info().cert.get(),
handler->request_url().host(),
handler->cert_error());
handler->ContinueRequest();
} else {
// Default behavior for rejecting a certificate.
- //
- // While DenyCertForHost() executes synchronously on this thread,
- // CancelRequest() gets posted to a different thread. Calling
- // DenyCertForHost() first ensures deterministic ordering.
- backend_->DenyCertForHost(handler->ssl_info().cert.get(),
- handler->request_url().host(),
- handler->cert_error());
handler->CancelRequest();
}
}
@@ -182,8 +188,11 @@ void SSLPolicy::OnAllowCertificate(scoped_refptr<SSLCertErrorHandler> handler,
// Certificate Error Routines
void SSLPolicy::OnCertErrorInternal(SSLCertErrorHandler* handler,
- bool overridable,
- bool strict_enforcement) {
+ int options_mask) {
+ bool overridable = (options_mask & OVERRIDABLE) != 0;
+ bool strict_enforcement = (options_mask & STRICT_ENFORCEMENT) != 0;
+ bool expired_previous_decision =
+ (options_mask & EXPIRED_PREVIOUS_DECISION) != 0;
CertificateRequestResultType result =
CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE;
GetContentClient()->browser()->AllowCertificateError(
@@ -195,7 +204,9 @@ void SSLPolicy::OnCertErrorInternal(SSLCertErrorHandler* handler,
handler->resource_type(),
overridable,
strict_enforcement,
- base::Bind(&SSLPolicy::OnAllowCertificate, base::Unretained(this),
+ expired_previous_decision,
+ base::Bind(&SSLPolicy::OnAllowCertificate,
+ base::Unretained(this),
make_scoped_refptr(handler)),
&result);
switch (result) {
diff --git a/chromium/content/browser/ssl/ssl_policy.h b/chromium/content/browser/ssl/ssl_policy.h
index c88e10c8440..78dbb6d8960 100644
--- a/chromium/content/browser/ssl/ssl_policy.h
+++ b/chromium/content/browser/ssl/ssl_policy.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/memory/ref_counted.h"
-#include "webkit/common/resource_type.h"
+#include "content/public/common/resource_type.h"
namespace content {
class NavigationEntryImpl;
@@ -44,20 +44,27 @@ class SSLPolicy {
SSLPolicyBackend* backend() const { return backend_; }
private:
+ enum OnCertErrorInternalOptionsMask {
+ OVERRIDABLE = 1 << 0,
+ STRICT_ENFORCEMENT = 1 << 1,
+ EXPIRED_PREVIOUS_DECISION = 1 << 2
+ };
+
// Callback that the user chose to accept or deny the certificate.
void OnAllowCertificate(scoped_refptr<SSLCertErrorHandler> handler,
bool allow);
// Helper method for derived classes handling certificate errors.
//
- // |overridable| indicates whether or not the user could (assuming perfect
+ // Options should be a bitmask combination of OnCertErrorInternalOptionsMask.
+ // OVERRIDABLE indicates whether or not the user could (assuming perfect
// knowledge) successfully override the error and still get the security
- // guarantees of TLS. |strict_enforcement| indicates whether or not the
- // site the user is trying to connect to has requested strict enforcement
- // of certificate validation (e.g. with HTTP Strict-Transport-Security).
- void OnCertErrorInternal(SSLCertErrorHandler* handler,
- bool overridable,
- bool strict_enforcement);
+ // guarantees of TLS. STRICT_ENFORCEMENT indicates whether or not the site the
+ // user is trying to connect to has requested strict enforcement of
+ // certificate validation (e.g. with HTTP Strict-Transport-Security).
+ // EXPIRED_PREVIOUS_DECISION indicates whether a user decision had been
+ // previously made but the decision has expired.
+ void OnCertErrorInternal(SSLCertErrorHandler* handler, int options_mask);
// If the security style of |entry| has not been initialized, then initialize
// it with the default style for its URL.
diff --git a/chromium/content/browser/ssl/ssl_policy_backend.cc b/chromium/content/browser/ssl/ssl_policy_backend.cc
index 3eb4f467e70..5c658748219 100644
--- a/chromium/content/browser/ssl/ssl_policy_backend.cc
+++ b/chromium/content/browser/ssl/ssl_policy_backend.cc
@@ -5,44 +5,48 @@
#include "content/browser/ssl/ssl_policy_backend.h"
#include "content/browser/frame_host/navigation_controller_impl.h"
-#include "content/browser/ssl/ssl_host_state.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/ssl_host_state_delegate.h"
namespace content {
SSLPolicyBackend::SSLPolicyBackend(NavigationControllerImpl* controller)
- : ssl_host_state_(SSLHostState::GetFor(controller->GetBrowserContext())),
+ : ssl_host_state_delegate_(
+ controller->GetBrowserContext()->GetSSLHostStateDelegate()),
controller_(controller) {
DCHECK(controller_);
}
void SSLPolicyBackend::HostRanInsecureContent(const std::string& host, int id) {
- ssl_host_state_->HostRanInsecureContent(host, id);
+ if (ssl_host_state_delegate_)
+ ssl_host_state_delegate_->HostRanInsecureContent(host, id);
SSLManager::NotifySSLInternalStateChanged(controller_->GetBrowserContext());
}
bool SSLPolicyBackend::DidHostRunInsecureContent(const std::string& host,
int pid) const {
- return ssl_host_state_->DidHostRunInsecureContent(host, pid);
-}
+ if (!ssl_host_state_delegate_)
+ return false;
-void SSLPolicyBackend::DenyCertForHost(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error) {
- ssl_host_state_->DenyCertForHost(cert, host, error);
+ return ssl_host_state_delegate_->DidHostRunInsecureContent(host, pid);
}
-void SSLPolicyBackend::AllowCertForHost(net::X509Certificate* cert,
+void SSLPolicyBackend::AllowCertForHost(const net::X509Certificate& cert,
const std::string& host,
net::CertStatus error) {
- ssl_host_state_->AllowCertForHost(cert, host, error);
+ if (ssl_host_state_delegate_)
+ ssl_host_state_delegate_->AllowCert(host, cert, error);
}
-net::CertPolicy::Judgment SSLPolicyBackend::QueryPolicy(
- net::X509Certificate* cert,
+SSLHostStateDelegate::CertJudgment SSLPolicyBackend::QueryPolicy(
+ const net::X509Certificate& cert,
const std::string& host,
- net::CertStatus error) {
- return ssl_host_state_->QueryPolicy(cert, host, error);
+ net::CertStatus error,
+ bool* expired_previous_decision) {
+ return ssl_host_state_delegate_ ?
+ ssl_host_state_delegate_->QueryPolicy(
+ host, cert, error, expired_previous_decision) :
+ SSLHostStateDelegate::DENIED;
}
} // namespace content
diff --git a/chromium/content/browser/ssl/ssl_policy_backend.h b/chromium/content/browser/ssl/ssl_policy_backend.h
index 06ea23eccca..15ebe310a0e 100644
--- a/chromium/content/browser/ssl/ssl_policy_backend.h
+++ b/chromium/content/browser/ssl/ssl_policy_backend.h
@@ -10,12 +10,12 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
+#include "content/public/browser/ssl_host_state_delegate.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
namespace content {
class NavigationControllerImpl;
-class SSLHostState;
class SSLPolicyBackend {
public:
@@ -27,26 +27,24 @@ class SSLPolicyBackend {
// Returns whether the specified host ran insecure content.
bool DidHostRunInsecureContent(const std::string& host, int pid) const;
- // Records that |cert| is not permitted to be used for |host| in the future,
- // for a specific error type.
- void DenyCertForHost(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error);
-
// Records that |cert| is permitted to be used for |host| in the future, for
// a specific error type.
- void AllowCertForHost(net::X509Certificate* cert,
+ void AllowCertForHost(const net::X509Certificate& cert,
const std::string& host,
net::CertStatus error);
- // Queries whether |cert| is allowed or denied for |host|.
- net::CertPolicy::Judgment QueryPolicy(net::X509Certificate* cert,
- const std::string& host,
- net::CertStatus error);
+ // Queries whether |cert| is allowed for |host|. Returns true in
+ // |expired_previous_decision| if a user decision had been made previously but
+ // that decision has expired, otherwise false.
+ SSLHostStateDelegate::CertJudgment QueryPolicy(
+ const net::X509Certificate& cert,
+ const std::string& host,
+ net::CertStatus error,
+ bool* expired_previous_decision);
private:
- // SSL state specific for each host.
- SSLHostState* ssl_host_state_;
+ // SSL state delegate specific for each host.
+ SSLHostStateDelegate* ssl_host_state_delegate_;
NavigationControllerImpl* controller_;
diff --git a/chromium/content/browser/ssl/ssl_request_info.cc b/chromium/content/browser/ssl/ssl_request_info.cc
index 0c23f83a3ca..f22376acff2 100644
--- a/chromium/content/browser/ssl/ssl_request_info.cc
+++ b/chromium/content/browser/ssl/ssl_request_info.cc
@@ -7,7 +7,7 @@
namespace content {
SSLRequestInfo::SSLRequestInfo(const GURL& url,
- ResourceType::Type resource_type,
+ ResourceType resource_type,
int child_id,
int ssl_cert_id,
net::CertStatus ssl_cert_status)
diff --git a/chromium/content/browser/ssl/ssl_request_info.h b/chromium/content/browser/ssl/ssl_request_info.h
index cf745fe7cfe..9f50448f4ed 100644
--- a/chromium/content/browser/ssl/ssl_request_info.h
+++ b/chromium/content/browser/ssl/ssl_request_info.h
@@ -8,9 +8,9 @@
#include <string>
#include "base/memory/ref_counted.h"
+#include "content/public/common/resource_type.h"
#include "net/cert/cert_status_flags.h"
#include "url/gurl.h"
-#include "webkit/common/resource_type.h"
namespace content {
@@ -20,13 +20,13 @@ namespace content {
class SSLRequestInfo : public base::RefCounted<SSLRequestInfo> {
public:
SSLRequestInfo(const GURL& url,
- ResourceType::Type resource_type,
+ ResourceType resource_type,
int child_id,
int ssl_cert_id,
net::CertStatus ssl_cert_status);
const GURL& url() const { return url_; }
- ResourceType::Type resource_type() const { return resource_type_; }
+ ResourceType resource_type() const { return resource_type_; }
int child_id() const { return child_id_; }
int ssl_cert_id() const { return ssl_cert_id_; }
net::CertStatus ssl_cert_status() const { return ssl_cert_status_; }
@@ -37,7 +37,7 @@ class SSLRequestInfo : public base::RefCounted<SSLRequestInfo> {
virtual ~SSLRequestInfo();
GURL url_;
- ResourceType::Type resource_type_;
+ ResourceType resource_type_;
int child_id_;
int ssl_cert_id_;
net::CertStatus ssl_cert_status_;
diff --git a/chromium/content/browser/startup_task_runner.cc b/chromium/content/browser/startup_task_runner.cc
index 4746afea6b0..8e680bd6d08 100644
--- a/chromium/content/browser/startup_task_runner.cc
+++ b/chromium/content/browser/startup_task_runner.cc
@@ -22,7 +22,7 @@ void StartupTaskRunner::AddTask(StartupTask& callback) {
}
void StartupTaskRunner::StartRunningTasksAsync() {
- DCHECK(proxy_);
+ DCHECK(proxy_.get());
int result = 0;
if (task_list_.empty()) {
if (!startup_complete_callback_.is_null()) {
diff --git a/chromium/content/browser/startup_task_runner_unittest.cc b/chromium/content/browser/startup_task_runner_unittest.cc
index fcd2b3d1da6..2ecf9ca63c5 100644
--- a/chromium/content/browser/startup_task_runner_unittest.cc
+++ b/chromium/content/browser/startup_task_runner_unittest.cc
@@ -42,8 +42,7 @@ void Observer(int result) {
class StartupTaskRunnerTest : public testing::Test {
public:
-
- virtual void SetUp() {
+ void SetUp() override {
last_task_ = 0;
observer_calls = 0;
task_count = 0;
@@ -96,22 +95,21 @@ class MockTaskRunner {
class TaskRunnerProxy : public base::SingleThreadTaskRunner {
public:
TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {}
- virtual bool RunsTasksOnCurrentThread() const OVERRIDE { return true; }
- virtual bool PostDelayedTask(const tracked_objects::Location& location,
- const Closure& closure,
- base::TimeDelta delta) OVERRIDE {
+ bool RunsTasksOnCurrentThread() const override { return true; }
+ bool PostDelayedTask(const tracked_objects::Location& location,
+ const Closure& closure,
+ base::TimeDelta delta) override {
return mock_->PostDelayedTask(location, closure, delta);
}
- virtual bool PostNonNestableDelayedTask(
- const tracked_objects::Location& location,
- const Closure& closure,
- base::TimeDelta delta) OVERRIDE {
+ bool PostNonNestableDelayedTask(const tracked_objects::Location& location,
+ const Closure& closure,
+ base::TimeDelta delta) override {
return mock_->PostNonNestableDelayedTask(location, closure, delta);
}
private:
MockTaskRunner* mock_;
- virtual ~TaskRunnerProxy() {}
+ ~TaskRunnerProxy() override {}
};
TEST_F(StartupTaskRunnerTest, SynchronousExecution) {
diff --git a/chromium/content/browser/storage_partition_impl.cc b/chromium/content/browser/storage_partition_impl.cc
index 9a876b5cff8..d4e49f60f13 100644
--- a/chromium/content/browser/storage_partition_impl.cc
+++ b/chromium/content/browser/storage_partition_impl.cc
@@ -8,6 +8,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
+#include "content/browser/geofencing/geofencing_manager.h"
#include "content/browser/gpu/shader_disk_cache.h"
#include "content/common/dom_storage/dom_storage_types.h"
#include "content/public/browser/browser_context.h"
@@ -21,8 +22,8 @@
#include "net/cookies/cookie_monster.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
-#include "webkit/browser/database/database_tracker.h"
-#include "webkit/browser/quota/quota_manager.h"
+#include "storage/browser/database/database_tracker.h"
+#include "storage/browser/quota/quota_manager.h"
namespace content {
@@ -72,13 +73,13 @@ void CheckQuotaManagedDataDeletionStatus(size_t* deletion_task_count,
}
void OnQuotaManagedOriginDeleted(const GURL& origin,
- quota::StorageType type,
+ storage::StorageType type,
size_t* deletion_task_count,
const base::Closure& callback,
- quota::QuotaStatusCode status) {
+ storage::QuotaStatusCode status) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK_GT(*deletion_task_count, 0u);
- if (status != quota::kQuotaStatusOk) {
+ if (status != storage::kQuotaStatusOk) {
DLOG(ERROR) << "Couldn't remove data of type " << type << " for origin "
<< origin << ". Status: " << status;
}
@@ -108,7 +109,7 @@ void ClearShaderCacheOnIOThread(const base::FilePath& path,
void OnLocalStorageUsageInfo(
const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Time delete_begin,
const base::Time delete_end,
@@ -132,7 +133,7 @@ void OnLocalStorageUsageInfo(
void OnSessionStorageUsageInfo(
const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Closure& callback,
const std::vector<SessionStorageUsageInfo>& infos) {
@@ -151,7 +152,7 @@ void OnSessionStorageUsageInfo(
void ClearLocalStorageOnUIThread(
const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const GURL& storage_origin,
const base::Time begin,
@@ -178,7 +179,7 @@ void ClearLocalStorageOnUIThread(
void ClearSessionStorageOnUIThread(
const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Closure& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -191,18 +192,53 @@ void ClearSessionStorageOnUIThread(
} // namespace
+// static
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_APPCACHE;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_COOKIES;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_WEBSQL;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_WEBRTC_IDENTITY;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::REMOVE_DATA_MASK_ALL;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::QUOTA_MANAGED_STORAGE_MASK_SYNCABLE;
+STATIC_CONST_MEMBER_DEFINITION const uint32
+ StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
+
// Static.
int StoragePartitionImpl::GenerateQuotaClientMask(uint32 remove_mask) {
int quota_client_mask = 0;
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS)
- quota_client_mask |= quota::QuotaClient::kFileSystem;
+ quota_client_mask |= storage::QuotaClient::kFileSystem;
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_WEBSQL)
- quota_client_mask |= quota::QuotaClient::kDatabase;
+ quota_client_mask |= storage::QuotaClient::kDatabase;
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_APPCACHE)
- quota_client_mask |= quota::QuotaClient::kAppcache;
+ quota_client_mask |= storage::QuotaClient::kAppcache;
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_INDEXEDDB)
- quota_client_mask |= quota::QuotaClient::kIndexedDatabase;
+ quota_client_mask |= storage::QuotaClient::kIndexedDatabase;
+ if (remove_mask & StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS) {
+ quota_client_mask |= storage::QuotaClient::kServiceWorker;
+ quota_client_mask |= storage::QuotaClient::kServiceWorkerCache;
+ }
+
return quota_client_mask;
}
@@ -226,18 +262,20 @@ struct StoragePartitionImpl::QuotaManagedDataDeletionHelper {
void DecrementTaskCountOnIO();
void ClearDataOnIOThread(
- const scoped_refptr<quota::QuotaManager>& quota_manager,
+ const scoped_refptr<storage::QuotaManager>& quota_manager,
const base::Time begin,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ const scoped_refptr<storage::SpecialStoragePolicy>&
+ special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher);
void ClearOriginsOnIOThread(
- quota::QuotaManager* quota_manager,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ storage::QuotaManager* quota_manager,
+ const scoped_refptr<storage::SpecialStoragePolicy>&
+ special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Closure& callback,
const std::set<GURL>& origins,
- quota::StorageType quota_storage_type);
+ storage::StorageType quota_storage_type);
// All of these data are accessed on IO thread.
uint32 remove_mask;
@@ -270,22 +308,24 @@ struct StoragePartitionImpl::DataDeletionHelper {
void IncrementTaskCountOnUI();
void DecrementTaskCountOnUI();
- void ClearDataOnUIThread(const GURL& storage_origin,
- const OriginMatcherFunction& origin_matcher,
- const base::FilePath& path,
- net::URLRequestContextGetter* rq_context,
- DOMStorageContextWrapper* dom_storage_context,
- quota::QuotaManager* quota_manager,
- quota::SpecialStoragePolicy* special_storage_policy,
- WebRTCIdentityStore* webrtc_identity_store,
- const base::Time begin,
- const base::Time end);
+ void ClearDataOnUIThread(
+ const GURL& storage_origin,
+ const OriginMatcherFunction& origin_matcher,
+ const base::FilePath& path,
+ net::URLRequestContextGetter* rq_context,
+ DOMStorageContextWrapper* dom_storage_context,
+ storage::QuotaManager* quota_manager,
+ storage::SpecialStoragePolicy* special_storage_policy,
+ WebRTCIdentityStore* webrtc_identity_store,
+ const base::Time begin,
+ const base::Time end);
void ClearQuotaManagedDataOnIOThread(
- const scoped_refptr<quota::QuotaManager>& quota_manager,
+ const scoped_refptr<storage::QuotaManager>& quota_manager,
const base::Time begin,
const GURL& storage_origin,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ const scoped_refptr<storage::SpecialStoragePolicy>&
+ special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Closure& callback);
@@ -299,10 +339,10 @@ struct StoragePartitionImpl::DataDeletionHelper {
};
void StoragePartitionImpl::DataDeletionHelper::ClearQuotaManagedDataOnIOThread(
- const scoped_refptr<quota::QuotaManager>& quota_manager,
+ const scoped_refptr<storage::QuotaManager>& quota_manager,
const base::Time begin,
const GURL& storage_origin,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher,
const base::Closure& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -319,15 +359,16 @@ void StoragePartitionImpl::DataDeletionHelper::ClearQuotaManagedDataOnIOThread(
StoragePartitionImpl::StoragePartitionImpl(
const base::FilePath& partition_path,
- quota::QuotaManager* quota_manager,
+ storage::QuotaManager* quota_manager,
ChromeAppCacheService* appcache_service,
- fileapi::FileSystemContext* filesystem_context,
- webkit_database::DatabaseTracker* database_tracker,
+ storage::FileSystemContext* filesystem_context,
+ storage::DatabaseTracker* database_tracker,
DOMStorageContextWrapper* dom_storage_context,
IndexedDBContextImpl* indexed_db_context,
ServiceWorkerContextWrapper* service_worker_context,
WebRTCIdentityStore* webrtc_identity_store,
- quota::SpecialStoragePolicy* special_storage_policy)
+ storage::SpecialStoragePolicy* special_storage_policy,
+ GeofencingManager* geofencing_manager)
: partition_path_(partition_path),
quota_manager_(quota_manager),
appcache_service_(appcache_service),
@@ -337,16 +378,18 @@ StoragePartitionImpl::StoragePartitionImpl(
indexed_db_context_(indexed_db_context),
service_worker_context_(service_worker_context),
webrtc_identity_store_(webrtc_identity_store),
- special_storage_policy_(special_storage_policy) {}
+ special_storage_policy_(special_storage_policy),
+ geofencing_manager_(geofencing_manager) {
+}
StoragePartitionImpl::~StoragePartitionImpl() {
// These message loop checks are just to avoid leaks in unittests.
if (GetDatabaseTracker() &&
BrowserThread::IsMessageLoopValid(BrowserThread::FILE)) {
BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&webkit_database::DatabaseTracker::Shutdown,
- GetDatabaseTracker()));
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&storage::DatabaseTracker::Shutdown, GetDatabaseTracker()));
}
if (GetFileSystemContext())
@@ -357,6 +400,9 @@ StoragePartitionImpl::~StoragePartitionImpl() {
if (GetServiceWorkerContext())
GetServiceWorkerContext()->Shutdown();
+
+ if (GetGeofencingManager())
+ GetGeofencingManager()->Shutdown();
}
// TODO(ajwong): Break the direct dependency on |context|. We only
@@ -374,28 +420,27 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
// QuotaManager prior to the QuotaManger being used. We do them
// all together here prior to handing out a reference to anything
// that utilizes the QuotaManager.
- scoped_refptr<quota::QuotaManager> quota_manager = new quota::QuotaManager(
- in_memory,
- partition_path,
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(),
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB).get(),
- context->GetSpecialStoragePolicy());
+ scoped_refptr<storage::QuotaManager> quota_manager =
+ new storage::QuotaManager(
+ in_memory,
+ partition_path,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(),
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB).get(),
+ context->GetSpecialStoragePolicy());
// Each consumer is responsible for registering its QuotaClient during
// its construction.
- scoped_refptr<fileapi::FileSystemContext> filesystem_context =
- CreateFileSystemContext(context,
- partition_path, in_memory,
- quota_manager->proxy());
-
- scoped_refptr<webkit_database::DatabaseTracker> database_tracker =
- new webkit_database::DatabaseTracker(
- partition_path,
- in_memory,
- context->GetSpecialStoragePolicy(),
- quota_manager->proxy(),
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
- .get());
+ scoped_refptr<storage::FileSystemContext> filesystem_context =
+ CreateFileSystemContext(
+ context, partition_path, in_memory, quota_manager->proxy());
+
+ scoped_refptr<storage::DatabaseTracker> database_tracker =
+ new storage::DatabaseTracker(partition_path,
+ in_memory,
+ context->GetSpecialStoragePolicy(),
+ quota_manager->proxy(),
+ BrowserThread::GetMessageLoopProxyForThread(
+ BrowserThread::FILE).get());
base::FilePath path = in_memory ? base::FilePath() : partition_path;
scoped_refptr<DOMStorageContextWrapper> dom_storage_context =
@@ -417,7 +462,8 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
new ServiceWorkerContextWrapper(context);
- service_worker_context->Init(path, quota_manager->proxy());
+ service_worker_context->Init(
+ path, quota_manager->proxy(), context->GetSpecialStoragePolicy());
scoped_refptr<ChromeAppCacheService> appcache_service =
new ChromeAppCacheService(quota_manager->proxy());
@@ -425,9 +471,13 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
scoped_refptr<WebRTCIdentityStore> webrtc_identity_store(
new WebRTCIdentityStore(path, context->GetSpecialStoragePolicy()));
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy(
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy(
context->GetSpecialStoragePolicy());
+ scoped_refptr<GeofencingManager> geofencing_manager =
+ new GeofencingManager(service_worker_context);
+ geofencing_manager->Init();
+
return new StoragePartitionImpl(partition_path,
quota_manager.get(),
appcache_service.get(),
@@ -437,7 +487,8 @@ StoragePartitionImpl* StoragePartitionImpl::Create(
indexed_db_context.get(),
service_worker_context.get(),
webrtc_identity_store.get(),
- special_storage_policy.get());
+ special_storage_policy.get(),
+ geofencing_manager.get());
}
base::FilePath StoragePartitionImpl::GetPath() {
@@ -453,7 +504,7 @@ StoragePartitionImpl::GetMediaURLRequestContext() {
return media_url_request_context_.get();
}
-quota::QuotaManager* StoragePartitionImpl::GetQuotaManager() {
+storage::QuotaManager* StoragePartitionImpl::GetQuotaManager() {
return quota_manager_.get();
}
@@ -461,11 +512,11 @@ ChromeAppCacheService* StoragePartitionImpl::GetAppCacheService() {
return appcache_service_.get();
}
-fileapi::FileSystemContext* StoragePartitionImpl::GetFileSystemContext() {
+storage::FileSystemContext* StoragePartitionImpl::GetFileSystemContext() {
return filesystem_context_.get();
}
-webkit_database::DatabaseTracker* StoragePartitionImpl::GetDatabaseTracker() {
+storage::DatabaseTracker* StoragePartitionImpl::GetDatabaseTracker() {
return database_tracker_.get();
}
@@ -481,6 +532,10 @@ ServiceWorkerContextWrapper* StoragePartitionImpl::GetServiceWorkerContext() {
return service_worker_context_.get();
}
+GeofencingManager* StoragePartitionImpl::GetGeofencingManager() {
+ return geofencing_manager_.get();
+}
+
void StoragePartitionImpl::ClearDataImpl(
uint32 remove_mask,
uint32 quota_storage_remove_mask,
@@ -496,10 +551,16 @@ void StoragePartitionImpl::ClearDataImpl(
callback);
// |helper| deletes itself when done in
// DataDeletionHelper::DecrementTaskCountOnUI().
- helper->ClearDataOnUIThread(storage_origin, origin_matcher, GetPath(),
- rq_context, dom_storage_context_, quota_manager_,
+ helper->ClearDataOnUIThread(storage_origin,
+ origin_matcher,
+ GetPath(),
+ rq_context,
+ dom_storage_context_.get(),
+ quota_manager_.get(),
special_storage_policy_.get(),
- webrtc_identity_store_, begin, end);
+ webrtc_identity_store_.get(),
+ begin,
+ end);
}
void StoragePartitionImpl::
@@ -521,9 +582,9 @@ void StoragePartitionImpl::
}
void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread(
- const scoped_refptr<quota::QuotaManager>& quota_manager,
+ const scoped_refptr<storage::QuotaManager>& quota_manager,
const base::Time begin,
- const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy,
+ const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
const StoragePartition::OriginMatcherFunction& origin_matcher) {
IncrementTaskCountOnIO();
base::Closure decrement_callback = base::Bind(
@@ -536,7 +597,8 @@ void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread(
// within the user-specified timeframe, and deal with the resulting set in
// ClearQuotaManagedOriginsOnIOThread().
quota_manager->GetOriginsModifiedSince(
- quota::kStorageTypePersistent, begin,
+ storage::kStorageTypePersistent,
+ begin,
base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread,
base::Unretained(this),
quota_manager,
@@ -549,7 +611,8 @@ void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread(
if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_TEMPORARY) {
IncrementTaskCountOnIO();
quota_manager->GetOriginsModifiedSince(
- quota::kStorageTypeTemporary, begin,
+ storage::kStorageTypeTemporary,
+ begin,
base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread,
base::Unretained(this),
quota_manager,
@@ -562,7 +625,8 @@ void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread(
if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_SYNCABLE) {
IncrementTaskCountOnIO();
quota_manager->GetOriginsModifiedSince(
- quota::kStorageTypeSyncable, begin,
+ storage::kStorageTypeSyncable,
+ begin,
base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread,
base::Unretained(this),
quota_manager,
@@ -574,15 +638,14 @@ void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread(
DecrementTaskCountOnIO();
}
-void StoragePartitionImpl::
- QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread(
- quota::QuotaManager* quota_manager,
- const scoped_refptr<quota::SpecialStoragePolicy>&
- special_storage_policy,
- const StoragePartition::OriginMatcherFunction& origin_matcher,
- const base::Closure& callback,
- const std::set<GURL>& origins,
- quota::StorageType quota_storage_type) {
+void
+StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread(
+ storage::QuotaManager* quota_manager,
+ const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
+ const StoragePartition::OriginMatcherFunction& origin_matcher,
+ const base::Closure& callback,
+ const std::set<GURL>& origins,
+ storage::StorageType quota_storage_type) {
// The QuotaManager manages all storage other than cookies, LocalStorage,
// and SessionStorage. This loop wipes out most HTML5 storage for the given
// origins.
@@ -645,8 +708,8 @@ void StoragePartitionImpl::DataDeletionHelper::ClearDataOnUIThread(
const base::FilePath& path,
net::URLRequestContextGetter* rq_context,
DOMStorageContextWrapper* dom_storage_context,
- quota::QuotaManager* quota_manager,
- quota::SpecialStoragePolicy* special_storage_policy,
+ storage::QuotaManager* quota_manager,
+ storage::SpecialStoragePolicy* special_storage_policy,
WebRTCIdentityStore* webrtc_identity_store,
const base::Time begin,
const base::Time end) {
@@ -670,7 +733,8 @@ void StoragePartitionImpl::DataDeletionHelper::ClearDataOnUIThread(
if (remove_mask & REMOVE_DATA_MASK_INDEXEDDB ||
remove_mask & REMOVE_DATA_MASK_WEBSQL ||
remove_mask & REMOVE_DATA_MASK_APPCACHE ||
- remove_mask & REMOVE_DATA_MASK_FILE_SYSTEMS) {
+ remove_mask & REMOVE_DATA_MASK_FILE_SYSTEMS ||
+ remove_mask & REMOVE_DATA_MASK_SERVICE_WORKERS) {
IncrementTaskCountOnUI();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
@@ -729,16 +793,21 @@ void StoragePartitionImpl::DataDeletionHelper::ClearDataOnUIThread(
DecrementTaskCountOnUI();
}
-
void StoragePartitionImpl::ClearDataForOrigin(
uint32 remove_mask,
uint32 quota_storage_remove_mask,
const GURL& storage_origin,
- net::URLRequestContextGetter* request_context_getter) {
+ net::URLRequestContextGetter* request_context_getter,
+ const base::Closure& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- ClearDataImpl(remove_mask, quota_storage_remove_mask, storage_origin,
- OriginMatcherFunction(), request_context_getter,
- base::Time(), base::Time::Max(), base::Bind(&base::DoNothing));
+ ClearDataImpl(remove_mask,
+ quota_storage_remove_mask,
+ storage_origin,
+ OriginMatcherFunction(),
+ request_context_getter,
+ base::Time(),
+ base::Time::Max(),
+ callback);
}
void StoragePartitionImpl::ClearData(
@@ -758,12 +827,12 @@ WebRTCIdentityStore* StoragePartitionImpl::GetWebRTCIdentityStore() {
}
void StoragePartitionImpl::OverrideQuotaManagerForTesting(
- quota::QuotaManager* quota_manager) {
+ storage::QuotaManager* quota_manager) {
quota_manager_ = quota_manager;
}
void StoragePartitionImpl::OverrideSpecialStoragePolicyForTesting(
- quota::SpecialStoragePolicy* special_storage_policy) {
+ storage::SpecialStoragePolicy* special_storage_policy) {
special_storage_policy_ = special_storage_policy;
}
diff --git a/chromium/content/browser/storage_partition_impl.h b/chromium/content/browser/storage_partition_impl.h
index 717038e7afc..30377392100 100644
--- a/chromium/content/browser/storage_partition_impl.h
+++ b/chromium/content/browser/storage_partition_impl.h
@@ -15,47 +15,48 @@
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/content_export.h"
#include "content/public/browser/storage_partition.h"
-#include "webkit/browser/quota/special_storage_policy.h"
+#include "storage/browser/quota/special_storage_policy.h"
namespace content {
class StoragePartitionImpl : public StoragePartition {
public:
- CONTENT_EXPORT virtual ~StoragePartitionImpl();
+ CONTENT_EXPORT ~StoragePartitionImpl() override;
// Quota managed data uses a different bitmask for types than
// StoragePartition uses. This method generates that mask.
CONTENT_EXPORT static int GenerateQuotaClientMask(uint32 remove_mask);
CONTENT_EXPORT void OverrideQuotaManagerForTesting(
- quota::QuotaManager* quota_manager);
+ storage::QuotaManager* quota_manager);
CONTENT_EXPORT void OverrideSpecialStoragePolicyForTesting(
- quota::SpecialStoragePolicy* special_storage_policy);
+ storage::SpecialStoragePolicy* special_storage_policy);
// StoragePartition interface.
- virtual base::FilePath GetPath() OVERRIDE;
- virtual net::URLRequestContextGetter* GetURLRequestContext() OVERRIDE;
- virtual net::URLRequestContextGetter* GetMediaURLRequestContext() OVERRIDE;
- virtual quota::QuotaManager* GetQuotaManager() OVERRIDE;
- virtual ChromeAppCacheService* GetAppCacheService() OVERRIDE;
- virtual fileapi::FileSystemContext* GetFileSystemContext() OVERRIDE;
- virtual webkit_database::DatabaseTracker* GetDatabaseTracker() OVERRIDE;
- virtual DOMStorageContextWrapper* GetDOMStorageContext() OVERRIDE;
- virtual IndexedDBContextImpl* GetIndexedDBContext() OVERRIDE;
- virtual ServiceWorkerContextWrapper* GetServiceWorkerContext() OVERRIDE;
-
- virtual void ClearDataForOrigin(
- uint32 remove_mask,
- uint32 quota_storage_remove_mask,
- const GURL& storage_origin,
- net::URLRequestContextGetter* request_context_getter) OVERRIDE;
- virtual void ClearData(uint32 remove_mask,
- uint32 quota_storage_remove_mask,
- const GURL& storage_origin,
- const OriginMatcherFunction& origin_matcher,
- const base::Time begin,
- const base::Time end,
- const base::Closure& callback) OVERRIDE;
+ base::FilePath GetPath() override;
+ net::URLRequestContextGetter* GetURLRequestContext() override;
+ net::URLRequestContextGetter* GetMediaURLRequestContext() override;
+ storage::QuotaManager* GetQuotaManager() override;
+ ChromeAppCacheService* GetAppCacheService() override;
+ storage::FileSystemContext* GetFileSystemContext() override;
+ storage::DatabaseTracker* GetDatabaseTracker() override;
+ DOMStorageContextWrapper* GetDOMStorageContext() override;
+ IndexedDBContextImpl* GetIndexedDBContext() override;
+ ServiceWorkerContextWrapper* GetServiceWorkerContext() override;
+ GeofencingManager* GetGeofencingManager() override;
+
+ void ClearDataForOrigin(uint32 remove_mask,
+ uint32 quota_storage_remove_mask,
+ const GURL& storage_origin,
+ net::URLRequestContextGetter* request_context_getter,
+ const base::Closure& callback) override;
+ void ClearData(uint32 remove_mask,
+ uint32 quota_storage_remove_mask,
+ const GURL& storage_origin,
+ const OriginMatcherFunction& origin_matcher,
+ const base::Time begin,
+ const base::Time end,
+ const base::Closure& callback) override;
WebRTCIdentityStore* GetWebRTCIdentityStore();
@@ -108,15 +109,16 @@ class StoragePartitionImpl : public StoragePartition {
CONTENT_EXPORT StoragePartitionImpl(
const base::FilePath& partition_path,
- quota::QuotaManager* quota_manager,
+ storage::QuotaManager* quota_manager,
ChromeAppCacheService* appcache_service,
- fileapi::FileSystemContext* filesystem_context,
- webkit_database::DatabaseTracker* database_tracker,
+ storage::FileSystemContext* filesystem_context,
+ storage::DatabaseTracker* database_tracker,
DOMStorageContextWrapper* dom_storage_context,
IndexedDBContextImpl* indexed_db_context,
ServiceWorkerContextWrapper* service_worker_context,
WebRTCIdentityStore* webrtc_identity_store,
- quota::SpecialStoragePolicy* special_storage_policy);
+ storage::SpecialStoragePolicy* special_storage_policy,
+ GeofencingManager* geofencing_manager);
void ClearDataImpl(uint32 remove_mask,
uint32 quota_storage_remove_mask,
@@ -147,15 +149,16 @@ class StoragePartitionImpl : public StoragePartition {
base::FilePath partition_path_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_;
scoped_refptr<net::URLRequestContextGetter> media_url_request_context_;
- scoped_refptr<quota::QuotaManager> quota_manager_;
+ scoped_refptr<storage::QuotaManager> quota_manager_;
scoped_refptr<ChromeAppCacheService> appcache_service_;
- scoped_refptr<fileapi::FileSystemContext> filesystem_context_;
- scoped_refptr<webkit_database::DatabaseTracker> database_tracker_;
+ scoped_refptr<storage::FileSystemContext> filesystem_context_;
+ scoped_refptr<storage::DatabaseTracker> database_tracker_;
scoped_refptr<DOMStorageContextWrapper> dom_storage_context_;
scoped_refptr<IndexedDBContextImpl> indexed_db_context_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
scoped_refptr<WebRTCIdentityStore> webrtc_identity_store_;
- scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<GeofencingManager> geofencing_manager_;
DISALLOW_COPY_AND_ASSIGN(StoragePartitionImpl);
};
diff --git a/chromium/content/browser/storage_partition_impl_map.cc b/chromium/content/browser/storage_partition_impl_map.cc
index fdfb34e3ebd..d36968b9e28 100644
--- a/chromium/content/browser/storage_partition_impl_map.cc
+++ b/chromium/content/browser/storage_partition_impl_map.cc
@@ -6,14 +6,15 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
@@ -35,14 +36,13 @@
#include "crypto/sha2.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
-#include "webkit/browser/blob/blob_storage_context.h"
-#include "webkit/browser/blob/blob_url_request_job_factory.h"
-#include "webkit/browser/fileapi/file_system_url_request_job_factory.h"
-#include "webkit/common/blob/blob_data.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/blob/blob_url_request_job_factory.h"
+#include "storage/browser/fileapi/file_system_url_request_job_factory.h"
+#include "storage/common/blob/blob_data.h"
-using appcache::AppCacheServiceImpl;
-using fileapi::FileSystemContext;
-using webkit_blob::BlobStorageContext;
+using storage::FileSystemContext;
+using storage::BlobStorageContext;
namespace content {
@@ -53,18 +53,16 @@ class BlobProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
public:
BlobProtocolHandler(ChromeBlobStorageContext* blob_storage_context,
StreamContext* stream_context,
- fileapi::FileSystemContext* file_system_context)
+ storage::FileSystemContext* file_system_context)
: blob_storage_context_(blob_storage_context),
stream_context_(stream_context),
- file_system_context_(file_system_context) {
- }
+ file_system_context_(file_system_context) {}
- virtual ~BlobProtocolHandler() {
- }
+ ~BlobProtocolHandler() override {}
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
scoped_refptr<Stream> stream =
stream_context_->registry()->GetStream(request->url());
if (stream.get())
@@ -74,12 +72,11 @@ class BlobProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
// Construction is deferred because 'this' is constructed on
// the main thread but we want blob_protocol_handler_ constructed
// on the IO thread.
- blob_protocol_handler_.reset(
- new webkit_blob::BlobProtocolHandler(
- blob_storage_context_->context(),
- file_system_context_,
- BrowserThread::GetMessageLoopProxyForThread(
- BrowserThread::FILE).get()));
+ blob_protocol_handler_.reset(new storage::BlobProtocolHandler(
+ blob_storage_context_->context(),
+ file_system_context_.get(),
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
+ .get()));
}
return blob_protocol_handler_->MaybeCreateJob(request, network_delegate);
}
@@ -87,8 +84,8 @@ class BlobProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
private:
const scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
const scoped_refptr<StreamContext> stream_context_;
- const scoped_refptr<fileapi::FileSystemContext> file_system_context_;
- mutable scoped_ptr<webkit_blob::BlobProtocolHandler> blob_protocol_handler_;
+ const scoped_refptr<storage::FileSystemContext> file_system_context_;
+ mutable scoped_ptr<storage::BlobProtocolHandler> blob_protocol_handler_;
DISALLOW_COPY_AND_ASSIGN(BlobProtocolHandler);
};
@@ -438,7 +435,10 @@ StoragePartitionImpl* StoragePartitionImplMap::Get(
URLRequestInterceptorScopedVector request_interceptors;
request_interceptors.push_back(
- ServiceWorkerRequestHandler::CreateInterceptor().release());
+ ServiceWorkerRequestHandler::CreateInterceptor(
+ browser_context_->GetResourceContext()).release());
+ request_interceptors.push_back(
+ AppCacheInterceptor::CreateStartInterceptor().release());
// These calls must happen after StoragePartitionImpl::Create().
if (partition_domain.empty()) {
@@ -495,8 +495,7 @@ void StoragePartitionImplMap::AsyncObliterate(
if (config.partition_domain == partition_domain) {
it->second->ClearData(
// All except shader cache.
- StoragePartition::REMOVE_DATA_MASK_ALL &
- (~StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE),
+ ~StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
GURL(),
StoragePartition::OriginMatcherFunction(),
@@ -582,6 +581,15 @@ void StoragePartitionImplMap::PostCreateInitialization(
make_scoped_refptr(
browser_context_->GetSpecialStoragePolicy())));
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&ServiceWorkerContextWrapper::SetBlobParametersForCache,
+ partition->GetServiceWorkerContext(),
+ make_scoped_refptr(partition->GetURLRequestContext()),
+ make_scoped_refptr(
+ ChromeBlobStorageContext::GetFor(browser_context_))));
+
// We do not call InitializeURLRequestContext() for media contexts because,
// other than the HTTP cache, the media contexts share the same backing
// objects as their associated "normal" request context. Thus, the previous
diff --git a/chromium/content/browser/storage_partition_impl_map.h b/chromium/content/browser/storage_partition_impl_map.h
index c15fefc3d8c..6536621e544 100644
--- a/chromium/content/browser/storage_partition_impl_map.h
+++ b/chromium/content/browser/storage_partition_impl_map.h
@@ -30,7 +30,7 @@ class CONTENT_EXPORT StoragePartitionImplMap
public:
explicit StoragePartitionImplMap(BrowserContext* browser_context);
- virtual ~StoragePartitionImplMap();
+ ~StoragePartitionImplMap() override;
// This map retains ownership of the returned StoragePartition objects.
StoragePartitionImpl* Get(const std::string& partition_domain,
diff --git a/chromium/content/browser/storage_partition_impl_map_unittest.cc b/chromium/content/browser/storage_partition_impl_map_unittest.cc
index ae7fa6d43d2..c88fb538764 100644
--- a/chromium/content/browser/storage_partition_impl_map_unittest.cc
+++ b/chromium/content/browser/storage_partition_impl_map_unittest.cc
@@ -4,7 +4,7 @@
#include "content/browser/storage_partition_impl_map.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "content/public/test/test_browser_context.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/content/browser/storage_partition_impl_unittest.cc b/chromium/content/browser/storage_partition_impl_unittest.cc
index 5fbdfbbab88..a2950c850aa 100644
--- a/chromium/content/browser/storage_partition_impl_unittest.cc
+++ b/chromium/content/browser/storage_partition_impl_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/file_util.h"
+#include "base/files/file_util.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "base/threading/thread.h"
@@ -20,8 +20,8 @@
#include "net/cookies/cookie_monster.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
+#include "storage/browser/quota/quota_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/quota/quota_manager.h"
namespace content {
namespace {
@@ -49,16 +49,16 @@ const base::FilePath::CharType kDomStorageOrigin2[] =
const base::FilePath::CharType kDomStorageOrigin3[] =
FILE_PATH_LITERAL("http_host3_1.localstorage");
-const quota::StorageType kTemporary = quota::kStorageTypeTemporary;
-const quota::StorageType kPersistent = quota::kStorageTypePersistent;
+const storage::StorageType kTemporary = storage::kStorageTypeTemporary;
+const storage::StorageType kPersistent = storage::kStorageTypePersistent;
-const quota::QuotaClient::ID kClientFile = quota::QuotaClient::kFileSystem;
+const storage::QuotaClient::ID kClientFile = storage::QuotaClient::kFileSystem;
const uint32 kAllQuotaRemoveMask =
- StoragePartition::REMOVE_DATA_MASK_INDEXEDDB |
- StoragePartition::REMOVE_DATA_MASK_WEBSQL |
+ StoragePartition::REMOVE_DATA_MASK_APPCACHE |
StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS |
- StoragePartition::REMOVE_DATA_MASK_APPCACHE;
+ StoragePartition::REMOVE_DATA_MASK_INDEXEDDB |
+ StoragePartition::REMOVE_DATA_MASK_WEBSQL;
class AwaitCompletionHelper {
public:
@@ -225,7 +225,7 @@ bool IsWebSafeSchemeForTest(const std::string& scheme) {
bool DoesOriginMatchForUnprotectedWeb(
const GURL& origin,
- quota::SpecialStoragePolicy* special_storage_policy) {
+ storage::SpecialStoragePolicy* special_storage_policy) {
if (IsWebSafeSchemeForTest(origin.scheme()))
return !special_storage_policy->IsStorageProtected(origin.GetOrigin());
@@ -234,23 +234,22 @@ bool DoesOriginMatchForUnprotectedWeb(
bool DoesOriginMatchForBothProtectedAndUnprotectedWeb(
const GURL& origin,
- quota::SpecialStoragePolicy* special_storage_policy) {
+ storage::SpecialStoragePolicy* special_storage_policy) {
return true;
}
bool DoesOriginMatchUnprotected(
const GURL& origin,
- quota::SpecialStoragePolicy* special_storage_policy) {
+ storage::SpecialStoragePolicy* special_storage_policy) {
return origin.GetOrigin().scheme() != kOriginDevTools.scheme();
}
void ClearQuotaData(content::StoragePartition* partition,
base::RunLoop* loop_to_quit) {
- partition->ClearData(
- kAllQuotaRemoveMask,
- StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
- GURL(), StoragePartition::OriginMatcherFunction(),
- base::Time(), base::Time::Max(), loop_to_quit->QuitClosure());
+ partition->ClearData(kAllQuotaRemoveMask,
+ StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, GURL(),
+ StoragePartition::OriginMatcherFunction(), base::Time(),
+ base::Time::Max(), loop_to_quit->QuitClosure());
}
void ClearQuotaDataWithOriginMatcher(
@@ -280,13 +279,11 @@ void ClearQuotaDataForNonPersistent(
content::StoragePartition* partition,
const base::Time delete_begin,
base::RunLoop* loop_to_quit) {
- uint32 quota_storage_remove_mask_no_persistent =
- StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL &
- ~StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT;
partition->ClearData(
- kAllQuotaRemoveMask, quota_storage_remove_mask_no_persistent,
- GURL(), StoragePartition::OriginMatcherFunction(),
- delete_begin, base::Time::Max(), loop_to_quit->QuitClosure());
+ kAllQuotaRemoveMask,
+ ~StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT,
+ GURL(), StoragePartition::OriginMatcherFunction(), delete_begin,
+ base::Time::Max(), loop_to_quit->QuitClosure());
}
void ClearCookies(content::StoragePartition* partition,
@@ -367,7 +364,7 @@ class StoragePartitionShaderClearTest : public testing::Test {
cache_ = ShaderCacheFactory::GetInstance()->Get(kDefaultClientId);
}
- virtual ~StoragePartitionShaderClearTest() {
+ ~StoragePartitionShaderClearTest() override {
cache_ = NULL;
ShaderCacheFactory::GetInstance()->RemoveCacheInfo(kDefaultClientId);
}
@@ -416,27 +413,23 @@ TEST_F(StoragePartitionShaderClearTest, ClearShaderCache) {
}
TEST_F(StoragePartitionImplTest, QuotaClientMaskGeneration) {
- EXPECT_EQ(quota::QuotaClient::kFileSystem,
+ EXPECT_EQ(storage::QuotaClient::kFileSystem,
StoragePartitionImpl::GenerateQuotaClientMask(
StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS));
- EXPECT_EQ(quota::QuotaClient::kDatabase,
+ EXPECT_EQ(storage::QuotaClient::kDatabase,
StoragePartitionImpl::GenerateQuotaClientMask(
StoragePartition::REMOVE_DATA_MASK_WEBSQL));
- EXPECT_EQ(quota::QuotaClient::kAppcache,
+ EXPECT_EQ(storage::QuotaClient::kAppcache,
StoragePartitionImpl::GenerateQuotaClientMask(
StoragePartition::REMOVE_DATA_MASK_APPCACHE));
- EXPECT_EQ(quota::QuotaClient::kIndexedDatabase,
- StoragePartitionImpl::GenerateQuotaClientMask(
- StoragePartition::REMOVE_DATA_MASK_INDEXEDDB));
- EXPECT_EQ(quota::QuotaClient::kFileSystem |
- quota::QuotaClient::kDatabase |
- quota::QuotaClient::kAppcache |
- quota::QuotaClient::kIndexedDatabase,
+ EXPECT_EQ(storage::QuotaClient::kIndexedDatabase,
StoragePartitionImpl::GenerateQuotaClientMask(
- StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS |
- StoragePartition::REMOVE_DATA_MASK_WEBSQL |
- StoragePartition::REMOVE_DATA_MASK_APPCACHE |
StoragePartition::REMOVE_DATA_MASK_INDEXEDDB));
+ EXPECT_EQ(storage::QuotaClient::kFileSystem |
+ storage::QuotaClient::kDatabase |
+ storage::QuotaClient::kAppcache |
+ storage::QuotaClient::kIndexedDatabase,
+ StoragePartitionImpl::GenerateQuotaClientMask(kAllQuotaRemoveMask));
}
void PopulateTestQuotaManagedPersistentData(MockQuotaManager* manager) {
@@ -679,7 +672,7 @@ TEST_F(StoragePartitionImplTest, RemoveQuotaManagedUnprotectedOrigins) {
BrowserContext::GetDefaultStoragePartition(browser_context()));
partition->OverrideQuotaManagerForTesting(
GetMockManager());
- partition->OverrideSpecialStoragePolicyForTesting(mock_policy);
+ partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
base::RunLoop run_loop;
base::MessageLoop::current()->PostTask(
@@ -715,7 +708,7 @@ TEST_F(StoragePartitionImplTest, RemoveQuotaManagedProtectedSpecificOrigin) {
BrowserContext::GetDefaultStoragePartition(browser_context()));
partition->OverrideQuotaManagerForTesting(
GetMockManager());
- partition->OverrideSpecialStoragePolicyForTesting(mock_policy);
+ partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
// Try to remove kOrigin1. Expect failure.
base::RunLoop run_loop;
@@ -754,7 +747,7 @@ TEST_F(StoragePartitionImplTest, RemoveQuotaManagedProtectedOrigins) {
BrowserContext::GetDefaultStoragePartition(browser_context()));
partition->OverrideQuotaManagerForTesting(
GetMockManager());
- partition->OverrideSpecialStoragePolicyForTesting(mock_policy);
+ partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&ClearQuotaDataWithOriginMatcher,
@@ -855,7 +848,7 @@ TEST_F(StoragePartitionImplTest, RemoveUnprotectedLocalStorageForever) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
BrowserContext::GetDefaultStoragePartition(browser_context()));
- partition->OverrideSpecialStoragePolicyForTesting(mock_policy);
+ partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
base::RunLoop run_loop;
base::MessageLoop::current()->PostTask(
@@ -887,7 +880,7 @@ TEST_F(StoragePartitionImplTest, RemoveProtectedLocalStorageForever) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
BrowserContext::GetDefaultStoragePartition(browser_context()));
- partition->OverrideSpecialStoragePolicyForTesting(mock_policy);
+ partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
base::RunLoop run_loop;
base::MessageLoop::current()->PostTask(
diff --git a/chromium/content/browser/streams/stream.cc b/chromium/content/browser/streams/stream.cc
index d10770c42d2..966313cc45d 100644
--- a/chromium/content/browser/streams/stream.cc
+++ b/chromium/content/browser/streams/stream.cc
@@ -160,15 +160,9 @@ Stream::StreamState Stream::ReadRawData(net::IOBuffer* buf,
return STREAM_HAS_DATA;
}
-scoped_ptr<StreamHandle> Stream::CreateHandle(
- const GURL& original_url,
- const std::string& mime_type,
- scoped_refptr<net::HttpResponseHeaders> response_headers) {
+scoped_ptr<StreamHandle> Stream::CreateHandle() {
CHECK(!stream_handle_);
- stream_handle_ = new StreamHandleImpl(weak_ptr_factory_.GetWeakPtr(),
- original_url,
- mime_type,
- response_headers);
+ stream_handle_ = new StreamHandleImpl(weak_ptr_factory_.GetWeakPtr());
return scoped_ptr<StreamHandle>(stream_handle_).Pass();
}
diff --git a/chromium/content/browser/streams/stream.h b/chromium/content/browser/streams/stream.h
index e7e9586ca96..7c938b87c47 100644
--- a/chromium/content/browser/streams/stream.h
+++ b/chromium/content/browser/streams/stream.h
@@ -13,7 +13,6 @@
#include "url/gurl.h"
namespace net {
-class HttpResponseHeaders;
class IOBuffer;
}
@@ -78,10 +77,7 @@ class CONTENT_EXPORT Stream : public base::RefCountedThreadSafe<Stream> {
// and STREAM_COMPLETE if the stream is finalized and all data has been read.
StreamState ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read);
- scoped_ptr<StreamHandle> CreateHandle(
- const GURL& original_url,
- const std::string& mime_type,
- scoped_refptr<net::HttpResponseHeaders> response_headers);
+ scoped_ptr<StreamHandle> CreateHandle();
void CloseHandle();
// Indicates whether there is space in the buffer to add more data.
diff --git a/chromium/content/browser/streams/stream_handle_impl.cc b/chromium/content/browser/streams/stream_handle_impl.cc
index 6ff49621b57..5bc2acbf4fa 100644
--- a/chromium/content/browser/streams/stream_handle_impl.cc
+++ b/chromium/content/browser/streams/stream_handle_impl.cc
@@ -8,7 +8,6 @@
#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
#include "content/browser/streams/stream.h"
-#include "net/http/http_response_headers.h"
namespace content {
@@ -21,16 +20,9 @@ void RunCloseListeners(const std::vector<base::Closure>& close_listeners) {
} // namespace
-StreamHandleImpl::StreamHandleImpl(
- const base::WeakPtr<Stream>& stream,
- const GURL& original_url,
- const std::string& mime_type,
- scoped_refptr<net::HttpResponseHeaders> response_headers)
+StreamHandleImpl::StreamHandleImpl(const base::WeakPtr<Stream>& stream)
: stream_(stream),
url_(stream->url()),
- original_url_(original_url),
- mime_type_(mime_type),
- response_headers_(response_headers),
stream_message_loop_(base::MessageLoopProxy::current().get()) {}
StreamHandleImpl::~StreamHandleImpl() {
@@ -43,18 +35,6 @@ const GURL& StreamHandleImpl::GetURL() {
return url_;
}
-const GURL& StreamHandleImpl::GetOriginalURL() {
- return original_url_;
-}
-
-const std::string& StreamHandleImpl::GetMimeType() {
- return mime_type_;
-}
-
-scoped_refptr<net::HttpResponseHeaders> StreamHandleImpl::GetResponseHeaders() {
- return response_headers_;
-}
-
void StreamHandleImpl::AddCloseListener(const base::Closure& callback) {
close_listeners_.push_back(callback);
}
diff --git a/chromium/content/browser/streams/stream_handle_impl.h b/chromium/content/browser/streams/stream_handle_impl.h
index dc64dade6da..d2bd94def8e 100644
--- a/chromium/content/browser/streams/stream_handle_impl.h
+++ b/chromium/content/browser/streams/stream_handle_impl.h
@@ -8,7 +8,6 @@
#include <vector>
#include "base/memory/weak_ptr.h"
-#include "base/synchronization/lock.h"
#include "content/public/browser/stream_handle.h"
namespace base {
@@ -21,25 +20,16 @@ class Stream;
class StreamHandleImpl : public StreamHandle {
public:
- StreamHandleImpl(const base::WeakPtr<Stream>& stream,
- const GURL& original_url,
- const std::string& mime_type,
- scoped_refptr<net::HttpResponseHeaders> response_headers);
- virtual ~StreamHandleImpl();
+ StreamHandleImpl(const base::WeakPtr<Stream>& stream);
+ ~StreamHandleImpl() override;
private:
// StreamHandle overrides
- virtual const GURL& GetURL() OVERRIDE;
- virtual const GURL& GetOriginalURL() OVERRIDE;
- virtual const std::string& GetMimeType() OVERRIDE;
- virtual scoped_refptr<net::HttpResponseHeaders> GetResponseHeaders() OVERRIDE;
- virtual void AddCloseListener(const base::Closure& callback) OVERRIDE;
+ const GURL& GetURL() override;
+ void AddCloseListener(const base::Closure& callback) override;
base::WeakPtr<Stream> stream_;
GURL url_;
- GURL original_url_;
- std::string mime_type_;
- scoped_refptr<net::HttpResponseHeaders> response_headers_;
base::MessageLoopProxy* stream_message_loop_;
std::vector<base::Closure> close_listeners_;
};
diff --git a/chromium/content/browser/streams/stream_unittest.cc b/chromium/content/browser/streams/stream_unittest.cc
index a2d959305fa..e0346e5a76e 100644
--- a/chromium/content/browser/streams/stream_unittest.cc
+++ b/chromium/content/browser/streams/stream_unittest.cc
@@ -16,9 +16,7 @@ class StreamTest : public testing::Test {
public:
StreamTest() : producing_seed_key_(0) {}
- virtual void SetUp() OVERRIDE {
- registry_.reset(new StreamRegistry());
- }
+ void SetUp() override { registry_.reset(new StreamRegistry()); }
// Create a new IO buffer of the given |buffer_size| and fill it with random
// data.
@@ -43,7 +41,7 @@ class TestStreamReader : public StreamReadObserver {
public:
TestStreamReader() : buffer_(new net::GrowableIOBuffer()), completed_(false) {
}
- virtual ~TestStreamReader() {}
+ ~TestStreamReader() override {}
void Read(Stream* stream) {
const size_t kBufferSize = 32768;
@@ -76,9 +74,7 @@ class TestStreamReader : public StreamReadObserver {
}
}
- virtual void OnDataAvailable(Stream* stream) OVERRIDE {
- Read(stream);
- }
+ void OnDataAvailable(Stream* stream) override { Read(stream); }
scoped_refptr<net::GrowableIOBuffer> buffer() { return buffer_; }
@@ -94,7 +90,7 @@ class TestStreamReader : public StreamReadObserver {
class TestStreamWriter : public StreamWriteObserver {
public:
TestStreamWriter() {}
- virtual ~TestStreamWriter() {}
+ ~TestStreamWriter() override {}
void Write(Stream* stream,
scoped_refptr<net::IOBuffer> buffer,
@@ -102,11 +98,9 @@ class TestStreamWriter : public StreamWriteObserver {
stream->AddData(buffer, buffer_size);
}
- virtual void OnSpaceAvailable(Stream* stream) OVERRIDE {
- }
+ void OnSpaceAvailable(Stream* stream) override {}
- virtual void OnClose(Stream* stream) OVERRIDE {
- }
+ void OnClose(Stream* stream) override {}
};
TEST_F(StreamTest, SetReadObserver) {
diff --git a/chromium/content/browser/streams/stream_url_request_job.h b/chromium/content/browser/streams/stream_url_request_job.h
index 03187bf2399..17e7eb2e3da 100644
--- a/chromium/content/browser/streams/stream_url_request_job.h
+++ b/chromium/content/browser/streams/stream_url_request_job.h
@@ -24,22 +24,19 @@ class CONTENT_EXPORT StreamURLRequestJob
scoped_refptr<Stream> stream);
// StreamObserver methods.
- virtual void OnDataAvailable(Stream* stream) OVERRIDE;
+ void OnDataAvailable(Stream* stream) override;
// net::URLRequestJob methods.
- virtual void Start() OVERRIDE;
- virtual void Kill() OVERRIDE;
- virtual bool ReadRawData(net::IOBuffer* buf,
- int buf_size,
- int* bytes_read) OVERRIDE;
- virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
- virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE;
- virtual int GetResponseCode() const OVERRIDE;
- virtual void SetExtraRequestHeaders(
- const net::HttpRequestHeaders& headers) OVERRIDE;
+ void Start() override;
+ void Kill() override;
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+ 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:
- virtual ~StreamURLRequestJob();
+ ~StreamURLRequestJob() override;
private:
void DidStart();
diff --git a/chromium/content/browser/streams/stream_url_request_job_unittest.cc b/chromium/content/browser/streams/stream_url_request_job_unittest.cc
index 035a588bc96..ad33f938a71 100644
--- a/chromium/content/browser/streams/stream_url_request_job_unittest.cc
+++ b/chromium/content/browser/streams/stream_url_request_job_unittest.cc
@@ -38,9 +38,9 @@ class StreamURLRequestJobTest : public testing::Test {
MockProtocolHandler(StreamRegistry* registry) : registry_(registry) {}
// net::URLRequestJobFactory::ProtocolHandler override.
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
scoped_refptr<Stream> stream = registry_->GetStream(request->url());
if (stream.get())
return new StreamURLRequestJob(request, network_delegate, stream);
@@ -53,7 +53,7 @@ class StreamURLRequestJobTest : public testing::Test {
StreamURLRequestJobTest() {}
- virtual void SetUp() {
+ void SetUp() override {
registry_.reset(new StreamRegistry());
url_request_job_factory_.SetProtocolHandler(
@@ -61,8 +61,7 @@ class StreamURLRequestJobTest : public testing::Test {
url_request_context_.set_job_factory(&url_request_job_factory_);
}
- virtual void TearDown() {
- }
+ void TearDown() override {}
void TestSuccessRequest(const GURL& url,
const std::string& expected_response) {
diff --git a/chromium/content/browser/system_message_window_win_unittest.cc b/chromium/content/browser/system_message_window_win_unittest.cc
index 25c77c9d141..f317f7be7cc 100644
--- a/chromium/content/browser/system_message_window_win_unittest.cc
+++ b/chromium/content/browser/system_message_window_win_unittest.cc
@@ -21,7 +21,7 @@ class SystemMessageWindowWinTest : public testing::Test {
virtual ~SystemMessageWindowWinTest() { }
protected:
- virtual void SetUp() OVERRIDE {
+ virtual void SetUp() override {
system_monitor_.AddDevicesChangedObserver(&observer_);
}
diff --git a/chromium/content/browser/tcmalloc_internals_request_job.cc b/chromium/content/browser/tcmalloc_internals_request_job.cc
index 58e78afeea2..750eae35868 100644
--- a/chromium/content/browser/tcmalloc_internals_request_job.cc
+++ b/chromium/content/browser/tcmalloc_internals_request_job.cc
@@ -5,6 +5,7 @@
#include "content/browser/tcmalloc_internals_request_job.h"
#include "base/allocator/allocator_extension.h"
+#include "base/profiler/scoped_tracker.h"
#include "content/common/child_process_messages.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/browser_thread.h"
@@ -108,6 +109,11 @@ int TcmallocInternalsRequestJob::GetData(
std::string* charset,
std::string* data,
const net::CompletionCallback& callback) const {
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "422489 TcmallocInternalsRequestJob::GetData"));
+
mime_type->assign("text/html");
charset->assign("UTF8");
diff --git a/chromium/content/browser/tcmalloc_internals_request_job.h b/chromium/content/browser/tcmalloc_internals_request_job.h
index 20b2d4fc5f7..d6d7e008d97 100644
--- a/chromium/content/browser/tcmalloc_internals_request_job.h
+++ b/chromium/content/browser/tcmalloc_internals_request_job.h
@@ -50,13 +50,13 @@ class TcmallocInternalsRequestJob : public net::URLRequestSimpleJob {
TcmallocInternalsRequestJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate);
- virtual int GetData(std::string* mime_type,
- std::string* charset,
- std::string* data,
- const net::CompletionCallback& callback) const OVERRIDE;
+ int GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* data,
+ const net::CompletionCallback& callback) const override;
protected:
- virtual ~TcmallocInternalsRequestJob() {}
+ ~TcmallocInternalsRequestJob() override {}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(TcmallocInternalsRequestJob);
diff --git a/chromium/content/browser/theme_helper_mac.h b/chromium/content/browser/theme_helper_mac.h
index 565903bbe3e..935ab3fe238 100644
--- a/chromium/content/browser/theme_helper_mac.h
+++ b/chromium/content/browser/theme_helper_mac.h
@@ -33,12 +33,12 @@ class ThemeHelperMac : public NotificationObserver {
friend struct DefaultSingletonTraits<ThemeHelperMac>;
ThemeHelperMac();
- virtual ~ThemeHelperMac();
+ ~ThemeHelperMac() override;
// Overridden from NotificationObserver:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
NotificationRegistrar registrar_;
diff --git a/chromium/content/browser/time_zone_monitor_chromeos.cc b/chromium/content/browser/time_zone_monitor_chromeos.cc
index 6fc885edba0..8c6aa0bd0a3 100644
--- a/chromium/content/browser/time_zone_monitor_chromeos.cc
+++ b/chromium/content/browser/time_zone_monitor_chromeos.cc
@@ -21,7 +21,7 @@ class TimeZoneMonitorChromeOS
}
// chromeos::system::TimezoneSettings::Observer implementation.
- virtual void TimezoneChanged(const icu::TimeZone& time_zone) OVERRIDE {
+ virtual void TimezoneChanged(const icu::TimeZone& time_zone) override {
NotifyRenderers();
}
diff --git a/chromium/content/browser/time_zone_monitor_linux.cc b/chromium/content/browser/time_zone_monitor_linux.cc
index f8cae0e2430..0836d5b8398 100644
--- a/chromium/content/browser/time_zone_monitor_linux.cc
+++ b/chromium/content/browser/time_zone_monitor_linux.cc
@@ -27,7 +27,7 @@ class TimeZoneMonitorLinuxImpl;
class TimeZoneMonitorLinux : public TimeZoneMonitor {
public:
TimeZoneMonitorLinux();
- virtual ~TimeZoneMonitorLinux();
+ ~TimeZoneMonitorLinux() override;
void NotifyRenderersFromImpl() {
NotifyRenderers();
@@ -151,7 +151,7 @@ TimeZoneMonitorLinux::TimeZoneMonitorLinux()
}
TimeZoneMonitorLinux::~TimeZoneMonitorLinux() {
- if (impl_) {
+ if (impl_.get()) {
impl_->StopWatching();
}
}
diff --git a/chromium/content/browser/time_zone_monitor_mac.mm b/chromium/content/browser/time_zone_monitor_mac.mm
index c435aae818e..700c17e6c58 100644
--- a/chromium/content/browser/time_zone_monitor_mac.mm
+++ b/chromium/content/browser/time_zone_monitor_mac.mm
@@ -21,7 +21,7 @@ class TimeZoneMonitorMac : public TimeZoneMonitor {
}];
}
- virtual ~TimeZoneMonitorMac() {
+ ~TimeZoneMonitorMac() override {
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:notification_observer_];
}
diff --git a/chromium/content/browser/time_zone_monitor_win.cc b/chromium/content/browser/time_zone_monitor_win.cc
index 6d99b940e41..2e8f9a56ed1 100644
--- a/chromium/content/browser/time_zone_monitor_win.cc
+++ b/chromium/content/browser/time_zone_monitor_win.cc
@@ -26,7 +26,7 @@ class TimeZoneMonitorWin : public TimeZoneMonitor,
virtual void OnWndProc(HWND hwnd,
UINT message,
WPARAM wparam,
- LPARAM lparam) OVERRIDE {
+ LPARAM lparam) override {
if (message != WM_TIMECHANGE) {
return;
}
diff --git a/chromium/content/browser/tracing/BUILD.gn b/chromium/content/browser/tracing/BUILD.gn
index 94694ee2fa4..ae9c7dfaf3c 100644
--- a/chromium/content/browser/tracing/BUILD.gn
+++ b/chromium/content/browser/tracing/BUILD.gn
@@ -12,14 +12,14 @@ tracing_gen_dir = "$root_gen_dir/content/browser/tracing"
tracing_grd = "$tracing_gen_dir/tracing_resources.grd"
action("generate_tracing_grd") {
- visibility = ":resources"
+ visibility = [ ":*" ]
script = "generate_trace_viewer_grd.py"
input_pages = [
"$tracing_gen_dir/about_tracing.html",
"$tracing_gen_dir/about_tracing.js",
]
- source_prereqs = input_pages
+ inputs = input_pages
outputs = [ tracing_grd ]
args = rebase_path(input_pages, target_gen_dir) + [
@@ -31,36 +31,19 @@ action("generate_tracing_grd") {
]
}
-# This can't use the grit template because the grd file is generated at build
-# time, so the trick of using grit_info to get the real inputs/outputs at GYP
-# time isn't possible.
-action("resources") {
- script = "//tools/grit/grit.py"
-
- # Get the list of grit script sources.
- grit_inputs_build_rel =
- exec_script("//tools/grit/grit_info.py", [ "--inputs" ], "list lines")
-
- source_prereqs = rebase_path(grit_inputs_build_rel, ".", root_build_dir) + [
- grit_resource_id_file,
- ]
+grit("resources") {
+ source = tracing_grd
outputs = [
- "$target_gen_dir/grit/tracing_resources.h",
- "$target_gen_dir/tracing_resources.pak",
+ "grit/tracing_resources.h",
+ "tracing_resources.pak",
]
- args = [
- "-i", rebase_path(tracing_grd, root_build_dir), "build",
- "-f", rebase_path(grit_resource_id_file, root_build_dir),
- "-o", rebase_path(target_gen_dir, root_build_dir),
- # resource_ids has an entry for our .grd file that looks like:
- # "<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/tracing_resources.grd"
- # and what we pass here should make that resolve to our .grd file.
- "-DSHARED_INTERMEDIATE_DIR=" +
- rebase_path(root_gen_dir, root_build_dir),
- ] + grit_defines
-
- deps = [
- ":generate_tracing_grd",
+ # resource_ids has an entry for our .grd file that looks like:
+ # "<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/tracing_resources.grd"
+ # and what we pass here should make that resolve to our .grd file.
+ defines = [
+ "SHARED_INTERMEDIATE_DIR=" + rebase_path(root_gen_dir, root_build_dir),
]
+
+ deps = [ ":generate_tracing_grd" ]
}
diff --git a/chromium/content/browser/tracing/DEPS b/chromium/content/browser/tracing/DEPS
index b4d8715021b..b99424f6482 100644
--- a/chromium/content/browser/tracing/DEPS
+++ b/chromium/content/browser/tracing/DEPS
@@ -1,4 +1,5 @@
include_rules = [
# Generated by the local tracing_resources.gyp:tracing_resources
"+grit/tracing_resources.h",
+ "+third_party/zlib/zlib.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 df20bce41d7..fc3522fd81e 100644
--- a/chromium/content/browser/tracing/etw_system_event_consumer_win.cc
+++ b/chromium/content/browser/tracing/etw_system_event_consumer_win.cc
@@ -195,7 +195,7 @@ void EtwSystemEventConsumer::TraceAndConsumeOnThread() {
void EtwSystemEventConsumer::FlushOnThread(const OutputCallback& callback) {
// Add the header information to the stream.
scoped_ptr<base::DictionaryValue> header(new base::DictionaryValue());
- header->Set("name", base::Value::CreateStringValue("ETW"));
+ header->Set("name", new base::StringValue("ETW"));
// Release and pass the events buffer.
header->Set("content", events_.release());
diff --git a/chromium/content/browser/tracing/trace_message_filter.cc b/chromium/content/browser/tracing/trace_message_filter.cc
index ba8ec65de16..e74ca96caa6 100644
--- a/chromium/content/browser/tracing/trace_message_filter.cc
+++ b/chromium/content/browser/tracing/trace_message_filter.cc
@@ -57,12 +57,12 @@ bool TraceMessageFilter::OnMessageReceived(const IPC::Message& message) {
}
void TraceMessageFilter::SendBeginTracing(
- const std::string& category_filter_str,
- base::debug::TraceLog::Options options) {
+ const base::debug::CategoryFilter& category_filter,
+ const base::debug::TraceOptions& options) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- Send(new TracingMsg_BeginTracing(category_filter_str,
+ Send(new TracingMsg_BeginTracing(category_filter.ToString(),
base::TimeTicks::NowFromSystemTraceTime(),
- options));
+ options.ToString()));
}
void TraceMessageFilter::SendEndTracing() {
@@ -73,12 +73,12 @@ void TraceMessageFilter::SendEndTracing() {
}
void TraceMessageFilter::SendEnableMonitoring(
- const std::string& category_filter_str,
- base::debug::TraceLog::Options options) {
+ const base::debug::CategoryFilter& category_filter,
+ const base::debug::TraceOptions& options) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- Send(new TracingMsg_EnableMonitoring(category_filter_str,
+ Send(new TracingMsg_EnableMonitoring(category_filter.ToString(),
base::TimeTicks::NowFromSystemTraceTime(),
- options));
+ options.ToString()));
}
void TraceMessageFilter::SendDisableMonitoring() {
diff --git a/chromium/content/browser/tracing/trace_message_filter.h b/chromium/content/browser/tracing/trace_message_filter.h
index 4233fe04480..3d12d76d300 100644
--- a/chromium/content/browser/tracing/trace_message_filter.h
+++ b/chromium/content/browser/tracing/trace_message_filter.h
@@ -21,14 +21,14 @@ class TraceMessageFilter : public BrowserMessageFilter {
TraceMessageFilter();
// BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ void OnChannelClosing() override;
+ bool OnMessageReceived(const IPC::Message& message) override;
- void SendBeginTracing(const std::string& category_filter_str,
- base::debug::TraceLog::Options options);
+ void SendBeginTracing(const base::debug::CategoryFilter& category_filter_str,
+ const base::debug::TraceOptions& options);
void SendEndTracing();
- void SendEnableMonitoring(const std::string& category_filter_str,
- base::debug::TraceLog::Options options);
+ void SendEnableMonitoring(const base::debug::CategoryFilter& category_filter,
+ const base::debug::TraceOptions& options);
void SendDisableMonitoring();
void SendCaptureMonitoringSnapshot();
void SendGetTraceBufferPercentFull();
@@ -37,7 +37,7 @@ class TraceMessageFilter : public BrowserMessageFilter {
void SendCancelWatchEvent();
protected:
- virtual ~TraceMessageFilter();
+ ~TraceMessageFilter() override;
private:
// Message handlers.
diff --git a/chromium/content/browser/tracing/trace_uploader.cc b/chromium/content/browser/tracing/trace_uploader.cc
new file mode 100644
index 00000000000..3bcc1872817
--- /dev/null
+++ b/chromium/content/browser/tracing/trace_uploader.cc
@@ -0,0 +1,210 @@
+// 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/tracing/trace_uploader.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/shared_memory.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/mime_util.h"
+#include "net/base/network_delegate.h"
+#include "net/proxy/proxy_config.h"
+#include "net/proxy/proxy_config_service.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "third_party/zlib/zlib.h"
+#include "url/gurl.h"
+
+namespace content {
+namespace {
+const char kUploadContentType[] = "multipart/form-data";
+const char kMultipartBoundary[] =
+ "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
+
+const int kHttpResponseOk = 200;
+
+} // namespace
+
+TraceUploader::TraceUploader(const std::string& product,
+ const std::string& version,
+ const std::string& upload_url,
+ net::URLRequestContextGetter* request_context)
+ : product_(product),
+ version_(version),
+ upload_url_(upload_url),
+ request_context_(request_context) {
+ DCHECK(!product_.empty());
+ DCHECK(!version_.empty());
+ DCHECK(!upload_url_.empty());
+}
+
+TraceUploader::~TraceUploader() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+void TraceUploader::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK_EQ(source, url_fetcher_.get());
+ int response_code = source->GetResponseCode();
+ string report_id;
+ string error_message;
+ bool success = (response_code == kHttpResponseOk);
+ if (success) {
+ source->GetResponseAsString(&report_id);
+ } else {
+ error_message = "Uploading failed, response code: " +
+ base::IntToString(response_code);
+ }
+
+ BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(done_callback_, success, report_id, error_message));
+ url_fetcher_.reset();
+}
+
+void TraceUploader::OnURLFetchUploadProgress(
+ const net::URLFetcher* source, int64 current, int64 total) {
+ DCHECK(url_fetcher_.get());
+
+ LOG(WARNING) << "Upload progress: " << current << " of " << total;
+ BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(progress_callback_, current, total));
+}
+
+void TraceUploader::DoUpload(
+ const std::string& file_contents,
+ UploadProgressCallback progress_callback,
+ UploadDoneCallback done_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ DCHECK(!url_fetcher_.get());
+
+ progress_callback_ = progress_callback;
+ done_callback_ = done_callback;
+
+ if (url_fetcher_.get()) {
+ OnUploadError("Already uploading.");
+ }
+
+ scoped_ptr<char[]> compressed_contents(new char[kMaxUploadBytes]);
+ int compressed_bytes;
+ if (!Compress(file_contents, kMaxUploadBytes, compressed_contents.get(),
+ &compressed_bytes)) {
+ OnUploadError("Compressing file failed.");
+ return;
+ }
+
+ std::string post_data;
+ SetupMultipart("trace.json.gz",
+ std::string(compressed_contents.get(), compressed_bytes),
+ &post_data);
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&TraceUploader::CreateAndStartURLFetcher,
+ base::Unretained(this),
+ post_data));
+}
+
+void TraceUploader::OnUploadError(std::string error_message) {
+ LOG(ERROR) << error_message;
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(done_callback_, false, "", error_message));
+}
+
+void TraceUploader::SetupMultipart(const std::string& trace_filename,
+ const std::string& trace_contents,
+ std::string* post_data) {
+ net::AddMultipartValueForUpload("prod", product_, kMultipartBoundary, "",
+ post_data);
+ net::AddMultipartValueForUpload("ver", version_ + "-trace",
+ kMultipartBoundary, "", post_data);
+ net::AddMultipartValueForUpload("guid", "0", kMultipartBoundary,
+ "", post_data);
+ net::AddMultipartValueForUpload("type", "trace", kMultipartBoundary,
+ "", post_data);
+ // No minidump means no need for crash to process the report.
+ net::AddMultipartValueForUpload("should_process", "false", kMultipartBoundary,
+ "", post_data);
+
+ AddTraceFile(trace_filename, trace_contents, post_data);
+
+ net::AddMultipartFinalDelimiterForUpload(kMultipartBoundary, post_data);
+}
+
+void TraceUploader::AddTraceFile(const std::string& trace_filename,
+ const std::string& trace_contents,
+ std::string* post_data) {
+ post_data->append("--");
+ post_data->append(kMultipartBoundary);
+ post_data->append("\r\n");
+ post_data->append("Content-Disposition: form-data; name=\"trace\"");
+ post_data->append("; filename=\"");
+ post_data->append(trace_filename);
+ post_data->append("\"\r\n");
+ post_data->append("Content-Type: application/gzip\r\n\r\n");
+ post_data->append(trace_contents);
+ post_data->append("\r\n");
+}
+
+bool TraceUploader::Compress(std::string input,
+ int max_compressed_bytes,
+ char* compressed,
+ int* compressed_bytes) {
+ DCHECK(compressed);
+ DCHECK(compressed_bytes);
+ z_stream stream = {0};
+ int result = deflateInit2(&stream,
+ Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ // 16 is added to produce a gzip header + trailer.
+ MAX_WBITS + 16,
+ 8, // memLevel = 8 is default.
+ Z_DEFAULT_STRATEGY);
+ DCHECK_EQ(Z_OK, result);
+ stream.next_in = reinterpret_cast<uint8*>(&input[0]);
+ stream.avail_in = input.size();
+ stream.next_out = reinterpret_cast<uint8*>(compressed);
+ stream.avail_out = max_compressed_bytes;
+ // Do a one-shot compression. This will return Z_STREAM_END only if |output|
+ // is large enough to hold all compressed data.
+ result = deflate(&stream, Z_FINISH);
+ bool success = (result == Z_STREAM_END);
+ result = deflateEnd(&stream);
+ DCHECK(result == Z_OK || result == Z_DATA_ERROR);
+
+ if (success)
+ *compressed_bytes = max_compressed_bytes - stream.avail_out;
+
+ LOG(WARNING) << "input size: " << input.size()
+ << ", output size: " << *compressed_bytes;
+ return success;
+}
+
+void TraceUploader::CreateAndStartURLFetcher(const std::string& post_data) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(!url_fetcher_.get());
+
+ std::string content_type = kUploadContentType;
+ content_type.append("; boundary=");
+ content_type.append(kMultipartBoundary);
+
+ url_fetcher_.reset(
+ net::URLFetcher::Create(GURL(upload_url_), net::URLFetcher::POST, this));
+ url_fetcher_->SetRequestContext(request_context_);
+ url_fetcher_->SetUploadData(content_type, post_data);
+ url_fetcher_->Start();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/tracing/trace_uploader.h b/chromium/content/browser/tracing/trace_uploader.h
new file mode 100644
index 00000000000..323a4c54668
--- /dev/null
+++ b/chromium/content/browser/tracing/trace_uploader.h
@@ -0,0 +1,92 @@
+// 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_TRACING_TRACE_UPLOADER_H_
+#define CONTENT_BROWSER_TRACING_TRACE_UPLOADER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "net/url_request/url_fetcher_delegate.h"
+
+namespace net {
+class URLFetcher;
+class URLRequestContextGetter;
+} // namespace net
+
+namespace content {
+
+namespace {
+
+// Allow up to 10MB for trace upload
+const int kMaxUploadBytes = 10000000;
+
+} // namespace
+
+// TraceUploader uploads traces.
+class TraceUploader : public net::URLFetcherDelegate {
+ public:
+ typedef base::Callback<void(bool, const std::string&, const std::string&)>
+ UploadDoneCallback;
+ typedef base::Callback<void(int64, int64)> UploadProgressCallback;
+
+ TraceUploader(const std::string& product,
+ const std::string& version,
+ const std::string& upload_url,
+ net::URLRequestContextGetter* request_context);
+ ~TraceUploader() override;
+
+ // net::URLFetcherDelegate implementation.
+ void OnURLFetchComplete(const net::URLFetcher* source) override;
+ void OnURLFetchUploadProgress(const net::URLFetcher* source,
+ int64 current,
+ int64 total) override;
+
+ // Compresses and uploads the given file contents.
+ void DoUpload(const std::string& file_contents,
+ UploadProgressCallback progress_callback,
+ UploadDoneCallback done_callback);
+
+ private:
+ // Sets up a multipart body to be uploaded. The body is produced according
+ // to RFC 2046.
+ void SetupMultipart(const std::string& trace_filename,
+ const std::string& trace_contents,
+ std::string* post_data);
+ void AddTraceFile(const std::string& trace_filename,
+ const std::string& trace_contents,
+ std::string* post_data);
+ // Compresses the input and returns whether compression was successful.
+ bool Compress(std::string input,
+ int max_compressed_bytes,
+ char* compressed_contents,
+ int* compressed_bytes);
+ void CreateAndStartURLFetcher(const std::string& post_data);
+ void OnUploadError(std::string error_message);
+
+ std::string product_;
+ std::string version_;
+
+ std::string upload_url_;
+
+ scoped_ptr<net::URLFetcher> url_fetcher_;
+ UploadProgressCallback progress_callback_;
+ UploadDoneCallback done_callback_;
+
+ net::URLRequestContextGetter* request_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceUploader);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_TRACING_TRACE_UPLOADER_H_
diff --git a/chromium/content/browser/tracing/tracing_controller_browsertest.cc b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
index 36f0dce85a8..cb74923afc1 100644
--- a/chromium/content/browser/tracing/tracing_controller_browsertest.cc
+++ b/chromium/content/browser/tracing/tracing_controller_browsertest.cc
@@ -2,21 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/file_util.h"
+#include "base/files/file_util.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/run_loop.h"
-#include "content/browser/tracing/tracing_controller_impl.h"
+#include "content/public/browser/tracing_controller.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"
+using base::debug::CategoryFilter;
+using base::debug::TraceOptions;
+using base::debug::RECORD_CONTINUOUSLY;
+using base::debug::RECORD_UNTIL_FULL;
+
namespace content {
class TracingControllerTest : public ContentBrowserTest {
public:
TracingControllerTest() {}
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
get_categories_done_callback_count_ = 0;
enable_recording_done_callback_count_ = 0;
disable_recording_done_callback_count_ = 0;
@@ -26,9 +32,7 @@ class TracingControllerTest : public ContentBrowserTest {
ContentBrowserTest::SetUp();
}
- virtual void TearDown() OVERRIDE {
- ContentBrowserTest::TearDown();
- }
+ void TearDown() override { ContentBrowserTest::TearDown(); }
void Navigate(Shell* shell) {
NavigateToURL(shell, GetTestUrl("", "title.html"));
@@ -46,8 +50,15 @@ class TracingControllerTest : public ContentBrowserTest {
quit_callback.Run();
}
- void DisableRecordingDoneCallbackTest(base::Closure quit_callback,
- const base::FilePath& file_path) {
+ void DisableRecordingStringDoneCallbackTest(base::Closure quit_callback,
+ base::RefCountedString* data) {
+ disable_recording_done_callback_count_++;
+ EXPECT_TRUE(data->size() > 0);
+ quit_callback.Run();
+ }
+
+ void DisableRecordingFileDoneCallbackTest(base::Closure quit_callback,
+ const base::FilePath& file_path) {
disable_recording_done_callback_count_++;
EXPECT_TRUE(PathExists(file_path));
int64 file_size;
@@ -110,7 +121,7 @@ class TracingControllerTest : public ContentBrowserTest {
return last_actual_monitoring_file_path_;
}
- void TestEnableAndDisableRecording(const base::FilePath& result_file_path) {
+ void TestEnableAndDisableRecordingString() {
Navigate(shell());
TracingController* controller = TracingController::GetInstance();
@@ -122,7 +133,7 @@ class TracingControllerTest : public ContentBrowserTest {
base::Unretained(this),
run_loop.QuitClosure());
bool result = controller->EnableRecording(
- "", TracingController::DEFAULT_OPTIONS, callback);
+ CategoryFilter(), TraceOptions(), callback);
ASSERT_TRUE(result);
run_loop.Run();
EXPECT_EQ(enable_recording_done_callback_count(), 1);
@@ -130,11 +141,46 @@ class TracingControllerTest : public ContentBrowserTest {
{
base::RunLoop run_loop;
- TracingController::TracingFileResultCallback callback =
- base::Bind(&TracingControllerTest::DisableRecordingDoneCallbackTest,
+ base::Callback<void(base::RefCountedString*)> callback = base::Bind(
+ &TracingControllerTest::DisableRecordingStringDoneCallbackTest,
+ base::Unretained(this),
+ run_loop.QuitClosure());
+ bool result = controller->DisableRecording(
+ TracingController::CreateStringSink(callback));
+ ASSERT_TRUE(result);
+ run_loop.Run();
+ EXPECT_EQ(disable_recording_done_callback_count(), 1);
+ }
+ }
+
+ void TestEnableAndDisableRecordingFile(
+ const base::FilePath& result_file_path) {
+ Navigate(shell());
+
+ TracingController* controller = TracingController::GetInstance();
+
+ {
+ base::RunLoop run_loop;
+ TracingController::EnableRecordingDoneCallback callback =
+ base::Bind(&TracingControllerTest::EnableRecordingDoneCallbackTest,
base::Unretained(this),
run_loop.QuitClosure());
- bool result = controller->DisableRecording(result_file_path, callback);
+ bool result = controller->EnableRecording(
+ CategoryFilter(), TraceOptions(), callback);
+ ASSERT_TRUE(result);
+ run_loop.Run();
+ EXPECT_EQ(enable_recording_done_callback_count(), 1);
+ }
+
+ {
+ base::RunLoop run_loop;
+ base::Closure callback = base::Bind(
+ &TracingControllerTest::DisableRecordingFileDoneCallbackTest,
+ base::Unretained(this),
+ run_loop.QuitClosure(),
+ result_file_path);
+ bool result = controller->DisableRecording(
+ TracingController::CreateFileSink(result_file_path, callback));
ASSERT_TRUE(result);
run_loop.Run();
EXPECT_EQ(disable_recording_done_callback_count(), 1);
@@ -149,16 +195,15 @@ class TracingControllerTest : public ContentBrowserTest {
{
bool is_monitoring;
- std::string category_filter;
- TracingController::Options options;
- controller->GetMonitoringStatus(&is_monitoring,
- &category_filter,
- &options);
+ CategoryFilter category_filter("");
+ TraceOptions options;
+ controller->GetMonitoringStatus(
+ &is_monitoring, &category_filter, &options);
EXPECT_FALSE(is_monitoring);
- EXPECT_EQ("-*Debug,-*Test", category_filter);
- EXPECT_FALSE(options & TracingController::ENABLE_SYSTRACE);
- EXPECT_FALSE(options & TracingController::RECORD_CONTINUOUSLY);
- EXPECT_FALSE(options & TracingController::ENABLE_SAMPLING);
+ EXPECT_EQ("-*Debug,-*Test", category_filter.ToString());
+ EXPECT_FALSE(options.record_mode == RECORD_CONTINUOUSLY);
+ EXPECT_FALSE(options.enable_sampling);
+ EXPECT_FALSE(options.enable_systrace);
}
{
@@ -167,8 +212,14 @@ class TracingControllerTest : public ContentBrowserTest {
base::Bind(&TracingControllerTest::EnableMonitoringDoneCallbackTest,
base::Unretained(this),
run_loop.QuitClosure());
+
+ TraceOptions trace_options;
+ trace_options.enable_sampling = true;
+
bool result = controller->EnableMonitoring(
- "*", TracingController::ENABLE_SAMPLING, callback);
+ CategoryFilter("*"),
+ trace_options,
+ callback);
ASSERT_TRUE(result);
run_loop.Run();
EXPECT_EQ(enable_monitoring_done_callback_count(), 1);
@@ -176,27 +227,26 @@ class TracingControllerTest : public ContentBrowserTest {
{
bool is_monitoring;
- std::string category_filter;
- TracingController::Options options;
- controller->GetMonitoringStatus(&is_monitoring,
- &category_filter,
- &options);
+ CategoryFilter category_filter("");
+ TraceOptions options;
+ controller->GetMonitoringStatus(
+ &is_monitoring, &category_filter, &options);
EXPECT_TRUE(is_monitoring);
- EXPECT_EQ("*", category_filter);
- EXPECT_FALSE(options & TracingController::ENABLE_SYSTRACE);
- EXPECT_FALSE(options & TracingController::RECORD_CONTINUOUSLY);
- EXPECT_TRUE(options & TracingController::ENABLE_SAMPLING);
+ EXPECT_EQ("*", category_filter.ToString());
+ EXPECT_FALSE(options.record_mode == RECORD_CONTINUOUSLY);
+ EXPECT_TRUE(options.enable_sampling);
+ EXPECT_FALSE(options.enable_systrace);
}
{
base::RunLoop run_loop;
- TracingController::TracingFileResultCallback callback =
- base::Bind(&TracingControllerTest::
- CaptureMonitoringSnapshotDoneCallbackTest,
- base::Unretained(this),
- run_loop.QuitClosure());
- ASSERT_TRUE(controller->CaptureMonitoringSnapshot(result_file_path,
- callback));
+ 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);
}
@@ -215,16 +265,16 @@ class TracingControllerTest : public ContentBrowserTest {
{
bool is_monitoring;
- std::string category_filter;
- TracingController::Options options;
+ CategoryFilter category_filter("");
+ TraceOptions options;
controller->GetMonitoringStatus(&is_monitoring,
&category_filter,
&options);
EXPECT_FALSE(is_monitoring);
- EXPECT_EQ("", category_filter);
- EXPECT_FALSE(options & TracingController::ENABLE_SYSTRACE);
- EXPECT_FALSE(options & TracingController::RECORD_CONTINUOUSLY);
- EXPECT_FALSE(options & TracingController::ENABLE_SAMPLING);
+ EXPECT_EQ("", category_filter.ToString());
+ EXPECT_FALSE(options.record_mode == RECORD_CONTINUOUSLY);
+ EXPECT_FALSE(options.enable_sampling);
+ EXPECT_FALSE(options.enable_systrace);
}
}
@@ -255,14 +305,14 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) {
}
IN_PROC_BROWSER_TEST_F(TracingControllerTest, EnableAndDisableRecording) {
- TestEnableAndDisableRecording(base::FilePath());
+ TestEnableAndDisableRecordingString();
}
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
EnableAndDisableRecordingWithFilePath) {
base::FilePath file_path;
base::CreateTemporaryFile(&file_path);
- TestEnableAndDisableRecording(file_path);
+ TestEnableAndDisableRecordingFile(file_path);
EXPECT_EQ(file_path.value(), last_actual_recording_file_path().value());
}
@@ -272,16 +322,18 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest,
TracingController* controller = TracingController::GetInstance();
EXPECT_TRUE(controller->EnableRecording(
- "", TracingController::DEFAULT_OPTIONS,
+ CategoryFilter(),
+ TraceOptions(),
TracingController::EnableRecordingDoneCallback()));
- EXPECT_TRUE(controller->DisableRecording(
- base::FilePath(), TracingController::TracingFileResultCallback()));
+ EXPECT_TRUE(controller->DisableRecording(NULL));
base::RunLoop().RunUntilIdle();
}
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
EnableCaptureAndDisableMonitoring) {
- TestEnableCaptureAndDisableMonitoring(base::FilePath());
+ base::FilePath file_path;
+ base::CreateTemporaryFile(&file_path);
+ TestEnableCaptureAndDisableMonitoring(file_path);
}
IN_PROC_BROWSER_TEST_F(TracingControllerTest,
@@ -292,17 +344,27 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest,
EXPECT_EQ(file_path.value(), last_actual_monitoring_file_path().value());
}
+// See http://crbug.com/392446
+#if defined(OS_ANDROID)
+#define MAYBE_EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback \
+ DISABLED_EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback
+#else
+#define MAYBE_EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback \
+ EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback
+#endif
IN_PROC_BROWSER_TEST_F(
TracingControllerTest,
- EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback) {
+ MAYBE_EnableCaptureAndDisableMonitoringWithEmptyFileAndNullCallback) {
Navigate(shell());
TracingController* controller = TracingController::GetInstance();
+ TraceOptions trace_options;
+ trace_options.enable_sampling = true;
EXPECT_TRUE(controller->EnableMonitoring(
- "*", TracingController::ENABLE_SAMPLING,
+ CategoryFilter("*"),
+ trace_options,
TracingController::EnableMonitoringDoneCallback()));
- controller->CaptureMonitoringSnapshot(
- base::FilePath(), TracingController::TracingFileResultCallback());
+ controller->CaptureMonitoringSnapshot(NULL);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(controller->DisableMonitoring(
TracingController::DisableMonitoringDoneCallback()));
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.cc b/chromium/content/browser/tracing/tracing_controller_impl.cc
index 63a44fcbcbf..3e8e1ac7cd1 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.cc
+++ b/chromium/content/browser/tracing/tracing_controller_impl.cc
@@ -5,8 +5,9 @@
#include "base/bind.h"
#include "base/debug/trace_event.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/json/string_escape.h"
+#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "content/browser/tracing/trace_message_filter.h"
#include "content/browser/tracing/tracing_ui.h"
@@ -24,6 +25,8 @@
#endif
using base::debug::TraceLog;
+using base::debug::TraceOptions;
+using base::debug::CategoryFilter;
namespace content {
@@ -32,134 +35,133 @@ namespace {
base::LazyInstance<TracingControllerImpl>::Leaky g_controller =
LAZY_INSTANCE_INITIALIZER;
-} // namespace
-
-TracingController* TracingController::GetInstance() {
- return TracingControllerImpl::GetInstance();
-}
-
-class TracingControllerImpl::ResultFile {
+class FileTraceDataSink : public TracingController::TraceDataSink {
public:
- explicit ResultFile(const base::FilePath& path);
- void Write(const scoped_refptr<base::RefCountedString>& events_str_ptr) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&TracingControllerImpl::ResultFile::WriteTask,
- base::Unretained(this), events_str_ptr));
+ explicit FileTraceDataSink(const base::FilePath& trace_file_path,
+ const base::Closure& callback)
+ : file_path_(trace_file_path),
+ completion_callback_(callback),
+ file_(NULL) {}
+
+ void AddTraceChunk(const std::string& chunk) override {
+ std::string tmp = chunk;
+ scoped_refptr<base::RefCountedString> chunk_ptr =
+ base::RefCountedString::TakeString(&tmp);
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(
+ &FileTraceDataSink::AddTraceChunkOnFileThread, this, chunk_ptr));
}
- void Close(const base::Closure& callback) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&TracingControllerImpl::ResultFile::CloseTask,
- base::Unretained(this), callback));
+ void SetSystemTrace(const std::string& data) override {
+ system_trace_ = data;
}
- void WriteSystemTrace(
- const scoped_refptr<base::RefCountedString>& events_str_ptr) {
+ void Close() override {
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
- base::Bind(&TracingControllerImpl::ResultFile::WriteSystemTraceTask,
- base::Unretained(this), events_str_ptr));
+ base::Bind(&FileTraceDataSink::CloseOnFileThread, this));
}
- const base::FilePath& path() const { return path_; }
-
private:
- void OpenTask();
- void WriteTask(const scoped_refptr<base::RefCountedString>& events_str_ptr);
- void WriteSystemTraceTask(
- const scoped_refptr<base::RefCountedString>& events_str_ptr);
- void CloseTask(const base::Closure& callback);
+ ~FileTraceDataSink() override { DCHECK(file_ == NULL); }
+
+ void AddTraceChunkOnFileThread(
+ const scoped_refptr<base::RefCountedString> chunk) {
+ if (file_ != NULL)
+ fputc(',', file_);
+ else if (!OpenFileIfNeededOnFileThread())
+ return;
+ ignore_result(fwrite(chunk->data().c_str(), strlen(chunk->data().c_str()),
+ 1, file_));
+ }
+
+ bool OpenFileIfNeededOnFileThread() {
+ if (file_ != NULL)
+ return true;
+ file_ = base::OpenFile(file_path_, "w");
+ if (file_ == NULL) {
+ LOG(ERROR) << "Failed to open " << file_path_.value();
+ return false;
+ }
+ const char preamble[] = "{\"traceEvents\": [";
+ ignore_result(fwrite(preamble, strlen(preamble), 1, file_));
+ return true;
+ }
+
+ void CloseOnFileThread() {
+ if (OpenFileIfNeededOnFileThread()) {
+ fputc(']', file_);
+ if (!system_trace_.empty()) {
+ const char systemTraceEvents[] = ",\"systemTraceEvents\": ";
+ ignore_result(fwrite(systemTraceEvents, strlen(systemTraceEvents),
+ 1, file_));
+ ignore_result(fwrite(system_trace_.c_str(),
+ strlen(system_trace_.c_str()), 1, file_));
+ }
+ fputc('}', file_);
+ base::CloseFile(file_);
+ file_ = NULL;
+ }
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&FileTraceDataSink::FinalizeOnUIThread, this));
+ }
+ void FinalizeOnUIThread() { completion_callback_.Run(); }
+
+ base::FilePath file_path_;
+ base::Closure completion_callback_;
FILE* file_;
- base::FilePath path_;
- bool has_at_least_one_result_;
- scoped_refptr<base::RefCountedString> system_trace_;
+ std::string system_trace_;
- DISALLOW_COPY_AND_ASSIGN(ResultFile);
+ DISALLOW_COPY_AND_ASSIGN(FileTraceDataSink);
};
-TracingControllerImpl::ResultFile::ResultFile(const base::FilePath& path)
- : file_(NULL),
- path_(path),
- has_at_least_one_result_(false) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&TracingControllerImpl::ResultFile::OpenTask,
- base::Unretained(this)));
-}
-
-void TracingControllerImpl::ResultFile::OpenTask() {
- if (path_.empty())
- base::CreateTemporaryFile(&path_);
- file_ = base::OpenFile(path_, "w");
- if (!file_) {
- LOG(ERROR) << "Failed to open " << path_.value();
- return;
- }
- const char* preamble = "{\"traceEvents\": [";
- size_t written = fwrite(preamble, strlen(preamble), 1, file_);
- DCHECK(written == 1);
-}
+class StringTraceDataSink : public TracingController::TraceDataSink {
+ public:
+ typedef base::Callback<void(base::RefCountedString*)> CompletionCallback;
-void TracingControllerImpl::ResultFile::WriteTask(
- const scoped_refptr<base::RefCountedString>& events_str_ptr) {
- if (!file_ || !events_str_ptr->data().size())
- return;
+ explicit StringTraceDataSink(CompletionCallback callback)
+ : completion_callback_(callback) {}
- // If there is already a result in the file, then put a comma
- // before the next batch of results.
- if (has_at_least_one_result_) {
- size_t written = fwrite(",", 1, 1, file_);
- DCHECK(written == 1);
+ // TracingController::TraceDataSink implementation
+ void AddTraceChunk(const std::string& chunk) override {
+ if (!trace_.empty())
+ trace_ += ",";
+ trace_ += chunk;
}
- has_at_least_one_result_ = true;
- size_t written = fwrite(events_str_ptr->data().c_str(),
- events_str_ptr->data().size(), 1,
- file_);
- DCHECK(written == 1);
-}
-
-void TracingControllerImpl::ResultFile::WriteSystemTraceTask(
- const scoped_refptr<base::RefCountedString>& events_str_ptr) {
- system_trace_ = events_str_ptr;
-}
-
-void TracingControllerImpl::ResultFile::CloseTask(
- const base::Closure& callback) {
- if (!file_)
- return;
-
- const char* trailevents = "]";
- size_t written = fwrite(trailevents, strlen(trailevents), 1, file_);
- DCHECK(written == 1);
+ void SetSystemTrace(const std::string& data) override {
+ system_trace_ = data;
+ }
+ void Close() override {
+ std::string result = "{\"traceEvents\":[" + trace_ + "]";
+ if (!system_trace_.empty())
+ result += ",\"systemTraceEvents\": " + system_trace_;
+ result += "}";
- if (system_trace_) {
-#if defined(OS_WIN)
- // The Windows kernel events are kept into a JSon format stored as string
- // and must not be escaped.
- std::string json_string = system_trace_->data();
-#else
- std::string json_string = base::GetQuotedJSONString(system_trace_->data());
-#endif
+ scoped_refptr<base::RefCountedString> str =
+ base::RefCountedString::TakeString(&result);
+ completion_callback_.Run(str.get());
+ }
- const char* systemTraceHead = ",\n\"systemTraceEvents\": ";
- written = fwrite(systemTraceHead, strlen(systemTraceHead), 1, file_);
- DCHECK(written == 1);
+ private:
+ ~StringTraceDataSink() override {}
- written = fwrite(json_string.data(), json_string.size(), 1, file_);
- DCHECK(written == 1);
+ std::string trace_;
+ std::string system_trace_;
+ CompletionCallback completion_callback_;
- system_trace_ = NULL;
- }
+ DISALLOW_COPY_AND_ASSIGN(StringTraceDataSink);
+};
- const char* trailout = "}";
- written = fwrite(trailout, strlen(trailout), 1, file_);
- DCHECK(written == 1);
- base::CloseFile(file_);
- file_ = NULL;
+} // namespace
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
+TracingController* TracingController::GetInstance() {
+ return TracingControllerImpl::GetInstance();
}
-
TracingControllerImpl::TracingControllerImpl() :
pending_disable_recording_ack_count_(0),
pending_capture_monitoring_snapshot_ack_count_(0),
@@ -191,28 +193,26 @@ bool TracingControllerImpl::GetCategories(
// message. So to get known categories, just begin and end tracing immediately
// afterwards. This will ping all the child processes for categories.
pending_get_categories_done_callback_ = callback;
- if (!EnableRecording("*", TracingController::Options(),
- EnableRecordingDoneCallback())) {
+ if (!EnableRecording(
+ CategoryFilter("*"), TraceOptions(), EnableRecordingDoneCallback())) {
pending_get_categories_done_callback_.Reset();
return false;
}
- bool ok = DisableRecording(base::FilePath(), TracingFileResultCallback());
+ bool ok = DisableRecording(NULL);
DCHECK(ok);
return true;
}
void TracingControllerImpl::SetEnabledOnFileThread(
- const std::string& category_filter,
+ const CategoryFilter& category_filter,
int mode,
- int trace_options,
+ const TraceOptions& trace_options,
const base::Closure& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
TraceLog::GetInstance()->SetEnabled(
- base::debug::CategoryFilter(category_filter),
- static_cast<TraceLog::Mode>(mode),
- static_cast<TraceLog::Options>(trace_options));
+ category_filter, static_cast<TraceLog::Mode>(mode), trace_options);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
}
@@ -225,8 +225,8 @@ void TracingControllerImpl::SetDisabledOnFileThread(
}
bool TracingControllerImpl::EnableRecording(
- const std::string& category_filter,
- TracingController::Options options,
+ const CategoryFilter& category_filter,
+ const TraceOptions& trace_options,
const EnableRecordingDoneCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -239,14 +239,9 @@ bool TracingControllerImpl::EnableRecording(
TraceLog::GetInstance()->AddClockSyncMetadataEvent();
#endif
- options_ = options;
- int trace_options = (options & RECORD_CONTINUOUSLY) ?
- TraceLog::RECORD_CONTINUOUSLY : TraceLog::RECORD_UNTIL_FULL;
- if (options & ENABLE_SAMPLING) {
- trace_options |= TraceLog::ENABLE_SAMPLING;
- }
+ trace_options_ = trace_options;
- if (options & ENABLE_SYSTRACE) {
+ if (trace_options.enable_systrace) {
#if defined(OS_CHROMEOS)
DCHECK(!is_system_tracing_);
chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
@@ -275,16 +270,15 @@ bool TracingControllerImpl::EnableRecording(
}
void TracingControllerImpl::OnEnableRecordingDone(
- const std::string& category_filter,
- int trace_options,
+ const CategoryFilter& category_filter,
+ const TraceOptions& trace_options,
const EnableRecordingDoneCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Notify all child processes.
for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
it != trace_message_filters_.end(); ++it) {
- it->get()->SendBeginTracing(category_filter,
- static_cast<TraceLog::Options>(trace_options));
+ it->get()->SendBeginTracing(category_filter, trace_options);
}
if (!callback.is_null())
@@ -292,20 +286,18 @@ void TracingControllerImpl::OnEnableRecordingDone(
}
bool TracingControllerImpl::DisableRecording(
- const base::FilePath& result_file_path,
- const TracingFileResultCallback& callback) {
+ const scoped_refptr<TraceDataSink>& trace_data_sink) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!can_disable_recording())
return false;
- options_ = TracingController::Options();
+ trace_data_sink_ = trace_data_sink;
+ trace_options_ = TraceOptions();
// Disable local trace early to avoid traces during end-tracing process from
// interfering with the process.
- base::Closure on_disable_recording_done_callback =
- base::Bind(&TracingControllerImpl::OnDisableRecordingDone,
- base::Unretained(this),
- result_file_path, callback);
+ base::Closure on_disable_recording_done_callback = base::Bind(
+ &TracingControllerImpl::OnDisableRecordingDone, base::Unretained(this));
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&TracingControllerImpl::SetDisabledOnFileThread,
base::Unretained(this),
@@ -313,21 +305,14 @@ bool TracingControllerImpl::DisableRecording(
return true;
}
-void TracingControllerImpl::OnDisableRecordingDone(
- const base::FilePath& result_file_path,
- const TracingFileResultCallback& callback) {
+void TracingControllerImpl::OnDisableRecordingDone() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- pending_disable_recording_done_callback_ = callback;
-
#if defined(OS_ANDROID)
if (pending_get_categories_done_callback_.is_null())
TraceLog::GetInstance()->AddClockSyncMetadataEvent();
#endif
- if (!callback.is_null() || !result_file_path.empty())
- result_file_.reset(new ResultFile(result_file_path));
-
// Count myself (local trace) in pending_disable_recording_ack_count_,
// acked below.
pending_disable_recording_ack_count_ = trace_message_filters_.size() + 1;
@@ -340,10 +325,14 @@ void TracingControllerImpl::OnDisableRecordingDone(
++pending_disable_recording_ack_count_;
#if defined(OS_CHROMEOS)
- chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
- RequestStopSystemTracing(
- base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
- base::Unretained(this)));
+ scoped_refptr<base::TaskRunner> task_runner =
+ BrowserThread::GetBlockingPool();
+ chromeos::DBusThreadManager::Get()
+ ->GetDebugDaemonClient()
+ ->RequestStopSystemTracing(
+ task_runner,
+ base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
+ base::Unretained(this)));
#elif defined(OS_WIN)
EtwSystemEventConsumer::GetInstance()->StopSystemTracing(
base::Bind(&TracingControllerImpl::OnEndSystemTracingAcked,
@@ -370,8 +359,8 @@ void TracingControllerImpl::OnDisableRecordingDone(
}
bool TracingControllerImpl::EnableMonitoring(
- const std::string& category_filter,
- TracingController::Options options,
+ const CategoryFilter& category_filter,
+ const TraceOptions& trace_options,
const EnableMonitoringDoneCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -383,10 +372,7 @@ bool TracingControllerImpl::EnableMonitoring(
TraceLog::GetInstance()->AddClockSyncMetadataEvent();
#endif
- options_ = options;
- int trace_options = 0;
- if (options & ENABLE_SAMPLING)
- trace_options |= TraceLog::ENABLE_SAMPLING;
+ trace_options_ = trace_options;
base::Closure on_enable_monitoring_done_callback =
base::Bind(&TracingControllerImpl::OnEnableMonitoringDone,
@@ -403,16 +389,15 @@ bool TracingControllerImpl::EnableMonitoring(
}
void TracingControllerImpl::OnEnableMonitoringDone(
- const std::string& category_filter,
- int trace_options,
+ const CategoryFilter& category_filter,
+ const TraceOptions& trace_options,
const EnableMonitoringDoneCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Notify all child processes.
for (TraceMessageFilterSet::iterator it = trace_message_filters_.begin();
it != trace_message_filters_.end(); ++it) {
- it->get()->SendEnableMonitoring(category_filter,
- static_cast<TraceLog::Options>(trace_options));
+ it->get()->SendEnableMonitoring(category_filter, trace_options);
}
if (!callback.is_null())
@@ -426,7 +411,7 @@ bool TracingControllerImpl::DisableMonitoring(
if (!can_disable_monitoring())
return false;
- options_ = TracingController::Options();
+ trace_options_ = TraceOptions();
base::Closure on_disable_monitoring_done_callback =
base::Bind(&TracingControllerImpl::OnDisableMonitoringDone,
base::Unretained(this), callback);
@@ -437,6 +422,18 @@ bool TracingControllerImpl::DisableMonitoring(
return true;
}
+scoped_refptr<TracingController::TraceDataSink>
+TracingController::CreateStringSink(
+ const base::Callback<void(base::RefCountedString*)>& callback) {
+ return new StringTraceDataSink(callback);
+}
+
+scoped_refptr<TracingController::TraceDataSink>
+TracingController::CreateFileSink(const base::FilePath& file_path,
+ const base::Closure& callback) {
+ return new FileTraceDataSink(file_path, callback);
+}
+
void TracingControllerImpl::OnDisableMonitoringDone(
const DisableMonitoringDoneCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -448,34 +445,30 @@ void TracingControllerImpl::OnDisableMonitoringDone(
it != trace_message_filters_.end(); ++it) {
it->get()->SendDisableMonitoring();
}
-
if (!callback.is_null())
callback.Run();
}
void TracingControllerImpl::GetMonitoringStatus(
bool* out_enabled,
- std::string* out_category_filter,
- TracingController::Options* out_options) {
+ CategoryFilter* out_category_filter,
+ TraceOptions* out_trace_options) {
*out_enabled = is_monitoring_;
- *out_category_filter =
- TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString();
- *out_options = options_;
+ *out_category_filter = TraceLog::GetInstance()->GetCurrentCategoryFilter();
+ *out_trace_options = trace_options_;
}
bool TracingControllerImpl::CaptureMonitoringSnapshot(
- const base::FilePath& result_file_path,
- const TracingFileResultCallback& callback) {
+ const scoped_refptr<TraceDataSink>& monitoring_data_sink) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!can_disable_monitoring())
return false;
- if (callback.is_null() && result_file_path.empty())
+ if (!monitoring_data_sink.get())
return false;
- pending_capture_monitoring_snapshot_done_callback_ = callback;
- monitoring_snapshot_file_.reset(new ResultFile(result_file_path));
+ monitoring_data_sink_ = monitoring_data_sink;
// Count myself in pending_capture_monitoring_snapshot_ack_count_,
// acked below.
@@ -595,13 +588,13 @@ void TracingControllerImpl::AddTraceMessageFilter(
}
if (can_disable_recording()) {
trace_message_filter->SendBeginTracing(
- TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(),
- TraceLog::GetInstance()->trace_options());
+ TraceLog::GetInstance()->GetCurrentCategoryFilter(),
+ TraceLog::GetInstance()->GetCurrentTraceOptions());
}
if (can_disable_monitoring()) {
trace_message_filter->SendEnableMonitoring(
- TraceLog::GetInstance()->GetCurrentCategoryFilter().ToString(),
- TraceLog::GetInstance()->trace_options());
+ TraceLog::GetInstance()->GetCurrentCategoryFilter(),
+ TraceLog::GetInstance()->GetCurrentTraceOptions());
}
}
@@ -692,10 +685,6 @@ void TracingControllerImpl::OnDisableRecordingAcked(
if (pending_disable_recording_ack_count_ != 0)
return;
- OnDisableRecordingComplete();
-}
-
-void TracingControllerImpl::OnDisableRecordingComplete() {
// All acks (including from the subprocesses and the local trace) have been
// received.
is_recording_ = false;
@@ -704,34 +693,28 @@ void TracingControllerImpl::OnDisableRecordingComplete() {
if (!pending_get_categories_done_callback_.is_null()) {
pending_get_categories_done_callback_.Run(known_category_groups_);
pending_get_categories_done_callback_.Reset();
- } else if (result_file_) {
- result_file_->Close(
- base::Bind(&TracingControllerImpl::OnResultFileClosed,
- base::Unretained(this)));
+ } else if (trace_data_sink_.get()) {
+ trace_data_sink_->Close();
+ trace_data_sink_ = NULL;
}
}
-void TracingControllerImpl::OnResultFileClosed() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (!result_file_)
- return;
-
- if (!pending_disable_recording_done_callback_.is_null()) {
- pending_disable_recording_done_callback_.Run(result_file_->path());
- pending_disable_recording_done_callback_.Reset();
- }
- result_file_.reset();
-}
-
#if defined(OS_CHROMEOS) || defined(OS_WIN)
void TracingControllerImpl::OnEndSystemTracingAcked(
const scoped_refptr<base::RefCountedString>& events_str_ptr) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (result_file_)
- result_file_->WriteSystemTrace(events_str_ptr);
-
+ if (trace_data_sink_.get()) {
+#if defined(OS_WIN)
+ // The Windows kernel events are kept into a JSon format stored as string
+ // and must not be escaped.
+ std::string json_string = events_str_ptr->data();
+#else
+ std::string json_string =
+ base::GetQuotedJSONString(events_str_ptr->data());
+#endif
+ trace_data_sink_->SetSystemTrace(json_string);
+ }
DCHECK(!is_system_tracing_);
std::vector<std::string> category_groups;
OnDisableRecordingAcked(NULL, category_groups);
@@ -770,25 +753,10 @@ void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked(
if (pending_capture_monitoring_snapshot_ack_count_ != 0)
return;
- if (monitoring_snapshot_file_) {
- monitoring_snapshot_file_->Close(
- base::Bind(&TracingControllerImpl::OnMonitoringSnapshotFileClosed,
- base::Unretained(this)));
- }
-}
-
-void TracingControllerImpl::OnMonitoringSnapshotFileClosed() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- if (!monitoring_snapshot_file_)
- return;
-
- if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) {
- pending_capture_monitoring_snapshot_done_callback_.Run(
- monitoring_snapshot_file_->path());
- pending_capture_monitoring_snapshot_done_callback_.Reset();
+ if (monitoring_data_sink_.get()) {
+ monitoring_data_sink_->Close();
+ monitoring_data_sink_ = NULL;
}
- monitoring_snapshot_file_.reset();
}
void TracingControllerImpl::OnTraceDataCollected(
@@ -802,8 +770,8 @@ void TracingControllerImpl::OnTraceDataCollected(
return;
}
- if (result_file_)
- result_file_->Write(events_str_ptr);
+ if (trace_data_sink_.get())
+ trace_data_sink_->AddTraceChunk(events_str_ptr->data());
}
void TracingControllerImpl::OnMonitoringTraceDataCollected(
@@ -815,8 +783,8 @@ void TracingControllerImpl::OnMonitoringTraceDataCollected(
return;
}
- if (monitoring_snapshot_file_)
- monitoring_snapshot_file_->Write(events_str_ptr);
+ if (monitoring_data_sink_.get())
+ monitoring_data_sink_->AddTraceChunk(events_str_ptr->data());
}
void TracingControllerImpl::OnLocalTraceDataCollected(
diff --git a/chromium/content/browser/tracing/tracing_controller_impl.h b/chromium/content/browser/tracing/tracing_controller_impl.h
index d4d5722d85b..9bd84200d45 100644
--- a/chromium/content/browser/tracing/tracing_controller_impl.h
+++ b/chromium/content/browser/tracing/tracing_controller_impl.h
@@ -9,12 +9,12 @@
#include <string>
#include <vector>
-#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "content/public/browser/tracing_controller.h"
namespace base {
class RefCountedString;
+class RefCountedMemory;
}
namespace content {
@@ -27,53 +27,47 @@ class TracingControllerImpl : public TracingController {
static TracingControllerImpl* GetInstance();
// TracingController implementation.
- virtual bool GetCategories(
- const GetCategoriesDoneCallback& callback) OVERRIDE;
- virtual bool EnableRecording(
- const std::string& category_filter,
- TracingController::Options options,
- const EnableRecordingDoneCallback& callback) OVERRIDE;
- virtual bool DisableRecording(
- const base::FilePath& result_file_path,
- const TracingFileResultCallback& callback) OVERRIDE;
- virtual bool EnableMonitoring(const std::string& category_filter,
- TracingController::Options options,
- const EnableMonitoringDoneCallback& callback) OVERRIDE;
- virtual bool DisableMonitoring(
- const DisableMonitoringDoneCallback& callback) OVERRIDE;
- virtual void GetMonitoringStatus(
+ bool GetCategories(const GetCategoriesDoneCallback& callback) override;
+ bool EnableRecording(const base::debug::CategoryFilter& category_filter,
+ const base::debug::TraceOptions& trace_options,
+ const EnableRecordingDoneCallback& callback) override;
+ bool DisableRecording(const scoped_refptr<TraceDataSink>& sink) override;
+ bool EnableMonitoring(const base::debug::CategoryFilter& category_filter,
+ const base::debug::TraceOptions& trace_options,
+ const EnableMonitoringDoneCallback& callback) override;
+ bool DisableMonitoring(
+ const DisableMonitoringDoneCallback& callback) override;
+ void GetMonitoringStatus(
bool* out_enabled,
- std::string* out_category_filter,
- TracingController::Options* out_options) OVERRIDE;
- virtual bool CaptureMonitoringSnapshot(
- const base::FilePath& result_file_path,
- const TracingFileResultCallback& callback) OVERRIDE;
- virtual bool GetTraceBufferPercentFull(
- const GetTraceBufferPercentFullCallback& callback) OVERRIDE;
- virtual bool SetWatchEvent(const std::string& category_name,
- const std::string& event_name,
- const WatchEventCallback& callback) OVERRIDE;
- virtual bool CancelWatchEvent() OVERRIDE;
+ base::debug::CategoryFilter* out_category_filter,
+ base::debug::TraceOptions* out_trace_options) override;
+ bool CaptureMonitoringSnapshot(
+ const scoped_refptr<TraceDataSink>& sink) override;
+ bool GetTraceBufferPercentFull(
+ const GetTraceBufferPercentFullCallback& callback) override;
+ bool SetWatchEvent(const std::string& category_name,
+ const std::string& event_name,
+ const WatchEventCallback& callback) override;
+ bool CancelWatchEvent() override;
void RegisterTracingUI(TracingUI* tracing_ui);
void UnregisterTracingUI(TracingUI* tracing_ui);
private:
typedef std::set<scoped_refptr<TraceMessageFilter> > TraceMessageFilterSet;
- class ResultFile;
friend struct base::DefaultLazyInstanceTraits<TracingControllerImpl>;
friend class TraceMessageFilter;
TracingControllerImpl();
- virtual ~TracingControllerImpl();
+ ~TracingControllerImpl() override;
bool can_enable_recording() const {
return !is_recording_;
}
bool can_disable_recording() const {
- return is_recording_ && !result_file_;
+ return is_recording_ && !trace_data_sink_.get();
}
bool can_enable_monitoring() const {
@@ -81,7 +75,7 @@ class TracingControllerImpl : public TracingController {
}
bool can_disable_monitoring() const {
- return is_monitoring_ && !monitoring_snapshot_file_;
+ return is_monitoring_ && !monitoring_data_sink_.get();
}
bool can_get_trace_buffer_percent_full() const {
@@ -113,8 +107,6 @@ class TracingControllerImpl : public TracingController {
void OnDisableRecordingAcked(
TraceMessageFilter* trace_message_filter,
const std::vector<std::string>& known_category_groups);
- void OnDisableRecordingComplete();
- void OnResultFileClosed();
#if defined(OS_CHROMEOS) || defined(OS_WIN)
void OnEndSystemTracingAcked(
@@ -123,7 +115,6 @@ class TracingControllerImpl : public TracingController {
void OnCaptureMonitoringSnapshotAcked(
TraceMessageFilter* trace_message_filter);
- void OnMonitoringSnapshotFileClosed();
void OnTraceBufferPercentFullReply(
TraceMessageFilter* trace_message_filter,
@@ -131,19 +122,20 @@ class TracingControllerImpl : public TracingController {
void OnWatchEventMatched();
- void SetEnabledOnFileThread(const std::string& category_filter,
- int mode,
- int options,
- const base::Closure& callback);
+ void SetEnabledOnFileThread(
+ const base::debug::CategoryFilter& category_filter,
+ int mode,
+ const base::debug::TraceOptions& trace_options,
+ const base::Closure& callback);
void SetDisabledOnFileThread(const base::Closure& callback);
- void OnEnableRecordingDone(const std::string& category_filter,
- int trace_options,
+ void OnEnableRecordingDone(const base::debug::CategoryFilter& category_filter,
+ const base::debug::TraceOptions& trace_options,
const EnableRecordingDoneCallback& callback);
- void OnDisableRecordingDone(const base::FilePath& result_file_path,
- const TracingFileResultCallback& callback);
- void OnEnableMonitoringDone(const std::string& category_filter,
- int trace_options,
- const EnableMonitoringDoneCallback& callback);
+ void OnDisableRecordingDone();
+ void OnEnableMonitoringDone(
+ const base::debug::CategoryFilter& category_filter,
+ const base::debug::TraceOptions& trace_options,
+ const EnableMonitoringDoneCallback& callback);
void OnDisableMonitoringDone(const DisableMonitoringDoneCallback& callback);
void OnMonitoringStateChanged(bool is_monitoring);
@@ -166,11 +158,9 @@ class TracingControllerImpl : public TracingController {
#endif
bool is_recording_;
bool is_monitoring_;
- TracingController::Options options_;
+ base::debug::TraceOptions trace_options_;
GetCategoriesDoneCallback pending_get_categories_done_callback_;
- TracingFileResultCallback pending_disable_recording_done_callback_;
- TracingFileResultCallback pending_capture_monitoring_snapshot_done_callback_;
GetTraceBufferPercentFullCallback pending_trace_buffer_percent_full_callback_;
std::string watch_category_name_;
@@ -179,8 +169,8 @@ class TracingControllerImpl : public TracingController {
std::set<std::string> known_category_groups_;
std::set<TracingUI*> tracing_uis_;
- scoped_ptr<ResultFile> result_file_;
- scoped_ptr<ResultFile> monitoring_snapshot_file_;
+ scoped_refptr<TraceDataSink> trace_data_sink_;
+ scoped_refptr<TraceDataSink> monitoring_data_sink_;
DISALLOW_COPY_AND_ASSIGN(TracingControllerImpl);
};
diff --git a/chromium/content/browser/tracing/tracing_resources.gyp b/chromium/content/browser/tracing/tracing_resources.gyp
index 7ad5b9652cb..1efc0ad72c6 100644
--- a/chromium/content/browser/tracing/tracing_resources.gyp
+++ b/chromium/content/browser/tracing/tracing_resources.gyp
@@ -9,6 +9,7 @@
},
'targets': [
{
+ # GN version: //content/browser/tracing:generate_tracing_grd
'target_name': 'generate_tracing_grd',
'type': 'none',
'dependencies': [
@@ -37,6 +38,7 @@
},
{
+ # GN version: //content/browser/tracing:resources
'target_name': 'tracing_resources',
'type': 'none',
'dependencies': [
diff --git a/chromium/content/browser/tracing/tracing_ui.cc b/chromium/content/browser/tracing/tracing_ui.cc
index 9f3175366eb..95e3ab92cde 100644
--- a/chromium/content/browser/tracing/tracing_ui.cc
+++ b/chromium/content/browser/tracing/tracing_ui.cc
@@ -4,33 +4,44 @@
#include "content/browser/tracing/tracing_ui.h"
+#include <set>
#include <string>
+#include <vector>
#include "base/base64.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/file_util.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/format_macros.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "content/browser/tracing/grit/tracing_resources.h"
+#include "content/browser/tracing/trace_uploader.h"
#include "content/browser/tracing/tracing_controller_impl.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/tracing_controller.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/content_client.h"
+#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
namespace content {
namespace {
+const char kUploadURL[] = "https://clients2.google.com/cr/staging_report";
+
void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
const std::set<std::string>& categorySet) {
-
scoped_ptr<base::ListValue> category_list(new base::ListValue());
for (std::set<std::string>::const_iterator it = categorySet.begin();
it != categorySet.end(); it++) {
@@ -43,8 +54,8 @@ void OnGotCategories(const WebUIDataSource::GotDataCallback& callback,
}
bool GetTracingOptions(const std::string& data64,
- std::string* category_filter_string,
- int* tracing_options) {
+ base::debug::CategoryFilter* category_filter,
+ base::debug::TraceOptions* tracing_options) {
std::string data;
if (!base::Base64Decode(data64, &data)) {
LOG(ERROR) << "Options were not base64 encoded.";
@@ -62,28 +73,39 @@ bool GetTracingOptions(const std::string& data64,
return false;
}
- bool use_system_tracing;
- bool use_continuous_tracing;
- bool use_sampling;
+ if (!category_filter) {
+ LOG(ERROR) << "category_filter can't be passed as NULL";
+ return false;
+ }
+
+ if (!tracing_options) {
+ LOG(ERROR) << "tracing_options can't be passed as NULL";
+ return false;
+ }
bool options_ok = true;
- options_ok &= options->GetString("categoryFilter", category_filter_string);
- options_ok &= options->GetBoolean("useSystemTracing", &use_system_tracing);
- options_ok &= options->GetBoolean("useContinuousTracing",
- &use_continuous_tracing);
- options_ok &= options->GetBoolean("useSampling", &use_sampling);
+ std::string category_filter_string;
+ options_ok &= options->GetString("categoryFilter", &category_filter_string);
+ *category_filter = base::debug::CategoryFilter(category_filter_string);
+
+ options_ok &= options->GetBoolean("useSystemTracing",
+ &tracing_options->enable_systrace);
+ options_ok &=
+ options->GetBoolean("useSampling", &tracing_options->enable_sampling);
+
+ bool use_continuous_tracing;
+ options_ok &=
+ options->GetBoolean("useContinuousTracing", &use_continuous_tracing);
+
+ if (use_continuous_tracing)
+ tracing_options->record_mode = base::debug::RECORD_CONTINUOUSLY;
+ else
+ tracing_options->record_mode = base::debug::RECORD_UNTIL_FULL;
+
if (!options_ok) {
LOG(ERROR) << "Malformed options";
return false;
}
-
- *tracing_options = 0;
- if (use_system_tracing)
- *tracing_options |= TracingController::ENABLE_SYSTRACE;
- if (use_sampling)
- *tracing_options |= TracingController::ENABLE_SAMPLING;
- if (use_continuous_tracing)
- *tracing_options |= TracingController::RECORD_CONTINUOUSLY;
return true;
}
@@ -91,14 +113,14 @@ void OnRecordingEnabledAck(const WebUIDataSource::GotDataCallback& callback);
bool BeginRecording(const std::string& data64,
const WebUIDataSource::GotDataCallback& callback) {
- std::string category_filter_string;
- int tracing_options = 0;
- if (!GetTracingOptions(data64, &category_filter_string, &tracing_options))
+ base::debug::CategoryFilter category_filter("");
+ base::debug::TraceOptions tracing_options;
+ if (!GetTracingOptions(data64, &category_filter, &tracing_options))
return false;
return TracingController::GetInstance()->EnableRecording(
- category_filter_string,
- static_cast<TracingController::Options>(tracing_options),
+ category_filter,
+ tracing_options,
base::Bind(&OnRecordingEnabledAck, callback));
}
@@ -113,35 +135,18 @@ void OnTraceBufferPercentFullResult(
callback.Run(base::RefCountedString::TakeString(&str));
}
-void ReadRecordingResult(const WebUIDataSource::GotDataCallback& callback,
- const base::FilePath& path) {
- std::string tmp;
- if (!base::ReadFileToString(path, &tmp))
- LOG(ERROR) << "Failed to read file " << path.value();
- base::DeleteFile(path, false);
- callback.Run(base::RefCountedString::TakeString(&tmp));
-}
-
-void BeginReadingRecordingResult(
- const WebUIDataSource::GotDataCallback& callback,
- const base::FilePath& path) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(ReadRecordingResult, callback, path));
-}
-
void OnMonitoringEnabledAck(const WebUIDataSource::GotDataCallback& callback);
bool EnableMonitoring(const std::string& data64,
const WebUIDataSource::GotDataCallback& callback) {
- std::string category_filter_string;
- int tracing_options = 0;
- if (!GetTracingOptions(data64, &category_filter_string, &tracing_options))
+ base::debug::TraceOptions tracing_options;
+ base::debug::CategoryFilter category_filter("");
+ if (!GetTracingOptions(data64, &category_filter, &tracing_options))
return false;
return TracingController::GetInstance()->EnableMonitoring(
- category_filter_string,
- static_cast<TracingController::Options>(tracing_options),
+ category_filter,
+ tracing_options,
base::Bind(OnMonitoringEnabledAck, callback));
}
@@ -157,21 +162,20 @@ void OnMonitoringDisabled(const WebUIDataSource::GotDataCallback& callback) {
void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
bool is_monitoring;
- std::string category_filter;
- TracingController::Options options;
+ base::debug::CategoryFilter category_filter("");
+ base::debug::TraceOptions options;
TracingController::GetInstance()->GetMonitoringStatus(
&is_monitoring, &category_filter, &options);
scoped_ptr<base::DictionaryValue>
monitoring_options(new base::DictionaryValue());
monitoring_options->SetBoolean("isMonitoring", is_monitoring);
- monitoring_options->SetString("categoryFilter", category_filter);
- monitoring_options->SetBoolean("useSystemTracing",
- (options & TracingController::ENABLE_SYSTRACE) != 0);
- monitoring_options->SetBoolean("useContinuousTracing",
- (options & TracingController::RECORD_CONTINUOUSLY) != 0);
- monitoring_options->SetBoolean("useSampling",
- (options & TracingController::ENABLE_SAMPLING) != 0);
+ monitoring_options->SetString("categoryFilter", category_filter.ToString());
+ monitoring_options->SetBoolean("useSystemTracing", options.enable_systrace);
+ monitoring_options->SetBoolean(
+ "useContinuousTracing",
+ options.record_mode == base::debug::RECORD_CONTINUOUSLY);
+ monitoring_options->SetBoolean("useSampling", options.enable_sampling);
std::string monitoring_options_json;
base::JSONWriter::Write(monitoring_options.get(), &monitoring_options_json);
@@ -183,21 +187,9 @@ void GetMonitoringStatus(const WebUIDataSource::GotDataCallback& callback) {
callback.Run(monitoring_options_base64);
}
-void ReadMonitoringSnapshot(const WebUIDataSource::GotDataCallback& callback,
- const base::FilePath& path) {
- std::string tmp;
- if (!base::ReadFileToString(path, &tmp))
- LOG(ERROR) << "Failed to read file " << path.value();
- base::DeleteFile(path, false);
- callback.Run(base::RefCountedString::TakeString(&tmp));
-}
-
-void OnMonitoringSnapshotCaptured(
- const WebUIDataSource::GotDataCallback& callback,
- const base::FilePath& path) {
- BrowserThread::PostTask(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(ReadMonitoringSnapshot, callback, path));
+void TracingCallbackWrapper(const WebUIDataSource::GotDataCallback& callback,
+ base::RefCountedString* data) {
+ callback.Run(data);
}
bool OnBeginJSONRequest(const std::string& path,
@@ -218,7 +210,8 @@ bool OnBeginJSONRequest(const std::string& path,
}
if (path == "json/end_recording") {
return TracingController::GetInstance()->DisableRecording(
- base::FilePath(), base::Bind(BeginReadingRecordingResult, callback));
+ TracingControllerImpl::CreateStringSink(
+ base::Bind(TracingCallbackWrapper, callback)));
}
const char* enableMonitoringPath = "json/begin_monitoring?";
@@ -232,7 +225,8 @@ bool OnBeginJSONRequest(const std::string& path,
}
if (path == "json/capture_monitoring") {
TracingController::GetInstance()->CaptureMonitoringSnapshot(
- base::FilePath(), base::Bind(OnMonitoringSnapshotCaptured, callback));
+ TracingControllerImpl::CreateStringSink(
+ base::Bind(TracingCallbackWrapper, callback)));
return true;
}
if (path == "json/get_monitoring_status") {
@@ -265,7 +259,13 @@ bool OnTracingRequest(const std::string& path,
//
////////////////////////////////////////////////////////////////////////////////
-TracingUI::TracingUI(WebUI* web_ui) : WebUIController(web_ui) {
+TracingUI::TracingUI(WebUI* web_ui)
+ : WebUIController(web_ui),
+ weak_factory_(this) {
+ web_ui->RegisterMessageCallback(
+ "doUpload",
+ base::Bind(&TracingUI::DoUpload, base::Unretained(this)));
+
// Set up the chrome://tracing/ source.
BrowserContext* browser_context =
web_ui->GetWebContents()->GetBrowserContext();
@@ -288,4 +288,99 @@ void TracingUI::OnMonitoringStateChanged(bool is_monitoring) {
"onMonitoringStateChanged", base::FundamentalValue(is_monitoring));
}
+void TracingUI::DoUpload(const base::ListValue* args) {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ std::string upload_url = kUploadURL;
+ if (command_line.HasSwitch(switches::kTraceUploadURL)) {
+ upload_url =
+ command_line.GetSwitchValueASCII(switches::kTraceUploadURL);
+ }
+ if (!GURL(upload_url).is_valid()) {
+ upload_url.clear();
+ }
+
+ if (upload_url.empty()) {
+ web_ui()->CallJavascriptFunction("onUploadError",
+ base::StringValue("Upload URL empty or invalid"));
+ return;
+ }
+
+ std::string file_contents;
+ if (!args || args->empty() || !args->GetString(0, &file_contents)) {
+ web_ui()->CallJavascriptFunction("onUploadError",
+ base::StringValue("Missing data"));
+ return;
+ }
+
+ TraceUploader::UploadProgressCallback progress_callback =
+ base::Bind(&TracingUI::OnTraceUploadProgress,
+ weak_factory_.GetWeakPtr());
+ TraceUploader::UploadDoneCallback done_callback =
+ base::Bind(&TracingUI::OnTraceUploadComplete,
+ weak_factory_.GetWeakPtr());
+
+#if defined(OS_WIN)
+ const char product[] = "Chrome";
+#elif defined(OS_MACOSX)
+ const char product[] = "Chrome_Mac";
+#elif defined(OS_LINUX)
+ const char product[] = "Chrome_Linux";
+#elif defined(OS_ANDROID)
+ const char product[] = "Chrome_Android";
+#elif defined(OS_CHROMEOS)
+ const char product[] = "Chrome_ChromeOS";
+#else
+#error Platform not supported.
+#endif
+
+ // GetProduct() returns a string like "Chrome/aa.bb.cc.dd", split out
+ // the part before the "/".
+ std::vector<std::string> product_components;
+ base::SplitString(content::GetContentClient()->GetProduct(), '/',
+ &product_components);
+ DCHECK_EQ(2U, product_components.size());
+ std::string version;
+ if (product_components.size() == 2U) {
+ version = product_components[1];
+ } else {
+ version = "unknown";
+ }
+
+ BrowserContext* browser_context =
+ web_ui()->GetWebContents()->GetBrowserContext();
+ TraceUploader* uploader = new TraceUploader(
+ product, version, upload_url, browser_context->GetRequestContext());
+
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
+ &TraceUploader::DoUpload,
+ base::Unretained(uploader),
+ file_contents,
+ progress_callback,
+ done_callback));
+ // TODO(mmandlis): Add support for stopping the upload in progress.
+}
+
+void TracingUI::OnTraceUploadProgress(int64 current, int64 total) {
+ DCHECK(current <= total);
+ int percent = (current / total) * 100;
+ web_ui()->CallJavascriptFunction(
+ "onUploadProgress",
+ base::FundamentalValue(percent),
+ base::StringValue(base::StringPrintf("%" PRId64, current)),
+ base::StringValue(base::StringPrintf("%" PRId64, total)));
+}
+
+void TracingUI::OnTraceUploadComplete(bool success,
+ const std::string& report_id,
+ const std::string& error_message) {
+ if (success) {
+ web_ui()->CallJavascriptFunction("onUploadComplete",
+ base::StringValue(report_id));
+ } else {
+ web_ui()->CallJavascriptFunction("onUploadError",
+ base::StringValue(error_message));
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/tracing/tracing_ui.h b/chromium/content/browser/tracing/tracing_ui.h
index 40ce0821e2d..7b69337c091 100644
--- a/chromium/content/browser/tracing/tracing_ui.h
+++ b/chromium/content/browser/tracing/tracing_ui.h
@@ -5,6 +5,10 @@
#ifndef CONTENT_BROWSER_TRACING_UI_H_
#define CONTENT_BROWSER_TRACING_UI_H_
+#include <map>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_ui_controller.h"
namespace content {
@@ -13,10 +17,17 @@ namespace content {
class CONTENT_EXPORT TracingUI : public WebUIController {
public:
explicit TracingUI(WebUI* web_ui);
- virtual ~TracingUI();
+ ~TracingUI() override;
void OnMonitoringStateChanged(bool is_monitoring);
+ void DoUpload(const base::ListValue* args);
+ void OnTraceUploadProgress(int64 current, int64 total);
+ void OnTraceUploadComplete(bool success,
+ const std::string& report_id,
+ const std::string& error_message);
private:
+ base::WeakPtrFactory<TracingUI> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(TracingUI);
};
diff --git a/chromium/content/browser/transition_browsertest.cc b/chromium/content/browser/transition_browsertest.cc
new file mode 100644
index 00000000000..1fba073174c
--- /dev/null
+++ b/chromium/content/browser/transition_browsertest.cc
@@ -0,0 +1,191 @@
+// 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 "base/bind.h"
+#include "base/command_line.h"
+#include "content/browser/loader/cross_site_resource_handler.h"
+#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/loader/resource_request_info_impl.h"
+#include "content/browser/transition_request_manager.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/web_contents_observer.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 "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/url_request/url_request.h"
+
+namespace content {
+
+class TransitionBrowserTest : public ContentBrowserTest {
+ public:
+ TransitionBrowserTest() {}
+
+ void SetUpCommandLine(CommandLine* command_line) override {
+ command_line->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransitionBrowserTest);
+};
+
+class TransitionBrowserTestObserver
+ : public WebContentsObserver,
+ public ShellResourceDispatcherHostDelegate {
+ public:
+ TransitionBrowserTestObserver(WebContents* web_contents)
+ : WebContentsObserver(web_contents),
+ request_(NULL),
+ did_defer_response_(false),
+ is_transition_request_(false),
+ did_clear_data_(false) {
+ }
+
+ void RequestBeginning(net::URLRequest* request,
+ ResourceContext* resource_context,
+ AppCacheService* appcache_service,
+ ResourceType resource_type,
+ ScopedVector<ResourceThrottle>* throttles) override {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ShellResourceDispatcherHostDelegate::RequestBeginning(request,
+ resource_context,
+ appcache_service,
+ resource_type,
+ throttles);
+ request_ = request;
+
+ ResourceRequestInfoImpl* info =
+ ResourceRequestInfoImpl::ForRequest(request_);
+
+ if (is_transition_request_) {
+ TransitionRequestManager::GetInstance(
+ )->AddPendingTransitionRequestDataForTesting(
+ info->GetChildID(), info->GetRenderFrameID());
+ }
+ }
+
+ void OnResponseStarted(net::URLRequest* request,
+ ResourceContext* resource_context,
+ ResourceResponse* response,
+ IPC::Sender* sender) override {
+ ResourceRequestInfoImpl* info =
+ ResourceRequestInfoImpl::ForRequest(request_);
+
+ did_defer_response_ = info->cross_site_handler()->did_defer_for_testing();
+ }
+
+ void RequestComplete(net::URLRequest* url_request) override {
+ if (is_transition_request_) {
+ ResourceRequestInfoImpl* info =
+ ResourceRequestInfoImpl::ForRequest(request_);
+ TransitionLayerData transition_data;
+ did_clear_data_ = !TransitionRequestManager::GetInstance(
+ )->GetPendingTransitionRequest(info->GetChildID(),
+ info->GetRenderFrameID(),
+ request_->url(),
+ &transition_data);
+ }
+ }
+
+ void set_pending_transition_request(bool is_transition_request) {
+ is_transition_request_ = is_transition_request;
+ }
+
+ bool did_defer_response() const { return did_defer_response_; }
+ bool did_clear_data() const { return did_clear_data_; }
+
+ private:
+ net::URLRequest* request_;
+ bool did_defer_response_;
+ bool is_transition_request_;
+ bool did_clear_data_;
+};
+
+// This tests that normal navigations don't defer at first response.
+IN_PROC_BROWSER_TEST_F(TransitionBrowserTest,
+ NormalNavigationNotDeferred) {
+ // This test shouldn't run in --site-per-process mode, where normal
+ // navigations are also deferred.
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kSitePerProcess))
+ return;
+
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ scoped_ptr<TransitionBrowserTestObserver> observer(
+ new TransitionBrowserTestObserver(shell()->web_contents()));
+
+ ResourceDispatcherHost::Get()->SetDelegate(observer.get());
+
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+
+ EXPECT_FALSE(observer->did_defer_response());
+}
+
+// This tests that when a navigation transition is detected, the response is
+// deferred.
+IN_PROC_BROWSER_TEST_F(TransitionBrowserTest,
+ TransitionNavigationIsDeferred) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ scoped_ptr<TransitionBrowserTestObserver> observer(
+ new TransitionBrowserTestObserver(shell()->web_contents()));
+
+ ResourceDispatcherHost::Get()->SetDelegate(observer.get());
+ observer->set_pending_transition_request(true);
+
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+
+ EXPECT_TRUE(observer->did_defer_response());
+}
+
+// This tests that the renderer is reused between the outgoing and transition.
+IN_PROC_BROWSER_TEST_F(TransitionBrowserTest,
+ TransitionNavigationSharesRenderer) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+
+ int outgoing_process_id =
+ shell()->web_contents()->GetRenderProcessHost()->GetID();
+
+ WebContents::CreateParams create_params(
+ shell()->web_contents()->GetBrowserContext(),
+ shell()->web_contents()->GetSiteInstance());
+ scoped_ptr<WebContents> transition_web_contents(
+ WebContents::Create(create_params));
+
+ GURL about_blank(url::kAboutBlankURL);
+ NavigationController::LoadURLParams params(about_blank);
+ transition_web_contents->GetController().LoadURLWithParams(params);
+ transition_web_contents->Focus();
+
+ WaitForLoadStop(transition_web_contents.get());
+
+ int transition_process_id =
+ transition_web_contents->GetRenderProcessHost()->GetID();
+
+ EXPECT_EQ(outgoing_process_id, transition_process_id);
+}
+
+// This tests that the transition data is cleared after the transition.
+IN_PROC_BROWSER_TEST_F(TransitionBrowserTest,
+ TransitionNavigationDataIsCleared) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ scoped_ptr<TransitionBrowserTestObserver> observer(
+ new TransitionBrowserTestObserver(shell()->web_contents()));
+
+ ResourceDispatcherHost::Get()->SetDelegate(observer.get());
+ observer->set_pending_transition_request(true);
+
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+ WaitForLoadStop(shell()->web_contents());
+
+ EXPECT_TRUE(observer->did_clear_data());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/transition_request_manager.cc b/chromium/content/browser/transition_request_manager.cc
new file mode 100644
index 00000000000..e3f4317695f
--- /dev/null
+++ b/chromium/content/browser/transition_request_manager.cc
@@ -0,0 +1,215 @@
+// 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/transition_request_manager.h"
+
+#include "base/command_line.h"
+#include "base/memory/singleton.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_switches.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+
+namespace {
+
+// Enumerate all Link: headers with the specified relation in this
+// response, and optionally returns the URL and any additional attributes of
+// each one. See EnumerateHeaders for |iter| usage.
+bool EnumerateLinkHeaders(
+ const scoped_refptr<net::HttpResponseHeaders>& headers,
+ void** iter,
+ const std::string& rel,
+ std::string* url,
+ base::StringPairs* attributes) {
+ std::string header_body;
+ bool rel_matched = false;
+ while (!rel_matched && headers->EnumerateHeader(iter, "link", &header_body)) {
+ const std::string::const_iterator begin = header_body.begin();
+ size_t url_start = header_body.find_first_of('<');
+ size_t url_end = header_body.find_first_of('>');
+ if (url_start == std::string::npos || url_end == std::string::npos ||
+ url_start > url_end) {
+ break;
+ }
+
+ if (attributes)
+ attributes->clear();
+
+ net::HttpUtil::NameValuePairsIterator param_iter(
+ begin + url_end + 1, header_body.end(), ';');
+
+ while (param_iter.GetNext()) {
+ if (LowerCaseEqualsASCII(
+ param_iter.name_begin(), param_iter.name_end(), "rel")) {
+ if (LowerCaseEqualsASCII(param_iter.value_begin(),
+ param_iter.value_end(),
+ rel.c_str())) {
+ if (url) {
+ url->assign(begin + url_start + 1, begin + url_end);
+ }
+ rel_matched = true;
+ } else {
+ break;
+ }
+ } else if (attributes) {
+ std::string attribute_name(param_iter.name_begin(),
+ param_iter.name_end());
+ std::string attribute_value(param_iter.value_begin(),
+ param_iter.value_end());
+ attributes->push_back(std::make_pair(attribute_name, attribute_value));
+ }
+ }
+ }
+
+ if (!rel_matched && attributes) {
+ attributes->clear();
+ }
+
+ return rel_matched;
+}
+
+} // namespace
+
+namespace content {
+
+TransitionLayerData::TransitionLayerData() {
+}
+
+TransitionLayerData::~TransitionLayerData() {
+}
+
+TransitionRequestManager::TransitionRequestData::AllowedEntry::AllowedEntry(
+ const std::string& allowed_destination_host_pattern,
+ const std::string& css_selector,
+ const std::string& markup,
+ const std::vector<TransitionElement>& elements)
+ : allowed_destination_host_pattern(allowed_destination_host_pattern),
+ css_selector(css_selector),
+ markup(markup),
+ elements(elements) {
+}
+
+TransitionRequestManager::TransitionRequestData::AllowedEntry::~AllowedEntry() {
+}
+
+void TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
+ const scoped_refptr<net::HttpResponseHeaders>& headers,
+ std::vector<GURL>& entering_stylesheets,
+ const GURL& resolve_address) {
+ if (headers.get() == NULL)
+ return;
+
+ std::string transition_stylesheet;
+ base::StringPairs attributes;
+ void* header_iter = NULL;
+ while (EnumerateLinkHeaders(headers,
+ &header_iter,
+ "transition-entering-stylesheet",
+ &transition_stylesheet,
+ &attributes)) {
+ GURL stylesheet_url = resolve_address.Resolve(transition_stylesheet);
+ if (stylesheet_url.is_valid())
+ entering_stylesheets.push_back(stylesheet_url);
+ }
+}
+
+TransitionRequestManager::TransitionRequestData::TransitionRequestData() {
+}
+
+TransitionRequestManager::TransitionRequestData::~TransitionRequestData() {
+}
+
+void TransitionRequestManager::TransitionRequestData::AddEntry(
+ const std::string& allowed_destination_host_pattern,
+ const std::string& css_selector,
+ const std::string& markup,
+ const std::vector<TransitionElement>& elements) {
+ allowed_entries_.push_back(AllowedEntry(allowed_destination_host_pattern,
+ css_selector,
+ markup,
+ elements));
+}
+
+bool TransitionRequestManager::TransitionRequestData::FindEntry(
+ const GURL& request_url,
+ TransitionLayerData* transition_data) {
+ DCHECK(!allowed_entries_.empty());
+ CHECK(transition_data);
+ // TODO(oysteine): Add CSP check to validate the host pattern and the
+ // request_url. Must be done before this feature is moved out from the flag.
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures) ||
+ base::FieldTrialList::FindFullName("NavigationTransitions") ==
+ "Enabled");
+
+ const AllowedEntry& allowed_entry = allowed_entries_[0];
+ transition_data->markup = allowed_entry.markup;
+ transition_data->css_selector = allowed_entry.css_selector;
+ transition_data->elements = allowed_entry.elements;
+ return true;
+}
+
+bool TransitionRequestManager::GetPendingTransitionRequest(
+ int render_process_id,
+ int render_frame_id,
+ const GURL& request_url,
+ TransitionLayerData* transition_data) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(transition_data);
+ std::pair<int, int> key(render_process_id, render_frame_id);
+ RenderFrameRequestDataMap::iterator iter =
+ pending_transition_frames_.find(key);
+ return iter != pending_transition_frames_.end() &&
+ iter->second.FindEntry(request_url, transition_data);
+}
+
+void TransitionRequestManager::AddPendingTransitionRequestData(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& allowed_destination_host_pattern,
+ const std::string& css_selector,
+ const std::string& markup,
+ const std::vector<TransitionElement>& elements) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ std::pair<int, int> key(render_process_id, render_frame_id);
+ pending_transition_frames_[key].AddEntry(
+ allowed_destination_host_pattern, css_selector, markup, elements);
+}
+
+void TransitionRequestManager::AddPendingTransitionRequestDataForTesting(
+ int render_process_id,
+ int render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ std::pair<int, int> key(render_process_id, render_frame_id);
+ pending_transition_frames_[key].AddEntry(
+ "*", /* allowed_destination_host_pattern */
+ "", /* css_selector */
+ "", /* markup */
+ std::vector<TransitionElement>()); /* elements */
+}
+
+void TransitionRequestManager::ClearPendingTransitionRequestData(
+ int render_process_id, int render_frame_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ std::pair<int, int> key(render_process_id, render_frame_id);
+ pending_transition_frames_.erase(key);
+}
+
+TransitionRequestManager::TransitionRequestManager() {
+}
+
+TransitionRequestManager::~TransitionRequestManager() {
+}
+
+// static
+TransitionRequestManager* TransitionRequestManager::GetInstance() {
+ return Singleton<TransitionRequestManager>::get();
+}
+
+} // namespace content
diff --git a/chromium/content/browser/transition_request_manager.h b/chromium/content/browser/transition_request_manager.h
new file mode 100644
index 00000000000..65b57924134
--- /dev/null
+++ b/chromium/content/browser/transition_request_manager.h
@@ -0,0 +1,139 @@
+// 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_TRANSITION_REQUEST_MANAGER_H_
+#define CONTENT_BROWSER_TRANSITION_REQUEST_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "content/public/common/transition_element.h"
+#include "ui/gfx/geometry/rect.h"
+#include "url/gurl.h"
+
+template <typename T>
+struct DefaultSingletonTraits;
+
+namespace net {
+class HttpResponseHeaders;
+}
+class GURL;
+
+namespace content {
+
+// This struct passes data about an imminent transition between threads.
+struct TransitionLayerData {
+ CONTENT_EXPORT TransitionLayerData();
+ CONTENT_EXPORT ~TransitionLayerData();
+
+ std::string markup;
+ std::string css_selector;
+ std::vector<TransitionElement> elements;
+ scoped_refptr<net::HttpResponseHeaders> response_headers;
+ GURL request_url;
+};
+
+// TransitionRequestManager is used to handle bookkeeping for transition
+// requests and responses.
+//
+// TransitionRequestManager is a singleton and should only be accessed on the IO
+// thread.
+//
+class TransitionRequestManager {
+ public:
+ // Returns the singleton instance.
+ CONTENT_EXPORT static TransitionRequestManager* GetInstance();
+
+ // Parses out any transition-entering-stylesheet link headers from the
+ // response headers.
+ CONTENT_EXPORT static void ParseTransitionStylesheetsFromHeaders(
+ const scoped_refptr<net::HttpResponseHeaders>& headers,
+ std::vector<GURL>& entering_stylesheets,
+ const GURL& resolve_address);
+
+ // Get pending transition request data from RenderFrameHost specified by the
+ // given IDs and return true if the data exists. For web to web transition, we
+ // will have to delay the response until the embedder resumes the request if
+ // the data exists.
+ CONTENT_EXPORT bool GetPendingTransitionRequest(
+ int render_process_id,
+ int render_frame_id,
+ const GURL& request_url,
+ TransitionLayerData* transition_data);
+
+ // Adds pending request data for a transition navigation for the
+ // RenderFrameHost specified by the given IDs.
+ CONTENT_EXPORT void AddPendingTransitionRequestData(
+ int render_process_id,
+ int render_frame_id,
+ const std::string& allowed_destination_host_pattern,
+ const std::string& css_selector,
+ const std::string& markup,
+ const std::vector<TransitionElement>& elements);
+ CONTENT_EXPORT void AddPendingTransitionRequestDataForTesting(
+ int render_process_id,
+ int render_frame_id);
+
+ CONTENT_EXPORT void ClearPendingTransitionRequestData(int render_process_id,
+ int render_frame_id);
+
+ // The maximum number of elements is meant to avoid passing arbitrarily large
+ // amount of objects across the IPC boundary.
+ static const int kMaxNumOfElements = 1024;
+
+ private:
+ class TransitionRequestData {
+ public:
+ TransitionRequestData();
+ ~TransitionRequestData();
+ void AddEntry(const std::string& allowed_destination_host_pattern,
+ const std::string& selector,
+ const std::string& markup,
+ const std::vector<TransitionElement>& elements);
+ bool FindEntry(const GURL& request_url,
+ TransitionLayerData* transition_data);
+
+ private:
+ struct AllowedEntry {
+ // These strings could have originated from a compromised renderer,
+ // and should not be trusted or assumed safe. They are only used within
+ // a sandboxed iframe with scripts disabled.
+ std::string allowed_destination_host_pattern;
+ std::string css_selector;
+ std::string markup;
+ std::vector<TransitionElement> elements;
+
+ AllowedEntry(const std::string& allowed_destination_host_pattern,
+ const std::string& css_selector,
+ const std::string& markup,
+ const std::vector<TransitionElement>& elements);
+ ~AllowedEntry();
+ };
+ std::vector<AllowedEntry> allowed_entries_;
+ };
+
+ friend struct DefaultSingletonTraits<TransitionRequestManager>;
+ typedef std::map<std::pair<int, int>, TransitionRequestData>
+ RenderFrameRequestDataMap;
+
+ TransitionRequestManager();
+ ~TransitionRequestManager();
+
+ // Map of (render_process_host_id, render_frame_id) pairs of all
+ // RenderFrameHosts that have pending cross-site requests and their data.
+ // Used to pass information to the CrossSiteResourceHandler without doing a
+ // round-trip between IO->UI->IO threads.
+ RenderFrameRequestDataMap pending_transition_frames_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransitionRequestManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_TRANSITION_REQUEST_MANAGER_H_
diff --git a/chromium/content/browser/transition_request_manager_unittest.cc b/chromium/content/browser/transition_request_manager_unittest.cc
new file mode 100644
index 00000000000..95bc01e0242
--- /dev/null
+++ b/chromium/content/browser/transition_request_manager_unittest.cc
@@ -0,0 +1,106 @@
+// 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/transition_request_manager.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class TransitionRequestManagerTest : public testing::Test {
+ public:
+ ~TransitionRequestManagerTest() override {}
+};
+
+TEST_F(TransitionRequestManagerTest,
+ ParseTransitionStylesheetsFromNullHeaders) {
+ const GURL url("http://www.test.com/");
+ std::vector<GURL> entering_stylesheets;
+ scoped_refptr<net::HttpResponseHeaders> headers;
+
+ TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
+ headers, entering_stylesheets, url);
+ ASSERT_TRUE(entering_stylesheets.empty());
+}
+
+TEST_F(TransitionRequestManagerTest,
+ ParseTransitionStylesheetsFromEmptyHeaders) {
+ const GURL url("http://www.test.com/");
+ std::vector<GURL> entering_stylesheets;
+
+ char headers_string[] = "";
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers_string, sizeof(headers_string))));
+
+ TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
+ headers, entering_stylesheets, url);
+ ASSERT_TRUE(entering_stylesheets.empty());
+}
+
+TEST_F(TransitionRequestManagerTest,
+ ParseTransitionStylesheetsFromHeadersForInvalidURL) {
+ const GURL url;
+ std::vector<GURL> entering_stylesheets;
+
+ char headers_string[] =
+ "HTTP/1.0 200 OK\r\n"
+ "link: <transition.css>;rel=transition-entering-stylesheet;scope=*\r\n"
+ "\r\n";
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers_string, sizeof(headers_string))));
+
+ TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
+ headers, entering_stylesheets, url);
+ ASSERT_TRUE(entering_stylesheets.empty());
+}
+
+TEST_F(TransitionRequestManagerTest, ParseTransitionStylesheetsFromHeaders) {
+ const GURL url("http://www.test.com/");
+ std::vector<GURL> entering_stylesheets;
+
+ char headers_string[] =
+ "HTTP/1.0 200 OK\r\n"
+ "link: <transition.css>;rel=transition-entering-stylesheet;scope=*\r\n"
+ "\r\n";
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers_string, sizeof(headers_string))));
+
+ TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
+ headers, entering_stylesheets, url);
+ ASSERT_TRUE(entering_stylesheets.size() == 1);
+ ASSERT_STREQ((url.spec() + "transition.css").c_str(),
+ entering_stylesheets[0].spec().c_str());
+}
+
+TEST_F(TransitionRequestManagerTest,
+ ParseMultipleTransitionStylesheetsFromHeaders) {
+ const GURL url("http://www.test.com/");
+ std::vector<GURL> entering_stylesheets;
+
+ char headers_string[] =
+ "HTTP/1.0 200 OK\r\n"
+ "link: <transition0.css>;rel=transition-entering-stylesheet;scope=*\r\n"
+ "link: <transition1.css>;rel=transition-entering-stylesheet;scope=*\r\n"
+ "link: <transition2.css>;rel=transition-entering-stylesheet;scope=*\r\n"
+ "\r\n";
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers_string, sizeof(headers_string))));
+
+ TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
+ headers, entering_stylesheets, url);
+ ASSERT_TRUE(entering_stylesheets.size() == 3);
+ ASSERT_STREQ((url.spec() + "transition0.css").c_str(),
+ entering_stylesheets[0].spec().c_str());
+ ASSERT_STREQ((url.spec() + "transition1.css").c_str(),
+ entering_stylesheets[1].spec().c_str());
+ ASSERT_STREQ((url.spec() + "transition2.css").c_str(),
+ entering_stylesheets[2].spec().c_str());
+}
+
+} // namespace content
diff --git a/chromium/content/browser/udev_linux.cc b/chromium/content/browser/udev_linux.cc
index f6f9443ab3f..80c929bf0ec 100644
--- a/chromium/content/browser/udev_linux.cc
+++ b/chromium/content/browser/udev_linux.cc
@@ -13,23 +13,21 @@ namespace content {
UdevLinux::UdevLinux(const std::vector<UdevMonitorFilter>& filters,
const UdevNotificationCallback& callback)
: udev_(udev_new()),
- monitor_(NULL),
+ monitor_(udev_monitor_new_from_netlink(udev_.get(), "udev")),
monitor_fd_(-1),
callback_(callback) {
CHECK(udev_);
-
- monitor_ = udev_monitor_new_from_netlink(udev_, "udev");
CHECK(monitor_);
for (size_t i = 0; i < filters.size(); ++i) {
int ret = udev_monitor_filter_add_match_subsystem_devtype(
- monitor_, filters[i].subsystem, filters[i].devtype);
+ monitor_.get(), filters[i].subsystem, filters[i].devtype);
CHECK_EQ(0, ret);
}
- int ret = udev_monitor_enable_receiving(monitor_);
+ int ret = udev_monitor_enable_receiving(monitor_.get());
CHECK_EQ(0, ret);
- monitor_fd_ = udev_monitor_get_fd(monitor_);
+ monitor_fd_ = udev_monitor_get_fd(monitor_.get());
CHECK_GE(monitor_fd_, 0);
bool success = base::MessageLoopForIO::current()->WatchFileDescriptor(
@@ -43,12 +41,10 @@ UdevLinux::UdevLinux(const std::vector<UdevMonitorFilter>& filters,
UdevLinux::~UdevLinux() {
monitor_watcher_.StopWatchingFileDescriptor();
- udev_monitor_unref(monitor_);
- udev_unref(udev_);
}
udev* UdevLinux::udev_handle() {
- return udev_;
+ return udev_.get();
}
void UdevLinux::OnFileCanReadWithoutBlocking(int fd) {
@@ -56,12 +52,12 @@ void UdevLinux::OnFileCanReadWithoutBlocking(int fd) {
// 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);
- udev_device* dev = udev_monitor_receive_device(monitor_);
+ device::ScopedUdevDevicePtr dev(
+ udev_monitor_receive_device(monitor_.get()));
if (!dev)
return;
- callback_.Run(dev);
- udev_device_unref(dev);
+ callback_.Run(dev.get());
}
void UdevLinux::OnFileCanWriteWithoutBlocking(int fd) {
diff --git a/chromium/content/browser/udev_linux.h b/chromium/content/browser/udev_linux.h
index 2b89094c8b6..0160fd3241b 100644
--- a/chromium/content/browser/udev_linux.h
+++ b/chromium/content/browser/udev_linux.h
@@ -42,6 +42,7 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_pump_libevent.h"
+#include "device/udev_linux/scoped_udev.h"
extern "C" {
struct udev;
@@ -70,21 +71,20 @@ class UdevLinux : public base::MessagePumpLibevent::Watcher {
// Calls |callback| upon device change events.
UdevLinux(const std::vector<UdevMonitorFilter>& filters,
const UdevNotificationCallback& callback);
- virtual ~UdevLinux();
-
+ ~UdevLinux() override;
// Returns the udev handle to be passed into other udev_*() functions.
udev* udev_handle();
private:
// base::MessagePump:Libevent::Watcher implementation.
- virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
- virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+ 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.
- udev* udev_;
- udev_monitor* monitor_;
+ device::ScopedUdevPtr udev_;
+ device::ScopedUdevMonitorPtr monitor_;
int monitor_fd_;
base::MessagePumpLibevent::FileDescriptorWatcher monitor_watcher_;
UdevNotificationCallback callback_;
diff --git a/chromium/content/browser/utility_process_host_impl.cc b/chromium/content/browser/utility_process_host_impl.cc
index ddc41a74131..0d24e3a5e69 100644
--- a/chromium/content/browser/utility_process_host_impl.cc
+++ b/chromium/content/browser/utility_process_host_impl.cc
@@ -47,27 +47,23 @@ class UtilitySandboxedProcessLauncherDelegate
#endif // OS_WIN
{}
- virtual ~UtilitySandboxedProcessLauncherDelegate() {}
+ ~UtilitySandboxedProcessLauncherDelegate() override {}
#if defined(OS_WIN)
- virtual bool ShouldLaunchElevated() OVERRIDE {
+ virtual bool ShouldLaunchElevated() override {
return launch_elevated_;
}
virtual void PreSandbox(bool* disable_default_policy,
- base::FilePath* exposed_dir) OVERRIDE {
+ base::FilePath* exposed_dir) override {
*exposed_dir = exposed_dir_;
}
#elif defined(OS_POSIX)
- virtual bool ShouldUseZygote() OVERRIDE {
+ bool ShouldUseZygote() override {
return !no_sandbox_ && exposed_dir_.empty();
}
- virtual base::EnvironmentMap GetEnvironment() OVERRIDE {
- return env_;
- }
- virtual int GetIpcFd() OVERRIDE {
- return ipc_fd_;
- }
+ base::EnvironmentMap GetEnvironment() override { return env_; }
+ base::ScopedFD TakeIpcFd() override { return ipc_fd_.Pass(); }
#endif // OS_WIN
private:
@@ -79,15 +75,15 @@ class UtilitySandboxedProcessLauncherDelegate
#elif defined(OS_POSIX)
base::EnvironmentMap env_;
bool no_sandbox_;
- int ipc_fd_;
+ base::ScopedFD ipc_fd_;
#endif // OS_WIN
};
UtilityMainThreadFactoryFunction g_utility_main_thread_factory = NULL;
UtilityProcessHost* UtilityProcessHost::Create(
- UtilityProcessHostClient* client,
- base::SequencedTaskRunner* client_task_runner) {
+ const scoped_refptr<UtilityProcessHostClient>& client,
+ const scoped_refptr<base::SequencedTaskRunner>& client_task_runner) {
return new UtilityProcessHostImpl(client, client_task_runner);
}
@@ -97,8 +93,8 @@ void UtilityProcessHostImpl::RegisterUtilityMainThreadFactory(
}
UtilityProcessHostImpl::UtilityProcessHostImpl(
- UtilityProcessHostClient* client,
- base::SequencedTaskRunner* client_task_runner)
+ const scoped_refptr<UtilityProcessHostClient>& client,
+ const scoped_refptr<base::SequencedTaskRunner>& client_task_runner)
: client_(client),
client_task_runner_(client_task_runner),
is_batch_mode_(false),
@@ -194,7 +190,8 @@ bool UtilityProcessHostImpl::StartProcess() {
in_process_thread_.reset(g_utility_main_thread_factory(channel_id));
in_process_thread_->Start();
} else {
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ const base::CommandLine& browser_command_line =
+ *base::CommandLine::ForCurrentProcess();
int child_flags = child_flags_;
#if defined(OS_POSIX)
@@ -216,7 +213,7 @@ bool UtilityProcessHostImpl::StartProcess() {
return false;
}
- CommandLine* cmd_line = new CommandLine(exe_path);
+ base::CommandLine* cmd_line = new base::CommandLine(exe_path);
cmd_line->AppendSwitchASCII(switches::kProcessType,
switches::kUtilityProcess);
cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
@@ -267,15 +264,23 @@ bool UtilityProcessHostImpl::StartProcess() {
}
bool UtilityProcessHostImpl::OnMessageReceived(const IPC::Message& message) {
+ if (!client_.get())
+ return true;
+
client_task_runner_->PostTask(
FROM_HERE,
- base::Bind(base::IgnoreResult(
- &UtilityProcessHostClient::OnMessageReceived), client_.get(),
+ base::Bind(
+ base::IgnoreResult(&UtilityProcessHostClient::OnMessageReceived),
+ client_.get(),
message));
+
return true;
}
void UtilityProcessHostImpl::OnProcessLaunchFailed() {
+ if (!client_.get())
+ return;
+
client_task_runner_->PostTask(
FROM_HERE,
base::Bind(&UtilityProcessHostClient::OnProcessLaunchFailed,
@@ -283,6 +288,9 @@ void UtilityProcessHostImpl::OnProcessLaunchFailed() {
}
void UtilityProcessHostImpl::OnProcessCrashed(int exit_code) {
+ if (!client_.get())
+ return;
+
client_task_runner_->PostTask(
FROM_HERE,
base::Bind(&UtilityProcessHostClient::OnProcessCrashed, client_.get(),
diff --git a/chromium/content/browser/utility_process_host_impl.h b/chromium/content/browser/utility_process_host_impl.h
index 84866551a3b..c310e9b4bf0 100644
--- a/chromium/content/browser/utility_process_host_impl.h
+++ b/chromium/content/browser/utility_process_host_impl.h
@@ -35,23 +35,24 @@ class CONTENT_EXPORT UtilityProcessHostImpl
static void RegisterUtilityMainThreadFactory(
UtilityMainThreadFactoryFunction create);
- UtilityProcessHostImpl(UtilityProcessHostClient* client,
- base::SequencedTaskRunner* client_task_runner);
- virtual ~UtilityProcessHostImpl();
+ UtilityProcessHostImpl(
+ const scoped_refptr<UtilityProcessHostClient>& client,
+ const scoped_refptr<base::SequencedTaskRunner>& client_task_runner);
+ ~UtilityProcessHostImpl() override;
// UtilityProcessHost implementation:
- virtual bool Send(IPC::Message* message) OVERRIDE;
- virtual bool StartBatchMode() OVERRIDE;
- virtual void EndBatchMode() OVERRIDE;
- virtual void SetExposedDir(const base::FilePath& dir) OVERRIDE;
- virtual void EnableMDns() OVERRIDE;
- virtual void DisableSandbox() OVERRIDE;
+ bool Send(IPC::Message* message) override;
+ bool StartBatchMode() override;
+ void EndBatchMode() override;
+ void SetExposedDir(const base::FilePath& dir) override;
+ void EnableMDns() override;
+ void DisableSandbox() override;
#if defined(OS_WIN)
- virtual void ElevatePrivileges() OVERRIDE;
+ virtual void ElevatePrivileges() override;
#endif
- virtual const ChildProcessData& GetData() OVERRIDE;
+ const ChildProcessData& GetData() override;
#if defined(OS_POSIX)
- virtual void SetEnv(const base::EnvironmentMap& env) OVERRIDE;
+ void SetEnv(const base::EnvironmentMap& env) override;
#endif
void set_child_flags(int flags) { child_flags_ = flags; }
@@ -62,9 +63,9 @@ class CONTENT_EXPORT UtilityProcessHostImpl
bool StartProcess();
// BrowserChildProcessHost:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- virtual void OnProcessLaunchFailed() OVERRIDE;
- virtual void OnProcessCrashed(int exit_code) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
+ void OnProcessLaunchFailed() override;
+ void OnProcessCrashed(int exit_code) override;
// A pointer to our client interface, who will be informed of progress.
scoped_refptr<UtilityProcessHostClient> client_;
diff --git a/chromium/content/browser/vibration/vibration_message_filter.h b/chromium/content/browser/vibration/vibration_message_filter.h
index 1d603ee412a..19e0e6121db 100644
--- a/chromium/content/browser/vibration/vibration_message_filter.h
+++ b/chromium/content/browser/vibration/vibration_message_filter.h
@@ -17,9 +17,9 @@ class VibrationMessageFilter : public BrowserMessageFilter {
VibrationMessageFilter();
private:
- virtual ~VibrationMessageFilter();
+ ~VibrationMessageFilter() override;
// BrowserMessageFilter implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
void OnVibrate(int64 milliseconds);
void OnCancelVibration();
diff --git a/chromium/content/browser/vibration/vibration_provider_android.h b/chromium/content/browser/vibration/vibration_provider_android.h
index 4d39c748fcd..e0bd1c1d7cb 100644
--- a/chromium/content/browser/vibration/vibration_provider_android.h
+++ b/chromium/content/browser/vibration/vibration_provider_android.h
@@ -19,8 +19,8 @@ class VibrationProviderAndroid : public VibrationProvider {
private:
virtual ~VibrationProviderAndroid();
- virtual void Vibrate(int64 milliseconds) OVERRIDE;
- virtual void CancelVibration() OVERRIDE;
+ virtual void Vibrate(int64 milliseconds) override;
+ virtual void CancelVibration() override;
base::android::ScopedJavaGlobalRef<jobject> j_vibration_provider_;
};
diff --git a/chromium/content/browser/web_contents/OWNERS b/chromium/content/browser/web_contents/OWNERS
index 7454076fe49..8a66bc176f1 100644
--- a/chromium/content/browser/web_contents/OWNERS
+++ b/chromium/content/browser/web_contents/OWNERS
@@ -1,6 +1,5 @@
# for *aura*
-per-file *aura*=ben@chromium.org
+per-file *aura*=sadrul@chromium.org
# for *android*
-per-file *android*=sievers@chromium.org
per-file *android*=tedchoc@chromium.org
diff --git a/chromium/content/browser/web_contents/aura/OWNERS b/chromium/content/browser/web_contents/aura/OWNERS
new file mode 100644
index 00000000000..6e8111fb817
--- /dev/null
+++ b/chromium/content/browser/web_contents/aura/OWNERS
@@ -0,0 +1,2 @@
+mfomitchev@chromium.org
+sadrul@chromium.org
diff --git a/chromium/content/browser/web_contents/aura/gesture_nav_simple.cc b/chromium/content/browser/web_contents/aura/gesture_nav_simple.cc
index f904fe28cf1..406f5545e28 100644
--- a/chromium/content/browser/web_contents/aura/gesture_nav_simple.cc
+++ b/chromium/content/browser/web_contents/aura/gesture_nav_simple.cc
@@ -12,7 +12,6 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/overscroll_configuration.h"
#include "content/public/common/content_client.h"
-#include "grit/ui_resources.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
@@ -21,6 +20,7 @@
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image.h"
+#include "ui/resources/grit/ui_resources.h"
namespace content {
@@ -56,7 +56,7 @@ class DeleteAfterAnimation : public ui::ImplicitAnimationObserver {
virtual ~DeleteAfterAnimation() {}
// ui::ImplicitAnimationObserver:
- virtual void OnImplicitAnimationsCompleted() OVERRIDE {
+ virtual void OnImplicitAnimationsCompleted() override {
// Deleting an observer when a ScopedLayerAnimationSettings is iterating
// over them can cause a crash (which can happen during tests). So instead,
// schedule this observer to be deleted soon.
@@ -78,13 +78,13 @@ class ArrowLayerDelegate : public ui::LayerDelegate {
CHECK(!image_.IsEmpty());
}
- virtual ~ArrowLayerDelegate() {}
+ ~ArrowLayerDelegate() override {}
bool left() const { return left_arrow_; }
private:
// ui::LayerDelegate:
- virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
+ void OnPaintLayer(gfx::Canvas* canvas) override {
SkPaint paint;
paint.setColor(SkColorSetARGB(0xa0, 0, 0, 0));
paint.setStyle(SkPaint::kFill_Style);
@@ -99,9 +99,11 @@ class ArrowLayerDelegate : public ui::LayerDelegate {
(kArrowHeight - image_.Height()) / 2);
}
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
+ void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
- virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE {
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
+
+ base::Closure PrepareForLayerBoundsChange() override {
return base::Closure();
}
@@ -145,9 +147,9 @@ void GestureNavSimple::CompleteGestureAnimation() {
ApplyEffectsAndDestroy(arrow_->transform(), 0.f);
}
-void GestureNavSimple::ApplyEffectsForDelta(float delta_x) {
+bool GestureNavSimple::ApplyEffectsForDelta(float delta_x) {
if (!arrow_)
- return;
+ return false;
CHECK_GT(completion_threshold_, 0.f);
CHECK_GE(delta_x, 0.f);
double complete = std::min(1.f, delta_x / completion_threshold_);
@@ -157,14 +159,15 @@ void GestureNavSimple::ApplyEffectsForDelta(float delta_x) {
0.f);
arrow_->SetTransform(transform);
arrow_->SetOpacity(gfx::Tween::FloatValueBetween(complete, kMinOpacity, 1.f));
+ return true;
}
gfx::Rect GestureNavSimple::GetVisibleBounds() const {
return web_contents_->GetNativeView()->bounds();
}
-void GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) {
- ApplyEffectsForDelta(std::abs(delta_x) + 50.f);
+bool GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) {
+ return ApplyEffectsForDelta(std::abs(delta_x) + 50.f);
}
void GestureNavSimple::OnOverscrollComplete(OverscrollMode overscroll_mode) {
diff --git a/chromium/content/browser/web_contents/aura/gesture_nav_simple.h b/chromium/content/browser/web_contents/aura/gesture_nav_simple.h
index e8466e5e6e2..46da9098470 100644
--- a/chromium/content/browser/web_contents/aura/gesture_nav_simple.h
+++ b/chromium/content/browser/web_contents/aura/gesture_nav_simple.h
@@ -26,20 +26,21 @@ class WebContentsImpl;
class GestureNavSimple : public OverscrollControllerDelegate {
public:
explicit GestureNavSimple(WebContentsImpl* web_contents);
- virtual ~GestureNavSimple();
+ ~GestureNavSimple() override;
private:
void ApplyEffectsAndDestroy(const gfx::Transform& transform, float opacity);
void AbortGestureAnimation();
void CompleteGestureAnimation();
- void ApplyEffectsForDelta(float delta_x);
+ bool ApplyEffectsForDelta(float delta_x);
// OverscrollControllerDelegate:
- virtual gfx::Rect GetVisibleBounds() const OVERRIDE;
- virtual void OnOverscrollUpdate(float delta_x, float delta_y) OVERRIDE;
- virtual void OnOverscrollComplete(OverscrollMode overscroll_mode) OVERRIDE;
- virtual void OnOverscrollModeChange(OverscrollMode old_mode,
- OverscrollMode new_mode) OVERRIDE;
+ gfx::Rect GetVisibleBounds() const override;
+ // Returns true if the scroll update was consumed.
+ bool OnOverscrollUpdate(float delta_x, float delta_y) override;
+ void OnOverscrollComplete(OverscrollMode overscroll_mode) override;
+ void OnOverscrollModeChange(OverscrollMode old_mode,
+ OverscrollMode new_mode) override;
WebContentsImpl* web_contents_;
scoped_ptr<ui::Layer> clip_layer_;
diff --git a/chromium/content/browser/web_contents/aura/image_window_delegate.cc b/chromium/content/browser/web_contents/aura/image_window_delegate.cc
index 0b40c0f0905..ccfd2c5bcb9 100644
--- a/chromium/content/browser/web_contents/aura/image_window_delegate.cc
+++ b/chromium/content/browser/web_contents/aura/image_window_delegate.cc
@@ -66,7 +66,7 @@ void ImageWindowDelegate::OnCaptureLost() {
void ImageWindowDelegate::OnPaint(gfx::Canvas* canvas) {
if (image_.IsEmpty()) {
- canvas->DrawColor(SK_ColorGRAY);
+ canvas->DrawColor(SK_ColorWHITE);
} else {
if (size_mismatch_)
canvas->DrawColor(SK_ColorWHITE);
diff --git a/chromium/content/browser/web_contents/aura/image_window_delegate.h b/chromium/content/browser/web_contents/aura/image_window_delegate.h
index d0f9b061918..53cf88e79eb 100644
--- a/chromium/content/browser/web_contents/aura/image_window_delegate.h
+++ b/chromium/content/browser/web_contents/aura/image_window_delegate.h
@@ -22,27 +22,27 @@ class CONTENT_EXPORT ImageWindowDelegate : public aura::WindowDelegate {
bool has_image() const { return !image_.IsEmpty(); }
protected:
- virtual ~ImageWindowDelegate();
+ ~ImageWindowDelegate() override;
// Overridden from aura::WindowDelegate:
- virtual gfx::Size GetMinimumSize() const OVERRIDE;
- virtual gfx::Size GetMaximumSize() const OVERRIDE;
- virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) OVERRIDE;
- virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE;
- virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
- virtual bool ShouldDescendIntoChildForEventHandling(
+ gfx::Size GetMinimumSize() const override;
+ gfx::Size GetMaximumSize() const override;
+ void OnBoundsChanged(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) override;
+ gfx::NativeCursor GetCursor(const gfx::Point& point) override;
+ int GetNonClientComponent(const gfx::Point& point) const override;
+ bool ShouldDescendIntoChildForEventHandling(
aura::Window* child,
- const gfx::Point& location) OVERRIDE;
- virtual bool CanFocus() OVERRIDE;
- virtual void OnCaptureLost() OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
- virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE;
- virtual bool HasHitTestMask() const OVERRIDE;
- virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
+ const gfx::Point& location) override;
+ bool CanFocus() override;
+ void OnCaptureLost() override;
+ void OnPaint(gfx::Canvas* canvas) override;
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override;
+ void OnWindowDestroying(aura::Window* window) override;
+ void OnWindowDestroyed(aura::Window* window) override;
+ void OnWindowTargetVisibilityChanged(bool visible) override;
+ bool HasHitTestMask() const override;
+ void GetHitTestMask(gfx::Path* mask) const override;
protected:
gfx::Image image_;
diff --git a/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.cc b/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.cc
index d2b8b6e7726..3660897dab3 100644
--- a/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.cc
+++ b/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.cc
@@ -21,13 +21,31 @@
#include "ui/gfx/image/image_skia.h"
namespace content {
+namespace {
+
+// Returns true if the entry's URL or any of the URLs in entry's redirect chain
+// match |url|.
+bool DoesEntryMatchURL(NavigationEntry* entry, const GURL& url) {
+ if (entry->GetURL() == url)
+ return true;
+ const std::vector<GURL>& redirect_chain = entry->GetRedirectChain();
+ for (std::vector<GURL>::const_iterator it = redirect_chain.begin();
+ it != redirect_chain.end();
+ it++) {
+ if (*it == url)
+ return true;
+ }
+ return false;
+}
+
+} // namespace
// A LayerDelegate that paints an image for the layer.
class ImageLayerDelegate : public ui::LayerDelegate {
public:
ImageLayerDelegate() {}
- virtual ~ImageLayerDelegate() {}
+ ~ImageLayerDelegate() override {}
void SetImage(const gfx::Image& image) {
image_ = image;
@@ -37,9 +55,9 @@ class ImageLayerDelegate : public ui::LayerDelegate {
private:
// Overridden from ui::LayerDelegate:
- virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
+ void OnPaintLayer(gfx::Canvas* canvas) override {
if (image_.IsEmpty()) {
- canvas->DrawColor(SK_ColorGRAY);
+ canvas->DrawColor(SK_ColorWHITE);
} else {
SkISize size = canvas->sk_canvas()->getDeviceSize();
if (size.width() != image_size_.width() ||
@@ -50,13 +68,14 @@ class ImageLayerDelegate : public ui::LayerDelegate {
}
}
+ void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
+
// Called when the layer's device scale factor has changed.
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {
- }
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
// Invoked prior to the bounds changing. The returned closured is run after
// the bounds change.
- virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE {
+ base::Closure PrepareForLayerBoundsChange() override {
return base::Closure();
}
@@ -89,21 +108,19 @@ class OverlayDismissAnimator
}
// Overridden from ui::LayerAnimationObserver
- virtual void OnLayerAnimationEnded(
- ui::LayerAnimationSequence* sequence) OVERRIDE {
+ void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {
delete this;
}
- virtual void OnLayerAnimationAborted(
- ui::LayerAnimationSequence* sequence) OVERRIDE {
+ void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {
delete this;
}
- virtual void OnLayerAnimationScheduled(
- ui::LayerAnimationSequence* sequence) OVERRIDE {}
+ void OnLayerAnimationScheduled(
+ ui::LayerAnimationSequence* sequence) override {}
private:
- virtual ~OverlayDismissAnimator() {}
+ ~OverlayDismissAnimator() override {}
scoped_ptr<ui::Layer> layer_;
@@ -116,7 +133,6 @@ OverscrollNavigationOverlay::OverscrollNavigationOverlay(
image_delegate_(NULL),
loading_complete_(false),
received_paint_update_(false),
- pending_entry_id_(0),
slide_direction_(SLIDE_UNKNOWN) {
}
@@ -127,7 +143,6 @@ void OverscrollNavigationOverlay::StartObserving() {
loading_complete_ = false;
received_paint_update_ = false;
overlay_dismiss_layer_.reset();
- pending_entry_id_ = 0;
Observe(web_contents_);
// Make sure the overlay window is on top.
@@ -137,10 +152,10 @@ void OverscrollNavigationOverlay::StartObserving() {
// Assumes the navigation has been initiated.
NavigationEntry* pending_entry =
web_contents_->GetController().GetPendingEntry();
- // Save id of the pending entry to identify when it loads and paints later.
+ // Save url of the pending entry to identify when it loads and paints later.
// Under some circumstances navigation can leave a null pending entry -
// see comments in NavigationControllerImpl::NavigateToPendingEntry().
- pending_entry_id_ = pending_entry ? pending_entry->GetUniqueID() : 0;
+ pending_entry_url_ = pending_entry ? pending_entry->GetURL() : GURL();
}
void OverscrollNavigationOverlay::SetOverlayWindow(
@@ -197,8 +212,7 @@ ui::Layer* OverscrollNavigationOverlay::CreateSlideLayer(int offset) {
gfx::Image image;
if (entry && entry->screenshot().get()) {
std::vector<gfx::ImagePNGRep> image_reps;
- image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(),
- ui::GetScaleFactorForNativeView(window_.get())));
+ image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 1.0f));
image = gfx::Image(image_reps);
}
if (!layer_delegate_)
@@ -274,29 +288,27 @@ void OverscrollNavigationOverlay::OnWindowSliderDestroyed() {
// (including recursively) for a single event.
if (window_slider_.get()) {
// The slider has just been destroyed. Release the ownership.
- WindowSlider* slider ALLOW_UNUSED = window_slider_.release();
+ ignore_result(window_slider_.release());
StopObservingIfDone();
}
}
void OverscrollNavigationOverlay::DidFirstVisuallyNonEmptyPaint() {
- int visible_entry_id =
- web_contents_->GetController().GetVisibleEntry()->GetUniqueID();
- if (visible_entry_id == pending_entry_id_ || !pending_entry_id_) {
+ NavigationEntry* visible_entry =
+ web_contents_->GetController().GetVisibleEntry();
+ if (pending_entry_url_.is_empty() ||
+ DoesEntryMatchURL(visible_entry, pending_entry_url_)) {
received_paint_update_ = true;
StopObservingIfDone();
}
}
void OverscrollNavigationOverlay::DidStopLoading(RenderViewHost* host) {
- // Use the last committed entry rather than the active one, in case a
- // pending entry has been created.
- int committed_entry_id =
- web_contents_->GetController().GetLastCommittedEntry()->GetUniqueID();
- if (committed_entry_id == pending_entry_id_ || !pending_entry_id_) {
- loading_complete_ = true;
- StopObservingIfDone();
- }
+ // Don't compare URLs in this case - it's possible they won't match if
+ // a gesture-nav initiated navigation was interrupted by some other in-site
+ // navigation ((e.g., from a script, or from a bookmark).
+ loading_complete_ = true;
+ StopObservingIfDone();
}
} // namespace content
diff --git a/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.h b/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.h
index e8e917136ca..d65d374a848 100644
--- a/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.h
+++ b/chromium/content/browser/web_contents/aura/overscroll_navigation_overlay.h
@@ -29,7 +29,7 @@ class CONTENT_EXPORT OverscrollNavigationOverlay
public WindowSlider::Delegate {
public:
explicit OverscrollNavigationOverlay(WebContentsImpl* web_contents);
- virtual ~OverscrollNavigationOverlay();
+ ~OverscrollNavigationOverlay() override;
bool has_window() const { return !!window_.get(); }
@@ -77,16 +77,16 @@ class CONTENT_EXPORT OverscrollNavigationOverlay
ui::Layer* CreateSlideLayer(int offset);
// Overridden from WindowSlider::Delegate:
- virtual ui::Layer* CreateBackLayer() OVERRIDE;
- virtual ui::Layer* CreateFrontLayer() OVERRIDE;
- virtual void OnWindowSlideCompleting() OVERRIDE;
- virtual void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) OVERRIDE;
- virtual void OnWindowSlideAborted() OVERRIDE;
- virtual void OnWindowSliderDestroyed() OVERRIDE;
+ ui::Layer* CreateBackLayer() override;
+ ui::Layer* CreateFrontLayer() override;
+ void OnWindowSlideCompleting() override;
+ void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override;
+ void OnWindowSlideAborted() override;
+ void OnWindowSliderDestroyed() override;
// Overridden from WebContentsObserver:
- virtual void DidFirstVisuallyNonEmptyPaint() OVERRIDE;
- virtual void DidStopLoading(RenderViewHost* host) OVERRIDE;
+ void DidFirstVisuallyNonEmptyPaint() override;
+ void DidStopLoading(RenderViewHost* host) override;
// The WebContents which is being navigated.
WebContentsImpl* web_contents_;
@@ -101,10 +101,10 @@ class CONTENT_EXPORT OverscrollNavigationOverlay
bool loading_complete_;
bool received_paint_update_;
- // Unique ID of the NavigationEntry we are navigating to. This is needed to
+ // URL of the NavigationEntry we are navigating to. This is needed to
// filter on WebContentsObserver callbacks and is used to dismiss the overlay
// when the relevant page loads and paints.
- int pending_entry_id_;
+ GURL pending_entry_url_;
// The |WindowSlider| that allows sliding history layers while the page is
// being reloaded.
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 4ff49761095..0e9eb4ef65a 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
@@ -7,8 +7,10 @@
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/web_contents/aura/image_window_delegate.h"
#include "content/browser/web_contents/web_contents_view.h"
+#include "content/common/frame_messages.h"
#include "content/common/view_messages.h"
#include "content/public/test/mock_render_process_host.h"
+#include "content/test/test_render_frame_host.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "ui/aura/test/test_windows.h"
@@ -20,20 +22,18 @@ namespace content {
class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
public:
OverscrollNavigationOverlayTest() {}
- virtual ~OverscrollNavigationOverlayTest() {}
+ ~OverscrollNavigationOverlayTest() override {}
gfx::Image CreateDummyScreenshot() {
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(SK_ColorWHITE);
return gfx::Image::CreateFrom1xBitmap(bitmap);
}
void SetDummyScreenshotOnNavEntry(NavigationEntry* entry) {
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(SK_ColorWHITE);
std::vector<unsigned char> png_data;
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &png_data);
@@ -45,7 +45,8 @@ class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
}
void ReceivePaintUpdate() {
- ViewHostMsg_DidFirstVisuallyNonEmptyPaint msg(test_rvh()->GetRoutingID());
+ FrameHostMsg_DidFirstVisuallyNonEmptyPaint msg(
+ main_test_rfh()->GetRoutingID());
RenderViewHostTester::TestOnMessageReceived(test_rvh(), msg);
}
@@ -61,7 +62,7 @@ class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
protected:
// RenderViewHostImplTestHarness:
- virtual void SetUp() OVERRIDE {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
const GURL first("https://www.google.com");
@@ -102,7 +103,7 @@ class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness {
EXPECT_FALSE(overlay_->received_paint_update_);
}
- virtual void TearDown() OVERRIDE {
+ void TearDown() override {
overlay_.reset();
RenderViewHostImplTestHarness::TearDown();
}
@@ -156,7 +157,7 @@ TEST_F(OverscrollNavigationOverlayTest, MultiNavigation_PaintUpdate) {
EXPECT_FALSE(GetOverlay()->received_paint_update_);
ReceivePaintUpdate();
- // Paint updates until the navigation is committed represent updates
+ // Paint updates until the navigation is committed typically represent updates
// for the previous page, so they shouldn't affect the flag.
EXPECT_FALSE(GetOverlay()->received_paint_update_);
@@ -178,17 +179,13 @@ TEST_F(OverscrollNavigationOverlayTest, MultiNavigation_LoadingUpdate) {
// Navigation was started, so the loading status flag should be reset.
EXPECT_FALSE(GetOverlay()->loading_complete_);
- // Load updates until the navigation is committed represent updates for the
- // previous page, so they shouldn't affect the flag.
+ // DidStopLoading for any navigation should always reset the load flag and
+ // dismiss the overlay even if the pending navigation wasn't committed -
+ // 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()->loading_complete_);
-
- contents()->CommitPendingNavigation();
- contents()->TestSetIsLoading(true);
- contents()->TestSetIsLoading(false);
- // Navigation was committed and the load update was received - the flag
- // should now be updated.
EXPECT_TRUE(GetOverlay()->loading_complete_);
EXPECT_FALSE(GetOverlay()->web_contents());
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 0d0fe934260..83e403b00b2 100644
--- a/chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc
+++ b/chromium/content/browser/web_contents/aura/shadow_layer_delegate.cc
@@ -51,6 +51,10 @@ void ShadowLayerDelegate::OnPaintLayer(gfx::Canvas* canvas) {
canvas->sk_canvas()->drawRect(gfx::RectToSkRect(paint_rect), paint);
}
+void ShadowLayerDelegate::OnDelegatedFrameDamage(
+ const gfx::Rect& damage_rect_in_dip) {
+}
+
void ShadowLayerDelegate::OnDeviceScaleFactorChanged(float scale_factor) {
}
diff --git a/chromium/content/browser/web_contents/aura/shadow_layer_delegate.h b/chromium/content/browser/web_contents/aura/shadow_layer_delegate.h
index 22659d91f11..69c2dcbc7da 100644
--- a/chromium/content/browser/web_contents/aura/shadow_layer_delegate.h
+++ b/chromium/content/browser/web_contents/aura/shadow_layer_delegate.h
@@ -24,7 +24,7 @@ namespace content {
class ShadowLayerDelegate : public ui::LayerDelegate {
public:
explicit ShadowLayerDelegate(ui::Layer* shadow_for);
- virtual ~ShadowLayerDelegate();
+ ~ShadowLayerDelegate() override;
// Returns the layer for the shadow. Note that the ShadowLayerDelegate owns
// the layer, and the layer is destroyed when the delegate is destroyed.
@@ -32,9 +32,10 @@ class ShadowLayerDelegate : public ui::LayerDelegate {
private:
// Overridden from ui::LayerDelegate:
- virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE;
+ void OnPaintLayer(gfx::Canvas* canvas) override;
+ void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override;
+ base::Closure PrepareForLayerBoundsChange() override;
scoped_ptr<ui::Layer> layer_;
diff --git a/chromium/content/browser/web_contents/aura/window_slider.cc b/chromium/content/browser/web_contents/aura/window_slider.cc
index 8248d6c7318..f7ffa7e3839 100644
--- a/chromium/content/browser/web_contents/aura/window_slider.cc
+++ b/chromium/content/browser/web_contents/aura/window_slider.cc
@@ -27,11 +27,11 @@ class CallbackAnimationObserver : public ui::ImplicitAnimationObserver {
: closure_(closure) {
}
- virtual ~CallbackAnimationObserver() {}
+ ~CallbackAnimationObserver() override {}
private:
// Overridden from ui::ImplicitAnimationObserver:
- virtual void OnImplicitAnimationsCompleted() OVERRIDE {
+ void OnImplicitAnimationsCompleted() override {
if (!closure_.is_null())
closure_.Run();
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
@@ -52,14 +52,14 @@ WindowSlider::WindowSlider(Delegate* delegate,
owner_(owner),
active_animator_(NULL),
delta_x_(0.f),
- weak_factory_(this),
active_start_threshold_(0.f),
start_threshold_touchscreen_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
start_threshold_touchpad_(content::GetOverscrollConfig(
content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD)),
complete_threshold_(content::GetOverscrollConfig(
- content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)) {
+ content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE)),
+ weak_factory_(this) {
event_window_->AddPreTargetHandler(this);
event_window_->AddObserver(this);
diff --git a/chromium/content/browser/web_contents/aura/window_slider.h b/chromium/content/browser/web_contents/aura/window_slider.h
index 83e56de330a..3263aadadf5 100644
--- a/chromium/content/browser/web_contents/aura/window_slider.h
+++ b/chromium/content/browser/web_contents/aura/window_slider.h
@@ -70,7 +70,7 @@ class CONTENT_EXPORT WindowSlider : public ui::EventHandler,
aura::Window* event_window,
aura::Window* owner);
- virtual ~WindowSlider();
+ ~WindowSlider() override;
// Changes the owner of the slider.
void ChangeOwner(aura::Window* new_owner);
@@ -105,14 +105,14 @@ class CONTENT_EXPORT WindowSlider : public ui::EventHandler,
scoped_ptr<ShadowLayerDelegate> shadow);
// Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
+ void OnKeyEvent(ui::KeyEvent* event) override;
+ void OnMouseEvent(ui::MouseEvent* event) override;
+ void OnScrollEvent(ui::ScrollEvent* event) override;
+ void OnGestureEvent(ui::GestureEvent* event) override;
// Overridden from aura::WindowObserver:
- virtual void OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) OVERRIDE;
+ void OnWindowRemovingFromRootWindow(aura::Window* window,
+ aura::Window* new_root) override;
Delegate* delegate_;
@@ -140,14 +140,14 @@ class CONTENT_EXPORT WindowSlider : public ui::EventHandler,
// This manages the shadow for the layers.
scoped_ptr<ShadowLayerDelegate> shadow_;
- base::WeakPtrFactory<WindowSlider> weak_factory_;
-
float active_start_threshold_;
const float start_threshold_touchscreen_;
const float start_threshold_touchpad_;
const float complete_threshold_;
+ base::WeakPtrFactory<WindowSlider> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(WindowSlider);
};
diff --git a/chromium/content/browser/web_contents/aura/window_slider_unittest.cc b/chromium/content/browser/web_contents/aura/window_slider_unittest.cc
index 4a2d0a56001..a1988d4990b 100644
--- a/chromium/content/browser/web_contents/aura/window_slider_unittest.cc
+++ b/chromium/content/browser/web_contents/aura/window_slider_unittest.cc
@@ -8,7 +8,6 @@
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
@@ -17,6 +16,7 @@
#include "ui/compositor/test/layer_animator_test_controller.h"
#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
+#include "ui/events/test/event_generator.h"
#include "ui/gfx/frame_time.h"
namespace content {
@@ -72,11 +72,11 @@ class NoEventWindowDelegate : public aura::test::TestWindowDelegate {
public:
NoEventWindowDelegate() {
}
- virtual ~NoEventWindowDelegate() {}
+ ~NoEventWindowDelegate() override {}
private:
// Overridden from aura::WindowDelegate:
- virtual bool HasHitTestMask() const OVERRIDE { return true; }
+ bool HasHitTestMask() const override { return true; }
DISALLOW_COPY_AND_ASSIGN(NoEventWindowDelegate);
};
@@ -92,7 +92,7 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate {
slide_aborted_(false),
slider_destroyed_(false) {
}
- virtual ~WindowSliderDelegateTest() {
+ ~WindowSliderDelegateTest() override {
// Make sure slide_completed() gets called if slide_completing() was called.
CHECK(!slide_completing_ || slide_completed_);
}
@@ -127,35 +127,29 @@ class WindowSliderDelegateTest : public WindowSlider::Delegate {
}
// Overridden from WindowSlider::Delegate:
- virtual ui::Layer* CreateBackLayer() OVERRIDE {
+ ui::Layer* CreateBackLayer() override {
if (!can_create_layer_)
return NULL;
created_back_layer_ = true;
return CreateLayerForTest();
}
- virtual ui::Layer* CreateFrontLayer() OVERRIDE {
+ ui::Layer* CreateFrontLayer() override {
if (!can_create_layer_)
return NULL;
created_front_layer_ = true;
return CreateLayerForTest();
}
- virtual void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) OVERRIDE {
+ void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override {
slide_completed_ = true;
}
- virtual void OnWindowSlideCompleting() OVERRIDE {
- slide_completing_ = true;
- }
+ void OnWindowSlideCompleting() override { slide_completing_ = true; }
- virtual void OnWindowSlideAborted() OVERRIDE {
- slide_aborted_ = true;
- }
+ void OnWindowSlideAborted() override { slide_aborted_ = true; }
- virtual void OnWindowSliderDestroyed() OVERRIDE {
- slider_destroyed_ = true;
- }
+ void OnWindowSliderDestroyed() override { slider_destroyed_ = true; }
private:
bool can_create_layer_;
@@ -175,11 +169,11 @@ class WindowSliderDeleteOwnerOnDestroy : public WindowSliderDelegateTest {
explicit WindowSliderDeleteOwnerOnDestroy(aura::Window* owner)
: owner_(owner) {
}
- virtual ~WindowSliderDeleteOwnerOnDestroy() {}
+ ~WindowSliderDeleteOwnerOnDestroy() override {}
private:
// Overridden from WindowSlider::Delegate:
- virtual void OnWindowSliderDestroyed() OVERRIDE {
+ void OnWindowSliderDestroyed() override {
WindowSliderDelegateTest::OnWindowSliderDestroyed();
delete owner_;
}
@@ -194,11 +188,11 @@ class WindowSliderDeleteOwnerOnComplete : public WindowSliderDelegateTest {
explicit WindowSliderDeleteOwnerOnComplete(aura::Window* owner)
: owner_(owner) {
}
- virtual ~WindowSliderDeleteOwnerOnComplete() {}
+ ~WindowSliderDeleteOwnerOnComplete() override {}
private:
// Overridden from WindowSlider::Delegate:
- virtual void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) OVERRIDE {
+ void OnWindowSlideCompleted(scoped_ptr<ui::Layer> layer) override {
WindowSliderDelegateTest::OnWindowSlideCompleted(layer.Pass());
delete owner_;
}
@@ -214,7 +208,7 @@ TEST_F(WindowSliderTest, WindowSlideUsingGesture) {
window->SetBounds(gfx::Rect(0, 0, 400, 400));
WindowSliderDelegateTest slider_delegate;
- aura::test::EventGenerator generator(root_window());
+ ui::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
WindowSlider* slider =
@@ -300,17 +294,14 @@ TEST_F(WindowSliderTest, WindowSlideIsCancelledOnEvent) {
gfx::Point(55, 10),
gfx::Point(55, 10),
0, 0),
- new ui::KeyEvent(ui::ET_KEY_PRESSED,
- ui::VKEY_A,
- 0,
- true),
+ new ui::KeyEvent('a', ui::VKEY_A, ui::EF_NONE),
NULL
};
new WindowSlider(&slider_delegate, root_window(), window.get());
for (int i = 0; events[i]; ++i) {
// Generate a horizontal overscroll.
- aura::test::EventGenerator generator(root_window());
+ ui::test::EventGenerator generator(root_window());
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
gfx::Point(80, 10),
@@ -352,7 +343,7 @@ TEST_F(WindowSliderTest, WindowSlideInterruptedThenContinues) {
gfx::Point(55, 10),
0, 0);
- aura::test::EventGenerator generator(root_window());
+ ui::test::EventGenerator generator(root_window());
// Start the scroll sequence. Scroll forward so that |window|'s layer is the
// one animating.
@@ -452,7 +443,7 @@ TEST_F(WindowSliderTest, OwnerWindowChangesDuringWindowSlide) {
// Generate a horizontal scroll, and change the owner in the middle of the
// scroll.
- aura::test::EventGenerator generator(root_window());
+ ui::test::EventGenerator generator(root_window());
aura::Window* old_window = window.get();
generator.GestureScrollSequenceWithCallback(
gfx::Point(10, 10),
@@ -484,7 +475,7 @@ TEST_F(WindowSliderTest, NoSlideWhenLayerCantBeCreated) {
WindowSlider* slider =
new WindowSlider(&slider_delegate, root_window(), window.get());
- aura::test::EventGenerator generator(root_window());
+ ui::test::EventGenerator generator(root_window());
// No slide in progress should be reported during scroll since the layer
// wasn't created.
@@ -530,7 +521,7 @@ TEST_F(WindowSliderTest, OwnerIsDestroyedOnSliderDestroy) {
EXPECT_EQ(child_windows + 1, root_window()->children().size());
WindowSliderDeleteOwnerOnDestroy slider_delegate(window);
- aura::test::EventGenerator generator(root_window());
+ ui::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
scoped_ptr<WindowSlider> slider(
@@ -561,7 +552,7 @@ TEST_F(WindowSliderTest, OwnerIsDestroyedOnSlideComplete) {
EXPECT_EQ(child_windows + 1, root_window()->children().size());
WindowSliderDeleteOwnerOnComplete slider_delegate(window);
- aura::test::EventGenerator generator(root_window());
+ ui::test::EventGenerator generator(root_window());
// Generate a horizontal overscroll.
new WindowSlider(&slider_delegate, root_window(), window);
@@ -592,13 +583,14 @@ TEST_F(WindowSliderTest, SwipeDuringSwipeAnimation) {
WindowSliderDelegateTest slider_delegate;
new WindowSlider(&slider_delegate, root_window(), window.get());
- ui::ScopedAnimationDurationScaleMode normal_duration_(
+ // This test uses explicit durations so needs a normal duration.
+ ui::ScopedAnimationDurationScaleMode normal_duration(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
ui::LayerAnimator* animator = window->layer()->GetAnimator();
animator->set_disable_timer_for_test(true);
ui::LayerAnimatorTestController test_controller(animator);
- aura::test::EventGenerator generator(root_window());
+ ui::test::EventGenerator generator(root_window());
// Swipe forward so that |window|'s layer is the one animating.
generator.GestureScrollSequence(
diff --git a/chromium/content/browser/web_contents/opened_by_dom_browsertest.cc b/chromium/content/browser/web_contents/opened_by_dom_browsertest.cc
index 1c2d94099ce..0a89f7189bd 100644
--- a/chromium/content/browser/web_contents/opened_by_dom_browsertest.cc
+++ b/chromium/content/browser/web_contents/opened_by_dom_browsertest.cc
@@ -28,7 +28,7 @@ class CloseTrackingDelegate : public WebContentsDelegate {
bool close_contents_called() const { return close_contents_called_; }
- virtual void CloseContents(WebContents* source) OVERRIDE {
+ void CloseContents(WebContents* source) override {
close_contents_called_ = true;
}
@@ -42,7 +42,7 @@ class CloseTrackingDelegate : public WebContentsDelegate {
class OpenedByDOMTest : public ContentBrowserTest {
protected:
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ void SetUpCommandLine(CommandLine* command_line) override {
// Use --site-per-process to force process swaps on cross-site navigations.
command_line->AppendSwitch(switches::kSitePerProcess);
}
@@ -114,7 +114,8 @@ IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, Popup) {
// Tests that window.close() works in a popup window that has navigated a few
// times and swapped processes.
-IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, CrossProcessPopup) {
+// Crashes on all platforms. http://crbug.com/399709
+IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, DISABLED_CrossProcessPopup) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
diff --git a/chromium/content/browser/web_contents/touch_editable_impl_aura.cc b/chromium/content/browser/web_contents/touch_editable_impl_aura.cc
index d28fa92deac..bef8ff7c6f9 100644
--- a/chromium/content/browser/web_contents/touch_editable_impl_aura.cc
+++ b/chromium/content/browser/web_contents/touch_editable_impl_aura.cc
@@ -10,13 +10,13 @@
#include "content/common/view_messages.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
-#include "grit/ui_strings.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/ui_base_switches_util.h"
#include "ui/gfx/range/range.h"
+#include "ui/strings/grit/ui_strings.h"
#include "ui/wm/public/activation_client.h"
namespace content {
@@ -61,26 +61,11 @@ void TouchEditableImplAura::UpdateEditingController() {
}
void TouchEditableImplAura::OverscrollStarted() {
- overscroll_in_progress_ = true;
+ scrolls_in_progress_++;
}
void TouchEditableImplAura::OverscrollCompleted() {
- // We might receive multiple OverscrollStarted() and OverscrollCompleted()
- // during the same scroll session (for example, when the scroll direction
- // changes). We want to show the handles only when:
- // 1. Overscroll has completed
- // 2. Scrolling session is over, i.e. we have received ET_GESTURE_SCROLL_END.
- // 3. If we had hidden the handles when scrolling started
- // 4. If there is still a need to show handles (there is a non-empty selection
- // or non-NONE |text_input_type_|)
- if (overscroll_in_progress_ && !scroll_in_progress_ &&
- handles_hidden_due_to_scroll_ &&
- (selection_anchor_rect_ != selection_focus_rect_ ||
- text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
- StartTouchEditing();
- UpdateEditingController();
- }
- overscroll_in_progress_ = false;
+ ScrollEnded();
}
////////////////////////////////////////////////////////////////////////////////
@@ -116,12 +101,10 @@ void TouchEditableImplAura::OnSelectionOrCursorChanged(const gfx::Rect& anchor,
selection_anchor_rect_ = anchor;
selection_focus_rect_ = focus;
- // If touch editing handles were not visible, we bring them up only if
- // there is non-zero selection on the page. And the current event is a
- // gesture event (we dont want to show handles if the user is selecting
- // using mouse or keyboard).
- if (selection_gesture_in_process_ && !scroll_in_progress_ &&
- !overscroll_in_progress_ &&
+ // If touch editing handles were not visible, we bring them up only if the
+ // current event is a gesture event, no scroll/fling/overscoll is in progress,
+ // and there is non-zero selection on the page
+ if (selection_gesture_in_process_ && !scrolls_in_progress_ &&
selection_anchor_rect_ != selection_focus_rect_) {
StartTouchEditing();
selection_gesture_in_process_ = false;
@@ -163,36 +146,29 @@ bool TouchEditableImplAura::HandleInputEvent(const ui::Event* event) {
}
// For single taps, not inside selected region, we want to show handles
// only when the tap is on an already focused textfield.
- textfield_was_focused_on_tap_ = false;
- if (gesture_event->details().tap_count() == 1 &&
- text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)
- textfield_was_focused_on_tap_ = true;
+ textfield_was_focused_on_tap_ =
+ gesture_event->details().tap_count() == 1 &&
+ text_input_type_ != ui::TEXT_INPUT_TYPE_NONE;
break;
case ui::ET_GESTURE_LONG_PRESS:
selection_gesture_in_process_ = true;
break;
case ui::ET_GESTURE_SCROLL_BEGIN:
- // If selection handles are currently visible, we want to get them back up
- // when scrolling ends. So we set |handles_hidden_due_to_scroll_| so that
- // we can re-start touch editing on scroll end gesture.
- scroll_in_progress_ = true;
- handles_hidden_due_to_scroll_ = false;
- if (touch_selection_controller_)
- handles_hidden_due_to_scroll_ = true;
+ scrolls_in_progress_++;
+ // We need to hide selection handles during scroll (including fling and
+ // overscroll), but they should be re-activated after scrolling if:
+ // - an existing scroll decided that handles should be shown after
+ // scrolling; or
+ // - the gesture in progress is going to end in selection; or
+ // - selection handles are currently active.
+ handles_hidden_due_to_scroll_ = handles_hidden_due_to_scroll_ ||
+ selection_gesture_in_process_ ||
+ touch_selection_controller_ != NULL;
+ selection_gesture_in_process_ = false;
EndTouchEditing(true);
break;
case ui::ET_GESTURE_SCROLL_END:
- // Scroll has ended, but we might still be in overscroll animation.
- if (handles_hidden_due_to_scroll_ && !overscroll_in_progress_ &&
- (selection_anchor_rect_ != selection_focus_rect_ ||
- text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
- StartTouchEditing();
- UpdateEditingController();
- }
- // fall through to reset |scroll_in_progress_|.
- case ui::ET_SCROLL_FLING_START:
- selection_gesture_in_process_ = false;
- scroll_in_progress_ = false;
+ ScrollEnded();
break;
default:
break;
@@ -210,6 +186,10 @@ void TouchEditableImplAura::GestureEventAck(int gesture_event_type) {
}
}
+void TouchEditableImplAura::DidStopFlinging() {
+ ScrollEnded();
+}
+
void TouchEditableImplAura::OnViewDestroyed() {
Cleanup();
}
@@ -280,7 +260,8 @@ void TouchEditableImplAura::OpenContextMenu(const gfx::Point& anchor) {
gfx::Point point = anchor;
ConvertPointFromScreen(&point);
RenderWidgetHost* host = rwhva_->GetRenderWidgetHost();
- host->Send(new ViewMsg_ShowContextMenu(host->GetRoutingID(), point));
+ host->Send(new ViewMsg_ShowContextMenu(
+ host->GetRoutingID(), ui::MENU_SOURCE_TOUCH_EDIT_MENU, point));
EndTouchEditing(false);
}
@@ -293,14 +274,15 @@ bool TouchEditableImplAura::IsCommandIdEnabled(int command_id) const {
if (!rwhva_)
return false;
bool editable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE;
+ bool readable = rwhva_->GetTextInputType() != ui::TEXT_INPUT_TYPE_PASSWORD;
gfx::Range selection_range;
rwhva_->GetSelectionRange(&selection_range);
bool has_selection = !selection_range.is_empty();
switch (command_id) {
case IDS_APP_CUT:
- return editable && has_selection;
+ return editable && readable && has_selection;
case IDS_APP_COPY:
- return has_selection;
+ return readable && has_selection;
case IDS_APP_PASTE: {
base::string16 result;
ui::Clipboard::GetForCurrentThread()->ReadText(
@@ -362,11 +344,23 @@ TouchEditableImplAura::TouchEditableImplAura()
rwhva_(NULL),
selection_gesture_in_process_(false),
handles_hidden_due_to_scroll_(false),
- scroll_in_progress_(false),
- overscroll_in_progress_(false),
+ scrolls_in_progress_(0),
textfield_was_focused_on_tap_(false) {
}
+void TouchEditableImplAura::ScrollEnded() {
+ scrolls_in_progress_--;
+ // If there is no scrolling left in progress, show selection handles if they
+ // were hidden due to scroll and there is a selection.
+ if (!scrolls_in_progress_ && handles_hidden_due_to_scroll_ &&
+ (selection_anchor_rect_ != selection_focus_rect_ ||
+ text_input_type_ != ui::TEXT_INPUT_TYPE_NONE)) {
+ StartTouchEditing();
+ UpdateEditingController();
+ handles_hidden_due_to_scroll_ = false;
+ }
+}
+
void TouchEditableImplAura::Cleanup() {
if (rwhva_) {
rwhva_->set_touch_editing_client(NULL);
@@ -376,8 +370,7 @@ void TouchEditableImplAura::Cleanup() {
EndTouchEditing(true);
selection_gesture_in_process_ = false;
handles_hidden_due_to_scroll_ = false;
- scroll_in_progress_ = false;
- overscroll_in_progress_ = false;
+ scrolls_in_progress_ = 0;
}
} // namespace content
diff --git a/chromium/content/browser/web_contents/touch_editable_impl_aura.h b/chromium/content/browser/web_contents/touch_editable_impl_aura.h
index dd19e8e4de6..050d559124b 100644
--- a/chromium/content/browser/web_contents/touch_editable_impl_aura.h
+++ b/chromium/content/browser/web_contents/touch_editable_impl_aura.h
@@ -28,7 +28,7 @@ class CONTENT_EXPORT TouchEditableImplAura
: public ui::TouchEditable,
public NON_EXPORTED_BASE(RenderWidgetHostViewAura::TouchEditingClient) {
public:
- virtual ~TouchEditableImplAura();
+ ~TouchEditableImplAura() override;
static TouchEditableImplAura* Create();
@@ -42,33 +42,32 @@ class CONTENT_EXPORT TouchEditableImplAura
void OverscrollCompleted();
// Overridden from RenderWidgetHostViewAura::TouchEditingClient.
- virtual void StartTouchEditing() OVERRIDE;
- virtual void EndTouchEditing(bool quick) OVERRIDE;
- virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
- const gfx::Rect& focus) OVERRIDE;
- virtual void OnTextInputTypeChanged(ui::TextInputType type) OVERRIDE;
- virtual bool HandleInputEvent(const ui::Event* event) OVERRIDE;
- virtual void GestureEventAck(int gesture_event_type) OVERRIDE;
- virtual void OnViewDestroyed() OVERRIDE;
+ void StartTouchEditing() override;
+ void EndTouchEditing(bool quick) override;
+ void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
+ const gfx::Rect& focus) override;
+ void OnTextInputTypeChanged(ui::TextInputType type) override;
+ bool HandleInputEvent(const ui::Event* event) override;
+ void GestureEventAck(int gesture_event_type) override;
+ void DidStopFlinging() override;
+ void OnViewDestroyed() override;
// Overridden from ui::TouchEditable:
- virtual void SelectRect(const gfx::Point& start,
- const gfx::Point& end) OVERRIDE;
- virtual void MoveCaretTo(const gfx::Point& point) OVERRIDE;
- virtual void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) OVERRIDE;
- virtual gfx::Rect GetBounds() OVERRIDE;
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual void ConvertPointToScreen(gfx::Point* point) OVERRIDE;
- virtual void ConvertPointFromScreen(gfx::Point* point) OVERRIDE;
- virtual bool DrawsHandles() OVERRIDE;
- virtual void OpenContextMenu(const gfx::Point& anchor) OVERRIDE;
- virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
- virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- ui::Accelerator* accelerator) OVERRIDE;
- virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
- virtual void DestroyTouchSelection() OVERRIDE;
+ void SelectRect(const gfx::Point& start, const gfx::Point& end) override;
+ void MoveCaretTo(const gfx::Point& point) override;
+ void GetSelectionEndPoints(gfx::Rect* p1, gfx::Rect* p2) override;
+ gfx::Rect GetBounds() override;
+ gfx::NativeView GetNativeView() const override;
+ void ConvertPointToScreen(gfx::Point* point) override;
+ void ConvertPointFromScreen(gfx::Point* point) override;
+ bool DrawsHandles() override;
+ void OpenContextMenu(const gfx::Point& anchor) override;
+ bool IsCommandIdChecked(int command_id) const override;
+ bool IsCommandIdEnabled(int command_id) const override;
+ bool GetAcceleratorForCommandId(int command_id,
+ ui::Accelerator* accelerator) override;
+ void ExecuteCommand(int command_id, int event_flags) override;
+ void DestroyTouchSelection() override;
protected:
TouchEditableImplAura();
@@ -76,6 +75,10 @@ class CONTENT_EXPORT TouchEditableImplAura
private:
friend class TouchEditableImplAuraTest;
+ // A convenience function that is called after scroll/fling/overscroll ends to
+ // re-activate touch selection if necessary.
+ void ScrollEnded();
+
void Cleanup();
// Rectangles for the selection anchor and focus.
@@ -96,11 +99,8 @@ class CONTENT_EXPORT TouchEditableImplAura
// whether to re-show handles after a scrolling session.
bool handles_hidden_due_to_scroll_;
- // Keeps track of when the user is scrolling.
- bool scroll_in_progress_;
-
- // Set to true when the page starts an overscroll.
- bool overscroll_in_progress_;
+ // Keeps track of number of scrolls/flings/overscrolls in progress.
+ int scrolls_in_progress_;
// Used to track if a textfield was focused when the current tap gesture
// happened.
diff --git a/chromium/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc b/chromium/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
index 9b4757f9c88..a35f28165b3 100644
--- a/chromium/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
+++ b/chromium/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
@@ -19,12 +19,12 @@
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/aura/test/event_generator.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ui_base_switches.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/event_utils.h"
+#include "ui/events/test/event_generator.h"
using blink::WebInputEvent;
@@ -36,24 +36,28 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
: selection_changed_callback_arrived_(false),
waiting_for_selection_changed_callback_(false),
waiting_for_gesture_ack_type_(WebInputEvent::Undefined),
- last_gesture_ack_type_(WebInputEvent::Undefined) {}
+ last_gesture_ack_type_(WebInputEvent::Undefined),
+ fling_stop_callback_arrived_(false),
+ waiting_for_fling_stop_callback_(false) {}
virtual void Reset() {
selection_changed_callback_arrived_ = false;
waiting_for_selection_changed_callback_ = false;
waiting_for_gesture_ack_type_ = WebInputEvent::Undefined;
last_gesture_ack_type_ = WebInputEvent::Undefined;
+ fling_stop_callback_arrived_ = false;
+ waiting_for_fling_stop_callback_ = false;
}
virtual void OnSelectionOrCursorChanged(const gfx::Rect& anchor,
- const gfx::Rect& focus) OVERRIDE {
+ const gfx::Rect& focus) override {
selection_changed_callback_arrived_ = true;
TouchEditableImplAura::OnSelectionOrCursorChanged(anchor, focus);
if (waiting_for_selection_changed_callback_)
selection_changed_wait_run_loop_->Quit();
}
- virtual void GestureEventAck(int gesture_event_type) OVERRIDE {
+ virtual void GestureEventAck(int gesture_event_type) override {
last_gesture_ack_type_ =
static_cast<WebInputEvent::Type>(gesture_event_type);
TouchEditableImplAura::GestureEventAck(gesture_event_type);
@@ -61,6 +65,13 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
gesture_ack_wait_run_loop_->Quit();
}
+ virtual void DidStopFlinging() override {
+ fling_stop_callback_arrived_ = true;
+ TouchEditableImplAura::DidStopFlinging();
+ if (waiting_for_fling_stop_callback_)
+ fling_stop_wait_run_loop_->Quit();
+ }
+
virtual void WaitForSelectionChangeCallback() {
if (selection_changed_callback_arrived_)
return;
@@ -77,6 +88,14 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
gesture_ack_wait_run_loop_->Run();
}
+ virtual void WaitForFlingStopCallback() {
+ if (fling_stop_callback_arrived_)
+ return;
+ waiting_for_fling_stop_callback_ = true;
+ fling_stop_wait_run_loop_.reset(new base::RunLoop());
+ fling_stop_wait_run_loop_->Run();
+ }
+
protected:
virtual ~TestTouchEditableImplAura() {}
@@ -85,8 +104,11 @@ class TestTouchEditableImplAura : public TouchEditableImplAura {
bool waiting_for_selection_changed_callback_;
WebInputEvent::Type waiting_for_gesture_ack_type_;
WebInputEvent::Type last_gesture_ack_type_;
+ bool fling_stop_callback_arrived_;
+ bool waiting_for_fling_stop_callback_;
scoped_ptr<base::RunLoop> selection_changed_wait_run_loop_;
scoped_ptr<base::RunLoop> gesture_ack_wait_run_loop_;
+ scoped_ptr<base::RunLoop> fling_stop_wait_run_loop_;
DISALLOW_COPY_AND_ASSIGN(TestTouchEditableImplAura);
};
@@ -96,7 +118,7 @@ class TouchEditableImplAuraTest : public ContentBrowserTest {
TouchEditableImplAuraTest() {}
protected:
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ virtual void SetUpCommandLine(CommandLine* command_line) override {
command_line->AppendSwitch(switches::kEnableTouchEditing);
}
@@ -149,7 +171,7 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
web_contents->GetRenderWidgetHostView());
aura::Window* content = web_contents->GetContentNativeView();
- aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ ui::test::EventGenerator generator(content->GetRootWindow(), content);
gfx::Rect bounds = content->GetBoundsInRootWindow();
touch_editable->Reset();
@@ -202,14 +224,12 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
// Long press to select word.
- ui::GestureEvent long_press(ui::ET_GESTURE_LONG_PRESS,
- 10,
- 10,
- 0,
- ui::EventTimeForNow(),
- ui::GestureEventDetails(
- ui::ET_GESTURE_LONG_PRESS, 0, 0),
- 1);
+ ui::GestureEvent long_press(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
touch_editable->Reset();
rwhva->OnGestureEvent(&long_press);
touch_editable->WaitForSelectionChangeCallback();
@@ -224,31 +244,83 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
EXPECT_STREQ("Some", selection.c_str());
// Start scrolling. Handles should get hidden.
- ui::GestureEvent scroll_begin(ui::ET_GESTURE_SCROLL_BEGIN,
- 10,
- 10,
- 0,
- ui::EventTimeForNow(),
- ui::GestureEventDetails(
- ui::ET_GESTURE_SCROLL_BEGIN, 0, 0),
- 1);
+ ui::GestureEvent scroll_begin(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
rwhva->OnGestureEvent(&scroll_begin);
EXPECT_FALSE(GetTouchSelectionController(touch_editable));
// Handles should come back after scroll ends.
- ui::GestureEvent scroll_end(ui::ET_GESTURE_SCROLL_END,
- 10,
- 10,
- 0,
- ui::EventTimeForNow(),
- ui::GestureEventDetails(
- ui::ET_GESTURE_SCROLL_END, 0, 0),
- 1);
+ ui::GestureEvent scroll_end(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
rwhva->OnGestureEvent(&scroll_end);
EXPECT_TRUE(GetTouchSelectionController(touch_editable));
}
IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
+ TestTouchSelectionReshownAfterFling) {
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ RenderFrameHost* main_frame = web_contents->GetMainFrame();
+ WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
+ web_contents->GetView());
+ TestTouchEditableImplAura* touch_editable = new TestTouchEditableImplAura;
+ view_aura->SetTouchEditableForTest(touch_editable);
+ RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+ web_contents->GetRenderWidgetHostView());
+ EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
+
+ // Long press to select word.
+ ui::GestureEvent long_press(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
+ touch_editable->Reset();
+ rwhva->OnGestureEvent(&long_press);
+ touch_editable->WaitForSelectionChangeCallback();
+
+ // Check if selection handles are showing.
+ EXPECT_TRUE(GetTouchSelectionController(touch_editable));
+
+ scoped_ptr<base::Value> value =
+ content::ExecuteScriptAndGetValue(main_frame, "get_selection()");
+ std::string selection;
+ value->GetAsString(&selection);
+ EXPECT_STREQ("Some", selection.c_str());
+
+ // Start scrolling. Handles should get hidden.
+ ui::GestureEvent scroll_begin(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
+ rwhva->OnGestureEvent(&scroll_begin);
+ EXPECT_FALSE(GetTouchSelectionController(touch_editable));
+
+ // Start a fling. Handles should come back after fling stops.
+ ui::GestureEvent fling_start(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_SCROLL_FLING_START, 1, 0));
+ rwhva->OnGestureEvent(&fling_start);
+ touch_editable->WaitForFlingStopCallback();
+ EXPECT_TRUE(GetTouchSelectionController(touch_editable));
+}
+
+IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
TouchSelectionOnLongPressTest) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
WebContentsImpl* web_contents =
@@ -263,14 +335,12 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
// Long press to select word.
- ui::GestureEvent long_press(ui::ET_GESTURE_LONG_PRESS,
- 10,
- 10,
- 0,
- ui::EventTimeForNow(),
- ui::GestureEventDetails(
- ui::ET_GESTURE_LONG_PRESS, 0, 0),
- 1);
+ ui::GestureEvent long_press(
+ 10,
+ 10,
+ 0,
+ ui::EventTimeForNow(),
+ ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
touch_editable->Reset();
rwhva->OnGestureEvent(&long_press);
touch_editable->WaitForSelectionChangeCallback();
@@ -300,13 +370,9 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
// Double-tap to select word.
- ui::GestureEvent double_tap(ui::ET_GESTURE_TAP,
- 10,
- 10,
- 0,
- ui::EventTimeForNow(),
- ui::GestureEventDetails(ui::ET_GESTURE_TAP, 2, 0),
- 1);
+ ui::GestureEventDetails details(ui::ET_GESTURE_TAP);
+ details.set_tap_count(2);
+ ui::GestureEvent double_tap(10, 10, 0, ui::EventTimeForNow(), details);
touch_editable->Reset();
rwhva->OnGestureEvent(&double_tap);
touch_editable->WaitForSelectionChangeCallback();
@@ -321,8 +387,14 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
EXPECT_STREQ("Some", selection.c_str());
}
+#if defined(OS_CHROMEOS)
+// http://crbug.com/396509
+#define MAYBE_TouchCursorInTextfieldTest DISABLED_TouchCursorInTextfieldTest
+#else
+#define MAYBE_TouchCursorInTextfieldTest TouchCursorInTextfieldTest
+#endif
IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
- TouchCursorInTextfieldTest) {
+ MAYBE_TouchCursorInTextfieldTest) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html"));
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
@@ -334,7 +406,7 @@ IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
web_contents->GetRenderWidgetHostView());
aura::Window* content = web_contents->GetContentNativeView();
- aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ ui::test::EventGenerator generator(content->GetRootWindow(), content);
gfx::Rect bounds = content->GetBoundsInRootWindow();
EXPECT_EQ(GetRenderWidgetHostViewAura(touch_editable), rwhva);
diff --git a/chromium/content/browser/web_contents/web_contents_android.cc b/chromium/content/browser/web_contents/web_contents_android.cc
index fb8c0db8aa5..85490c178b8 100644
--- a/chromium/content/browser/web_contents/web_contents_android.cc
+++ b/chromium/content/browser/web_contents/web_contents_android.cc
@@ -6,12 +6,43 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
+#include "base/command_line.h"
+#include "base/json/json_writer.h"
#include "base/logging.h"
+#include "content/browser/android/interstitial_page_delegate_android.h"
+#include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/media/android/browser_media_player_manager.h"
+#include "content/browser/media/media_web_contents_observer.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/frame_messages.h"
+#include "content/common/input_messages.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/web_contents.h"
+#include "content/public/common/content_switches.h"
#include "jni/WebContentsImpl_jni.h"
using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ScopedJavaGlobalRef;
+
+namespace {
+
+void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
+ const base::Value* result) {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ std::string json;
+ base::JSONWriter::Write(result, &json);
+ ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
+ content::Java_WebContentsImpl_onEvaluateJavaScriptResult(
+ env, j_json.obj(), callback.obj());
+}
+
+} // namespace
namespace content {
@@ -62,8 +93,307 @@ ScopedJavaLocalRef<jstring> WebContentsAndroid::GetTitle(
web_contents_->GetTitle());
}
+ScopedJavaLocalRef<jstring> WebContentsAndroid::GetVisibleURL(
+ JNIEnv* env, jobject obj) const {
+ return base::android::ConvertUTF8ToJavaString(
+ env, web_contents_->GetVisibleURL().spec());
+}
+
+bool WebContentsAndroid::IsLoading(JNIEnv* env, jobject obj) const {
+ return web_contents_->IsLoading();
+}
+
+bool WebContentsAndroid::IsLoadingToDifferentDocument(JNIEnv* env,
+ jobject obj) const {
+ return web_contents_->IsLoadingToDifferentDocument();
+}
+
void WebContentsAndroid::Stop(JNIEnv* env, jobject obj) {
web_contents_->Stop();
}
+void WebContentsAndroid::InsertCSS(
+ JNIEnv* env, jobject jobj, jstring jcss) {
+ web_contents_->InsertCSS(base::android::ConvertJavaStringToUTF8(env, jcss));
+}
+
+RenderWidgetHostViewAndroid*
+ WebContentsAndroid::GetRenderWidgetHostViewAndroid() {
+ RenderWidgetHostView* rwhv = NULL;
+ rwhv = web_contents_->GetRenderWidgetHostView();
+ if (web_contents_->ShowingInterstitialPage()) {
+ rwhv = static_cast<InterstitialPageImpl*>(
+ web_contents_->GetInterstitialPage())->
+ GetRenderViewHost()->GetView();
+ }
+ return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
+}
+
+jint WebContentsAndroid::GetBackgroundColor(JNIEnv* env, jobject obj) {
+ RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
+ if (!rwhva)
+ return SK_ColorWHITE;
+ return rwhva->GetCachedBackgroundColor();
+}
+
+ScopedJavaLocalRef<jstring> WebContentsAndroid::GetURL(JNIEnv* env,
+ jobject obj) const {
+ return ConvertUTF8ToJavaString(env, web_contents_->GetURL().spec());
+}
+
+jboolean WebContentsAndroid::IsIncognito(JNIEnv* env, jobject obj) {
+ return web_contents_->GetBrowserContext()->IsOffTheRecord();
+}
+
+void WebContentsAndroid::ResumeResponseDeferredAtStart(JNIEnv* env,
+ jobject obj) {
+ static_cast<WebContentsImpl*>(web_contents_)->ResumeResponseDeferredAtStart();
+}
+
+void WebContentsAndroid::SetHasPendingNavigationTransitionForTesting(
+ JNIEnv* env,
+ jobject obj) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
+ RenderFrameHost* frame =
+ static_cast<WebContentsImpl*>(web_contents_)->GetMainFrame();
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &TransitionRequestManager::AddPendingTransitionRequestDataForTesting,
+ base::Unretained(TransitionRequestManager::GetInstance()),
+ frame->GetProcess()->GetID(),
+ frame->GetRoutingID()));
+}
+
+void WebContentsAndroid::SetupTransitionView(JNIEnv* env,
+ jobject jobj,
+ jstring markup) {
+ web_contents_->GetMainFrame()->Send(new FrameMsg_SetupTransitionView(
+ web_contents_->GetMainFrame()->GetRoutingID(),
+ ConvertJavaStringToUTF8(env, markup)));
+}
+
+void WebContentsAndroid::BeginExitTransition(JNIEnv* env,
+ jobject jobj,
+ jstring css_selector) {
+ web_contents_->GetMainFrame()->Send(new FrameMsg_BeginExitTransition(
+ web_contents_->GetMainFrame()->GetRoutingID(),
+ ConvertJavaStringToUTF8(env, css_selector)));
+}
+
+void WebContentsAndroid::ClearNavigationTransitionData(JNIEnv* env,
+ jobject jobj) {
+ static_cast<WebContentsImpl*>(web_contents_)->ClearNavigationTransitionData();
+}
+
+void WebContentsAndroid::OnHide(JNIEnv* env, jobject obj) {
+ web_contents_->WasHidden();
+}
+
+void WebContentsAndroid::OnShow(JNIEnv* env, jobject obj) {
+ web_contents_->WasShown();
+}
+
+void WebContentsAndroid::ReleaseMediaPlayers(JNIEnv* env, jobject jobj) {
+#if defined(ENABLE_BROWSER_CDMS)
+ RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
+ web_contents_->GetRenderViewHost());
+ if (!rvhi || !rvhi->GetMainFrame())
+ return;
+
+ BrowserMediaPlayerManager* manager =
+ rvhi->media_web_contents_observer()->GetMediaPlayerManager(
+ rvhi->GetMainFrame());
+ if (manager)
+ manager->ReleaseAllMediaPlayers();
+#endif // defined(ENABLE_BROWSER_CDMS)
+}
+
+void WebContentsAndroid::AddStyleSheetByURL(
+ JNIEnv* env,
+ jobject obj,
+ jstring url) {
+ web_contents_->GetMainFrame()->Send(new FrameMsg_AddStyleSheetByURL(
+ web_contents_->GetMainFrame()->GetRoutingID(),
+ ConvertJavaStringToUTF8(env, url)));
+}
+
+void WebContentsAndroid::ShowInterstitialPage(
+ JNIEnv* env,
+ jobject obj,
+ jstring jurl,
+ jlong delegate_ptr) {
+ GURL url(base::android::ConvertJavaStringToUTF8(env, jurl));
+ InterstitialPageDelegateAndroid* delegate =
+ reinterpret_cast<InterstitialPageDelegateAndroid*>(delegate_ptr);
+ InterstitialPage* interstitial = InterstitialPage::Create(
+ web_contents_, false, url, delegate);
+ delegate->set_interstitial_page(interstitial);
+ interstitial->Show();
+}
+
+jboolean WebContentsAndroid::IsShowingInterstitialPage(JNIEnv* env,
+ jobject obj) {
+ return web_contents_->ShowingInterstitialPage();
+}
+
+jboolean WebContentsAndroid::IsRenderWidgetHostViewReady(
+ JNIEnv* env,
+ jobject obj) {
+ RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
+ return view && view->HasValidFrame();
+}
+
+void WebContentsAndroid::ExitFullscreen(JNIEnv* env, jobject obj) {
+ RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (!host)
+ return;
+ host->ExitFullscreen();
+}
+
+void WebContentsAndroid::UpdateTopControlsState(
+ JNIEnv* env,
+ jobject obj,
+ bool enable_hiding,
+ bool enable_showing,
+ bool animate) {
+ RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (!host)
+ return;
+ host->Send(new ViewMsg_UpdateTopControlsState(host->GetRoutingID(),
+ enable_hiding,
+ enable_showing,
+ animate));
+}
+
+void WebContentsAndroid::ShowImeIfNeeded(JNIEnv* env, jobject obj) {
+ RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (!host)
+ return;
+ host->Send(new ViewMsg_ShowImeIfNeeded(host->GetRoutingID()));
+}
+
+void WebContentsAndroid::ScrollFocusedEditableNodeIntoView(
+ JNIEnv* env,
+ jobject obj) {
+ RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (!host)
+ return;
+ host->Send(new InputMsg_ScrollFocusedEditableNodeIntoRect(
+ host->GetRoutingID(), gfx::Rect()));
+}
+
+void WebContentsAndroid::SelectWordAroundCaret(JNIEnv* env, jobject obj) {
+ RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (!host)
+ return;
+ host->SelectWordAroundCaret();
+}
+
+bool WebContentsAndroid::WillHandleDeferAfterResponseStarted() {
+ JNIEnv* env = AttachCurrentThread();
+ return Java_WebContentsImpl_willHandleDeferAfterResponseStarted(env,
+ obj_.obj());
+}
+
+void WebContentsAndroid::DidDeferAfterResponseStarted(
+ const TransitionLayerData& transition_data) {
+ JNIEnv* env = AttachCurrentThread();
+ std::vector<GURL> entering_stylesheets;
+ std::string transition_color;
+ if (transition_data.response_headers.get()) {
+ TransitionRequestManager::ParseTransitionStylesheetsFromHeaders(
+ transition_data.response_headers,
+ entering_stylesheets,
+ transition_data.request_url);
+
+ transition_data.response_headers->EnumerateHeader(
+ NULL, "X-Transition-Entering-Color", &transition_color);
+ }
+
+ ScopedJavaLocalRef<jstring> jstring_markup(
+ ConvertUTF8ToJavaString(env, transition_data.markup));
+
+ ScopedJavaLocalRef<jstring> jstring_css_selector(
+ ConvertUTF8ToJavaString(env, transition_data.css_selector));
+
+ ScopedJavaLocalRef<jstring> jstring_transition_color(
+ ConvertUTF8ToJavaString(env, transition_color));
+
+ Java_WebContentsImpl_didDeferAfterResponseStarted(
+ env,
+ obj_.obj(),
+ jstring_markup.obj(),
+ jstring_css_selector.obj(),
+ jstring_transition_color.obj());
+
+ std::vector<GURL>::const_iterator iter = entering_stylesheets.begin();
+ for (; iter != entering_stylesheets.end(); ++iter) {
+ ScopedJavaLocalRef<jstring> jstring_url(
+ ConvertUTF8ToJavaString(env, iter->spec()));
+ Java_WebContentsImpl_addEnteringStylesheetToTransition(
+ env, obj_.obj(), jstring_url.obj());
+ }
+}
+
+void WebContentsAndroid::DidStartNavigationTransitionForFrame(int64 frame_id) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_WebContentsImpl_didStartNavigationTransitionForFrame(
+ env, obj_.obj(), frame_id);
+}
+
+void WebContentsAndroid::EvaluateJavaScript(JNIEnv* env,
+ jobject obj,
+ jstring script,
+ jobject callback) {
+ RenderViewHost* rvh = web_contents_->GetRenderViewHost();
+ DCHECK(rvh);
+
+ if (!rvh->IsRenderViewLive()) {
+ if (!static_cast<WebContentsImpl*>(web_contents_)->
+ CreateRenderViewForInitialEmptyDocument()) {
+ LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
+ return;
+ }
+ }
+
+ if (!callback) {
+ // No callback requested.
+ web_contents_->GetMainFrame()->ExecuteJavaScript(
+ ConvertJavaStringToUTF16(env, script));
+ return;
+ }
+
+ // 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);
+ content::RenderFrameHost::JavaScriptResultCallback js_callback =
+ base::Bind(&JavaScriptResultCallback, j_callback);
+
+ web_contents_->GetMainFrame()->ExecuteJavaScript(
+ ConvertJavaStringToUTF16(env, script), js_callback);
+}
+
+// TODO(sgurun) add support for posting a frame whose name is known (only
+// main frame is supported at this time, see crbug.com/389721)
+// TODO(sgurun) add support for passing message ports
+void WebContentsAndroid::PostMessageToFrame(JNIEnv* env, jobject obj,
+ jstring frame_name, jstring message, jstring source_origin,
+ jstring target_origin) {
+
+ RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (!host)
+ return;
+ ViewMsg_PostMessage_Params params;
+ params.source_origin = ConvertJavaStringToUTF16(env, source_origin);
+ params.target_origin = ConvertJavaStringToUTF16(env, target_origin);
+ params.data = ConvertJavaStringToUTF16(env, message);
+ params.is_data_raw_string = true;
+ params.source_routing_id = MSG_ROUTING_NONE;
+ host->Send(new ViewMsg_PostMessageEvent(host->GetRoutingID(), params));
+}
+
} // namespace content
diff --git a/chromium/content/browser/web_contents/web_contents_android.h b/chromium/content/browser/web_contents/web_contents_android.h
index eec6127220a..4b79231c005 100644
--- a/chromium/content/browser/web_contents/web_contents_android.h
+++ b/chromium/content/browser/web_contents/web_contents_android.h
@@ -12,11 +12,14 @@
#include "base/compiler_specific.h"
#include "base/supports_user_data.h"
#include "content/browser/frame_host/navigation_controller_android.h"
+#include "content/browser/renderer_host/render_widget_host_view_android.h"
+#include "content/browser/transition_request_manager.h"
#include "content/common/content_export.h"
namespace content {
class WebContents;
+struct TransitionLayerData;
// Android wrapper around WebContents that provides safer passage from java and
// back to native and provides java with a means of communicating with its
@@ -36,9 +39,65 @@ class CONTENT_EXPORT WebContentsAndroid
// Methods called from Java
base::android::ScopedJavaLocalRef<jstring> GetTitle(JNIEnv* env,
jobject obj) const;
+ base::android::ScopedJavaLocalRef<jstring> GetVisibleURL(JNIEnv* env,
+ jobject obj) const;
+
+ bool IsLoading(JNIEnv* env, jobject obj) const;
+ bool IsLoadingToDifferentDocument(JNIEnv* env, jobject obj) const;
+
void Stop(JNIEnv* env, jobject obj);
+ jint GetBackgroundColor(JNIEnv* env, jobject obj);
+ base::android::ScopedJavaLocalRef<jstring> GetURL(JNIEnv* env, jobject) const;
+ jboolean IsIncognito(JNIEnv* env, jobject obj);
+
+ void ResumeResponseDeferredAtStart(JNIEnv* env, jobject obj);
+ void SetHasPendingNavigationTransitionForTesting(JNIEnv* env, jobject obj);
+ void SetupTransitionView(JNIEnv* env, jobject jobj, jstring markup);
+ void BeginExitTransition(JNIEnv* env, jobject jobj, jstring css_selector);
+ void ClearNavigationTransitionData(JNIEnv* env, jobject jobj);
+
+ // This method is invoked when the request is deferred immediately after
+ // receiving response headers.
+ void DidDeferAfterResponseStarted(const TransitionLayerData& transition_data);
+
+ // This method is invoked when a navigation transition is detected, to
+ // determine if the embedder intends to handle it.
+ bool WillHandleDeferAfterResponseStarted();
+ // This method is invoked when a navigation transition has started.
+ void DidStartNavigationTransitionForFrame(int64 frame_id);
+
+ void OnHide(JNIEnv* env, jobject obj);
+ void OnShow(JNIEnv* env, jobject obj);
+ void ReleaseMediaPlayers(JNIEnv* env, jobject jobj);
+
+ void AddStyleSheetByURL(
+ JNIEnv* env, jobject obj, jstring url);
+ void ShowInterstitialPage(
+ JNIEnv* env, jobject obj, jstring jurl, jlong delegate_ptr);
+ jboolean IsShowingInterstitialPage(JNIEnv* env, jobject obj);
+ jboolean IsRenderWidgetHostViewReady(JNIEnv* env, jobject obj);
+ void ExitFullscreen(JNIEnv* env, jobject obj);
+ void UpdateTopControlsState(
+ JNIEnv* env,
+ jobject obj,
+ bool enable_hiding,
+ bool enable_showing,
+ bool animate);
+ void ShowImeIfNeeded(JNIEnv* env, jobject obj);
+ void ScrollFocusedEditableNodeIntoView(JNIEnv* env, jobject obj);
+ void SelectWordAroundCaret(JNIEnv* env, jobject obj);
+
+ void InsertCSS(JNIEnv* env, jobject jobj, jstring jcss);
+ void EvaluateJavaScript(JNIEnv* env,
+ jobject obj,
+ jstring script,
+ jobject callback);
+ void PostMessageToFrame(JNIEnv* env, jobject obj, jstring frame_id,
+ jstring message, jstring source_origin, jstring target_origin);
private:
+ RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
+
WebContents* web_contents_;
NavigationControllerAndroid navigation_controller_;
base::android::ScopedJavaGlobalRef<jobject> obj_;
diff --git a/chromium/content/browser/web_contents/web_contents_impl.cc b/chromium/content/browser/web_contents/web_contents_impl.cc
index 817093a03f6..d3e8b13b9d3 100644
--- a/chromium/content/browser/web_contents/web_contents_impl.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl.cc
@@ -18,10 +18,12 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "content/browser/accessibility/accessibility_mode_helper.h"
+#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/browser_plugin/browser_plugin_embedder.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/devtools/render_view_devtools_agent_host.h"
+#include "content/browser/devtools/devtools_manager.h"
#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"
@@ -34,18 +36,23 @@
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
#include "content/browser/geolocation/geolocation_dispatcher_host.h"
+#include "content/browser/geolocation/geolocation_service_context.h"
#include "content/browser/host_zoom_map_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/manifest/manifest_manager_host.h"
+#include "content/browser/media/audio_stream_monitor.h"
+#include "content/browser/media/capture/web_contents_audio_muter.h"
#include "content/browser/media/midi_dispatcher_host.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/message_port_service.h"
+#include "content/browser/plugin_content_origin_whitelist.h"
#include "content/browser/power_save_blocker_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/browser/renderer_host/render_view_host_impl.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/screen_orientation/screen_orientation_dispatcher_host.h"
+#include "content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/web_contents/web_contents_view_guest.h"
#include "content/browser/webui/generic_handler.h"
@@ -72,7 +79,9 @@
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/resource_request_details.h"
+#include "content/public/browser/screen_orientation_dispatcher_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents_delegate.h"
@@ -84,6 +93,7 @@
#include "content/public/common/result_codes.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
+#include "content/public/common/web_preferences.h"
#include "net/base/mime_util.h"
#include "net/base/net_util.h"
#include "net/http/http_cache.h"
@@ -94,70 +104,17 @@
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
#include "ui/gl/gl_switches.h"
-#include "webkit/common/webpreferences.h"
#if defined(OS_ANDROID)
#include "content/browser/android/date_time_chooser_android.h"
#include "content/browser/media/android/browser_media_player_manager.h"
#include "content/browser/web_contents/web_contents_android.h"
-#include "content/public/browser/android/content_view_core.h"
#endif
#if defined(OS_MACOSX)
#include "base/mac/foundation_util.h"
#endif
-// Cross-Site Navigations
-//
-// If a WebContentsImpl is told to navigate to a different web site (as
-// determined by SiteInstance), it will replace its current RenderViewHost with
-// a new RenderViewHost dedicated to the new SiteInstance. This works as
-// follows:
-//
-// - RVHM::Navigate determines whether the destination is cross-site, and if so,
-// it creates a pending_render_view_host_.
-// - The pending RVH is "suspended," so that no navigation messages are sent to
-// its renderer until the beforeunload JavaScript handler has a chance to
-// run in the current RVH.
-// - The pending RVH tells CrossSiteRequestManager (a thread-safe singleton)
-// that it has a pending cross-site request. We will check this on the IO
-// thread when deciding how to handle the response.
-// - The current RVH runs its beforeunload handler. If it returns false, we
-// cancel all the pending logic. Otherwise we allow the pending RVH to send
-// the navigation request to its renderer.
-// - ResourceDispatcherHost receives a ResourceRequest on the IO thread for the
-// main resource load on the pending RVH. It creates a
-// CrossSiteResourceHandler to check whether a process swap is needed when
-// the request is ready to commit.
-// - When RDH receives a response, the BufferedResourceHandler determines
-// whether it is a download. If so, it sends a message to the new renderer
-// causing it to cancel the request, and the download proceeds. For now, the
-// pending RVH remains until the next DidNavigate event for this
-// WebContentsImpl. This isn't ideal, but it doesn't affect any functionality.
-// - After RDH receives a response and determines that it is safe and not a
-// download, the CrossSiteResourceHandler checks whether a process swap is
-// needed (either because CrossSiteRequestManager has state for it or because
-// a transfer was needed for a redirect).
-// - If so, CrossSiteResourceHandler pauses the response to first run the old
-// page's unload handler. It does this by asynchronously calling the
-// OnCrossSiteResponse method of RenderFrameHostManager on the UI thread,
-// which sends a SwapOut message to the current RVH.
-// - Once the unload handler is finished, RVHM::SwappedOut checks if a transfer
-// to a new process is needed, based on the stored pending_nav_params_. (This
-// is independent of whether we started out with a cross-process navigation.)
-// - If not, it just tells the ResourceDispatcherHost to resume the response
-// to its current RenderViewHost.
-// - If so, it cancels the current pending RenderViewHost and sets up a new
-// navigation using RequestTransferURL. When the transferred request
-// arrives in the ResourceDispatcherHost, we transfer the response and
-// resume it.
-// - The pending renderer sends a FrameNavigate message that invokes the
-// DidNavigate method. This replaces the current RVH with the
-// pending RVH.
-// - The previous renderer is kept swapped out in RenderFrameHostManager in case
-// the user goes back. The process only stays live if another tab is using
-// it, but if so, the existing frame relationships will be maintained.
-
namespace content {
namespace {
@@ -176,7 +133,7 @@ const char kWebContentsAndroidKey[] = "web_contents_android";
base::LazyInstance<std::vector<WebContentsImpl::CreatedCallback> >
g_created_callbacks = LAZY_INSTANCE_INITIALIZER;
-static int StartDownload(content::RenderFrameHost* rfh,
+static int StartDownload(RenderFrameHost* rfh,
const GURL& url,
bool is_favicon,
uint32_t max_bitmap_size) {
@@ -212,6 +169,16 @@ bool ForEachFrameInternal(
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(IPC::Message* message, RenderFrameHost* rfh) {
IPC::Message* message_copy = new IPC::Message(*message);
message_copy->set_routing_id(rfh->GetRoutingID());
@@ -227,6 +194,11 @@ void AddRenderWidgetHostViewToSet(std::set<RenderWidgetHostView*>* set,
set->insert(rwhv);
}
+void SetAccessibilityModeOnFrame(AccessibilityMode mode,
+ RenderFrameHost* frame_host) {
+ static_cast<RenderFrameHostImpl*>(frame_host)->SetAccessibilityMode(mode);
+}
+
} // namespace
WebContents* WebContents::Create(const WebContents::CreateParams& params) {
@@ -286,7 +258,7 @@ class WebContentsImpl::DestructionObserver : public WebContentsObserver {
}
// WebContentsObserver:
- virtual void WebContentsDestroyed() OVERRIDE {
+ void WebContentsDestroyed() override {
owner_->OnWebContentsDestroyed(
static_cast<WebContentsImpl*>(web_contents()));
}
@@ -312,9 +284,8 @@ WebContentsImpl::ColorChooserInfo::~ColorChooserInfo() {
// WebContentsImpl -------------------------------------------------------------
-WebContentsImpl::WebContentsImpl(
- BrowserContext* browser_context,
- WebContentsImpl* opener)
+WebContentsImpl::WebContentsImpl(BrowserContext* browser_context,
+ WebContentsImpl* opener)
: delegate_(NULL),
controller_(this, browser_context),
render_view_host_delegate_view_(NULL),
@@ -324,7 +295,10 @@ WebContentsImpl::WebContentsImpl(
accessible_parent_(NULL),
#endif
frame_tree_(new NavigatorImpl(&controller_, this),
- this, this, this, this),
+ this,
+ this,
+ this,
+ this),
is_loading_(false),
is_load_to_different_document_(false),
crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING),
@@ -332,7 +306,6 @@ WebContentsImpl::WebContentsImpl(
waiting_for_response_(false),
load_state_(net::LOAD_STATE_IDLE, base::string16()),
loading_total_progress_(0.0),
- loading_weak_factory_(this),
loading_frames_in_progress_(0),
upload_size_(0),
upload_position_(0),
@@ -352,9 +325,15 @@ WebContentsImpl::WebContentsImpl(
currentPinchZoomStepDelta_(0),
render_view_message_source_(NULL),
fullscreen_widget_routing_id_(MSG_ROUTING_NONE),
+ fullscreen_widget_had_focus_at_shutdown_(false),
is_subframe_(false),
- touch_emulation_enabled_(false),
- last_dialog_suppressed_(false) {
+ force_disable_overscroll_content_(false),
+ last_dialog_suppressed_(false),
+ geolocation_service_context_(new GeolocationServiceContext()),
+ accessibility_mode_(
+ BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()),
+ audio_stream_monitor_(this),
+ loading_weak_factory_(this) {
for (size_t i = 0; i < g_created_callbacks.Get().size(); i++)
g_created_callbacks.Get().at(i).Run(this);
frame_tree_.SetFrameRemoveListener(
@@ -439,17 +418,10 @@ WebContentsImpl* WebContentsImpl::CreateWithOpener(
WebContentsImpl* new_contents = new WebContentsImpl(
params.browser_context, params.opener_suppressed ? NULL : opener);
- if (params.guest_instance_id) {
- scoped_ptr<base::DictionaryValue> extra_params;
- if (params.guest_extra_params)
- extra_params.reset(params.guest_extra_params->DeepCopy());
+ if (params.guest_delegate) {
// This makes |new_contents| act as a guest.
// For more info, see comment above class BrowserPluginGuest.
- BrowserPluginGuest::Create(params.guest_instance_id,
- params.site_instance,
- new_contents,
- extra_params.Pass(),
- opener ? opener->GetBrowserPluginGuest() : NULL);
+ BrowserPluginGuest::Create(new_contents, params.guest_delegate);
// We are instantiating a WebContents for browser plugin. Set its subframe
// bit to true.
new_contents->is_subframe_ = true;
@@ -458,6 +430,30 @@ WebContentsImpl* WebContentsImpl::CreateWithOpener(
return new_contents;
}
+// static
+std::vector<WebContentsImpl*> WebContentsImpl::GetAllWebContents() {
+ std::vector<WebContentsImpl*> result;
+ scoped_ptr<RenderWidgetHostIterator> widgets(
+ RenderWidgetHostImpl::GetRenderWidgetHosts());
+ std::set<WebContentsImpl*> web_contents_set;
+ while (RenderWidgetHost* rwh = widgets->GetNextHost()) {
+ if (!rwh->IsRenderView())
+ continue;
+ RenderViewHost* rvh = RenderViewHost::From(rwh);
+ if (!rvh)
+ continue;
+ WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
+ if (!web_contents)
+ continue;
+ WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents);
+ if (web_contents_set.find(wci) == web_contents_set.end()) {
+ web_contents_set.insert(wci);
+ result.push_back(wci);
+ }
+ }
+ return result;
+}
+
RenderFrameHostManager* WebContentsImpl::GetRenderManagerForTesting() {
return GetRenderManager();
}
@@ -491,22 +487,13 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
// Message handlers should be aware of which
// RenderViewHost/RenderFrameHost sent the message, which is temporarily
// stored in render_(view|frame)_message_source_.
- if (render_frame_host) {
- if (RenderViewDevToolsAgentHost::DispatchIPCMessage(
- render_frame_host->GetRenderViewHost(), message))
- return true;
+ if (render_frame_host)
render_frame_message_source_ = render_frame_host;
- } else {
- if (RenderViewDevToolsAgentHost::DispatchIPCMessage(
- render_view_host, message))
- return true;
+ else
render_view_message_source_ = render_view_host;
- }
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebContentsImpl, message)
- IPC_MESSAGE_HANDLER(FrameHostMsg_PepperPluginHung, OnPepperPluginHung)
- IPC_MESSAGE_HANDLER(FrameHostMsg_PluginCrashed, OnPluginCrashed)
IPC_MESSAGE_HANDLER(FrameHostMsg_DomOperationResponse,
OnDomOperationResponse)
IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeThemeColor,
@@ -526,6 +513,8 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
OnMediaPlayingNotification)
IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification,
OnMediaPausedNotification)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_DidFirstVisuallyNonEmptyPaint,
+ OnFirstVisuallyNonEmptyPaint)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidLoadResourceFromMemoryCache,
OnDidLoadResourceFromMemoryCache)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidDisplayInsecureContent,
@@ -537,17 +526,21 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
IPC_MESSAGE_HANDLER(ViewHostMsg_EnumerateDirectory, OnEnumerateDirectory)
IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterProtocolHandler,
OnRegisterProtocolHandler)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UnregisterProtocolHandler,
+ OnUnregisterProtocolHandler)
IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnFindReply)
IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed)
IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend)
+#if defined(ENABLE_PLUGINS)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_PepperPluginHung, OnPepperPluginHung)
+ IPC_MESSAGE_HANDLER(FrameHostMsg_PluginCrashed, OnPluginCrashed)
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestPpapiBrokerPermission,
OnRequestPpapiBrokerPermission)
IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_Attach,
OnBrowserPluginMessage(message))
+#endif
IPC_MESSAGE_HANDLER(ImageHostMsg_DidDownloadImage, OnDidDownloadImage)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
- IPC_MESSAGE_HANDLER(ViewHostMsg_DidFirstVisuallyNonEmptyPaint,
- OnFirstVisuallyNonEmptyPaint)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowValidationMessage,
OnShowValidationMessage)
IPC_MESSAGE_HANDLER(ViewHostMsg_HideValidationMessage,
@@ -680,6 +673,32 @@ WebContentsView* WebContentsImpl::GetView() const {
return view_.get();
}
+void WebContentsImpl::SetAccessibilityMode(AccessibilityMode mode) {
+ if (mode == accessibility_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)));
+}
+
+void WebContentsImpl::AddAccessibilityMode(AccessibilityMode mode) {
+ SetAccessibilityMode(AddAccessibilityModeTo(accessibility_mode_, mode));
+}
+
+void WebContentsImpl::RemoveAccessibilityMode(AccessibilityMode mode) {
+ SetAccessibilityMode(RemoveAccessibilityModeFrom(accessibility_mode_, mode));
+}
+
+void WebContentsImpl::ClearNavigationTransitionData() {
+ FrameTreeNode* node = frame_tree_.root();
+ node->render_manager()->ClearNavigationTransitionData();
+}
+
WebUI* WebContentsImpl::CreateWebUI(const GURL& url) {
WebUIImpl* web_ui = new WebUIImpl(this);
WebUIController* controller = WebUIControllerFactoryRegistry::GetInstance()->
@@ -728,12 +747,25 @@ const std::string& WebContentsImpl::GetUserAgentOverride() const {
return renderer_preferences_.user_agent_override;
}
+void WebContentsImpl::EnableTreeOnlyAccessibilityMode() {
+ AddAccessibilityMode(AccessibilityModeTreeOnly);
+}
+
+bool WebContentsImpl::IsTreeOnlyAccessibilityModeForTesting() const {
+ return accessibility_mode_ == AccessibilityModeTreeOnly;
+}
+
+bool WebContentsImpl::IsFullAccessibilityModeForTesting() const {
+ return accessibility_mode_ == AccessibilityModeComplete;
+}
+
#if defined(OS_WIN)
void WebContentsImpl::SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) {
accessible_parent_ = accessible_parent;
- if (GetRenderViewHost())
- GetRenderViewHostImpl()->SetParentNativeViewAccessible(accessible_parent);
+ RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
+ if (rfh)
+ rfh->SetParentNativeViewAccessible(accessible_parent);
}
#endif
@@ -819,14 +851,15 @@ void WebContentsImpl::CopyMaxPageIDsFrom(WebContents* web_contents) {
max_page_ids_ = contents->max_page_ids_;
}
-SiteInstance* WebContentsImpl::GetSiteInstance() const {
+SiteInstanceImpl* WebContentsImpl::GetSiteInstance() const {
return GetRenderManager()->current_host()->GetSiteInstance();
}
-SiteInstance* WebContentsImpl::GetPendingSiteInstance() const {
- RenderViewHost* dest_rvh = GetRenderManager()->pending_render_view_host() ?
- GetRenderManager()->pending_render_view_host() :
- GetRenderManager()->current_host();
+SiteInstanceImpl* WebContentsImpl::GetPendingSiteInstance() const {
+ RenderViewHostImpl* dest_rvh =
+ GetRenderManager()->pending_render_view_host() ?
+ GetRenderManager()->pending_render_view_host() :
+ GetRenderManager()->current_host();
return dest_rvh->GetSiteInstance();
}
@@ -913,6 +946,30 @@ int WebContentsImpl::GetCapturerCount() const {
return capturer_count_;
}
+bool WebContentsImpl::IsAudioMuted() const {
+ return audio_muter_.get() && audio_muter_->is_muting();
+}
+
+void WebContentsImpl::SetAudioMuted(bool mute) {
+ DVLOG(1) << "SetAudioMuted(mute=" << mute << "), was " << IsAudioMuted()
+ << " for WebContentsImpl@" << this;
+
+ if (mute == IsAudioMuted())
+ return;
+
+ if (mute) {
+ if (!audio_muter_)
+ audio_muter_.reset(new WebContentsAudioMuter(this));
+ audio_muter_->StartMuting();
+ } else {
+ DCHECK(audio_muter_);
+ audio_muter_->StopMuting();
+ }
+
+ // Notification for UI updates in response to the changed muting state.
+ NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+}
+
bool WebContentsImpl::IsCrashed() const {
return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED ||
crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
@@ -937,7 +994,20 @@ bool WebContentsImpl::IsBeingDestroyed() const {
return is_being_destroyed_;
}
-void WebContentsImpl::NotifyNavigationStateChanged(unsigned changed_flags) {
+void WebContentsImpl::NotifyNavigationStateChanged(
+ InvalidateTypes changed_flags) {
+ // Create and release the audio power save blocker depending on whether the
+ // tab is actively producing audio or not.
+ if (changed_flags == INVALIDATE_TYPE_TAB &&
+ AudioStreamMonitor::monitoring_available()) {
+ if (WasRecentlyAudible()) {
+ if (!audio_power_save_blocker_)
+ CreateAudioPowerSaveBlocker();
+ } else {
+ audio_power_save_blocker_.reset();
+ }
+ }
+
if (delegate_)
delegate_->NavigationStateChanged(this, changed_flags);
}
@@ -971,6 +1041,10 @@ void WebContentsImpl::WasShown() {
rvh->ResizeRectChanged(GetRootWindowResizerRect());
}
+ // Restore power save blocker if there are active video players running.
+ if (!active_video_players_.empty() && !video_power_save_blocker_)
+ CreateVideoPowerSaveBlocker();
+
FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasShown());
should_normally_be_visible_ = true;
@@ -993,6 +1067,9 @@ void WebContentsImpl::WasHidden() {
if (*iter)
(*iter)->Hide();
}
+
+ // Release any video power save blockers held as video is not visible.
+ video_power_save_blocker_.reset();
}
FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden());
@@ -1038,11 +1115,21 @@ void WebContentsImpl::Observe(int type,
switch (type) {
case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
RenderWidgetHost* host = Source<RenderWidgetHost>(source).ptr();
- for (PendingWidgetViews::iterator i = pending_widget_views_.begin();
- i != pending_widget_views_.end(); ++i) {
- if (host->GetView() == i->second) {
- pending_widget_views_.erase(i);
- break;
+ RenderWidgetHostView* view = host->GetView();
+ if (view == GetFullscreenRenderWidgetHostView()) {
+ // We cannot just call view_->RestoreFocus() here. On some platforms,
+ // attempting to focus the currently-invisible WebContentsView will be
+ // flat-out ignored. Therefore, this boolean is used to track whether
+ // we will request focus after the fullscreen widget has been
+ // destroyed.
+ fullscreen_widget_had_focus_at_shutdown_ = (view && view->HasFocus());
+ } else {
+ for (PendingWidgetViews::iterator i = pending_widget_views_.begin();
+ i != pending_widget_views_.end(); ++i) {
+ if (host->GetView() == i->second) {
+ pending_widget_views_.erase(i);
+ break;
+ }
}
}
break;
@@ -1093,6 +1180,11 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
if (opener_)
AddDestructionObserver(opener_);
+#if defined(ENABLE_PLUGINS)
+ plugin_content_origin_whitelist_.reset(
+ new PluginContentOriginWhitelist(this));
+#endif
+
registrar_.Add(this,
NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
NotificationService::AllBrowserContextsAndSources());
@@ -1101,7 +1193,9 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params) {
midi_dispatcher_host_.reset(new MidiDispatcherHost(this));
screen_orientation_dispatcher_host_.reset(
- new ScreenOrientationDispatcherHost(this));
+ new ScreenOrientationDispatcherHostImpl(this));
+
+ manifest_manager_host_.reset(new ManifestManagerHost(this));
#if defined(OS_ANDROID)
date_time_chooser_.reset(new DateTimeChooserAndroid());
@@ -1200,9 +1294,20 @@ void WebContentsImpl::RenderWidgetDeleted(
DidDestroyFullscreenWidget(
fullscreen_widget_routing_id_));
fullscreen_widget_routing_id_ = MSG_ROUTING_NONE;
+ if (fullscreen_widget_had_focus_at_shutdown_)
+ view_->RestoreFocus();
}
}
+void WebContentsImpl::RenderWidgetGotFocus(
+ RenderWidgetHostImpl* render_widget_host) {
+ // Notify the delegate if an embedded fullscreen widget was focused.
+ if (delegate_ && render_widget_host &&
+ delegate_->EmbedsFullscreenWidget() &&
+ render_widget_host->GetView() == GetFullscreenRenderWidgetHostView())
+ delegate_->WebContentsFocused(this);
+}
+
bool WebContentsImpl::PreHandleKeyboardEvent(
const NativeWebKeyboardEvent& event,
bool* is_keyboard_shortcut) {
@@ -1211,6 +1316,10 @@ bool WebContentsImpl::PreHandleKeyboardEvent(
}
void WebContentsImpl::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
+ if (browser_plugin_embedder_ &&
+ browser_plugin_embedder_->HandleKeyboardEvent(event)) {
+ return;
+ }
if (delegate_)
delegate_->HandleKeyboardEvent(this, event);
}
@@ -1282,12 +1391,6 @@ bool WebContentsImpl::HandleGestureEvent(
return false;
}
-#if defined(OS_WIN)
-gfx::NativeViewAccessible WebContentsImpl::GetParentNativeViewAccessible() {
- return accessible_parent_;
-}
-#endif
-
void WebContentsImpl::HandleMouseDown() {
if (delegate_)
delegate_->HandleMouseDown();
@@ -1378,7 +1481,7 @@ void WebContentsImpl::CreateNewWindow(
if (process_handle != base::kNullProcessHandle) {
RecordAction(
base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWindow"));
- base::KillProcess(process_handle, content::RESULT_CODE_KILLED, false);
+ base::KillProcess(process_handle, RESULT_CODE_KILLED, false);
}
return;
}
@@ -1428,15 +1531,15 @@ void WebContentsImpl::CreateNewWindow(
if (params.disposition == NEW_BACKGROUND_TAB)
create_params.initially_hidden = true;
+ WebContentsImpl* new_contents = NULL;
if (!is_guest) {
create_params.context = view_->GetNativeView();
create_params.initial_size = GetContainerBounds().size();
- } else {
- create_params.guest_instance_id =
- GetBrowserContext()->GetGuestManager()->GetNextInstanceID();
+ new_contents = static_cast<WebContentsImpl*>(
+ WebContents::Create(create_params));
+ } else {
+ new_contents = GetBrowserPluginGuest()->CreateNewGuestWindow(create_params);
}
- WebContentsImpl* new_contents = static_cast<WebContentsImpl*>(
- WebContents::Create(create_params));
new_contents->GetController().SetSessionStorageNamespace(
partition_id,
session_storage_namespace);
@@ -1450,7 +1553,7 @@ void WebContentsImpl::CreateNewWindow(
// TODO(brettw): It seems bogus that we have to call this function on the
// newly created object and give it one of its own member variables.
- new_view->CreateViewForWidget(new_contents->GetRenderViewHost());
+ new_view->CreateViewForWidget(new_contents->GetRenderViewHost(), false);
}
// Save the created window associated with the route so we can show it
// later.
@@ -1479,7 +1582,7 @@ void WebContentsImpl::CreateNewWindow(
OpenURLParams open_params(params.target_url,
Referrer(),
CURRENT_TAB,
- PAGE_TRANSITION_LINK,
+ ui::PAGE_TRANSITION_LINK,
true /* is_renderer_initiated */);
open_params.user_gesture = params.user_gesture;
new_contents->OpenURL(open_params);
@@ -1512,7 +1615,7 @@ void WebContentsImpl::CreateNewWidget(int render_process_id,
if (process_handle != base::kNullProcessHandle) {
RecordAction(
base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWidget"));
- base::KillProcess(process_handle, content::RESULT_CODE_KILLED, false);
+ base::KillProcess(process_handle, RESULT_CODE_KILLED, false);
}
return;
}
@@ -1581,6 +1684,7 @@ void WebContentsImpl::ShowCreatedWidget(int route_id,
if (is_fullscreen) {
DCHECK_EQ(MSG_ROUTING_NONE, fullscreen_widget_routing_id_);
+ view_->StoreFocus();
fullscreen_widget_routing_id_ = route_id;
if (delegate_ && delegate_->EmbedsFullscreenWidget()) {
widget_host_view->InitAsChild(GetRenderWidgetHostView()->GetNativeView());
@@ -1633,8 +1737,11 @@ WebContentsImpl* WebContentsImpl::GetCreatedWindow(int route_id) {
!new_contents->GetRenderViewHost()->GetView())
return NULL;
+ // Resume blocked requests for both the RenderViewHost and RenderFrameHost.
// TODO(brettw): It seems bogus to reach into here and initialize the host.
static_cast<RenderViewHostImpl*>(new_contents->GetRenderViewHost())->Init();
+ static_cast<RenderFrameHostImpl*>(new_contents->GetMainFrame())->Init();
+
return new_contents;
}
@@ -1664,11 +1771,19 @@ void WebContentsImpl::RequestMediaAccessPermission(
delegate_->RequestMediaAccessPermission(this, request, callback);
} else {
callback.Run(MediaStreamDevices(),
- MEDIA_DEVICE_INVALID_STATE,
+ MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
scoped_ptr<MediaStreamUI>());
}
}
+bool WebContentsImpl::CheckMediaAccessPermission(const GURL& security_origin,
+ MediaStreamType type) {
+ DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ type == MEDIA_DEVICE_VIDEO_CAPTURE);
+ return delegate_ &&
+ delegate_->CheckMediaAccessPermission(this, security_origin, type);
+}
+
SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace(
SiteInstance* instance) {
return controller_.GetSessionStorageNamespace(instance);
@@ -1682,12 +1797,31 @@ FrameTree* WebContentsImpl::GetFrameTree() {
return &frame_tree_;
}
+AccessibilityMode WebContentsImpl::GetAccessibilityMode() const {
+ return accessibility_mode_;
+}
+
void WebContentsImpl::AccessibilityEventReceived(
const std::vector<AXEventNotificationDetails>& details) {
FOR_EACH_OBSERVER(
WebContentsObserver, observers_, AccessibilityEventReceived(details));
}
+RenderFrameHost* WebContentsImpl::GetGuestByInstanceID(
+ int browser_plugin_instance_id) {
+ BrowserPluginGuestManager* guest_manager =
+ GetBrowserContext()->GetGuestManager();
+ WebContents* guest = guest_manager->GetGuestByInstanceID(
+ this, browser_plugin_instance_id);
+ if (!guest)
+ return NULL;
+ return guest->GetMainFrame();
+}
+
+GeolocationServiceContext* WebContentsImpl::GetGeolocationServiceContext() {
+ return geolocation_service_context_.get();
+}
+
void WebContentsImpl::OnShowValidationMessage(
const gfx::Rect& anchor_in_root_view,
const base::string16& main_text,
@@ -1713,10 +1847,16 @@ void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) {
browser_plugin_embedder_->DidSendScreenRects();
}
-void WebContentsImpl::OnTouchEmulationEnabled(bool enabled) {
- touch_emulation_enabled_ = enabled;
- if (view_)
- view_->SetOverscrollControllerEnabled(CanOverscrollContent());
+BrowserAccessibilityManager*
+ WebContentsImpl::GetRootBrowserAccessibilityManager() {
+ RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
+ return rfh ? rfh->browser_accessibility_manager() : NULL;
+}
+
+BrowserAccessibilityManager*
+ WebContentsImpl::GetOrCreateRootBrowserAccessibilityManager() {
+ RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
+ return rfh ? rfh->GetOrCreateBrowserAccessibilityManager() : NULL;
}
void WebContentsImpl::UpdatePreferredSize(const gfx::Size& pref_size) {
@@ -1751,13 +1891,16 @@ bool WebContentsImpl::NavigateToPendingEntry(
NavigationController::ReloadType reload_type) {
FrameTreeNode* node = frame_tree_.root();
- // If we are using --site-per-process, we should navigate in the FrameTreeNode
- // specified in the pending entry.
+ // Navigate in the FrameTreeNode specified in the pending entry, if any. This
+ // is currently only used in --site-per-process and tests.
NavigationEntryImpl* pending_entry =
NavigationEntryImpl::FromNavigationEntry(controller_.GetPendingEntry());
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
- pending_entry->frame_tree_node_id() != -1) {
- node = frame_tree_.FindByID(pending_entry->frame_tree_node_id());
+ if (pending_entry->frame_tree_node_id() != -1) {
+ FrameTreeNode* subframe =
+ frame_tree_.FindByID(pending_entry->frame_tree_node_id());
+ DCHECK(subframe);
+ if (subframe)
+ node = subframe;
}
return node->navigator()->NavigateToPendingEntry(
@@ -2003,6 +2146,12 @@ void WebContentsImpl::FocusThroughTabTraversal(bool reverse) {
GetRenderManager()->interstitial_page()->FocusThroughTabTraversal(reverse);
return;
}
+ RenderWidgetHostView* const fullscreen_view =
+ GetFullscreenRenderWidgetHostView();
+ if (fullscreen_view) {
+ fullscreen_view->Focus();
+ return;
+ }
GetRenderViewHostImpl()->SetInitialFocus(reverse);
}
@@ -2176,18 +2325,6 @@ bool WebContentsImpl::GetClosedByUserGesture() const {
return closed_by_user_gesture_;
}
-int WebContentsImpl::GetZoomPercent(bool* enable_increment,
- bool* enable_decrement) const {
- *enable_decrement = *enable_increment = false;
- // Calculate the zoom percent from the factor. Round up to the nearest whole
- // number.
- int percent = static_cast<int>(
- ZoomLevelToZoomFactor(HostZoomMap::GetZoomLevel(this)) * 100 + 0.5);
- *enable_decrement = percent > minimum_zoom_percent_;
- *enable_increment = percent < maximum_zoom_percent_;
- return percent;
-}
-
void WebContentsImpl::ViewSource() {
if (!delegate_)
return;
@@ -2274,6 +2411,11 @@ bool WebContentsImpl::IsSubframe() const {
void WebContentsImpl::Find(int request_id,
const base::string16& search_text,
const blink::WebFindOptions& options) {
+ // See if a top level browser plugin handles the find request first.
+ if (browser_plugin_embedder_ &&
+ browser_plugin_embedder_->Find(request_id, search_text, options)) {
+ return;
+ }
Send(new ViewMsg_Find(GetRoutingID(), request_id, search_text, options));
}
@@ -2286,6 +2428,14 @@ void WebContentsImpl::InsertCSS(const std::string& css) {
GetMainFrame()->GetRoutingID(), css));
}
+bool WebContentsImpl::WasRecentlyAudible() {
+ return audio_stream_monitor_.WasRecentlyAudible();
+}
+
+void WebContentsImpl::GetManifest(const GetManifestCallback& callback) {
+ manifest_manager_host_->GetManifest(GetMainFrame(), callback);
+}
+
bool WebContentsImpl::FocusLocationBarByDefault() {
NavigationEntry* entry = controller_.GetVisibleEntry();
if (entry && entry->GetURL() == GURL(url::kAboutBlankURL))
@@ -2300,47 +2450,36 @@ void WebContentsImpl::SetFocusToLocationBar(bool select_all) {
void WebContentsImpl::DidStartProvisionalLoad(
RenderFrameHostImpl* render_frame_host,
- int parent_routing_id,
const GURL& validated_url,
bool is_error_page,
bool is_iframe_srcdoc) {
- bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
-
// Notify observers about the start of the provisional load.
- int render_frame_id = render_frame_host->GetRoutingID();
- RenderViewHost* render_view_host = render_frame_host->render_view_host();
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidStartProvisionalLoadForFrame(
- render_frame_id, parent_routing_id, is_main_frame,
- validated_url, is_error_page, is_iframe_srcdoc,
- render_view_host));
+ FOR_EACH_OBSERVER(
+ WebContentsObserver,
+ observers_,
+ DidStartProvisionalLoadForFrame(
+ render_frame_host, validated_url, is_error_page, is_iframe_srcdoc));
+}
- if (is_main_frame) {
- FOR_EACH_OBSERVER(
- WebContentsObserver,
- observers_,
- ProvisionalChangeToMainFrameUrl(validated_url,
- render_frame_host));
- }
+void WebContentsImpl::DidStartNavigationTransition(
+ RenderFrameHostImpl* render_frame_host) {
+#if defined(OS_ANDROID)
+ int render_frame_id = render_frame_host->GetRoutingID();
+ GetWebContentsAndroid()->DidStartNavigationTransitionForFrame(
+ render_frame_id);
+#endif
}
void WebContentsImpl::DidFailProvisionalLoadWithError(
RenderFrameHostImpl* render_frame_host,
const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) {
GURL validated_url(params.url);
- int render_frame_id = render_frame_host->GetRoutingID();
- bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
- RenderViewHost* render_view_host = render_frame_host->render_view_host();
- FOR_EACH_OBSERVER(
- WebContentsObserver,
- observers_,
- DidFailProvisionalLoad(render_frame_id,
- params.frame_unique_name,
- is_main_frame,
- validated_url,
- params.error_code,
- params.error_description,
- render_view_host));
+ FOR_EACH_OBSERVER(WebContentsObserver,
+ observers_,
+ DidFailProvisionalLoad(render_frame_host,
+ validated_url,
+ params.error_code,
+ params.error_description));
}
void WebContentsImpl::DidFailLoadWithError(
@@ -2348,12 +2487,10 @@ void WebContentsImpl::DidFailLoadWithError(
const GURL& url,
int error_code,
const base::string16& error_description) {
- int render_frame_id = render_frame_host->GetRoutingID();
- bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
- RenderViewHost* render_view_host = render_frame_host->render_view_host();
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidFailLoad(render_frame_id, url, is_main_frame, error_code,
- error_description, render_view_host));
+ FOR_EACH_OBSERVER(
+ WebContentsObserver,
+ observers_,
+ DidFailLoad(render_frame_host, url, error_code, error_description));
}
void WebContentsImpl::NotifyChangedNavigationState(
@@ -2405,45 +2542,23 @@ bool WebContentsImpl::ShouldPreserveAbortedURLs() {
return delegate_->ShouldPreserveAbortedURLs(this);
}
-void WebContentsImpl::DidRedirectProvisionalLoad(
- RenderFrameHostImpl* render_frame_host,
- const GURL& validated_target_url) {
- // Notify observers about the provisional change in the main frame URL.
- FOR_EACH_OBSERVER(
- WebContentsObserver,
- observers_,
- ProvisionalChangeToMainFrameUrl(validated_target_url,
- render_frame_host));
-}
-
void WebContentsImpl::DidCommitProvisionalLoad(
RenderFrameHostImpl* render_frame_host,
- const base::string16& frame_unique_name,
- bool is_main_frame,
const GURL& url,
- PageTransition transition_type) {
- int render_frame_id = render_frame_host->GetRoutingID();
- RenderViewHost* render_view_host = render_frame_host->render_view_host();
+ ui::PageTransition transition_type) {
// Notify observers about the commit of the provisional load.
- FOR_EACH_OBSERVER(
- WebContentsObserver,
- observers_,
- DidCommitProvisionalLoadForFrame(render_frame_id,
- frame_unique_name,
- is_main_frame,
- url,
- transition_type,
- render_view_host));
+ FOR_EACH_OBSERVER(WebContentsObserver,
+ observers_,
+ DidCommitProvisionalLoadForFrame(
+ render_frame_host, url, transition_type));
}
void WebContentsImpl::DidNavigateMainFramePreCommit(
- const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
+ bool navigation_is_within_page) {
// Ensure fullscreen mode is exited before committing the navigation to a
// different page. The next page will not start out assuming it is in
// fullscreen mode.
- if (controller_.IsURLInPageNavigation(params.url,
- params.was_within_same_page,
- NAVIGATION_TYPE_UNKNOWN)) {
+ if (navigation_is_within_page) {
// No page change? Then, the renderer and browser can remain in fullscreen.
return;
}
@@ -2462,7 +2577,7 @@ void WebContentsImpl::DidNavigateMainFramePostCommit(
// clicking on a link); see bugs 1184641 and 980803. We don't want to
// clear the bubble when a user navigates to a named anchor in the same
// page.
- UpdateTargetURL(details.entry->GetPageID(), GURL());
+ UpdateTargetURL(GURL());
}
if (!details.is_in_page) {
@@ -2496,7 +2611,7 @@ void WebContentsImpl::DidNavigateAnyFramePostCommit(
// Notify observers about navigation.
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidNavigateAnyFrame(details, params));
+ DidNavigateAnyFrame(render_frame_host, details, params));
}
void WebContentsImpl::SetMainFrameMimeType(const std::string& mime_type) {
@@ -2505,7 +2620,7 @@ void WebContentsImpl::SetMainFrameMimeType(const std::string& mime_type) {
bool WebContentsImpl::CanOverscrollContent() const {
// Disable overscroll when touch emulation is on. See crbug.com/369938.
- if (touch_emulation_enabled_)
+ if (force_disable_overscroll_content_)
return false;
if (delegate_)
@@ -2524,7 +2639,7 @@ void WebContentsImpl::OnDidLoadResourceFromMemoryCache(
const std::string& security_info,
const std::string& http_method,
const std::string& mime_type,
- ResourceType::Type resource_type) {
+ ResourceType resource_type) {
base::StatsCounter cache("WebKit.CacheHit");
cache.Increment();
@@ -2549,7 +2664,7 @@ void WebContentsImpl::OnDidLoadResourceFromMemoryCache(
if (url.is_valid() && url.SchemeIsHTTPOrHTTPS()) {
scoped_refptr<net::URLRequestContextGetter> request_context(
- resource_type == ResourceType::MEDIA ?
+ resource_type == RESOURCE_TYPE_MEDIA ?
GetBrowserContext()->GetMediaRequestContextForRenderProcess(
GetRenderProcessHost()->GetID()) :
GetBrowserContext()->GetRequestContextForRenderProcess(
@@ -2586,12 +2701,8 @@ void WebContentsImpl::OnDocumentLoadedInFrame() {
CHECK(!render_view_message_source_);
RenderFrameHostImpl* rfh =
static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
-
- int render_frame_id = rfh->GetRoutingID();
- RenderViewHost* render_view_host = rfh->render_view_host();
- FOR_EACH_OBSERVER(WebContentsObserver,
- observers_,
- DocumentLoadedInFrame(render_frame_id, render_view_host));
+ FOR_EACH_OBSERVER(
+ WebContentsObserver, observers_, DocumentLoadedInFrame(rfh));
}
void WebContentsImpl::OnDidFinishLoad(
@@ -2609,12 +2720,8 @@ void WebContentsImpl::OnDidFinishLoad(
RenderFrameHostImpl* rfh =
static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
- int render_frame_id = rfh->GetRoutingID();
- RenderViewHost* render_view_host = rfh->render_view_host();
- bool is_main_frame = rfh->frame_tree_node()->IsMainFrame();
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- DidFinishLoad(render_frame_id, validated_url,
- is_main_frame, render_view_host));
+ FOR_EACH_OBSERVER(
+ WebContentsObserver, observers_, DidFinishLoad(rfh, validated_url));
}
void WebContentsImpl::OnDidStartLoading(bool to_different_document) {
@@ -2739,6 +2846,20 @@ void WebContentsImpl::OnRegisterProtocolHandler(const std::string& protocol,
delegate_->RegisterProtocolHandler(this, protocol, url, user_gesture);
}
+void WebContentsImpl::OnUnregisterProtocolHandler(const std::string& protocol,
+ const GURL& url,
+ bool user_gesture) {
+ if (!delegate_)
+ return;
+
+ ChildProcessSecurityPolicyImpl* policy =
+ ChildProcessSecurityPolicyImpl::GetInstance();
+ if (policy->IsPseudoScheme(protocol))
+ return;
+
+ delegate_->UnregisterProtocolHandler(this, protocol, url, user_gesture);
+}
+
void WebContentsImpl::OnFindReply(int request_id,
int number_of_matches,
const gfx::Rect& selection_rect,
@@ -2761,7 +2882,7 @@ void WebContentsImpl::OnFindMatchRectsReply(
void WebContentsImpl::OnOpenDateTimeDialog(
const ViewHostMsg_DateTimeDialogValue_Params& value) {
- date_time_chooser_->ShowDialog(ContentViewCore::FromWebContents(this),
+ date_time_chooser_->ShowDialog(GetTopLevelNativeWindow(),
GetRenderViewHost(),
value.dialog_type,
value.dialog_value,
@@ -2770,24 +2891,8 @@ void WebContentsImpl::OnOpenDateTimeDialog(
value.step,
value.suggestions);
}
-
#endif
-void WebContentsImpl::OnPepperPluginHung(int plugin_child_id,
- const base::FilePath& path,
- bool is_hung) {
- UMA_HISTOGRAM_COUNTS("Pepper.PluginHung", 1);
-
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- PluginHungStatusChanged(plugin_child_id, path, is_hung));
-}
-
-void WebContentsImpl::OnPluginCrashed(const base::FilePath& plugin_path,
- base::ProcessId plugin_pid) {
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- PluginCrashed(plugin_path, plugin_pid));
-}
-
void WebContentsImpl::OnDomOperationResponse(const std::string& json_string,
int automation_id) {
DomOperationNotificationDetails details(json_string, automation_id);
@@ -2845,6 +2950,22 @@ void WebContentsImpl::OnWebUISend(const GURL& source_url,
delegate_->WebUISend(this, source_url, name, args);
}
+#if defined(ENABLE_PLUGINS)
+void WebContentsImpl::OnPepperPluginHung(int plugin_child_id,
+ const base::FilePath& path,
+ bool is_hung) {
+ UMA_HISTOGRAM_COUNTS("Pepper.PluginHung", 1);
+
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ PluginHungStatusChanged(plugin_child_id, path, is_hung));
+}
+
+void WebContentsImpl::OnPluginCrashed(const base::FilePath& plugin_path,
+ base::ProcessId plugin_pid) {
+ FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+ PluginCrashed(plugin_path, plugin_pid));
+}
+
void WebContentsImpl::OnRequestPpapiBrokerPermission(
int routing_id,
const GURL& url,
@@ -2878,6 +2999,7 @@ void WebContentsImpl::OnBrowserPluginMessage(const IPC::Message& message) {
browser_plugin_embedder_.reset(BrowserPluginEmbedder::Create(this));
browser_plugin_embedder_->OnMessageReceived(message);
}
+#endif // defined(ENABLE_PLUGINS)
void WebContentsImpl::OnDidDownloadImage(
int id,
@@ -2907,37 +3029,75 @@ void WebContentsImpl::OnUpdateFaviconURL(
DidUpdateFaviconURL(candidates));
}
-void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie,
- bool has_video,
- bool has_audio) {
-// Chrome OS does its own detection of audio and video.
+void WebContentsImpl::CreateAudioPowerSaveBlocker() {
+ // ChromeOS has its own way of handling power save blocks for media.
#if !defined(OS_CHROMEOS)
- scoped_ptr<PowerSaveBlocker> blocker;
- if (has_video) {
- blocker = PowerSaveBlocker::Create(
- PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, "Playing video");
+ DCHECK(!audio_power_save_blocker_);
+ audio_power_save_blocker_ = PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, "Playing Audio");
+#endif
+}
+
+void WebContentsImpl::CreateVideoPowerSaveBlocker() {
+ // ChromeOS has its own way of handling power save blocks for media.
+#if !defined(OS_CHROMEOS)
+ DCHECK(!video_power_save_blocker_);
+ DCHECK(!active_video_players_.empty());
+ video_power_save_blocker_ = PowerSaveBlocker::Create(
+ PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, "Playing Video");
#if defined(OS_ANDROID)
- static_cast<PowerSaveBlockerImpl*>(blocker.get())
- ->InitDisplaySleepBlocker(GetView()->GetNativeView());
+ static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
+ ->InitDisplaySleepBlocker(GetView()->GetNativeView());
+#endif
#endif
- } else if (has_audio) {
- blocker = PowerSaveBlocker::Create(
- PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, "Playing audio");
+}
+
+void WebContentsImpl::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
+ // NotifyNavigationStateChanged().
+ if (active_audio_players_.empty() &&
+ !AudioStreamMonitor::monitoring_available()) {
+ audio_power_save_blocker_.reset();
+ }
+
+ // If there are no more video players, clear the video power save blocker.
+ if (active_video_players_.empty())
+ video_power_save_blocker_.reset();
+}
+
+void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie,
+ bool has_video,
+ bool has_audio,
+ bool is_remote) {
+ // Ignore the videos playing remotely and don't hold the wake lock for the
+ // screen.
+ if (is_remote) return;
+
+ if (has_audio) {
+ AddMediaPlayerEntry(player_cookie, &active_audio_players_);
+
+ // If we don't have audio stream monitoring, allocate the audio power save
+ // blocker here instead of during NotifyNavigationStateChanged().
+ if (!audio_power_save_blocker_ &&
+ !AudioStreamMonitor::monitoring_available()) {
+ CreateAudioPowerSaveBlocker();
+ }
}
- if (blocker) {
- power_save_blockers_[render_frame_message_source_][player_cookie] =
- blocker.release();
+ if (has_video) {
+ AddMediaPlayerEntry(player_cookie, &active_video_players_);
+
+ // If we're not hidden and have just created a player, create a blocker.
+ if (!video_power_save_blocker_ && !IsHidden())
+ CreateVideoPowerSaveBlocker();
}
-#endif // !defined(OS_CHROMEOS)
}
void WebContentsImpl::OnMediaPausedNotification(int64 player_cookie) {
- // Chrome OS does its own detection of audio and video.
-#if !defined(OS_CHROMEOS)
- delete power_save_blockers_[render_frame_message_source_][player_cookie];
- power_save_blockers_[render_frame_message_source_].erase(player_cookie);
-#endif // !defined(OS_CHROMEOS)
+ RemoveMediaPlayerEntry(player_cookie, &active_audio_players_);
+ RemoveMediaPlayerEntry(player_cookie, &active_video_players_);
+ MaybeReleasePowerSaveBlockers();
}
void WebContentsImpl::OnFirstVisuallyNonEmptyPaint() {
@@ -2955,7 +3115,6 @@ void WebContentsImpl::NotifyBeforeFormRepostWarningShow() {
BeforeFormRepostWarningShow());
}
-
void WebContentsImpl::ActivateAndShowRepostFormWarningDialog() {
Activate();
if (delegate_)
@@ -2995,13 +3154,13 @@ void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host,
std::string url = (details ? details->url.possibly_invalid_spec() : "NULL");
if (is_loading) {
- TRACE_EVENT_ASYNC_BEGIN1("browser", "WebContentsImpl Loading", this,
- "URL", url);
+ TRACE_EVENT_ASYNC_BEGIN1("browser,navigation", "WebContentsImpl Loading",
+ this, "URL", url);
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidStartLoading(render_view_host));
} else {
- TRACE_EVENT_ASYNC_END1("browser", "WebContentsImpl Loading", this,
- "URL", url);
+ TRACE_EVENT_ASYNC_END1("browser,navigation", "WebContentsImpl Loading",
+ this, "URL", url);
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidStopLoading(render_view_host));
}
@@ -3015,14 +3174,23 @@ void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host,
type, Source<NavigationController>(&controller_), det);
}
-void WebContentsImpl::SelectRange(const gfx::Point& start,
- const gfx::Point& end) {
+void WebContentsImpl::MoveRangeSelectionExtent(const gfx::Point& extent) {
+ RenderFrameHost* focused_frame = GetFocusedFrame();
+ if (!focused_frame)
+ return;
+
+ focused_frame->Send(new InputMsg_MoveRangeSelectionExtent(
+ focused_frame->GetRoutingID(), extent));
+}
+
+void WebContentsImpl::SelectRange(const gfx::Point& base,
+ const gfx::Point& extent) {
RenderFrameHost* focused_frame = GetFocusedFrame();
if (!focused_frame)
return;
focused_frame->Send(
- new InputMsg_SelectRange(focused_frame->GetRoutingID(), start, end));
+ new InputMsg_SelectRange(focused_frame->GetRoutingID(), base, extent));
}
void WebContentsImpl::UpdateMaxPageIDIfNecessary(RenderViewHost* rvh) {
@@ -3117,8 +3285,8 @@ void WebContentsImpl::ResetLoadProgressState() {
loading_last_progress_update_ = base::TimeTicks();
}
-void WebContentsImpl::NotifySwapped(RenderViewHost* old_host,
- RenderViewHost* new_host) {
+void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host,
+ RenderViewHost* new_host) {
// After sending out a swap notification, we need to send a disconnect
// notification so that clients that pick up a pointer to |this| can NULL the
// pointer. See Bug 1230284.
@@ -3140,6 +3308,13 @@ void WebContentsImpl::NotifySwapped(RenderViewHost* old_host,
RemoveBrowserPluginEmbedder();
}
+void WebContentsImpl::NotifyFrameSwapped(RenderFrameHost* old_host,
+ RenderFrameHost* new_host) {
+ FOR_EACH_OBSERVER(WebContentsObserver,
+ observers_,
+ RenderFrameHostChanged(old_host, new_host));
+}
+
// TODO(avi): Remove this entire function because this notification is already
// covered by two observer functions. http://crbug.com/170921
void WebContentsImpl::NotifyDisconnected() {
@@ -3174,6 +3349,7 @@ void WebContentsImpl::RenderFrameCreated(RenderFrameHost* render_frame_host) {
FOR_EACH_OBSERVER(WebContentsObserver,
observers_,
RenderFrameCreated(render_frame_host));
+ SetAccessibilityModeOnFrame(accessibility_mode_, render_frame_host);
}
void WebContentsImpl::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
@@ -3215,8 +3391,7 @@ 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<RenderViewHostImpl*>(render_frame_host->GetRenderViewHost())->
- IsSwappedOut() ||
+ static_cast<RenderFrameHostImpl*>(render_frame_host)->is_swapped_out() ||
ShowingInterstitialPage() ||
!delegate_ ||
delegate_->ShouldSuppressDialogs() ||
@@ -3261,13 +3436,11 @@ void WebContentsImpl::RunBeforeUnloadConfirm(
IPC::Message* reply_msg) {
RenderFrameHostImpl* rfhi =
static_cast<RenderFrameHostImpl*>(render_frame_host);
- RenderViewHostImpl* rvhi =
- static_cast<RenderViewHostImpl*>(render_frame_host->GetRenderViewHost());
if (delegate_)
delegate_->WillRunBeforeUnloadConfirm();
bool suppress_this_message =
- rvhi->rvh_state() != RenderViewHostImpl::STATE_DEFAULT ||
+ rfhi->rfh_state() != RenderFrameHostImpl::STATE_DEFAULT ||
!delegate_ ||
delegate_->ShouldSuppressDialogs() ||
!delegate_->GetJavaScriptDialogManager();
@@ -3296,6 +3469,12 @@ 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_;
}
@@ -3320,7 +3499,7 @@ void WebContentsImpl::RenderViewCreated(RenderViewHost* render_view_host) {
// Don't send notifications if we are just creating a swapped-out RVH for
// the opener chain. These won't be used for view-source or WebUI, so it's
// ok to return early.
- if (static_cast<RenderViewHostImpl*>(render_view_host)->IsSwappedOut())
+ if (!static_cast<RenderViewHostImpl*>(render_view_host)->is_active())
return;
if (delegate_)
@@ -3354,6 +3533,9 @@ void WebContentsImpl::RenderViewCreated(RenderViewHost* render_view_host) {
RenderFrameHost* main_frame = render_view_host->GetMainFrame();
FOR_EACH_OBSERVER(
WebContentsObserver, observers_, RenderFrameCreated(main_frame));
+ SetAccessibilityModeOnFrame(accessibility_mode_, main_frame);
+
+ DevToolsManager::GetInstance()->RenderViewCreated(this, render_view_host);
}
void WebContentsImpl::RenderViewReady(RenderViewHost* rvh) {
@@ -3454,9 +3636,9 @@ void WebContentsImpl::UpdateState(RenderViewHost* rvh,
controller_.NotifyEntryChanged(entry, entry_index);
}
-void WebContentsImpl::UpdateTargetURL(int32 page_id, const GURL& url) {
+void WebContentsImpl::UpdateTargetURL(const GURL& url) {
if (delegate_)
- delegate_->UpdateTargetURL(this, page_id, url);
+ delegate_->UpdateTargetURL(this, url);
}
void WebContentsImpl::Close(RenderViewHost* rvh) {
@@ -3484,6 +3666,21 @@ void WebContentsImpl::SwappedOut(RenderFrameHost* rfh) {
delegate_->SwappedOut(this);
}
+void WebContentsImpl::DidDeferAfterResponseStarted(
+ const TransitionLayerData& transition_data) {
+#if defined(OS_ANDROID)
+ GetWebContentsAndroid()->DidDeferAfterResponseStarted(transition_data);
+#endif
+}
+
+bool WebContentsImpl::WillHandleDeferAfterResponseStarted() {
+#if defined(OS_ANDROID)
+ return GetWebContentsAndroid()->WillHandleDeferAfterResponseStarted();
+#else
+ return false;
+#endif
+}
+
void WebContentsImpl::RequestMove(const gfx::Rect& new_bounds) {
if (delegate_ && delegate_->IsPopupOrPanel(this))
delegate_->MoveContents(this, new_bounds);
@@ -3538,21 +3735,23 @@ void WebContentsImpl::DidAccessInitialDocument() {
controller_.DiscardPendingEntry();
// Update the URL display.
- NotifyNavigationStateChanged(content::INVALIDATE_TYPE_URL);
+ NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
}
void WebContentsImpl::DidDisownOpener(RenderFrameHost* render_frame_host) {
- if (opener_) {
- // Clear our opener so that future cross-process navigations don't have an
- // opener assigned.
- RemoveDestructionObserver(opener_);
- opener_ = NULL;
- }
+ // No action is necessary if the opener has already been cleared.
+ if (!opener_)
+ return;
+
+ // Clear our opener so that future cross-process navigations don't have an
+ // opener assigned.
+ RemoveDestructionObserver(opener_);
+ opener_ = NULL;
// Notify all swapped out RenderViewHosts for this tab. This is important
// in case we go back to them, or if another window in those processes tries
// to access window.opener.
- GetRenderManager()->DidDisownOpener(render_frame_host->GetRenderViewHost());
+ GetRenderManager()->DidDisownOpener(render_frame_host);
}
void WebContentsImpl::DocumentOnLoadCompleted(
@@ -3690,7 +3889,7 @@ bool WebContentsImpl::AddMessageToConsole(int32 level,
source_id);
}
-WebPreferences WebContentsImpl::GetWebkitPrefs() {
+WebPreferences WebContentsImpl::ComputeWebkitPrefs() {
// We want to base the page config off of the actual URL, rather than the
// virtual URL.
// TODO(nasko): Investigate how to remove the GetActiveEntry usage here,
@@ -3698,13 +3897,13 @@ WebPreferences WebContentsImpl::GetWebkitPrefs() {
GURL url = controller_.GetActiveEntry()
? controller_.GetActiveEntry()->GetURL() : GURL::EmptyGURL();
- return GetRenderManager()->current_host()->GetWebkitPrefs(url);
+ return GetRenderManager()->current_host()->ComputeWebkitPrefs(url);
}
int WebContentsImpl::CreateSwappedOutRenderView(
SiteInstance* instance) {
- return GetRenderManager()->CreateRenderFrame(instance, MSG_ROUTING_NONE,
- true, true);
+ return GetRenderManager()->CreateRenderFrame(
+ instance, MSG_ROUTING_NONE, true, true, true);
}
void WebContentsImpl::OnUserGesture() {
@@ -3721,14 +3920,14 @@ void WebContentsImpl::OnIgnoredUIEvent() {
FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetIgnoredUIEvent());
}
-void WebContentsImpl::RendererUnresponsive(RenderViewHost* rvh,
- bool is_during_beforeunload,
- bool is_during_unload) {
+void WebContentsImpl::RendererUnresponsive(RenderViewHost* render_view_host) {
// Don't show hung renderer dialog for a swapped out RVH.
- if (rvh != GetRenderViewHost())
+ if (render_view_host != GetRenderViewHost())
return;
- RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(rvh);
+ RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(render_view_host);
+ RenderFrameHostImpl* rfhi =
+ static_cast<RenderFrameHostImpl*>(rvhi->GetMainFrame());
// Ignore renderer unresponsive event if debugger is attached to the tab
// since the event may be a result of the renderer sitting on a breakpoint.
@@ -3736,7 +3935,8 @@ void WebContentsImpl::RendererUnresponsive(RenderViewHost* rvh,
if (DevToolsAgentHost::IsDebuggerAttached(this))
return;
- if (is_during_beforeunload || is_during_unload) {
+ if (rfhi->is_waiting_for_beforeunload_ack() ||
+ rfhi->IsWaitingForUnloadACK()) {
// Hang occurred while firing the beforeunload/unload handler.
// Pretend the handler fired so tab closing continues as if it had.
rvhi->set_sudden_termination_allowed(true);
@@ -3751,11 +3951,11 @@ void WebContentsImpl::RendererUnresponsive(RenderViewHost* rvh,
// close. Otherwise, pretend the unload listeners have all fired and close
// the tab.
bool close = true;
- if (is_during_beforeunload && delegate_) {
+ if (rfhi->is_waiting_for_beforeunload_ack() && delegate_) {
delegate_->BeforeUnloadFired(this, true, &close);
}
if (close)
- Close(rvh);
+ Close(rvhi);
return;
}
@@ -3785,7 +3985,8 @@ void WebContentsImpl::LoadStateChanged(
if (load_state_.state == net::LOAD_STATE_READING_RESPONSE)
SetNotWaitingForResponse();
if (IsLoading()) {
- NotifyNavigationStateChanged(INVALIDATE_TYPE_LOAD | INVALIDATE_TYPE_TAB);
+ NotifyNavigationStateChanged(static_cast<InvalidateTypes>(
+ INVALIDATE_TYPE_LOAD | INVALIDATE_TYPE_TAB));
}
}
@@ -3823,15 +4024,21 @@ void WebContentsImpl::CancelModalDialogsForRenderManager() {
dialog_manager_->CancelActiveAndPendingDialogs(this);
}
-void WebContentsImpl::NotifySwappedFromRenderManager(RenderViewHost* old_host,
- RenderViewHost* new_host) {
- NotifySwapped(old_host, new_host);
+void WebContentsImpl::NotifySwappedFromRenderManager(RenderFrameHost* old_host,
+ RenderFrameHost* new_host,
+ bool is_main_frame) {
+ if (is_main_frame) {
+ NotifyViewSwapped(old_host ? old_host->GetRenderViewHost() : NULL,
+ new_host->GetRenderViewHost());
- // Make sure the visible RVH reflects the new delegate's preferences.
- if (delegate_)
- view_->SetOverscrollControllerEnabled(CanOverscrollContent());
+ // Make sure the visible RVH reflects the new delegate's preferences.
+ if (delegate_)
+ view_->SetOverscrollControllerEnabled(CanOverscrollContent());
- view_->RenderViewSwappedIn(new_host);
+ view_->RenderViewSwappedIn(new_host->GetRenderViewHost());
+ }
+
+ NotifyFrameSwapped(old_host, new_host);
}
int WebContentsImpl::CreateOpenerRenderViewsForRenderManager(
@@ -3868,8 +4075,8 @@ int WebContentsImpl::CreateOpenerRenderViews(SiteInstance* instance) {
// Create a swapped out RenderView in the given SiteInstance if none exists,
// setting its opener to the given route_id. Return the new view's route_id.
- return GetRenderManager()->CreateRenderFrame(instance, opener_route_id,
- true, true);
+ return GetRenderManager()->CreateRenderFrame(
+ instance, opener_route_id, true, true, true);
}
NavigationControllerImpl& WebContentsImpl::GetControllerForRenderManager() {
@@ -3889,20 +4096,21 @@ bool WebContentsImpl::CreateRenderViewForRenderManager(
RenderViewHost* render_view_host,
int opener_route_id,
int proxy_routing_id,
- bool for_main_frame) {
- TRACE_EVENT0("browser", "WebContentsImpl::CreateRenderViewForRenderManager");
+ bool for_main_frame_navigation) {
+ TRACE_EVENT0("browser,navigation",
+ "WebContentsImpl::CreateRenderViewForRenderManager");
// Can be NULL during tests.
RenderWidgetHostViewBase* rwh_view;
// TODO(kenrb): RenderWidgetHostViewChildFrame special casing is temporary
// until RenderWidgetHost is attached to RenderFrameHost. We need to special
// case this because RWH is still a base class of RenderViewHost, and child
// frame RWHVs are unique in that they do not have their own WebContents.
- if (!for_main_frame) {
+ if (!for_main_frame_navigation) {
RenderWidgetHostViewChildFrame* rwh_view_child =
new RenderWidgetHostViewChildFrame(render_view_host);
rwh_view = rwh_view_child;
} else {
- rwh_view = view_->CreateViewForWidget(render_view_host);
+ rwh_view = view_->CreateViewForWidget(render_view_host, false);
}
// Now that the RenderView has been created, we need to tell it its size.
@@ -3935,19 +4143,41 @@ bool WebContentsImpl::CreateRenderViewForRenderManager(
return true;
}
+bool WebContentsImpl::CreateRenderFrameForRenderManager(
+ RenderFrameHost* render_frame_host,
+ int parent_routing_id,
+ int proxy_routing_id) {
+ TRACE_EVENT0("browser,navigation",
+ "WebContentsImpl::CreateRenderFrameForRenderManager");
+
+ RenderFrameHostImpl* rfh =
+ static_cast<RenderFrameHostImpl*>(render_frame_host);
+ if (!rfh->CreateRenderFrame(parent_routing_id, proxy_routing_id))
+ return false;
+
+ // TODO(nasko): When RenderWidgetHost is owned by RenderFrameHost, the passed
+ // RenderFrameHost will have to be associated with the appropriate
+ // RenderWidgetHostView or a new one should be created here.
+
+ return true;
+}
+
#if defined(OS_ANDROID)
base::android::ScopedJavaLocalRef<jobject>
WebContentsImpl::GetJavaWebContents() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return GetWebContentsAndroid()->GetJavaObject();
+}
+WebContentsAndroid* WebContentsImpl::GetWebContentsAndroid() {
WebContentsAndroid* web_contents_android =
static_cast<WebContentsAndroid*>(GetUserData(kWebContentsAndroidKey));
if (!web_contents_android) {
web_contents_android = new WebContentsAndroid(this);
SetUserData(kWebContentsAndroidKey, web_contents_android);
}
- return web_contents_android->GetJavaObject();
+ return web_contents_android;
}
bool WebContentsImpl::CreateRenderViewForInitialEmptyDocument() {
@@ -3959,22 +4189,12 @@ bool WebContentsImpl::CreateRenderViewForInitialEmptyDocument() {
#elif defined(OS_MACOSX)
-void WebContentsImpl::SetAllowOverlappingViews(bool overlapping) {
- view_->SetAllowOverlappingViews(overlapping);
+void WebContentsImpl::SetAllowOtherViews(bool allow) {
+ view_->SetAllowOtherViews(allow);
}
-bool WebContentsImpl::GetAllowOverlappingViews() {
- return view_->GetAllowOverlappingViews();
-}
-
-void WebContentsImpl::SetOverlayView(WebContents* overlay,
- const gfx::Point& offset) {
- view_->SetOverlayView(static_cast<WebContentsImpl*>(overlay)->GetView(),
- offset);
-}
-
-void WebContentsImpl::RemoveOverlayView() {
- view_->RemoveOverlayView();
+bool WebContentsImpl::GetAllowOtherViews() {
+ return view_->GetAllowOtherViews();
}
#endif
@@ -4019,13 +4239,6 @@ void WebContentsImpl::SetEncoding(const std::string& encoding) {
GetCanonicalEncodingNameByAliasName(encoding);
}
-void WebContentsImpl::CreateViewAndSetSizeForRVH(RenderViewHost* rvh) {
- RenderWidgetHostViewBase* rwh_view = view_->CreateViewForWidget(rvh);
- // Can be NULL during tests.
- if (rwh_view)
- rwh_view->SetSize(GetContainerBounds().size());
-}
-
bool WebContentsImpl::IsHidden() {
return capturer_count_ == 0 && !should_normally_be_visible_;
}
@@ -4053,15 +4266,16 @@ BrowserPluginEmbedder* WebContentsImpl::GetBrowserPluginEmbedder() const {
void WebContentsImpl::ClearPowerSaveBlockers(
RenderFrameHost* render_frame_host) {
- STLDeleteValues(&power_save_blockers_[render_frame_host]);
- power_save_blockers_.erase(render_frame_host);
+ RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_);
+ RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_);
+ MaybeReleasePowerSaveBlockers();
}
void WebContentsImpl::ClearAllPowerSaveBlockers() {
- for (PowerSaveBlockerMap::iterator i(power_save_blockers_.begin());
- i != power_save_blockers_.end(); ++i)
- STLDeleteValues(&power_save_blockers_[i->first]);
- power_save_blockers_.clear();
+ active_audio_players_.clear();
+ active_video_players_.clear();
+ audio_power_save_blocker_.reset();
+ video_power_save_blocker_.reset();
}
gfx::Size WebContentsImpl::GetSizeForNewRenderView() {
@@ -4073,11 +4287,9 @@ gfx::Size WebContentsImpl::GetSizeForNewRenderView() {
return size;
}
-void WebContentsImpl::OnFrameRemoved(
- RenderViewHostImpl* render_view_host,
- int frame_routing_id) {
- FOR_EACH_OBSERVER(WebContentsObserver, observers_,
- FrameDetached(render_view_host, frame_routing_id));
+void WebContentsImpl::OnFrameRemoved(RenderFrameHost* render_frame_host) {
+ FOR_EACH_OBSERVER(
+ WebContentsObserver, observers_, FrameDetached(render_frame_host));
}
void WebContentsImpl::OnPreferredSizeChanged(const gfx::Size& old_size) {
@@ -4088,4 +4300,54 @@ void WebContentsImpl::OnPreferredSizeChanged(const gfx::Size& old_size) {
delegate_->UpdatePreferredSize(this, new_size);
}
+void WebContentsImpl::AddMediaPlayerEntry(int64 player_cookie,
+ ActiveMediaPlayerMap* player_map) {
+ const uintptr_t key =
+ reinterpret_cast<uintptr_t>(render_frame_message_source_);
+ DCHECK(std::find((*player_map)[key].begin(),
+ (*player_map)[key].end(),
+ player_cookie) == (*player_map)[key].end());
+ (*player_map)[key].push_back(player_cookie);
+}
+
+void WebContentsImpl::RemoveMediaPlayerEntry(int64 player_cookie,
+ ActiveMediaPlayerMap* player_map) {
+ const uintptr_t key =
+ reinterpret_cast<uintptr_t>(render_frame_message_source_);
+ ActiveMediaPlayerMap::iterator it = player_map->find(key);
+ if (it == player_map->end())
+ return;
+
+ // Remove the player.
+ PlayerList::iterator player_it =
+ std::find(it->second.begin(), it->second.end(), player_cookie);
+ if (player_it != it->second.end())
+ it->second.erase(player_it);
+
+ // If there are no players left, remove the map entry.
+ if (it->second.empty())
+ player_map->erase(it);
+}
+
+void WebContentsImpl::RemoveAllMediaPlayerEntries(
+ RenderFrameHost* render_frame_host,
+ ActiveMediaPlayerMap* player_map) {
+ ActiveMediaPlayerMap::iterator it =
+ player_map->find(reinterpret_cast<uintptr_t>(render_frame_host));
+ if (it == player_map->end())
+ return;
+ player_map->erase(it);
+}
+
+void WebContentsImpl::ResumeResponseDeferredAtStart() {
+ FrameTreeNode* node = frame_tree_.root();
+ node->render_manager()->ResumeResponseDeferredAtStart();
+}
+
+void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) {
+ force_disable_overscroll_content_ = force_disable;
+ if (view_)
+ view_->SetOverscrollControllerEnabled(CanOverscrollContent());
+}
+
} // namespace content
diff --git a/chromium/content/browser/web_contents/web_contents_impl.h b/chromium/content/browser/web_contents/web_contents_impl.h
index ba10e415d14..7869292bdb0 100644
--- a/chromium/content/browser/web_contents/web_contents_impl.h
+++ b/chromium/content/browser/web_contents/web_contents_impl.h
@@ -10,6 +10,7 @@
#include <string>
#include "base/compiler_specific.h"
+#include "base/containers/scoped_ptr_hash_map.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
@@ -21,21 +22,24 @@
#include "content/browser/frame_host/navigator_delegate.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/browser/frame_host/render_frame_host_manager.h"
+#include "content/browser/media/audio_stream_monitor.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/common/accessibility_mode_enums.h"
#include "content/common/content_export.h"
#include "content/public/browser/color_chooser.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents.h"
-#include "content/public/common/page_transition_types.h"
#include "content/public/common/renderer_preferences.h"
+#include "content/public/common/resource_type.h"
#include "content/public/common/three_d_api_types.h"
#include "net/base/load_states.h"
+#include "net/http/http_response_headers.h"
#include "third_party/WebKit/public/web/WebDragOperation.h"
+#include "ui/base/page_transition_types.h"
#include "ui/gfx/rect_f.h"
#include "ui/gfx/size.h"
-#include "webkit/common/resource_type.h"
struct BrowserPluginHostMsg_ResizeGuest_Params;
struct ViewHostMsg_DateTimeDialogValue_Params;
@@ -48,9 +52,12 @@ class BrowserPluginGuestManager;
class DateTimeChooserAndroid;
class DownloadItem;
class GeolocationDispatcherHost;
+class GeolocationServiceContext;
class InterstitialPageImpl;
class JavaScriptDialogManager;
+class ManifestManagerHost;
class MidiDispatcherHost;
+class PluginContentOriginWhitelist;
class PowerSaveBlocker;
class RenderViewHost;
class RenderViewHostDelegateView;
@@ -60,6 +67,7 @@ class SavePackage;
class ScreenOrientationDispatcherHost;
class SiteInstance;
class TestWebContents;
+class WebContentsAudioMuter;
class WebContentsDelegate;
class WebContentsImpl;
class WebContentsObserver;
@@ -72,6 +80,10 @@ struct LoadNotificationDetails;
struct ResourceRedirectDetails;
struct ResourceRequestDetails;
+#if defined(OS_ANDROID)
+class WebContentsAndroid;
+#endif
+
// Factory function for the implementations that content knows about. Takes
// ownership of |delegate|.
WebContentsView* CreateWebContentsView(
@@ -89,12 +101,14 @@ class CONTENT_EXPORT WebContentsImpl
public NON_EXPORTED_BASE(NavigationControllerDelegate),
public NON_EXPORTED_BASE(NavigatorDelegate) {
public:
- virtual ~WebContentsImpl();
+ ~WebContentsImpl() override;
static WebContentsImpl* CreateWithOpener(
const WebContents::CreateParams& params,
WebContentsImpl* opener);
+ static std::vector<WebContentsImpl*> GetAllWebContents();
+
// Returns the opener WebContentsImpl, if any. This can be set to null if the
// opener is closed or the page clears its window.opener.
WebContentsImpl* opener() const { return opener_; }
@@ -161,422 +175,426 @@ class CONTENT_EXPORT WebContentsImpl
WebContentsView* GetView() const;
- GeolocationDispatcherHost* geolocation_dispatcher_host() {
- return geolocation_dispatcher_host_.get();
+ ScreenOrientationDispatcherHost* screen_orientation_dispatcher_host() {
+ return screen_orientation_dispatcher_host_.get();
}
bool should_normally_be_visible() { return should_normally_be_visible_; }
+ // Broadcasts the mode change to all frames.
+ void SetAccessibilityMode(AccessibilityMode mode);
+
+ // Adds the given accessibility mode to the current accessibility mode
+ // bitmap.
+ void AddAccessibilityMode(AccessibilityMode mode);
+
+ // Removes the given accessibility mode from the current accessibility
+ // mode bitmap, managing the bits that are shared with other modes such
+ // that a bit will only be turned off when all modes that depend on it
+ // have been removed.
+ void RemoveAccessibilityMode(AccessibilityMode mode);
+
+ // Clear the navigation transition data when the user navigates back to Chrome
+ // from a native app.
+ void ClearNavigationTransitionData();
+
// WebContents ------------------------------------------------------
- virtual WebContentsDelegate* GetDelegate() OVERRIDE;
- virtual void SetDelegate(WebContentsDelegate* delegate) OVERRIDE;
- virtual NavigationControllerImpl& GetController() OVERRIDE;
- virtual const NavigationControllerImpl& GetController() const OVERRIDE;
- virtual BrowserContext* GetBrowserContext() const OVERRIDE;
- virtual const GURL& GetURL() const OVERRIDE;
- virtual const GURL& GetVisibleURL() const OVERRIDE;
- virtual const GURL& GetLastCommittedURL() const OVERRIDE;
- virtual RenderProcessHost* GetRenderProcessHost() const OVERRIDE;
- virtual RenderFrameHost* GetMainFrame() OVERRIDE;
- virtual RenderFrameHost* GetFocusedFrame() OVERRIDE;
- virtual void ForEachFrame(
- const base::Callback<void(RenderFrameHost*)>& on_frame) OVERRIDE;
- virtual void SendToAllFrames(IPC::Message* message) OVERRIDE;
- virtual RenderViewHost* GetRenderViewHost() const OVERRIDE;
- virtual int GetRoutingID() const OVERRIDE;
- virtual RenderWidgetHostView* GetRenderWidgetHostView() const OVERRIDE;
- virtual RenderWidgetHostView* GetFullscreenRenderWidgetHostView() const
- OVERRIDE;
- virtual WebUI* CreateWebUI(const GURL& url) OVERRIDE;
- virtual WebUI* GetWebUI() const OVERRIDE;
- virtual WebUI* GetCommittedWebUI() const OVERRIDE;
- virtual void SetUserAgentOverride(const std::string& override) OVERRIDE;
- virtual const std::string& GetUserAgentOverride() const OVERRIDE;
+ WebContentsDelegate* GetDelegate() override;
+ void SetDelegate(WebContentsDelegate* delegate) override;
+ NavigationControllerImpl& GetController() override;
+ const NavigationControllerImpl& GetController() const override;
+ BrowserContext* GetBrowserContext() const override;
+ const GURL& GetURL() const override;
+ const GURL& GetVisibleURL() const override;
+ const GURL& GetLastCommittedURL() const override;
+ RenderProcessHost* GetRenderProcessHost() const override;
+ RenderFrameHost* GetMainFrame() override;
+ RenderFrameHost* GetFocusedFrame() override;
+ void ForEachFrame(
+ const base::Callback<void(RenderFrameHost*)>& on_frame) override;
+ void SendToAllFrames(IPC::Message* message) override;
+ RenderViewHost* GetRenderViewHost() const override;
+ int GetRoutingID() const override;
+ RenderWidgetHostView* GetRenderWidgetHostView() const override;
+ RenderWidgetHostView* GetFullscreenRenderWidgetHostView() const override;
+ WebUI* CreateWebUI(const GURL& url) override;
+ WebUI* GetWebUI() const override;
+ WebUI* GetCommittedWebUI() const override;
+ void SetUserAgentOverride(const std::string& override) override;
+ const std::string& GetUserAgentOverride() const override;
+ void EnableTreeOnlyAccessibilityMode() override;
+ bool IsTreeOnlyAccessibilityModeForTesting() const override;
+ bool IsFullAccessibilityModeForTesting() const override;
#if defined(OS_WIN)
virtual void SetParentNativeViewAccessible(
- gfx::NativeViewAccessible accessible_parent) OVERRIDE;
+ gfx::NativeViewAccessible accessible_parent) override;
#endif
- virtual const base::string16& GetTitle() const OVERRIDE;
- virtual int32 GetMaxPageID() OVERRIDE;
- virtual int32 GetMaxPageIDForSiteInstance(
- SiteInstance* site_instance) OVERRIDE;
- virtual SiteInstance* GetSiteInstance() const OVERRIDE;
- virtual SiteInstance* GetPendingSiteInstance() const OVERRIDE;
- virtual bool IsLoading() const OVERRIDE;
- virtual bool IsLoadingToDifferentDocument() const OVERRIDE;
- virtual bool IsWaitingForResponse() const OVERRIDE;
- virtual const net::LoadStateWithParam& GetLoadState() const OVERRIDE;
- virtual const base::string16& GetLoadStateHost() const OVERRIDE;
- virtual uint64 GetUploadSize() const OVERRIDE;
- virtual uint64 GetUploadPosition() const OVERRIDE;
- virtual std::set<GURL> GetSitesInTab() const OVERRIDE;
- virtual const std::string& GetEncoding() const OVERRIDE;
- virtual bool DisplayedInsecureContent() const OVERRIDE;
- virtual void IncrementCapturerCount(const gfx::Size& capture_size) OVERRIDE;
- virtual void DecrementCapturerCount() OVERRIDE;
- virtual int GetCapturerCount() const OVERRIDE;
- virtual bool IsCrashed() const OVERRIDE;
- virtual void SetIsCrashed(base::TerminationStatus status,
- int error_code) OVERRIDE;
- virtual base::TerminationStatus GetCrashedStatus() const OVERRIDE;
- virtual bool IsBeingDestroyed() const OVERRIDE;
- virtual void NotifyNavigationStateChanged(unsigned changed_flags) OVERRIDE;
- virtual base::TimeTicks GetLastActiveTime() const OVERRIDE;
- virtual void WasShown() OVERRIDE;
- virtual void WasHidden() OVERRIDE;
- virtual bool NeedToFireBeforeUnload() OVERRIDE;
- virtual void DispatchBeforeUnload(bool for_cross_site_transition) OVERRIDE;
- virtual void Stop() OVERRIDE;
- virtual WebContents* Clone() OVERRIDE;
- virtual void ReloadFocusedFrame(bool ignore_cache) OVERRIDE;
- virtual void Undo() OVERRIDE;
- virtual void Redo() OVERRIDE;
- virtual void Cut() OVERRIDE;
- virtual void Copy() OVERRIDE;
- virtual void CopyToFindPboard() OVERRIDE;
- virtual void Paste() OVERRIDE;
- virtual void PasteAndMatchStyle() OVERRIDE;
- virtual void Delete() OVERRIDE;
- virtual void SelectAll() OVERRIDE;
- virtual void Unselect() OVERRIDE;
- virtual void Replace(const base::string16& word) OVERRIDE;
- virtual void ReplaceMisspelling(const base::string16& word) OVERRIDE;
- virtual void NotifyContextMenuClosed(
- const CustomContextMenuContext& context) OVERRIDE;
- virtual void ExecuteCustomContextMenuCommand(
- int action, const CustomContextMenuContext& context) OVERRIDE;
- virtual gfx::NativeView GetNativeView() OVERRIDE;
- virtual gfx::NativeView GetContentNativeView() OVERRIDE;
- virtual gfx::NativeWindow GetTopLevelNativeWindow() OVERRIDE;
- virtual gfx::Rect GetContainerBounds() OVERRIDE;
- virtual gfx::Rect GetViewBounds() OVERRIDE;
- virtual DropData* GetDropData() OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void SetInitialFocus() OVERRIDE;
- virtual void StoreFocus() OVERRIDE;
- virtual void RestoreFocus() OVERRIDE;
- virtual void FocusThroughTabTraversal(bool reverse) OVERRIDE;
- virtual bool ShowingInterstitialPage() const OVERRIDE;
- virtual InterstitialPage* GetInterstitialPage() const OVERRIDE;
- virtual bool IsSavable() OVERRIDE;
- virtual void OnSavePage() OVERRIDE;
- virtual bool SavePage(const base::FilePath& main_file,
- const base::FilePath& dir_path,
- SavePageType save_type) OVERRIDE;
- virtual void SaveFrame(const GURL& url,
- const Referrer& referrer) OVERRIDE;
- virtual void GenerateMHTML(
- const base::FilePath& file,
- const base::Callback<void(int64)>& callback)
- OVERRIDE;
- virtual const std::string& GetContentsMimeType() const OVERRIDE;
- virtual bool WillNotifyDisconnection() const OVERRIDE;
- virtual void SetOverrideEncoding(const std::string& encoding) OVERRIDE;
- virtual void ResetOverrideEncoding() OVERRIDE;
- virtual RendererPreferences* GetMutableRendererPrefs() OVERRIDE;
- virtual void Close() OVERRIDE;
- virtual void SystemDragEnded() OVERRIDE;
- virtual void UserGestureDone() OVERRIDE;
- virtual void SetClosedByUserGesture(bool value) OVERRIDE;
- virtual bool GetClosedByUserGesture() const OVERRIDE;
- virtual int GetZoomPercent(bool* enable_increment,
- bool* enable_decrement) const OVERRIDE;
- virtual void ViewSource() OVERRIDE;
- virtual void ViewFrameSource(const GURL& url,
- const PageState& page_state) OVERRIDE;
- virtual int GetMinimumZoomPercent() const OVERRIDE;
- virtual int GetMaximumZoomPercent() const OVERRIDE;
- virtual gfx::Size GetPreferredSize() const OVERRIDE;
- virtual bool GotResponseToLockMouseRequest(bool allowed) OVERRIDE;
- virtual bool HasOpener() const OVERRIDE;
- virtual void DidChooseColorInColorChooser(SkColor color) OVERRIDE;
- virtual void DidEndColorChooser() OVERRIDE;
- virtual int DownloadImage(const GURL& url,
- bool is_favicon,
- uint32_t max_bitmap_size,
- const ImageDownloadCallback& callback) OVERRIDE;
- virtual bool IsSubframe() const OVERRIDE;
- virtual void Find(int request_id,
- const base::string16& search_text,
- const blink::WebFindOptions& options) OVERRIDE;
- virtual void StopFinding(StopFindAction action) OVERRIDE;
- virtual void InsertCSS(const std::string& css) OVERRIDE;
+ const base::string16& GetTitle() const override;
+ int32 GetMaxPageID() override;
+ int32 GetMaxPageIDForSiteInstance(SiteInstance* site_instance) override;
+ SiteInstanceImpl* GetSiteInstance() const override;
+ SiteInstanceImpl* GetPendingSiteInstance() const override;
+ bool IsLoading() const override;
+ bool IsLoadingToDifferentDocument() const override;
+ bool IsWaitingForResponse() const override;
+ const net::LoadStateWithParam& GetLoadState() const override;
+ const base::string16& GetLoadStateHost() const override;
+ uint64 GetUploadSize() const override;
+ uint64 GetUploadPosition() const override;
+ std::set<GURL> GetSitesInTab() const override;
+ const std::string& GetEncoding() const override;
+ bool DisplayedInsecureContent() const override;
+ void IncrementCapturerCount(const gfx::Size& capture_size) override;
+ void DecrementCapturerCount() override;
+ int GetCapturerCount() const override;
+ bool IsAudioMuted() const override;
+ void SetAudioMuted(bool mute) override;
+ bool IsCrashed() const override;
+ void SetIsCrashed(base::TerminationStatus status, int error_code) override;
+ base::TerminationStatus GetCrashedStatus() const override;
+ bool IsBeingDestroyed() const override;
+ void NotifyNavigationStateChanged(InvalidateTypes changed_flags) override;
+ base::TimeTicks GetLastActiveTime() const override;
+ void WasShown() override;
+ void WasHidden() override;
+ bool NeedToFireBeforeUnload() override;
+ void DispatchBeforeUnload(bool for_cross_site_transition) override;
+ void Stop() override;
+ WebContents* Clone() override;
+ void ReloadFocusedFrame(bool ignore_cache) override;
+ void Undo() override;
+ void Redo() override;
+ void Cut() override;
+ void Copy() override;
+ void CopyToFindPboard() override;
+ void Paste() override;
+ void PasteAndMatchStyle() override;
+ void Delete() override;
+ void SelectAll() override;
+ void Unselect() override;
+ void Replace(const base::string16& word) override;
+ void ReplaceMisspelling(const base::string16& word) override;
+ void NotifyContextMenuClosed(
+ const CustomContextMenuContext& context) override;
+ void ExecuteCustomContextMenuCommand(
+ int action,
+ const CustomContextMenuContext& context) override;
+ gfx::NativeView GetNativeView() override;
+ gfx::NativeView GetContentNativeView() override;
+ gfx::NativeWindow GetTopLevelNativeWindow() override;
+ gfx::Rect GetContainerBounds() override;
+ gfx::Rect GetViewBounds() override;
+ DropData* GetDropData() override;
+ void Focus() override;
+ void SetInitialFocus() override;
+ void StoreFocus() override;
+ void RestoreFocus() override;
+ void FocusThroughTabTraversal(bool reverse) override;
+ bool ShowingInterstitialPage() const override;
+ InterstitialPage* GetInterstitialPage() const override;
+ bool IsSavable() override;
+ void OnSavePage() override;
+ bool SavePage(const base::FilePath& main_file,
+ const base::FilePath& dir_path,
+ SavePageType save_type) override;
+ void SaveFrame(const GURL& url, const Referrer& referrer) override;
+ void GenerateMHTML(const base::FilePath& file,
+ const base::Callback<void(int64)>& callback) override;
+ const std::string& GetContentsMimeType() const override;
+ bool WillNotifyDisconnection() const override;
+ void SetOverrideEncoding(const std::string& encoding) override;
+ void ResetOverrideEncoding() override;
+ RendererPreferences* GetMutableRendererPrefs() override;
+ void Close() override;
+ void SystemDragEnded() override;
+ void UserGestureDone() override;
+ void SetClosedByUserGesture(bool value) override;
+ bool GetClosedByUserGesture() const override;
+ void ViewSource() override;
+ void ViewFrameSource(const GURL& url, const PageState& page_state) override;
+ int GetMinimumZoomPercent() const override;
+ int GetMaximumZoomPercent() const override;
+ gfx::Size GetPreferredSize() const override;
+ bool GotResponseToLockMouseRequest(bool allowed) override;
+ bool HasOpener() const override;
+ void DidChooseColorInColorChooser(SkColor color) override;
+ void DidEndColorChooser() override;
+ int DownloadImage(const GURL& url,
+ bool is_favicon,
+ uint32_t max_bitmap_size,
+ const ImageDownloadCallback& callback) override;
+ bool IsSubframe() const override;
+ void Find(int request_id,
+ const base::string16& search_text,
+ const blink::WebFindOptions& options) override;
+ void StopFinding(StopFindAction action) override;
+ void InsertCSS(const std::string& css) override;
+ bool WasRecentlyAudible() override;
+ void GetManifest(const GetManifestCallback&) override;
#if defined(OS_ANDROID)
virtual base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents()
- OVERRIDE;
+ override;
+ virtual WebContentsAndroid* GetWebContentsAndroid();
#elif defined(OS_MACOSX)
- virtual void SetAllowOverlappingViews(bool overlapping) OVERRIDE;
- virtual bool GetAllowOverlappingViews() OVERRIDE;
- virtual void SetOverlayView(WebContents* overlay,
- const gfx::Point& offset) OVERRIDE;
- virtual void RemoveOverlayView() OVERRIDE;
+ void SetAllowOtherViews(bool allow) override;
+ bool GetAllowOtherViews() override;
#endif
// Implementation of PageNavigator.
- virtual WebContents* OpenURL(const OpenURLParams& params) OVERRIDE;
+ WebContents* OpenURL(const OpenURLParams& params) override;
// Implementation of IPC::Sender.
- virtual bool Send(IPC::Message* message) OVERRIDE;
+ bool Send(IPC::Message* message) override;
// RenderFrameHostDelegate ---------------------------------------------------
- virtual bool OnMessageReceived(RenderFrameHost* render_frame_host,
- const IPC::Message& message) OVERRIDE;
- virtual const GURL& GetMainFrameLastCommittedURL() const OVERRIDE;
- virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void DidStartLoading(RenderFrameHost* render_frame_host,
- bool to_different_document) OVERRIDE;
- virtual void SwappedOut(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void WorkerCrashed(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void ShowContextMenu(RenderFrameHost* render_frame_host,
- const ContextMenuParams& params) OVERRIDE;
- virtual void RunJavaScriptMessage(RenderFrameHost* render_frame_host,
- const base::string16& message,
- const base::string16& default_prompt,
- const GURL& frame_url,
- JavaScriptMessageType type,
- IPC::Message* reply_msg) OVERRIDE;
- virtual void RunBeforeUnloadConfirm(RenderFrameHost* render_frame_host,
- const base::string16& message,
- bool is_reload,
- IPC::Message* reply_msg) OVERRIDE;
- virtual void DidAccessInitialDocument() OVERRIDE;
- virtual void DidDisownOpener(RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void DocumentOnLoadCompleted(
- RenderFrameHost* render_frame_host) OVERRIDE;
- virtual void UpdateTitle(RenderFrameHost* render_frame_host,
- int32 page_id,
- const base::string16& title,
- base::i18n::TextDirection title_direction) OVERRIDE;
- virtual void UpdateEncoding(RenderFrameHost* render_frame_host,
- const std::string& encoding) OVERRIDE;
- virtual WebContents* GetAsWebContents() OVERRIDE;
- virtual bool IsNeverVisible() OVERRIDE;
+ bool OnMessageReceived(RenderFrameHost* render_frame_host,
+ const IPC::Message& message) override;
+ const GURL& GetMainFrameLastCommittedURL() const override;
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+ void DidStartLoading(RenderFrameHost* render_frame_host,
+ bool to_different_document) override;
+ void SwappedOut(RenderFrameHost* render_frame_host) override;
+ void DidDeferAfterResponseStarted(
+ const TransitionLayerData& transition_data) override;
+ bool WillHandleDeferAfterResponseStarted() override;
+ void WorkerCrashed(RenderFrameHost* render_frame_host) override;
+ void ShowContextMenu(RenderFrameHost* render_frame_host,
+ const ContextMenuParams& params) override;
+ void RunJavaScriptMessage(RenderFrameHost* render_frame_host,
+ const base::string16& message,
+ const base::string16& default_prompt,
+ const GURL& frame_url,
+ 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;
+ void DidDisownOpener(RenderFrameHost* render_frame_host) override;
+ void DocumentOnLoadCompleted(RenderFrameHost* render_frame_host) override;
+ void UpdateTitle(RenderFrameHost* render_frame_host,
+ int32 page_id,
+ const base::string16& title,
+ base::i18n::TextDirection title_direction) override;
+ void UpdateEncoding(RenderFrameHost* render_frame_host,
+ const std::string& encoding) override;
+ WebContents* GetAsWebContents() override;
+ bool IsNeverVisible() override;
+ AccessibilityMode GetAccessibilityMode() const override;
+ void AccessibilityEventReceived(
+ const std::vector<AXEventNotificationDetails>& details) override;
+ RenderFrameHost* GetGuestByInstanceID(
+ int browser_plugin_instance_id) override;
+ GeolocationServiceContext* GetGeolocationServiceContext() override;
+#if defined(OS_WIN)
+ gfx::NativeViewAccessible GetParentNativeViewAccessible() override;
+#endif
// RenderViewHostDelegate ----------------------------------------------------
- virtual RenderViewHostDelegateView* GetDelegateView() OVERRIDE;
- virtual bool OnMessageReceived(RenderViewHost* render_view_host,
- const IPC::Message& message) OVERRIDE;
+ RenderViewHostDelegateView* GetDelegateView() override;
+ bool OnMessageReceived(RenderViewHost* render_view_host,
+ const IPC::Message& message) override;
// RenderFrameHostDelegate has the same method, so list it there because this
// interface is going away.
- // virtual WebContents* GetAsWebContents() OVERRIDE;
- virtual gfx::Rect GetRootWindowResizerRect() const OVERRIDE;
- virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
- virtual void RenderViewReady(RenderViewHost* render_view_host) OVERRIDE;
- virtual void RenderViewTerminated(RenderViewHost* render_view_host,
- base::TerminationStatus status,
- int error_code) OVERRIDE;
- virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE;
- virtual void UpdateState(RenderViewHost* render_view_host,
- int32 page_id,
- const PageState& page_state) OVERRIDE;
- virtual void UpdateTargetURL(int32 page_id, const GURL& url) OVERRIDE;
- virtual void Close(RenderViewHost* render_view_host) OVERRIDE;
- virtual void RequestMove(const gfx::Rect& new_bounds) OVERRIDE;
- virtual void DidCancelLoading() OVERRIDE;
- virtual void DocumentAvailableInMainFrame(
- RenderViewHost* render_view_host) OVERRIDE;
- virtual void RouteCloseEvent(RenderViewHost* rvh) OVERRIDE;
- virtual void RouteMessageEvent(
- RenderViewHost* rvh,
- const ViewMsg_PostMessage_Params& params) OVERRIDE;
- virtual bool AddMessageToConsole(int32 level,
- const base::string16& message,
- int32 line_no,
- const base::string16& source_id) OVERRIDE;
- virtual RendererPreferences GetRendererPrefs(
- BrowserContext* browser_context) const OVERRIDE;
- virtual WebPreferences GetWebkitPrefs() OVERRIDE;
- virtual void OnUserGesture() OVERRIDE;
- virtual void OnIgnoredUIEvent() OVERRIDE;
- virtual void RendererUnresponsive(RenderViewHost* render_view_host,
- bool is_during_beforeunload,
- bool is_during_unload) OVERRIDE;
- virtual void RendererResponsive(RenderViewHost* render_view_host) OVERRIDE;
- virtual void LoadStateChanged(const GURL& url,
- const net::LoadStateWithParam& load_state,
- uint64 upload_position,
- uint64 upload_size) OVERRIDE;
- virtual void Activate() OVERRIDE;
- virtual void Deactivate() OVERRIDE;
- virtual void LostCapture() OVERRIDE;
- virtual void HandleMouseDown() OVERRIDE;
- virtual void HandleMouseUp() OVERRIDE;
- virtual void HandlePointerActivate() OVERRIDE;
- virtual void HandleGestureBegin() OVERRIDE;
- virtual void HandleGestureEnd() OVERRIDE;
- virtual void RunFileChooser(
- RenderViewHost* render_view_host,
- const FileChooserParams& params) OVERRIDE;
- virtual void ToggleFullscreenMode(bool enter_fullscreen) OVERRIDE;
- virtual bool IsFullscreenForCurrentTab() const OVERRIDE;
- virtual void UpdatePreferredSize(const gfx::Size& pref_size) OVERRIDE;
- virtual void ResizeDueToAutoResize(const gfx::Size& new_size) OVERRIDE;
- virtual void RequestToLockMouse(bool user_gesture,
- bool last_unlocked_by_target) OVERRIDE;
- virtual void LostMouseLock() OVERRIDE;
- virtual void CreateNewWindow(
+ // virtual WebContents* GetAsWebContents() override;
+ gfx::Rect GetRootWindowResizerRect() const override;
+ void RenderViewCreated(RenderViewHost* render_view_host) override;
+ void RenderViewReady(RenderViewHost* render_view_host) override;
+ void RenderViewTerminated(RenderViewHost* render_view_host,
+ base::TerminationStatus status,
+ int error_code) override;
+ void RenderViewDeleted(RenderViewHost* render_view_host) override;
+ void UpdateState(RenderViewHost* render_view_host,
+ int32 page_id,
+ const PageState& page_state) override;
+ void UpdateTargetURL(const GURL& url) override;
+ void Close(RenderViewHost* render_view_host) override;
+ void RequestMove(const gfx::Rect& new_bounds) override;
+ void DidCancelLoading() override;
+ void DocumentAvailableInMainFrame(RenderViewHost* render_view_host) override;
+ void RouteCloseEvent(RenderViewHost* rvh) override;
+ void RouteMessageEvent(RenderViewHost* rvh,
+ const ViewMsg_PostMessage_Params& params) override;
+ bool AddMessageToConsole(int32 level,
+ const base::string16& message,
+ int32 line_no,
+ const base::string16& source_id) override;
+ RendererPreferences GetRendererPrefs(
+ BrowserContext* browser_context) const override;
+ WebPreferences ComputeWebkitPrefs() override;
+ void OnUserGesture() override;
+ void OnIgnoredUIEvent() override;
+ void RendererUnresponsive(RenderViewHost* render_view_host) override;
+ void RendererResponsive(RenderViewHost* render_view_host) override;
+ void LoadStateChanged(const GURL& url,
+ const net::LoadStateWithParam& load_state,
+ uint64 upload_position,
+ uint64 upload_size) override;
+ void Activate() override;
+ void Deactivate() override;
+ void LostCapture() override;
+ void HandleMouseDown() override;
+ void HandleMouseUp() override;
+ void HandlePointerActivate() override;
+ void HandleGestureBegin() override;
+ void HandleGestureEnd() override;
+ void RunFileChooser(RenderViewHost* render_view_host,
+ const FileChooserParams& params) override;
+ void ToggleFullscreenMode(bool enter_fullscreen) override;
+ bool IsFullscreenForCurrentTab() const override;
+ void UpdatePreferredSize(const gfx::Size& pref_size) override;
+ void ResizeDueToAutoResize(const gfx::Size& new_size) override;
+ void RequestToLockMouse(bool user_gesture,
+ bool last_unlocked_by_target) override;
+ void LostMouseLock() override;
+ void CreateNewWindow(
int render_process_id,
int route_id,
int main_frame_route_id,
const ViewHostMsg_CreateWindow_Params& params,
- SessionStorageNamespace* session_storage_namespace) OVERRIDE;
- virtual void CreateNewWidget(int render_process_id,
- int route_id,
- blink::WebPopupType popup_type) OVERRIDE;
- virtual void CreateNewFullscreenWidget(int render_process_id,
- int route_id) OVERRIDE;
- virtual void ShowCreatedWindow(int route_id,
- WindowOpenDisposition disposition,
- const gfx::Rect& initial_pos,
- bool user_gesture) OVERRIDE;
- virtual void ShowCreatedWidget(int route_id,
- const gfx::Rect& initial_pos) OVERRIDE;
- virtual void ShowCreatedFullscreenWidget(int route_id) OVERRIDE;
- virtual void RequestMediaAccessPermission(
+ SessionStorageNamespace* session_storage_namespace) override;
+ void CreateNewWidget(int render_process_id,
+ int route_id,
+ blink::WebPopupType popup_type) override;
+ void CreateNewFullscreenWidget(int render_process_id, int route_id) override;
+ void ShowCreatedWindow(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) override;
+ void ShowCreatedWidget(int route_id, const gfx::Rect& initial_pos) override;
+ void ShowCreatedFullscreenWidget(int route_id) override;
+ void RequestMediaAccessPermission(
const MediaStreamRequest& request,
- const MediaResponseCallback& callback) OVERRIDE;
- virtual SessionStorageNamespace* GetSessionStorageNamespace(
- SiteInstance* instance) OVERRIDE;
- virtual SessionStorageNamespaceMap GetSessionStorageNamespaceMap() OVERRIDE;
- virtual FrameTree* GetFrameTree() OVERRIDE;
- virtual void AccessibilityEventReceived(
- const std::vector<AXEventNotificationDetails>& details) OVERRIDE;
+ const MediaResponseCallback& callback) override;
+ bool CheckMediaAccessPermission(const GURL& security_origin,
+ MediaStreamType type) override;
+ SessionStorageNamespace* GetSessionStorageNamespace(
+ SiteInstance* instance) override;
+ SessionStorageNamespaceMap GetSessionStorageNamespaceMap() override;
+ FrameTree* GetFrameTree() override;
// NavigatorDelegate ---------------------------------------------------------
- virtual void DidStartProvisionalLoad(
- RenderFrameHostImpl* render_frame_host,
- int parent_routing_id,
- const GURL& validated_url,
- bool is_error_page,
- bool is_iframe_srcdoc) OVERRIDE;
- virtual void DidFailProvisionalLoadWithError(
+ void DidStartProvisionalLoad(RenderFrameHostImpl* render_frame_host,
+ const GURL& validated_url,
+ bool is_error_page,
+ bool is_iframe_srcdoc) override;
+ void DidStartNavigationTransition(
+ RenderFrameHostImpl* render_frame_host) override;
+ void DidFailProvisionalLoadWithError(
RenderFrameHostImpl* render_frame_host,
const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params)
- OVERRIDE;
- virtual void DidFailLoadWithError(
- RenderFrameHostImpl* render_frame_host,
- const GURL& url,
- int error_code,
- const base::string16& error_description) OVERRIDE;
- virtual void DidRedirectProvisionalLoad(
- RenderFrameHostImpl* render_frame_host,
- const GURL& validated_target_url) OVERRIDE;
- virtual void DidCommitProvisionalLoad(
- RenderFrameHostImpl* render_frame_host,
- const base::string16& frame_unique_name,
- bool is_main_frame,
- const GURL& url,
- PageTransition transition_type) OVERRIDE;
- virtual void DidNavigateMainFramePreCommit(
- const FrameHostMsg_DidCommitProvisionalLoad_Params& params) OVERRIDE;
- virtual void DidNavigateMainFramePostCommit(
+ override;
+ void DidFailLoadWithError(RenderFrameHostImpl* render_frame_host,
+ const GURL& url,
+ int error_code,
+ const base::string16& error_description) override;
+ void DidCommitProvisionalLoad(RenderFrameHostImpl* render_frame_host,
+ const GURL& url,
+ ui::PageTransition transition_type) override;
+ void DidNavigateMainFramePreCommit(bool navigation_is_within_page) override;
+ void DidNavigateMainFramePostCommit(
const LoadCommittedDetails& details,
- const FrameHostMsg_DidCommitProvisionalLoad_Params& params) OVERRIDE;
- virtual void DidNavigateAnyFramePostCommit(
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params) override;
+ void DidNavigateAnyFramePostCommit(
RenderFrameHostImpl* render_frame_host,
const LoadCommittedDetails& details,
- const FrameHostMsg_DidCommitProvisionalLoad_Params& params) OVERRIDE;
- virtual void SetMainFrameMimeType(const std::string& mime_type) OVERRIDE;
- virtual bool CanOverscrollContent() const OVERRIDE;
- virtual void NotifyChangedNavigationState(
- InvalidateTypes changed_flags) OVERRIDE;
- virtual void AboutToNavigateRenderFrame(
- RenderFrameHostImpl* render_frame_host) OVERRIDE;
- virtual void DidStartNavigationToPendingEntry(
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params) override;
+ void SetMainFrameMimeType(const std::string& mime_type) override;
+ bool CanOverscrollContent() const override;
+ void NotifyChangedNavigationState(InvalidateTypes changed_flags) override;
+ void AboutToNavigateRenderFrame(
+ RenderFrameHostImpl* render_frame_host) override;
+ void DidStartNavigationToPendingEntry(
RenderFrameHostImpl* render_frame_host,
const GURL& url,
- NavigationController::ReloadType reload_type) OVERRIDE;
- virtual void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
- const OpenURLParams& params) OVERRIDE;
- virtual bool ShouldPreserveAbortedURLs() OVERRIDE;
+ NavigationController::ReloadType reload_type) override;
+ void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
+ const OpenURLParams& params) override;
+ bool ShouldPreserveAbortedURLs() override;
// RenderWidgetHostDelegate --------------------------------------------------
- virtual void RenderWidgetDeleted(
- RenderWidgetHostImpl* render_widget_host) OVERRIDE;
- virtual bool PreHandleKeyboardEvent(
- const NativeWebKeyboardEvent& event,
- bool* is_keyboard_shortcut) OVERRIDE;
- virtual void HandleKeyboardEvent(
- const NativeWebKeyboardEvent& event) OVERRIDE;
- virtual bool HandleWheelEvent(
- const blink::WebMouseWheelEvent& event) OVERRIDE;
- virtual bool PreHandleGestureEvent(
- const blink::WebGestureEvent& event) OVERRIDE;
- virtual bool HandleGestureEvent(
- const blink::WebGestureEvent& event) OVERRIDE;
- virtual void DidSendScreenRects(RenderWidgetHostImpl* rwh) OVERRIDE;
- virtual void OnTouchEmulationEnabled(bool enabled) OVERRIDE;
-#if defined(OS_WIN)
- virtual gfx::NativeViewAccessible GetParentNativeViewAccessible() OVERRIDE;
-#endif
+ void RenderWidgetDeleted(RenderWidgetHostImpl* render_widget_host) override;
+ void RenderWidgetGotFocus(RenderWidgetHostImpl* render_widget_host) override;
+ bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) override;
+ void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) override;
+ bool HandleWheelEvent(const blink::WebMouseWheelEvent& event) override;
+ bool PreHandleGestureEvent(const blink::WebGestureEvent& event) override;
+ bool HandleGestureEvent(const blink::WebGestureEvent& event) override;
+ void DidSendScreenRects(RenderWidgetHostImpl* rwh) override;
+ BrowserAccessibilityManager* GetRootBrowserAccessibilityManager() override;
+ BrowserAccessibilityManager* GetOrCreateRootBrowserAccessibilityManager()
+ override;
// RenderFrameHostManager::Delegate ------------------------------------------
- virtual bool CreateRenderViewForRenderManager(
+ bool CreateRenderViewForRenderManager(
RenderViewHost* render_view_host,
int opener_route_id,
int proxy_routing_id,
- bool for_main_frame) OVERRIDE;
- virtual void BeforeUnloadFiredFromRenderManager(
- bool proceed, const base::TimeTicks& proceed_time,
- bool* proceed_to_fire_unload) OVERRIDE;
- virtual void RenderProcessGoneFromRenderManager(
- RenderViewHost* render_view_host) OVERRIDE;
- virtual void UpdateRenderViewSizeForRenderManager() OVERRIDE;
- virtual void CancelModalDialogsForRenderManager() OVERRIDE;
- virtual void NotifySwappedFromRenderManager(
- RenderViewHost* old_host, RenderViewHost* new_host) OVERRIDE;
- virtual int CreateOpenerRenderViewsForRenderManager(
- SiteInstance* instance) OVERRIDE;
- virtual NavigationControllerImpl&
- GetControllerForRenderManager() OVERRIDE;
- virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) OVERRIDE;
- virtual NavigationEntry*
- GetLastCommittedNavigationEntryForRenderManager() OVERRIDE;
- virtual bool FocusLocationBarByDefault() OVERRIDE;
- virtual void SetFocusToLocationBar(bool select_all) OVERRIDE;
- virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) OVERRIDE;
- virtual bool IsHidden() OVERRIDE;
+ bool for_main_frame_navigation) override;
+ bool CreateRenderFrameForRenderManager(RenderFrameHost* render_frame_host,
+ int parent_routing_id,
+ int proxy_routing_id) override;
+ void BeforeUnloadFiredFromRenderManager(
+ bool proceed,
+ const base::TimeTicks& proceed_time,
+ bool* proceed_to_fire_unload) override;
+ void RenderProcessGoneFromRenderManager(
+ RenderViewHost* render_view_host) override;
+ void UpdateRenderViewSizeForRenderManager() override;
+ void CancelModalDialogsForRenderManager() override;
+ void NotifySwappedFromRenderManager(RenderFrameHost* old_host,
+ RenderFrameHost* new_host,
+ bool is_main_frame) override;
+ int CreateOpenerRenderViewsForRenderManager(SiteInstance* instance) override;
+ NavigationControllerImpl& GetControllerForRenderManager() override;
+ WebUIImpl* CreateWebUIForRenderManager(const GURL& url) override;
+ NavigationEntry* GetLastCommittedNavigationEntryForRenderManager() override;
+ bool FocusLocationBarByDefault() override;
+ void SetFocusToLocationBar(bool select_all) override;
+ bool IsHidden() override;
// NotificationObserver ------------------------------------------------------
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override;
// NavigationControllerDelegate ----------------------------------------------
- virtual WebContents* GetWebContents() OVERRIDE;
- virtual void NotifyNavigationEntryCommitted(
- const LoadCommittedDetails& load_details) OVERRIDE;
+ WebContents* GetWebContents() override;
+ void NotifyNavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) override;
// Invoked before a form repost warning is shown.
- virtual void NotifyBeforeFormRepostWarningShow() OVERRIDE;
+ void NotifyBeforeFormRepostWarningShow() override;
// Activate this WebContents and show a form repost warning.
- virtual void ActivateAndShowRepostFormWarningDialog() OVERRIDE;
+ void ActivateAndShowRepostFormWarningDialog() override;
// Whether the initial empty page of this view has been accessed by another
// page, making it unsafe to show the pending URL. Always false after the
// first commit.
- virtual bool HasAccessedInitialDocument() OVERRIDE;
+ bool HasAccessedInitialDocument() override;
// Updates the max page ID for the current SiteInstance in this
// WebContentsImpl to be at least |page_id|.
- virtual void UpdateMaxPageID(int32 page_id) OVERRIDE;
+ void UpdateMaxPageID(int32 page_id) override;
// Updates the max page ID for the given SiteInstance in this WebContentsImpl
// to be at least |page_id|.
- virtual void UpdateMaxPageIDForSiteInstance(SiteInstance* site_instance,
- int32 page_id) OVERRIDE;
+ void UpdateMaxPageIDForSiteInstance(SiteInstance* site_instance,
+ int32 page_id) override;
// Copy the current map of SiteInstance ID to max page ID from another tab.
// This is necessary when this tab adopts the NavigationEntries from
// |web_contents|.
- virtual void CopyMaxPageIDsFrom(WebContents* web_contents) OVERRIDE;
+ void CopyMaxPageIDsFrom(WebContents* web_contents) override;
// Called by the NavigationController to cause the WebContentsImpl to navigate
// to the current pending entry. The NavigationController should be called
@@ -588,43 +606,63 @@ class CONTENT_EXPORT WebContentsImpl
//
// If this method returns false, then the navigation is discarded (equivalent
// to calling DiscardPendingEntry on the NavigationController).
- virtual bool NavigateToPendingEntry(
- NavigationController::ReloadType reload_type) OVERRIDE;
+ bool NavigateToPendingEntry(
+ NavigationController::ReloadType reload_type) override;
// Sets the history for this WebContentsImpl to |history_length| entries, and
// moves the current page_id to the last entry in the list if it's valid.
// This is mainly used when a prerendered page is swapped into the current
// tab. The method is virtual for testing.
- virtual void SetHistoryLengthAndPrune(
- const SiteInstance* site_instance,
- int merge_history_length,
- int32 minimum_page_id) OVERRIDE;
+ void SetHistoryLengthAndPrune(const SiteInstance* site_instance,
+ int merge_history_length,
+ int32 minimum_page_id) override;
// Called by InterstitialPageImpl when it creates a RenderFrameHost.
- virtual void RenderFrameForInterstitialPageCreated(
- RenderFrameHost* render_frame_host) OVERRIDE;
+ void RenderFrameForInterstitialPageCreated(
+ RenderFrameHost* render_frame_host) override;
// Sets the passed interstitial as the currently showing interstitial.
// No interstitial page should already be attached.
- virtual void AttachInterstitialPage(
- InterstitialPageImpl* interstitial_page) OVERRIDE;
+ void AttachInterstitialPage(InterstitialPageImpl* interstitial_page) override;
// Unsets the currently showing interstitial.
- virtual void DetachInterstitialPage() OVERRIDE;
+ 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).
- virtual void SetIsLoading(RenderViewHost* render_view_host,
- bool is_loading,
- bool to_different_document,
- LoadNotificationDetails* details) OVERRIDE;
+ void SetIsLoading(RenderViewHost* render_view_host,
+ bool is_loading,
+ bool to_different_document,
+ LoadNotificationDetails* details) override;
typedef base::Callback<void(WebContents*)> CreatedCallback;
+ // Requests the renderer to move the selection extent to a new position.
+ void MoveRangeSelectionExtent(const gfx::Point& extent);
+
// Requests the renderer to select the region between two points in the
// currently focused frame.
- void SelectRange(const gfx::Point& start, const gfx::Point& end);
+ void SelectRange(const gfx::Point& base, const gfx::Point& extent);
+
+ // Notifies the main frame that it can continue navigation (if it was deferred
+ // immediately at first response).
+ void ResumeResponseDeferredAtStart();
+
+ // Forces overscroll to be disabled (used by touch emulation).
+ void SetForceDisableOverscrollContent(bool force_disable);
+
+ AudioStreamMonitor* audio_stream_monitor() {
+ return &audio_stream_monitor_;
+ }
+
+ bool has_audio_power_save_blocker_for_testing() const {
+ return audio_power_save_blocker_;
+ }
+
+ bool has_video_power_save_blocker_for_testing() const {
+ return video_power_save_blocker_;
+ }
private:
friend class TestNavigationObserver;
@@ -644,6 +682,8 @@ class CONTENT_EXPORT WebContentsImpl
FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest, HistoryNavigate);
FRIEND_TEST_ALL_PREFIXES(RenderFrameHostManagerTest, PageDoesBackAndReload);
FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, CrossSiteIframe);
+ FRIEND_TEST_ALL_PREFIXES(SitePerProcessAccessibilityBrowserTest,
+ CrossSiteIframeAccessibility);
// So InterstitialPageImpl can access SetIsLoading.
friend class InterstitialPageImpl;
@@ -688,10 +728,6 @@ class CONTENT_EXPORT WebContentsImpl
bool success,
const base::string16& user_input);
- // Callback function when requesting permission to access the PPAPI broker.
- // |result| is true if permission was granted.
- void OnPpapiBrokerPermissionResult(int routing_id, bool result);
-
bool OnMessageReceived(RenderViewHost* render_view_host,
RenderFrameHost* render_frame_host,
const IPC::Message& message);
@@ -702,7 +738,7 @@ class CONTENT_EXPORT WebContentsImpl
const std::string& security_info,
const std::string& http_request,
const std::string& mime_type,
- ResourceType::Type resource_type);
+ ResourceType resource_type);
void OnDidDisplayInsecureContent();
void OnDidRunInsecureContent(const std::string& security_origin,
const GURL& target_url);
@@ -720,6 +756,9 @@ class CONTENT_EXPORT WebContentsImpl
const GURL& url,
const base::string16& title,
bool user_gesture);
+ void OnUnregisterProtocolHandler(const std::string& protocol,
+ const GURL& url,
+ bool user_gesture);
void OnFindReply(int request_id,
int number_of_matches,
const gfx::Rect& selection_rect,
@@ -733,11 +772,6 @@ class CONTENT_EXPORT WebContentsImpl
void OnOpenDateTimeDialog(
const ViewHostMsg_DateTimeDialogValue_Params& value);
#endif
- void OnPepperPluginHung(int plugin_child_id,
- const base::FilePath& path,
- bool is_hung);
- void OnPluginCrashed(const base::FilePath& plugin_path,
- base::ProcessId plugin_pid);
void OnDomOperationResponse(const std::string& json_string,
int automation_id);
void OnAppCacheAccessed(const GURL& manifest_url, bool blocked_by_policy);
@@ -749,10 +783,22 @@ class CONTENT_EXPORT WebContentsImpl
void OnWebUISend(const GURL& source_url,
const std::string& name,
const base::ListValue& args);
+#if defined(ENABLE_PLUGINS)
+ void OnPepperPluginHung(int plugin_child_id,
+ const base::FilePath& path,
+ bool is_hung);
+ void OnPluginCrashed(const base::FilePath& plugin_path,
+ base::ProcessId plugin_pid);
void OnRequestPpapiBrokerPermission(int routing_id,
const GURL& url,
const base::FilePath& plugin_path);
+
+ // Callback function when requesting permission to access the PPAPI broker.
+ // |result| is true if permission was granted.
+ void OnPpapiBrokerPermissionResult(int routing_id, bool result);
+
void OnBrowserPluginMessage(const IPC::Message& message);
+#endif // defined(ENABLE_PLUGINS)
void OnDidDownloadImage(int id,
int http_status_code,
const GURL& image_url,
@@ -762,7 +808,8 @@ class CONTENT_EXPORT WebContentsImpl
void OnFirstVisuallyNonEmptyPaint();
void OnMediaPlayingNotification(int64 player_cookie,
bool has_video,
- bool has_audio);
+ bool has_audio,
+ bool is_remote);
void OnMediaPausedNotification(int64 player_cookie);
void OnShowValidationMessage(const gfx::Rect& anchor_in_root_view,
const base::string16& main_text,
@@ -841,7 +888,8 @@ class CONTENT_EXPORT WebContentsImpl
// Misc non-view stuff -------------------------------------------------------
// Helper functions for sending notifications.
- void NotifySwapped(RenderViewHost* old_host, RenderViewHost* new_host);
+ void NotifyViewSwapped(RenderViewHost* old_host, RenderViewHost* new_host);
+ void NotifyFrameSwapped(RenderFrameHost* old_host, RenderFrameHost* new_host);
void NotifyDisconnected();
void SetEncoding(const std::string& encoding);
@@ -855,23 +903,44 @@ class CONTENT_EXPORT WebContentsImpl
// Removes browser plugin embedder if there is one.
void RemoveBrowserPluginEmbedder();
- // Clear |render_frame_host|'s PowerSaveBlockers.
+ // Clear |render_frame_host|'s tracking entry for its power save blockers.
void ClearPowerSaveBlockers(RenderFrameHost* render_frame_host);
- // Clear all PowerSaveBlockers, leave power_save_blocker_ empty.
+ // Clear tracking entries for all RenderFrameHosts, clears
+ // |audio_power_save_blocker_| and |video_power_save_blocker_|.
void ClearAllPowerSaveBlockers();
+ // Creates an audio or video power save blocker respectively.
+ void CreateAudioPowerSaveBlocker();
+ void CreateVideoPowerSaveBlocker();
+
+ // Releases the audio power save blockers if |active_audio_players_| is empty.
+ // Likewise, releases the video power save blockers if |active_video_players_|
+ // is empty.
+ void MaybeReleasePowerSaveBlockers();
+
// Helper function to invoke WebContentsDelegate::GetSizeForNewRenderView().
gfx::Size GetSizeForNewRenderView();
- void OnFrameRemoved(RenderViewHostImpl* render_view_host,
- int frame_routing_id);
+ void OnFrameRemoved(RenderFrameHost* render_frame_host);
// Helper method that's called whenever |preferred_size_| or
// |preferred_size_for_capture_| changes, to propagate the new value to the
// |delegate_|.
void OnPreferredSizeChanged(const gfx::Size& old_size);
+ // Helper methods for adding or removing player entries in |player_map| under
+ // the key |render_frame_message_source_|.
+ typedef std::vector<int64> PlayerList;
+ typedef std::map<uintptr_t, PlayerList> ActiveMediaPlayerMap;
+ void AddMediaPlayerEntry(int64 player_cookie,
+ ActiveMediaPlayerMap* player_map);
+ void RemoveMediaPlayerEntry(int64 player_cookie,
+ ActiveMediaPlayerMap* player_map);
+ // Removes all entries from |player_map| for |render_frame_host|.
+ void RemoveAllMediaPlayerEntries(RenderFrameHost* render_frame_host,
+ ActiveMediaPlayerMap* player_map);
+
// Adds/removes a callback called on creation of each new WebContents.
// Deprecated, about to remove.
static void AddCreatedCallback(const CreatedCallback& callback);
@@ -926,12 +995,11 @@ class CONTENT_EXPORT WebContentsImpl
// Helper classes ------------------------------------------------------------
- // Maps the RenderFrameHost to its media_player_cookie and PowerSaveBlocker
- // pairs. Key is the RenderFrameHost, value is the map which maps
- // player_cookie on to PowerSaveBlocker.
- typedef std::map<RenderFrameHost*, std::map<int64, PowerSaveBlocker*> >
- PowerSaveBlockerMap;
- PowerSaveBlockerMap power_save_blockers_;
+ // 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_;
// Manages the frame tree of the page and process swaps in each node.
FrameTree frame_tree_;
@@ -974,8 +1042,6 @@ class CONTENT_EXPORT WebContentsImpl
base::TimeTicks loading_last_progress_update_;
- base::WeakPtrFactory<WebContentsImpl> loading_weak_factory_;
-
// Counter to track how many frames have sent start notifications but not
// stop notifications.
int loading_frames_in_progress_;
@@ -1101,6 +1167,11 @@ class CONTENT_EXPORT WebContentsImpl
// NULL otherwise.
scoped_ptr<BrowserPluginGuest> browser_plugin_guest_;
+#if defined(ENABLE_PLUGINS)
+ // Manages the whitelist of plugin content origins exempt from power saving.
+ scoped_ptr<PluginContentOriginWhitelist> plugin_content_origin_whitelist_;
+#endif
+
// This must be at the end, or else we might get notifications and use other
// member variables that are gone.
NotificationRegistrar registrar_;
@@ -1118,6 +1189,12 @@ class CONTENT_EXPORT WebContentsImpl
// Routing id of the shown fullscreen widget or MSG_ROUTING_NONE otherwise.
int fullscreen_widget_routing_id_;
+ // At the time the fullscreen widget was being shut down, did it have focus?
+ // This is used to restore focus to the WebContentsView after both: 1) the
+ // fullscreen widget is destroyed, and 2) the WebContentsDelegate has
+ // completed making layout changes to effect an exit from fullscreen mode.
+ bool fullscreen_widget_had_focus_at_shutdown_;
+
// Maps the ids of pending image downloads to their callbacks
typedef std::map<int, ImageDownloadCallback> ImageDownloadMap;
ImageDownloadMap image_download_map_;
@@ -1126,12 +1203,14 @@ class CONTENT_EXPORT WebContentsImpl
// different process from its parent page.
bool is_subframe_;
- // Whether touch emulation is enabled in RenderWidgetHost.
- bool touch_emulation_enabled_;
+ // Whether overscroll should be unconditionally disabled.
+ bool force_disable_overscroll_content_;
// Whether the last JavaScript dialog shown was suppressed. Used for testing.
bool last_dialog_suppressed_;
+ scoped_ptr<GeolocationServiceContext> geolocation_service_context_;
+
scoped_ptr<GeolocationDispatcherHost> geolocation_dispatcher_host_;
scoped_ptr<MidiDispatcherHost> midi_dispatcher_host_;
@@ -1139,6 +1218,20 @@ class CONTENT_EXPORT WebContentsImpl
scoped_ptr<ScreenOrientationDispatcherHost>
screen_orientation_dispatcher_host_;
+ scoped_ptr<ManifestManagerHost> manifest_manager_host_;
+
+ // The accessibility mode for all frames. This is queried when each frame
+ // is created, and broadcast to all frames when it changes.
+ AccessibilityMode accessibility_mode_;
+
+ // Monitors power levels for audio streams associated with this WebContents.
+ AudioStreamMonitor audio_stream_monitor_;
+
+ // Created on-demand to mute all audio output from this WebContents.
+ scoped_ptr<WebContentsAudioMuter> audio_muter_;
+
+ base::WeakPtrFactory<WebContentsImpl> loading_weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(WebContentsImpl);
};
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 1f0586cd33d..349af0e73e5 100644
--- a/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -63,9 +63,9 @@ class LoadStopNotificationObserver : public WindowedNotificationObserver {
session_index_(-1),
controller_(NULL) {
}
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE {
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override {
if (type == NOTIFICATION_LOAD_STOP) {
const Details<LoadNotificationDetails> load_details(details);
url_ = load_details->url;
@@ -93,8 +93,8 @@ class NavigateOnCommitObserver : public WebContentsObserver {
}
// WebContentsObserver:
- virtual void NavigationEntryCommitted(
- const LoadCommittedDetails& load_details) OVERRIDE {
+ void NavigationEntryCommitted(
+ const LoadCommittedDetails& load_details) override {
if (!done_) {
done_ = true;
shell_->Stop();
@@ -114,8 +114,7 @@ class RenderViewSizeDelegate : public WebContentsDelegate {
}
// WebContentsDelegate:
- virtual gfx::Size GetSizeForNewRenderView(
- WebContents* web_contents) const OVERRIDE {
+ gfx::Size GetSizeForNewRenderView(WebContents* web_contents) const override {
gfx::Size size(web_contents->GetContainerBounds().size());
size.Enlarge(size_insets_.width(), size_insets_.height());
return size;
@@ -134,13 +133,13 @@ class RenderViewSizeObserver : public WebContentsObserver {
}
// WebContentsObserver:
- virtual void RenderViewCreated(RenderViewHost* rvh) OVERRIDE {
+ void RenderViewCreated(RenderViewHost* rvh) override {
rwhv_create_size_ = rvh->GetView()->GetViewBounds().size();
}
- virtual void DidStartNavigationToPendingEntry(
+ void DidStartNavigationToPendingEntry(
const GURL& url,
- NavigationController::ReloadType reload_type) OVERRIDE {
+ NavigationController::ReloadType reload_type) override {
ResizeWebContentsView(shell_, wcv_new_size_, false);
}
@@ -160,8 +159,8 @@ class LoadingStateChangedDelegate : public WebContentsDelegate {
}
// WebContentsDelegate:
- virtual void LoadingStateChanged(WebContents* contents,
- bool to_different_document) OVERRIDE {
+ void LoadingStateChanged(WebContents* contents,
+ bool to_different_document) override {
loadingStateChangedCount_++;
if (to_different_document)
loadingStateToDifferentDocumentCount_++;
@@ -259,9 +258,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
shell()->web_contents()->GetVisibleURL());
}
-// TODO(shrikant): enable this for Windows when issue with
-// force-compositing-mode is resolved (http://crbug.com/281726).
-// Also crashes under ThreadSanitizer, http://crbug.com/356758.
+// Crashes under ThreadSanitizer, http://crbug.com/356758.
#if defined(OS_WIN) || defined(OS_ANDROID) \
|| defined(THREAD_SANITIZER)
#define MAYBE_GetSizeForNewRenderView DISABLED_GetSizeForNewRenderView
@@ -341,20 +338,43 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
}
IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, OpenURLSubframe) {
-
- // Navigate with FrameTreeNode ID 4.
- const GURL url("http://foo");
- OpenURLParams params(url, Referrer(), 4, CURRENT_TAB, PAGE_TRANSITION_LINK,
- true);
+ // Navigate to a page with frames and grab a subframe's FrameTreeNode ID.
+ ASSERT_TRUE(test_server()->Start());
+ NavigateToURL(shell(),
+ test_server()->GetURL("files/frame_tree/top.html"));
+ WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
+ FrameTreeNode* root = wc->GetFrameTree()->root();
+ ASSERT_EQ(3UL, root->child_count());
+ int64 frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
+ EXPECT_NE(-1, frame_tree_node_id);
+
+ // Navigate with the subframe's FrameTreeNode ID.
+ const GURL url(test_server()->GetURL("files/title1.html"));
+ OpenURLParams params(url, Referrer(), frame_tree_node_id, CURRENT_TAB,
+ ui::PAGE_TRANSITION_LINK, true);
shell()->web_contents()->OpenURL(params);
// Make sure the NavigationEntry ends up with the FrameTreeNode ID.
NavigationController* controller = &shell()->web_contents()->GetController();
EXPECT_TRUE(controller->GetPendingEntry());
- EXPECT_EQ(4, NavigationEntryImpl::FromNavigationEntry(
+ EXPECT_EQ(frame_tree_node_id,
+ NavigationEntryImpl::FromNavigationEntry(
controller->GetPendingEntry())->frame_tree_node_id());
}
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ AppendingFrameInWebUIDoesNotCrash) {
+ const GURL kWebUIUrl("chrome://tracing");
+ const char kJSCodeForAppendingFrame[] =
+ "document.body.appendChild(document.createElement('iframe'));";
+
+ NavigateToURL(shell(), kWebUIUrl);
+
+ bool js_executed = content::ExecuteScript(shell()->web_contents(),
+ kJSCodeForAppendingFrame);
+ EXPECT_TRUE(js_executed);
+}
+
// Observer class to track the creation of RenderFrameHost objects. It is used
// in subsequent tests.
class RenderFrameCreatedObserver : public WebContentsObserver {
@@ -364,7 +384,7 @@ class RenderFrameCreatedObserver : public WebContentsObserver {
last_rfh_(NULL) {
}
- virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE {
+ void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
last_rfh_ = render_frame_host;
}
@@ -468,22 +488,21 @@ struct LoadProgressDelegateAndObserver : public WebContentsDelegate,
}
// WebContentsDelegate:
- virtual void LoadProgressChanged(WebContents* source,
- double progress) OVERRIDE {
+ void LoadProgressChanged(WebContents* source, double progress) override {
EXPECT_TRUE(did_start_loading);
EXPECT_FALSE(did_stop_loading);
progresses.push_back(progress);
}
// WebContentsObserver:
- virtual void DidStartLoading(RenderViewHost* render_view_host) OVERRIDE {
+ void DidStartLoading(RenderViewHost* render_view_host) override {
EXPECT_FALSE(did_start_loading);
EXPECT_EQ(0U, progresses.size());
EXPECT_FALSE(did_stop_loading);
did_start_loading = true;
}
- virtual void DidStopLoading(RenderViewHost* render_view_host) OVERRIDE {
+ void DidStopLoading(RenderViewHost* render_view_host) override {
EXPECT_TRUE(did_start_loading);
EXPECT_GE(progresses.size(), 1U);
EXPECT_FALSE(did_stop_loading);
@@ -517,5 +536,46 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, LoadProgress) {
EXPECT_EQ(1.0, *progresses.rbegin());
}
+struct FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver {
+ FirstVisuallyNonEmptyPaintObserver(Shell* shell)
+ : WebContentsObserver(shell->web_contents()),
+ did_fist_visually_non_empty_paint_(false) {}
+
+ void DidFirstVisuallyNonEmptyPaint() override {
+ did_fist_visually_non_empty_paint_ = true;
+ on_did_first_visually_non_empty_paint_.Run();
+ }
+
+ void WaitForDidFirstVisuallyNonEmptyPaint() {
+ if (did_fist_visually_non_empty_paint_)
+ return;
+ base::RunLoop run_loop;
+ on_did_first_visually_non_empty_paint_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+
+ base::Closure on_did_first_visually_non_empty_paint_;
+ bool did_fist_visually_non_empty_paint_;
+};
+
+// See: http://crbug.com/395664
+#if defined(OS_ANDROID)
+#define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
+#else
+// http://crbug.com/398471
+#define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
+#endif
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ MAYBE_FirstVisuallyNonEmptyPaint) {
+ ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+ scoped_ptr<FirstVisuallyNonEmptyPaintObserver> observer(
+ new FirstVisuallyNonEmptyPaintObserver(shell()));
+
+ NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+
+ observer->WaitForDidFirstVisuallyNonEmptyPaint();
+ ASSERT_TRUE(observer->did_fist_visually_non_empty_paint_);
+}
+
} // 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 a345598fcf0..a361553dd25 100644
--- a/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/chromium/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -7,6 +7,7 @@
#include "content/browser/frame_host/cross_site_transferring_request.h"
#include "content/browser/frame_host/interstitial_page_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/media/audio_stream_monitor.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/site_instance_impl.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
@@ -30,6 +31,7 @@
#include "content/public/test/test_utils.h"
#include "content/test/test_content_browser_client.h"
#include "content/test/test_content_client.h"
+#include "content/test/test_render_frame_host.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -42,25 +44,25 @@ const char kTestWebUIUrl[] = "chrome://blah";
class WebContentsImplTestWebUIControllerFactory
: public WebUIControllerFactory {
public:
- virtual WebUIController* CreateWebUIControllerForURL(
- WebUI* web_ui, const GURL& url) const OVERRIDE {
+ WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
+ const GURL& url) const override {
if (!UseWebUI(url))
return NULL;
return new WebUIController(web_ui);
}
- virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
+ const GURL& url) const override {
return WebUI::kNoWebUI;
}
- virtual bool UseWebUIForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ bool UseWebUIForURL(BrowserContext* browser_context,
+ const GURL& url) const override {
return UseWebUI(url);
}
- virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ bool UseWebUIBindingsForURL(BrowserContext* browser_context,
+ const GURL& url) const override {
return UseWebUI(url);
}
@@ -76,10 +78,11 @@ class TestInterstitialPageDelegate : public InterstitialPageDelegate {
public:
explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
: interstitial_page_(interstitial_page) {}
- virtual void CommandReceived(const std::string& command) OVERRIDE;
- virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
- virtual void OnDontProceed() OVERRIDE;
- virtual void OnProceed() OVERRIDE;
+ void CommandReceived(const std::string& command) override;
+ std::string GetHTMLContents() override { return std::string(); }
+ void OnDontProceed() override;
+ void OnProceed() override;
+
private:
TestInterstitialPage* interstitial_page_;
};
@@ -128,7 +131,7 @@ class TestInterstitialPage : public InterstitialPageImpl {
*deleted_ = false;
}
- virtual ~TestInterstitialPage() {
+ ~TestInterstitialPage() override {
if (deleted_)
*deleted_ = true;
if (delegate_)
@@ -155,7 +158,7 @@ class TestInterstitialPage : public InterstitialPageImpl {
void TestDidNavigate(int page_id, const GURL& url) {
FrameHostMsg_DidCommitProvisionalLoad_Params params;
- InitNavigateParams(&params, page_id, url, PAGE_TRANSITION_TYPED);
+ InitNavigateParams(&params, page_id, url, ui::PAGE_TRANSITION_TYPED);
DidNavigate(GetRenderViewHostForTesting(), params);
}
@@ -184,9 +187,7 @@ class TestInterstitialPage : public InterstitialPageImpl {
}
protected:
- virtual WebContentsView* CreateWebContentsView() OVERRIDE {
- return NULL;
- }
+ WebContentsView* CreateWebContentsView() override { return NULL; }
private:
InterstitialState* state_;
@@ -215,13 +216,13 @@ class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
DCHECK(interstitial_page_);
interstitial_page_->set_delegate(this);
}
- virtual ~TestInterstitialPageStateGuard() {
+ ~TestInterstitialPageStateGuard() override {
if (interstitial_page_)
interstitial_page_->ClearStates();
}
- virtual void TestInterstitialPageDeleted(
- TestInterstitialPage* interstitial) OVERRIDE {
+ void TestInterstitialPageDeleted(
+ TestInterstitialPage* interstitial) override {
DCHECK(interstitial_page_ == interstitial);
interstitial_page_ = NULL;
}
@@ -235,9 +236,9 @@ class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
WebContentsImplTestBrowserClient()
: assign_site_for_url_(false) {}
- virtual ~WebContentsImplTestBrowserClient() {}
+ ~WebContentsImplTestBrowserClient() override {}
- virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
+ bool ShouldAssignSiteForURL(const GURL& url) override {
return assign_site_for_url_;
}
@@ -251,12 +252,12 @@ class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
class WebContentsImplTest : public RenderViewHostImplTestHarness {
public:
- virtual void SetUp() {
+ void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
WebUIControllerFactory::RegisterFactory(&factory_);
}
- virtual void TearDown() {
+ void TearDown() override {
WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
RenderViewHostImplTestHarness::TearDown();
}
@@ -270,20 +271,16 @@ class TestWebContentsObserver : public WebContentsObserver {
explicit TestWebContentsObserver(WebContents* contents)
: WebContentsObserver(contents) {
}
- virtual ~TestWebContentsObserver() {}
+ ~TestWebContentsObserver() override {}
- virtual void DidFinishLoad(int64 frame_id,
- const GURL& validated_url,
- bool is_main_frame,
- RenderViewHost* render_view_host) OVERRIDE {
+ void DidFinishLoad(RenderFrameHost* render_frame_host,
+ const GURL& validated_url) override {
last_url_ = validated_url;
}
- virtual void DidFailLoad(int64 frame_id,
- const GURL& validated_url,
- bool is_main_frame,
- int error_code,
- const base::string16& error_description,
- RenderViewHost* render_view_host) OVERRIDE {
+ void DidFailLoad(RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code,
+ const base::string16& error_description) override {
last_url_ = validated_url;
}
@@ -300,15 +297,15 @@ class TestWebContentsObserver : public WebContentsObserver {
class FakeFullscreenDelegate : public WebContentsDelegate {
public:
FakeFullscreenDelegate() : fullscreened_contents_(NULL) {}
- virtual ~FakeFullscreenDelegate() {}
+ ~FakeFullscreenDelegate() override {}
- virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
- bool enter_fullscreen) OVERRIDE {
+ void ToggleFullscreenModeForTab(WebContents* web_contents,
+ bool enter_fullscreen) override {
fullscreened_contents_ = enter_fullscreen ? web_contents : NULL;
}
- virtual bool IsFullscreenForTabOrPending(const WebContents* web_contents)
- const OVERRIDE {
+ bool IsFullscreenForTabOrPending(
+ const WebContents* web_contents) const override {
return fullscreened_contents_ && web_contents == fullscreened_contents_;
}
@@ -322,9 +319,9 @@ class FakeValidationMessageDelegate : public WebContentsDelegate {
public:
FakeValidationMessageDelegate()
: hide_validation_message_was_called_(false) {}
- virtual ~FakeValidationMessageDelegate() {}
+ ~FakeValidationMessageDelegate() override {}
- virtual void HideValidationMessage(WebContents* web_contents) OVERRIDE {
+ void HideValidationMessage(WebContents* web_contents) override {
hide_validation_message_was_called_ = true;
}
@@ -346,12 +343,12 @@ TEST_F(WebContentsImplTest, UpdateTitle) {
static_cast<NavigationControllerImpl&>(controller());
FrameHostMsg_DidCommitProvisionalLoad_Params params;
InitNavigateParams(
- &params, 0, GURL(url::kAboutBlankURL), PAGE_TRANSITION_TYPED);
+ &params, 0, GURL(url::kAboutBlankURL), ui::PAGE_TRANSITION_TYPED);
LoadCommittedDetails details;
- cont.RendererDidNavigate(main_test_rfh(), params, &details);
+ cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
- contents()->UpdateTitle(main_test_rfh(), 0,
+ contents()->UpdateTitle(contents()->GetMainFrame(), 0,
base::ASCIIToUTF16(" Lots O' Whitespace\n"),
base::i18n::LEFT_TO_RIGHT);
EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
@@ -360,7 +357,7 @@ TEST_F(WebContentsImplTest, UpdateTitle) {
TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
const GURL kGURL("chrome://blah");
controller().LoadURL(
- kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_EQ(base::string16(), contents()->GetTitle());
}
@@ -368,7 +365,7 @@ TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
const GURL kGURL("chrome://blah");
const base::string16 title = base::ASCIIToUTF16("My Title");
controller().LoadURL(
- kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
NavigationEntry* entry = controller().GetVisibleEntry();
ASSERT_EQ(kGURL, entry->GetURL());
@@ -387,16 +384,16 @@ TEST_F(WebContentsImplTest, NTPViewSource) {
process()->sink().ClearMessages();
cont.LoadURL(
- kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
rvh()->GetDelegate()->RenderViewCreated(rvh());
// Did we get the expected message?
EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
ViewMsg_EnableViewSourceMode::ID));
FrameHostMsg_DidCommitProvisionalLoad_Params params;
- InitNavigateParams(&params, 0, kGURL, PAGE_TRANSITION_TYPED);
+ InitNavigateParams(&params, 0, kGURL, ui::PAGE_TRANSITION_TYPED);
LoadCommittedDetails details;
- cont.RendererDidNavigate(main_test_rfh(), params, &details);
+ cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
// Also check title and url.
EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
}
@@ -426,16 +423,16 @@ TEST_F(WebContentsImplTest, UpdateMaxPageID) {
// Test simple same-SiteInstance navigation.
TEST_F(WebContentsImplTest, SimpleNavigation) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
SiteInstance* instance1 = contents()->GetSiteInstance();
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
+ EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
// Navigate to URL
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
+ EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
// Controller's pending entry will have a NULL site instance until we assign
// it in DidNavigate.
EXPECT_TRUE(
@@ -443,10 +440,10 @@ TEST_F(WebContentsImplTest, SimpleNavigation) {
site_instance() == NULL);
// DidNavigate from the page
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
- EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
+ EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
// Controller's entry should now have the SiteInstance, or else we won't be
// able to find it later.
EXPECT_EQ(
@@ -462,73 +459,66 @@ TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
GetMaxURLChars() + 1, 'a'));
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
+ url, Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
}
// Test that navigating across a site boundary creates a new RenderViewHost
// with a new SiteInstance. Going back should do the same.
TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
- TestRenderViewHost* orig_rvh = test_rvh();
- RenderFrameHostImpl* orig_rfh =
- contents()->GetFrameTree()->root()->current_frame_host();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
int orig_rvh_delete_count = 0;
- orig_rvh->set_delete_counter(&orig_rvh_delete_count);
+ orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
SiteInstance* instance1 = contents()->GetSiteInstance();
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
- // Keep the number of active views in orig_rvh's SiteInstance
- // non-zero so that orig_rvh doesn't get deleted when it gets
- // swapped out.
- static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
- increment_active_view_count();
+ // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
+ // that orig_rfh doesn't get deleted when it gets swapped out.
+ orig_rfh->GetSiteInstance()->increment_active_frame_count();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
EXPECT_EQ(url, contents()->GetLastCommittedURL());
EXPECT_EQ(url, contents()->GetVisibleURL());
// Navigate to new site
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_TRUE(contents()->cross_navigation_pending());
EXPECT_EQ(url, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
- TestRenderViewHost* pending_rvh =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+ TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
int pending_rvh_delete_count = 0;
- pending_rvh->set_delete_counter(&pending_rvh_delete_count);
- RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
- render_manager()->pending_frame_host();
+ pending_rfh->GetRenderViewHost()->set_delete_counter(
+ &pending_rvh_delete_count);
- // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
- EXPECT_TRUE(pending_rvh->are_navigations_suspended());
- orig_rvh->SendBeforeUnloadACK(true);
- EXPECT_FALSE(pending_rvh->are_navigations_suspended());
+ // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
+ EXPECT_TRUE(pending_rfh->are_navigations_suspended());
+ orig_rfh->SendBeforeUnloadACK(true);
+ EXPECT_FALSE(pending_rfh->are_navigations_suspended());
// DidNavigate from the pending page
contents()->TestDidNavigate(
- pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2 = contents()->GetSiteInstance();
- // Keep the number of active views in pending_rvh's SiteInstance
- // non-zero so that orig_rvh doesn't get deleted when it gets
+ // Keep the number of active frames in pending_rfh's SiteInstance
+ // non-zero so that orig_rfh doesn't get deleted when it gets
// swapped out.
- static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
- increment_active_view_count();
+ pending_rfh->GetSiteInstance()->increment_active_frame_count();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
EXPECT_EQ(url2, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
EXPECT_NE(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
+ EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
// We keep the original RFH around, swapped out.
EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
orig_rfh));
@@ -536,29 +526,27 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
// Going back should switch SiteInstances again. The first SiteInstance is
// stored in the NavigationEntry, so it should be the same as at the start.
- // We should use the same RVH as before, swapping it back in.
+ // We should use the same RFH as before, swapping it back in.
controller().GoBack();
- TestRenderViewHost* goback_rvh =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
- EXPECT_EQ(orig_rvh, goback_rvh);
+ TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame();
+ EXPECT_EQ(orig_rfh, goback_rfh);
EXPECT_TRUE(contents()->cross_navigation_pending());
- // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
- EXPECT_TRUE(goback_rvh->are_navigations_suspended());
- pending_rvh->SendBeforeUnloadACK(true);
- EXPECT_FALSE(goback_rvh->are_navigations_suspended());
+ // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
+ EXPECT_TRUE(goback_rfh->are_navigations_suspended());
+ pending_rfh->SendBeforeUnloadACK(true);
+ EXPECT_FALSE(goback_rfh->are_navigations_suspended());
// DidNavigate from the back action
- contents()->TestDidNavigate(
- goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(goback_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(goback_rfh, contents()->GetMainFrame());
EXPECT_EQ(instance1, contents()->GetSiteInstance());
// The pending RFH should now be swapped out, not deleted.
EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
IsOnSwappedOutList(pending_rfh));
EXPECT_EQ(pending_rvh_delete_count, 0);
- pending_rvh->OnSwappedOut(false);
+ pending_rfh->OnSwappedOut();
// Close contents and ensure RVHs are deleted.
DeleteContents();
@@ -567,43 +555,45 @@ TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
}
// Test that navigating across a site boundary after a crash creates a new
-// RVH without requiring a cross-site transition (i.e., PENDING state).
+// RFH without requiring a cross-site transition (i.e., PENDING state).
TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
+
int orig_rvh_delete_count = 0;
- orig_rvh->set_delete_counter(&orig_rvh_delete_count);
+ orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
SiteInstance* instance1 = contents()->GetSiteInstance();
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
- // Crash the renderer.
- orig_rvh->set_render_view_created(false);
+ // Simulate a renderer crash.
+ orig_rfh->GetRenderViewHost()->set_render_view_created(false);
+ orig_rfh->set_render_frame_created(false);
// Navigate to new site. We should not go into PENDING.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- RenderViewHost* new_rvh = rvh();
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ TestRenderFrameHost* new_rfh = contents()->GetMainFrame();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
- EXPECT_NE(orig_rvh, new_rvh);
+ EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
+ EXPECT_NE(orig_rfh, new_rfh);
EXPECT_EQ(orig_rvh_delete_count, 1);
// DidNavigate from the new page
- contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(new_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2 = contents()->GetSiteInstance();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(new_rvh, rvh());
+ EXPECT_EQ(new_rfh, main_rfh());
EXPECT_NE(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
+ EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
// Close contents and ensure RVHs are deleted.
DeleteContents();
@@ -614,56 +604,53 @@ TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
// both contentses to a new site will place both contentses in a single
// SiteInstance.
TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
SiteInstance* instance1 = contents()->GetSiteInstance();
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
// Open a new contents with the same SiteInstance, navigated to the same site.
scoped_ptr<TestWebContents> contents2(
TestWebContents::Create(browser_context(), instance1));
contents2->GetController().LoadURL(url, Referrer(),
- PAGE_TRANSITION_TYPED,
- std::string());
+ ui::PAGE_TRANSITION_TYPED,
+ std::string());
// Need this page id to be 2 since the site instance is the same (which is the
// scope of page IDs) and we want to consider this a new page.
contents2->TestDidNavigate(
- contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
+ contents2->GetMainFrame(), 2, url, ui::PAGE_TRANSITION_TYPED);
// Navigate first contents to a new site.
const GURL url2a("http://www.yahoo.com");
controller().LoadURL(
- url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- orig_rvh->SendBeforeUnloadACK(true);
- TestRenderViewHost* pending_rvh_a =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+ url2a, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ orig_rfh->SendBeforeUnloadACK(true);
+ TestRenderFrameHost* pending_rfh_a = contents()->GetPendingMainFrame();
contents()->TestDidNavigate(
- pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
+ pending_rfh_a, 1, url2a, ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2a = contents()->GetSiteInstance();
EXPECT_NE(instance1, instance2a);
// Navigate second contents to the same site as the first tab.
const GURL url2b("http://mail.yahoo.com");
contents2->GetController().LoadURL(url2b, Referrer(),
- PAGE_TRANSITION_TYPED,
- std::string());
- TestRenderViewHost* rvh2 =
- static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
- rvh2->SendBeforeUnloadACK(true);
- TestRenderViewHost* pending_rvh_b =
- static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
- EXPECT_TRUE(pending_rvh_b != NULL);
+ ui::PAGE_TRANSITION_TYPED,
+ std::string());
+ TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
+ rfh2->SendBeforeUnloadACK(true);
+ TestRenderFrameHost* pending_rfh_b = contents2->GetPendingMainFrame();
+ EXPECT_TRUE(pending_rfh_b != NULL);
EXPECT_TRUE(contents2->cross_navigation_pending());
// NOTE(creis): We used to be in danger of showing a crash page here if the
// second contents hadn't navigated somewhere first (bug 1145430). That case
// is now covered by the CrossSiteBoundariesAfterCrash test.
contents2->TestDidNavigate(
- pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
+ pending_rfh_b, 2, url2b, ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2b = contents2->GetSiteInstance();
EXPECT_NE(instance1, instance2b);
@@ -671,27 +658,29 @@ TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
EXPECT_EQ(instance2a, instance2b);
}
-TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
+// The embedder can request sites for certain urls not be be assigned to the
+// SiteInstance through ShouldAssignSiteForURL() in content browser client,
+// allowing to reuse the renderer backing certain chrome urls for subsequent
+// navigation. The test verifies that the override is honored.
+TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
WebContentsImplTestBrowserClient browser_client;
SetBrowserClientForTesting(&browser_client);
- TestRenderViewHost* orig_rvh = test_rvh();
- RenderFrameHostImpl* orig_rfh =
- contents()->GetFrameTree()->root()->current_frame_host();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
int orig_rvh_delete_count = 0;
- orig_rvh->set_delete_counter(&orig_rvh_delete_count);
- SiteInstanceImpl* orig_instance =
- static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
+ orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
+ SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
browser_client.set_assign_site_for_url(false);
// Navigate to an URL that will not assign a new SiteInstance.
const GURL native_url("non-site-url://stuffandthings");
controller().LoadURL(
- native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
+ native_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(
+ orig_rfh, 1, native_url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
EXPECT_EQ(native_url, contents()->GetVisibleURL());
EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
@@ -702,18 +691,17 @@ TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
// Navigate to new site (should keep same site instance).
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_FALSE(contents()->cross_navigation_pending());
EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
EXPECT_EQ(url, contents()->GetVisibleURL());
- EXPECT_FALSE(contents()->GetPendingRenderViewHost());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ EXPECT_FALSE(contents()->GetPendingMainFrame());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
- // Keep the number of active views in orig_rvh's SiteInstance
- // non-zero so that orig_rvh doesn't get deleted when it gets
+ // Keep the number of active frames in orig_rfh's SiteInstance
+ // non-zero so that orig_rfh doesn't get deleted when it gets
// swapped out.
- static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
- increment_active_view_count();
+ orig_rfh->GetSiteInstance()->increment_active_frame_count();
EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
EXPECT_TRUE(
@@ -723,36 +711,36 @@ TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
// Navigate to another new site (should create a new site instance).
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_TRUE(contents()->cross_navigation_pending());
EXPECT_EQ(url, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
- TestRenderViewHost* pending_rvh =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+ TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
int pending_rvh_delete_count = 0;
- pending_rvh->set_delete_counter(&pending_rvh_delete_count);
+ pending_rfh->GetRenderViewHost()->set_delete_counter(
+ &pending_rvh_delete_count);
// Navigations should be suspended in pending_rvh until BeforeUnloadACK.
- EXPECT_TRUE(pending_rvh->are_navigations_suspended());
- orig_rvh->SendBeforeUnloadACK(true);
- EXPECT_FALSE(pending_rvh->are_navigations_suspended());
+ EXPECT_TRUE(pending_rfh->are_navigations_suspended());
+ orig_rfh->SendBeforeUnloadACK(true);
+ EXPECT_FALSE(pending_rfh->are_navigations_suspended());
// DidNavigate from the pending page.
contents()->TestDidNavigate(
- pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
SiteInstance* new_instance = contents()->GetSiteInstance();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
EXPECT_EQ(url2, contents()->GetLastCommittedURL());
EXPECT_EQ(url2, contents()->GetVisibleURL());
EXPECT_NE(new_instance, orig_instance);
- EXPECT_FALSE(contents()->GetPendingRenderViewHost());
+ EXPECT_FALSE(contents()->GetPendingMainFrame());
// We keep the original RFH around, swapped out.
EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
orig_rfh));
EXPECT_EQ(orig_rvh_delete_count, 0);
- orig_rvh->OnSwappedOut(false);
+ orig_rfh->OnSwappedOut();
// Close contents and ensure RVHs are deleted.
DeleteContents();
@@ -760,61 +748,146 @@ TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
EXPECT_EQ(pending_rvh_delete_count, 1);
}
+// Regression test for http://crbug.com/386542 - variation of
+// NavigateFromSitelessUrl in which the original navigation is a session
+// restore.
+TEST_F(WebContentsImplTest, NavigateFromRestoredSitelessUrl) {
+ WebContentsImplTestBrowserClient browser_client;
+ SetBrowserClientForTesting(&browser_client);
+ SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
+
+ // Restore a navigation entry for URL that should not assign site to the
+ // SiteInstance.
+ browser_client.set_assign_site_for_url(false);
+ const GURL native_url("non-site-url://stuffandthings");
+ std::vector<NavigationEntry*> entries;
+ NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
+ native_url, Referrer(), ui::PAGE_TRANSITION_LINK, false, std::string(),
+ browser_context());
+ entry->SetPageID(0);
+ entries.push_back(entry);
+ controller().Restore(
+ 0,
+ NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
+ &entries);
+ ASSERT_EQ(0u, entries.size());
+ ASSERT_EQ(1, controller().GetEntryCount());
+ controller().GoToIndex(0);
+ contents()->TestDidNavigate(
+ orig_rfh, 0, native_url, ui::PAGE_TRANSITION_RELOAD);
+ EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
+ EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
+ EXPECT_FALSE(orig_instance->HasSite());
+
+ // Navigate to a regular site and verify that the SiteInstance was kept.
+ browser_client.set_assign_site_for_url(true);
+ const GURL url("http://www.google.com");
+ controller().LoadURL(
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 2, url, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
+
+ // Cleanup.
+ DeleteContents();
+}
+
+// Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
+// tab is restored, the SiteInstance will change upon navigation.
+TEST_F(WebContentsImplTest, NavigateFromRestoredRegularUrl) {
+ WebContentsImplTestBrowserClient browser_client;
+ SetBrowserClientForTesting(&browser_client);
+ SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
+
+ // Restore a navigation entry for a regular URL ensuring that the embedder
+ // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
+ browser_client.set_assign_site_for_url(true);
+ const GURL regular_url("http://www.yahoo.com");
+ std::vector<NavigationEntry*> entries;
+ NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
+ regular_url, Referrer(), ui::PAGE_TRANSITION_LINK, false, std::string(),
+ browser_context());
+ entry->SetPageID(0);
+ entries.push_back(entry);
+ controller().Restore(
+ 0,
+ NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
+ &entries);
+ ASSERT_EQ(0u, entries.size());
+ ASSERT_EQ(1, controller().GetEntryCount());
+ controller().GoToIndex(0);
+ contents()->TestDidNavigate(
+ orig_rfh, 0, regular_url, ui::PAGE_TRANSITION_RELOAD);
+ EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
+ EXPECT_TRUE(orig_instance->HasSite());
+
+ // Navigate to another site and verify that a new SiteInstance was created.
+ const GURL url("http://www.google.com");
+ controller().LoadURL(
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(
+ contents()->GetPendingMainFrame(), 2, url, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_NE(orig_instance, contents()->GetSiteInstance());
+
+ // Cleanup.
+ DeleteContents();
+}
+
// Test that we can find an opener RVH even if it's pending.
// http://crbug.com/176252.
TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
// Navigate to a URL.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
// Start to navigate first tab to a new site, so that it has a pending RVH.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- orig_rvh->SendBeforeUnloadACK(true);
- TestRenderViewHost* pending_rvh =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ orig_rfh->SendBeforeUnloadACK(true);
+ TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
// While it is still pending, simulate opening a new tab with the first tab
// as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
// on the opener to ensure that an RVH exists.
- int opener_routing_id = contents()->CreateOpenerRenderViews(
- pending_rvh->GetSiteInstance());
+ int opener_routing_id =
+ contents()->CreateOpenerRenderViews(pending_rfh->GetSiteInstance());
// We should find the pending RVH and not create a new one.
- EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
+ EXPECT_EQ(pending_rfh->GetRenderViewHost()->GetRoutingID(),
+ opener_routing_id);
}
// Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
// to determine whether a navigation is cross-site.
TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
- RenderViewHost* orig_rvh = rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
SiteInstance* instance1 = contents()->GetSiteInstance();
// Navigate to URL.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
contents()->TestDidNavigate(
- orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
// Open a related contents to a second site.
scoped_ptr<TestWebContents> contents2(
TestWebContents::Create(browser_context(), instance1));
const GURL url2("http://www.yahoo.com");
contents2->GetController().LoadURL(url2, Referrer(),
- PAGE_TRANSITION_TYPED,
- std::string());
+ ui::PAGE_TRANSITION_TYPED,
+ std::string());
// The first RVH in contents2 isn't live yet, so we shortcut the cross site
// pending.
- TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
- contents2->GetRenderViewHost());
+ TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
EXPECT_FALSE(contents2->cross_navigation_pending());
- contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
+ contents2->TestDidNavigate(rfh2, 2, url2, ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2 = contents2->GetSiteInstance();
EXPECT_NE(instance1, instance2);
EXPECT_FALSE(contents2->cross_navigation_pending());
@@ -822,7 +895,7 @@ TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
// Simulate a link click in first contents to second site. Doesn't switch
// SiteInstances, because we don't intercept WebKit navigations.
contents()->TestDidNavigate(
- orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
+ orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance3 = contents()->GetSiteInstance();
EXPECT_EQ(instance1, instance3);
EXPECT_FALSE(contents()->cross_navigation_pending());
@@ -831,10 +904,10 @@ TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
// compare against the current URL, not the SiteInstance's site.
const GURL url3("http://mail.yahoo.com");
controller().LoadURL(
- url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_FALSE(contents()->cross_navigation_pending());
contents()->TestDidNavigate(
- orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
+ orig_rfh, 3, url3, ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance4 = contents()->GetSiteInstance();
EXPECT_EQ(instance1, instance4);
}
@@ -842,150 +915,149 @@ TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
// Test that the onbeforeunload and onunload handlers run when navigating
// across site boundaries.
TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
SiteInstance* instance1 = contents()->GetSiteInstance();
// Navigate to URL. First URL should use first RenderViewHost.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Navigate to new site, but simulate an onbeforeunload denial.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
base::TimeTicks now = base::TimeTicks::Now();
- orig_rvh->GetMainFrame()->OnMessageReceived(
+ orig_rfh->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
- EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Navigate again, but simulate an onbeforeunload approval.
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
now = base::TimeTicks::Now();
- orig_rvh->GetMainFrame()->OnMessageReceived(
+ orig_rfh->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
EXPECT_TRUE(contents()->cross_navigation_pending());
- TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
- contents()->GetPendingRenderViewHost());
+ TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
// We won't hear DidNavigate until the onunload handler has finished running.
// DidNavigate from the pending page.
contents()->TestDidNavigate(
- pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
SiteInstance* instance2 = contents()->GetSiteInstance();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(pending_rvh, rvh());
+ EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
EXPECT_NE(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
+ EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
}
// Test that during a slow cross-site navigation, the original renderer can
// navigate to a different URL and have it displayed, canceling the slow
// navigation.
TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
SiteInstance* instance1 = contents()->GetSiteInstance();
- // Navigate to URL. First URL should use first RenderViewHost.
+ // Navigate to URL. First URL should use first RenderFrameHost.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Navigate to new site, simulating an onbeforeunload approval.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
base::TimeTicks now = base::TimeTicks::Now();
- orig_rvh->GetMainFrame()->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
+ orig_rfh->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
EXPECT_TRUE(contents()->cross_navigation_pending());
// Suppose the original renderer navigates before the new one is ready.
- orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
+ orig_rfh->SendNavigate(2, GURL("http://www.google.com/foo"));
// Verify that the pending navigation is cancelled.
- EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
SiteInstance* instance2 = contents()->GetSiteInstance();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, rvh());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
EXPECT_EQ(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
+ EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
}
TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
// Start with a web ui page, which gets a new RVH with WebUI bindings.
const GURL url1("chrome://blah");
controller().LoadURL(
- url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- TestRenderViewHost* ntp_rvh = test_rvh();
- contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
+ url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
+ contents()->TestDidNavigate(ntp_rfh, 1, url1, ui::PAGE_TRANSITION_TYPED);
NavigationEntry* entry1 = controller().GetLastCommittedEntry();
SiteInstance* instance1 = contents()->GetSiteInstance();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(ntp_rfh, contents()->GetMainFrame());
EXPECT_EQ(url1, entry1->GetURL());
EXPECT_EQ(instance1,
NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
- EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+ EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->GetEnabledBindings() &
+ BINDINGS_POLICY_WEB_UI);
// Navigate to new site.
const GURL url2("http://www.google.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_TRUE(contents()->cross_navigation_pending());
- TestRenderViewHost* google_rvh =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+ TestRenderFrameHost* google_rfh = contents()->GetPendingMainFrame();
// Simulate beforeunload approval.
- EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(ntp_rfh->is_waiting_for_beforeunload_ack());
base::TimeTicks now = base::TimeTicks::Now();
- ntp_rvh->GetMainFrame()->OnMessageReceived(
+ ntp_rfh->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
// DidNavigate from the pending page.
contents()->TestDidNavigate(
- google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ google_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
NavigationEntry* entry2 = controller().GetLastCommittedEntry();
SiteInstance* instance2 = contents()->GetSiteInstance();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(google_rfh, contents()->GetMainFrame());
EXPECT_NE(instance1, instance2);
- EXPECT_FALSE(contents()->GetPendingRenderViewHost());
+ EXPECT_FALSE(contents()->GetPendingMainFrame());
EXPECT_EQ(url2, entry2->GetURL());
EXPECT_EQ(instance2,
NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
- EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
+ EXPECT_FALSE(google_rfh->GetRenderViewHost()->GetEnabledBindings() &
+ BINDINGS_POLICY_WEB_UI);
// Navigate to third page on same site.
const GURL url3("http://news.google.com");
controller().LoadURL(
- url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_FALSE(contents()->cross_navigation_pending());
contents()->TestDidNavigate(
- google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
+ google_rfh, 2, url3, ui::PAGE_TRANSITION_TYPED);
NavigationEntry* entry3 = controller().GetLastCommittedEntry();
SiteInstance* instance3 = contents()->GetSiteInstance();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(google_rfh, contents()->GetMainFrame());
EXPECT_EQ(instance2, instance3);
- EXPECT_FALSE(contents()->GetPendingRenderViewHost());
+ EXPECT_FALSE(contents()->GetPendingMainFrame());
EXPECT_EQ(url3, entry3->GetURL());
EXPECT_EQ(instance3,
NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
@@ -998,22 +1070,22 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
// Before that commits, go back again.
controller().GoBack();
EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_TRUE(contents()->GetPendingRenderViewHost());
+ EXPECT_TRUE(contents()->GetPendingMainFrame());
EXPECT_EQ(entry1, controller().GetPendingEntry());
// Simulate beforeunload approval.
- EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(google_rfh->is_waiting_for_beforeunload_ack());
now = base::TimeTicks::Now();
- google_rvh->GetMainFrame()->OnMessageReceived(
+ google_rfh->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- // DidNavigate from the first back. This aborts the second back's pending RVH.
- contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ // DidNavigate from the first back. This aborts the second back's pending RFH.
+ contents()->TestDidNavigate(google_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
// We should commit this page and forget about the second back.
EXPECT_FALSE(contents()->cross_navigation_pending());
EXPECT_FALSE(controller().GetPendingEntry());
- EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(google_rfh, contents()->GetMainFrame());
EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
// We should not have corrupted the NTP entry.
@@ -1029,33 +1101,34 @@ TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
// Test that during a slow cross-site navigation, a sub-frame navigation in the
// original renderer will not cancel the slow navigation (bug 42029).
TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
- // Navigate to URL. First URL should use first RenderViewHost.
+ // Navigate to URL. First URL should use the original RenderFrameHost.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Start navigating to new site.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Simulate a sub-frame navigation arriving and ensure the RVH is still
// waiting for a before unload response.
- orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
- PAGE_TRANSITION_AUTO_SUBFRAME);
- EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
+ TestRenderFrameHost* child_rfh = orig_rfh->AppendChild("subframe");
+ child_rfh->SendNavigateWithTransition(
+ 1, GURL("http://google.com/frame"), ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+ EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
// Now simulate the onbeforeunload approval and verify the navigation is
// not canceled.
base::TimeTicks now = base::TimeTicks::Now();
- orig_rvh->GetMainFrame()->OnMessageReceived(
+ orig_rfh->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
EXPECT_TRUE(contents()->cross_navigation_pending());
}
@@ -1067,163 +1140,107 @@ TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
// Navigate to NTP URL.
const GURL url("chrome://blah");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- TestRenderViewHost* orig_rvh = test_rvh();
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
EXPECT_FALSE(contents()->cross_navigation_pending());
// Navigate to new site, with the beforeunload request in flight.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- TestRenderViewHost* pending_rvh =
- static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
// Suppose the first navigation tries to commit now, with a
- // ViewMsg_Stop in flight. This should not cancel the pending navigation,
+ // FrameMsg_Stop in flight. This should not cancel the pending navigation,
// but it should act as if the beforeunload ack arrived.
- orig_rvh->SendNavigate(1, GURL("chrome://blah"));
+ orig_rfh->SendNavigate(1, GURL("chrome://blah"));
EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
- EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
+ EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
// The pending navigation should be able to commit successfully.
- contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
-}
-
-// Test that the original renderer cannot preempt a cross-site navigation once
-// the unload request has been made. At this point, the cross-site navigation
-// is almost ready to be displayed, and the original renderer is only given a
-// short chance to run an unload handler. Prevents regression of bug 23942.
-TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
- TestRenderViewHost* orig_rvh = test_rvh();
- SiteInstance* instance1 = contents()->GetSiteInstance();
-
- // Navigate to URL. First URL should use first RenderViewHost.
- const GURL url("http://www.google.com");
- controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
- EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
-
- // Navigate to new site, simulating an onbeforeunload approval.
- const GURL url2("http://www.yahoo.com");
- controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- base::TimeTicks now = base::TimeTicks::Now();
- orig_rvh->GetMainFrame()->OnMessageReceived(
- FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
- EXPECT_TRUE(contents()->cross_navigation_pending());
- TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
- contents()->GetPendingRenderViewHost());
-
- // Simulate the pending renderer's response, which leads to an unload request
- // being sent to orig_rvh.
- std::vector<GURL> url_chain;
- url_chain.push_back(GURL());
- contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
- contents()->GetRenderManagerForTesting()->pending_frame_host(),
- GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
- url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
-
- // Suppose the original renderer navigates now, while the unload request is in
- // flight. We should ignore it, wait for the unload ack, and let the pending
- // request continue. Otherwise, the contents may close spontaneously or stop
- // responding to navigation requests. (See bug 23942.)
- FrameHostMsg_DidCommitProvisionalLoad_Params params1a;
- InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"),
- PAGE_TRANSITION_TYPED);
- orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
-
- // Verify that the pending navigation is still in progress.
- EXPECT_TRUE(contents()->cross_navigation_pending());
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
-
- // DidNavigate from the pending page should commit it.
- contents()->TestDidNavigate(
- pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
- SiteInstance* instance2 = contents()->GetSiteInstance();
- EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(pending_rvh, rvh());
- EXPECT_NE(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
+ EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
}
// Test that a cross-site navigation that doesn't commit after the unload
// handler doesn't leave the contents in a stuck state. http://crbug.com/88562
TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
SiteInstance* instance1 = contents()->GetSiteInstance();
- // Navigate to URL. First URL should use first RenderViewHost.
+ // Navigate to URL. First URL should use original RenderFrameHost.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Navigate to new site, simulating an onbeforeunload approval.
const GURL url2("http://www.yahoo.com");
- controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
+ controller().LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
base::TimeTicks now = base::TimeTicks::Now();
- orig_rvh->GetMainFrame()->OnMessageReceived(
+ orig_rfh->OnMessageReceived(
FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
EXPECT_TRUE(contents()->cross_navigation_pending());
// Simulate swap out message when the response arrives.
- orig_rvh->OnSwappedOut(false);
+ orig_rfh->OnSwappedOut();
// Suppose the navigation doesn't get a chance to commit, and the user
- // navigates in the current RVH's SiteInstance.
- controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ // navigates in the current RFH's SiteInstance.
+ controller().LoadURL(
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Verify that the pending navigation is cancelled and the renderer is no
// longer swapped out.
- EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
+ EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
SiteInstance* instance2 = contents()->GetSiteInstance();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, rvh());
- EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
+ EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, orig_rfh->rfh_state());
EXPECT_EQ(instance1, instance2);
- EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
+ EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL);
}
// Test that NavigationEntries have the correct page state after going
// forward and back. Prevents regression for bug 1116137.
TEST_F(WebContentsImplTest, NavigationEntryContentState) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
// Navigate to URL. There should be no committed entry yet.
const GURL url("http://www.google.com");
- controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller().LoadURL(
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
NavigationEntry* entry = controller().GetLastCommittedEntry();
EXPECT_TRUE(entry == NULL);
// Committed entry should have page state after DidNavigate.
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
entry = controller().GetLastCommittedEntry();
EXPECT_TRUE(entry->GetPageState().IsValid());
// Navigate to same site.
const GURL url2("http://images.google.com");
- controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller().LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
entry = controller().GetLastCommittedEntry();
EXPECT_TRUE(entry->GetPageState().IsValid());
// Committed entry should have page state after DidNavigate.
- contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
entry = controller().GetLastCommittedEntry();
EXPECT_TRUE(entry->GetPageState().IsValid());
// Now go back. Committed entry should still have page state.
controller().GoBack();
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
entry = controller().GetLastCommittedEntry();
EXPECT_TRUE(entry->GetPageState().IsValid());
}
@@ -1232,13 +1249,13 @@ TEST_F(WebContentsImplTest, NavigationEntryContentState) {
// state after opening a new window to about:blank. Prevents regression for
// bugs b/1116137 and http://crbug.com/111975.
TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
// When opening a new window, it is navigated to about:blank internally.
// Currently, this results in two DidNavigate events.
const GURL url(url::kAboutBlankURL);
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
// Should have a page state here.
NavigationEntry* entry = controller().GetLastCommittedEntry();
@@ -1253,10 +1270,10 @@ TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
// Navigating to a normal page should not cause a process swap.
const GURL new_url("http://www.google.com");
controller().LoadURL(new_url, Referrer(),
- PAGE_TRANSITION_TYPED, std::string());
+ ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
- contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
+ contents()->TestDidNavigate(orig_rfh, 1, new_url, ui::PAGE_TRANSITION_TYPED);
NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
controller().GetLastCommittedEntry());
EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
@@ -1268,14 +1285,15 @@ TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
FakeFullscreenDelegate fake_delegate;
contents()->SetDelegate(&fake_delegate);
- TestRenderViewHost* orig_rvh = test_rvh();
+ TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
+ TestRenderViewHost* orig_rvh = orig_rfh->GetRenderViewHost();
// Navigate to a site.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Toggle fullscreen mode on (as if initiated via IPC from renderer).
EXPECT_FALSE(orig_rvh->IsFullscreen());
@@ -1290,10 +1308,10 @@ TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
// Navigate to a new site.
const GURL url2("http://www.yahoo.com");
controller().LoadURL(
- url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- RenderViewHost* const pending_rvh = contents()->GetPendingRenderViewHost();
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ TestRenderFrameHost* const pending_rfh = contents()->GetPendingMainFrame();
contents()->TestDidNavigate(
- pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
+ pending_rfh, 1, url2, ui::PAGE_TRANSITION_TYPED);
// Confirm fullscreen has exited.
EXPECT_FALSE(orig_rvh->IsFullscreen());
@@ -1308,20 +1326,23 @@ TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
FakeFullscreenDelegate fake_delegate;
contents()->SetDelegate(&fake_delegate);
- TestRenderViewHost* const orig_rvh = test_rvh();
+ TestRenderFrameHost* const orig_rfh = contents()->GetMainFrame();
+ TestRenderViewHost* const orig_rvh = orig_rfh->GetRenderViewHost();
// Navigate to a site.
const GURL url("http://www.google.com");
- controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ controller().LoadURL(
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(orig_rfh, 1, url, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Now, navigate to another page on the same site.
const GURL url2("http://www.google.com/search?q=kittens");
- controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller().LoadURL(
+ url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_FALSE(contents()->cross_navigation_pending());
- contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ contents()->TestDidNavigate(orig_rfh, 2, url2, ui::PAGE_TRANSITION_TYPED);
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
// Sanity-check: Confirm we're not starting out in fullscreen mode.
EXPECT_FALSE(orig_rvh->IsFullscreen());
@@ -1342,9 +1363,9 @@ TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
else
controller().GoForward();
EXPECT_FALSE(contents()->cross_navigation_pending());
- EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
+ EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
contents()->TestDidNavigate(
- orig_rvh, i + 1, url, PAGE_TRANSITION_FORWARD_BACK);
+ orig_rfh, i + 1, url, ui::PAGE_TRANSITION_FORWARD_BACK);
// Confirm fullscreen has exited.
EXPECT_FALSE(orig_rvh->IsFullscreen());
@@ -1361,7 +1382,7 @@ TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
EXPECT_FALSE(fake_delegate.hide_validation_message_was_called());
// Crash the renderer.
- test_rvh()->OnMessageReceived(
+ contents()->GetMainFrame()->GetRenderViewHost()->OnMessageReceived(
ViewHostMsg_RenderProcessGone(
0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
@@ -1380,9 +1401,9 @@ TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
// Navigate to a site.
const GURL url("http://www.google.com");
controller().LoadURL(
- url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
- contents()->TestDidNavigate(test_rvh(), 1, url, PAGE_TRANSITION_TYPED);
- EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
+ contents()->TestDidNavigate(
+ contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
// Toggle fullscreen mode on (as if initiated via IPC from renderer).
EXPECT_FALSE(test_rvh()->IsFullscreen());
@@ -1418,12 +1439,12 @@ TEST_F(WebContentsImplTest,
ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Initiate a browser navigation that will trigger the interstitial
controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
- PAGE_TRANSITION_TYPED, std::string());
+ ui::PAGE_TRANSITION_TYPED, std::string());
// Show an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -1468,7 +1489,7 @@ TEST_F(WebContentsImplTest,
ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial (no pending entry, the interstitial would have been
@@ -1514,7 +1535,7 @@ TEST_F(WebContentsImplTest,
TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1561,12 +1582,12 @@ TEST_F(WebContentsImplTest,
ShowInterstitialFromBrowserNewNavigationProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Initiate a browser navigation that will trigger the interstitial
controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
- PAGE_TRANSITION_TYPED, std::string());
+ ui::PAGE_TRANSITION_TYPED, std::string());
// Show an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -1602,7 +1623,7 @@ TEST_F(WebContentsImplTest,
// Simulate the navigation to the page, that's when the interstitial gets
// hidden.
GURL url3("http://www.thepage.com");
- test_rvh()->SendNavigate(2, url3);
+ contents()->GetMainFrame()->SendNavigate(2, url3);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
@@ -1623,7 +1644,7 @@ TEST_F(WebContentsImplTest,
ShowInterstitialFromRendererNewNavigationProceed) {
// Navigate to a page.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1660,7 +1681,7 @@ TEST_F(WebContentsImplTest,
// Simulate the navigation to the page, that's when the interstitial gets
// hidden.
GURL url3("http://www.thepage.com");
- test_rvh()->SendNavigate(2, url3);
+ contents()->GetMainFrame()->SendNavigate(2, url3);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
@@ -1680,7 +1701,7 @@ TEST_F(WebContentsImplTest,
TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
// Navigate to a page so we have a navigation entry in the controller.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1738,7 +1759,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
// While interstitial showing, navigate to a new URL.
const GURL url2("http://www.yahoo.com");
- test_rvh()->SendNavigate(1, url2);
+ contents()->GetMainFrame()->SendNavigate(1, url2);
EXPECT_EQ(TestInterstitialPage::CANCELED, state);
@@ -1750,7 +1771,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
// Navigate to a page so we have a navigation entry in the controller.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show interstitial.
@@ -1767,7 +1788,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
// While the interstitial is showing, go back.
controller().GoBack();
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
// Make sure we are back to the original page and that the interstitial is
// gone.
@@ -1785,7 +1806,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
// Navigate to a page so we have a navigation entry in the controller.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show interstitial.
@@ -1807,7 +1828,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
// While the interstitial is showing, go back.
controller().GoBack();
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
// Make sure we are back to the original page and that the interstitial is
// gone.
@@ -1825,7 +1846,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
// Navigate to a page so we have a navigation entry in the controller.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show interstitial.
@@ -1904,7 +1925,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
// Navigate to a page so we have a navigation entry in the controller.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1939,7 +1960,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
// Navigate to a page so we have a navigation entry in the controller.
GURL start_url("http://www.google.com");
- test_rvh()->SendNavigate(1, start_url);
+ contents()->GetMainFrame()->SendNavigate(1, start_url);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -1975,7 +1996,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
// Let's make sure interstitial2 is working as intended.
interstitial2->Proceed();
GURL landing_url("http://www.thepage.com");
- test_rvh()->SendNavigate(2, landing_url);
+ contents()->GetMainFrame()->SendNavigate(2, landing_url);
EXPECT_FALSE(contents()->ShowingInterstitialPage());
EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
@@ -1992,7 +2013,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
// Navigate to a page so we have a navigation entry in the controller.
GURL start_url("http://www.google.com");
- test_rvh()->SendNavigate(1, start_url);
+ contents()->GetMainFrame()->SendNavigate(1, start_url);
EXPECT_EQ(1, controller().GetEntryCount());
// Show an interstitial.
@@ -2032,7 +2053,7 @@ TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
// Let's make sure interstitial2 is working as intended.
interstitial2->Proceed();
GURL landing_url("http://www.thepage.com");
- test_rvh()->SendNavigate(2, landing_url);
+ contents()->GetMainFrame()->SendNavigate(2, landing_url);
RunAllPendingInMessageLoop();
EXPECT_TRUE(deleted2);
@@ -2061,7 +2082,8 @@ TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
// Let's simulate a navigation initiated from the browser before the
// interstitial finishes loading.
const GURL url("http://www.google.com");
- controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ controller().LoadURL(
+ url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
EXPECT_FALSE(interstitial->is_showing());
RunAllPendingInMessageLoop();
ASSERT_FALSE(deleted);
@@ -2158,7 +2180,7 @@ TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
// Start a navigation to a page
contents()->GetController().LoadURL(
- kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// Simulate that navigation triggering an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -2173,7 +2195,7 @@ TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
// Initiate a new navigation from the browser that also triggers an
// interstitial.
contents()->GetController().LoadURL(
- kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
TestInterstitialPage::InterstitialState state2 =
TestInterstitialPage::INVALID;
bool deleted2 = false;
@@ -2204,9 +2226,10 @@ TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
// Start a navigation to a page
contents()->GetController().LoadURL(
- kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
// DidNavigate from the page
- contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
+ contents()->TestDidNavigate(
+ contents()->GetMainFrame(), 1, kGURL, ui::PAGE_TRANSITION_TYPED);
// Simulate showing an interstitial while the page is showing.
TestInterstitialPage::InterstitialState state =
@@ -2233,12 +2256,12 @@ TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
// Navigate to a page.
GURL url1("http://www.google.com");
- test_rvh()->SendNavigate(1, url1);
+ contents()->GetMainFrame()->SendNavigate(1, url1);
EXPECT_EQ(1, controller().GetEntryCount());
// Initiate a browser navigation that will trigger the interstitial
controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
- PAGE_TRANSITION_TYPED, std::string());
+ ui::PAGE_TRANSITION_TYPED, std::string());
// Show an interstitial.
TestInterstitialPage::InterstitialState state =
@@ -2429,7 +2452,7 @@ class ContentsZoomChangedDelegate : public WebContentsDelegate {
}
// WebContentsDelegate:
- virtual void ContentsZoomChange(bool zoom_in) OVERRIDE {
+ void ContentsZoomChange(bool zoom_in) override {
contents_zoom_changed_call_count_++;
last_zoom_in_ = zoom_in;
}
@@ -2567,12 +2590,12 @@ TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
scoped_ptr<TestWebContents> contents1(
- TestWebContents::Create(browser_context(), instance1));
+ TestWebContents::Create(browser_context(), instance1.get()));
EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
scoped_ptr<TestWebContents> contents2(
- TestWebContents::Create(browser_context(), instance1));
+ TestWebContents::Create(browser_context(), instance1.get()));
EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
@@ -2594,26 +2617,32 @@ TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
scoped_ptr<TestWebContents> contents(
- TestWebContents::Create(browser_context(), instance));
+ TestWebContents::Create(browser_context(), instance.get()));
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
// Navigate to a URL.
- contents->GetController().LoadURL(
- GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ contents->GetController().LoadURL(GURL("http://a.com/1"),
+ Referrer(),
+ ui::PAGE_TRANSITION_TYPED,
+ std::string());
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
contents->CommitPendingNavigation();
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
// Navigate to a URL in the same site.
- contents->GetController().LoadURL(
- GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ contents->GetController().LoadURL(GURL("http://a.com/2"),
+ Referrer(),
+ ui::PAGE_TRANSITION_TYPED,
+ std::string());
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
contents->CommitPendingNavigation();
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
// Navigate to a URL in a different site.
- contents->GetController().LoadURL(
- GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ contents->GetController().LoadURL(GURL("http://b.com"),
+ Referrer(),
+ ui::PAGE_TRANSITION_TYPED,
+ std::string());
EXPECT_TRUE(contents->cross_navigation_pending());
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
contents->CommitPendingNavigation();
@@ -2632,7 +2661,7 @@ TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
scoped_ptr<TestWebContents> contents(
- TestWebContents::Create(browser_context(), instance));
+ TestWebContents::Create(browser_context(), instance.get()));
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
// Navigate to a URL.
@@ -2640,11 +2669,13 @@ TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
// Navigate to a URL with WebUI. This will change BrowsingInstances.
- contents->GetController().LoadURL(
- GURL(kTestWebUIUrl), Referrer(), PAGE_TRANSITION_TYPED, std::string());
+ contents->GetController().LoadURL(GURL(kTestWebUIUrl),
+ Referrer(),
+ ui::PAGE_TRANSITION_TYPED,
+ std::string());
EXPECT_TRUE(contents->cross_navigation_pending());
scoped_refptr<SiteInstance> instance_webui(
- contents->GetPendingRenderViewHost()->GetSiteInstance());
+ contents->GetPendingMainFrame()->GetSiteInstance());
EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
// At this point, contents still counts for the old BrowsingInstance.
@@ -2661,4 +2692,106 @@ TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
}
+// ChromeOS doesn't use WebContents based power save blocking.
+#if !defined(OS_CHROMEOS)
+TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
+ // PlayerIDs are actually pointers cast to int64, so verify that both negative
+ // and positive player ids don't blow up.
+ const int kPlayerAudioVideoId = 15;
+ const int kPlayerAudioOnlyId = -15;
+ const int kPlayerVideoOnlyId = 30;
+ const int kPlayerRemoteId = -30;
+
+ EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+ EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
+
+ TestRenderFrameHost* rfh = contents()->GetMainFrame();
+ AudioStreamMonitor* monitor = contents()->audio_stream_monitor();
+
+ // The audio power save blocker should not be based on having a media player
+ // when audio stream monitoring is available.
+ if (AudioStreamMonitor::monitoring_available()) {
+ // Send a fake audio stream monitor notification. The audio power save
+ // blocker should be created.
+ monitor->set_was_recently_audible_for_testing(true);
+ contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+ EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
+
+ // Send another fake notification, this time when WasRecentlyAudible() will
+ // be false. The power save blocker should be released.
+ monitor->set_was_recently_audible_for_testing(false);
+ contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+ EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+ }
+
+ // 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));
+ EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
+ EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+ !AudioStreamMonitor::monitoring_available());
+
+ // Upon hiding the video power save blocker should be released.
+ contents()->WasHidden();
+ EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
+
+ // 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));
+ EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
+ EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+ !AudioStreamMonitor::monitoring_available());
+
+ // Showing the WebContents should result in the creation of the blocker.
+ contents()->WasShown();
+ EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
+
+ // 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));
+ EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
+ EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+ !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));
+ EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
+ EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+ !AudioStreamMonitor::monitoring_available());
+
+ // Destroy the original audio video player. Both power save blockers should
+ // remain.
+ rfh->OnMessageReceived(
+ FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId));
+ EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
+ EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
+ !AudioStreamMonitor::monitoring_available());
+
+ // Destroy the audio only player. The video power save blocker should remain.
+ rfh->OnMessageReceived(
+ FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId));
+ EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
+ EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+
+ // Destroy the video only player. No power save blockers should remain.
+ rfh->OnMessageReceived(
+ FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId));
+ EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
+ EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+
+ // Destroy the remote player. No power save blockers should remain.
+ rfh->OnMessageReceived(
+ FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId));
+ EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
+ EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
+}
+#endif
+
} // namespace content
diff --git a/chromium/content/browser/web_contents/web_contents_user_data_unittest.cc b/chromium/content/browser/web_contents/web_contents_user_data_unittest.cc
index acec01ded69..eeb2acb3de2 100644
--- a/chromium/content/browser/web_contents/web_contents_user_data_unittest.cc
+++ b/chromium/content/browser/web_contents/web_contents_user_data_unittest.cc
@@ -15,7 +15,8 @@ namespace content {
class WebContentsAttachedClass1
: public WebContentsUserData<WebContentsAttachedClass1> {
public:
- virtual ~WebContentsAttachedClass1() {}
+ ~WebContentsAttachedClass1() override {}
+
private:
explicit WebContentsAttachedClass1(WebContents* contents) {}
friend class WebContentsUserData<WebContentsAttachedClass1>;
@@ -24,7 +25,8 @@ class WebContentsAttachedClass1
class WebContentsAttachedClass2
: public WebContentsUserData<WebContentsAttachedClass2> {
public:
- virtual ~WebContentsAttachedClass2() {}
+ ~WebContentsAttachedClass2() override {}
+
private:
explicit WebContentsAttachedClass2(WebContents* contents) {}
friend class WebContentsUserData<WebContentsAttachedClass2>;
diff --git a/chromium/content/browser/web_contents/web_contents_view.h b/chromium/content/browser/web_contents/web_contents_view.h
index b2eb5090138..47daee9bac8 100644
--- a/chromium/content/browser/web_contents/web_contents_view.h
+++ b/chromium/content/browser/web_contents/web_contents_view.h
@@ -79,8 +79,13 @@ class WebContentsView {
// Sets up the View that holds the rendered web page, receives messages for
// it and contains page plugins. The host view should be sized to the current
// size of the WebContents.
+ //
+ // |is_guest_view_hack| is temporary hack and will be removed once
+ // RenderWidgetHostViewGuest is not dependent on platform view.
+ // TODO(lazyboy): Remove |is_guest_view_hack| once http://crbug.com/330264 is
+ // fixed.
virtual RenderWidgetHostViewBase* CreateViewForWidget(
- RenderWidgetHost* render_widget_host) = 0;
+ RenderWidgetHost* render_widget_host, bool is_guest_view_hack) = 0;
// Creates a new View that holds a popup and receives messages for it.
virtual RenderWidgetHostViewBase* CreateViewForPopupWidget(
@@ -104,23 +109,12 @@ class WebContentsView {
virtual void SetOverscrollControllerEnabled(bool enabled) = 0;
#if defined(OS_MACOSX)
- // The web contents view assumes that its view will never be overlapped by
- // another view (either partially or fully). This allows it to perform
- // optimizations. If the view is in a view hierarchy where it might be
- // overlapped by another view, notify the view by calling this with |true|.
- virtual void SetAllowOverlappingViews(bool overlapping) = 0;
-
- // Returns true if overlapping views are allowed, false otherwise.
- virtual bool GetAllowOverlappingViews() const = 0;
-
- // To draw two overlapping web contents view, the underlaying one should
- // know about the overlaying one. Caller must ensure that |overlay| exists
- // until |RemoveOverlayView| is called.
- virtual void SetOverlayView(WebContentsView* overlay,
- const gfx::Point& offset) = 0;
-
- // Removes the previously set overlay view.
- virtual void RemoveOverlayView() = 0;
+ // Allowing other views disables optimizations which assume that only a single
+ // WebContents is present.
+ virtual void SetAllowOtherViews(bool allow) = 0;
+
+ // Returns true if other views are allowed, false otherwise.
+ virtual bool GetAllowOtherViews() const = 0;
// If we close the tab while a UI control is in an event-tracking
// loop, the control may message freed objects and crash.
diff --git a/chromium/content/browser/web_contents/web_contents_view_android.cc b/chromium/content/browser/web_contents/web_contents_view_android.cc
index 3378595be7e..b276b191409 100644
--- a/chromium/content/browser/web_contents/web_contents_view_android.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_android.cc
@@ -121,7 +121,7 @@ void WebContentsViewAndroid::CreateView(
}
RenderWidgetHostViewBase* WebContentsViewAndroid::CreateViewForWidget(
- RenderWidgetHost* render_widget_host) {
+ RenderWidgetHost* render_widget_host, bool is_guest_view_hack) {
if (render_widget_host->GetView()) {
// During testing, the view will already be set up in most cases to the
// test view, so we don't want to clobber it with a real one. To verify that
@@ -163,6 +163,7 @@ void WebContentsViewAndroid::ShowContextMenu(
}
void WebContentsViewAndroid::ShowPopupMenu(
+ RenderFrameHost* render_frame_host,
const gfx::Rect& bounds,
int item_height,
double item_font_size,
@@ -171,8 +172,11 @@ void WebContentsViewAndroid::ShowPopupMenu(
bool right_aligned,
bool allow_multiple_selection) {
if (content_view_core_) {
- content_view_core_->ShowSelectPopupMenu(
- bounds, items, selected_item, allow_multiple_selection);
+ content_view_core_->ShowSelectPopupMenu(render_frame_host,
+ bounds,
+ items,
+ selected_item,
+ allow_multiple_selection);
}
}
diff --git a/chromium/content/browser/web_contents/web_contents_view_android.h b/chromium/content/browser/web_contents/web_contents_view_android.h
index 2503595e840..c480c0e9bd9 100644
--- a/chromium/content/browser/web_contents/web_contents_view_android.h
+++ b/chromium/content/browser/web_contents/web_contents_view_android.h
@@ -30,47 +30,48 @@ class WebContentsViewAndroid : public WebContentsView,
void SetContentViewCore(ContentViewCoreImpl* content_view_core);
// WebContentsView implementation --------------------------------------------
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeView GetContentNativeView() const OVERRIDE;
- virtual gfx::NativeWindow GetTopLevelNativeWindow() const OVERRIDE;
- virtual void GetContainerBounds(gfx::Rect* out) const OVERRIDE;
- virtual void SizeContents(const gfx::Size& size) OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void SetInitialFocus() OVERRIDE;
- virtual void StoreFocus() OVERRIDE;
- virtual void RestoreFocus() OVERRIDE;
- virtual DropData* GetDropData() const OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
+ virtual gfx::NativeView GetNativeView() const override;
+ virtual gfx::NativeView GetContentNativeView() const override;
+ virtual gfx::NativeWindow GetTopLevelNativeWindow() const override;
+ virtual void GetContainerBounds(gfx::Rect* out) const override;
+ virtual void SizeContents(const gfx::Size& size) override;
+ virtual void Focus() override;
+ virtual void SetInitialFocus() override;
+ virtual void StoreFocus() override;
+ virtual void RestoreFocus() override;
+ virtual DropData* GetDropData() const override;
+ virtual gfx::Rect GetViewBounds() const override;
virtual void CreateView(
- const gfx::Size& initial_size, gfx::NativeView context) OVERRIDE;
+ const gfx::Size& initial_size, gfx::NativeView context) override;
virtual RenderWidgetHostViewBase* CreateViewForWidget(
- RenderWidgetHost* render_widget_host) OVERRIDE;
+ RenderWidgetHost* render_widget_host, bool is_guest_view_hack) override;
virtual RenderWidgetHostViewBase* CreateViewForPopupWidget(
- RenderWidgetHost* render_widget_host) OVERRIDE;
- virtual void SetPageTitle(const base::string16& title) OVERRIDE;
- virtual void RenderViewCreated(RenderViewHost* host) OVERRIDE;
- virtual void RenderViewSwappedIn(RenderViewHost* host) OVERRIDE;
- virtual void SetOverscrollControllerEnabled(bool enabled) OVERRIDE;
+ RenderWidgetHost* render_widget_host) override;
+ virtual void SetPageTitle(const base::string16& title) override;
+ virtual void RenderViewCreated(RenderViewHost* host) override;
+ virtual void RenderViewSwappedIn(RenderViewHost* host) override;
+ virtual void SetOverscrollControllerEnabled(bool enabled) override;
// Backend implementation of RenderViewHostDelegateView.
virtual void ShowContextMenu(RenderFrameHost* render_frame_host,
- const ContextMenuParams& params) OVERRIDE;
- virtual void ShowPopupMenu(const gfx::Rect& bounds,
+ const ContextMenuParams& params) override;
+ virtual void ShowPopupMenu(RenderFrameHost* render_frame_host,
+ const gfx::Rect& bounds,
int item_height,
double item_font_size,
int selected_item,
const std::vector<MenuItem>& items,
bool right_aligned,
- bool allow_multiple_selection) OVERRIDE;
- virtual void HidePopupMenu() OVERRIDE;
+ bool allow_multiple_selection) override;
+ virtual void HidePopupMenu() override;
virtual void StartDragging(const DropData& drop_data,
blink::WebDragOperationsMask allowed_ops,
const gfx::ImageSkia& image,
const gfx::Vector2d& image_offset,
- const DragEventSourceInfo& event_info) OVERRIDE;
- virtual void UpdateDragCursor(blink::WebDragOperation operation) OVERRIDE;
- virtual void GotFocus() OVERRIDE;
- virtual void TakeFocus(bool reverse) OVERRIDE;
+ const DragEventSourceInfo& event_info) override;
+ virtual void UpdateDragCursor(blink::WebDragOperation operation) override;
+ virtual void GotFocus() override;
+ virtual void TakeFocus(bool reverse) override;
private:
// The WebContents whose contents we display.
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 db7b056258f..056bb3e3cc3 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_aura.cc
@@ -6,7 +6,7 @@
#include "base/auto_reset.h"
#include "base/command_line.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
@@ -19,6 +19,7 @@
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#include "content/browser/renderer_host/web_input_event_aura.h"
#include "content/browser/web_contents/aura/gesture_nav_simple.h"
#include "content/browser/web_contents/aura/image_window_delegate.h"
#include "content/browser/web_contents/aura/overscroll_navigation_overlay.h"
@@ -66,10 +67,17 @@
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/screen.h"
#include "ui/wm/public/drag_drop_client.h"
#include "ui/wm/public/drag_drop_delegate.h"
+#if defined(OS_WIN)
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/browser_accessibility_win.h"
+#include "ui/base/win/hidden_window.h"
+#endif
+
namespace content {
WebContentsView* CreateWebContentsView(
WebContentsImpl* web_contents,
@@ -83,7 +91,7 @@ WebContentsView* CreateWebContentsView(
namespace {
bool IsScrollEndEffectEnabled() {
- return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kScrollEndEffect) == "1";
}
@@ -99,17 +107,6 @@ bool ShouldNavigateBack(const NavigationController& controller,
controller.CanGoBack();
}
-// Update the |web contents| to be |visible|.
-void UpdateWebContentsVisibility(WebContentsImpl* web_contents, bool visible) {
- if (visible) {
- if (!web_contents->should_normally_be_visible())
- web_contents->WasShown();
- } else {
- if (web_contents->should_normally_be_visible())
- web_contents->WasHidden();
- }
-}
-
RenderWidgetHostViewAura* ToRenderWidgetHostViewAura(
RenderWidgetHostView* view) {
if (!view || RenderViewHostFactory::has_factory())
@@ -145,8 +142,7 @@ class OverscrollWindowDelegate : public ImageWindowDelegate {
gfx::Image image;
if (entry && entry->screenshot().get()) {
std::vector<gfx::ImagePNGRep> image_reps;
- image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(),
- ui::GetScaleFactorForNativeView(web_contents_window())));
+ image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 1.0f));
image = gfx::Image(image_reps);
}
SetImage(image);
@@ -155,19 +151,19 @@ class OverscrollWindowDelegate : public ImageWindowDelegate {
void stop_forwarding_events() { forward_events_ = false; }
private:
- virtual ~OverscrollWindowDelegate() {}
+ ~OverscrollWindowDelegate() override {}
aura::Window* web_contents_window() {
return web_contents_->GetView()->GetContentNativeView();
}
// Overridden from ui::EventHandler.
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
+ void OnScrollEvent(ui::ScrollEvent* event) override {
if (forward_events_ && web_contents_window())
web_contents_window()->delegate()->OnScrollEvent(event);
}
- virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+ void OnGestureEvent(ui::GestureEvent* event) override {
if (forward_events_ && web_contents_window())
web_contents_window()->delegate()->OnGestureEvent(event);
}
@@ -197,13 +193,12 @@ class WebDragSourceAura : public NotificationObserver {
Source<WebContents>(contents));
}
- virtual ~WebDragSourceAura() {
- }
+ ~WebDragSourceAura() override {}
// NotificationObserver:
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE {
+ void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) override {
if (type != NOTIFICATION_WEB_CONTENTS_DISCONNECTED)
return;
@@ -320,7 +315,7 @@ const ui::OSExchangeData::CustomFormat& GetFileSystemFileCustomFormat() {
void WriteFileSystemFilesToPickle(
const std::vector<DropData::FileSystemFileInfo>& file_system_files,
Pickle* pickle) {
- pickle->WriteUInt64(file_system_files.size());
+ pickle->WriteSizeT(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);
@@ -333,12 +328,12 @@ bool ReadFileSystemFilesFromPickle(
std::vector<DropData::FileSystemFileInfo>* file_system_files) {
PickleIterator iter(pickle);
- uint64 num_files = 0;
- if (!pickle.ReadUInt64(&iter, &num_files))
+ size_t num_files = 0;
+ if (!pickle.ReadSizeT(&iter, &num_files))
return false;
file_system_files->resize(num_files);
- for (uint64 i = 0; i < num_files; ++i) {
+ for (size_t i = 0; i < num_files; ++i) {
std::string url_string;
int64 size = 0;
if (!pickle.ReadString(&iter, &url_string) ||
@@ -373,6 +368,10 @@ void PrepareDragData(const DropData& drop_data,
if (!drop_data.file_contents.empty())
PrepareDragForFileContents(drop_data, provider);
#endif
+ // Call SetString() before SetURL() when we actually have a custom string.
+ // SetURL() will itself do SetString() when a string hasn't been set yet,
+ // but we want to prefer drop_data.text.string() over the URL string if it
+ // exists.
if (!drop_data.text.string().empty())
provider->SetString(drop_data.text.string());
if (drop_data.url.is_valid())
@@ -477,7 +476,7 @@ class WebContentsViewAura::WindowObserver
public:
explicit WindowObserver(WebContentsViewAura* view)
: view_(view),
- parent_(NULL) {
+ host_window_(NULL) {
view_->window_->AddObserver(this);
#if defined(OS_WIN)
@@ -486,16 +485,15 @@ class WebContentsViewAura::WindowObserver
#endif
}
- virtual ~WindowObserver() {
+ ~WindowObserver() override {
view_->window_->RemoveObserver(this);
if (view_->window_->GetHost())
view_->window_->GetHost()->RemoveObserver(this);
- if (parent_)
- parent_->RemoveObserver(this);
-
+ if (host_window_)
+ host_window_->RemoveObserver(this);
#if defined(OS_WIN)
- if (parent_) {
- const aura::Window::Windows& children = parent_->children();
+ if (host_window_) {
+ const aura::Window::Windows& children = host_window_->children();
for (size_t i = 0; i < children.size(); ++i)
children[i]->RemoveObserver(this);
}
@@ -511,6 +509,20 @@ class WebContentsViewAura::WindowObserver
}
// Overridden from aura::WindowObserver:
+ void OnWindowHierarchyChanged(
+ const aura::WindowObserver::HierarchyChangeParams& params) override {
+ if (params.receiver != view_->window_.get() ||
+ !params.target->Contains(view_->window_.get())) {
+ return;
+ }
+
+ // Use the new parent's root window for calculating HiDPI subpixel offset.
+ RenderWidgetHostViewAura* rwhv = ToRenderWidgetHostViewAura(
+ view_->web_contents_->GetRenderWidgetHostView());
+ if (rwhv)
+ rwhv->SnapToPhysicalPixelBoundary();
+ }
+
#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
@@ -518,25 +530,25 @@ class WebContentsViewAura::WindowObserver
// 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.
- virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE {
- if (new_window != view_->window_) {
+ virtual 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 != parent_) {
+ if (new_window != host_window_) {
// Observe sibling windows of the WebContents, or children of the root
// window.
- if (new_window->parent() == parent_ ||
+ if (new_window->parent() == host_window_ ||
new_window->parent() == view_->window_->GetRootWindow()) {
new_window->AddObserver(this);
}
}
}
- if (new_window->parent() == parent_) {
+ if (new_window->parent() == host_window_) {
UpdateConstrainedWindows(NULL);
}
}
- virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE {
+ virtual void OnWillRemoveWindow(aura::Window* window) override {
if (window == view_->window_)
return;
@@ -545,58 +557,63 @@ class WebContentsViewAura::WindowObserver
}
virtual void OnWindowVisibilityChanged(aura::Window* window,
- bool visible) OVERRIDE {
+ bool visible) override {
if (window == view_->window_ ||
- window->parent() == parent_ ||
+ window->parent() == host_window_ ||
window->parent() == view_->window_->GetRootWindow()) {
UpdateConstrainedWindows(NULL);
}
}
#endif
- virtual void OnWindowParentChanged(aura::Window* window,
- aura::Window* parent) OVERRIDE {
+ void OnWindowParentChanged(aura::Window* window,
+ aura::Window* parent) override {
if (window != view_->window_)
return;
- if (parent_)
- parent_->RemoveObserver(this);
+
+ aura::Window* host_window =
+ window->GetProperty(aura::client::kHostWindowKey);
+ if (!host_window)
+ host_window = parent;
+
+ if (host_window_)
+ host_window_->RemoveObserver(this);
#if defined(OS_WIN)
- if (parent_) {
- const aura::Window::Windows& children = parent_->children();
+ 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* view = ToRenderWidgetHostViewAura(
+ RenderWidgetHostViewAura* rwhv = ToRenderWidgetHostViewAura(
view_->web_contents_->GetRenderWidgetHostView());
- if (view)
- view->UpdateConstrainedWindowRects(std::vector<gfx::Rect>());
+ if (rwhv)
+ rwhv->UpdateConstrainedWindowRects(std::vector<gfx::Rect>());
}
// When we get parented to the root window, the code below will watch the
- // parent, aka root window. Since we already watch the root window on
+ // 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 (parent && parent == window->GetRootWindow())
- parent->RemoveObserver(this);
+ 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() &&
- parent != window->GetRootWindow() &&
+ host_window != window->GetRootWindow() &&
!window->GetRootWindow()->HasObserver(this)) {
window->GetRootWindow()->AddObserver(this);
}
#endif
- parent_ = parent;
- if (parent) {
- parent->AddObserver(this);
+ host_window_ = host_window;
+ if (host_window) {
+ host_window->AddObserver(this);
#if defined(OS_WIN)
- if (parent != window->GetRootWindow()) {
- const aura::Window::Windows& children = parent->children();
+ 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] != view_->window_)
+ if (!children[i]->Contains(view_->window_.get()))
children[i]->AddObserver(this);
}
}
@@ -604,10 +621,10 @@ class WebContentsViewAura::WindowObserver
}
}
- virtual void OnWindowBoundsChanged(aura::Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) OVERRIDE {
- if (window == parent_ || window == view_->window_) {
+ void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) override {
+ if (window == host_window_ || window == view_->window_) {
SendScreenRects();
if (view_->touch_editable_)
view_->touch_editable_->UpdateEditingController();
@@ -618,18 +635,29 @@ class WebContentsViewAura::WindowObserver
}
}
- virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE {
+ void OnWindowDestroying(aura::Window* window) override {
+ if (window == host_window_) {
+ host_window_->RemoveObserver(this);
+ host_window_ = NULL;
+ }
+ }
+
+ void OnWindowAddedToRootWindow(aura::Window* window) override {
if (window == view_->window_) {
window->GetHost()->AddObserver(this);
#if defined(OS_WIN)
if (!window->GetRootWindow()->HasObserver(this))
window->GetRootWindow()->AddObserver(this);
+ if (view_->legacy_hwnd_) {
+ view_->legacy_hwnd_->UpdateParent(
+ window->GetHost()->GetAcceleratedWidget());
+ }
#endif
}
}
- virtual void OnWindowRemovingFromRootWindow(aura::Window* window,
- aura::Window* new_root) OVERRIDE {
+ void OnWindowRemovingFromRootWindow(aura::Window* window,
+ aura::Window* new_root) override {
if (window == view_->window_) {
window->GetHost()->RemoveObserver(this);
#if defined(OS_WIN)
@@ -638,16 +666,21 @@ class WebContentsViewAura::WindowObserver
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_ && root_children[i] != parent_)
+ if (root_children[i] != view_->window_ &&
+ root_children[i] != host_window_) {
root_children[i]->RemoveObserver(this);
+ }
}
+
+ if (view_->legacy_hwnd_)
+ view_->legacy_hwnd_->UpdateParent(ui::GetHiddenWindow());
#endif
}
}
// Overridden WindowTreeHostObserver:
- virtual void OnHostMoved(const aura::WindowTreeHost* host,
- const gfx::Point& new_origin) OVERRIDE {
+ void OnHostMoved(const aura::WindowTreeHost* host,
+ const gfx::Point& new_origin) override {
TRACE_EVENT1("ui",
"WebContentsViewAura::WindowObserver::OnHostMoved",
"new_origin", new_origin.ToString());
@@ -670,10 +703,10 @@ class WebContentsViewAura::WindowObserver
return;
std::vector<gfx::Rect> constrained_windows;
- if (parent_) {
- const aura::Window::Windows& children = parent_->children();
+ if (host_window_) {
+ const aura::Window::Windows& children = host_window_->children();
for (size_t i = 0; i < children.size(); ++i) {
- if (children[i] != view_->window_ &&
+ if (!children[i]->Contains(view_->window_.get()) &&
children[i] != exclude &&
children[i]->IsVisible()) {
constrained_windows.push_back(children[i]->GetBoundsInRootWindow());
@@ -699,9 +732,9 @@ class WebContentsViewAura::WindowObserver
WebContentsViewAura* view_;
- // We cache the old parent so that we can unregister when it's not the parent
- // anymore.
- aura::Window* parent_;
+ // The parent window that hosts the constrained windows. We cache the old host
+ // view so that we can unregister when it's not the parent anymore.
+ aura::Window* host_window_;
DISALLOW_COPY_AND_ASSIGN(WindowObserver);
};
@@ -720,7 +753,8 @@ WebContentsViewAura::WebContentsViewAura(
overscroll_change_brightness_(false),
current_overscroll_gesture_(OVERSCROLL_NONE),
completed_overscroll_gesture_(OVERSCROLL_NONE),
- touch_editable_(TouchEditableImplAura::Create()) {
+ touch_editable_(TouchEditableImplAura::Create()),
+ is_or_was_visible_(false) {
}
////////////////////////////////////////////////////////////////////////////////
@@ -769,7 +803,7 @@ void WebContentsViewAura::EndDrag(blink::WebDragOperationsMask ops) {
void WebContentsViewAura::InstallOverscrollControllerDelegate(
RenderWidgetHostViewAura* view) {
- const std::string value = CommandLine::ForCurrentProcess()->
+ const std::string value = base::CommandLine::ForCurrentProcess()->
GetSwitchValueASCII(switches::kOverscrollHistoryNavigation);
if (value == "0") {
navigation_overlay_.reset();
@@ -790,7 +824,7 @@ void WebContentsViewAura::InstallOverscrollControllerDelegate(
void WebContentsViewAura::PrepareOverscrollWindow() {
// If there is an existing |overscroll_window_| which is in the middle of an
// animation, then destroying the window here causes the animation to be
- // completed immidiately, which triggers |OnImplicitAnimationsCompleted()|
+ // completed immediately, which triggers |OnImplicitAnimationsCompleted()|
// callback, and that tries to reset |overscroll_window_| again, causing a
// double-free. So use a temporary variable here.
if (overscroll_window_) {
@@ -891,7 +925,8 @@ void WebContentsViewAura::CompleteOverscrollNavigation(OverscrollMode mode) {
gfx::Transform transform;
int content_width =
web_contents_->GetRenderWidgetHostView()->GetViewBounds().width();
- int translate_x = mode == OVERSCROLL_WEST ? -content_width : content_width;
+ float translate_x = static_cast<float>(mode == OVERSCROLL_WEST ?
+ -content_width : content_width);
transform.Translate(translate_x, 0);
target->SetTransform(transform);
UpdateOverscrollWindowBrightness(translate_x);
@@ -906,21 +941,22 @@ aura::Window* WebContentsViewAura::GetWindowToAnimateForOverscroll() {
overscroll_window_.get() : GetContentNativeView();
}
-gfx::Vector2d WebContentsViewAura::GetTranslationForOverscroll(int delta_x,
- int delta_y) {
+gfx::Vector2dF WebContentsViewAura::GetTranslationForOverscroll(float delta_x,
+ float delta_y) {
if (current_overscroll_gesture_ == OVERSCROLL_NORTH ||
current_overscroll_gesture_ == OVERSCROLL_SOUTH) {
- return gfx::Vector2d(0, delta_y);
+ return gfx::Vector2dF(0, delta_y);
}
// For horizontal overscroll, scroll freely if a navigation is possible. Do a
// resistive scroll otherwise.
const NavigationControllerImpl& controller = web_contents_->GetController();
const gfx::Rect& bounds = GetViewBounds();
+ const float bounds_width = static_cast<float>(bounds.width());
if (ShouldNavigateForward(controller, current_overscroll_gesture_))
- return gfx::Vector2d(std::max(-bounds.width(), delta_x), 0);
+ return gfx::Vector2dF(std::max(-bounds_width, delta_x), 0);
else if (ShouldNavigateBack(controller, current_overscroll_gesture_))
- return gfx::Vector2d(std::min(bounds.width(), delta_x), 0);
- return gfx::Vector2d();
+ return gfx::Vector2dF(std::min(bounds_width, delta_x), 0);
+ return gfx::Vector2dF();
}
void WebContentsViewAura::PrepareOverscrollNavigationOverlay() {
@@ -963,7 +999,8 @@ void WebContentsViewAura::AttachTouchEditableToRenderView() {
touch_editable_->AttachToView(rwhva);
}
-void WebContentsViewAura::OverscrollUpdateForWebContentsDelegate(int delta_y) {
+void WebContentsViewAura::OverscrollUpdateForWebContentsDelegate(
+ float delta_y) {
if (web_contents_->GetDelegate() && IsScrollEndEffectEnabled())
web_contents_->GetDelegate()->OverscrollUpdate(delta_y);
}
@@ -993,6 +1030,10 @@ void WebContentsViewAura::SizeContents(const gfx::Size& size) {
if (bounds.size() != size) {
bounds.set_size(size);
window_->SetBounds(bounds);
+#if defined(OS_WIN)
+ if (legacy_hwnd_)
+ legacy_hwnd_->SetBounds(window_->GetBoundsInRootWindow());
+#endif
} else {
// Our size matches what we want but the renderers size may not match.
// Pretend we were resized so that the renderers size is updated too.
@@ -1009,7 +1050,10 @@ void WebContentsViewAura::Focus() {
if (delegate_.get() && delegate_->Focus())
return;
- RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
+ RenderWidgetHostView* rwhv =
+ web_contents_->GetFullscreenRenderWidgetHostView();
+ if (!rwhv)
+ rwhv = web_contents_->GetRenderWidgetHostView();
if (rwhv)
rwhv->Focus();
}
@@ -1086,10 +1130,18 @@ void WebContentsViewAura::CreateView(
// platforms as well.
if (delegate_)
drag_dest_delegate_ = delegate_->GetDragDestDelegate();
+
+#if defined(OS_WIN)
+ if (context && context->GetHost()) {
+ HWND parent_hwnd = context->GetHost()->GetAcceleratedWidget();
+ CHECK(parent_hwnd);
+ legacy_hwnd_.reset(LegacyRenderWidgetHostHWND::Create(parent_hwnd, this));
+ }
+#endif
}
RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForWidget(
- RenderWidgetHost* render_widget_host) {
+ RenderWidgetHost* render_widget_host, bool is_guest_view_hack) {
if (render_widget_host->GetView()) {
// During testing, the view will already be set up in most cases to the
// test view, so we don't want to clobber it with a real one. To verify that
@@ -1102,7 +1154,7 @@ RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForWidget(
}
RenderWidgetHostViewAura* view =
- new RenderWidgetHostViewAura(render_widget_host);
+ new RenderWidgetHostViewAura(render_widget_host, is_guest_view_hack);
view->InitAsChild(NULL);
GetNativeView()->AddChild(view->GetNativeView());
@@ -1126,16 +1178,28 @@ RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForWidget(
}
AttachTouchEditableToRenderView();
+
+#if defined(OS_WIN)
+ if (legacy_hwnd_)
+ view->SetLegacyRenderWidgetHostHWND(legacy_hwnd_.get());
+#endif
+
return view;
}
RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForPopupWidget(
RenderWidgetHost* render_widget_host) {
- return new RenderWidgetHostViewAura(render_widget_host);
+ RenderWidgetHostViewAura* view =
+ new RenderWidgetHostViewAura(render_widget_host, false);
+#if defined(OS_WIN)
+ if (legacy_hwnd_)
+ view->SetLegacyRenderWidgetHostHWND(legacy_hwnd_.get());
+#endif
+ return view;
}
void WebContentsViewAura::SetPageTitle(const base::string16& title) {
- window_->set_title(title);
+ window_->SetTitle(title);
}
void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) {
@@ -1249,6 +1313,22 @@ void WebContentsViewAura::TakeFocus(bool reverse) {
}
}
+void WebContentsViewAura::ShowDisambiguationPopup(
+ const gfx::Rect& target_rect,
+ const SkBitmap& zoomed_bitmap,
+ const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
+ const base::Callback<void(ui::MouseEvent*)>& mouse_cb) {
+ if (delegate_) {
+ delegate_->ShowDisambiguationPopup(target_rect, zoomed_bitmap,
+ window_.get(), gesture_cb, mouse_cb);
+ }
+}
+
+void WebContentsViewAura::HideDisambiguationPopup() {
+ if (delegate_)
+ delegate_->HideDisambiguationPopup();
+}
+
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewAura, OverscrollControllerDelegate implementation:
@@ -1260,28 +1340,34 @@ gfx::Rect WebContentsViewAura::GetVisibleBounds() const {
return rwhv->GetViewBounds();
}
-void WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) {
+bool WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) {
if (current_overscroll_gesture_ == OVERSCROLL_NONE)
- return;
+ return false;
aura::Window* target = GetWindowToAnimateForOverscroll();
- gfx::Vector2d translate = GetTranslationForOverscroll(delta_x, delta_y);
+ gfx::Vector2dF translate = GetTranslationForOverscroll(delta_x, delta_y);
gfx::Transform transform;
- // Vertical overscrolls don't participate in the navigation gesture.
- if (current_overscroll_gesture_ != OVERSCROLL_NORTH &&
- current_overscroll_gesture_ != OVERSCROLL_SOUTH) {
+ if (current_overscroll_gesture_ == OVERSCROLL_NORTH ||
+ current_overscroll_gesture_ == OVERSCROLL_SOUTH) {
+ OverscrollUpdateForWebContentsDelegate(translate.y());
+ } else {
+ // Only horizontal overscrolls participate in the navigation gesture.
transform.Translate(translate.x(), translate.y());
target->SetTransform(transform);
UpdateOverscrollWindowBrightness(delta_x);
}
- OverscrollUpdateForWebContentsDelegate(translate.y());
+ return !translate.IsZero();
}
void WebContentsViewAura::OnOverscrollComplete(OverscrollMode mode) {
UMA_HISTOGRAM_ENUMERATION("Overscroll.Completed", mode, OVERSCROLL_COUNT);
- OverscrollUpdateForWebContentsDelegate(0);
+ if (web_contents_->GetDelegate() &&
+ IsScrollEndEffectEnabled() &&
+ (mode == OVERSCROLL_NORTH || mode == OVERSCROLL_SOUTH)) {
+ web_contents_->GetDelegate()->OverscrollComplete();
+ }
NavigationControllerImpl& controller = web_contents_->GetController();
if (ShouldNavigateForward(controller, mode) ||
ShouldNavigateBack(controller, mode)) {
@@ -1297,6 +1383,9 @@ void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode,
// Reset any in-progress overscroll animation first.
ResetOverscrollTransform();
+ if (old_mode == OVERSCROLL_NORTH || old_mode == OVERSCROLL_SOUTH)
+ OverscrollUpdateForWebContentsDelegate(0);
+
if (new_mode != OVERSCROLL_NONE && touch_editable_)
touch_editable_->OverscrollStarted();
@@ -1305,7 +1394,6 @@ void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode,
((new_mode == OVERSCROLL_EAST || new_mode == OVERSCROLL_WEST) &&
navigation_overlay_.get() && navigation_overlay_->has_window())) {
current_overscroll_gesture_ = OVERSCROLL_NONE;
- OverscrollUpdateForWebContentsDelegate(0);
} else {
aura::Window* target = GetWindowToAnimateForOverscroll();
if (target) {
@@ -1481,9 +1569,9 @@ void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
// Give the delegate an opportunity to cancel the drag.
- if (!web_contents_->GetDelegate()->CanDragEnter(web_contents_,
- *current_drop_data_.get(),
- op)) {
+ if (web_contents_->GetDelegate() &&
+ !web_contents_->GetDelegate()->CanDragEnter(
+ web_contents_, *current_drop_data_.get(), op)) {
current_drop_data_.reset(NULL);
return;
}
@@ -1557,22 +1645,65 @@ int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
return ConvertFromWeb(current_drag_op_);
}
-void WebContentsViewAura::OnWindowParentChanged(aura::Window* window,
- aura::Window* parent) {
- // On Windows we will get called with a parent of NULL as part of the shut
- // down process. As such we do only change the visibility when a parent gets
- // set.
- if (parent)
- UpdateWebContentsVisibility(web_contents_, window->IsVisible());
-}
-
void WebContentsViewAura::OnWindowVisibilityChanged(aura::Window* window,
bool visible) {
// Ignore any visibility changes in the hierarchy below.
if (window != window_.get() && window_->Contains(window))
return;
- UpdateWebContentsVisibility(web_contents_, visible);
+ 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();
+ }
+
+#if defined(OS_WIN)
+ if (!legacy_hwnd_)
+ return;
+
+ if (visible && GetNativeView() && GetNativeView()->GetHost()) {
+ legacy_hwnd_->UpdateParent(
+ GetNativeView()->GetHost()->GetAcceleratedWidget());
+ legacy_hwnd_->SetBounds(window_->GetBoundsInRootWindow());
+ legacy_hwnd_->Show();
+ } else {
+ // We reparent the legacy Chrome_RenderWidgetHostHWND window to the global
+ // hidden window on the same lines as Windowed plugin windows.
+ legacy_hwnd_->UpdateParent(ui::GetHiddenWindow());
+ legacy_hwnd_->Hide();
+ }
+#endif
+}
+
+#if defined(OS_WIN)
+gfx::NativeViewAccessible
+WebContentsViewAura::GetNativeViewAccessible() {
+ BrowserAccessibilityManager* manager =
+ web_contents_->GetRootBrowserAccessibilityManager();
+ if (!manager)
+ return nullptr;
+
+ return manager->GetRoot()->ToBrowserAccessibilityWin();
+}
+#endif
+
} // 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 71a425a18f8..cf5177662ae 100644
--- a/chromium/content/browser/web_contents/web_contents_view_aura.h
+++ b/chromium/content/browser/web_contents/web_contents_view_aura.h
@@ -18,6 +18,11 @@
#include "ui/compositor/layer_animation_observer.h"
#include "ui/wm/public/drag_drop_delegate.h"
+#if defined(OS_WIN)
+#include "content/browser/renderer_host/legacy_render_widget_host_win.h"
+#include "content/browser/renderer_host/legacy_render_widget_host_win_delegate.h"
+#endif
+
namespace aura {
class Window;
}
@@ -37,8 +42,15 @@ class WebContentsViewDelegate;
class WebContentsImpl;
class WebDragDestDelegate;
+#if defined(OS_WIN)
+class LegacyRenderWidgetHostHWND;
+#endif
+
class WebContentsViewAura
: public WebContentsView,
+#if defined(OS_WIN)
+ public LegacyRenderWidgetHostHWNDDelegate,
+#endif
public RenderViewHostDelegateView,
public OverscrollControllerDelegate,
public ui::ImplicitAnimationObserver,
@@ -55,7 +67,7 @@ class WebContentsViewAura
private:
class WindowObserver;
- virtual ~WebContentsViewAura();
+ ~WebContentsViewAura() override;
void SizeChangedCommon(const gfx::Size& size);
@@ -88,7 +100,7 @@ class WebContentsViewAura
// Returns the amount the animating window should be translated in response to
// the overscroll gesture.
- gfx::Vector2d GetTranslationForOverscroll(int delta_x, int delta_y);
+ gfx::Vector2dF GetTranslationForOverscroll(float delta_x, float delta_y);
// A window showing the screenshot is overlayed during a navigation triggered
// by overscroll. This function sets this up.
@@ -100,88 +112,100 @@ class WebContentsViewAura
void AttachTouchEditableToRenderView();
- void OverscrollUpdateForWebContentsDelegate(int delta_y);
+ void OverscrollUpdateForWebContentsDelegate(float delta_y);
// Overridden from WebContentsView:
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeView GetContentNativeView() const OVERRIDE;
- virtual gfx::NativeWindow GetTopLevelNativeWindow() const OVERRIDE;
- virtual void GetContainerBounds(gfx::Rect *out) const OVERRIDE;
- virtual void SizeContents(const gfx::Size& size) OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void SetInitialFocus() OVERRIDE;
- virtual void StoreFocus() OVERRIDE;
- virtual void RestoreFocus() OVERRIDE;
- virtual DropData* GetDropData() const OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
- virtual void CreateView(
- const gfx::Size& initial_size, gfx::NativeView context) OVERRIDE;
- virtual RenderWidgetHostViewBase* CreateViewForWidget(
- RenderWidgetHost* render_widget_host) OVERRIDE;
- virtual RenderWidgetHostViewBase* CreateViewForPopupWidget(
- RenderWidgetHost* render_widget_host) OVERRIDE;
- virtual void SetPageTitle(const base::string16& title) OVERRIDE;
- virtual void RenderViewCreated(RenderViewHost* host) OVERRIDE;
- virtual void RenderViewSwappedIn(RenderViewHost* host) OVERRIDE;
- virtual void SetOverscrollControllerEnabled(bool enabled) OVERRIDE;
+ gfx::NativeView GetNativeView() const override;
+ gfx::NativeView GetContentNativeView() const override;
+ gfx::NativeWindow GetTopLevelNativeWindow() const override;
+ void GetContainerBounds(gfx::Rect* out) const override;
+ void SizeContents(const gfx::Size& size) override;
+ void Focus() override;
+ void SetInitialFocus() override;
+ void StoreFocus() override;
+ void RestoreFocus() override;
+ DropData* GetDropData() const override;
+ gfx::Rect GetViewBounds() const override;
+ void CreateView(const gfx::Size& initial_size,
+ gfx::NativeView context) override;
+ RenderWidgetHostViewBase* CreateViewForWidget(
+ RenderWidgetHost* render_widget_host,
+ bool is_guest_view_hack) override;
+ RenderWidgetHostViewBase* CreateViewForPopupWidget(
+ RenderWidgetHost* render_widget_host) override;
+ void SetPageTitle(const base::string16& title) override;
+ void RenderViewCreated(RenderViewHost* host) override;
+ void RenderViewSwappedIn(RenderViewHost* host) override;
+ void SetOverscrollControllerEnabled(bool enabled) override;
// Overridden from RenderViewHostDelegateView:
- virtual void ShowContextMenu(RenderFrameHost* render_frame_host,
- const ContextMenuParams& params) OVERRIDE;
- virtual void StartDragging(const DropData& drop_data,
- blink::WebDragOperationsMask operations,
- const gfx::ImageSkia& image,
- const gfx::Vector2d& image_offset,
- const DragEventSourceInfo& event_info) OVERRIDE;
- virtual void UpdateDragCursor(blink::WebDragOperation operation) OVERRIDE;
- virtual void GotFocus() OVERRIDE;
- virtual void TakeFocus(bool reverse) OVERRIDE;
+ void ShowContextMenu(RenderFrameHost* render_frame_host,
+ const ContextMenuParams& params) override;
+ void StartDragging(const DropData& drop_data,
+ blink::WebDragOperationsMask operations,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const DragEventSourceInfo& event_info) override;
+ void UpdateDragCursor(blink::WebDragOperation operation) override;
+ void GotFocus() override;
+ void TakeFocus(bool reverse) override;
+ void ShowDisambiguationPopup(
+ const gfx::Rect& target_rect,
+ const SkBitmap& zoomed_bitmap,
+ const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
+ const base::Callback<void(ui::MouseEvent*)>& mouse_cb) override;
+ void HideDisambiguationPopup() override;
// Overridden from OverscrollControllerDelegate:
- virtual gfx::Rect GetVisibleBounds() const OVERRIDE;
- virtual void OnOverscrollUpdate(float delta_x, float delta_y) OVERRIDE;
- virtual void OnOverscrollComplete(OverscrollMode overscroll_mode) OVERRIDE;
- virtual void OnOverscrollModeChange(OverscrollMode old_mode,
- OverscrollMode new_mode) OVERRIDE;
+ gfx::Rect GetVisibleBounds() const override;
+ bool OnOverscrollUpdate(float delta_x, float delta_y) override;
+ void OnOverscrollComplete(OverscrollMode overscroll_mode) override;
+ void OnOverscrollModeChange(OverscrollMode old_mode,
+ OverscrollMode new_mode) override;
// Overridden from ui::ImplicitAnimationObserver:
- virtual void OnImplicitAnimationsCompleted() OVERRIDE;
+ void OnImplicitAnimationsCompleted() override;
// Overridden from aura::WindowDelegate:
- virtual gfx::Size GetMinimumSize() const OVERRIDE;
- virtual gfx::Size GetMaximumSize() const OVERRIDE;
- virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) OVERRIDE;
- virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE;
- virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE;
- virtual bool ShouldDescendIntoChildForEventHandling(
+ gfx::Size GetMinimumSize() const override;
+ gfx::Size GetMaximumSize() const override;
+ void OnBoundsChanged(const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) override;
+ gfx::NativeCursor GetCursor(const gfx::Point& point) override;
+ int GetNonClientComponent(const gfx::Point& point) const override;
+ bool ShouldDescendIntoChildForEventHandling(
aura::Window* child,
- const gfx::Point& location) OVERRIDE;
- virtual bool CanFocus() OVERRIDE;
- virtual void OnCaptureLost() OVERRIDE;
- virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
- virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
- virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE;
- virtual bool HasHitTestMask() const OVERRIDE;
- virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE;
+ const gfx::Point& location) override;
+ bool CanFocus() override;
+ void OnCaptureLost() override;
+ void OnPaint(gfx::Canvas* canvas) override;
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override;
+ void OnWindowDestroying(aura::Window* window) override;
+ void OnWindowDestroyed(aura::Window* window) override;
+ void OnWindowTargetVisibilityChanged(bool visible) override;
+ bool HasHitTestMask() const override;
+ void GetHitTestMask(gfx::Path* mask) const override;
// Overridden from ui::EventHandler:
- virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ void OnKeyEvent(ui::KeyEvent* event) override;
+ void OnMouseEvent(ui::MouseEvent* event) override;
// Overridden from aura::client::DragDropDelegate:
- virtual void OnDragEntered(const ui::DropTargetEvent& event) OVERRIDE;
- virtual int OnDragUpdated(const ui::DropTargetEvent& event) OVERRIDE;
- virtual void OnDragExited() OVERRIDE;
- virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
+ void OnDragEntered(const ui::DropTargetEvent& event) override;
+ int OnDragUpdated(const ui::DropTargetEvent& event) override;
+ void OnDragExited() override;
+ int OnPerformDrop(const ui::DropTargetEvent& event) override;
// Overridden from aura::WindowObserver:
- virtual void OnWindowParentChanged(aura::Window* window,
- aura::Window* parent) OVERRIDE;
- virtual void OnWindowVisibilityChanged(aura::Window* window,
- bool visible) OVERRIDE;
+ void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
+
+ // Update the web contents visiblity.
+ void UpdateWebContentsVisibility(bool visible);
+
+#if defined(OS_WIN)
+ // Overridden from LegacyRenderWidgetHostHWNDDelegate:
+ virtual gfx::NativeViewAccessible GetNativeViewAccessible() override;
+#endif
scoped_ptr<aura::Window> window_;
@@ -226,6 +250,18 @@ class WebContentsViewAura
scoped_ptr<TouchEditableImplAura> touch_editable_;
scoped_ptr<GestureNavSimple> gesture_nav_simple_;
+#if defined(OS_WIN)
+ // 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,
+ // etc.
+ scoped_ptr<LegacyRenderWidgetHostHWND> legacy_hwnd_;
+#endif
+
+ // 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 41dab4c5c18..2687376c109 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
@@ -15,10 +15,15 @@
#include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/browser/web_contents/web_contents_view.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/browser_message_filter.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
@@ -27,12 +32,61 @@
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
-#include "ui/aura/test/event_generator.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/event_processor.h"
+#include "ui/events/event_switches.h"
#include "ui/events/event_utils.h"
+#include "ui/events/test/event_generator.h"
+
+namespace {
+
+// TODO(tdresser): Find a way to avoid sleeping like this. See crbug.com/405282
+// for details.
+void GiveItSomeTime() {
+ base::RunLoop run_loop;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ run_loop.QuitClosure(),
+ base::TimeDelta::FromMillisecondsD(10));
+ run_loop.Run();
+}
+
+// WebContentsDelegate which tracks vertical overscroll updates.
+class VerticalOverscrollTracker : public content::WebContentsDelegate {
+ public:
+ VerticalOverscrollTracker() : count_(0), completed_(false) {}
+ ~VerticalOverscrollTracker() override {}
+
+ int num_overscroll_updates() const {
+ return count_;
+ }
+
+ bool overscroll_completed() const {
+ return completed_;
+ }
+
+ void Reset() {
+ count_ = 0;
+ completed_ = false;
+ }
+
+ private:
+ bool CanOverscrollContent() const override { return true; }
+
+ void OverscrollUpdate(float delta_y) override { ++count_; }
+
+ void OverscrollComplete() override { completed_ = true; }
+
+ int count_;
+ bool completed_;
+
+ DISALLOW_COPY_AND_ASSIGN(VerticalOverscrollTracker);
+};
+
+} //namespace
+
namespace content {
@@ -45,8 +99,7 @@ class ScreenshotTracker : public NavigationEntryScreenshotManager {
waiting_for_screenshots_(0) {
}
- virtual ~ScreenshotTracker() {
- }
+ ~ScreenshotTracker() override {}
RenderViewHost* screenshot_taken_for() { return screenshot_taken_for_; }
@@ -72,14 +125,14 @@ class ScreenshotTracker : public NavigationEntryScreenshotManager {
private:
// Overridden from NavigationEntryScreenshotManager:
- virtual void TakeScreenshotImpl(RenderViewHost* host,
- NavigationEntryImpl* entry) OVERRIDE {
+ void TakeScreenshotImpl(RenderViewHost* host,
+ NavigationEntryImpl* entry) override {
++waiting_for_screenshots_;
screenshot_taken_for_ = host;
NavigationEntryScreenshotManager::TakeScreenshotImpl(host, entry);
}
- virtual void OnScreenshotSet(NavigationEntryImpl* entry) OVERRIDE {
+ void OnScreenshotSet(NavigationEntryImpl* entry) override {
--waiting_for_screenshots_;
screenshot_set_[entry] = true;
NavigationEntryScreenshotManager::OnScreenshotSet(entry);
@@ -103,7 +156,7 @@ class NavigationWatcher : public WebContentsObserver {
should_quit_loop_(false) {
}
- virtual ~NavigationWatcher() {}
+ ~NavigationWatcher() override {}
void WaitUntilNavigationStarts() {
if (navigated_)
@@ -114,7 +167,7 @@ class NavigationWatcher : public WebContentsObserver {
private:
// Overridden from WebContentsObserver:
- virtual void AboutToNavigateRenderView(RenderViewHost* host) OVERRIDE {
+ void AboutToNavigateRenderView(RenderViewHost* host) override {
navigated_ = true;
if (should_quit_loop_)
base::MessageLoop::current()->Quit();
@@ -126,6 +179,55 @@ class NavigationWatcher : public WebContentsObserver {
DISALLOW_COPY_AND_ASSIGN(NavigationWatcher);
};
+class InputEventMessageFilterWaitsForAcks : public BrowserMessageFilter {
+ public:
+ InputEventMessageFilterWaitsForAcks()
+ : BrowserMessageFilter(InputMsgStart),
+ type_(blink::WebInputEvent::Undefined),
+ state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {}
+
+ void WaitForAck(blink::WebInputEvent::Type type) {
+ base::RunLoop run_loop;
+ base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure());
+ base::AutoReset<blink::WebInputEvent::Type> reset_type(&type_, type);
+ run_loop.Run();
+ }
+
+ InputEventAckState last_ack_state() const { return state_; }
+
+ protected:
+ ~InputEventMessageFilterWaitsForAcks() override {}
+
+ private:
+ void ReceivedEventAck(blink::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);
+ blink::WebInputEvent::Type type = params.a.type;
+ InputEventAckState ack = params.a.state;
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&InputEventMessageFilterWaitsForAcks::ReceivedEventAck,
+ this, type, ack));
+ }
+ return false;
+ }
+
+ base::Closure quit_;
+ blink::WebInputEvent::Type type_;
+ InputEventAckState state_;
+
+ DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilterWaitsForAcks);
+};
+
class WebContentsViewAuraTest : public ContentBrowserTest {
public:
WebContentsViewAuraTest()
@@ -155,6 +257,11 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
controller->SetScreenshotManager(screenshot_manager_);
}
+ void SetUpCommandLine(CommandLine* cmd) override {
+ cmd->AppendSwitchASCII(switches::kTouchEvents,
+ switches::kTouchEventsEnabled);
+ }
+
void TestOverscrollNavigation(bool touch_handler) {
ASSERT_NO_FATAL_FAILURE(
StartTestWithPage("files/overscroll_navigation.html"));
@@ -184,7 +291,7 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
aura::Window* content = web_contents->GetContentNativeView();
gfx::Rect bounds = content->GetBoundsInRootWindow();
- aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ ui::test::EventGenerator generator(content->GetRootWindow(), content);
const int kScrollDurationMs = 20;
const int kScrollSteps = 10;
@@ -255,21 +362,74 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
return index;
}
+ int ExecuteScriptAndExtractInt(const std::string& script) {
+ int value = 0;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
+ shell()->web_contents(),
+ "domAutomationController.send(" + script + ")",
+ &value));
+ return value;
+ }
+
+ RenderViewHost* GetRenderViewHost() const {
+ RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
+ CHECK(rvh);
+ return rvh;
+ }
+
+ RenderWidgetHostImpl* GetRenderWidgetHost() const {
+ RenderWidgetHostImpl* const rwh =
+ RenderWidgetHostImpl::From(shell()
+ ->web_contents()
+ ->GetRenderWidgetHostView()
+ ->GetRenderWidgetHost());
+ CHECK(rwh);
+ return rwh;
+ }
+
+ RenderWidgetHostViewBase* GetRenderWidgetHostView() const {
+ return static_cast<RenderWidgetHostViewBase*>(
+ GetRenderViewHost()->GetView());
+ }
+
+ InputEventMessageFilterWaitsForAcks* filter() {
+ return filter_.get();
+ }
+
+ void WaitAFrame() {
+ uint32 frame = GetRenderWidgetHostView()->RendererFrameNumber();
+ while (!GetRenderWidgetHost()->ScheduleComposite())
+ GiveItSomeTime();
+ while (GetRenderWidgetHostView()->RendererFrameNumber() == frame)
+ GiveItSomeTime();
+ }
+
protected:
ScreenshotTracker* screenshot_manager() { return screenshot_manager_; }
void set_min_screenshot_interval(int interval_ms) {
screenshot_manager_->SetScreenshotInterval(interval_ms);
}
+ void AddInputEventMessageFilter() {
+ filter_ = new InputEventMessageFilterWaitsForAcks();
+ GetRenderWidgetHost()->GetProcess()->AddFilter(filter_.get());
+ }
+
private:
ScreenshotTracker* screenshot_manager_;
+ scoped_refptr<InputEventMessageFilterWaitsForAcks> filter_;
DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest);
};
-// Flaky on Windows and ChromeOS: http://crbug.com/305722
-IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
- DISABLED_OverscrollNavigation) {
+// Flaky on Windows: http://crbug.com/305722
+#if defined(OS_WIN)
+#define MAYBE_OverscrollNavigation DISABLED_OverscrollNavigation
+#else
+#define MAYBE_OverscrollNavigation OverscrollNavigation
+#endif
+
+IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollNavigation) {
TestOverscrollNavigation(false);
}
@@ -377,9 +537,16 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
// - interactively, when user does an overscroll gesture
// - interactively, when user navigates in history without the overscroll
// gesture.
-// Flaky on Windows and ChromeOS (http://crbug.com/357311). Might be related to
+// Flaky on Windows (http://crbug.com/357311). Might be related to
// OverscrollNavigation test.
-IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, DISABLED_OverscrollScreenshot) {
+// Flaky on Ozone (http://crbug.com/399676).
+// Flaky on ChromeOS (http://crbug.com/405945).
+#if defined(OS_WIN) || defined(USE_OZONE) || defined(OS_CHROMEOS)
+#define MAYBE_OverscrollScreenshot DISABLED_OverscrollScreenshot
+#else
+#define MAYBE_OverscrollScreenshot OverscrollScreenshot
+#endif
+IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) {
// Disable the test for WinXP. See http://crbug/294116.
#if defined(OS_WIN)
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
@@ -434,7 +601,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, DISABLED_OverscrollScreenshot) {
content::TitleWatcher title_watcher(web_contents, expected_title);
aura::Window* content = web_contents->GetContentNativeView();
gfx::Rect bounds = content->GetBoundsInRootWindow();
- aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ ui::test::EventGenerator generator(content->GetRootWindow(), content);
generator.GestureScrollSequence(
gfx::Point(bounds.x() + 2, bounds.y() + 10),
gfx::Point(bounds.right() - 10, bounds.y() + 10),
@@ -504,11 +671,11 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
int transition;
} navigations[] = {
{ https_server.GetURL("files/title1.html"),
- PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR },
+ ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR },
{ test_server()->GetURL("files/title2.html"),
- PAGE_TRANSITION_AUTO_BOOKMARK },
+ ui::PAGE_TRANSITION_AUTO_BOOKMARK },
{ https_server.GetURL("files/title3.html"),
- PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR },
+ ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR },
{ GURL(), 0 }
};
@@ -516,7 +683,8 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
for (int i = 0; !navigations[i].url.is_empty(); ++i) {
// Navigate via the user initiating a navigation from the UI.
NavigationController::LoadURLParams params(navigations[i].url);
- params.transition_type = PageTransitionFromInt(navigations[i].transition);
+ params.transition_type =
+ ui::PageTransitionFromInt(navigations[i].transition);
RenderViewHost* old_host = web_contents->GetRenderViewHost();
web_contents->GetController().LoadURLWithParams(params);
@@ -544,7 +712,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
// Navigate again. This should not take any screenshot because of the
// increased screenshot interval.
NavigationController::LoadURLParams params(navigations[0].url);
- params.transition_type = PageTransitionFromInt(navigations[0].transition);
+ params.transition_type = ui::PageTransitionFromInt(navigations[0].transition);
web_contents->GetController().LoadURLWithParams(params);
WaitForLoadStop(web_contents);
screenshot_manager()->WaitUntilScreenshotIsReady();
@@ -607,7 +775,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
aura::Window* content = web_contents->GetContentNativeView();
gfx::Rect bounds = content->GetBoundsInRootWindow();
- aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ ui::test::EventGenerator generator(content->GetRootWindow(), content);
generator.GestureScrollSequence(
gfx::Point(bounds.x() + 2, bounds.y() + 10),
gfx::Point(bounds.right() - 10, bounds.y() + 10),
@@ -628,7 +796,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ContentWindowClose) {
aura::Window* content = web_contents->GetContentNativeView();
gfx::Rect bounds = content->GetBoundsInRootWindow();
- aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ ui::test::EventGenerator generator(content->GetRootWindow(), content);
generator.GestureScrollSequence(
gfx::Point(bounds.x() + 2, bounds.y() + 10),
gfx::Point(bounds.right() - 10, bounds.y() + 10),
@@ -676,7 +844,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
aura::Window* content = web_contents->GetContentNativeView();
gfx::Rect bounds = content->GetBoundsInRootWindow();
- aura::test::EventGenerator generator(content->GetRootWindow(), content);
+ ui::test::EventGenerator generator(content->GetRootWindow(), content);
// Do a swipe left to start a forward navigation. Then quickly do a swipe
// right.
@@ -717,4 +885,266 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, HideContentOnParenHide) {
EXPECT_TRUE(web_contents->should_normally_be_visible());
}
+// Ensure that SnapToPhysicalPixelBoundary() is called on WebContentsView parent
+// change. This is a regression test for http://crbug.com/388908.
+IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, WebContentsViewReparent) {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestWithPage("files/overscroll_navigation.html"));
+
+ scoped_ptr<aura::Window> window(new aura::Window(NULL));
+ window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
+
+ RenderWidgetHostViewAura* rwhva =
+ static_cast<RenderWidgetHostViewAura*>(
+ shell()->web_contents()->GetRenderWidgetHostView());
+ rwhva->ResetHasSnappedToBoundary();
+ EXPECT_FALSE(rwhva->has_snapped_to_boundary());
+ window->AddChild(shell()->web_contents()->GetNativeView());
+ EXPECT_TRUE(rwhva->has_snapped_to_boundary());
+}
+
+// Flaky on some platforms, likely for the same reason as other flaky overscroll
+// tests. http://crbug.com/305722
+// TODO(tdresser): Re-enable this once eager GR is back on. See
+// crbug.com/410280.
+#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#define MAYBE_OverscrollNavigationTouchThrottling \
+ DISABLED_OverscrollNavigationTouchThrottling
+#else
+#define MAYBE_OverscrollNavigationTouchThrottling \
+ DISABLED_OverscrollNavigationTouchThrottling
+#endif
+
+// Tests that touch moves are not throttled when performing a scroll gesture on
+// a non-scrollable area, except during gesture-nav.
+IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
+ MAYBE_OverscrollNavigationTouchThrottling) {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestWithPage("files/overscroll_navigation.html"));
+
+ AddInputEventMessageFilter();
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ aura::Window* content = web_contents->GetContentNativeView();
+ gfx::Rect bounds = content->GetBoundsInRootWindow();
+ const int dx = 20;
+
+ ExecuteSyncJSFunction(web_contents->GetMainFrame(),
+ "install_touchmove_handler()");
+
+ WaitAFrame();
+
+ for (int navigated = 0; navigated <= 1; ++navigated) {
+ if (navigated) {
+ ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
+ ExecuteSyncJSFunction(web_contents->GetMainFrame(),
+ "reset_touchmove_count()");
+ }
+ // Send touch press.
+ SyntheticWebTouchEvent touch;
+ touch.PressPoint(bounds.x() + 2, bounds.y() + 10);
+ GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch,
+ ui::LatencyInfo());
+ filter()->WaitForAck(blink::WebInputEvent::TouchStart);
+ WaitAFrame();
+
+ // Assert on the ack, because we'll end up waiting for acks that will never
+ // come if this is not true.
+ ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
+
+ // Send first touch move, and then a scroll begin.
+ touch.MovePoint(0, bounds.x() + 20 + 1 * dx, bounds.y() + 100);
+ GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch,
+ ui::LatencyInfo());
+ filter()->WaitForAck(blink::WebInputEvent::TouchMove);
+ ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
+
+ blink::WebGestureEvent scroll_begin =
+ SyntheticWebGestureEventBuilder::BuildScrollBegin(1, 1);
+ GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
+ scroll_begin, ui::LatencyInfo());
+ // Scroll begin ignores ack disposition, so don't wait for the ack.
+ WaitAFrame();
+
+ // First touchmove already sent, start at 2.
+ for (int i = 2; i <= 10; ++i) {
+ // Send a touch move, followed by a scroll update
+ touch.MovePoint(0, bounds.x() + 20 + i * dx, bounds.y() + 100);
+ GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(
+ touch, ui::LatencyInfo());
+ WaitAFrame();
+
+ blink::WebGestureEvent scroll_update =
+ SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, 5, 0);
+
+ GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
+ scroll_update, ui::LatencyInfo());
+
+ WaitAFrame();
+ }
+
+ touch.ReleasePoint(0);
+ GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch,
+ ui::LatencyInfo());
+ WaitAFrame();
+
+ blink::WebGestureEvent scroll_end;
+ scroll_end.type = blink::WebInputEvent::GestureScrollEnd;
+ GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
+ scroll_end, ui::LatencyInfo());
+ WaitAFrame();
+
+ if (!navigated)
+ EXPECT_EQ(10, ExecuteScriptAndExtractInt("touchmoveCount"));
+ else
+ EXPECT_GT(10, ExecuteScriptAndExtractInt("touchmoveCount"));
+ }
+}
+
+// Test that vertical overscroll updates are sent only when a user overscrolls
+// vertically.
+#if defined(OS_WIN)
+#define MAYBE_VerticalOverscroll DISABLED_VerticalOverscroll
+#else
+#define MAYBE_VerticalOverscroll VerticalOverscroll
+#endif
+
+IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_VerticalOverscroll) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kScrollEndEffect, "1");
+
+ ASSERT_NO_FATAL_FAILURE(StartTestWithPage("about:blank"));
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ VerticalOverscrollTracker tracker;
+ web_contents->SetDelegate(&tracker);
+
+ // This test triggers a large number of animations. Speed them up to ensure
+ // the test completes within its time limit.
+ ui::ScopedAnimationDurationScaleMode fast_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
+
+ aura::Window* content = web_contents->GetContentNativeView();
+ ui::EventProcessor* dispatcher = content->GetHost()->event_processor();
+ gfx::Rect bounds = content->GetBoundsInRootWindow();
+
+ // Overscroll horizontally.
+ {
+ int kXStep = bounds.width() / 10;
+ gfx::Point location(bounds.right() - kXStep, bounds.y() + 5);
+ base::TimeDelta timestamp = ui::EventTimeForNow();
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED,
+ location,
+ 0,
+ timestamp);
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+ location -= gfx::Vector2d(kXStep, 0);
+ timestamp += base::TimeDelta::FromMilliseconds(10);
+
+ while (location.x() > bounds.x() + kXStep) {
+ ui::TouchEvent inc(ui::ET_TOUCH_MOVED, location, 0, timestamp);
+ details = dispatcher->OnEventFromSource(&inc);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+ location -= gfx::Vector2d(10, 0);
+ timestamp += base::TimeDelta::FromMilliseconds(10);
+ }
+
+ ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
+ details = dispatcher->OnEventFromSource(&press);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+
+ EXPECT_EQ(0, tracker.num_overscroll_updates());
+ EXPECT_FALSE(tracker.overscroll_completed());
+ }
+
+ // Overscroll vertically.
+ {
+ tracker.Reset();
+
+ int kYStep = bounds.height() / 10;
+ gfx::Point location(bounds.x() + 10, bounds.y() + kYStep);
+ base::TimeDelta timestamp = ui::EventTimeForNow();
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED,
+ location,
+ 0,
+ timestamp);
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+ location += gfx::Vector2d(0, kYStep);
+ timestamp += base::TimeDelta::FromMilliseconds(10);
+
+ while (location.y() < bounds.bottom() - kYStep) {
+ ui::TouchEvent inc(ui::ET_TOUCH_MOVED, location, 0, timestamp);
+ details = dispatcher->OnEventFromSource(&inc);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+ location += gfx::Vector2d(0, kYStep);
+ timestamp += base::TimeDelta::FromMilliseconds(10);
+ }
+
+ ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
+ details = dispatcher->OnEventFromSource(&release);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+
+ EXPECT_LT(0, tracker.num_overscroll_updates());
+ EXPECT_TRUE(tracker.overscroll_completed());
+ }
+
+ // Start out overscrolling vertically, then switch directions and finish
+ // overscrolling horizontally.
+ {
+ tracker.Reset();
+
+ int kXStep = bounds.width() / 10;
+ int kYStep = bounds.height() / 10;
+ gfx::Point location = bounds.origin() + gfx::Vector2d(0, kYStep);
+ base::TimeDelta timestamp = ui::EventTimeForNow();
+ ui::TouchEvent press(
+ ui::ET_TOUCH_PRESSED,
+ location,
+ 0,
+ timestamp);
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+ location += gfx::Vector2d(0, kYStep);
+ timestamp += base::TimeDelta::FromMilliseconds(10);
+
+ for (size_t i = 0; i < 3; ++i) {
+ ui::TouchEvent inc(ui::ET_TOUCH_MOVED, location, 0, timestamp);
+ details = dispatcher->OnEventFromSource(&inc);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+ location += gfx::Vector2d(0, kYStep);
+ timestamp += base::TimeDelta::FromMilliseconds(10);
+ }
+
+ while (location.x() < bounds.right() - kXStep) {
+ ui::TouchEvent inc(ui::ET_TOUCH_MOVED, location, 0, timestamp);
+ details = dispatcher->OnEventFromSource(&inc);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+ location += gfx::Vector2d(kXStep, 0);
+ timestamp += base::TimeDelta::FromMilliseconds(10);
+ }
+
+ ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
+ details = dispatcher->OnEventFromSource(&release);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ WaitAFrame();
+
+ EXPECT_LT(0, tracker.num_overscroll_updates());
+ EXPECT_FALSE(tracker.overscroll_completed());
+ }
+}
+
} // namespace content
diff --git a/chromium/content/browser/web_contents/web_contents_view_guest.cc b/chromium/content/browser/web_contents/web_contents_view_guest.cc
index 14f460077b8..6cc1581e6a3 100644
--- a/chromium/content/browser/web_contents/web_contents_view_guest.cc
+++ b/chromium/content/browser/web_contents/web_contents_view_guest.cc
@@ -60,7 +60,7 @@ gfx::NativeWindow WebContentsViewGuest::GetTopLevelNativeWindow() const {
return guest_->embedder_web_contents()->GetTopLevelNativeWindow();
}
-void WebContentsViewGuest::OnGuestInitialized(WebContentsView* parent_view) {
+void WebContentsViewGuest::OnGuestAttached(WebContentsView* parent_view) {
#if defined(USE_AURA)
// In aura, ScreenPositionClient doesn't work properly if we do
// not have the native view associated with this WebContentsViewGuest in the
@@ -71,14 +71,17 @@ void WebContentsViewGuest::OnGuestInitialized(WebContentsView* parent_view) {
#endif // defined(USE_AURA)
}
+void WebContentsViewGuest::OnGuestDetached(WebContentsView* old_parent_view) {
+#if defined(USE_AURA)
+ old_parent_view->GetNativeView()->RemoveChild(
+ platform_view_->GetNativeView());
+#endif // defined(USE_AURA)
+}
+
ContextMenuParams WebContentsViewGuest::ConvertContextMenuParams(
const ContextMenuParams& params) const {
-#if defined(USE_AURA)
- // Context menu uses ScreenPositionClient::ConvertPointToScreen() in aura
- // to calculate popup position. Guest's native view
- // (platform_view_->GetNativeView()) is part of the embedder's view hierarchy,
- // but is placed at (0, 0) w.r.t. the embedder's position. Therefore, |offset|
- // is added to |params|.
+ // We need to add |offset| of the guest from the embedder to position the
+ // menu properly.
gfx::Rect embedder_bounds;
guest_->embedder_web_contents()->GetView()->GetContainerBounds(
&embedder_bounds);
@@ -90,16 +93,18 @@ ContextMenuParams WebContentsViewGuest::ConvertContextMenuParams(
params_in_embedder.x += offset.x();
params_in_embedder.y += offset.y();
return params_in_embedder;
-#else
- return params;
-#endif
}
void WebContentsViewGuest::GetContainerBounds(gfx::Rect* out) const {
- // We need embedder container's bounds to calculate our bounds.
- guest_->embedder_web_contents()->GetView()->GetContainerBounds(out);
- gfx::Point guest_coordinates = guest_->GetScreenCoordinates(gfx::Point());
- out->Offset(guest_coordinates.x(), guest_coordinates.y());
+ if (guest_->embedder_web_contents()) {
+ // We need embedder container's bounds to calculate our bounds.
+ guest_->embedder_web_contents()->GetView()->GetContainerBounds(out);
+ gfx::Point guest_coordinates = guest_->GetScreenCoordinates(gfx::Point());
+ out->Offset(guest_coordinates.x(), guest_coordinates.y());
+ } else {
+ out->set_origin(gfx::Point());
+ }
+
out->set_size(size_);
}
@@ -119,21 +124,12 @@ gfx::Rect WebContentsViewGuest::GetViewBounds() const {
}
#if defined(OS_MACOSX)
-void WebContentsViewGuest::SetAllowOverlappingViews(bool overlapping) {
- platform_view_->SetAllowOverlappingViews(overlapping);
-}
-
-bool WebContentsViewGuest::GetAllowOverlappingViews() const {
- return platform_view_->GetAllowOverlappingViews();
+void WebContentsViewGuest::SetAllowOtherViews(bool allow) {
+ platform_view_->SetAllowOtherViews(allow);
}
-void WebContentsViewGuest::SetOverlayView(
- WebContentsView* overlay, const gfx::Point& offset) {
- platform_view_->SetOverlayView(overlay, offset);
-}
-
-void WebContentsViewGuest::RemoveOverlayView() {
- platform_view_->RemoveOverlayView();
+bool WebContentsViewGuest::GetAllowOtherViews() const {
+ return platform_view_->GetAllowOtherViews();
}
#endif
@@ -144,7 +140,7 @@ void WebContentsViewGuest::CreateView(const gfx::Size& initial_size,
}
RenderWidgetHostViewBase* WebContentsViewGuest::CreateViewForWidget(
- RenderWidgetHost* render_widget_host) {
+ RenderWidgetHost* render_widget_host, bool is_guest_view_hack) {
if (render_widget_host->GetView()) {
// During testing, the view will already be set up in most cases to the
// test view, so we don't want to clobber it with a real one. To verify that
@@ -157,14 +153,11 @@ RenderWidgetHostViewBase* WebContentsViewGuest::CreateViewForWidget(
}
RenderWidgetHostViewBase* platform_widget =
- platform_view_->CreateViewForWidget(render_widget_host);
-
- RenderWidgetHostViewBase* view = new RenderWidgetHostViewGuest(
- render_widget_host,
- guest_,
- platform_widget);
+ platform_view_->CreateViewForWidget(render_widget_host, true);
- return view;
+ return new RenderWidgetHostViewGuest(render_widget_host,
+ guest_,
+ platform_widget->GetWeakPtr());
}
RenderWidgetHostViewBase* WebContentsViewGuest::CreateViewForPopupWidget(
diff --git a/chromium/content/browser/web_contents/web_contents_view_guest.h b/chromium/content/browser/web_contents/web_contents_view_guest.h
index 53edd64e47f..e21f19a6956 100644
--- a/chromium/content/browser/web_contents/web_contents_view_guest.h
+++ b/chromium/content/browser/web_contents/web_contents_view_guest.h
@@ -31,11 +31,13 @@ class WebContentsViewGuest : public WebContentsView,
BrowserPluginGuest* guest,
scoped_ptr<WebContentsView> platform_view,
RenderViewHostDelegateView* platform_view_delegate_view);
- virtual ~WebContentsViewGuest();
+ ~WebContentsViewGuest() override;
WebContents* web_contents();
- void OnGuestInitialized(WebContentsView* parent_view);
+ void OnGuestAttached(WebContentsView* parent_view);
+
+ void OnGuestDetached(WebContentsView* old_parent_view);
// Converts the guest specific coordinates in |params| to embedder specific
// ones.
@@ -43,48 +45,46 @@ class WebContentsViewGuest : public WebContentsView,
const ContextMenuParams& params) const;
// WebContentsView implementation --------------------------------------------
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeView GetContentNativeView() const OVERRIDE;
- virtual gfx::NativeWindow GetTopLevelNativeWindow() const OVERRIDE;
- virtual void GetContainerBounds(gfx::Rect* out) const OVERRIDE;
- virtual void SizeContents(const gfx::Size& size) OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void SetInitialFocus() OVERRIDE;
- virtual void StoreFocus() OVERRIDE;
- virtual void RestoreFocus() OVERRIDE;
- virtual DropData* GetDropData() const OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
- virtual void CreateView(const gfx::Size& initial_size,
- gfx::NativeView context) OVERRIDE;
- virtual RenderWidgetHostViewBase* CreateViewForWidget(
- RenderWidgetHost* render_widget_host) OVERRIDE;
- virtual RenderWidgetHostViewBase* CreateViewForPopupWidget(
- RenderWidgetHost* render_widget_host) OVERRIDE;
- virtual void SetPageTitle(const base::string16& title) OVERRIDE;
- virtual void RenderViewCreated(RenderViewHost* host) OVERRIDE;
- virtual void RenderViewSwappedIn(RenderViewHost* host) OVERRIDE;
- virtual void SetOverscrollControllerEnabled(bool enabled) OVERRIDE;
+ gfx::NativeView GetNativeView() const override;
+ gfx::NativeView GetContentNativeView() const override;
+ gfx::NativeWindow GetTopLevelNativeWindow() const override;
+ void GetContainerBounds(gfx::Rect* out) const override;
+ void SizeContents(const gfx::Size& size) override;
+ void Focus() override;
+ void SetInitialFocus() override;
+ void StoreFocus() override;
+ void RestoreFocus() override;
+ DropData* GetDropData() const override;
+ gfx::Rect GetViewBounds() const override;
+ void CreateView(const gfx::Size& initial_size,
+ gfx::NativeView context) override;
+ RenderWidgetHostViewBase* CreateViewForWidget(
+ RenderWidgetHost* render_widget_host,
+ bool is_guest_view_hack) override;
+ RenderWidgetHostViewBase* CreateViewForPopupWidget(
+ RenderWidgetHost* render_widget_host) override;
+ void SetPageTitle(const base::string16& title) override;
+ void RenderViewCreated(RenderViewHost* host) override;
+ void RenderViewSwappedIn(RenderViewHost* host) override;
+ void SetOverscrollControllerEnabled(bool enabled) override;
#if defined(OS_MACOSX)
- virtual void SetAllowOverlappingViews(bool overlapping) OVERRIDE;
- virtual bool GetAllowOverlappingViews() const OVERRIDE;
- virtual void SetOverlayView(WebContentsView* overlay,
- const gfx::Point& offset) OVERRIDE;
- virtual void RemoveOverlayView() OVERRIDE;
- virtual bool IsEventTracking() const OVERRIDE;
- virtual void CloseTabAfterEventTracking() OVERRIDE;
+ void SetAllowOtherViews(bool allow) override;
+ bool GetAllowOtherViews() const override;
+ bool IsEventTracking() const override;
+ void CloseTabAfterEventTracking() override;
#endif
// Backend implementation of RenderViewHostDelegateView.
- virtual void ShowContextMenu(RenderFrameHost* render_frame_host,
- const ContextMenuParams& params) OVERRIDE;
- virtual void StartDragging(const DropData& drop_data,
- blink::WebDragOperationsMask allowed_ops,
- const gfx::ImageSkia& image,
- const gfx::Vector2d& image_offset,
- const DragEventSourceInfo& event_info) OVERRIDE;
- virtual void UpdateDragCursor(blink::WebDragOperation operation) OVERRIDE;
- virtual void GotFocus() OVERRIDE;
- virtual void TakeFocus(bool reverse) OVERRIDE;
+ void ShowContextMenu(RenderFrameHost* render_frame_host,
+ const ContextMenuParams& params) override;
+ void StartDragging(const DropData& drop_data,
+ blink::WebDragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const DragEventSourceInfo& event_info) override;
+ void UpdateDragCursor(blink::WebDragOperation operation) override;
+ void GotFocus() override;
+ void TakeFocus(bool reverse) override;
private:
// The WebContentsImpl whose contents we display.
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 c6bc9dac7b8..93c1eaff906 100644
--- a/chromium/content/browser/web_contents/web_contents_view_mac.h
+++ b/chromium/content/browser/web_contents/web_contents_view_mac.h
@@ -63,57 +63,56 @@ class WebContentsViewMac : public WebContentsView,
// because that's what was easiest when they were split.
WebContentsViewMac(WebContentsImpl* web_contents,
WebContentsViewDelegate* delegate);
- virtual ~WebContentsViewMac();
+ ~WebContentsViewMac() override;
// WebContentsView implementation --------------------------------------------
- virtual gfx::NativeView GetNativeView() const OVERRIDE;
- virtual gfx::NativeView GetContentNativeView() const OVERRIDE;
- virtual gfx::NativeWindow GetTopLevelNativeWindow() const OVERRIDE;
- virtual void GetContainerBounds(gfx::Rect* out) const OVERRIDE;
- virtual void SizeContents(const gfx::Size& size) OVERRIDE;
- virtual void Focus() OVERRIDE;
- virtual void SetInitialFocus() OVERRIDE;
- virtual void StoreFocus() OVERRIDE;
- virtual void RestoreFocus() OVERRIDE;
- virtual DropData* GetDropData() const OVERRIDE;
- virtual gfx::Rect GetViewBounds() const OVERRIDE;
- virtual void SetAllowOverlappingViews(bool overlapping) OVERRIDE;
- virtual bool GetAllowOverlappingViews() const OVERRIDE;
- virtual void SetOverlayView(WebContentsView* overlay,
- const gfx::Point& offset) OVERRIDE;
- virtual void RemoveOverlayView() OVERRIDE;
- virtual void CreateView(
- const gfx::Size& initial_size, gfx::NativeView context) OVERRIDE;
- virtual RenderWidgetHostViewBase* CreateViewForWidget(
- RenderWidgetHost* render_widget_host) OVERRIDE;
- virtual RenderWidgetHostViewBase* CreateViewForPopupWidget(
- RenderWidgetHost* render_widget_host) OVERRIDE;
- virtual void SetPageTitle(const base::string16& title) OVERRIDE;
- virtual void RenderViewCreated(RenderViewHost* host) OVERRIDE;
- virtual void RenderViewSwappedIn(RenderViewHost* host) OVERRIDE;
- virtual void SetOverscrollControllerEnabled(bool enabled) OVERRIDE;
- virtual bool IsEventTracking() const OVERRIDE;
- virtual void CloseTabAfterEventTracking() OVERRIDE;
+ gfx::NativeView GetNativeView() const override;
+ gfx::NativeView GetContentNativeView() const override;
+ gfx::NativeWindow GetTopLevelNativeWindow() const override;
+ void GetContainerBounds(gfx::Rect* out) const override;
+ void SizeContents(const gfx::Size& size) override;
+ void Focus() override;
+ void SetInitialFocus() override;
+ void StoreFocus() override;
+ void RestoreFocus() override;
+ DropData* GetDropData() const override;
+ gfx::Rect GetViewBounds() const override;
+ void SetAllowOtherViews(bool allow) override;
+ bool GetAllowOtherViews() const override;
+ void CreateView(const gfx::Size& initial_size,
+ gfx::NativeView context) override;
+ RenderWidgetHostViewBase* CreateViewForWidget(
+ RenderWidgetHost* render_widget_host,
+ bool is_guest_view_hack) override;
+ RenderWidgetHostViewBase* CreateViewForPopupWidget(
+ RenderWidgetHost* render_widget_host) override;
+ void SetPageTitle(const base::string16& title) override;
+ void RenderViewCreated(RenderViewHost* host) override;
+ void RenderViewSwappedIn(RenderViewHost* host) override;
+ void SetOverscrollControllerEnabled(bool enabled) override;
+ bool IsEventTracking() const override;
+ void CloseTabAfterEventTracking() override;
// Backend implementation of RenderViewHostDelegateView.
- virtual void ShowContextMenu(content::RenderFrameHost* render_frame_host,
- const ContextMenuParams& params) OVERRIDE;
- virtual void ShowPopupMenu(const gfx::Rect& bounds,
- int item_height,
- double item_font_size,
- int selected_item,
- const std::vector<MenuItem>& items,
- bool right_aligned,
- bool allow_multiple_selection) OVERRIDE;
- virtual void HidePopupMenu() OVERRIDE;
- virtual void StartDragging(const DropData& drop_data,
- blink::WebDragOperationsMask allowed_operations,
- const gfx::ImageSkia& image,
- const gfx::Vector2d& image_offset,
- const DragEventSourceInfo& event_info) OVERRIDE;
- virtual void UpdateDragCursor(blink::WebDragOperation operation) OVERRIDE;
- virtual void GotFocus() OVERRIDE;
- virtual void TakeFocus(bool reverse) OVERRIDE;
+ void ShowContextMenu(RenderFrameHost* render_frame_host,
+ const ContextMenuParams& params) override;
+ void ShowPopupMenu(RenderFrameHost* render_frame_host,
+ const gfx::Rect& bounds,
+ int item_height,
+ double item_font_size,
+ int selected_item,
+ const std::vector<MenuItem>& items,
+ bool right_aligned,
+ bool allow_multiple_selection) override;
+ void HidePopupMenu() override;
+ void StartDragging(const DropData& drop_data,
+ blink::WebDragOperationsMask allowed_operations,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const DragEventSourceInfo& event_info) override;
+ void UpdateDragCursor(blink::WebDragOperation operation) override;
+ void GotFocus() override;
+ void TakeFocus(bool reverse) override;
// A helper method for closing the tab in the
// CloseTabAfterEventTracking() implementation.
@@ -123,8 +122,10 @@ class WebContentsViewMac : public WebContentsView,
WebContentsViewDelegate* delegate() { return delegate_.get(); }
private:
- // Updates overlay view on current RenderWidgetHostView.
- void UpdateRenderWidgetHostViewOverlay();
+ // Returns the fullscreen view, if one exists; otherwise, returns the content
+ // native view. This ensures that the view currently attached to a NSWindow is
+ // being used to query or set first responder state.
+ gfx::NativeView GetNativeViewForFocus() const;
// The WebContentsImpl whose contents we display.
WebContentsImpl* web_contents_;
@@ -139,19 +140,8 @@ class WebContentsViewMac : public WebContentsView,
// Our optional delegate.
scoped_ptr<WebContentsViewDelegate> delegate_;
- // Whether to allow overlapping views.
- bool allow_overlapping_views_;
-
- // The overlay view which is rendered above this one.
- // Overlay view has |underlay_view_| set to this view.
- WebContentsViewMac* overlay_view_;
-
- // The offset of overlay view relative to this view.
- gfx::Point overlay_view_offset_;
-
- // The underlay view which this view is rendered above.
- // Underlay view has |overlay_view_| set to this view.
- WebContentsViewMac* underlay_view_;
+ // Whether to allow other views.
+ bool allow_other_views_;
scoped_ptr<PopupMenuHelper> popup_menu_helper_;
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 39e579baec2..3c99ac330cc 100644
--- a/chromium/content/browser/web_contents/web_contents_view_mac.mm
+++ b/chromium/content/browser/web_contents/web_contents_view_mac.mm
@@ -8,10 +8,12 @@
#include <string>
+#import "base/mac/mac_util.h"
#import "base/mac/scoped_sending_event.h"
+#include "base/mac/sdk_forward_declarations.h"
#include "base/message_loop/message_loop.h"
#import "base/message_loop/message_pump_mac.h"
-#include "content/browser/renderer_host/popup_menu_helper_mac.h"
+#include "content/browser/frame_host/popup_menu_helper_mac.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
@@ -68,6 +70,7 @@ COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
@end
namespace content {
+
WebContentsView* CreateWebContentsView(
WebContentsImpl* web_contents,
WebContentsViewDelegate* delegate,
@@ -81,9 +84,7 @@ WebContentsViewMac::WebContentsViewMac(WebContentsImpl* web_contents,
WebContentsViewDelegate* delegate)
: web_contents_(web_contents),
delegate_(delegate),
- allow_overlapping_views_(false),
- overlay_view_(NULL),
- underlay_view_(NULL) {
+ allow_other_views_(false) {
}
WebContentsViewMac::~WebContentsViewMac() {
@@ -159,9 +160,18 @@ void WebContentsViewMac::SizeContents(const gfx::Size& size) {
// previous implementation.
}
+gfx::NativeView WebContentsViewMac::GetNativeViewForFocus() const {
+ RenderWidgetHostView* rwhv =
+ web_contents_->GetFullscreenRenderWidgetHostView();
+ if (!rwhv)
+ rwhv = web_contents_->GetRenderWidgetHostView();
+ return rwhv ? rwhv->GetNativeView() : nil;
+}
+
void WebContentsViewMac::Focus() {
- NSWindow* window = [cocoa_view_.get() window];
- [window makeFirstResponder:GetContentNativeView()];
+ gfx::NativeView native_view = GetNativeViewForFocus();
+ NSWindow* window = [native_view window];
+ [window makeFirstResponder:native_view];
if (![window isVisible])
return;
[window makeKeyAndOrderFront:nil];
@@ -171,21 +181,23 @@ void WebContentsViewMac::SetInitialFocus() {
if (web_contents_->FocusLocationBarByDefault())
web_contents_->SetFocusToLocationBar(false);
else
- [[cocoa_view_.get() window] makeFirstResponder:GetContentNativeView()];
+ Focus();
}
void WebContentsViewMac::StoreFocus() {
+ gfx::NativeView native_view = GetNativeViewForFocus();
// We're explicitly being asked to store focus, so don't worry if there's
// already a view saved.
focus_tracker_.reset(
- [[FocusTracker alloc] initWithWindow:[cocoa_view_ window]]);
+ [[FocusTracker alloc] initWithWindow:[native_view window]]);
}
void WebContentsViewMac::RestoreFocus() {
+ gfx::NativeView native_view = GetNativeViewForFocus();
// TODO(avi): Could we be restoring a view that's no longer in the key view
// chain?
if (!(focus_tracker_.get() &&
- [focus_tracker_ restoreFocusInWindow:[cocoa_view_ window]])) {
+ [focus_tracker_ restoreFocusInWindow:[native_view window]])) {
// Fall back to the default focus behavior if we could not restore focus.
// TODO(shess): If location-bar gets focus by default, this will
// select-all in the field. If there was a specific selection in
@@ -221,7 +233,7 @@ void WebContentsViewMac::TakeFocus(bool reverse) {
}
void WebContentsViewMac::ShowContextMenu(
- content::RenderFrameHost* render_frame_host,
+ RenderFrameHost* render_frame_host,
const ContextMenuParams& params) {
// Allow delegates to handle the context menu operation first.
if (web_contents_->GetDelegate() &&
@@ -235,8 +247,8 @@ void WebContentsViewMac::ShowContextMenu(
DLOG(ERROR) << "Cannot show context menus without a delegate.";
}
-// Display a popup menu for WebKit using Cocoa widgets.
void WebContentsViewMac::ShowPopupMenu(
+ RenderFrameHost* render_frame_host,
const gfx::Rect& bounds,
int item_height,
double item_font_size,
@@ -244,8 +256,7 @@ void WebContentsViewMac::ShowPopupMenu(
const std::vector<MenuItem>& items,
bool right_aligned,
bool allow_multiple_selection) {
- popup_menu_helper_.reset(
- new PopupMenuHelper(web_contents_->GetRenderViewHost()));
+ popup_menu_helper_.reset(new PopupMenuHelper(render_frame_host));
popup_menu_helper_->ShowPopupMenu(bounds, item_height, item_font_size,
selected_item, items, right_aligned,
allow_multiple_selection);
@@ -263,67 +274,19 @@ gfx::Rect WebContentsViewMac::GetViewBounds() const {
return gfx::Rect();
}
-void WebContentsViewMac::SetAllowOverlappingViews(bool overlapping) {
- if (allow_overlapping_views_ == overlapping)
+void WebContentsViewMac::SetAllowOtherViews(bool allow) {
+ if (allow_other_views_ == allow)
return;
- allow_overlapping_views_ = overlapping;
+ allow_other_views_ = allow;
RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>(
web_contents_->GetRenderWidgetHostView());
if (view)
- view->SetAllowOverlappingViews(allow_overlapping_views_);
+ view->SetAllowPauseForResizeOrRepaint(!allow_other_views_);
}
-bool WebContentsViewMac::GetAllowOverlappingViews() const {
- return allow_overlapping_views_;
-}
-
-void WebContentsViewMac::SetOverlayView(
- WebContentsView* overlay, const gfx::Point& offset) {
- DCHECK(!underlay_view_);
- if (overlay_view_)
- RemoveOverlayView();
-
- overlay_view_ = static_cast<WebContentsViewMac*>(overlay);
- DCHECK(!overlay_view_->overlay_view_);
- overlay_view_->underlay_view_ = this;
- overlay_view_offset_ = offset;
- UpdateRenderWidgetHostViewOverlay();
-}
-
-void WebContentsViewMac::RemoveOverlayView() {
- DCHECK(overlay_view_);
-
- RenderWidgetHostViewMac* rwhv = static_cast<RenderWidgetHostViewMac*>(
- web_contents_->GetRenderWidgetHostView());
- if (rwhv)
- rwhv->RemoveOverlayView();
-
- overlay_view_->underlay_view_ = NULL;
- overlay_view_ = NULL;
-}
-
-void WebContentsViewMac::UpdateRenderWidgetHostViewOverlay() {
- RenderWidgetHostViewMac* rwhv = static_cast<RenderWidgetHostViewMac*>(
- web_contents_->GetRenderWidgetHostView());
- if (!rwhv)
- return;
-
- if (overlay_view_) {
- RenderWidgetHostViewMac* overlay_rwhv =
- static_cast<RenderWidgetHostViewMac*>(
- overlay_view_->web_contents_->GetRenderWidgetHostView());
- if (overlay_rwhv)
- rwhv->SetOverlayView(overlay_rwhv, overlay_view_offset_);
- }
-
- if (underlay_view_) {
- RenderWidgetHostViewMac* underlay_rwhv =
- static_cast<RenderWidgetHostViewMac*>(
- underlay_view_->web_contents_->GetRenderWidgetHostView());
- if (underlay_rwhv)
- underlay_rwhv->SetOverlayView(rwhv, underlay_view_->overlay_view_offset_);
- }
+bool WebContentsViewMac::GetAllowOtherViews() const {
+ return allow_other_views_;
}
void WebContentsViewMac::CreateView(
@@ -334,7 +297,7 @@ void WebContentsViewMac::CreateView(
}
RenderWidgetHostViewBase* WebContentsViewMac::CreateViewForWidget(
- RenderWidgetHost* render_widget_host) {
+ RenderWidgetHost* render_widget_host, bool is_guest_view_hack) {
if (render_widget_host->GetView()) {
// During testing, the view will already be set up in most cases to the
// test view, so we don't want to clobber it with a real one. To verify that
@@ -347,7 +310,7 @@ RenderWidgetHostViewBase* WebContentsViewMac::CreateViewForWidget(
}
RenderWidgetHostViewMac* view = new RenderWidgetHostViewMac(
- render_widget_host);
+ render_widget_host, is_guest_view_hack);
if (delegate()) {
base::scoped_nsobject<NSObject<RenderWidgetHostViewMacDelegate> >
rw_delegate(
@@ -355,7 +318,7 @@ RenderWidgetHostViewBase* WebContentsViewMac::CreateViewForWidget(
view->SetDelegate(rw_delegate.get());
}
- view->SetAllowOverlappingViews(allow_overlapping_views_);
+ view->SetAllowPauseForResizeOrRepaint(!allow_other_views_);
// Fancy layout comes later; for now just make it our size and resize it
// with us. In case there are other siblings of the content area, we want
@@ -381,7 +344,7 @@ RenderWidgetHostViewBase* WebContentsViewMac::CreateViewForWidget(
RenderWidgetHostViewBase* WebContentsViewMac::CreateViewForPopupWidget(
RenderWidgetHost* render_widget_host) {
- return new RenderWidgetHostViewMac(render_widget_host);
+ return new RenderWidgetHostViewMac(render_widget_host, false);
}
void WebContentsViewMac::SetPageTitle(const base::string16& title) {
@@ -397,7 +360,6 @@ void WebContentsViewMac::RenderViewCreated(RenderViewHost* host) {
}
void WebContentsViewMac::RenderViewSwappedIn(RenderViewHost* host) {
- UpdateRenderWidgetHostViewOverlay();
}
void WebContentsViewMac::SetOverscrollControllerEnabled(bool enabled) {
@@ -634,4 +596,51 @@ void WebContentsViewMac::CloseTab() {
[subview setFrame:self.bounds];
}
+- (void)viewWillMoveToWindow:(NSWindow*)newWindow {
+ NSWindow* oldWindow = [self window];
+
+ NSNotificationCenter* notificationCenter =
+ [NSNotificationCenter defaultCenter];
+
+ // Occlusion notification APIs are new in Mavericks.
+ bool supportsOcclusionAPIs = base::mac::IsOSMavericksOrLater();
+
+ // Use of occlusion APIs is causing bugs:
+ // http://crbug.com/430968: focus set incorrectly.
+ // http://crbug.com/431272: flashes of incorrect content.
+ // http://crbug.com/310374: white flashes (comment 22).
+ supportsOcclusionAPIs = false;
+
+ if (supportsOcclusionAPIs) {
+ if (oldWindow) {
+ [notificationCenter
+ removeObserver:self
+ name:NSWindowDidChangeOcclusionStateNotification
+ object:oldWindow];
+ }
+ if (newWindow) {
+ [notificationCenter
+ addObserver:self
+ selector:@selector(windowChangedOcclusionState:)
+ name:NSWindowDidChangeOcclusionStateNotification
+ object:newWindow];
+ }
+ }
+}
+
+- (void)windowChangedOcclusionState:(NSNotification*)notification {
+ DCHECK(base::mac::IsOSMavericksOrLater());
+ NSWindow* window = [notification object];
+ WebContentsImpl* webContents = [self webContents];
+ if (window && webContents) {
+ if ([window occlusionState] & NSWindowOcclusionStateVisible) {
+ if (!webContents->should_normally_be_visible())
+ webContents->WasShown();
+ } else {
+ if (webContents->should_normally_be_visible())
+ webContents->WasHidden();
+ }
+ }
+}
+
@end
diff --git a/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm b/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm
index 29c84c1cdf5..5d21e7293b1 100644
--- a/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm
+++ b/chromium/content/browser/web_contents/web_contents_view_overscroll_animator_slider_mac.mm
@@ -72,7 +72,7 @@ class WebContentsPaintObserver : public content::WebContentsObserver {
OverscrollAnimatorSliderView* slider_view)
: WebContentsObserver(web_contents), slider_view_(slider_view) {}
- virtual void DidFirstVisuallyNonEmptyPaint() OVERRIDE {
+ virtual void DidFirstVisuallyNonEmptyPaint() override {
[slider_view_ webContentsFinishedNonEmptyPaint];
}
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 b0cb8e2d376..0e57d4fffde 100644
--- a/chromium/content/browser/web_contents/web_drag_dest_mac.mm
+++ b/chromium/content/browser/web_contents/web_drag_dest_mac.mm
@@ -216,7 +216,7 @@ int GetModifierFlags() {
GURL url;
ui::PopulateURLAndTitleFromPasteboard(&url, NULL, pboard, YES);
webContents_->OpenURL(OpenURLParams(
- url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_AUTO_BOOKMARK,
+ url, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_AUTO_BOOKMARK,
false));
return YES;
} else {
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 b0f21609338..f8b639c434f 100644
--- a/chromium/content/browser/web_contents/web_drag_source_mac.mm
+++ b/chromium/content/browser/web_contents/web_drag_source_mac.mm
@@ -24,13 +24,13 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/drop_data.h"
-#include "grit/ui_resources.h"
#include "net/base/escape.h"
#include "net/base/filename_util.h"
#include "net/base/mime_util.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/dragdrop/cocoa_dnd_util.h"
#include "ui/gfx/image/image.h"
+#include "ui/resources/grit/ui_resources.h"
#include "url/url_constants.h"
using base::SysNSStringToUTF8;
diff --git a/chromium/content/browser/webui/content_web_ui_controller_factory.h b/chromium/content/browser/webui/content_web_ui_controller_factory.h
index cee0ec728b0..f2638117720 100644
--- a/chromium/content/browser/webui/content_web_ui_controller_factory.h
+++ b/chromium/content/browser/webui/content_web_ui_controller_factory.h
@@ -14,21 +14,20 @@ namespace content {
class ContentWebUIControllerFactory : public WebUIControllerFactory {
public:
- virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE;
- virtual bool UseWebUIForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE;
- virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE;
- virtual WebUIController* CreateWebUIControllerForURL(
- WebUI* web_ui,
- const GURL& url) const OVERRIDE;
+ WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
+ const GURL& url) const override;
+ bool UseWebUIForURL(BrowserContext* browser_context,
+ const GURL& url) const override;
+ bool UseWebUIBindingsForURL(BrowserContext* browser_context,
+ const GURL& url) const override;
+ WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
+ const GURL& url) const override;
static ContentWebUIControllerFactory* GetInstance();
protected:
ContentWebUIControllerFactory();
- virtual ~ContentWebUIControllerFactory();
+ ~ContentWebUIControllerFactory() override;
private:
friend struct DefaultSingletonTraits<ContentWebUIControllerFactory>;
diff --git a/chromium/content/browser/webui/generic_handler.cc b/chromium/content/browser/webui/generic_handler.cc
index 058382fa8a8..b26bcd9294a 100644
--- a/chromium/content/browser/webui/generic_handler.cc
+++ b/chromium/content/browser/webui/generic_handler.cc
@@ -50,8 +50,11 @@ void GenericHandler::HandleNavigateToUrl(const base::ListValue* args) {
if (disposition == CURRENT_TAB && target_string == "_blank")
disposition = NEW_FOREGROUND_TAB;
- web_ui()->GetWebContents()->OpenURL(OpenURLParams(
- GURL(url_string), Referrer(), disposition, PAGE_TRANSITION_LINK, false));
+ web_ui()->GetWebContents()->OpenURL(OpenURLParams(GURL(url_string),
+ Referrer(),
+ disposition,
+ ui::PAGE_TRANSITION_LINK,
+ false));
// This may delete us!
}
diff --git a/chromium/content/browser/webui/generic_handler.h b/chromium/content/browser/webui/generic_handler.h
index 431373dd3b1..dd352555d0d 100644
--- a/chromium/content/browser/webui/generic_handler.h
+++ b/chromium/content/browser/webui/generic_handler.h
@@ -18,10 +18,10 @@ namespace content {
class GenericHandler : public WebUIMessageHandler {
public:
GenericHandler();
- virtual ~GenericHandler();
+ ~GenericHandler() override;
// WebUIMessageHandler implementation.
- virtual void RegisterMessages() OVERRIDE;
+ void RegisterMessages() override;
private:
void HandleNavigateToUrl(const base::ListValue* args);
diff --git a/chromium/content/browser/webui/shared_resources_data_source.cc b/chromium/content/browser/webui/shared_resources_data_source.cc
index aa1dc390100..2ce6e147b09 100644
--- a/chromium/content/browser/webui/shared_resources_data_source.cc
+++ b/chromium/content/browser/webui/shared_resources_data_source.cc
@@ -10,8 +10,8 @@
#include "base/threading/thread_restrictions.h"
#include "content/public/common/content_client.h"
#include "content/public/common/url_constants.h"
-#include "grit/webui_resources_map.h"
#include "net/base/mime_util.h"
+#include "ui/resources/grit/webui_resources_map.h"
namespace {
@@ -89,3 +89,17 @@ std::string SharedResourcesDataSource::GetMimeType(
net::GetMimeTypeFromFile(base::FilePath().AppendASCII(path), &mime_type);
return mime_type;
}
+
+std::string
+SharedResourcesDataSource::GetAccessControlAllowOriginForOrigin(
+ const std::string& origin) const {
+ // For now we give access only for "chrome://*" origins.
+ // According to CORS spec, Access-Control-Allow-Origin header doesn't support
+ // wildcards, so we need to set its value explicitly by passing the |origin|
+ // back.
+ std::string allowed_origin_prefix = content::kChromeUIScheme;
+ allowed_origin_prefix += "://";
+ if (origin.find(allowed_origin_prefix) != 0)
+ return "none";
+ return origin;
+}
diff --git a/chromium/content/browser/webui/shared_resources_data_source.h b/chromium/content/browser/webui/shared_resources_data_source.h
index 9c3a3c464ef..87b5121ad22 100644
--- a/chromium/content/browser/webui/shared_resources_data_source.h
+++ b/chromium/content/browser/webui/shared_resources_data_source.h
@@ -15,16 +15,18 @@ class SharedResourcesDataSource : public content::URLDataSource {
SharedResourcesDataSource();
// content::URLDataSource implementation.
- virtual std::string GetSource() const OVERRIDE;
- virtual void StartDataRequest(
+ std::string GetSource() const override;
+ void StartDataRequest(
const std::string& path,
int render_process_id,
int render_frame_id,
- const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
- virtual std::string GetMimeType(const std::string&) const OVERRIDE;
+ const content::URLDataSource::GotDataCallback& callback) override;
+ std::string GetMimeType(const std::string&) const override;
+ std::string GetAccessControlAllowOriginForOrigin(
+ const std::string& origin) const override;
private:
- virtual ~SharedResourcesDataSource();
+ ~SharedResourcesDataSource() override;
DISALLOW_COPY_AND_ASSIGN(SharedResourcesDataSource);
};
diff --git a/chromium/content/browser/webui/url_data_manager.h b/chromium/content/browser/webui/url_data_manager.h
index e94568d7c82..8a318b73dba 100644
--- a/chromium/content/browser/webui/url_data_manager.h
+++ b/chromium/content/browser/webui/url_data_manager.h
@@ -26,7 +26,7 @@ class WebUIDataSource;
class CONTENT_EXPORT URLDataManager : public base::SupportsUserData::Data {
public:
explicit URLDataManager(BrowserContext* browser_context);
- virtual ~URLDataManager();
+ ~URLDataManager() override;
// Adds a DataSource to the collection of data sources. This *must* be invoked
// on the UI thread.
diff --git a/chromium/content/browser/webui/url_data_manager_backend.cc b/chromium/content/browser/webui/url_data_manager_backend.cc
index 9f661af2f6a..9e12864b322 100644
--- a/chromium/content/browser/webui/url_data_manager_backend.cc
+++ b/chromium/content/browser/webui/url_data_manager_backend.cc
@@ -44,8 +44,6 @@
#include "net/url_request/url_request_job_factory.h"
#include "url/url_util.h"
-using appcache::AppCacheServiceImpl;
-
namespace content {
namespace {
@@ -92,6 +90,19 @@ void URLToRequestPath(const GURL& url, std::string* path) {
path->assign(spec.substr(offset));
}
+// Returns a value of 'Origin:' header for the |request| if the header is set.
+// Otherwise returns an empty string.
+std::string GetOriginHeaderValue(const net::URLRequest* request) {
+ std::string result;
+ if (request->extra_request_headers().GetHeader(
+ net::HttpRequestHeaders::kOrigin, &result))
+ return result;
+ net::HttpRequestHeaders headers;
+ if (request->GetFullRequestHeaders(&headers))
+ headers.GetHeader(net::HttpRequestHeaders::kOrigin, &result);
+ return result;
+}
+
} // namespace
// URLRequestChromeJob is a net::URLRequestJob that manages running
@@ -108,14 +119,12 @@ class URLRequestChromeJob : public net::URLRequestJob,
bool is_incognito);
// net::URLRequestJob implementation.
- virtual void Start() OVERRIDE;
- virtual void Kill() OVERRIDE;
- virtual bool ReadRawData(net::IOBuffer* buf,
- int buf_size,
- int* bytes_read) OVERRIDE;
- virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
- virtual int GetResponseCode() const OVERRIDE;
- virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE;
+ void Start() override;
+ void Kill() override;
+ bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+ bool GetMimeType(std::string* mime_type) const override;
+ int GetResponseCode() const override;
+ void GetResponseInfo(net::HttpResponseInfo* info) override;
// Used to notify that the requested data's |mime_type| is ready.
void MimeTypeAvailable(const std::string& mime_type);
@@ -154,13 +163,17 @@ class URLRequestChromeJob : public net::URLRequestJob,
send_content_type_header_ = send_content_type_header;
}
+ void set_access_control_allow_origin(const std::string& value) {
+ access_control_allow_origin_ = value;
+ }
+
// Returns true when job was generated from an incognito profile.
bool is_incognito() const {
return is_incognito_;
}
private:
- virtual ~URLRequestChromeJob();
+ ~URLRequestChromeJob() override;
// Helper for Start(), to let us start asynchronously.
// (This pattern is shared by most net::URLRequestJob implementations.)
@@ -204,10 +217,14 @@ class URLRequestChromeJob : public net::URLRequestJob,
// If true, sets the "Content-Type: <mime-type>" header.
bool send_content_type_header_;
+ // If not empty, "Access-Control-Allow-Origin:" is set to the value of this
+ // string.
+ std::string access_control_allow_origin_;
+
// True when job is generated from an incognito profile.
const bool is_incognito_;
- // The backend is owned by ChromeURLRequestContext and always outlives us.
+ // The backend is owned by net::URLRequestContext and always outlives us.
URLDataManagerBackend* backend_;
base::WeakPtrFactory<URLRequestChromeJob> weak_factory_;
@@ -295,6 +312,12 @@ void URLRequestChromeJob::GetResponseInfo(net::HttpResponseInfo* info) {
mime_type_.c_str());
info->headers->AddHeader(content_type);
}
+
+ if (!access_control_allow_origin_.empty()) {
+ info->headers->AddHeader("Access-Control-Allow-Origin: " +
+ access_control_allow_origin_);
+ info->headers->AddHeader("Vary: Origin");
+ }
}
void URLRequestChromeJob::MimeTypeAvailable(const std::string& mime_type) {
@@ -434,11 +457,11 @@ class ChromeProtocolHandler
is_incognito_(is_incognito),
appcache_service_(appcache_service),
blob_storage_context_(blob_storage_context) {}
- virtual ~ChromeProtocolHandler() {}
+ ~ChromeProtocolHandler() override {}
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE {
+ net::NetworkDelegate* network_delegate) const override {
DCHECK(request);
// Check for chrome://view-http-cache/*, which uses its own job type.
@@ -479,7 +502,7 @@ class ChromeProtocolHandler
GetURLDataManagerForResourceContext(resource_context_), is_incognito_);
}
- virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
+ bool IsSafeRedirectTarget(const GURL& location) const override {
return false;
}
@@ -580,6 +603,15 @@ bool URLDataManagerBackend::StartRequest(const net::URLRequest* request,
job->set_send_content_type_header(
source->source()->ShouldServeMimeTypeAsContentTypeHeader());
+ std::string origin = GetOriginHeaderValue(request);
+ if (!origin.empty()) {
+ std::string header =
+ source->source()->GetAccessControlAllowOriginForOrigin(origin);
+ DCHECK(header.empty() || header == origin || header == "*" ||
+ header == "null");
+ job->set_access_control_allow_origin(header);
+ }
+
// Look up additional request info to pass down.
int render_process_id = -1;
int render_frame_id = -1;
@@ -695,11 +727,11 @@ class DevToolsJobFactory
// |is_incognito| should be set for incognito profiles.
DevToolsJobFactory(content::ResourceContext* resource_context,
bool is_incognito);
- virtual ~DevToolsJobFactory();
+ ~DevToolsJobFactory() override;
- virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
- net::NetworkDelegate* network_delegate) const OVERRIDE;
+ net::NetworkDelegate* network_delegate) const override;
private:
// |resource_context_| and |network_delegate_| are owned by ProfileIOData,
diff --git a/chromium/content/browser/webui/url_data_manager_backend.h b/chromium/content/browser/webui/url_data_manager_backend.h
index a307cdbfa10..19d6bd24aec 100644
--- a/chromium/content/browser/webui/url_data_manager_backend.h
+++ b/chromium/content/browser/webui/url_data_manager_backend.h
@@ -18,15 +18,13 @@
class GURL;
-namespace appcache {
-class AppCacheServiceImpl;
-}
-
namespace base {
class RefCountedMemory;
}
namespace content {
+
+class AppCacheServiceImpl;
class ChromeBlobStorageContext;
class ResourceContext;
class URLDataManagerBackend;
@@ -41,14 +39,14 @@ class URLDataManagerBackend : public base::SupportsUserData::Data {
typedef int RequestID;
URLDataManagerBackend();
- virtual ~URLDataManagerBackend();
+ ~URLDataManagerBackend() override;
// Invoked to create the protocol handler for chrome://. |is_incognito| should
// be set for incognito profiles. Called on the UI thread.
static net::URLRequestJobFactory::ProtocolHandler* CreateProtocolHandler(
content::ResourceContext* resource_context,
bool is_incognito,
- appcache::AppCacheServiceImpl* appcache_service,
+ AppCacheServiceImpl* appcache_service,
ChromeBlobStorageContext* blob_storage_context);
// Adds a DataSource to the collection of data sources.
diff --git a/chromium/content/browser/webui/web_ui_controller_factory_registry.h b/chromium/content/browser/webui/web_ui_controller_factory_registry.h
index 6d0da82edeb..b59162f6e1d 100644
--- a/chromium/content/browser/webui/web_ui_controller_factory_registry.h
+++ b/chromium/content/browser/webui/web_ui_controller_factory_registry.h
@@ -19,14 +19,14 @@ class CONTENT_EXPORT WebUIControllerFactoryRegistry
// WebUIControllerFactory implementation. Each method loops through the same
// method on all the factories.
- virtual WebUIController* CreateWebUIControllerForURL(
- WebUI* web_ui, const GURL& url) const OVERRIDE;
- virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE;
- virtual bool UseWebUIForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE;
- virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE;
+ WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
+ const GURL& url) const override;
+ WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
+ const GURL& url) const override;
+ bool UseWebUIForURL(BrowserContext* browser_context,
+ const GURL& url) const override;
+ bool UseWebUIBindingsForURL(BrowserContext* browser_context,
+ const GURL& url) const override;
// Returns true if the given URL can be loaded by Web UI system. This allows
// URLs that UseWebUIForURL returns true for, and also URLs that can be loaded
@@ -38,7 +38,7 @@ class CONTENT_EXPORT WebUIControllerFactoryRegistry
friend struct DefaultSingletonTraits<WebUIControllerFactoryRegistry>;
WebUIControllerFactoryRegistry();
- virtual ~WebUIControllerFactoryRegistry();
+ ~WebUIControllerFactoryRegistry() override;
DISALLOW_COPY_AND_ASSIGN(WebUIControllerFactoryRegistry);
};
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 052396746fe..caa8f9ad858 100644
--- a/chromium/content/browser/webui/web_ui_data_source_impl.cc
+++ b/chromium/content/browser/webui/web_ui_data_source_impl.cc
@@ -9,9 +9,9 @@
#include "base/bind.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_util.h"
+#include "content/grit/content_resources.h"
#include "content/public/common/content_client.h"
-#include "grit/content_resources.h"
-#include "mojo/public/js/bindings/constants.h"
+#include "mojo/public/js/constants.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "ui/base/webui/web_ui_util.h"
@@ -31,13 +31,15 @@ WebUIDataSource* WebUIDataSource::AddMojoDataSource(
const char* path;
int id;
} resources[] = {
+ { 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_UNSAFE(resources); ++i)
+ for (size_t i = 0; i < arraysize(resources); ++i)
mojo_source->AddResourcePath(resources[i].path, resources[i].id);
URLDataManager::AddWebUIDataSource(browser_context, mojo_source);
@@ -57,44 +59,39 @@ class WebUIDataSourceImpl::InternalDataSource : public URLDataSource {
InternalDataSource(WebUIDataSourceImpl* parent) : parent_(parent) {
}
- virtual ~InternalDataSource() {
- }
+ ~InternalDataSource() override {}
// URLDataSource implementation.
- virtual std::string GetSource() const OVERRIDE {
- return parent_->GetSource();
- }
- virtual std::string GetMimeType(const std::string& path) const OVERRIDE {
+ std::string GetSource() const override { return parent_->GetSource(); }
+ std::string GetMimeType(const std::string& path) const override {
return parent_->GetMimeType(path);
}
- virtual void StartDataRequest(
+ void StartDataRequest(
const std::string& path,
int render_process_id,
int render_frame_id,
- const URLDataSource::GotDataCallback& callback) OVERRIDE {
+ const URLDataSource::GotDataCallback& callback) override {
return parent_->StartDataRequest(path, render_process_id, render_frame_id,
callback);
}
- virtual bool ShouldReplaceExistingSource() const OVERRIDE {
+ bool ShouldReplaceExistingSource() const override {
return parent_->replace_existing_source_;
}
- virtual bool AllowCaching() const OVERRIDE {
- return false;
- }
- virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
+ bool AllowCaching() const override { return false; }
+ bool ShouldAddContentSecurityPolicy() const override {
return parent_->add_csp_;
}
- virtual std::string GetContentSecurityPolicyObjectSrc() const OVERRIDE {
+ std::string GetContentSecurityPolicyObjectSrc() const override {
if (parent_->object_src_set_)
return parent_->object_src_;
return URLDataSource::GetContentSecurityPolicyObjectSrc();
}
- virtual std::string GetContentSecurityPolicyFrameSrc() const OVERRIDE {
+ std::string GetContentSecurityPolicyFrameSrc() const override {
if (parent_->frame_src_set_)
return parent_->frame_src_;
return URLDataSource::GetContentSecurityPolicyFrameSrc();
}
- virtual bool ShouldDenyXFrameOptions() const OVERRIDE {
+ bool ShouldDenyXFrameOptions() const override {
return parent_->deny_xframe_options_;
}
@@ -108,7 +105,6 @@ WebUIDataSourceImpl::WebUIDataSourceImpl(const std::string& source_name)
new InternalDataSource(this)),
source_name_(source_name),
default_resource_(-1),
- json_js_format_v2_(false),
add_csp_(true),
object_src_set_(false),
frame_src_set_(false),
@@ -149,10 +145,6 @@ void WebUIDataSourceImpl::SetJsonPath(const std::string& path) {
json_path_ = path;
}
-void WebUIDataSourceImpl::SetUseJsonJSFormatV2() {
- json_js_format_v2_ = true;
-}
-
void WebUIDataSourceImpl::AddResourcePath(const std::string &path,
int resource_id) {
path_to_idr_map_[path] = resource_id;
@@ -241,10 +233,6 @@ void WebUIDataSourceImpl::SendLocalizedStringsAsJSON(
if (!disable_set_font_strings_)
webui::SetFontAndTextDirection(&localized_strings_);
- scoped_ptr<webui::UseVersion2> version2;
- if (json_js_format_v2_)
- version2.reset(new webui::UseVersion2);
-
webui::AppendJsonJS(&localized_strings_, &template_data);
callback.Run(base::RefCountedString::TakeString(&template_data));
}
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 9a015899c1a..d9f44887d1c 100644
--- a/chromium/content/browser/webui/web_ui_data_source_impl.h
+++ b/chromium/content/browser/webui/web_ui_data_source_impl.h
@@ -27,31 +27,25 @@ class CONTENT_EXPORT WebUIDataSourceImpl
public NON_EXPORTED_BASE(WebUIDataSource) {
public:
// WebUIDataSource implementation:
- virtual void AddString(const std::string& name,
- const base::string16& value) OVERRIDE;
- virtual void AddString(const std::string& name,
- const std::string& value) OVERRIDE;
- virtual void AddLocalizedString(const std::string& name, int ids) OVERRIDE;
- virtual void AddLocalizedStrings(
- const base::DictionaryValue& localized_strings) OVERRIDE;
- virtual void AddBoolean(const std::string& name, bool value) OVERRIDE;
- virtual void SetJsonPath(const std::string& path) OVERRIDE;
- virtual void SetUseJsonJSFormatV2() OVERRIDE;
- virtual void AddResourcePath(const std::string &path,
- int resource_id) OVERRIDE;
- virtual void SetDefaultResource(int resource_id) OVERRIDE;
- virtual void SetRequestFilter(
- const WebUIDataSource::HandleRequestCallback& callback) OVERRIDE;
- virtual void DisableReplaceExistingSource() OVERRIDE;
- virtual void DisableContentSecurityPolicy() OVERRIDE;
- virtual void OverrideContentSecurityPolicyObjectSrc(
- const std::string& data) OVERRIDE;
- virtual void OverrideContentSecurityPolicyFrameSrc(
- const std::string& data) OVERRIDE;
- virtual void DisableDenyXFrameOptions() OVERRIDE;
+ void AddString(const std::string& name, const base::string16& value) override;
+ void AddString(const std::string& name, const std::string& value) override;
+ void AddLocalizedString(const std::string& name, int ids) override;
+ void AddLocalizedStrings(
+ const base::DictionaryValue& localized_strings) override;
+ void AddBoolean(const std::string& name, bool value) override;
+ void SetJsonPath(const std::string& path) override;
+ void AddResourcePath(const std::string& path, int resource_id) override;
+ void SetDefaultResource(int resource_id) override;
+ void SetRequestFilter(
+ const WebUIDataSource::HandleRequestCallback& callback) override;
+ void DisableReplaceExistingSource() override;
+ void DisableContentSecurityPolicy() override;
+ void OverrideContentSecurityPolicyObjectSrc(const std::string& data) override;
+ void OverrideContentSecurityPolicyFrameSrc(const std::string& data) override;
+ void DisableDenyXFrameOptions() override;
protected:
- virtual ~WebUIDataSourceImpl();
+ ~WebUIDataSourceImpl() override;
// Completes a request by sending our dictionary of localized strings.
void SendLocalizedStringsAsJSON(
@@ -88,7 +82,6 @@ class CONTENT_EXPORT WebUIDataSourceImpl
// specific resources like "favicon/34" getting sent to this source.
std::string source_name_;
int default_resource_;
- bool json_js_format_v2_;
std::string json_path_;
std::map<std::string, int> path_to_idr_map_;
base::DictionaryValue localized_strings_;
diff --git a/chromium/content/browser/webui/web_ui_data_source_unittest.cc b/chromium/content/browser/webui/web_ui_data_source_unittest.cc
index 97fa85ec82f..c5b469860a2 100644
--- a/chromium/content/browser/webui/web_ui_data_source_unittest.cc
+++ b/chromium/content/browser/webui/web_ui_data_source_unittest.cc
@@ -6,6 +6,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/webui/web_ui_data_source_impl.h"
+#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/test_content_client.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,17 +24,17 @@ const char kDummytResource[] = "<html>blah</html>";
class TestClient : public TestContentClient {
public:
TestClient() {}
- virtual ~TestClient() {}
+ ~TestClient() override {}
- virtual base::string16 GetLocalizedString(int message_id) const OVERRIDE {
+ base::string16 GetLocalizedString(int message_id) const override {
if (message_id == kDummyStringId)
return base::UTF8ToUTF16(kDummyString);
return base::string16();
}
- virtual base::RefCountedStaticMemory* GetDataResourceBytes(
- int resource_id) const OVERRIDE {
+ base::RefCountedStaticMemory* GetDataResourceBytes(
+ int resource_id) const override {
base::RefCountedStaticMemory* bytes = NULL;
if (resource_id == kDummyDefaultResourceId) {
bytes = new base::RefCountedStaticMemory(
@@ -51,7 +52,7 @@ class TestClient : public TestContentClient {
class WebUIDataSourceTest : public testing::Test {
public:
WebUIDataSourceTest() : result_data_(NULL) {}
- virtual ~WebUIDataSourceTest() {}
+ ~WebUIDataSourceTest() override {}
WebUIDataSourceImpl* source() { return source_.get(); }
void StartDataRequest(const std::string& path) {
@@ -69,7 +70,7 @@ class WebUIDataSourceTest : public testing::Test {
scoped_refptr<base::RefCountedMemory> result_data_;
private:
- virtual void SetUp() {
+ void SetUp() override {
SetContentClient(&client_);
WebUIDataSource* source = WebUIDataSourceImpl::Create("host");
WebUIDataSourceImpl* source_impl = static_cast<WebUIDataSourceImpl*>(
@@ -83,6 +84,7 @@ class WebUIDataSourceTest : public testing::Test {
result_data_ = data;
}
+ TestBrowserThreadBundle thread_bundle_;
scoped_refptr<WebUIDataSourceImpl> source_;
TestClient client_;
};
@@ -91,7 +93,7 @@ TEST_F(WebUIDataSourceTest, EmptyStrings) {
source()->SetJsonPath("strings.js");
StartDataRequest("strings.js");
std::string result(result_data_->front_as<char>(), result_data_->size());
- EXPECT_NE(result.find("var templateData = {"), std::string::npos);
+ EXPECT_NE(result.find("loadTimeData.data = {"), std::string::npos);
EXPECT_NE(result.find("};"), std::string::npos);
}
diff --git a/chromium/content/browser/webui/web_ui_impl.cc b/chromium/content/browser/webui/web_ui_impl.cc
index 340a047b398..a9194a992fd 100644
--- a/chromium/content/browser/webui/web_ui_impl.cc
+++ b/chromium/content/browser/webui/web_ui_impl.cc
@@ -44,7 +44,7 @@ base::string16 WebUI::GetJavascriptCall(
}
WebUIImpl::WebUIImpl(WebContents* contents)
- : link_transition_type_(PAGE_TRANSITION_LINK),
+ : link_transition_type_(ui::PAGE_TRANSITION_LINK),
bindings_(BINDINGS_POLICY_WEB_UI),
web_contents_(contents) {
DCHECK(contents);
@@ -110,11 +110,11 @@ void WebUIImpl::OverrideTitle(const base::string16& title) {
overridden_title_ = title;
}
-PageTransition WebUIImpl::GetLinkTransitionType() const {
+ui::PageTransition WebUIImpl::GetLinkTransitionType() const {
return link_transition_type_;
}
-void WebUIImpl::SetLinkTransitionType(PageTransition type) {
+void WebUIImpl::SetLinkTransitionType(ui::PageTransition type) {
link_transition_type_ = type;
}
diff --git a/chromium/content/browser/webui/web_ui_impl.h b/chromium/content/browser/webui/web_ui_impl.h
index 40cb559c1f6..c08db2927f6 100644
--- a/chromium/content/browser/webui/web_ui_impl.h
+++ b/chromium/content/browser/webui/web_ui_impl.h
@@ -23,7 +23,7 @@ class CONTENT_EXPORT WebUIImpl : public WebUI,
public base::SupportsWeakPtr<WebUIImpl> {
public:
explicit WebUIImpl(WebContents* contents);
- virtual ~WebUIImpl();
+ ~WebUIImpl() override;
// Called by WebContentsImpl when the RenderView is first created. This is
// *not* called for every page load because in some cases
@@ -31,47 +31,45 @@ class CONTENT_EXPORT WebUIImpl : public WebUI,
void RenderViewCreated(RenderViewHost* render_view_host);
// WebUI implementation:
- virtual WebContents* GetWebContents() const OVERRIDE;
- virtual WebUIController* GetController() const OVERRIDE;
- virtual void SetController(WebUIController* controller) OVERRIDE;
- virtual float GetDeviceScaleFactor() const OVERRIDE;
- virtual const base::string16& GetOverriddenTitle() const OVERRIDE;
- virtual void OverrideTitle(const base::string16& title) OVERRIDE;
- virtual PageTransition GetLinkTransitionType() const OVERRIDE;
- virtual void SetLinkTransitionType(PageTransition type) OVERRIDE;
- virtual int GetBindings() const OVERRIDE;
- virtual void SetBindings(int bindings) OVERRIDE;
- virtual void OverrideJavaScriptFrame(const std::string& frame_name) OVERRIDE;
- virtual void AddMessageHandler(WebUIMessageHandler* handler) OVERRIDE;
+ WebContents* GetWebContents() const override;
+ WebUIController* GetController() const override;
+ void SetController(WebUIController* controller) override;
+ float GetDeviceScaleFactor() const override;
+ const base::string16& GetOverriddenTitle() const override;
+ void OverrideTitle(const base::string16& title) override;
+ ui::PageTransition GetLinkTransitionType() const override;
+ void SetLinkTransitionType(ui::PageTransition type) override;
+ int GetBindings() const override;
+ void SetBindings(int bindings) override;
+ void OverrideJavaScriptFrame(const std::string& frame_name) override;
+ void AddMessageHandler(WebUIMessageHandler* handler) override;
typedef base::Callback<void(const base::ListValue*)> MessageCallback;
- virtual void RegisterMessageCallback(
- const std::string& message,
- const MessageCallback& callback) OVERRIDE;
- virtual void ProcessWebUIMessage(const GURL& source_url,
- const std::string& message,
- const base::ListValue& args) OVERRIDE;
- virtual void CallJavascriptFunction(
- const std::string& function_name) OVERRIDE;
- virtual void CallJavascriptFunction(const std::string& function_name,
- const base::Value& arg) OVERRIDE;
- virtual void CallJavascriptFunction(const std::string& function_name,
- const base::Value& arg1,
- const base::Value& arg2) OVERRIDE;
- virtual void CallJavascriptFunction(const std::string& function_name,
- const base::Value& arg1,
- const base::Value& arg2,
- const base::Value& arg3) OVERRIDE;
- virtual void CallJavascriptFunction(const std::string& function_name,
- const base::Value& arg1,
- const base::Value& arg2,
- const base::Value& arg3,
- const base::Value& arg4) OVERRIDE;
- virtual void CallJavascriptFunction(
+ void RegisterMessageCallback(const std::string& message,
+ const MessageCallback& callback) override;
+ void ProcessWebUIMessage(const GURL& source_url,
+ const std::string& message,
+ const base::ListValue& args) override;
+ void CallJavascriptFunction(const std::string& function_name) override;
+ void CallJavascriptFunction(const std::string& function_name,
+ const base::Value& arg) override;
+ void CallJavascriptFunction(const std::string& function_name,
+ const base::Value& arg1,
+ const base::Value& arg2) override;
+ void CallJavascriptFunction(const std::string& function_name,
+ const base::Value& arg1,
+ const base::Value& arg2,
+ const base::Value& arg3) override;
+ void CallJavascriptFunction(const std::string& function_name,
+ const base::Value& arg1,
+ const base::Value& arg2,
+ const base::Value& arg3,
+ const base::Value& arg4) override;
+ void CallJavascriptFunction(
const std::string& function_name,
- const std::vector<const base::Value*>& args) OVERRIDE;
+ const std::vector<const base::Value*>& args) override;
// IPC::Listener implementation:
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ bool OnMessageReceived(const IPC::Message& message) override;
private:
// IPC message handling.
@@ -99,7 +97,7 @@ class CONTENT_EXPORT WebUIImpl : public WebUI,
// Options that may be overridden by individual Web UI implementations. The
// bool options default to false. See the public getters for more information.
base::string16 overridden_title_; // Defaults to empty string.
- PageTransition link_transition_type_; // Defaults to LINK.
+ ui::PageTransition link_transition_type_; // Defaults to LINK.
int bindings_; // The bindings from BindingsPolicy that should be enabled for
// this page.
diff --git a/chromium/content/browser/webui/web_ui_mojo_browsertest.cc b/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
index 5007a8da6a0..9830f1df006 100644
--- a/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/chromium/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -5,26 +5,30 @@
#include <limits>
#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/files/file_path.h"
-#include "base/path_service.h"
+#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/service_registry.h"
#include "content/public/common/url_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/test/data/web_ui_test_mojo_bindings.mojom.h"
-#include "grit/content_resources.h"
-#include "mojo/common/test/test_utils.h"
-#include "mojo/public/js/bindings/constants.h"
+#include "mojo/edk/test/test_utils.h"
+#include "mojo/public/cpp/bindings/interface_impl.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/js/constants.h"
namespace content {
namespace {
@@ -36,11 +40,13 @@ bool got_message = false;
bool GetResource(const std::string& id,
const WebUIDataSource::GotDataCallback& callback) {
// These are handled by the WebUIDataSource that AddMojoDataSource() creates.
- if (id == mojo::kCodecModuleName ||
+ if (id == mojo::kBufferModuleName ||
+ id == mojo::kCodecModuleName ||
id == mojo::kConnectionModuleName ||
id == mojo::kConnectorModuleName ||
id == mojo::kUnicodeModuleName ||
- id == mojo::kRouterModuleName)
+ id == mojo::kRouterModuleName ||
+ id == mojo::kValidatorModuleName)
return false;
std::string contents;
@@ -53,24 +59,16 @@ bool GetResource(const std::string& id,
return true;
}
-class BrowserTargetImpl : public BrowserTarget {
+class BrowserTargetImpl : public mojo::InterfaceImpl<BrowserTarget> {
public:
- BrowserTargetImpl(mojo::ScopedMessagePipeHandle handle,
- base::RunLoop* run_loop)
- : run_loop_(run_loop) {
- renderer_.Bind(handle.Pass());
- renderer_.set_client(this);
- }
+ explicit BrowserTargetImpl(base::RunLoop* run_loop) : run_loop_(run_loop) {}
- virtual ~BrowserTargetImpl() {}
+ ~BrowserTargetImpl() override {}
- // BrowserTarget overrides:
- virtual void PingResponse() OVERRIDE {
- NOTREACHED();
- }
+ // mojo::InterfaceImpl<BrowserTarget> overrides:
+ void PingResponse() override { NOTREACHED(); }
protected:
- RendererTargetPtr renderer_;
base::RunLoop* run_loop_;
private:
@@ -79,17 +77,16 @@ class BrowserTargetImpl : public BrowserTarget {
class PingBrowserTargetImpl : public BrowserTargetImpl {
public:
- PingBrowserTargetImpl(mojo::ScopedMessagePipeHandle handle,
- base::RunLoop* run_loop)
- : BrowserTargetImpl(handle.Pass(), run_loop) {
- renderer_->Ping();
- }
+ explicit PingBrowserTargetImpl(base::RunLoop* run_loop)
+ : BrowserTargetImpl(run_loop) {}
- virtual ~PingBrowserTargetImpl() {}
+ ~PingBrowserTargetImpl() override {}
+
+ // mojo::InterfaceImpl<BrowserTarget> overrides:
+ void OnConnectionEstablished() override { client()->Ping(); }
- // BrowserTarget overrides:
// Quit the RunLoop when called.
- virtual void PingResponse() OVERRIDE {
+ void PingResponse() override {
got_message = true;
run_loop_->Quit();
}
@@ -125,13 +122,18 @@ class PingTestWebUIController : public TestWebUIController {
PingTestWebUIController(WebUI* web_ui, base::RunLoop* run_loop)
: TestWebUIController(web_ui, run_loop) {
}
+ ~PingTestWebUIController() override {}
// WebUIController overrides:
- virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE {
- mojo::MessagePipe pipe;
- browser_target_.reset(
- new PingBrowserTargetImpl(pipe.handle0.Pass(), run_loop_));
- render_view_host->SetWebUIHandle(pipe.handle1.Pass());
+ void RenderViewCreated(RenderViewHost* render_view_host) override {
+ render_view_host->GetMainFrame()->GetServiceRegistry()->
+ AddService<BrowserTarget>(base::Bind(
+ &PingTestWebUIController::CreateHandler, base::Unretained(this)));
+ }
+
+ void CreateHandler(mojo::InterfaceRequest<BrowserTarget> request) {
+ browser_target_.reset(mojo::WeakBindToRequest(
+ new PingBrowserTargetImpl(run_loop_), &request));
}
private:
@@ -145,22 +147,22 @@ class TestWebUIControllerFactory : public WebUIControllerFactory {
void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; }
- virtual WebUIController* CreateWebUIControllerForURL(
- WebUI* web_ui, const GURL& url) const OVERRIDE {
+ WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
+ const GURL& url) const override {
if (url.query() == "ping")
return new PingTestWebUIController(web_ui, run_loop_);
return NULL;
}
- virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
+ const GURL& url) const override {
return reinterpret_cast<WebUI::TypeID>(1);
}
- virtual bool UseWebUIForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ bool UseWebUIForURL(BrowserContext* browser_context,
+ const GURL& url) const override {
return true;
}
- virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
- const GURL& url) const OVERRIDE {
+ bool UseWebUIBindingsForURL(BrowserContext* browser_context,
+ const GURL& url) const override {
return true;
}
@@ -176,7 +178,7 @@ class WebUIMojoTest : public ContentBrowserTest {
WebUIControllerFactory::RegisterFactory(&factory_);
}
- virtual ~WebUIMojoTest() {
+ ~WebUIMojoTest() override {
WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
}
@@ -212,6 +214,19 @@ IN_PROC_BROWSER_TEST_F(WebUIMojoTest, EndToEndPing) {
// RunLoop is quit when message received from page.
run_loop.Run();
EXPECT_TRUE(got_message);
+
+ // Check that a second render frame in the same renderer process works
+ // correctly.
+ Shell* other_shell = CreateBrowser();
+ got_message = false;
+ base::RunLoop other_run_loop;
+ factory()->set_run_loop(&other_run_loop);
+ NavigateToURL(other_shell, test_url);
+ // RunLoop is quit when message received from page.
+ other_run_loop.Run();
+ EXPECT_TRUE(got_message);
+ EXPECT_EQ(shell()->web_contents()->GetRenderProcessHost(),
+ other_shell->web_contents()->GetRenderProcessHost());
}
} // namespace
diff --git a/chromium/content/browser/worker.sb b/chromium/content/browser/worker.sb
deleted file mode 100644
index 2e408883e87..00000000000
--- a/chromium/content/browser/worker.sb
+++ /dev/null
@@ -1,12 +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.
-;;
-; This is the Sandbox configuration file used for safeguarding the worker
-; process which is used to run web workers in a sandboxed environment.
-;
-; This is the most restrictive sandbox profile and only enables just enough
-; to allow basic use of Cocoa.
-
-; *** The contents of content/common/common.sb are implicitly included here. ***
diff --git a/chromium/content/browser/worker_host/OWNERS b/chromium/content/browser/worker_host/OWNERS
deleted file mode 100644
index 61fc3fd49ea..00000000000
--- a/chromium/content/browser/worker_host/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-atwilson@chromium.org
-kinuko@chromium.org
-horo@chromium.org
diff --git a/chromium/content/browser/worker_host/worker_message_filter.cc b/chromium/content/browser/worker_host/worker_message_filter.cc
deleted file mode 100644
index 62348b5ff0b..00000000000
--- a/chromium/content/browser/worker_host/worker_message_filter.cc
+++ /dev/null
@@ -1,75 +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 "content/browser/worker_host/worker_message_filter.h"
-
-#include "content/browser/message_port_message_filter.h"
-#include "content/browser/worker_host/worker_service_impl.h"
-#include "content/common/view_messages.h"
-#include "content/common/worker_messages.h"
-#include "content/public/browser/resource_context.h"
-
-namespace content {
-
-WorkerMessageFilter::WorkerMessageFilter(
- int render_process_id,
- ResourceContext* resource_context,
- const WorkerStoragePartition& partition,
- MessagePortMessageFilter* message_port_message_filter)
- : BrowserMessageFilter(ViewMsgStart),
- render_process_id_(render_process_id),
- resource_context_(resource_context),
- partition_(partition),
- message_port_message_filter_(message_port_message_filter) {
- // Note: This constructor is called on both IO or UI thread.
- DCHECK(resource_context);
-}
-
-WorkerMessageFilter::~WorkerMessageFilter() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-}
-
-void WorkerMessageFilter::OnChannelClosing() {
- WorkerServiceImpl::GetInstance()->OnWorkerMessageFilterClosing(this);
-}
-
-bool WorkerMessageFilter::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(WorkerMessageFilter, message)
- // Worker messages.
- // Only sent from renderer for now, until we have nested workers.
- IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker)
- IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, OnForwardToWorker)
- // Only sent from renderer.
- IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentDetached, OnDocumentDetached)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-int WorkerMessageFilter::GetNextRoutingID() {
- return message_port_message_filter_->GetNextRoutingID();
-}
-
-void WorkerMessageFilter::OnCreateWorker(
- const ViewHostMsg_CreateWorker_Params& params,
- int* route_id) {
- bool url_error = false;
- *route_id = GetNextRoutingID();
- WorkerServiceImpl::GetInstance()->CreateWorker(
- params, *route_id, this, resource_context_, partition_, &url_error);
- if (url_error)
- *route_id = MSG_ROUTING_NONE;
-}
-
-void WorkerMessageFilter::OnForwardToWorker(const IPC::Message& message) {
- WorkerServiceImpl::GetInstance()->ForwardToWorker(message, this);
-}
-
-void WorkerMessageFilter::OnDocumentDetached(unsigned long long document_id) {
- WorkerServiceImpl::GetInstance()->DocumentDetached(document_id, this);
-}
-
-} // namespace content
diff --git a/chromium/content/browser/worker_host/worker_message_filter.h b/chromium/content/browser/worker_host/worker_message_filter.h
deleted file mode 100644
index ab9bade8e64..00000000000
--- a/chromium/content/browser/worker_host/worker_message_filter.h
+++ /dev/null
@@ -1,56 +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.
-
-#ifndef CONTENT_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
-#define CONTENT_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
-
-#include "base/callback.h"
-#include "content/browser/worker_host/worker_storage_partition.h"
-#include "content/public/browser/browser_message_filter.h"
-
-class ResourceDispatcherHost;
-struct ViewHostMsg_CreateWorker_Params;
-
-namespace content {
-class MessagePortMessageFilter;
-class ResourceContext;
-
-class WorkerMessageFilter : public BrowserMessageFilter {
- public:
- WorkerMessageFilter(int render_process_id,
- ResourceContext* resource_context,
- const WorkerStoragePartition& partition,
- MessagePortMessageFilter* message_port_filter);
-
- // BrowserMessageFilter implementation.
- virtual void OnChannelClosing() OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- int GetNextRoutingID();
- int render_process_id() const { return render_process_id_; }
-
- MessagePortMessageFilter* message_port_message_filter() const {
- return message_port_message_filter_;
- }
-
- private:
- virtual ~WorkerMessageFilter();
-
- // Message handlers.
- void OnCreateWorker(const ViewHostMsg_CreateWorker_Params& params,
- int* route_id);
- void OnForwardToWorker(const IPC::Message& message);
- void OnDocumentDetached(unsigned long long document_id);
-
- int render_process_id_;
- ResourceContext* const resource_context_;
- WorkerStoragePartition partition_;
-
- MessagePortMessageFilter* message_port_message_filter_;
- DISALLOW_IMPLICIT_CONSTRUCTORS(WorkerMessageFilter);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_WORKER_HOST_WORKER_MESSAGE_FILTER_H_
diff --git a/chromium/content/browser/worker_host/worker_process_host.cc b/chromium/content/browser/worker_host/worker_process_host.cc
deleted file mode 100644
index 81645f66732..00000000000
--- a/chromium/content/browser/worker_host/worker_process_host.cc
+++ /dev/null
@@ -1,830 +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/worker_host/worker_process_host.h"
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/base_switches.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/browser/appcache/appcache_dispatcher_host.h"
-#include "content/browser/appcache/chrome_appcache_service.h"
-#include "content/browser/browser_child_process_host_impl.h"
-#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/devtools/worker_devtools_manager.h"
-#include "content/browser/devtools/worker_devtools_message_filter.h"
-#include "content/browser/fileapi/fileapi_message_filter.h"
-#include "content/browser/frame_host/render_frame_host_delegate.h"
-#include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
-#include "content/browser/loader/resource_message_filter.h"
-#include "content/browser/message_port_message_filter.h"
-#include "content/browser/message_port_service.h"
-#include "content/browser/mime_registry_message_filter.h"
-#include "content/browser/quota_dispatcher_host.h"
-#include "content/browser/renderer_host/database_message_filter.h"
-#include "content/browser/renderer_host/file_utilities_message_filter.h"
-#include "content/browser/renderer_host/render_view_host_delegate.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/renderer_host/socket_stream_dispatcher_host.h"
-#include "content/browser/renderer_host/websocket_dispatcher_host.h"
-#include "content/browser/resource_context_impl.h"
-#include "content/browser/worker_host/worker_message_filter.h"
-#include "content/browser/worker_host/worker_service_impl.h"
-#include "content/common/child_process_host_impl.h"
-#include "content/common/view_messages.h"
-#include "content/common/worker_messages.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/user_metrics.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/result_codes.h"
-#include "content/public/common/sandboxed_process_launcher_delegate.h"
-#include "ipc/ipc_switches.h"
-#include "net/base/mime_util.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "ui/base/ui_base_switches.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/sandbox_file_system_backend.h"
-#include "webkit/common/resource_type.h"
-
-#if defined(OS_WIN)
-#include "content/common/sandbox_win.h"
-#endif
-
-namespace content {
-namespace {
-
-// NOTE: changes to this class need to be reviewed by the security team.
-class WorkerSandboxedProcessLauncherDelegate
- : public content::SandboxedProcessLauncherDelegate {
- public:
- WorkerSandboxedProcessLauncherDelegate(ChildProcessHost* host,
- bool debugging_child)
-#if defined(OS_POSIX)
- : ipc_fd_(host->TakeClientFileDescriptor()),
- debugging_child_(debugging_child)
-#endif // OS_POSIX
- {}
-
- virtual ~WorkerSandboxedProcessLauncherDelegate() {}
-
-#if defined(OS_WIN)
- virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
- bool* success) {
- AddBaseHandleClosePolicy(policy);
- }
-#elif defined(OS_POSIX)
- virtual bool ShouldUseZygote() OVERRIDE {
- return !debugging_child_;
- }
- virtual int GetIpcFd() OVERRIDE {
- return ipc_fd_;
- }
-#endif // OS_WIN
-
- private:
-#if defined(OS_POSIX)
- int ipc_fd_;
- bool debugging_child_;
-#endif // OS_POSIX
-};
-
-// Notifies RenderViewHost that one or more worker objects crashed.
-void WorkerCrashCallback(int render_process_unique_id, int render_frame_id) {
- RenderFrameHostImpl* host =
- RenderFrameHostImpl::FromID(render_process_unique_id, render_frame_id);
- if (host)
- host->delegate()->WorkerCrashed(host);
-}
-
-void WorkerCreatedCallback(int render_process_id,
- int render_frame_id,
- int worker_process_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- RenderFrameHost* render_frame_host =
- RenderFrameHost::FromID(render_process_id, render_frame_id);
- if (!render_frame_host)
- return;
- SiteInstance* site_instance = render_frame_host->GetSiteInstance();
- GetContentClient()->browser()->WorkerProcessCreated(site_instance,
- worker_process_id);
-}
-
-void WorkerTerminatedCallback(int render_process_id,
- int render_frame_id,
- int worker_process_id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- RenderFrameHost* render_frame_host =
- RenderFrameHost::FromID(render_process_id, render_frame_id);
- if (!render_frame_host)
- return;
- SiteInstance* site_instance = render_frame_host->GetSiteInstance();
- GetContentClient()->browser()->WorkerProcessTerminated(site_instance,
- worker_process_id);
-}
-
-} // namespace
-
-WorkerProcessHost::WorkerProcessHost(
- ResourceContext* resource_context,
- const WorkerStoragePartition& partition)
- : resource_context_(resource_context),
- partition_(partition),
- process_launched_(false) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(resource_context_);
- process_.reset(
- new BrowserChildProcessHostImpl(PROCESS_TYPE_WORKER, this));
-}
-
-WorkerProcessHost::~WorkerProcessHost() {
- // If we crashed, tell the RenderViewHosts.
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (!i->load_failed()) {
- const WorkerDocumentSet::DocumentInfoSet& parents =
- i->worker_document_set()->documents();
- for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
- parents.begin(); parent_iter != parents.end(); ++parent_iter) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&WorkerCrashCallback, parent_iter->render_process_id(),
- parent_iter->render_frame_id()));
- }
- }
- WorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
- this, i->worker_route_id());
- }
-
- ChildProcessSecurityPolicyImpl::GetInstance()->Remove(
- process_->GetData().id);
-}
-
-bool WorkerProcessHost::Send(IPC::Message* message) {
- return process_->Send(message);
-}
-
-bool WorkerProcessHost::Init(int render_process_id, int render_frame_id) {
- std::string channel_id = process_->GetHost()->CreateChannel();
- if (channel_id.empty())
- return false;
-
-#if defined(OS_LINUX)
- int flags = ChildProcessHost::CHILD_ALLOW_SELF;
-#else
- int flags = ChildProcessHost::CHILD_NORMAL;
-#endif
-
- base::FilePath exe_path = ChildProcessHost::GetChildPath(flags);
- if (exe_path.empty())
- return false;
-
- CommandLine* cmd_line = new CommandLine(exe_path);
- cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kWorkerProcess);
- cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
- std::string locale = GetContentClient()->browser()->GetApplicationLocale();
- cmd_line->AppendSwitchASCII(switches::kLang, locale);
-
- static const char* const kSwitchNames[] = {
- switches::kDisableApplicationCache,
- switches::kDisableDatabases,
-#if defined(OS_WIN)
- switches::kDisableDesktopNotifications,
-#endif
- switches::kDisableFileSystem,
- switches::kDisableSeccompFilterSandbox,
- switches::kEnableExperimentalWebPlatformFeatures,
- switches::kEnablePreciseMemoryInfo,
- switches::kEnableServiceWorker,
-#if defined(OS_MACOSX)
- switches::kEnableSandboxLogging,
-#endif
- switches::kJavaScriptFlags,
- switches::kNoSandbox
- };
- cmd_line->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), kSwitchNames,
- arraysize(kSwitchNames));
-
-bool debugging_child = false;
-#if defined(OS_POSIX)
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kWaitForDebuggerChildren)) {
- // Look to pass-on the kWaitForDebugger flag.
- std::string value = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kWaitForDebuggerChildren);
- if (value.empty() || value == switches::kWorkerProcess) {
- cmd_line->AppendSwitch(switches::kWaitForDebugger);
- debugging_child = true;
- }
- }
-#endif
-
- process_->Launch(
- new WorkerSandboxedProcessLauncherDelegate(process_->GetHost(),
- debugging_child),
- cmd_line);
-
- ChildProcessSecurityPolicyImpl::GetInstance()->AddWorker(
- process_->GetData().id, render_process_id);
- CreateMessageFilters(render_process_id);
-
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&WorkerCreatedCallback,
- render_process_id,
- render_frame_id,
- process_->GetData().id));
- return true;
-}
-
-void WorkerProcessHost::CreateMessageFilters(int render_process_id) {
- ChromeBlobStorageContext* blob_storage_context =
- GetChromeBlobStorageContextForResourceContext(resource_context_);
- StreamContext* stream_context =
- GetStreamContextForResourceContext(resource_context_);
-
- net::URLRequestContextGetter* url_request_context =
- partition_.url_request_context();
-
- ResourceMessageFilter::GetContextsCallback get_contexts_callback(
- base::Bind(&WorkerProcessHost::GetContexts,
- base::Unretained(this)));
-
- ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
- process_->GetData().id, PROCESS_TYPE_WORKER,
- partition_.appcache_service(),
- blob_storage_context,
- partition_.filesystem_context(),
- partition_.service_worker_context(),
- get_contexts_callback);
- process_->AddFilter(resource_message_filter);
-
- MessagePortMessageFilter* message_port_message_filter =
- new MessagePortMessageFilter(
- base::Bind(&WorkerServiceImpl::next_worker_route_id,
- base::Unretained(WorkerServiceImpl::GetInstance())));
- process_->AddFilter(message_port_message_filter);
- worker_message_filter_ = new WorkerMessageFilter(render_process_id,
- resource_context_,
- partition_,
- message_port_message_filter);
- process_->AddFilter(worker_message_filter_.get());
- process_->AddFilter(new AppCacheDispatcherHost(
- partition_.appcache_service(), process_->GetData().id));
- process_->AddFilter(new FileAPIMessageFilter(
- process_->GetData().id,
- url_request_context,
- partition_.filesystem_context(),
- blob_storage_context,
- stream_context));
- process_->AddFilter(new FileUtilitiesMessageFilter(
- process_->GetData().id));
- process_->AddFilter(new MimeRegistryMessageFilter());
- process_->AddFilter(new DatabaseMessageFilter(partition_.database_tracker()));
- process_->AddFilter(new QuotaDispatcherHost(
- process_->GetData().id,
- partition_.quota_manager(),
- GetContentClient()->browser()->CreateQuotaPermissionContext()));
-
- SocketStreamDispatcherHost::GetRequestContextCallback
- request_context_callback(
- base::Bind(&WorkerProcessHost::GetRequestContext,
- base::Unretained(this)));
-
- SocketStreamDispatcherHost* socket_stream_dispatcher_host =
- new SocketStreamDispatcherHost(
- render_process_id,
- request_context_callback,
- resource_context_);
- socket_stream_dispatcher_host_ = socket_stream_dispatcher_host;
- process_->AddFilter(socket_stream_dispatcher_host);
-
- WebSocketDispatcherHost::GetRequestContextCallback
- websocket_request_context_callback(
- base::Bind(&WorkerProcessHost::GetRequestContext,
- base::Unretained(this),
- ResourceType::SUB_RESOURCE));
-
- process_->AddFilter(new WebSocketDispatcherHost(
- render_process_id, websocket_request_context_callback));
-
- process_->AddFilter(new WorkerDevToolsMessageFilter(process_->GetData().id));
- process_->AddFilter(
- new IndexedDBDispatcherHost(process_->GetData().id,
- url_request_context,
- partition_.indexed_db_context(),
- blob_storage_context));
-}
-
-void WorkerProcessHost::CreateWorker(const WorkerInstance& instance,
- bool pause_on_start) {
- ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
- process_->GetData().id, instance.url());
-
- instances_.push_back(instance);
-
- WorkerProcessMsg_CreateWorker_Params params;
- params.url = instance.url();
- params.name = instance.name();
- params.content_security_policy = instance.content_security_policy();
- params.security_policy_type = instance.security_policy_type();
- params.pause_on_start = pause_on_start;
- params.route_id = instance.worker_route_id();
- Send(new WorkerProcessMsg_CreateWorker(params));
-
- UpdateTitle();
-
- // Walk all pending filters and let them know the worker has been created
- // (could be more than one in the case where we had to queue up worker
- // creation because the worker process limit was reached).
- for (WorkerInstance::FilterList::const_iterator i =
- instance.filters().begin();
- i != instance.filters().end(); ++i) {
- i->filter()->Send(new ViewMsg_WorkerCreated(i->route_id()));
- }
-}
-
-bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
- WorkerMessageFilter* filter) {
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (!i->closed() && i->HasFilter(filter, message.routing_id())) {
- RelayMessage(message, filter, &(*i));
- return true;
- }
- }
-
- return false;
-}
-
-void WorkerProcessHost::OnProcessLaunched() {
- process_launched_ = true;
-
- WorkerServiceImpl::GetInstance()->NotifyWorkerProcessCreated();
-}
-
-bool WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(WorkerProcessHost, message)
- IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed,
- OnWorkerContextClosed)
- IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextDestroyed,
- OnWorkerContextDestroyed)
- IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerScriptLoaded,
- OnWorkerScriptLoaded)
- IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerScriptLoadFailed,
- OnWorkerScriptLoadFailed)
- IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerConnected,
- OnWorkerConnected)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowDatabase, OnAllowDatabase)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_RequestFileSystemAccessSync,
- OnRequestFileSystemAccessSync)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowIndexedDB, OnAllowIndexedDB)
- IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_ForceKillWorker,
- OnForceKillWorkerProcess)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-// Sent to notify the browser process when a worker context invokes close(), so
-// no new connections are sent to shared workers.
-void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) {
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() == worker_route_id) {
- // Set the closed flag - this will stop any further messages from
- // being sent to the worker (messages can still be sent from the worker,
- // for exception reporting, etc).
- i->set_closed(true);
- break;
- }
- }
-}
-
-void WorkerProcessHost::OnWorkerContextDestroyed(int worker_route_id) {
- WorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
- this, worker_route_id);
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() == worker_route_id) {
- instances_.erase(i);
- UpdateTitle();
- return;
- }
- }
-}
-
-void WorkerProcessHost::OnWorkerScriptLoaded(int worker_route_id) {
- WorkerDevToolsManager::GetInstance()->WorkerContextStarted(this,
- worker_route_id);
-}
-
-void WorkerProcessHost::OnWorkerScriptLoadFailed(int worker_route_id) {
- bool shutdown = true;
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() != worker_route_id) {
- shutdown = false;
- continue;
- }
- i->set_load_failed(true);
- for (WorkerInstance::FilterList::const_iterator j = i->filters().begin();
- j != i->filters().end(); ++j) {
- j->filter()->Send(new ViewMsg_WorkerScriptLoadFailed(j->route_id()));
- }
- }
- if (shutdown) {
- base::KillProcess(
- process_->GetData().handle, RESULT_CODE_NORMAL_EXIT, false);
- }
-}
-
-void WorkerProcessHost::OnWorkerConnected(int message_port_id,
- int worker_route_id) {
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() != worker_route_id)
- continue;
- for (WorkerInstance::FilterList::const_iterator j = i->filters().begin();
- j != i->filters().end(); ++j) {
- if (j->message_port_id() != message_port_id)
- continue;
- j->filter()->Send(new ViewMsg_WorkerConnected(j->route_id()));
- return;
- }
- }
-}
-
-void WorkerProcessHost::OnAllowDatabase(int worker_route_id,
- const GURL& url,
- const base::string16& name,
- const base::string16& display_name,
- unsigned long estimated_size,
- bool* result) {
- *result = GetContentClient()->browser()->AllowWorkerDatabase(
- url, name, display_name, estimated_size, resource_context_,
- GetRenderFrameIDsForWorker(worker_route_id));
-}
-
-void WorkerProcessHost::OnRequestFileSystemAccessSync(int worker_route_id,
- const GURL& url,
- bool* result) {
- *result = GetContentClient()->browser()->AllowWorkerFileSystem(
- url, resource_context_, GetRenderFrameIDsForWorker(worker_route_id));
-}
-
-void WorkerProcessHost::OnAllowIndexedDB(int worker_route_id,
- const GURL& url,
- const base::string16& name,
- bool* result) {
- *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
- url, name, resource_context_,
- GetRenderFrameIDsForWorker(worker_route_id));
-}
-
-void WorkerProcessHost::OnForceKillWorkerProcess() {
- if (process_ && process_launched_)
- base::KillProcess(
- process_->GetData().handle, RESULT_CODE_NORMAL_EXIT, false);
- else
- RecordAction(base::UserMetricsAction("WorkerProcess_BadProcessToKill"));
-}
-
-void WorkerProcessHost::RelayMessage(
- const IPC::Message& message,
- WorkerMessageFilter* incoming_filter,
- WorkerInstance* instance) {
- if (message.type() == WorkerMsg_Connect::ID) {
- // Crack the SharedWorker Connect message to setup routing for the port.
- WorkerMsg_Connect::Param params;
- if (!WorkerMsg_Connect::Read(&message, &params))
- return;
-
- int sent_message_port_id = params.a;
- int new_routing_id = params.b;
- new_routing_id = worker_message_filter_->GetNextRoutingID();
- MessagePortService::GetInstance()->UpdateMessagePort(
- sent_message_port_id,
- worker_message_filter_->message_port_message_filter(),
- new_routing_id);
-
- instance->SetMessagePortID(incoming_filter,
- message.routing_id(),
- sent_message_port_id);
- // Resend the message with the new routing id.
- worker_message_filter_->Send(new WorkerMsg_Connect(
- instance->worker_route_id(), sent_message_port_id, new_routing_id));
-
- // Send any queued messages for the sent port.
- MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
- sent_message_port_id);
- } else {
- IPC::Message* new_message = new IPC::Message(message);
- new_message->set_routing_id(instance->worker_route_id());
- worker_message_filter_->Send(new_message);
- return;
- }
-}
-
-void WorkerProcessHost::ShutdownSocketStreamDispatcherHostIfNecessary() {
- if (!instances_.size() && socket_stream_dispatcher_host_.get()) {
- // We can assume that this object is going to delete, because
- // currently a WorkerInstance will never be added to a WorkerProcessHost
- // once it is initialized.
-
- // SocketStreamDispatcherHost should be notified now that the worker
- // process will shutdown soon.
- socket_stream_dispatcher_host_->Shutdown();
- socket_stream_dispatcher_host_ = NULL;
- }
-}
-
-void WorkerProcessHost::FilterShutdown(WorkerMessageFilter* filter) {
- for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
- bool shutdown = false;
- i->RemoveFilters(filter);
-
- int render_frame_id = 0;
- const WorkerDocumentSet::DocumentInfoSet& documents =
- i->worker_document_set()->documents();
- for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
- documents.begin(); doc != documents.end(); ++doc) {
- if (doc->filter() == filter) {
- render_frame_id = doc->render_frame_id();
- break;
- }
- }
- i->worker_document_set()->RemoveAll(filter);
- if (i->worker_document_set()->IsEmpty()) {
- shutdown = true;
- }
- if (shutdown) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&WorkerTerminatedCallback,
- filter->render_process_id(),
- render_frame_id,
- process_->GetData().id));
- Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
- i = instances_.erase(i);
- } else {
- ++i;
- }
- }
- ShutdownSocketStreamDispatcherHostIfNecessary();
-}
-
-bool WorkerProcessHost::CanShutdown() {
- return instances_.empty();
-}
-
-void WorkerProcessHost::UpdateTitle() {
- std::set<std::string> titles;
- for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
- // Allow the embedder first crack at special casing the title.
- std::string title = GetContentClient()->browser()->
- GetWorkerProcessTitle(i->url(), resource_context_);
-
- if (title.empty()) {
- title = net::registry_controlled_domains::GetDomainAndRegistry(
- i->url(),
- net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
- }
-
- // Use the host name if the domain is empty, i.e. localhost or IP address.
- if (title.empty())
- title = i->url().host();
-
- // If the host name is empty, i.e. file url, use the path.
- if (title.empty())
- title = i->url().path();
- titles.insert(title);
- }
-
- std::string display_title;
- for (std::set<std::string>::iterator i = titles.begin();
- i != titles.end(); ++i) {
- if (!display_title.empty())
- display_title += ", ";
- display_title += *i;
- }
-
- process_->SetName(base::UTF8ToUTF16(display_title));
-}
-
-void WorkerProcessHost::DocumentDetached(WorkerMessageFilter* filter,
- unsigned long long document_id) {
- // Walk all instances and remove the document from their document set.
- for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
- int render_frame_id = 0;
- const WorkerDocumentSet::DocumentInfoSet& documents =
- i->worker_document_set()->documents();
- for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
- documents.begin(); doc != documents.end(); ++doc) {
- if (doc->filter() == filter && doc->document_id() == document_id) {
- render_frame_id = doc->render_frame_id();
- break;
- }
- }
- i->worker_document_set()->Remove(filter, document_id);
- if (i->worker_document_set()->IsEmpty()) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&WorkerTerminatedCallback,
- filter->render_process_id(),
- render_frame_id,
- process_->GetData().id));
- // This worker has no more associated documents - shut it down.
- Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
- i = instances_.erase(i);
- } else {
- ++i;
- }
- }
- ShutdownSocketStreamDispatcherHostIfNecessary();
-}
-
-void WorkerProcessHost::TerminateWorker(int worker_route_id) {
- Send(new WorkerMsg_TerminateWorkerContext(worker_route_id));
-}
-
-void WorkerProcessHost::SetBackgrounded(bool backgrounded) {
- process_->SetBackgrounded(backgrounded);
-}
-
-const ChildProcessData& WorkerProcessHost::GetData() {
- return process_->GetData();
-}
-
-std::vector<std::pair<int, int> > WorkerProcessHost::GetRenderFrameIDsForWorker(
- int worker_route_id) {
- std::vector<std::pair<int, int> > result;
- WorkerProcessHost::Instances::const_iterator i;
- for (i = instances_.begin(); i != instances_.end(); ++i) {
- if (i->worker_route_id() != worker_route_id)
- continue;
- const WorkerDocumentSet::DocumentInfoSet& documents =
- i->worker_document_set()->documents();
- for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
- documents.begin(); doc != documents.end(); ++doc) {
- result.push_back(
- std::make_pair(doc->render_process_id(), doc->render_frame_id()));
- }
- break;
- }
- return result;
-}
-
-void WorkerProcessHost::GetContexts(const ResourceHostMsg_Request& request,
- ResourceContext** resource_context,
- net::URLRequestContext** request_context) {
- *resource_context = resource_context_;
- *request_context = partition_.url_request_context()->GetURLRequestContext();
-}
-
-net::URLRequestContext* WorkerProcessHost::GetRequestContext(
- ResourceType::Type resource_type) {
- return partition_.url_request_context()->GetURLRequestContext();
-}
-
-WorkerProcessHost::WorkerInstance::WorkerInstance(
- const GURL& url,
- const base::string16& name,
- const base::string16& content_security_policy,
- blink::WebContentSecurityPolicyType security_policy_type,
- int worker_route_id,
- int render_frame_id,
- ResourceContext* resource_context,
- const WorkerStoragePartition& partition)
- : url_(url),
- closed_(false),
- name_(name),
- content_security_policy_(content_security_policy),
- security_policy_type_(security_policy_type),
- worker_route_id_(worker_route_id),
- render_frame_id_(render_frame_id),
- worker_document_set_(new WorkerDocumentSet()),
- resource_context_(resource_context),
- partition_(partition),
- load_failed_(false) {
- DCHECK(resource_context_);
-}
-
-WorkerProcessHost::WorkerInstance::~WorkerInstance() {
-}
-
-void WorkerProcessHost::WorkerInstance::SetMessagePortID(
- WorkerMessageFilter* filter,
- int route_id,
- int message_port_id) {
- for (FilterList::iterator i = filters_.begin(); i != filters_.end(); ++i) {
- if (i->filter() == filter && i->route_id() == route_id) {
- i->set_message_port_id(message_port_id);
- return;
- }
- }
-}
-
-// Compares an instance based on the algorithm in the WebWorkers spec - an
-// instance matches if the origins of the URLs match, and:
-// a) the names are non-empty and equal
-// -or-
-// b) the names are both empty, and the urls are equal
-bool WorkerProcessHost::WorkerInstance::Matches(
- const GURL& match_url,
- const base::string16& match_name,
- const WorkerStoragePartition& partition,
- ResourceContext* resource_context) const {
- // Only match open shared workers.
- if (closed_)
- return false;
-
- // ResourceContext equivalence is being used as a proxy to ensure we only
- // matched shared workers within the same BrowserContext.
- if (resource_context_ != resource_context)
- return false;
-
- // We must be in the same storage partition otherwise sharing will violate
- // isolation.
- if (!partition_.Equals(partition))
- return false;
-
- if (url_.GetOrigin() != match_url.GetOrigin())
- return false;
-
- if (name_.empty() && match_name.empty())
- return url_ == match_url;
-
- return name_ == match_name;
-}
-
-void WorkerProcessHost::WorkerInstance::AddFilter(WorkerMessageFilter* filter,
- int route_id) {
- CHECK(filter);
- if (!HasFilter(filter, route_id)) {
- FilterInfo info(filter, route_id);
- filters_.push_back(info);
- }
-}
-
-void WorkerProcessHost::WorkerInstance::RemoveFilter(
- WorkerMessageFilter* filter, int route_id) {
- for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
- if (i->filter() == filter && i->route_id() == route_id)
- i = filters_.erase(i);
- else
- ++i;
- }
- // Should not be duplicate copies in the filter set.
- DCHECK(!HasFilter(filter, route_id));
-}
-
-void WorkerProcessHost::WorkerInstance::RemoveFilters(
- WorkerMessageFilter* filter) {
- for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
- if (i->filter() == filter)
- i = filters_.erase(i);
- else
- ++i;
- }
-}
-
-bool WorkerProcessHost::WorkerInstance::HasFilter(
- WorkerMessageFilter* filter, int route_id) const {
- for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
- ++i) {
- if (i->filter() == filter && i->route_id() == route_id)
- return true;
- }
- return false;
-}
-
-bool WorkerProcessHost::WorkerInstance::FrameIsParent(
- int render_process_id, int render_frame_id) const {
- const WorkerDocumentSet::DocumentInfoSet& parents =
- worker_document_set()->documents();
- for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
- parents.begin();
- parent_iter != parents.end(); ++parent_iter) {
- if (parent_iter->render_process_id() == render_process_id &&
- parent_iter->render_frame_id() == render_frame_id) {
- return true;
- }
- }
- return false;
-}
-
-WorkerProcessHost::WorkerInstance::FilterInfo
-WorkerProcessHost::WorkerInstance::GetFilter() const {
- DCHECK(NumFilters() == 1);
- return *filters_.begin();
-}
-
-} // namespace content
diff --git a/chromium/content/browser/worker_host/worker_process_host.h b/chromium/content/browser/worker_host/worker_process_host.h
deleted file mode 100644
index 150153139fe..00000000000
--- a/chromium/content/browser/worker_host/worker_process_host.h
+++ /dev/null
@@ -1,288 +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_WORKER_HOST_WORKER_PROCESS_HOST_H_
-#define CONTENT_BROWSER_WORKER_HOST_WORKER_PROCESS_HOST_H_
-
-#include <list>
-#include <string>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/browser/worker_host/worker_document_set.h"
-#include "content/browser/worker_host/worker_storage_partition.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 "ipc/ipc_sender.h"
-#include "third_party/WebKit/public/web/WebContentSecurityPolicy.h"
-#include "url/gurl.h"
-#include "webkit/common/resource_type.h"
-
-struct ResourceHostMsg_Request;
-
-namespace fileapi {
-class FileSystemContext;
-} // namespace fileapi
-
-namespace net {
-class URLRequestContext;
-}
-
-namespace webkit_database {
-class DatabaseTracker;
-} // namespace webkit_database
-
-namespace content {
-class BrowserChildProcessHostImpl;
-class IndexedDBContextImpl;
-class ResourceContext;
-class SocketStreamDispatcherHost;
-class WorkerMessageFilter;
-class WorkerServiceImpl;
-
-// The WorkerProcessHost is the interface that represents the browser side of
-// the browser <-> worker communication channel. There will be one
-// WorkerProcessHost per worker process. Currently each worker runs in its own
-// process, but that may change. However, we do assume (by storing a
-// net::URLRequestContext) that a WorkerProcessHost serves a single
-// BrowserContext.
-class WorkerProcessHost : public BrowserChildProcessHostDelegate,
- public IPC::Sender {
- public:
- // Contains information about each worker instance, needed to forward messages
- // between the renderer and worker processes.
- class WorkerInstance {
- public:
- WorkerInstance(const GURL& url,
- const base::string16& name,
- const base::string16& content_security_policy,
- blink::WebContentSecurityPolicyType security_policy_type,
- int worker_route_id,
- int render_frame_id,
- ResourceContext* resource_context,
- const WorkerStoragePartition& partition);
- ~WorkerInstance();
-
- // Unique identifier for a worker client.
- class FilterInfo {
- public:
- FilterInfo(WorkerMessageFilter* filter, int route_id)
- : filter_(filter), route_id_(route_id), message_port_id_(0) { }
- WorkerMessageFilter* filter() const { return filter_; }
- int route_id() const { return route_id_; }
- int message_port_id() const { return message_port_id_; }
- void set_message_port_id(int id) { message_port_id_ = id; }
-
- private:
- WorkerMessageFilter* filter_;
- int route_id_;
- int message_port_id_;
- };
-
- // APIs to manage the filter list for a given instance.
- void AddFilter(WorkerMessageFilter* filter, int route_id);
- void RemoveFilter(WorkerMessageFilter* filter, int route_id);
- void RemoveFilters(WorkerMessageFilter* filter);
- bool HasFilter(WorkerMessageFilter* filter, int route_id) const;
- bool FrameIsParent(int render_process_id, int render_frame_id) const;
- int NumFilters() const { return filters_.size(); }
- void SetMessagePortID(WorkerMessageFilter* filter,
- int route_id,
- int message_port_id);
- // Returns the single filter (must only be one).
- FilterInfo GetFilter() const;
-
- typedef std::list<FilterInfo> FilterList;
- const FilterList& filters() const { return filters_; }
-
- // Checks if this WorkerInstance matches the passed url/name params
- // (per the comparison algorithm in the WebWorkers spec). This API only
- // applies to shared workers.
- bool Matches(
- const GURL& url,
- const base::string16& name,
- const WorkerStoragePartition& partition,
- ResourceContext* resource_context) const;
-
- // Shares the passed instance's WorkerDocumentSet with this instance. This
- // instance's current WorkerDocumentSet is dereferenced (and freed if this
- // is the only reference) as a result.
- void ShareDocumentSet(const WorkerInstance& instance) {
- worker_document_set_ = instance.worker_document_set_;
- };
-
- // Accessors
- bool closed() const { return closed_; }
- void set_closed(bool closed) { closed_ = closed; }
- const GURL& url() const { return url_; }
- const base::string16 name() const { return name_; }
- const base::string16 content_security_policy() const {
- return content_security_policy_;
- }
- blink::WebContentSecurityPolicyType security_policy_type() const {
- return security_policy_type_;
- }
- int worker_route_id() const { return worker_route_id_; }
- int render_frame_id() const { return render_frame_id_; }
- WorkerDocumentSet* worker_document_set() const {
- return worker_document_set_.get();
- }
- ResourceContext* resource_context() const {
- return resource_context_;
- }
- const WorkerStoragePartition& partition() const {
- return partition_;
- }
- void set_load_failed(bool failed) { load_failed_ = failed; }
- bool load_failed() { return load_failed_; }
-
- private:
- // Set of all filters (clients) associated with this worker.
- GURL url_;
- bool closed_;
- base::string16 name_;
- base::string16 content_security_policy_;
- blink::WebContentSecurityPolicyType security_policy_type_;
- int worker_route_id_;
- int render_frame_id_;
- FilterList filters_;
- scoped_refptr<WorkerDocumentSet> worker_document_set_;
- ResourceContext* const resource_context_;
- WorkerStoragePartition partition_;
- bool load_failed_;
- };
-
- WorkerProcessHost(ResourceContext* resource_context,
- const WorkerStoragePartition& partition);
- virtual ~WorkerProcessHost();
-
- // IPC::Sender implementation:
- virtual bool Send(IPC::Message* message) OVERRIDE;
-
- // Starts the process. Returns true iff it succeeded.
- // |render_process_id| and |render_frame_id| are the renderer process and the
- // renderer frame responsible for starting this worker.
- bool Init(int render_process_id, int render_frame_id);
-
- // Creates a worker object in the process.
- void CreateWorker(const WorkerInstance& instance, bool pause_on_start);
-
- // Returns true iff the given message from a renderer process was forwarded to
- // the worker.
- bool FilterMessage(const IPC::Message& message, WorkerMessageFilter* filter);
-
- void FilterShutdown(WorkerMessageFilter* filter);
-
- // Shuts down any shared workers that are no longer referenced by active
- // documents.
- void DocumentDetached(WorkerMessageFilter* filter,
- unsigned long long document_id);
-
- // Terminates the given worker, i.e. based on a UI action.
- CONTENT_EXPORT void TerminateWorker(int worker_route_id);
-
- // Callers can reduce the WorkerProcess' priority.
- void SetBackgrounded(bool backgrounded);
-
- CONTENT_EXPORT const ChildProcessData& GetData();
-
- typedef std::list<WorkerInstance> Instances;
- const Instances& instances() const { return instances_; }
-
- ResourceContext* resource_context() const {
- return resource_context_;
- }
-
- bool process_launched() const { return process_launched_; }
-
- protected:
- friend class WorkerServiceImpl;
-
- Instances& mutable_instances() { return instances_; }
-
- private:
- // BrowserChildProcessHostDelegate implementation:
- virtual void OnProcessLaunched() OVERRIDE;
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- // Creates and adds the message filters.
- void CreateMessageFilters(int render_process_id);
-
- void OnWorkerContextClosed(int worker_route_id);
- void OnWorkerContextDestroyed(int worker_route_id);
- 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 OnRequestFileSystemAccessSync(int worker_route_id,
- const GURL& url,
- bool* result);
- void OnAllowIndexedDB(int worker_route_id,
- const GURL& url,
- const base::string16& name,
- bool* result);
- void OnForceKillWorkerProcess();
-
- // Relays a message to the given endpoint. Takes care of parsing the message
- // if it contains a message port and sending it a valid route id.
- void RelayMessage(const IPC::Message& message,
- WorkerMessageFilter* incoming_filter,
- WorkerInstance* instance);
-
- void ShutdownSocketStreamDispatcherHostIfNecessary();
-
- virtual bool CanShutdown() OVERRIDE;
-
- // Updates the title shown in the task manager.
- void UpdateTitle();
-
- // Return a vector of all the render process/render frame IDs that use the
- // given worker.
- std::vector<std::pair<int, int> > GetRenderFrameIDsForWorker(int route_id);
-
- // Callbacks for ResourceMessageFilter and SocketStreamDispatcherHost.
- void GetContexts(const ResourceHostMsg_Request& request,
- ResourceContext** resource_context,
- net::URLRequestContext** request_context);
- net::URLRequestContext* GetRequestContext(ResourceType::Type resource_type);
-
- Instances instances_;
-
- ResourceContext* const resource_context_;
- WorkerStoragePartition partition_;
-
- // A reference to the filter associated with this worker process. We need to
- // keep this around since we'll use it when forward messages to the worker
- // process.
- scoped_refptr<WorkerMessageFilter> worker_message_filter_;
-
- scoped_ptr<BrowserChildProcessHostImpl> process_;
- bool process_launched_;
-
- scoped_refptr<SocketStreamDispatcherHost> socket_stream_dispatcher_host_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkerProcessHost);
-};
-
-class WorkerProcessHostIterator
- : public BrowserChildProcessHostTypeIterator<WorkerProcessHost> {
- public:
- WorkerProcessHostIterator()
- : BrowserChildProcessHostTypeIterator<WorkerProcessHost>(
- PROCESS_TYPE_WORKER) {
- }
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_WORKER_HOST_WORKER_PROCESS_HOST_H_
diff --git a/chromium/content/browser/worker_host/worker_service_impl.cc b/chromium/content/browser/worker_host/worker_service_impl.cc
deleted file mode 100644
index 4636777e1ce..00000000000
--- a/chromium/content/browser/worker_host/worker_service_impl.cc
+++ /dev/null
@@ -1,600 +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/worker_host/worker_service_impl.h"
-
-#include <string>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/threading/thread.h"
-#include "content/browser/devtools/worker_devtools_manager.h"
-#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/browser/shared_worker/shared_worker_service_impl.h"
-#include "content/browser/worker_host/worker_message_filter.h"
-#include "content/browser/worker_host/worker_process_host.h"
-#include "content/common/view_messages.h"
-#include "content/common/worker_messages.h"
-#include "content/public/browser/child_process_data.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_iterator.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/resource_context.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/worker_service_observer.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/process_type.h"
-
-namespace content {
-
-namespace {
-void AddRenderFrameID(std::set<std::pair<int, int> >* visible_frame_ids,
- RenderFrameHost* rfh) {
- visible_frame_ids->insert(
- std::pair<int, int>(rfh->GetProcess()->GetID(),
- rfh->GetRoutingID()));
-}
-}
-
-const int WorkerServiceImpl::kMaxWorkersWhenSeparate = 64;
-const int WorkerServiceImpl::kMaxWorkersPerFrameWhenSeparate = 16;
-
-class WorkerPrioritySetter
- : public NotificationObserver,
- public base::RefCountedThreadSafe<WorkerPrioritySetter,
- BrowserThread::DeleteOnUIThread> {
- public:
- WorkerPrioritySetter();
-
- // Posts a task to the UI thread to register to receive notifications.
- void Initialize();
-
- // Invoked by WorkerServiceImpl when a worker process is created.
- void NotifyWorkerProcessCreated();
-
- private:
- friend class base::RefCountedThreadSafe<WorkerPrioritySetter>;
- friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
- friend class base::DeleteHelper<WorkerPrioritySetter>;
- virtual ~WorkerPrioritySetter();
-
- // Posts a task to perform a worker priority update.
- void PostTaskToGatherAndUpdateWorkerPriorities();
-
- // Gathers up a list of the visible tabs and then updates priorities for
- // all the shared workers.
- void GatherVisibleIDsAndUpdateWorkerPriorities();
-
- // Registers as an observer to receive notifications about
- // widgets being shown.
- void RegisterObserver();
-
- // Sets priorities for shared workers given a set of visible frames (as a
- // std::set of std::pair<render_process, render_frame> ids.
- void UpdateWorkerPrioritiesFromVisibleSet(
- const std::set<std::pair<int, int> >* visible);
-
- // Called to refresh worker priorities when focus changes between tabs.
- void OnRenderWidgetVisibilityChanged(std::pair<int, int>);
-
- // NotificationObserver implementation.
- virtual void Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) OVERRIDE;
-
- NotificationRegistrar registrar_;
-};
-
-WorkerPrioritySetter::WorkerPrioritySetter() {
-}
-
-WorkerPrioritySetter::~WorkerPrioritySetter() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-void WorkerPrioritySetter::Initialize() {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&WorkerPrioritySetter::RegisterObserver, this));
-}
-
-void WorkerPrioritySetter::NotifyWorkerProcessCreated() {
- PostTaskToGatherAndUpdateWorkerPriorities();
-}
-
-void WorkerPrioritySetter::PostTaskToGatherAndUpdateWorkerPriorities() {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(
- &WorkerPrioritySetter::GatherVisibleIDsAndUpdateWorkerPriorities,
- this));
-}
-
-void WorkerPrioritySetter::GatherVisibleIDsAndUpdateWorkerPriorities() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- std::set<std::pair<int, int> >* visible_frame_ids =
- new std::set<std::pair<int, int> >();
-
- // Gather up all the visible renderer process/view pairs
- scoped_ptr<RenderWidgetHostIterator> widgets(
- RenderWidgetHost::GetRenderWidgetHosts());
- while (RenderWidgetHost* widget = widgets->GetNextHost()) {
- if (widget->GetProcess()->VisibleWidgetCount() == 0)
- continue;
- if (!widget->IsRenderView())
- continue;
-
- RenderWidgetHostView* widget_view = widget->GetView();
- if (!widget_view || !widget_view->IsShowing())
- continue;
- RenderViewHost* rvh = RenderViewHost::From(widget);
- WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
- if (!web_contents)
- continue;
- web_contents->ForEachFrame(
- base::Bind(&AddRenderFrameID, visible_frame_ids));
- }
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&WorkerPrioritySetter::UpdateWorkerPrioritiesFromVisibleSet,
- this, base::Owned(visible_frame_ids)));
-}
-
-void WorkerPrioritySetter::UpdateWorkerPrioritiesFromVisibleSet(
- const std::set<std::pair<int, int> >* visible_frame_ids) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- if (!iter->process_launched())
- continue;
- bool throttle = true;
-
- for (WorkerProcessHost::Instances::const_iterator instance =
- iter->instances().begin(); instance != iter->instances().end();
- ++instance) {
-
- // This code assumes one worker per process
- WorkerProcessHost::Instances::const_iterator first_instance =
- iter->instances().begin();
- if (first_instance == iter->instances().end())
- continue;
-
- WorkerDocumentSet::DocumentInfoSet::const_iterator info =
- first_instance->worker_document_set()->documents().begin();
-
- for (; info != first_instance->worker_document_set()->documents().end();
- ++info) {
- std::pair<int, int> id(
- info->render_process_id(), info->render_frame_id());
- if (visible_frame_ids->find(id) != visible_frame_ids->end()) {
- throttle = false;
- break;
- }
- }
-
- if (!throttle ) {
- break;
- }
- }
-
- iter->SetBackgrounded(throttle);
- }
-}
-
-void WorkerPrioritySetter::OnRenderWidgetVisibilityChanged(
- std::pair<int, int> id) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- std::set<std::pair<int, int> > visible_frame_ids;
-
- visible_frame_ids.insert(id);
-
- UpdateWorkerPrioritiesFromVisibleSet(&visible_frame_ids);
-}
-
-void WorkerPrioritySetter::RegisterObserver() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- registrar_.Add(this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
- NotificationService::AllBrowserContextsAndSources());
- registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CREATED,
- NotificationService::AllBrowserContextsAndSources());
-}
-
-void WorkerPrioritySetter::Observe(int type,
- const NotificationSource& source, const NotificationDetails& details) {
- if (type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
- bool visible = *Details<bool>(details).ptr();
-
- if (visible) {
- int render_widget_id =
- Source<RenderWidgetHost>(source).ptr()->GetRoutingID();
- int render_process_pid =
- Source<RenderWidgetHost>(source).ptr()->GetProcess()->GetID();
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&WorkerPrioritySetter::OnRenderWidgetVisibilityChanged,
- this, std::pair<int, int>(render_process_pid, render_widget_id)));
- }
- }
- else if (type == NOTIFICATION_RENDERER_PROCESS_CREATED) {
- PostTaskToGatherAndUpdateWorkerPriorities();
- }
-}
-
-WorkerService* WorkerService::GetInstance() {
- if (EmbeddedSharedWorkerEnabled())
- return SharedWorkerServiceImpl::GetInstance();
- else
- return WorkerServiceImpl::GetInstance();
-}
-
-bool WorkerService::EmbeddedSharedWorkerEnabled() {
- static bool disabled = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableEmbeddedSharedWorker);
- return !disabled;
-}
-
-WorkerServiceImpl* WorkerServiceImpl::GetInstance() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- return Singleton<WorkerServiceImpl>::get();
-}
-
-WorkerServiceImpl::WorkerServiceImpl()
- : priority_setter_(new WorkerPrioritySetter()),
- next_worker_route_id_(0) {
- priority_setter_->Initialize();
-}
-
-WorkerServiceImpl::~WorkerServiceImpl() {
- // The observers in observers_ can't be used here because they might be
- // gone already.
-}
-
-void WorkerServiceImpl::PerformTeardownForTesting() {
- priority_setter_ = NULL;
-}
-
-void WorkerServiceImpl::OnWorkerMessageFilterClosing(
- WorkerMessageFilter* filter) {
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- iter->FilterShutdown(filter);
- }
-
- // See if that process had any queued workers.
- for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
- i != queued_workers_.end();) {
- i->RemoveFilters(filter);
- if (i->NumFilters() == 0) {
- i = queued_workers_.erase(i);
- } else {
- ++i;
- }
- }
-
- // Either a worker proceess has shut down, in which case we can start one of
- // the queued workers, or a renderer has shut down, in which case it doesn't
- // affect anything. We call this function in both scenarios because then we
- // don't have to keep track which filters are from worker processes.
- TryStartingQueuedWorker();
-}
-
-void WorkerServiceImpl::CreateWorker(
- const ViewHostMsg_CreateWorker_Params& params,
- int route_id,
- WorkerMessageFilter* filter,
- ResourceContext* resource_context,
- const WorkerStoragePartition& partition,
- bool* url_mismatch) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- *url_mismatch = false;
- WorkerProcessHost::WorkerInstance* existing_instance =
- FindSharedWorkerInstance(
- params.url, params.name, partition, resource_context);
- if (existing_instance) {
- if (params.url != existing_instance->url()) {
- *url_mismatch = true;
- return;
- }
- if (existing_instance->load_failed()) {
- filter->Send(new ViewMsg_WorkerScriptLoadFailed(route_id));
- return;
- }
- existing_instance->AddFilter(filter, route_id);
- existing_instance->worker_document_set()->Add(
- filter, params.document_id, filter->render_process_id(),
- params.render_frame_route_id);
- filter->Send(new ViewMsg_WorkerCreated(route_id));
- return;
- }
- for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
- i != queued_workers_.end(); ++i) {
- if (i->Matches(params.url, params.name, partition, resource_context) &&
- params.url != i->url()) {
- *url_mismatch = true;
- return;
- }
- }
-
- // Generate a unique route id for the browser-worker communication that's
- // unique among all worker processes. That way when the worker process sends
- // a wrapped IPC message through us, we know which WorkerProcessHost to give
- // it to.
- WorkerProcessHost::WorkerInstance instance(
- params.url,
- params.name,
- params.content_security_policy,
- params.security_policy_type,
- next_worker_route_id(),
- params.render_frame_route_id,
- resource_context,
- partition);
- instance.AddFilter(filter, route_id);
- instance.worker_document_set()->Add(
- filter, params.document_id, filter->render_process_id(),
- params.render_frame_route_id);
-
- CreateWorkerFromInstance(instance);
-}
-
-void WorkerServiceImpl::ForwardToWorker(const IPC::Message& message,
- WorkerMessageFilter* filter) {
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- if (iter->FilterMessage(message, filter))
- return;
- }
-
- // TODO(jabdelmalek): tell filter that callee is gone
-}
-
-void WorkerServiceImpl::DocumentDetached(unsigned long long document_id,
- WorkerMessageFilter* filter) {
- // Any associated shared workers can be shut down.
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter)
- iter->DocumentDetached(filter, document_id);
-
- // Remove any queued shared workers for this document.
- for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
- iter != queued_workers_.end();) {
-
- iter->worker_document_set()->Remove(filter, document_id);
- if (iter->worker_document_set()->IsEmpty()) {
- iter = queued_workers_.erase(iter);
- continue;
- }
- ++iter;
- }
-}
-
-bool WorkerServiceImpl::CreateWorkerFromInstance(
- WorkerProcessHost::WorkerInstance instance) {
- if (!CanCreateWorkerProcess(instance)) {
- queued_workers_.push_back(instance);
- return true;
- }
-
- // Remove any queued instances of this worker and copy over the filter to
- // this instance.
- for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
- iter != queued_workers_.end();) {
- if (iter->Matches(instance.url(), instance.name(),
- instance.partition(), instance.resource_context())) {
- DCHECK(iter->NumFilters() == 1);
- DCHECK_EQ(instance.url(), iter->url());
- WorkerProcessHost::WorkerInstance::FilterInfo filter_info =
- iter->GetFilter();
- instance.AddFilter(filter_info.filter(), filter_info.route_id());
- iter = queued_workers_.erase(iter);
- } else {
- ++iter;
- }
- }
-
- WorkerMessageFilter* first_filter = instance.filters().begin()->filter();
- WorkerProcessHost* worker = new WorkerProcessHost(
- instance.resource_context(), instance.partition());
- // TODO(atwilson): This won't work if the message is from a worker process.
- // We don't support that yet though (this message is only sent from
- // renderers) but when we do, we'll need to add code to pass in the current
- // worker's document set for nested workers.
- if (!worker->Init(first_filter->render_process_id(),
- instance.render_frame_id())) {
- delete worker;
- return false;
- }
-
- worker->CreateWorker(
- instance,
- WorkerDevToolsManager::GetInstance()->WorkerCreated(worker, instance));
- FOR_EACH_OBSERVER(
- WorkerServiceObserver, observers_,
- WorkerCreated(instance.url(), instance.name(), worker->GetData().id,
- instance.worker_route_id()));
- return true;
-}
-
-bool WorkerServiceImpl::CanCreateWorkerProcess(
- const WorkerProcessHost::WorkerInstance& instance) {
- // Worker can be fired off if *any* parent has room.
- const WorkerDocumentSet::DocumentInfoSet& parents =
- instance.worker_document_set()->documents();
-
- for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
- parents.begin();
- parent_iter != parents.end(); ++parent_iter) {
- bool hit_total_worker_limit = false;
- if (FrameCanCreateWorkerProcess(parent_iter->render_process_id(),
- parent_iter->render_frame_id(),
- &hit_total_worker_limit)) {
- return true;
- }
- // Return false if already at the global worker limit (no need to continue
- // checking parent tabs).
- if (hit_total_worker_limit)
- return false;
- }
- // If we've reached here, none of the parent tabs is allowed to create an
- // instance.
- return false;
-}
-
-bool WorkerServiceImpl::FrameCanCreateWorkerProcess(
- int render_process_id,
- int render_frame_id,
- bool* hit_total_worker_limit) {
- int total_workers = 0;
- int workers_per_tab = 0;
- *hit_total_worker_limit = false;
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- for (WorkerProcessHost::Instances::const_iterator cur_instance =
- iter->instances().begin();
- cur_instance != iter->instances().end(); ++cur_instance) {
- total_workers++;
- if (total_workers >= kMaxWorkersWhenSeparate) {
- *hit_total_worker_limit = true;
- return false;
- }
- if (cur_instance->FrameIsParent(render_process_id, render_frame_id)) {
- workers_per_tab++;
- if (workers_per_tab >= kMaxWorkersPerFrameWhenSeparate)
- return false;
- }
- }
- }
-
- return true;
-}
-
-void WorkerServiceImpl::TryStartingQueuedWorker() {
- if (queued_workers_.empty())
- return;
-
- for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
- i != queued_workers_.end();) {
- if (CanCreateWorkerProcess(*i)) {
- WorkerProcessHost::WorkerInstance instance = *i;
- queued_workers_.erase(i);
- CreateWorkerFromInstance(instance);
-
- // CreateWorkerFromInstance can modify the queued_workers_ list when it
- // coalesces queued instances after starting a shared worker, so we
- // have to rescan the list from the beginning (our iterator is now
- // invalid). This is not a big deal as having any queued workers will be
- // rare in practice so the list will be small.
- i = queued_workers_.begin();
- } else {
- ++i;
- }
- }
-}
-
-bool WorkerServiceImpl::GetRendererForWorker(int worker_process_id,
- int* render_process_id,
- int* render_frame_id) const {
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- if (iter.GetData().id != worker_process_id)
- continue;
-
- // This code assumes one worker per process, see function comment in header!
- WorkerProcessHost::Instances::const_iterator first_instance =
- iter->instances().begin();
- if (first_instance == iter->instances().end())
- return false;
-
- WorkerDocumentSet::DocumentInfoSet::const_iterator info =
- first_instance->worker_document_set()->documents().begin();
- *render_process_id = info->render_process_id();
- *render_frame_id = info->render_frame_id();
- return true;
- }
- return false;
-}
-
-const WorkerProcessHost::WorkerInstance* WorkerServiceImpl::FindWorkerInstance(
- int worker_process_id) {
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- if (iter.GetData().id != worker_process_id)
- continue;
-
- WorkerProcessHost::Instances::const_iterator instance =
- iter->instances().begin();
- return instance == iter->instances().end() ? NULL : &*instance;
- }
- return NULL;
-}
-
-bool WorkerServiceImpl::TerminateWorker(int process_id, int route_id) {
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- if (iter.GetData().id == process_id) {
- iter->TerminateWorker(route_id);
- return true;
- }
- }
- return false;
-}
-
-std::vector<WorkerService::WorkerInfo> WorkerServiceImpl::GetWorkers() {
- std::vector<WorkerService::WorkerInfo> results;
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- const WorkerProcessHost::Instances& instances = (*iter)->instances();
- for (WorkerProcessHost::Instances::const_iterator i = instances.begin();
- i != instances.end(); ++i) {
- WorkerService::WorkerInfo info;
- info.url = i->url();
- info.name = i->name();
- info.route_id = i->worker_route_id();
- info.process_id = iter.GetData().id;
- info.handle = iter.GetData().handle;
- results.push_back(info);
- }
- }
- return results;
-}
-
-void WorkerServiceImpl::AddObserver(WorkerServiceObserver* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- observers_.AddObserver(observer);
-}
-
-void WorkerServiceImpl::RemoveObserver(WorkerServiceObserver* observer) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- observers_.RemoveObserver(observer);
-}
-
-void WorkerServiceImpl::NotifyWorkerDestroyed(
- WorkerProcessHost* process,
- int worker_route_id) {
- WorkerDevToolsManager::GetInstance()->WorkerDestroyed(
- process, worker_route_id);
- FOR_EACH_OBSERVER(WorkerServiceObserver, observers_,
- WorkerDestroyed(process->GetData().id, worker_route_id));
-}
-
-void WorkerServiceImpl::NotifyWorkerProcessCreated() {
- priority_setter_->NotifyWorkerProcessCreated();
-}
-
-WorkerProcessHost::WorkerInstance* WorkerServiceImpl::FindSharedWorkerInstance(
- const GURL& url,
- const base::string16& name,
- const WorkerStoragePartition& partition,
- ResourceContext* resource_context) {
- for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
- for (WorkerProcessHost::Instances::iterator instance_iter =
- iter->mutable_instances().begin();
- instance_iter != iter->mutable_instances().end();
- ++instance_iter) {
- if (instance_iter->Matches(url, name, partition, resource_context))
- return &(*instance_iter);
- }
- }
- return NULL;
-}
-
-} // namespace content
diff --git a/chromium/content/browser/worker_host/worker_service_impl.h b/chromium/content/browser/worker_host/worker_service_impl.h
deleted file mode 100644
index 133c0a38e1a..00000000000
--- a/chromium/content/browser/worker_host/worker_service_impl.h
+++ /dev/null
@@ -1,121 +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_WORKER_HOST_WORKER_SERVICE_H_
-#define CONTENT_BROWSER_WORKER_HOST_WORKER_SERVICE_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/singleton.h"
-#include "base/observer_list.h"
-#include "base/threading/non_thread_safe.h"
-#include "content/browser/worker_host/worker_process_host.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/worker_service.h"
-
-class GURL;
-struct ViewHostMsg_CreateWorker_Params;
-
-namespace content {
-class ResourceContext;
-class WorkerServiceObserver;
-class WorkerStoragePartition;
-class WorkerPrioritySetter;
-
-class CONTENT_EXPORT WorkerServiceImpl
- : public NON_EXPORTED_BASE(WorkerService) {
- public:
- // Returns the WorkerServiceImpl singleton.
- static WorkerServiceImpl* GetInstance();
-
- // Releases the priority setter to avoid memory leak error.
- void PerformTeardownForTesting();
-
- // WorkerService implementation:
- virtual bool TerminateWorker(int process_id, int route_id) OVERRIDE;
- virtual std::vector<WorkerInfo> GetWorkers() OVERRIDE;
- virtual void AddObserver(WorkerServiceObserver* observer) OVERRIDE;
- virtual void RemoveObserver(WorkerServiceObserver* observer) OVERRIDE;
-
- // These methods correspond to worker related IPCs.
- void CreateWorker(const ViewHostMsg_CreateWorker_Params& params,
- int route_id,
- WorkerMessageFilter* filter,
- ResourceContext* resource_context,
- const WorkerStoragePartition& worker_partition,
- bool* url_mismatch);
- void ForwardToWorker(const IPC::Message& message,
- WorkerMessageFilter* filter);
- void DocumentDetached(unsigned long long document_id,
- WorkerMessageFilter* filter);
-
- void OnWorkerMessageFilterClosing(WorkerMessageFilter* filter);
-
- int next_worker_route_id() { return ++next_worker_route_id_; }
-
- // Given a worker's process id, return the IDs of the renderer process and
- // render frame that created it. For shared workers, this returns the first
- // parent.
- // TODO(dimich): This code assumes there is 1 worker per worker process, which
- // is how it is today until V8 can run in separate threads.
- bool GetRendererForWorker(int worker_process_id,
- int* render_process_id,
- int* render_frame_id) const;
- const WorkerProcessHost::WorkerInstance* FindWorkerInstance(
- int worker_process_id);
-
- void NotifyWorkerDestroyed(
- WorkerProcessHost* process,
- int worker_route_id);
-
- void NotifyWorkerProcessCreated();
-
- // Used when we run each worker in a separate process.
- static const int kMaxWorkersWhenSeparate;
- static const int kMaxWorkersPerFrameWhenSeparate;
-
- private:
- friend struct DefaultSingletonTraits<WorkerServiceImpl>;
-
- WorkerServiceImpl();
- virtual ~WorkerServiceImpl();
-
- // Given a WorkerInstance, create an associated worker process.
- bool CreateWorkerFromInstance(WorkerProcessHost::WorkerInstance instance);
-
- // Checks if we can create a worker process based on the process limit when
- // we're using a strategy of one process per core.
- bool CanCreateWorkerProcess(
- const WorkerProcessHost::WorkerInstance& instance);
-
- // Checks if the frame associated with the passed RenderFrame can create a
- // worker process based on the process limit when we're using a strategy of
- // one worker per process.
- bool FrameCanCreateWorkerProcess(
- int render_process_id, int render_frame_id, bool* hit_total_worker_limit);
-
- // Tries to see if any of the queued workers can be created.
- void TryStartingQueuedWorker();
-
- WorkerProcessHost::WorkerInstance* FindSharedWorkerInstance(
- const GURL& url,
- const base::string16& name,
- const WorkerStoragePartition& worker_partition,
- ResourceContext* resource_context);
-
- scoped_refptr<WorkerPrioritySetter> priority_setter_;
-
- int next_worker_route_id_;
-
- WorkerProcessHost::Instances queued_workers_;
-
- ObserverList<WorkerServiceObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(WorkerServiceImpl);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_WORKER_HOST_WORKER_SERVICE_H_
diff --git a/chromium/content/browser/zygote_host/OWNERS b/chromium/content/browser/zygote_host/OWNERS
index 602e00e0750..c2dd4263b5c 100644
--- a/chromium/content/browser/zygote_host/OWNERS
+++ b/chromium/content/browser/zygote_host/OWNERS
@@ -1,3 +1,2 @@
-markus@chromium.org
-cevans@chromium.org
jln@chromium.org
+mdempsky@chromium.org
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 81d075688d7..c2f1c908c0a 100644
--- a/chromium/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/chromium/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -13,8 +13,8 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/environment.h"
-#include "base/file_util.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"
@@ -100,7 +100,7 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
base::FilePath chrome_path;
CHECK(PathService::Get(base::FILE_EXE, &chrome_path));
- CommandLine cmd_line(chrome_path);
+ base::CommandLine cmd_line(chrome_path);
cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kZygoteProcess);
@@ -111,7 +111,8 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
fds_to_map.push_back(std::make_pair(fds[1], kZygoteSocketPairFd));
base::LaunchOptions options;
- const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
+ 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));
@@ -121,18 +122,17 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
// Should this list be obtained from browser_render_process_host.cc?
static const char* kForwardSwitches[] = {
switches::kAllowSandboxDebugging,
- switches::kLoggingLevel,
- switches::kEnableLogging, // Support, e.g., --enable-logging=stderr.
- switches::kV,
- switches::kVModule,
- switches::kRegisterPepperPlugins,
switches::kDisableSeccompFilterSandbox,
-
+ 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));
@@ -287,10 +287,9 @@ ssize_t ZygoteHostImpl::ReadReply(void* buf, size_t buf_len) {
return HANDLE_EINTR(read(control_fd_, buf, buf_len));
}
-pid_t ZygoteHostImpl::ForkRequest(
- const std::vector<std::string>& argv,
- const std::vector<FileDescriptorInfo>& mapping,
- const std::string& process_type) {
+pid_t ZygoteHostImpl::ForkRequest(const std::vector<std::string>& argv,
+ scoped_ptr<FileDescriptorInfo> mapping,
+ const std::string& process_type) {
DCHECK(init_);
Pickle pickle;
@@ -309,26 +308,20 @@ pid_t ZygoteHostImpl::ForkRequest(
// 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.size();
+ const size_t num_fds_to_send = 1 + mapping->GetMappingSize();
pickle.WriteInt(num_fds_to_send);
std::vector<int> fds;
- ScopedVector<base::ScopedFD> autoclose_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());
- autoclose_fds.push_back(new base::ScopedFD(peer_sock.Pass()));
// The rest come from mapping.
- for (std::vector<FileDescriptorInfo>::const_iterator
- i = mapping.begin(); i != mapping.end(); ++i) {
- pickle.WriteUInt32(i->id);
- fds.push_back(i->fd.fd);
- if (i->fd.auto_close) {
- // Auto-close means we need to close the FDs after they have been passed
- // to the other process.
- autoclose_fds.push_back(new base::ScopedFD(i->fd.fd));
- }
+ 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.
@@ -339,7 +332,8 @@ pid_t ZygoteHostImpl::ForkRequest(
base::AutoLock lock(control_lock_);
if (!SendMessage(pickle, &fds))
return base::kNullProcessHandle;
- autoclose_fds.clear();
+ mapping.reset();
+ peer_sock.reset();
{
char buf[sizeof(kZygoteChildPingMessage) + 1];
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 c4435469849..e18e098088b 100644
--- a/chromium/content/browser/zygote_host/zygote_host_impl_linux.h
+++ b/chromium/content/browser/zygote_host/zygote_host_impl_linux.h
@@ -34,7 +34,7 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost {
// Returns its pid on success, otherwise
// base::kNullProcessHandle;
pid_t ForkRequest(const std::vector<std::string>& command_line,
- const std::vector<FileDescriptorInfo>& mapping,
+ scoped_ptr<FileDescriptorInfo> mapping,
const std::string& process_type);
void EnsureProcessTerminated(pid_t process);
@@ -54,16 +54,16 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost {
int* exit_code);
// ZygoteHost implementation:
- virtual pid_t GetPid() const OVERRIDE;
- virtual int GetSandboxStatus() const OVERRIDE;
- virtual void AdjustRendererOOMScore(base::ProcessHandle process_handle,
- int score) OVERRIDE;
+ pid_t GetPid() const override;
+ int GetSandboxStatus() const override;
+ void AdjustRendererOOMScore(base::ProcessHandle process_handle,
+ int score) override;
private:
friend struct DefaultSingletonTraits<ZygoteHostImpl>;
ZygoteHostImpl();
- virtual ~ZygoteHostImpl();
+ ~ZygoteHostImpl() override;
// Notify the Zygote to exit immediately. This object should not be
// used afterwards.